Update MHUv2 driver

The files are copied from TF-M, version 311bca757, without any
changes.

Signed-off-by: Bence Balogh <bence.balogh@arm.com>
Change-Id: I42603a96f0dd78abe3f512d41fee5067c8f8007d
diff --git a/platform/drivers/arm/mhu_driver/mhu.h b/platform/drivers/arm/mhu_driver/mhu.h
new file mode 100644
index 0000000..a02fdd8
--- /dev/null
+++ b/platform/drivers/arm/mhu_driver/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.c b/platform/drivers/arm/mhu_driver/mhu_v2_x.c
index d7e70ef..a252937 100644
--- a/platform/drivers/arm/mhu_driver/mhu_v2_x.c
+++ b/platform/drivers/arm/mhu_driver/mhu_v2_x.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2021 Arm Limited
+ * Copyright (c) 2020-2022 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,7 @@
  */
 #include <stdint.h>
 #include <stdbool.h>
-#include "mhu_v2.h"
+#include "mhu_v2_x.h"
 
 #define _MHU_V2_X_MAX_CHANNELS    124
 #define _MHU_V2_1_MAX_CHCOMB_INT  4
@@ -70,7 +70,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;
@@ -220,6 +220,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 +608,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.h
similarity index 93%
rename from platform/drivers/arm/mhu_driver/mhu_v2.h
rename to platform/drivers/arm/mhu_driver/mhu_v2_x.h
index 26b3a5d..ec0a505 100644
--- a/platform/drivers/arm/mhu_driver/mhu_v2.h
+++ b/platform/drivers/arm/mhu_driver/mhu_v2_x.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2021 Arm Limited
+ * Copyright (c) 2020-2022 Arm Limited
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -49,7 +49,7 @@
 };
 
 struct mhu_v2_x_dev_t {
-    uintptr_t base;
+    const uintptr_t base;
     enum mhu_v2_x_frame_t frame;
     uint32_t subversion;    /*!< Hardware subversion: v2.X */
     bool is_initialized;    /*!< Indicates if the MHU driver
@@ -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_wrapper_v2_x.c b/platform/drivers/arm/mhu_driver/mhu_wrapper_v2_x.c
new file mode 100644
index 0000000..f749f76
--- /dev/null
+++ b/platform/drivers/arm/mhu_driver/mhu_wrapper_v2_x.c
@@ -0,0 +1,353 @@
+/*
+ * 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.
+ */
+
+#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 = mhu_v2_x_get_num_channel_implemented(dev);
+    uint32_t val, i;
+
+    /* 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 = mhu_v2_x_get_num_channel_implemented(dev);
+    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;
+    }
+
+    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 = mhu_v2_x_get_num_channel_implemented(dev);
+    uint32_t val;
+
+    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 = mhu_v2_x_get_num_channel_implemented(dev);
+    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;
+    }
+
+    /* 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;
+}