xref: /optee_os/core/drivers/imx/mu/imx_mu.c (revision 35e561d87c7e50ccdbb8048ffa10a7f2b14756fb)
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