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