1af26d7d6STamas Ban /* 2af26d7d6STamas Ban * Copyright (c) 2022, Arm Limited. All rights reserved. 3af26d7d6STamas Ban * 4af26d7d6STamas Ban * SPDX-License-Identifier: BSD-3-Clause 5af26d7d6STamas Ban */ 6af26d7d6STamas Ban 7af26d7d6STamas Ban #include <assert.h> 8af26d7d6STamas Ban #include <stddef.h> 9af26d7d6STamas Ban #include <stdint.h> 10af26d7d6STamas Ban #include <string.h> 11af26d7d6STamas Ban 12af26d7d6STamas Ban #include <drivers/arm/mhu.h> 13af26d7d6STamas Ban 14af26d7d6STamas Ban #include "mhu_v2_x.h" 15af26d7d6STamas Ban 16af26d7d6STamas Ban #define MHU_NOTIFY_VALUE (1234u) 17af26d7d6STamas Ban 18af26d7d6STamas Ban /* 19af26d7d6STamas Ban * MHU devices for host: 20af26d7d6STamas Ban * HSE: Host to Secure Enclave (sender device) 21af26d7d6STamas Ban * SEH: Secure Enclave to Host (receiver device) 22af26d7d6STamas Ban */ 23af26d7d6STamas Ban struct mhu_v2_x_dev_t MHU1_HSE_DEV = {0, MHU_V2_X_SENDER_FRAME}; 24af26d7d6STamas Ban struct mhu_v2_x_dev_t MHU1_SEH_DEV = {0, MHU_V2_X_RECEIVER_FRAME}; 25af26d7d6STamas Ban 26af26d7d6STamas Ban static enum mhu_error_t error_mapping_to_mhu_error_t(enum mhu_v2_x_error_t err) 27af26d7d6STamas Ban { 28af26d7d6STamas Ban switch (err) { 29af26d7d6STamas Ban case MHU_V_2_X_ERR_NONE: 30af26d7d6STamas Ban return MHU_ERR_NONE; 31af26d7d6STamas Ban case MHU_V_2_X_ERR_NOT_INIT: 32af26d7d6STamas Ban return MHU_ERR_NOT_INIT; 33af26d7d6STamas Ban case MHU_V_2_X_ERR_ALREADY_INIT: 34af26d7d6STamas Ban return MHU_ERR_ALREADY_INIT; 35af26d7d6STamas Ban case MHU_V_2_X_ERR_UNSUPPORTED_VERSION: 36af26d7d6STamas Ban return MHU_ERR_UNSUPPORTED_VERSION; 37af26d7d6STamas Ban case MHU_V_2_X_ERR_INVALID_ARG: 38af26d7d6STamas Ban return MHU_ERR_INVALID_ARG; 39af26d7d6STamas Ban case MHU_V_2_X_ERR_GENERAL: 40af26d7d6STamas Ban return MHU_ERR_GENERAL; 41af26d7d6STamas Ban default: 42af26d7d6STamas Ban return MHU_ERR_GENERAL; 43af26d7d6STamas Ban } 44af26d7d6STamas Ban } 45af26d7d6STamas Ban 46af26d7d6STamas Ban static enum mhu_v2_x_error_t signal_and_wait_for_clear(void) 47af26d7d6STamas Ban { 48af26d7d6STamas Ban enum mhu_v2_x_error_t err; 49af26d7d6STamas Ban struct mhu_v2_x_dev_t *dev = &MHU1_HSE_DEV; 50af26d7d6STamas Ban uint32_t val = MHU_NOTIFY_VALUE; 51af26d7d6STamas Ban /* Using the last channel for notifications */ 52af26d7d6STamas Ban uint32_t channel_notify = mhu_v2_x_get_num_channel_implemented(dev) - 1; 53af26d7d6STamas Ban 54af26d7d6STamas Ban err = mhu_v2_x_channel_send(dev, channel_notify, val); 55af26d7d6STamas Ban if (err != MHU_V_2_X_ERR_NONE) { 56af26d7d6STamas Ban return err; 57af26d7d6STamas Ban } 58af26d7d6STamas Ban 59af26d7d6STamas Ban do { 60af26d7d6STamas Ban err = mhu_v2_x_channel_poll(dev, channel_notify, &val); 61af26d7d6STamas Ban if (err != MHU_V_2_X_ERR_NONE) { 62af26d7d6STamas Ban break; 63af26d7d6STamas Ban } 64af26d7d6STamas Ban } while (val != 0); 65af26d7d6STamas Ban 66af26d7d6STamas Ban return err; 67af26d7d6STamas Ban } 68af26d7d6STamas Ban 69af26d7d6STamas Ban static enum mhu_v2_x_error_t wait_for_signal(void) 70af26d7d6STamas Ban { 71af26d7d6STamas Ban enum mhu_v2_x_error_t err; 72af26d7d6STamas Ban struct mhu_v2_x_dev_t *dev = &MHU1_SEH_DEV; 73af26d7d6STamas Ban uint32_t val = 0; 74af26d7d6STamas Ban /* Using the last channel for notifications */ 75af26d7d6STamas Ban uint32_t channel_notify = mhu_v2_x_get_num_channel_implemented(dev) - 1; 76af26d7d6STamas Ban 77af26d7d6STamas Ban do { 78af26d7d6STamas Ban err = mhu_v2_x_channel_receive(dev, channel_notify, &val); 79af26d7d6STamas Ban if (err != MHU_V_2_X_ERR_NONE) { 80af26d7d6STamas Ban break; 81af26d7d6STamas Ban } 82af26d7d6STamas Ban } while (val != MHU_NOTIFY_VALUE); 83af26d7d6STamas Ban 84af26d7d6STamas Ban return err; 85af26d7d6STamas Ban } 86af26d7d6STamas Ban 87af26d7d6STamas Ban static enum mhu_v2_x_error_t clear_and_wait_for_next_signal(void) 88af26d7d6STamas Ban { 89af26d7d6STamas Ban enum mhu_v2_x_error_t err; 90af26d7d6STamas Ban struct mhu_v2_x_dev_t *dev = &MHU1_SEH_DEV; 91af26d7d6STamas Ban uint32_t num_channels = mhu_v2_x_get_num_channel_implemented(dev); 92af26d7d6STamas Ban uint32_t i; 93af26d7d6STamas Ban 94af26d7d6STamas Ban /* Clear all channels */ 95af26d7d6STamas Ban for (i = 0; i < num_channels; ++i) { 96af26d7d6STamas Ban err = mhu_v2_x_channel_clear(dev, i); 97af26d7d6STamas Ban if (err != MHU_V_2_X_ERR_NONE) { 98af26d7d6STamas Ban return err; 99af26d7d6STamas Ban } 100af26d7d6STamas Ban } 101af26d7d6STamas Ban 102af26d7d6STamas Ban return wait_for_signal(); 103af26d7d6STamas Ban } 104af26d7d6STamas Ban 105af26d7d6STamas Ban enum mhu_error_t mhu_init_sender(uintptr_t mhu_sender_base) 106af26d7d6STamas Ban { 107af26d7d6STamas Ban enum mhu_v2_x_error_t err; 108af26d7d6STamas Ban 109af26d7d6STamas Ban assert(mhu_sender_base != (uintptr_t)NULL); 110af26d7d6STamas Ban 111af26d7d6STamas Ban MHU1_HSE_DEV.base = mhu_sender_base; 112af26d7d6STamas Ban 113af26d7d6STamas Ban err = mhu_v2_x_driver_init(&MHU1_HSE_DEV, MHU_REV_READ_FROM_HW); 114af26d7d6STamas Ban return error_mapping_to_mhu_error_t(err); 115af26d7d6STamas Ban } 116af26d7d6STamas Ban 117af26d7d6STamas Ban enum mhu_error_t mhu_init_receiver(uintptr_t mhu_receiver_base) 118af26d7d6STamas Ban { 119af26d7d6STamas Ban enum mhu_v2_x_error_t err; 120af26d7d6STamas Ban uint32_t num_channels, i; 121af26d7d6STamas Ban 122af26d7d6STamas Ban assert(mhu_receiver_base != (uintptr_t)NULL); 123af26d7d6STamas Ban 124af26d7d6STamas Ban MHU1_SEH_DEV.base = mhu_receiver_base; 125af26d7d6STamas Ban 126af26d7d6STamas Ban err = mhu_v2_x_driver_init(&MHU1_SEH_DEV, MHU_REV_READ_FROM_HW); 127af26d7d6STamas Ban if (err != MHU_V_2_X_ERR_NONE) { 128af26d7d6STamas Ban return error_mapping_to_mhu_error_t(err); 129af26d7d6STamas Ban } 130af26d7d6STamas Ban 131af26d7d6STamas Ban num_channels = mhu_v2_x_get_num_channel_implemented(&MHU1_SEH_DEV); 132af26d7d6STamas Ban 133af26d7d6STamas Ban /* Mask all channels except the notifying channel */ 134af26d7d6STamas Ban for (i = 0; i < (num_channels - 1); ++i) { 135af26d7d6STamas Ban err = mhu_v2_x_channel_mask_set(&MHU1_SEH_DEV, i, UINT32_MAX); 136af26d7d6STamas Ban if (err != MHU_V_2_X_ERR_NONE) { 137af26d7d6STamas Ban return error_mapping_to_mhu_error_t(err); 138af26d7d6STamas Ban } 139af26d7d6STamas Ban } 140af26d7d6STamas Ban 141af26d7d6STamas Ban /* The last channel is used for notifications */ 142af26d7d6STamas Ban err = mhu_v2_x_channel_mask_clear( 143af26d7d6STamas Ban &MHU1_SEH_DEV, (num_channels - 1), UINT32_MAX); 144af26d7d6STamas Ban return error_mapping_to_mhu_error_t(err); 145af26d7d6STamas Ban } 146af26d7d6STamas Ban 147af26d7d6STamas Ban /* 148af26d7d6STamas Ban * Public function. See mhu.h 149af26d7d6STamas Ban * 150af26d7d6STamas Ban * The basic steps of transferring a message: 151af26d7d6STamas Ban * 1. Initiate MHU transfer. 152af26d7d6STamas Ban * 2. Send over the size of the payload on Channel 1. It is the very first 153af26d7d6STamas Ban * 4 Bytes of the transfer. Continue with Channel 2. 154af26d7d6STamas Ban * 3. Send over the payload, writing the channels one after the other 155af26d7d6STamas Ban * (4 Bytes each). The last available channel is reserved for controlling 156af26d7d6STamas Ban * the transfer. 157af26d7d6STamas Ban * When the last channel is reached or no more data is left, STOP. 158af26d7d6STamas Ban * 4. Notify the receiver using the last channel and wait for acknowledge. 159af26d7d6STamas Ban * If there is still data to transfer, jump to step 3. Otherwise, proceed. 160af26d7d6STamas Ban * 5. Close MHU transfer. 161af26d7d6STamas Ban * 162af26d7d6STamas Ban */ 163af26d7d6STamas Ban enum mhu_error_t mhu_send_data(const uint8_t *send_buffer, size_t size) 164af26d7d6STamas Ban { 165af26d7d6STamas Ban enum mhu_v2_x_error_t err; 166af26d7d6STamas Ban struct mhu_v2_x_dev_t *dev = &MHU1_HSE_DEV; 167af26d7d6STamas Ban uint32_t num_channels = mhu_v2_x_get_num_channel_implemented(dev); 168af26d7d6STamas Ban uint32_t chan = 0; 169af26d7d6STamas Ban uint32_t i; 170af26d7d6STamas Ban uint32_t *p; 171af26d7d6STamas Ban 172af26d7d6STamas Ban /* For simplicity, require the send_buffer to be 4-byte aligned */ 173af26d7d6STamas Ban if ((uintptr_t)send_buffer & 0x3U) { 174af26d7d6STamas Ban return MHU_ERR_INVALID_ARG; 175af26d7d6STamas Ban } 176af26d7d6STamas Ban 177af26d7d6STamas Ban err = mhu_v2_x_initiate_transfer(dev); 178af26d7d6STamas Ban if (err != MHU_V_2_X_ERR_NONE) { 179af26d7d6STamas Ban return error_mapping_to_mhu_error_t(err); 180af26d7d6STamas Ban } 181af26d7d6STamas Ban 182af26d7d6STamas Ban /* First send over the size of the actual message */ 183af26d7d6STamas Ban err = mhu_v2_x_channel_send(dev, chan, (uint32_t)size); 184af26d7d6STamas Ban if (err != MHU_V_2_X_ERR_NONE) { 185af26d7d6STamas Ban return error_mapping_to_mhu_error_t(err); 186af26d7d6STamas Ban } 187af26d7d6STamas Ban chan++; 188af26d7d6STamas Ban 189af26d7d6STamas Ban p = (uint32_t *)send_buffer; 190af26d7d6STamas Ban for (i = 0; i < size; i += 4) { 191af26d7d6STamas Ban err = mhu_v2_x_channel_send(dev, chan, *p++); 192af26d7d6STamas Ban if (err != MHU_V_2_X_ERR_NONE) { 193af26d7d6STamas Ban return error_mapping_to_mhu_error_t(err); 194af26d7d6STamas Ban } 195af26d7d6STamas Ban if (++chan == (num_channels - 1)) { 196af26d7d6STamas Ban err = signal_and_wait_for_clear(); 197af26d7d6STamas Ban if (err != MHU_V_2_X_ERR_NONE) { 198af26d7d6STamas Ban return error_mapping_to_mhu_error_t(err); 199af26d7d6STamas Ban } 200af26d7d6STamas Ban chan = 0; 201af26d7d6STamas Ban } 202af26d7d6STamas Ban } 203af26d7d6STamas Ban 204af26d7d6STamas Ban /* Signal the end of transfer. 205af26d7d6STamas Ban * It's not required to send a signal when the message was 206af26d7d6STamas Ban * perfectly-aligned (num_channels - 1 channels were used in the last 207af26d7d6STamas Ban * round) preventing it from signaling twice at the end of transfer. 208af26d7d6STamas Ban */ 209af26d7d6STamas Ban if (chan != 0) { 210af26d7d6STamas Ban err = signal_and_wait_for_clear(); 211af26d7d6STamas Ban if (err != MHU_V_2_X_ERR_NONE) { 212af26d7d6STamas Ban return error_mapping_to_mhu_error_t(err); 213af26d7d6STamas Ban } 214af26d7d6STamas Ban } 215af26d7d6STamas Ban 216af26d7d6STamas Ban err = mhu_v2_x_close_transfer(dev); 217af26d7d6STamas Ban return error_mapping_to_mhu_error_t(err); 218af26d7d6STamas Ban } 219af26d7d6STamas Ban 220af26d7d6STamas Ban /* 221af26d7d6STamas Ban * Public function. See mhu.h 222af26d7d6STamas Ban * 223af26d7d6STamas Ban * The basic steps of receiving a message: 224af26d7d6STamas Ban * 1. Read the size of the payload from Channel 1. It is the very first 225af26d7d6STamas Ban * 4 Bytes of the transfer. Continue with Channel 2. 226af26d7d6STamas Ban * 2. Receive the payload, read the channels one after the other 227af26d7d6STamas Ban * (4 Bytes each). The last available channel is reserved for controlling 228af26d7d6STamas Ban * the transfer. 229af26d7d6STamas Ban * When the last channel is reached clear all the channels 230af26d7d6STamas Ban * (also sending an acknowledge on the last channel). 231af26d7d6STamas Ban * 3. If there is still data to receive wait for a notification on the last 232af26d7d6STamas Ban * channel and jump to step 2 as soon as it arrived. Otherwise, proceed. 233af26d7d6STamas Ban * 4. End of transfer. 234af26d7d6STamas Ban * 235af26d7d6STamas Ban */ 236af26d7d6STamas Ban enum mhu_error_t mhu_receive_data(uint8_t *receive_buffer, size_t *size) 237af26d7d6STamas Ban { 238af26d7d6STamas Ban enum mhu_v2_x_error_t err; 239af26d7d6STamas Ban struct mhu_v2_x_dev_t *dev = &MHU1_SEH_DEV; 240af26d7d6STamas Ban uint32_t num_channels = mhu_v2_x_get_num_channel_implemented(dev); 241af26d7d6STamas Ban uint32_t chan = 0; 242af26d7d6STamas Ban uint32_t message_len; 243af26d7d6STamas Ban uint32_t i; 244af26d7d6STamas Ban uint32_t *p; 245af26d7d6STamas Ban 246af26d7d6STamas Ban /* For simplicity, require: 247af26d7d6STamas Ban * - the receive_buffer to be 4-byte aligned, 248af26d7d6STamas Ban * - the buffer size to be a multiple of 4. 249af26d7d6STamas Ban */ 250af26d7d6STamas Ban if (((uintptr_t)receive_buffer & 0x3U) || (*size & 0x3U)) { 251af26d7d6STamas Ban return MHU_ERR_INVALID_ARG; 252af26d7d6STamas Ban } 253af26d7d6STamas Ban 254af26d7d6STamas Ban /* Busy wait for incoming reply */ 255af26d7d6STamas Ban err = wait_for_signal(); 256af26d7d6STamas Ban if (err != MHU_V_2_X_ERR_NONE) { 257af26d7d6STamas Ban return error_mapping_to_mhu_error_t(err); 258af26d7d6STamas Ban } 259af26d7d6STamas Ban 260af26d7d6STamas Ban /* The first word is the length of the actual message */ 261af26d7d6STamas Ban err = mhu_v2_x_channel_receive(dev, chan, &message_len); 262af26d7d6STamas Ban if (err != MHU_V_2_X_ERR_NONE) { 263af26d7d6STamas Ban return error_mapping_to_mhu_error_t(err); 264af26d7d6STamas Ban } 265af26d7d6STamas Ban chan++; 266af26d7d6STamas Ban 267af26d7d6STamas Ban if (message_len > *size) { 268af26d7d6STamas Ban /* Message buffer too small */ 269af26d7d6STamas Ban *size = message_len; 270af26d7d6STamas Ban return MHU_ERR_BUFFER_TOO_SMALL; 271af26d7d6STamas Ban } 272af26d7d6STamas Ban 273af26d7d6STamas Ban p = (uint32_t *)receive_buffer; 274af26d7d6STamas Ban for (i = 0; i < message_len; i += 4) { 275af26d7d6STamas Ban err = mhu_v2_x_channel_receive(dev, chan, p++); 276af26d7d6STamas Ban if (err != MHU_V_2_X_ERR_NONE) { 277af26d7d6STamas Ban return error_mapping_to_mhu_error_t(err); 278af26d7d6STamas Ban } 279af26d7d6STamas Ban 280af26d7d6STamas Ban /* Only wait for next transfer if there is still missing data */ 281af26d7d6STamas Ban if (++chan == (num_channels - 1) && (message_len - i) > 4) { 282af26d7d6STamas Ban /* Busy wait for next transfer */ 283af26d7d6STamas Ban err = clear_and_wait_for_next_signal(); 284af26d7d6STamas Ban if (err != MHU_V_2_X_ERR_NONE) { 285af26d7d6STamas Ban return error_mapping_to_mhu_error_t(err); 286af26d7d6STamas Ban } 287af26d7d6STamas Ban chan = 0; 288af26d7d6STamas Ban } 289af26d7d6STamas Ban } 290af26d7d6STamas Ban 291af26d7d6STamas Ban /* Clear all channels */ 292af26d7d6STamas Ban for (i = 0; i < num_channels; ++i) { 293af26d7d6STamas Ban err = mhu_v2_x_channel_clear(dev, i); 294af26d7d6STamas Ban if (err != MHU_V_2_X_ERR_NONE) { 295af26d7d6STamas Ban return error_mapping_to_mhu_error_t(err); 296af26d7d6STamas Ban } 297af26d7d6STamas Ban } 298af26d7d6STamas Ban 299af26d7d6STamas Ban *size = message_len; 300af26d7d6STamas Ban 301af26d7d6STamas Ban return MHU_ERR_NONE; 302af26d7d6STamas Ban } 30331259019SRaef Coles 30431259019SRaef Coles size_t mhu_get_max_message_size(void) 30531259019SRaef Coles { 30631259019SRaef Coles struct mhu_v2_x_dev_t *dev = &MHU1_SEH_DEV; 30731259019SRaef Coles uint32_t num_channels = mhu_v2_x_get_num_channel_implemented(dev); 30831259019SRaef Coles 30931259019SRaef Coles assert(num_channels != 0); 31031259019SRaef Coles 311*5cd10848SSathyam Panda /* 312*5cd10848SSathyam Panda * Returns only usable size of memory. As one channel is specifically 313*5cd10848SSathyam Panda * used to inform about the size of payload, discard it from avialable 314*5cd10848SSathyam Panda * memory size. 315*5cd10848SSathyam Panda */ 316*5cd10848SSathyam Panda return (num_channels - 1) * sizeof(uint32_t); 31731259019SRaef Coles } 318