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