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