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_mhu.c b/components/messaging/openamp/sp/openamp_mhu.c
new file mode 100644
index 0000000..bafba3e
--- /dev/null
+++ b/components/messaging/openamp/sp/openamp_mhu.c
@@ -0,0 +1,191 @@
+/*
+ * 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 <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 <trace.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <stddef.h>
+#include <limits.h>
+
+#include "openamp_messenger_api.h"
+
+#define MHU_V_2_NOTIFY_CHANNEL 0
+#define MHU_V_2_NOTIFY_VALUE 0xff
+
+struct openamp_mhu {
+ struct device_region rx_region;
+ struct device_region tx_region;
+ struct mhu_v2_x_dev_t rx_dev;
+ struct mhu_v2_x_dev_t tx_dev;
+};
+
+static int openamp_mhu_device_get(const char *dev,
+ struct device_region *dev_region)
+{
+ bool found;
+
+ found = config_store_query(CONFIG_CLASSIFIER_DEVICE_REGION, dev, 0,
+ dev_region, sizeof(*dev_region));
+ if (!found)
+ return -EINVAL;
+
+ if (!dev_region->base_addr)
+ return -EINVAL;
+
+ IMSG("mhu: device region found: %s addr: 0x%p size: %lu", dev,
+ (void *)dev_region->base_addr, dev_region->io_region_size);
+
+ return 0;
+}
+
+int openamp_mhu_receive(struct openamp_messenger *openamp)
+{
+ struct mhu_v2_x_dev_t *rx_dev;
+ enum mhu_v2_x_error_t ret;
+ struct openamp_mhu *mhu;
+ uint32_t channel = 0;
+ uint32_t irq_status;
+
+ if (!openamp->transport) {
+ EMSG("openamp: mhu: receive transport not initialized");
+ return -EINVAL;
+ }
+
+ mhu = openamp->transport;
+ rx_dev = &mhu->rx_dev;
+
+ irq_status = 0;
+
+ do {
+ irq_status = mhu_v2_x_get_interrupt_status(rx_dev);
+ } while(!irq_status);
+
+ ret = mhu_v2_1_get_ch_interrupt_num(rx_dev, &channel);
+
+ ret = mhu_v2_x_channel_clear(rx_dev, channel);
+ if (ret != MHU_V_2_X_ERR_NONE) {
+ EMSG("openamp: mhu: failed to clear channel: %d", channel);
+ return -EPROTO;
+ }
+
+ return 0;
+}
+
+int openamp_mhu_notify_peer(struct openamp_messenger *openamp)
+{
+ struct mhu_v2_x_dev_t *tx_dev;
+ enum mhu_v2_x_error_t ret;
+ struct openamp_mhu *mhu;
+ uint32_t access_ready;
+
+ if (!openamp->transport) {
+ EMSG("openamp: mhu: notify transport not initialized");
+ return -EINVAL;
+ }
+
+ mhu = openamp->transport;
+ tx_dev = &mhu->tx_dev;
+
+ ret = mhu_v2_x_set_access_request(tx_dev);
+ if (ret != MHU_V_2_X_ERR_NONE) {
+ EMSG("openamp: mhu: set access request failed");
+ return -EPROTO;
+ }
+
+ do {
+ ret = mhu_v2_x_get_access_ready(tx_dev, &access_ready);
+ if (ret != MHU_V_2_X_ERR_NONE) {
+ EMSG("openamp: mhu: failed to get access_ready");
+ return -EPROTO;
+ }
+ } while (!access_ready);
+
+ ret = mhu_v2_x_channel_send(tx_dev, MHU_V_2_NOTIFY_CHANNEL,
+ MHU_V_2_NOTIFY_VALUE);
+ if (ret != MHU_V_2_X_ERR_NONE) {
+ EMSG("openamp: mhu: failed send over channel");
+ return -EPROTO;
+ }
+
+ ret = mhu_v2_x_reset_access_request(tx_dev);
+ if (ret != MHU_V_2_X_ERR_NONE) {
+ EMSG("openamp: mhu: failed reset access request");
+ return -EPROTO;
+ }
+
+ return 0;
+}
+
+int openamp_mhu_init(struct openamp_messenger *openamp)
+{
+ struct mhu_v2_x_dev_t *rx_dev;
+ struct mhu_v2_x_dev_t *tx_dev;
+ struct openamp_mhu *mhu;
+ int ret;
+
+ /* if we already have initialized skip this */
+ if (openamp->transport)
+ return 0;
+
+ mhu = malloc(sizeof(*mhu));
+ if (!mhu)
+ return -1;
+
+ ret = openamp_mhu_device_get("mhu-sender", &mhu->tx_region);
+ if (ret < 0)
+ goto free_mhu;
+
+ ret = openamp_mhu_device_get("mhu-receiver", &mhu->rx_region);
+ if (ret < 0)
+ goto free_mhu;
+
+ rx_dev = &mhu->rx_dev;
+ tx_dev = &mhu->tx_dev;
+
+ rx_dev->base = mhu->rx_region.base_addr;
+ rx_dev->frame = MHU_V2_X_RECEIVER_FRAME;
+
+ tx_dev->base = mhu->tx_region.base_addr;
+ tx_dev->frame = MHU_V2_X_SENDER_FRAME;
+
+ ret = mhu_v2_x_driver_init(rx_dev, MHU_REV_READ_FROM_HW);
+ if (ret < 0)
+ goto free_mhu;
+
+ ret = mhu_v2_x_driver_init(tx_dev, MHU_REV_READ_FROM_HW);
+ if (ret < 0)
+ goto free_mhu;
+
+ openamp->transport = (void *)mhu;
+
+ return 0;
+
+free_mhu:
+ free(mhu);
+
+ return ret;
+}
+
+int openamp_mhu_deinit(struct openamp_messenger *openamp)
+{
+ struct openamp_mhu *mhu;
+
+ if (!openamp->transport)
+ return 0;
+
+ mhu = openamp->transport;
+ free(mhu);
+
+ openamp->transport = NULL;
+
+ return 0;
+}