1 // SPDX-License-Identifier: BSD-2-Clause 2 /* 3 * Copyright 2022 NXP 4 */ 5 #include <assert.h> 6 #include <drivers/imx_mu.h> 7 #include <kernel/delay.h> 8 #include <kernel/spinlock.h> 9 #include <string.h> 10 #include <trace.h> 11 12 #include "imx_mu_platform.h" 13 14 #define RX_TIMEOUT (100 * 1000) 15 16 static unsigned int mu_spinlock = SPINLOCK_UNLOCK; 17 18 __weak void imx_mu_plat_init(vaddr_t base __unused) 19 { 20 } 21 22 __weak TEE_Result imx_mu_plat_send(vaddr_t base __unused, 23 unsigned int index __unused, 24 uint32_t msg __unused) 25 { 26 return TEE_ERROR_NOT_IMPLEMENTED; 27 } 28 29 __weak TEE_Result imx_mu_plat_receive(vaddr_t base __unused, 30 unsigned int index __unused, 31 uint32_t *msg __unused) 32 { 33 return TEE_ERROR_NOT_IMPLEMENTED; 34 } 35 36 /* 37 * Receive a message via the MU 38 * 39 * @base: virtual base address of the MU controller 40 * @[out]msg: message received 41 */ 42 static TEE_Result imx_mu_receive_msg(vaddr_t base, struct imx_mu_msg *msg) 43 { 44 TEE_Result res = TEE_ERROR_GENERIC; 45 unsigned int count = 0; 46 uint32_t response = 0; 47 unsigned int nb_channel = 0; 48 uint64_t tout_rx = timeout_init_us(RX_TIMEOUT); 49 50 assert(base && msg); 51 52 do { 53 res = imx_mu_plat_receive(base, 0, &response); 54 if (timeout_elapsed(tout_rx)) 55 break; 56 } while (res == TEE_ERROR_NO_DATA); 57 58 if (res) 59 return res; 60 61 memcpy(&msg->header, &response, sizeof(response)); 62 63 /* Check the size of the message to receive */ 64 if (msg->header.size > IMX_MU_MSG_SIZE) { 65 EMSG("Size of the message is > than IMX_MU_MSG_SIZE"); 66 return TEE_ERROR_BAD_FORMAT; 67 } 68 69 nb_channel = imx_mu_plat_get_rx_channel(); 70 71 for (count = 1; count < msg->header.size; count++) { 72 res = imx_mu_plat_receive(base, count % nb_channel, 73 &msg->data.u32[count - 1]); 74 if (res) 75 return res; 76 } 77 78 return TEE_SUCCESS; 79 } 80 81 /* 82 * Send a message via the MU 83 * 84 * @base: virtual base address of the MU controller 85 * @[in]msg: message to send 86 */ 87 static TEE_Result imx_mu_send_msg(vaddr_t base, struct imx_mu_msg *msg) 88 { 89 TEE_Result res = TEE_ERROR_GENERIC; 90 unsigned int count = 0; 91 unsigned int nb_channel = 0; 92 uint32_t word = 0; 93 94 assert(base && msg); 95 96 if (msg->header.size > IMX_MU_MSG_SIZE) { 97 EMSG("msg->size is > than IMX_MU_MSG_SIZE"); 98 return TEE_ERROR_BAD_FORMAT; 99 } 100 101 memcpy(&word, &msg->header, sizeof(uint32_t)); 102 res = imx_mu_plat_send(base, 0, word); 103 if (res) 104 return res; 105 106 nb_channel = imx_mu_plat_get_tx_channel(); 107 108 for (count = 1; count < msg->header.size; count++) { 109 res = imx_mu_plat_send(base, count % nb_channel, 110 msg->data.u32[count - 1]); 111 if (res) 112 return res; 113 } 114 115 return TEE_SUCCESS; 116 } 117 118 void imx_mu_init(vaddr_t base) 119 { 120 uint32_t exceptions = 0; 121 122 if (!base) { 123 EMSG("Bad MU base address"); 124 return; 125 } 126 127 exceptions = cpu_spin_lock_xsave(&mu_spinlock); 128 129 imx_mu_plat_init(base); 130 131 cpu_spin_unlock_xrestore(&mu_spinlock, exceptions); 132 } 133 134 TEE_Result imx_mu_call(vaddr_t base, struct imx_mu_msg *msg, 135 bool wait_for_answer) 136 { 137 TEE_Result res = TEE_ERROR_GENERIC; 138 uint32_t exceptions = 0; 139 140 if (!base || !msg) 141 return TEE_ERROR_BAD_PARAMETERS; 142 143 exceptions = cpu_spin_lock_xsave(&mu_spinlock); 144 145 res = imx_mu_send_msg(base, msg); 146 if (res == TEE_SUCCESS && wait_for_answer) 147 res = imx_mu_receive_msg(base, msg); 148 149 cpu_spin_unlock_xrestore(&mu_spinlock, exceptions); 150 151 return res; 152 } 153