1 /* 2 * Copyright (c) 2024, Arm Limited and Contributors. All rights reserved. 3 * 4 * SPDX-License-Identifier: BSD-3-Clause 5 */ 6 7 #include <assert.h> 8 #include <stddef.h> 9 #include <stdint.h> 10 #include <string.h> 11 12 #include <drivers/arm/mhu.h> 13 14 #include "mhu_v3_x.h" 15 16 #define MHU_NOTIFY_VALUE U(1234) 17 18 #ifndef ALIGN_UP 19 #define ALIGN_UP(num, align) (((num) + ((align) - 1)) & ~((align) - 1)) 20 #endif 21 22 /* 23 * MHUv3 Wrapper utility macros 24 */ 25 #define IS_ALIGNED(val, align) (val == ALIGN_UP(val, align)) 26 27 /* 28 * MHU devices for host: 29 * HSE: Host to Secure Enclave (sender device) 30 * SEH: Secure Enclave to Host (receiver device) 31 */ 32 struct mhu_v3_x_dev_t mhu_hse_dev = {0, MHU_V3_X_PBX_FRAME}; 33 struct mhu_v3_x_dev_t mhu_seh_dev = {0, MHU_V3_X_MBX_FRAME}; 34 35 /* MHUv3 driver error to MHUv3 wrapper error mapping */ 36 static enum mhu_error_t error_mapping_to_mhu_error_t(enum mhu_v3_x_error_t err) 37 { 38 switch (err) { 39 case MHU_V_3_X_ERR_NONE: 40 return MHU_ERR_NONE; 41 42 case MHU_V_3_X_ERR_NOT_INIT: 43 return MHU_ERR_NOT_INIT; 44 45 case MHU_V_3_X_ERR_UNSUPPORTED_VERSION: 46 return MHU_ERR_UNSUPPORTED_VERSION; 47 48 case MHU_V_3_X_ERR_UNSUPPORTED: 49 return MHU_ERR_UNSUPPORTED; 50 51 case MHU_V_3_X_ERR_INVALID_PARAM: 52 return MHU_ERR_INVALID_ARG; 53 54 default: 55 return MHU_ERR_GENERAL; 56 } 57 } 58 59 static enum mhu_error_t signal_and_wait_for_clear( 60 void *mhu_sender_dev, uint32_t value) 61 { 62 enum mhu_v3_x_error_t err; 63 struct mhu_v3_x_dev_t *dev; 64 uint8_t num_channels; 65 uint32_t read_val; 66 67 dev = (struct mhu_v3_x_dev_t *)mhu_sender_dev; 68 69 if ((dev == NULL) || (dev->base == 0)) { 70 return MHU_ERR_INVALID_ARG; 71 } 72 73 err = mhu_v3_x_get_num_channel_implemented(dev, 74 MHU_V3_X_CHANNEL_TYPE_DBCH, &num_channels); 75 if (err != MHU_V_3_X_ERR_NONE) { 76 return error_mapping_to_mhu_error_t(err); 77 } 78 79 /* Wait for any pending acknowledgment from transmitter side */ 80 do { 81 err = mhu_v3_x_doorbell_read(dev, num_channels - 1, &read_val); 82 if (err != MHU_V_3_X_ERR_NONE) { 83 return error_mapping_to_mhu_error_t(err); 84 } 85 } while ((read_val & value) == value); 86 87 /* Use the last channel to notify that a transfer is ready */ 88 err = mhu_v3_x_doorbell_write(dev, num_channels - 1, value); 89 if (err != MHU_V_3_X_ERR_NONE) { 90 return error_mapping_to_mhu_error_t(err); 91 } 92 93 /* Wait until receiver side acknowledges the transfer */ 94 do { 95 err = mhu_v3_x_doorbell_read(dev, num_channels - 1, &read_val); 96 if (err != MHU_V_3_X_ERR_NONE) { 97 return error_mapping_to_mhu_error_t(err); 98 } 99 } while ((read_val & value) == value); 100 101 return error_mapping_to_mhu_error_t(MHU_V_3_X_ERR_NONE); 102 } 103 104 static enum mhu_error_t wait_for_signal( 105 void *mhu_receiver_dev, uint32_t value) 106 { 107 enum mhu_v3_x_error_t err; 108 struct mhu_v3_x_dev_t *dev; 109 uint32_t read_val; 110 uint8_t num_channels; 111 112 dev = (struct mhu_v3_x_dev_t *)mhu_receiver_dev; 113 114 if ((dev == NULL) || (dev->base == 0)) { 115 return MHU_ERR_INVALID_ARG; 116 } 117 118 err = mhu_v3_x_get_num_channel_implemented(dev, 119 MHU_V3_X_CHANNEL_TYPE_DBCH, &num_channels); 120 if (err != MHU_V_3_X_ERR_NONE) { 121 return error_mapping_to_mhu_error_t(err); 122 } 123 124 do { 125 err = mhu_v3_x_doorbell_read(dev, num_channels - 1, &read_val); 126 if (err != MHU_V_3_X_ERR_NONE) { 127 return error_mapping_to_mhu_error_t(err); 128 } 129 } while (read_val != value); 130 131 return error_mapping_to_mhu_error_t(err); 132 } 133 134 static enum mhu_error_t clear_and_wait_for_signal( 135 void *mhu_receiver_dev, uint32_t value) 136 { 137 enum mhu_v3_x_error_t err; 138 struct mhu_v3_x_dev_t *dev; 139 uint8_t num_channels; 140 141 dev = (struct mhu_v3_x_dev_t *)mhu_receiver_dev; 142 143 if ((dev == NULL) || (dev->base == 0)) { 144 return MHU_ERR_INVALID_ARG; 145 } 146 147 err = mhu_v3_x_get_num_channel_implemented(dev, 148 MHU_V3_X_CHANNEL_TYPE_DBCH, &num_channels); 149 if (err != MHU_V_3_X_ERR_NONE) { 150 return error_mapping_to_mhu_error_t(err); 151 } 152 153 /* Clear all channels */ 154 for (int i = 0; i < num_channels; i++) { 155 err = mhu_v3_x_doorbell_clear(dev, i, UINT32_MAX); 156 if (err != MHU_V_3_X_ERR_NONE) { 157 return error_mapping_to_mhu_error_t(err); 158 } 159 } 160 161 return wait_for_signal(mhu_receiver_dev, value); 162 } 163 164 static enum mhu_error_t validate_buffer_params(uintptr_t buf_addr) 165 { 166 if ((buf_addr == 0) || (!IS_ALIGNED(buf_addr, sizeof(uint32_t)))) { 167 return MHU_ERR_INVALID_ARG; 168 } 169 170 return MHU_ERR_NONE; 171 } 172 173 enum mhu_error_t mhu_init_sender(uintptr_t mhu_sender_base) 174 { 175 enum mhu_v3_x_error_t err; 176 struct mhu_v3_x_dev_t *dev; 177 uint8_t num_ch; 178 uint32_t ch; 179 180 assert(mhu_sender_base != (uintptr_t)NULL); 181 182 mhu_hse_dev.base = mhu_sender_base; 183 dev = (struct mhu_v3_x_dev_t *)&mhu_hse_dev; 184 185 /* Initialize MHUv3 */ 186 err = mhu_v3_x_driver_init(dev); 187 if (err != MHU_V_3_X_ERR_NONE) { 188 return error_mapping_to_mhu_error_t(err); 189 } 190 191 /* Read the number of doorbell channels implemented in the MHU */ 192 err = mhu_v3_x_get_num_channel_implemented( 193 dev, MHU_V3_X_CHANNEL_TYPE_DBCH, &num_ch); 194 if (err != MHU_V_3_X_ERR_NONE) { 195 return error_mapping_to_mhu_error_t(err); 196 } else if (num_ch < 2) { 197 /* This wrapper requires at least two channels implemented */ 198 return MHU_ERR_UNSUPPORTED; 199 } 200 201 /* 202 * The sender polls the postbox doorbell channel window status register 203 * to get notified about successful transfer. So, disable the doorbell 204 * channel's contribution to postbox combined interrupt. 205 * 206 * Also, clear and disable the postbox doorbell channel transfer 207 * acknowledge interrupt. 208 */ 209 for (ch = 0; ch < num_ch; ch++) { 210 err = mhu_v3_x_channel_interrupt_disable( 211 dev, ch, MHU_V3_X_CHANNEL_TYPE_DBCH); 212 if (err != MHU_V_3_X_ERR_NONE) { 213 return error_mapping_to_mhu_error_t(err); 214 } 215 } 216 217 return MHU_ERR_NONE; 218 } 219 220 enum mhu_error_t mhu_init_receiver(uintptr_t mhu_receiver_base) 221 { 222 enum mhu_v3_x_error_t err; 223 struct mhu_v3_x_dev_t *dev; 224 uint32_t ch; 225 uint8_t num_ch; 226 227 assert(mhu_receiver_base != (uintptr_t)NULL); 228 229 mhu_seh_dev.base = mhu_receiver_base; 230 dev = (struct mhu_v3_x_dev_t *)&mhu_seh_dev; 231 232 /* Initialize MHUv3 */ 233 err = mhu_v3_x_driver_init(dev); 234 if (err != MHU_V_3_X_ERR_NONE) { 235 return error_mapping_to_mhu_error_t(err); 236 } 237 238 /* Read the number of doorbell channels implemented in the MHU */ 239 err = mhu_v3_x_get_num_channel_implemented( 240 dev, MHU_V3_X_CHANNEL_TYPE_DBCH, &num_ch); 241 if (err != MHU_V_3_X_ERR_NONE) { 242 return error_mapping_to_mhu_error_t(err); 243 } else if (num_ch < 2) { 244 /* This wrapper requires at least two channels implemented */ 245 return MHU_ERR_UNSUPPORTED; 246 } 247 248 /* Mask all channels except the notifying channel */ 249 for (ch = 0; ch < (num_ch - 1); ch++) { 250 /* Mask interrupts on channels used for data */ 251 err = mhu_v3_x_doorbell_mask_set(dev, ch, UINT32_MAX); 252 if (err != MHU_V_3_X_ERR_NONE) { 253 return error_mapping_to_mhu_error_t(err); 254 } 255 } 256 257 /* Unmask doorbell notification channel interrupt */ 258 err = mhu_v3_x_doorbell_mask_clear(dev, (num_ch - 1), UINT32_MAX); 259 if (err != MHU_V_3_X_ERR_NONE) { 260 return error_mapping_to_mhu_error_t(err); 261 } 262 263 /* 264 * Enable the doorbell channel's contribution to mailbox combined 265 * interrupt. 266 */ 267 err = mhu_v3_x_channel_interrupt_enable(dev, (num_ch - 1), 268 MHU_V3_X_CHANNEL_TYPE_DBCH); 269 if (err != MHU_V_3_X_ERR_NONE) { 270 return error_mapping_to_mhu_error_t(err); 271 } 272 273 return MHU_ERR_NONE; 274 } 275 276 /* 277 * Public function. See mhu.h 278 * 279 * The basic steps of transferring a message: 280 * 1. Send the size of the payload on Channel 0. It is the very first Bytes of 281 * the transfer. Continue with Channel 1. 282 * 2. Send the payload, writing the channels one after the other (4 Bytes 283 * each). The last available channel is reserved for controlling the 284 * transfer. When the last channel is reached or no more data is left, STOP. 285 * 3. Notify the receiver using the last channel and wait for acknowledge. If 286 * there is still data to transfer, jump to step 2. Otherwise, proceed. 287 * 288 */ 289 enum mhu_error_t mhu_send_data(const uint8_t *send_buffer, size_t size) 290 { 291 enum mhu_error_t mhu_err; 292 enum mhu_v3_x_error_t mhu_v3_err; 293 uint8_t num_channels; 294 uint8_t chan; 295 uint32_t *buffer; 296 struct mhu_v3_x_dev_t *dev; 297 298 if (size == 0) { 299 return MHU_ERR_NONE; 300 } 301 302 dev = (struct mhu_v3_x_dev_t *)&mhu_hse_dev; 303 chan = 0; 304 305 if ((dev == NULL) || (dev->base == 0)) { 306 return MHU_ERR_INVALID_ARG; 307 } 308 309 mhu_err = validate_buffer_params((uintptr_t)send_buffer); 310 if (mhu_err != MHU_ERR_NONE) { 311 return mhu_err; 312 } 313 314 mhu_v3_err = mhu_v3_x_get_num_channel_implemented(dev, 315 MHU_V3_X_CHANNEL_TYPE_DBCH, &num_channels); 316 if (mhu_v3_err != MHU_V_3_X_ERR_NONE) { 317 return error_mapping_to_mhu_error_t(mhu_v3_err); 318 } 319 320 /* First send the size of the actual message. */ 321 mhu_v3_err = mhu_v3_x_doorbell_write(dev, chan, (uint32_t)size); 322 if (mhu_v3_err != MHU_V_3_X_ERR_NONE) { 323 return error_mapping_to_mhu_error_t(mhu_v3_err); 324 } 325 chan++; 326 327 buffer = (uint32_t *)send_buffer; 328 for (size_t i = 0; i < size; i += 4) { 329 mhu_v3_err = mhu_v3_x_doorbell_write(dev, chan, *buffer++); 330 if (mhu_v3_err != MHU_V_3_X_ERR_NONE) { 331 return error_mapping_to_mhu_error_t(mhu_v3_err); 332 } 333 334 if (++chan == (num_channels - 1)) { 335 /* Use the last channel to notify transfer complete */ 336 mhu_err = signal_and_wait_for_clear( 337 dev, MHU_NOTIFY_VALUE); 338 if (mhu_err != MHU_ERR_NONE) { 339 return mhu_err; 340 } 341 chan = 0; 342 } 343 } 344 345 if (chan != 0) { 346 /* Use the last channel to notify transfer complete */ 347 mhu_err = signal_and_wait_for_clear(dev, MHU_NOTIFY_VALUE); 348 if (mhu_err != MHU_ERR_NONE) { 349 return mhu_err; 350 } 351 } 352 353 return MHU_ERR_NONE; 354 } 355 356 /* 357 * Public function. See mhu.h 358 * 359 * The basic steps of receiving a message: 360 * 1. Read the size of the payload from Channel 0. It is the very first 361 * 4 Bytes of the transfer. Continue with Channel 1. 362 * 2. Receive the payload, read the channels one after the other 363 * (4 Bytes each). The last available channel is reserved for controlling 364 * the transfer. 365 * When the last channel is reached clear all the channels 366 * (also sending an acknowledge on the last channel). 367 * 3. If there is still data to receive wait for a notification on the last 368 * channel and jump to step 2 as soon as it arrived. Otherwise, proceed. 369 * 370 */ 371 enum mhu_error_t mhu_receive_data(uint8_t *receive_buffer, size_t *size) 372 { 373 enum mhu_error_t mhu_err; 374 enum mhu_v3_x_error_t mhu_v3_err; 375 uint32_t msg_len; 376 uint8_t num_channels; 377 uint8_t chan; 378 uint32_t *buffer; 379 struct mhu_v3_x_dev_t *dev; 380 381 dev = (struct mhu_v3_x_dev_t *)&mhu_seh_dev; 382 chan = 0; 383 384 mhu_err = validate_buffer_params((uintptr_t)receive_buffer); 385 if (mhu_err != MHU_ERR_NONE) { 386 return mhu_err; 387 } 388 389 mhu_v3_err = mhu_v3_x_get_num_channel_implemented(dev, 390 MHU_V3_X_CHANNEL_TYPE_DBCH, &num_channels); 391 if (mhu_v3_err != MHU_V_3_X_ERR_NONE) { 392 return error_mapping_to_mhu_error_t(mhu_v3_err); 393 } 394 395 /* Busy wait for incoming reply */ 396 mhu_err = wait_for_signal(dev, MHU_NOTIFY_VALUE); 397 if (mhu_err != MHU_ERR_NONE) { 398 return mhu_err; 399 } 400 401 /* The first word is the length of the actual message. */ 402 mhu_v3_err = mhu_v3_x_doorbell_read(dev, chan, &msg_len); 403 if (mhu_v3_err != MHU_V_3_X_ERR_NONE) { 404 return error_mapping_to_mhu_error_t(mhu_v3_err); 405 } 406 chan++; 407 408 if (*size < msg_len) { 409 /* Message buffer too small */ 410 *size = msg_len; 411 return MHU_ERR_BUFFER_TOO_SMALL; 412 } 413 414 buffer = (uint32_t *)receive_buffer; 415 for (size_t i = 0; i < msg_len; i += 4) { 416 mhu_v3_err = mhu_v3_x_doorbell_read(dev, chan, buffer++); 417 if (mhu_v3_err != MHU_V_3_X_ERR_NONE) { 418 return error_mapping_to_mhu_error_t(mhu_v3_err); 419 } 420 421 /* Only wait for next transfer if still missing data. */ 422 if (++chan == (num_channels - 1) && (msg_len - i) > 4) { 423 /* Busy wait for next transfer */ 424 mhu_err = clear_and_wait_for_signal( 425 dev, MHU_NOTIFY_VALUE); 426 if (mhu_err != MHU_ERR_NONE) { 427 return mhu_err; 428 } 429 chan = 0; 430 } 431 } 432 433 /* Clear all channels */ 434 for (uint8_t i = U(0); i < num_channels; i++) { 435 mhu_v3_err = mhu_v3_x_doorbell_clear(dev, i, UINT32_MAX); 436 if (mhu_v3_err != MHU_V_3_X_ERR_NONE) { 437 return error_mapping_to_mhu_error_t(mhu_v3_err); 438 } 439 } 440 441 *size = msg_len; 442 443 return MHU_ERR_NONE; 444 } 445 446 size_t mhu_get_max_message_size(void) 447 { 448 enum mhu_v3_x_error_t err; 449 uint8_t num_channels; 450 451 err = mhu_v3_x_get_num_channel_implemented(&mhu_seh_dev, 452 MHU_V3_X_CHANNEL_TYPE_DBCH, &num_channels); 453 454 assert(err == MHU_V_3_X_ERR_NONE); 455 assert(num_channels != U(0)); 456 /* 457 * Returns only usable size of memory. As one channel is specifically 458 * used to inform about the size of payload, discard it from available 459 * memory size. 460 */ 461 return (num_channels - 1) * sizeof(uint32_t); 462 } 463