1 /*
2 * Copyright 2022 NXP
3 * All rights reserved.
4 *
5 * SPDX-License-Identifier: BSD-3-Clause
6 */
7 #include <stdint.h>
8 #include <stdbool.h>
9 #include <stddef.h>
10
11 #include "fsl_s3mu.h"
12
13 /* Component ID definition, used by tools. */
14 #ifndef FSL_COMPONENT_ID
15 #define FSL_COMPONENT_ID "platform.drivers.s3mu"
16 #endif
17
18 /*******************************************************************************
19 * Definitions
20 *******************************************************************************/
21
22 #define _BIT(x) (uint32_t)(1UL << (x))
23 #define MU_READ_HEADER (0x01u)
24 #define GET_HDR_SIZE(x) (((x) & (uint32_t)0xFF00) >> 8u)
25
26 typedef struct mu_message
27 {
28 mu_hdr_t header;
29 uint32_t payload[S3MU_TR_COUNT - MU_MSG_HEADER_SIZE];
30 } mu_message_t;
31
32 /*******************************************************************************
33 * Prototypes
34 ******************************************************************************/
35 static void s3mu_hal_send_data(S3MU_Type *mu, uint32_t regid, uint32_t *data);
36 static void s3mu_hal_receive_data(S3MU_Type *mu, uint32_t regid, uint32_t *data);
37 static status_t s3mu_read_data_wait(S3MU_Type *mu, uint32_t *buf, uint8_t *size, uint32_t wait);
38 static status_t s3mu_hal_receive_data_wait(S3MU_Type *mu, uint8_t regid, uint32_t *data, uint32_t wait);
39 /*******************************************************************************
40 * Code
41 ******************************************************************************/
42
43 /*!
44 * brief Send message to MU
45 *
46 * This function writes messgae into MU regsters and send message to EdgeLock Enclave.
47 *
48 * param base MU peripheral base address
49 * param buf buffer to store read data
50 * param wordCount size of data in words
51 *
52 * return Status kStatus_Success if success, kStatus_Fail if fail
53 * Possible errors: kStatus_S3MU_InvalidArgument, kStatus_S3MU_AgumentOutOfRange
54 */
S3MU_SendMessage(S3MU_Type * mu,void * buf,size_t wordCount)55 status_t S3MU_SendMessage(S3MU_Type *mu, void *buf, size_t wordCount)
56 {
57 uint8_t tx_reg_idx = 0u;
58 uint8_t counter = 0u;
59 status_t ret = kStatus_Fail;
60 if (buf == NULL)
61 {
62 ret = kStatus_S3MU_InvalidArgument;
63 }
64 else
65 {
66 while (wordCount != 0u)
67 {
68 tx_reg_idx = tx_reg_idx % S3MU_TR_COUNT;
69 s3mu_hal_send_data(mu, tx_reg_idx, (uint32_t*)buf+counter);
70 tx_reg_idx++;
71 counter++;
72 wordCount--;
73 }
74 ret = kStatus_Success;
75 }
76 return ret;
77 }
78
79 /* Static function to write one word to transmit register specified by index */
s3mu_hal_send_data(S3MU_Type * mu,uint32_t regid,uint32_t * data)80 static void s3mu_hal_send_data(S3MU_Type *mu, uint32_t regid, uint32_t *data)
81 {
82 uint32_t mask = (_BIT(regid));
83 while ((mu->TSR & mask) == 0u)
84 {
85 }
86 mu->TR[regid] = *data;
87 }
88
89 /*!
90 * brief Get response from MU
91 *
92 * This function reads response data from EdgeLock Enclave if available.
93 *
94 * param base MU peripheral base address
95 * param buf buffer to store read data
96 * param wordCount size of data in words
97 *
98 * return Status kStatus_Success if success, kStatus_Fail if fail
99 * Possible errors: kStatus_S3MU_InvalidArgument, kStatus_S3MU_AgumentOutOfRange
100 */
S3MU_GetResponse(S3MU_Type * mu,void * buf)101 status_t S3MU_GetResponse(S3MU_Type *mu, void *buf)
102 {
103 size_t size;
104 (void)size; /* Not used here */
105
106 if (buf == NULL)
107 {
108 return kStatus_S3MU_InvalidArgument;
109 }
110
111 return S3MU_ReadMessage(mu, buf, &size, MU_READ_HEADER);
112 }
113
114 /*!
115 * brief Read message from MU
116 *
117 * This function reads message date from EdgeLock Enclave if available.
118 *
119 * param base MU peripheral base address
120 * param buf buffer to store read data
121 * param size If read_header equals MU_READ_HEADER, size represent number of word obtained from header.
122 * If read header not equals MU_READ_HEADER, size is used to determine number of word to be read.
123 * param read_header specifies if size is obtained by response header or provided in parameter.
124 *
125 * return Status kStatus_Success if success, kStatus_Fail if fail
126 * Possible errors: kStatus_S3MU_InvalidArgument, kStatus_S3MU_AgumentOutOfRange
127 */
S3MU_ReadMessage(S3MU_Type * mu,uint32_t * buf,size_t * size,uint8_t read_header)128 status_t S3MU_ReadMessage(S3MU_Type *mu, uint32_t *buf, size_t *size, uint8_t read_header)
129 {
130 uint32_t msg_size = 0u;
131 uint32_t rx_reg_idx = 0u;
132 uint32_t *buf_ptr = buf;
133 status_t ret = kStatus_Fail;
134
135 if ((buf == NULL) || (size == NULL))
136 {
137 ret = kStatus_S3MU_InvalidArgument;
138 }
139 else
140 {
141 if (read_header == MU_READ_HEADER)
142 {
143 s3mu_hal_receive_data(mu, rx_reg_idx, buf);
144 msg_size = (GET_HDR_SIZE(buf[0]));
145 *size = msg_size;
146 rx_reg_idx++;
147 msg_size--; /* payload size = size - 1 (header) */
148 }
149 else
150 {
151 msg_size = *size;
152 }
153
154 while (msg_size != 0u)
155 {
156 rx_reg_idx = rx_reg_idx % S3MU_RR_COUNT;
157 buf_ptr++;
158 s3mu_hal_receive_data(mu, rx_reg_idx, buf_ptr);
159 rx_reg_idx++;
160 msg_size--;
161 }
162 ret = kStatus_Success;
163 }
164 return ret;
165 }
166
167 /* Static function to retrieve one word from receive register specified by index */
s3mu_hal_receive_data(S3MU_Type * mu,uint32_t regid,uint32_t * data)168 static void s3mu_hal_receive_data(S3MU_Type *mu, uint32_t regid, uint32_t *data)
169 {
170 uint32_t mask = _BIT(regid);
171
172 while ((mu->RSR & mask) == 0u)
173 {
174 }
175
176 *data = mu->RR[regid];
177 }
178
179 /*!
180 * brief Wait and Read data from MU
181 *
182 * This function wait limited time (ticks) and tests if data are ready to be read.
183 * When data are ready, reads them into buffer.
184 *
185 * param base MU peripheral base address
186 * param buf buffer to store read data
187 * param wordCount size of data in words
188 * param wait number of iterations to wait
189 *
190 * return Status kStatus_Success if success, kStatus_S3MU_RequestTimeout if timeout
191 * Possible errors: kStatus_S3MU_InvalidArgument, kStatus_S3MU_AgumentOutOfRange
192 */
S3MU_WaitForData(S3MU_Type * mu,uint32_t * buf,size_t wordCount,uint32_t wait)193 status_t S3MU_WaitForData(S3MU_Type *mu, uint32_t *buf, size_t wordCount, uint32_t wait)
194 {
195 uint8_t size = (uint8_t)wordCount;
196 status_t ret;
197 if (buf == NULL)
198 {
199 ret = kStatus_S3MU_InvalidArgument;
200 }
201 else if (wordCount > S3MU_RR_COUNT)
202 {
203 ret = kStatus_S3MU_AgumentOutOfRange;
204 }
205 else
206 {
207 ret = s3mu_read_data_wait(mu, buf, &size, wait);
208 }
209 return ret;
210 }
211
212 /* Static function to retrieve message form retrieve registers with wait */
s3mu_read_data_wait(S3MU_Type * mu,uint32_t * buf,uint8_t * size,uint32_t wait)213 static status_t s3mu_read_data_wait(S3MU_Type *mu, uint32_t *buf, uint8_t *size, uint32_t wait)
214 {
215 uint8_t msg_size = *size;
216 uint8_t counter = 0u;
217 uint8_t rx_reg_idx = 0u;
218 status_t ret = kStatus_Success;
219
220 if ((buf == NULL) || (size == NULL))
221 {
222 ret = kStatus_S3MU_InvalidArgument;
223 }
224 else
225 {
226 while (msg_size != 0u)
227 {
228 rx_reg_idx = rx_reg_idx % S3MU_RR_COUNT;
229 if (wait != 0u)
230 {
231 if ((ret = s3mu_hal_receive_data_wait(mu, rx_reg_idx, &buf[counter], wait)) != kStatus_Success)
232 {
233 break;
234 }
235 }
236 else
237 {
238 s3mu_hal_receive_data(mu, rx_reg_idx, &buf[counter]);
239 }
240 rx_reg_idx++;
241 counter++;
242 msg_size--;
243 }
244 }
245 return ret;
246 }
247
248 /* Static function to retrieve one word from receive register specified by index with wait */
s3mu_hal_receive_data_wait(S3MU_Type * mu,uint8_t regid,uint32_t * data,uint32_t wait)249 static status_t s3mu_hal_receive_data_wait(S3MU_Type *mu, uint8_t regid, uint32_t *data, uint32_t wait)
250 {
251 uint32_t mask = _BIT(regid);
252 status_t ret = kStatus_Fail;
253 while ((mu->RSR & mask) == 0u)
254 {
255 if (--wait == 0u)
256 {
257 ret = kStatus_S3MU_RequestTimeout;
258 break;
259 }
260 }
261 if (ret != kStatus_S3MU_RequestTimeout)
262 {
263 *data = mu->RR[regid];
264 ret = kStatus_Success;
265 }
266 return ret;
267 }
268
269 /*!
270 * brief Init MU
271 *
272 * This function does nothing. MU is initialized after leaving ROM.
273 *
274 * param base MU peripheral base address
275 */
S3MU_Init(S3MU_Type * mu)276 void S3MU_Init(S3MU_Type *mu)
277 {
278 /* nothing to do for initialization */
279 }
280
281 /*!
282 * brief Computes CRC
283 *
284 * This function computes CRC of input message.
285 *
286 * param msg pointer to message
287 * param msg_len size of message in words
288 *
289 * return CRC32 checksum value
290 */
S3MU_ComputeMsgCrc(uint32_t * msg,uint32_t msg_len)291 uint32_t S3MU_ComputeMsgCrc(uint32_t *msg, uint32_t msg_len)
292 {
293 uint32_t crc;
294 uint32_t i;
295
296 crc = 0u;
297 for (i = 0u; i < msg_len; i++)
298 {
299 crc ^= *(msg + i);
300 }
301 return crc;
302 }
303