xref: /optee_os/core/drivers/imx/mu/imx_mu.c (revision 35e561d87c7e50ccdbb8048ffa10a7f2b14756fb)
19756bcc4SClement Faure // SPDX-License-Identifier: BSD-2-Clause
29756bcc4SClement Faure /*
3*35e561d8SSahil Malhotra  * Copyright 2022-2023, 2025 NXP
49756bcc4SClement Faure  */
59756bcc4SClement Faure #include <assert.h>
69756bcc4SClement Faure #include <drivers/imx_mu.h>
7*35e561d8SSahil Malhotra #include <imx-regs.h>
89756bcc4SClement Faure #include <kernel/delay.h>
99756bcc4SClement Faure #include <kernel/spinlock.h>
109756bcc4SClement Faure #include <string.h>
119756bcc4SClement Faure #include <trace.h>
129756bcc4SClement Faure 
139756bcc4SClement Faure #include "imx_mu_platform.h"
149756bcc4SClement Faure 
159756bcc4SClement Faure #define RX_TIMEOUT (100 * 1000)
169756bcc4SClement Faure 
17*35e561d8SSahil Malhotra #if defined(CFG_MX93) || defined(CFG_MX91)
18*35e561d8SSahil Malhotra #define IS_MU_TRUST (MU_BASE == MU_TRUST_BASE)
19*35e561d8SSahil Malhotra #else
20*35e561d8SSahil Malhotra #define IS_MU_TRUST false
21*35e561d8SSahil Malhotra #endif
22*35e561d8SSahil Malhotra 
239756bcc4SClement Faure static unsigned int mu_spinlock = SPINLOCK_UNLOCK;
249756bcc4SClement Faure 
imx_mu_plat_init(vaddr_t base __unused)259756bcc4SClement Faure __weak void imx_mu_plat_init(vaddr_t base __unused)
269756bcc4SClement Faure {
279756bcc4SClement Faure }
289756bcc4SClement Faure 
imx_mu_plat_send(vaddr_t base __unused,unsigned int index __unused,uint32_t msg __unused)299756bcc4SClement Faure __weak TEE_Result imx_mu_plat_send(vaddr_t base __unused,
309756bcc4SClement Faure 				   unsigned int index __unused,
319756bcc4SClement Faure 				   uint32_t msg __unused)
329756bcc4SClement Faure {
339756bcc4SClement Faure 	return TEE_ERROR_NOT_IMPLEMENTED;
349756bcc4SClement Faure }
359756bcc4SClement Faure 
imx_mu_plat_receive(vaddr_t base __unused,unsigned int index __unused,uint32_t * msg __unused)369756bcc4SClement Faure __weak TEE_Result imx_mu_plat_receive(vaddr_t base __unused,
379756bcc4SClement Faure 				      unsigned int index __unused,
389756bcc4SClement Faure 				      uint32_t *msg __unused)
399756bcc4SClement Faure {
409756bcc4SClement Faure 	return TEE_ERROR_NOT_IMPLEMENTED;
419756bcc4SClement Faure }
429756bcc4SClement Faure 
439756bcc4SClement Faure /*
449756bcc4SClement Faure  * Receive a message via the MU
459756bcc4SClement Faure  *
469756bcc4SClement Faure  * @base: virtual base address of the MU controller
479756bcc4SClement Faure  * @[out]msg: message received
489756bcc4SClement Faure  */
imx_mu_receive_msg(vaddr_t base,struct imx_mu_msg * msg)499756bcc4SClement Faure static TEE_Result imx_mu_receive_msg(vaddr_t base, struct imx_mu_msg *msg)
509756bcc4SClement Faure {
519756bcc4SClement Faure 	TEE_Result res = TEE_ERROR_GENERIC;
529756bcc4SClement Faure 	unsigned int count = 0;
539756bcc4SClement Faure 	uint32_t response = 0;
549756bcc4SClement Faure 	unsigned int nb_channel = 0;
559756bcc4SClement Faure 	uint64_t tout_rx = timeout_init_us(RX_TIMEOUT);
569756bcc4SClement Faure 
579756bcc4SClement Faure 	assert(base && msg);
589756bcc4SClement Faure 
599756bcc4SClement Faure 	do {
609756bcc4SClement Faure 		res = imx_mu_plat_receive(base, 0, &response);
619756bcc4SClement Faure 		if (timeout_elapsed(tout_rx))
629756bcc4SClement Faure 			break;
639756bcc4SClement Faure 	} while (res == TEE_ERROR_NO_DATA);
649756bcc4SClement Faure 
659756bcc4SClement Faure 	if (res)
669756bcc4SClement Faure 		return res;
679756bcc4SClement Faure 
689756bcc4SClement Faure 	memcpy(&msg->header, &response, sizeof(response));
699756bcc4SClement Faure 
709756bcc4SClement Faure 	/* Check the size of the message to receive */
719756bcc4SClement Faure 	if (msg->header.size > IMX_MU_MSG_SIZE) {
729756bcc4SClement Faure 		EMSG("Size of the message is > than IMX_MU_MSG_SIZE");
739756bcc4SClement Faure 		return TEE_ERROR_BAD_FORMAT;
749756bcc4SClement Faure 	}
759756bcc4SClement Faure 
76c4023a0fSSahil Malhotra 	nb_channel = imx_mu_plat_get_rx_channel(base);
779756bcc4SClement Faure 
789756bcc4SClement Faure 	for (count = 1; count < msg->header.size; count++) {
799756bcc4SClement Faure 		res = imx_mu_plat_receive(base, count % nb_channel,
809756bcc4SClement Faure 					  &msg->data.u32[count - 1]);
819756bcc4SClement Faure 		if (res)
829756bcc4SClement Faure 			return res;
839756bcc4SClement Faure 	}
849756bcc4SClement Faure 
859756bcc4SClement Faure 	return TEE_SUCCESS;
869756bcc4SClement Faure }
879756bcc4SClement Faure 
889756bcc4SClement Faure /*
899756bcc4SClement Faure  * Send a message via the MU
909756bcc4SClement Faure  *
919756bcc4SClement Faure  * @base: virtual base address of the MU controller
929756bcc4SClement Faure  * @[in]msg: message to send
939756bcc4SClement Faure  */
imx_mu_send_msg(vaddr_t base,struct imx_mu_msg * msg)949756bcc4SClement Faure static TEE_Result imx_mu_send_msg(vaddr_t base, struct imx_mu_msg *msg)
959756bcc4SClement Faure {
969756bcc4SClement Faure 	TEE_Result res = TEE_ERROR_GENERIC;
979756bcc4SClement Faure 	unsigned int count = 0;
989756bcc4SClement Faure 	unsigned int nb_channel = 0;
99*35e561d8SSahil Malhotra 	unsigned int start_index = 0;
100*35e561d8SSahil Malhotra 	unsigned int end_index = 0;
1019756bcc4SClement Faure 	uint32_t word = 0;
1029756bcc4SClement Faure 
1039756bcc4SClement Faure 	assert(base && msg);
1049756bcc4SClement Faure 
1059756bcc4SClement Faure 	if (msg->header.size > IMX_MU_MSG_SIZE) {
1069756bcc4SClement Faure 		EMSG("msg->size is > than IMX_MU_MSG_SIZE");
1079756bcc4SClement Faure 		return TEE_ERROR_BAD_FORMAT;
1089756bcc4SClement Faure 	}
1099756bcc4SClement Faure 
110*35e561d8SSahil Malhotra 	if (IS_MU_TRUST) {
111*35e561d8SSahil Malhotra 		/*
112*35e561d8SSahil Malhotra 		 * make sure command (bit[31:26]) is higher than SCM_CR2_CMD_VAL
113*35e561d8SSahil Malhotra 		 * SCM_CR2_CMD_VAL is set to 0 by ELE FW. but let’s use
114*35e561d8SSahil Malhotra 		 * max value.
115*35e561d8SSahil Malhotra 		 */
116*35e561d8SSahil Malhotra 		word |= GENMASK_32(31, 26);
117*35e561d8SSahil Malhotra 
118*35e561d8SSahil Malhotra 		/* size (including dummy header) ->  bit[19:16]*/
119*35e561d8SSahil Malhotra 		word |= SHIFT_U32(((msg->header.size + 1) & GENMASK_32(3, 0)),
120*35e561d8SSahil Malhotra 				  16);
121*35e561d8SSahil Malhotra 
122*35e561d8SSahil Malhotra 		res = imx_mu_plat_send(base, start_index, word);
1239756bcc4SClement Faure 		if (res)
1249756bcc4SClement Faure 			return res;
1259756bcc4SClement Faure 
126*35e561d8SSahil Malhotra 		start_index++;
127*35e561d8SSahil Malhotra 		memcpy(&word, &msg->header, sizeof(uint32_t));
128*35e561d8SSahil Malhotra 		res = imx_mu_plat_send(base, start_index, word);
129*35e561d8SSahil Malhotra 		if (res)
130*35e561d8SSahil Malhotra 			return res;
1319756bcc4SClement Faure 
132*35e561d8SSahil Malhotra 		start_index++;
133*35e561d8SSahil Malhotra 		/*
134*35e561d8SSahil Malhotra 		 * TR15 is reserved for special USM commands
135*35e561d8SSahil Malhotra 		 */
136*35e561d8SSahil Malhotra 		nb_channel = imx_mu_plat_get_tx_channel(base) - 1;
137*35e561d8SSahil Malhotra 		end_index = msg->header.size + 1;
138*35e561d8SSahil Malhotra 		assert(end_index < nb_channel);
139*35e561d8SSahil Malhotra 	} else {
140*35e561d8SSahil Malhotra 		memcpy(&word, &msg->header, sizeof(uint32_t));
141*35e561d8SSahil Malhotra 		res = imx_mu_plat_send(base, start_index, word);
142*35e561d8SSahil Malhotra 		if (res)
143*35e561d8SSahil Malhotra 			return res;
144*35e561d8SSahil Malhotra 
145*35e561d8SSahil Malhotra 		start_index++;
146*35e561d8SSahil Malhotra 		nb_channel = imx_mu_plat_get_tx_channel(base);
147*35e561d8SSahil Malhotra 		end_index = msg->header.size;
148*35e561d8SSahil Malhotra 	}
149*35e561d8SSahil Malhotra 
150*35e561d8SSahil Malhotra 	for (count = start_index; count < end_index; count++) {
1519756bcc4SClement Faure 		res = imx_mu_plat_send(base, count % nb_channel,
152*35e561d8SSahil Malhotra 				       msg->data.u32[count - start_index]);
1539756bcc4SClement Faure 		if (res)
1549756bcc4SClement Faure 			return res;
1559756bcc4SClement Faure 	}
1569756bcc4SClement Faure 
1579756bcc4SClement Faure 	return TEE_SUCCESS;
1589756bcc4SClement Faure }
1599756bcc4SClement Faure 
imx_mu_init(vaddr_t base)1609756bcc4SClement Faure void imx_mu_init(vaddr_t base)
1619756bcc4SClement Faure {
1629756bcc4SClement Faure 	uint32_t exceptions = 0;
1639756bcc4SClement Faure 
1649756bcc4SClement Faure 	if (!base) {
1659756bcc4SClement Faure 		EMSG("Bad MU base address");
1669756bcc4SClement Faure 		return;
1679756bcc4SClement Faure 	}
1689756bcc4SClement Faure 
1699756bcc4SClement Faure 	exceptions = cpu_spin_lock_xsave(&mu_spinlock);
1709756bcc4SClement Faure 
1719756bcc4SClement Faure 	imx_mu_plat_init(base);
1729756bcc4SClement Faure 
1739756bcc4SClement Faure 	cpu_spin_unlock_xrestore(&mu_spinlock, exceptions);
1749756bcc4SClement Faure }
1759756bcc4SClement Faure 
imx_mu_call(vaddr_t base,struct imx_mu_msg * msg,bool wait_for_answer)1769756bcc4SClement Faure TEE_Result imx_mu_call(vaddr_t base, struct imx_mu_msg *msg,
1779756bcc4SClement Faure 		       bool wait_for_answer)
1789756bcc4SClement Faure {
1799756bcc4SClement Faure 	TEE_Result res = TEE_ERROR_GENERIC;
1809756bcc4SClement Faure 	uint32_t exceptions = 0;
1819756bcc4SClement Faure 
1829756bcc4SClement Faure 	if (!base || !msg)
1839756bcc4SClement Faure 		return TEE_ERROR_BAD_PARAMETERS;
1849756bcc4SClement Faure 
1859756bcc4SClement Faure 	exceptions = cpu_spin_lock_xsave(&mu_spinlock);
1869756bcc4SClement Faure 
1879756bcc4SClement Faure 	res = imx_mu_send_msg(base, msg);
1889756bcc4SClement Faure 	if (res == TEE_SUCCESS && wait_for_answer)
1899756bcc4SClement Faure 		res = imx_mu_receive_msg(base, msg);
1909756bcc4SClement Faure 
1919756bcc4SClement Faure 	cpu_spin_unlock_xrestore(&mu_spinlock, exceptions);
1929756bcc4SClement Faure 
1939756bcc4SClement Faure 	return res;
1949756bcc4SClement Faure }
195