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 
imx_mu_plat_init(vaddr_t base __unused)18 __weak void imx_mu_plat_init(vaddr_t base __unused)
19 {
20 }
21 
imx_mu_plat_send(vaddr_t base __unused,unsigned int index __unused,uint32_t msg __unused)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 
imx_mu_plat_receive(vaddr_t base __unused,unsigned int index __unused,uint32_t * msg __unused)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  */
imx_mu_receive_msg(vaddr_t base,struct imx_mu_msg * msg)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  */
imx_mu_send_msg(vaddr_t base,struct imx_mu_msg * msg)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 
imx_mu_init(vaddr_t base)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 
imx_mu_call(vaddr_t base,struct imx_mu_msg * msg,bool wait_for_answer)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