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