1 // SPDX-License-Identifier: BSD-2-Clause
2 /*
3 * Copyright 2022-2023, 2025 NXP
4 */
5 #include <assert.h>
6 #include <drivers/imx_mu.h>
7 #include <imx-regs.h>
8 #include <kernel/delay.h>
9 #include <kernel/spinlock.h>
10 #include <string.h>
11 #include <trace.h>
12
13 #include "imx_mu_platform.h"
14
15 #define RX_TIMEOUT (100 * 1000)
16
17 #if defined(CFG_MX93) || defined(CFG_MX91)
18 #define IS_MU_TRUST (MU_BASE == MU_TRUST_BASE)
19 #else
20 #define IS_MU_TRUST false
21 #endif
22
23 static unsigned int mu_spinlock = SPINLOCK_UNLOCK;
24
imx_mu_plat_init(vaddr_t base __unused)25 __weak void imx_mu_plat_init(vaddr_t base __unused)
26 {
27 }
28
imx_mu_plat_send(vaddr_t base __unused,unsigned int index __unused,uint32_t msg __unused)29 __weak TEE_Result imx_mu_plat_send(vaddr_t base __unused,
30 unsigned int index __unused,
31 uint32_t msg __unused)
32 {
33 return TEE_ERROR_NOT_IMPLEMENTED;
34 }
35
imx_mu_plat_receive(vaddr_t base __unused,unsigned int index __unused,uint32_t * msg __unused)36 __weak TEE_Result imx_mu_plat_receive(vaddr_t base __unused,
37 unsigned int index __unused,
38 uint32_t *msg __unused)
39 {
40 return TEE_ERROR_NOT_IMPLEMENTED;
41 }
42
43 /*
44 * Receive a message via the MU
45 *
46 * @base: virtual base address of the MU controller
47 * @[out]msg: message received
48 */
imx_mu_receive_msg(vaddr_t base,struct imx_mu_msg * msg)49 static TEE_Result imx_mu_receive_msg(vaddr_t base, struct imx_mu_msg *msg)
50 {
51 TEE_Result res = TEE_ERROR_GENERIC;
52 unsigned int count = 0;
53 uint32_t response = 0;
54 unsigned int nb_channel = 0;
55 uint64_t tout_rx = timeout_init_us(RX_TIMEOUT);
56
57 assert(base && msg);
58
59 do {
60 res = imx_mu_plat_receive(base, 0, &response);
61 if (timeout_elapsed(tout_rx))
62 break;
63 } while (res == TEE_ERROR_NO_DATA);
64
65 if (res)
66 return res;
67
68 memcpy(&msg->header, &response, sizeof(response));
69
70 /* Check the size of the message to receive */
71 if (msg->header.size > IMX_MU_MSG_SIZE) {
72 EMSG("Size of the message is > than IMX_MU_MSG_SIZE");
73 return TEE_ERROR_BAD_FORMAT;
74 }
75
76 nb_channel = imx_mu_plat_get_rx_channel(base);
77
78 for (count = 1; count < msg->header.size; count++) {
79 res = imx_mu_plat_receive(base, count % nb_channel,
80 &msg->data.u32[count - 1]);
81 if (res)
82 return res;
83 }
84
85 return TEE_SUCCESS;
86 }
87
88 /*
89 * Send a message via the MU
90 *
91 * @base: virtual base address of the MU controller
92 * @[in]msg: message to send
93 */
imx_mu_send_msg(vaddr_t base,struct imx_mu_msg * msg)94 static TEE_Result imx_mu_send_msg(vaddr_t base, struct imx_mu_msg *msg)
95 {
96 TEE_Result res = TEE_ERROR_GENERIC;
97 unsigned int count = 0;
98 unsigned int nb_channel = 0;
99 unsigned int start_index = 0;
100 unsigned int end_index = 0;
101 uint32_t word = 0;
102
103 assert(base && msg);
104
105 if (msg->header.size > IMX_MU_MSG_SIZE) {
106 EMSG("msg->size is > than IMX_MU_MSG_SIZE");
107 return TEE_ERROR_BAD_FORMAT;
108 }
109
110 if (IS_MU_TRUST) {
111 /*
112 * make sure command (bit[31:26]) is higher than SCM_CR2_CMD_VAL
113 * SCM_CR2_CMD_VAL is set to 0 by ELE FW. but let’s use
114 * max value.
115 */
116 word |= GENMASK_32(31, 26);
117
118 /* size (including dummy header) -> bit[19:16]*/
119 word |= SHIFT_U32(((msg->header.size + 1) & GENMASK_32(3, 0)),
120 16);
121
122 res = imx_mu_plat_send(base, start_index, word);
123 if (res)
124 return res;
125
126 start_index++;
127 memcpy(&word, &msg->header, sizeof(uint32_t));
128 res = imx_mu_plat_send(base, start_index, word);
129 if (res)
130 return res;
131
132 start_index++;
133 /*
134 * TR15 is reserved for special USM commands
135 */
136 nb_channel = imx_mu_plat_get_tx_channel(base) - 1;
137 end_index = msg->header.size + 1;
138 assert(end_index < nb_channel);
139 } else {
140 memcpy(&word, &msg->header, sizeof(uint32_t));
141 res = imx_mu_plat_send(base, start_index, word);
142 if (res)
143 return res;
144
145 start_index++;
146 nb_channel = imx_mu_plat_get_tx_channel(base);
147 end_index = msg->header.size;
148 }
149
150 for (count = start_index; count < end_index; count++) {
151 res = imx_mu_plat_send(base, count % nb_channel,
152 msg->data.u32[count - start_index]);
153 if (res)
154 return res;
155 }
156
157 return TEE_SUCCESS;
158 }
159
imx_mu_init(vaddr_t base)160 void imx_mu_init(vaddr_t base)
161 {
162 uint32_t exceptions = 0;
163
164 if (!base) {
165 EMSG("Bad MU base address");
166 return;
167 }
168
169 exceptions = cpu_spin_lock_xsave(&mu_spinlock);
170
171 imx_mu_plat_init(base);
172
173 cpu_spin_unlock_xrestore(&mu_spinlock, exceptions);
174 }
175
imx_mu_call(vaddr_t base,struct imx_mu_msg * msg,bool wait_for_answer)176 TEE_Result imx_mu_call(vaddr_t base, struct imx_mu_msg *msg,
177 bool wait_for_answer)
178 {
179 TEE_Result res = TEE_ERROR_GENERIC;
180 uint32_t exceptions = 0;
181
182 if (!base || !msg)
183 return TEE_ERROR_BAD_PARAMETERS;
184
185 exceptions = cpu_spin_lock_xsave(&mu_spinlock);
186
187 res = imx_mu_send_msg(base, msg);
188 if (res == TEE_SUCCESS && wait_for_answer)
189 res = imx_mu_receive_msg(base, msg);
190
191 cpu_spin_unlock_xrestore(&mu_spinlock, exceptions);
192
193 return res;
194 }
195