1 /*
2  * Copyright 2019-2024 NXP
3  * All rights reserved.
4  *
5  * SPDX-License-Identifier: BSD-3-Clause
6  */
7 
8 #include "fsl_elemu.h"
9 
10 /* Component ID definition, used by tools. */
11 #ifndef FSL_COMPONENT_ID
12 #define FSL_COMPONENT_ID "platform.drivers.elemu"
13 #endif
14 
15 #define ELEMU_READY_WAIT_TIME 0xFFFFFFFFU
16 #define ELEMU_RESET_COMPLETED (0x1B00803Cu)
17 #define ELEMU_RESET_STARTED   (0x1700D03Cu)
18 
19 static status_t ELEMU_StartupWait(ELEMU_Type *mu);
20 
21 #if (defined(ELEMU_HAS_LOADABLE_FW) && ELEMU_HAS_LOADABLE_FW)
22 #include "fsl_sss_mgmt.h"
23 #include "fsl_sss_sscp.h"
24 #include "fsl_sscp_mu.h"
25 
26 #endif
27 /* ELEMU driver */
28 
29 #define BIT(x)         (((uint32_t)1u << (x)))
30 #define MU_READ_HEADER (0x01u)
31 #define READ_RETRIES   (0x5u)
32 
33 #define MU_SEMA4_RESERVED_BY_OTHER (0xFFFFFFAAu)
34 #define MU_SEMA4_LOCKED_TO_CURRENT (0x00000055u)
35 #define MU_SEMA4_FREE              (0x0u)
36 
37 typedef struct mu_message
38 {
39     mu_hdr_t header;
40     uint32_t payload[ELEMU_TR_COUNT - MU_MSG_HEADER_SIZE];
41 } mu_message_t;
42 
ELEMU_mu_hal_send_data(ELEMU_Type * mu,uint8_t regid,uint32_t * data)43 void ELEMU_mu_hal_send_data(ELEMU_Type *mu, uint8_t regid, uint32_t *data)
44 {
45     uint32_t mask = (BIT(regid));
46     while ((mu->TSR & mask) == 0u)
47     {
48     }
49     mu->TR[regid] = *data;
50 }
51 
ELEMU_mu_hal_receive_data(ELEMU_Type * mu,uint8_t regid,uint32_t * data)52 void ELEMU_mu_hal_receive_data(ELEMU_Type *mu, uint8_t regid, uint32_t *data)
53 {
54     uint32_t mask        = BIT(regid);
55     uint8_t read_retries = READ_RETRIES;
56     while ((mu->RSR & mask) == 0u)
57     {
58     }
59     *data = mu->RR[regid];
60     while (((mu->RSR & mask) != 0u) && (read_retries != 0u))
61     {
62         *data = mu->RR[regid];
63         read_retries--;
64     }
65 }
66 
ELEMU_mu_hal_receive_data_wait(ELEMU_Type * mu,uint8_t regid,uint32_t * data,uint32_t wait)67 status_t ELEMU_mu_hal_receive_data_wait(ELEMU_Type *mu, uint8_t regid, uint32_t *data, uint32_t wait)
68 {
69     uint32_t mask        = BIT(regid);
70     uint8_t read_retries = READ_RETRIES;
71     status_t ret         = 0;
72     while ((mu->RSR & mask) == 0u)
73     {
74         if (--wait == 0u)
75         {
76             ret = kStatus_ELEMU_RequestTimeout;
77             break;
78         }
79     }
80     if (ret != kStatus_ELEMU_RequestTimeout)
81     {
82         *data = mu->RR[regid];
83         while (((mu->RSR & mask) != 0u) && (read_retries != 0u))
84         {
85             *data = mu->RR[regid];
86             read_retries--;
87         }
88         ret = kStatus_Success;
89     }
90     return ret;
91 }
92 
ELEMU_mu_send_message(ELEMU_Type * mu,uint32_t buf[],size_t wordCount)93 status_t ELEMU_mu_send_message(ELEMU_Type *mu, uint32_t buf[], size_t wordCount)
94 {
95     uint8_t tx_reg_idx = 0u;
96     uint8_t counter    = 0u;
97     status_t ret       = kStatus_Fail;
98     if (buf == NULL)
99     {
100         ret = kStatus_ELEMU_InvalidArgument;
101     }
102     else if (wordCount > ELEMU_TR_COUNT)
103     {
104         ret = kStatus_ELEMU_AgumentOutOfRange;
105     }
106     else
107     {
108         while (wordCount > 0u)
109         {
110             tx_reg_idx = tx_reg_idx % ELEMU_TR_COUNT;
111             ELEMU_mu_hal_send_data(mu, tx_reg_idx, &buf[counter]);
112             tx_reg_idx++;
113             counter++;
114             wordCount--;
115         }
116         ret = kStatus_Success;
117     }
118     return ret;
119 }
120 
ELEMU_mu_wait_for_ready(ELEMU_Type * mu,uint32_t wait)121 status_t ELEMU_mu_wait_for_ready(ELEMU_Type *mu, uint32_t wait)
122 {
123     if (kStatus_Success != ELEMU_LP_WakeupPathInit(mu))
124     {
125         return kStatus_ELEMU_RequestTimeout;
126     }
127 
128 #if (defined(FSL_FEATURE_ELEMU_HAS_SEMA4_STATUS_REGISTER) && FSL_FEATURE_ELEMU_HAS_SEMA4_STATUS_REGISTER)
129     status_t ret = kStatus_ELEMU_RequestTimeout;
130     if (wait == 0u)
131     {
132         if ((ELEMUA->SEMA4_SR & (ELEMU_SEMA4_SR_MISC_BSY(0x30) | ELEMU_SEMA4_SR_SSS_CIP1_MASK)) == 0u)
133         {
134             ret = kStatus_Success;
135         }
136     }
137     else
138     {
139         do
140         {
141             if ((ELEMUA->SEMA4_SR & (ELEMU_SEMA4_SR_MISC_BSY(0x30) | ELEMU_SEMA4_SR_SSS_CIP1_MASK)) == 0u)
142             {
143                 ret = kStatus_Success;
144                 break;
145             }
146             wait--;
147         } while (wait != 0u);
148     }
149     return ret;
150 #else /* FSL_FEATURE_ELEMU_HAS_SEMA4_STATUS_REGISTER */
151     return kStatus_Success;
152 #endif
153 }
154 #if (defined(FSL_FEATURE_ELEMU_HAS_SEMA4_STATUS_REGISTER) && FSL_FEATURE_ELEMU_HAS_SEMA4_STATUS_REGISTER)
ELEMU_mu_get_ownership_status(ELEMU_Type * mu)155 elemu_ownership_status_t ELEMU_mu_get_ownership_status(ELEMU_Type *mu)
156 {
157     elemu_ownership_status_t ret = kStatus_ELEMU_Unknown;
158     uint32_t result              = mu->SEMA4_OWNR;
159     if (result == MU_SEMA4_LOCKED_TO_CURRENT)
160     {
161         ret = kStatus_ELEMU_LockedByMe;
162     }
163     else if (result == MU_SEMA4_RESERVED_BY_OTHER)
164     {
165         ret = kStatus_ELEMU_LockedByOther;
166     }
167     else if (result == MU_SEMA4_FREE)
168     {
169         ret = kStatus_ELEMU_Free;
170     }
171     else
172     {
173         ret = kStatus_ELEMU_Unknown;
174     }
175     return ret;
176 }
177 
ELEMU_mu_get_ownership(ELEMU_Type * mu)178 status_t ELEMU_mu_get_ownership(ELEMU_Type *mu)
179 {
180     status_t ret    = kStatus_Fail;
181     uint32_t result = mu->SEMA4_ACQ;
182     if (result == MU_SEMA4_LOCKED_TO_CURRENT)
183     {
184         ret = kStatus_Success;
185     }
186     else if (result == MU_SEMA4_RESERVED_BY_OTHER)
187     {
188         ret = kStatus_ELEMU_Busy;
189     }
190     else
191     {
192         ret = kStatus_Fail;
193     }
194     return ret;
195 }
196 
ELEMU_mu_release_ownership(ELEMU_Type * mu)197 status_t ELEMU_mu_release_ownership(ELEMU_Type *mu)
198 {
199     status_t ret    = kStatus_Fail;
200     uint32_t result = mu->SEMA4_REL;
201     if (result == MU_SEMA4_FREE)
202     {
203         ret = kStatus_Success;
204     }
205     else if (result == MU_SEMA4_RESERVED_BY_OTHER)
206     {
207         ret = kStatus_ELEMU_Busy;
208     }
209     else
210     {
211         ret = kStatus_Fail;
212     }
213     return ret;
214 }
215 
ELEMU_mu_release_ownership_force(ELEMU_Type * mu)216 status_t ELEMU_mu_release_ownership_force(ELEMU_Type *mu)
217 {
218     status_t ret    = kStatus_Fail;
219     uint32_t result = mu->SEMA4_FREL;
220     if (result == MU_SEMA4_FREE)
221     {
222         ret = kStatus_Success;
223     }
224     else if (result == MU_SEMA4_RESERVED_BY_OTHER)
225     {
226         ret = kStatus_ELEMU_Busy;
227     }
228     else
229     {
230         ret = kStatus_Fail;
231     }
232     return ret;
233 }
234 #endif /* FSL_FEATURE_ELEMU_HAS_SEMA4_STATUS_REGISTER */
235 
ELEMU_mu_read_message(ELEMU_Type * mu,uint32_t * buf,uint8_t * size,uint8_t read_header)236 status_t ELEMU_mu_read_message(ELEMU_Type *mu, uint32_t *buf, uint8_t *size, uint8_t read_header)
237 {
238     uint8_t msg_size   = 0u;
239     uint8_t rx_reg_idx = 0u;
240     mu_message_t *msg  = (mu_message_t *)(uintptr_t)buf;
241     uint32_t counter   = 0u;
242     status_t ret       = kStatus_Fail;
243 
244     if ((buf == NULL) || (size == NULL))
245     {
246         ret = kStatus_ELEMU_InvalidArgument;
247     }
248     else
249     {
250         if (read_header == MU_READ_HEADER)
251         {
252             ELEMU_mu_hal_receive_data(mu, rx_reg_idx, (uint32_t *)(uintptr_t)&msg->header);
253             msg_size = msg->header.size;
254             rx_reg_idx++;
255             *size = msg_size + 1u;
256         }
257         else
258         {
259             msg_size = *size;
260         }
261 
262         while (msg_size > 0u)
263         {
264             rx_reg_idx = rx_reg_idx % ELEMU_RR_COUNT;
265             ELEMU_mu_hal_receive_data(mu, rx_reg_idx, &msg->payload[counter]);
266             rx_reg_idx++;
267             counter++;
268             msg_size--;
269         }
270         ret = kStatus_Success;
271     }
272     return ret;
273 }
274 
ELEMU_mu_read_data_wait(ELEMU_Type * mu,uint32_t buf[],uint8_t * size,uint32_t wait)275 status_t ELEMU_mu_read_data_wait(ELEMU_Type *mu, uint32_t buf[], uint8_t *size, uint32_t wait)
276 {
277     uint8_t msg_size   = 0u;
278     uint8_t counter    = 0u;
279     uint8_t rx_reg_idx = 0u;
280     status_t ret       = kStatus_Success;
281 
282     if ((buf == NULL) || (size == NULL))
283     {
284         ret = kStatus_ELEMU_InvalidArgument;
285     }
286     else
287     {
288         msg_size = *size;
289         while (msg_size > 0u)
290         {
291             rx_reg_idx = rx_reg_idx % ELEMU_RR_COUNT;
292             if (wait > 0u)
293             {
294                 if ((ret = ELEMU_mu_hal_receive_data_wait(mu, rx_reg_idx, &buf[counter], wait)) != kStatus_Success)
295                 {
296                     break;
297                 }
298             }
299             else
300             {
301                 ELEMU_mu_hal_receive_data(mu, rx_reg_idx, &buf[counter]);
302             }
303             rx_reg_idx++;
304             counter++;
305             msg_size--;
306         }
307     }
308     return ret;
309 }
310 
ELEMU_mu_get_response(ELEMU_Type * mu,uint32_t * buf,size_t wordCount)311 status_t ELEMU_mu_get_response(ELEMU_Type *mu, uint32_t *buf, size_t wordCount)
312 {
313     uint8_t size = (uint8_t)wordCount;
314     status_t ret;
315     if (buf == NULL)
316     {
317         ret = kStatus_ELEMU_InvalidArgument;
318     }
319     else if (wordCount > ELEMU_RR_COUNT)
320     {
321         ret = kStatus_ELEMU_AgumentOutOfRange;
322     }
323     else
324     {
325         ret = ELEMU_mu_read_message(mu, buf, &size, MU_READ_HEADER);
326     }
327     return ret;
328 }
329 
ELEMU_mu_wait_for_data(ELEMU_Type * mu,uint32_t * buf,size_t wordCount,uint32_t wait)330 status_t ELEMU_mu_wait_for_data(ELEMU_Type *mu, uint32_t *buf, size_t wordCount, uint32_t wait)
331 {
332     uint8_t size = (uint8_t)wordCount;
333     status_t ret;
334     if (buf == NULL)
335     {
336         ret = kStatus_ELEMU_InvalidArgument;
337     }
338     else if (wordCount > ELEMU_RR_COUNT)
339     {
340         ret = kStatus_ELEMU_AgumentOutOfRange;
341     }
342     else
343     {
344         ret = ELEMU_mu_read_data_wait(mu, buf, &size, wait);
345     }
346     return ret;
347 }
348 
ELEMU_mu_init(ELEMU_Type * mu)349 void ELEMU_mu_init(ELEMU_Type *mu)
350 {
351     /* nothing to do for initialization */
352 }
353 
ELEMU_StartupWait(ELEMU_Type * mu)354 static status_t ELEMU_StartupWait(ELEMU_Type *mu)
355 {
356     uint32_t msg[2] = {0};
357     status_t status = kStatus_Fail;
358 
359     if (kStatus_Success != ELEMU_mu_wait_for_data(mu, msg, 2u, ELEMU_READY_WAIT_TIME))
360     {
361     }
362     else if (msg[0] != ELEMU_RESET_STARTED)
363     {
364         status = kStatus_Fail;
365     }
366     else if (msg[1] != ELEMU_RESET_COMPLETED)
367     {
368         status = kStatus_Fail;
369     }
370     else
371     {
372         status = kStatus_Success;
373     }
374 
375     return status;
376 }
377 
ELEMU_LP_WakeupPathInit(ELEMU_Type * mu)378 status_t ELEMU_LP_WakeupPathInit(ELEMU_Type *mu)
379 {
380     status_t status = kStatus_Fail;
381 
382     do
383     {
384         /* read current value of the MRCC_SECSUBSYS register */
385         uint32_t mrcc_secsubsys = CLOCK_REG(kCLOCK_Secsubsys);
386 
387         /* test if the module is released from reset and clocks are enabled */
388         if (((mrcc_secsubsys & MRCC_RSTB_MASK) == MRCC_RSTB_MASK) && ((mrcc_secsubsys & MRCC_CC_MASK) != 0x0u))
389         {
390             status = kStatus_Success;
391         }
392 
393         /* apply the requested MRCC_SECSUBSYS[CC] (control) */
394         /* the actual non-zero CC value might be different from the setting configured by ROM bootloader */
395         /* the MRCC_SECSUBSYS[CC] is set to 2'b11  */
396         CLOCK_EnableClockLPMode(kCLOCK_Secsubsys, kCLOCK_IpClkControl_fun3);
397 
398         /* the module is running and the CC is configured, return */
399         if (kStatus_Success == status)
400         {
401             break;
402         }
403 
404         /* the module is NOT running at the time when this function is entered. */
405         /* therefore, wait for its startup sequence to complete */
406         status = ELEMU_StartupWait(mu);
407     } while (false);
408 
409     return status;
410 }
411 
412 #if (defined(ELEMU_HAS_LOADABLE_FW) && ELEMU_HAS_LOADABLE_FW)
413 
414 /* Tunnel type is EdgeLock Firmware upload */
415 #define TUNNEL_TYPE_SB3_ELE_FW   0x22u
416 #define SB3_BLOCK0_SIZE_IN_BYTES 0x60u
417 
ELEMU_loadFw(ELEMU_Type * mu,uint32_t image[])418 status_t ELEMU_loadFw(ELEMU_Type *mu, uint32_t image[])
419 {
420     uint32_t resultState = 0u;
421     sss_sscp_tunnel_t tunnelCtx;
422     sss_sscp_session_t sssSession;
423     sscp_context_t sscpContext;
424     status_t status = kStatus_Fail;
425     do
426     {
427         if (sscp_mu_init(&(sscpContext), (ELEMU_Type *)mu) != kStatus_SSCP_Success)
428         {
429             break;
430         }
431         /* OPEN SESSION */
432         if (sss_sscp_open_session(&sssSession, 0u, kType_SSS_Ele200, &sscpContext) != kStatus_SSS_Success)
433         {
434             break;
435         }
436 
437         /* OPEN TUNNEL */
438         if (sss_sscp_tunnel_context_init(&tunnelCtx, &sssSession, TUNNEL_TYPE_SB3_ELE_FW) != kStatus_SSS_Success)
439         {
440             break;
441         }
442 
443         /* Pass loadable ELE FW */
444         if (sss_sscp_tunnel(&tunnelCtx, (uint8_t *)image, SB3_BLOCK0_SIZE_IN_BYTES, &resultState) !=
445             kStatus_SSS_Success)
446         {
447             break;
448         }
449 
450         /* If all steps before passes without break, then consider it as success*/
451         status = kStatus_Success;
452 
453     } while (false);
454     /* FREE TUNNEL CONTEXT */
455     sss_sscp_tunnel_context_free(&tunnelCtx);
456     /* CLOSE SESSION */
457     sss_sscp_close_session(&sssSession);
458 
459     return status;
460 }
461 
462 #endif /* ELEMU_HAS_LOADABLE_FW */
463