1 /*
2  * Copyright 2021-2024 NXP
3  * All rights reserved.
4  *
5  *
6  * SPDX-License-Identifier: BSD-3-Clause
7  */
8 
9 /* -------------------------------------------------------------------------- */
10 /*                                  Includes                                  */
11 /* -------------------------------------------------------------------------- */
12 
13 #include <stdarg.h>
14 
15 #include "fsl_common.h"
16 #include "fwk_platform_ics.h"
17 #include "fwk_platform.h"
18 #include "fsl_adapter_rpmsg.h"
19 
20 #if defined(NBU_VERSION_DBG) && (NBU_VERSION_DBG == 1)
21 #include "fsl_debug_console.h"
22 #endif
23 
24 /* -------------------------------------------------------------------------- */
25 /*                               Private macros                               */
26 /* -------------------------------------------------------------------------- */
27 
28 /* Number of loops we spin waiting for NBU processor to respond */
29 #define MAX_WAIT_NBU_RESPONSE_LOOPS 10000U
30 
31 /* API wait loop counter */
32 #define MAX_WAIT_NBU_API_RESPONSE_LOOPS 100000000U
33 
34 /* -------------------------------------------------------------------------- */
35 /*                             Private prototypes                             */
36 /* -------------------------------------------------------------------------- */
37 static hal_rpmsg_return_status_t PLATFORM_FwkSrv_RxCallBack(void *param, uint8_t *data, uint32_t len);
38 static bool                      FwkSrv_MsgTypeInExpectedSet(uint8_t msg_type);
39 
40 extern PLATFORM_FroDebugCallback_t pfPlatformDebugCallback;
41 PLATFORM_FroDebugCallback_t        pfPlatformDebugCallback = (void *)0;
42 
43 static void PLATFORM_RxNbuInitDoneService(uint8_t *data, uint32_t len);
44 static void PLATFORM_RxNbuVersionIndicationService(uint8_t *data, uint32_t len);
45 static void PLATFORM_RxNbuApiIndicationService(uint8_t *data, uint32_t len);
46 static void PLATFORM_RxNbuMemFullIndicationService(uint8_t *data, uint32_t len);
47 static void PLATFORM_RxHostSetLowPowerConstraintService(uint8_t *data, uint32_t len);
48 static void PLATFORM_RxHostReleaseLowPowerConstraintService(uint8_t *data, uint32_t len);
49 static void PLATFORM_RxFroNotificationService(uint8_t *data, uint32_t len);
50 static void PLATFORM_RxFwkSrvNbuIssueIndicationService(uint8_t *data, uint32_t len);
51 static void PLATFORM_RxNbuSecurityEventIndicationService(uint8_t *data, uint32_t len);
52 static void PLATFORM_RxNbuRequestRngSeedService(uint8_t *data, uint32_t len);
53 
54 /* -------------------------------------------------------------------------- */
55 /*                         Private memory declarations                        */
56 /* -------------------------------------------------------------------------- */
57 
58 static RPMSG_HANDLE_DEFINE(fwkRpmsgHandle);
59 static const hal_rpmsg_config_t fwkRpmsgConfig = {
60     .local_addr  = 110,
61     .remote_addr = 100,
62     .callback    = PLATFORM_FwkSrv_RxCallBack,
63     .param       = NULL,
64 };
65 
66 /* flag notifying of NBU Infor reception from CM3 */
67 static volatile bool g_nbu_info_resp_received = false;
68 static NbuInfo_t *   g_nbu_info_p             = (NbuInfo_t *)NULL;
69 static volatile bool g_nbu_init_done          = false;
70 
71 static uint32_t                      m_nbu_api_dbg_max_wait_loop = 0; /* maximum loop counter logged */
72 static volatile bool                 m_nbu_api_ind_received;
73 static volatile bool                 m_nbu_api_rpmsg_status;
74 static volatile uint32_t             m_nbu_api_return_param_len;
75 static uint8_t                       m_nbu_api_return_param[NBU_API_MAX_RETURN_PARAM_LENGTH];
76 static nbu_memory_error_callback_t   nbu_mem_error_callback      = (nbu_memory_error_callback_t)NULL;
77 static nbu_issue_callback_t          nbu_issue_callback          = (nbu_issue_callback_t)NULL;
78 static nbu_security_event_callback_t nbu_security_event_callback = (nbu_security_event_callback_t)NULL;
79 
80 static const FwkSrv_LowPowerConstraintCallbacks_t *pLowPowerConstraintCallbacks =
81     (const FwkSrv_LowPowerConstraintCallbacks_t *)NULL;
82 
83 __attribute__((weak)) void RNG_TriggerReseed(void);
RNG_TriggerReseed(void)84 __attribute__((weak)) void RNG_TriggerReseed(void)
85 {
86     ; /* Stub of the RNG_TriggerReseed() function */
87 }
88 
89 /* Array of pointer of function used in PLATFORM_FwkSrv_RxCallBack() */
90 static void (*PLATFORM_RxCallbackService[gFwkSrvNbu2HostLast_c - gFwkSrvNbu2HostFirst_c - 1U])(uint8_t *data,
91                                                                                                uint32_t len) = {
92     PLATFORM_RxNbuInitDoneService,
93     PLATFORM_RxNbuVersionIndicationService,
94     PLATFORM_RxNbuApiIndicationService,
95     PLATFORM_RxNbuMemFullIndicationService,
96     PLATFORM_RxHostSetLowPowerConstraintService,
97     PLATFORM_RxHostReleaseLowPowerConstraintService,
98     PLATFORM_RxFroNotificationService,
99     PLATFORM_RxFwkSrvNbuIssueIndicationService,
100     PLATFORM_RxNbuSecurityEventIndicationService,
101     PLATFORM_RxNbuRequestRngSeedService,
102 };
103 /* -------------------------------------------------------------------------- */
104 /*                              Public functions                              */
105 /* -------------------------------------------------------------------------- */
106 
PLATFORM_FwkSrvInit(void)107 int PLATFORM_FwkSrvInit(void)
108 {
109     int result = 0;
110 
111     static bool_t      mFwkSrvInit  = FALSE;
112     hal_rpmsg_config_t rpmsg_config = fwkRpmsgConfig;
113 
114     uint32_t irqMask = DisableGlobalIRQ();
115 
116     do
117     {
118         if (mFwkSrvInit == TRUE)
119         {
120             result = 1;
121             break;
122         }
123         if (kStatus_HAL_RpmsgSuccess != HAL_RpmsgInit((hal_rpmsg_handle_t)fwkRpmsgHandle, &rpmsg_config))
124         {
125             result = -2;
126             break;
127         }
128         /* Flag initialization on module */
129         mFwkSrvInit = TRUE;
130     } while (false);
131     EnableGlobalIRQ(irqMask);
132 
133     return result;
134 }
135 
PLATFORM_FwkSrvSendPacket(eFwkSrvMsgType msg_type,void * msg,uint16_t msg_lg)136 int PLATFORM_FwkSrvSendPacket(eFwkSrvMsgType msg_type, void *msg, uint16_t msg_lg)
137 {
138     uint8_t *buf    = NULL;
139     int      result = 0;
140     uint32_t sz     = ((uint32_t)msg_lg + 1U);
141 
142     if (PLATFORM_IsNbuStarted() == 0)
143     {
144         /* If NBU is not started at all do not go further */
145         result = -4;
146     }
147     else
148     {
149         /* Make sure remote CPU is awake */
150         PLATFORM_RemoteActiveReq();
151         do
152         {
153             buf = HAL_RpmsgAllocTxBuffer((hal_rpmsg_handle_t)fwkRpmsgHandle, sz);
154 
155             if (NULL == buf)
156             {
157                 result = -1;
158                 break;
159             }
160 
161             buf[0] = (uint8_t)msg_type;
162 
163             if (msg != NULL && msg_lg != 0U)
164             {
165                 memcpy(&buf[1], (uint8_t *)msg, msg_lg);
166             }
167 
168             if (kStatus_HAL_RpmsgSuccess != HAL_RpmsgNoCopySend((hal_rpmsg_handle_t)fwkRpmsgHandle, buf, (uint32_t)sz))
169             {
170                 result = -2;
171                 break;
172             }
173         } while (false);
174 
175         /* Release wake up to other CPU */
176         PLATFORM_RemoteActiveRel();
177     }
178 
179     return result;
180 }
181 
182 /* Returns negative value if info is not available, 0 otherwise */
PLATFORM_GetNbuInfo(NbuInfo_t * nbu_info_p)183 int PLATFORM_GetNbuInfo(NbuInfo_t *nbu_info_p)
184 {
185     int st = -1;
186 
187     do
188     {
189         uint32_t cnt;
190 
191         g_nbu_info_resp_received = false;
192 
193         /* Need a storage supplied by the caller to copy result from RPMSG memory */
194         if (nbu_info_p == NULL)
195         {
196             break;
197         }
198         g_nbu_info_p = nbu_info_p;
199         st           = PLATFORM_FwkSrvSendPacket(gFwkSrvNbuVersionRequest_c, (void *)NULL, 0);
200         if (0 != st)
201         {
202             break;
203         }
204         /* Wait for NBU / CM3 to answer but not forever */
205         st = -10; /*default status in case NBU does not respond */
206         for (cnt = MAX_WAIT_NBU_RESPONSE_LOOPS * 10U; cnt > 0U; cnt--)
207         {
208             if (g_nbu_info_resp_received)
209             {
210                 /* NBU response received */
211                 st = 0;
212                 break;
213             }
214         }
215     } while (false);
216     /* The Rx Call back has already filled the structure the global pointer can
217      be cleared. Should the indication arrive late - becasue of a breakpoint in
218      the CM3 for instance, the callback would simply drop the indication  */
219     g_nbu_info_p = NULL;
220     assert(st == 0);
221     return st;
222 }
223 
PLATFORM_SendChipRevision(void)224 int PLATFORM_SendChipRevision(void)
225 {
226     uint8_t chip_rev_reg = Chip_GetVersion();
227     uint8_t chip_rev     = 0xFF;
228     int     ret          = -3;
229 
230     if (chip_rev_reg == DEVICE_REVISION_A0)
231     {
232         chip_rev = 0u;
233     }
234     else if (chip_rev_reg == DEVICE_REVISION_A1)
235     {
236         chip_rev = 1u;
237     }
238 #if !defined(FPGA_SUPPORT) || (FPGA_SUPPORT == 0)
239     else if (chip_rev_reg == DEVICE_REVISION_A2)
240     {
241         chip_rev = 2u;
242     }
243 #endif
244     else
245     {
246         /* MISRA compliance */
247     }
248 
249     if (chip_rev != 0xFFu)
250     {
251         ret = PLATFORM_FwkSrvSendPacket(gFwkSrvHostChipRevision_c, (void *)&chip_rev, 1);
252     }
253 
254     return ret;
255 }
256 
PLATFORM_NbuApiReq(uint8_t * api_return,uint16_t api_id,const uint8_t * fmt,uint32_t * tab,uint32_t nb_returns)257 bool_t PLATFORM_NbuApiReq(uint8_t *api_return, uint16_t api_id, const uint8_t *fmt, uint32_t *tab, uint32_t nb_returns)
258 {
259     bool rpmsg_status = true;
260     bool nbu_rpmsg_status;
261 
262     /* Make sure remote CPU is awake */
263     PLATFORM_RemoteActiveReq();
264 
265     do
266     {
267         /* build the message payload */
268         uint8_t data[2 + NBU_API_MAX_PARAM_LENGTH];
269 
270         /* start with API identifier */
271         data[0U] = (uint8_t)api_id;
272         data[1U] = (uint8_t)(api_id >> 8U) & 0xffU;
273 
274         uint16_t data_len = 2U;
275         uint32_t param;
276         uint32_t j = 0U;
277 
278         for (uint32_t i = 0U; fmt[i] != 0U; i++)
279         {
280             if ((data_len + (uint16_t)fmt[i]) > NBU_API_MAX_PARAM_LENGTH)
281             {
282                 /* too many arguments */
283                 rpmsg_status = false;
284                 break;
285             }
286             else
287             {
288                 switch (fmt[i])
289                 {
290                     case 1U:
291                         param = tab[j];
292                         j++;
293                         if ((((int32_t)param < INT8_MIN) || ((int32_t)param > INT8_MAX)) && (param > 0xFFU))
294                         {
295                             rpmsg_status = false;
296                         }
297                         else
298                         {
299                             data[data_len++] = (uint8_t)param;
300                         }
301                         break;
302 
303                     case 2U:
304                         param = tab[j];
305                         j++;
306                         if ((((int32_t)param < INT16_MIN) || ((int32_t)param > INT16_MAX)) && (param > 0xFFFFU))
307                         {
308                             rpmsg_status = false;
309                         }
310                         else
311                         {
312                             data[data_len++] = (uint8_t)param;
313                             data[data_len++] = (uint8_t)(param >> 8U);
314                         }
315                         break;
316 
317                     case 4U:
318                         param = tab[j];
319                         j++;
320                         data[data_len++] = (uint8_t)param;
321                         data[data_len++] = (uint8_t)(param >> 8U);
322                         data[data_len++] = (uint8_t)(param >> 16U);
323                         data[data_len++] = (uint8_t)(param >> 24U);
324                         break;
325 
326                     default:
327                         rpmsg_status = false;
328                         break;
329                 }
330             }
331         }
332 
333         if (!rpmsg_status)
334         {
335             break;
336         }
337 
338         /* send to NBU */
339         m_nbu_api_ind_received = false;
340         if (0 != PLATFORM_FwkSrvSendPacket(gFwkSrvNbuApiRequest_c, (void *)&data, data_len))
341         {
342             rpmsg_status = false;
343             break;
344         }
345 
346         /* Wait for NBU / CM3 to answer but not forever */
347         uint32_t cnt          = 0;
348         bool     nbu_received = m_nbu_api_ind_received;
349 
350         while ((!m_nbu_api_ind_received) && (cnt < MAX_WAIT_NBU_API_RESPONSE_LOOPS))
351         {
352             // wait loop
353             cnt++;
354             assert(cnt != MAX_WAIT_NBU_API_RESPONSE_LOOPS);
355         }
356         if (m_nbu_api_dbg_max_wait_loop < cnt)
357         {
358             // log for debug purpose
359             m_nbu_api_dbg_max_wait_loop = cnt;
360         }
361 
362         assert(m_nbu_api_rpmsg_status);
363         nbu_rpmsg_status = m_nbu_api_rpmsg_status;
364 
365         nbu_received = m_nbu_api_ind_received;
366         rpmsg_status = nbu_received && nbu_rpmsg_status;
367 
368         /* API executed */
369         assert(m_nbu_api_return_param_len == nb_returns);
370         memcpy(api_return, (void *)&m_nbu_api_return_param[0], m_nbu_api_return_param_len);
371     } while (0U != 0U);
372 
373     /* Release wake up to other CPU */
374     PLATFORM_RemoteActiveRel();
375 
376     /* return rmpsg status, API status in *api_status */
377     assert(rpmsg_status);
378     return rpmsg_status;
379 }
380 
PLATFORM_RegisterNbuMemErrorCallback(nbu_memory_error_callback_t cb)381 void PLATFORM_RegisterNbuMemErrorCallback(nbu_memory_error_callback_t cb)
382 {
383     nbu_mem_error_callback = cb;
384 }
385 
PLATFORM_FwkSrvRegisterLowPowerCallbacks(const FwkSrv_LowPowerConstraintCallbacks_t * callbacks)386 void PLATFORM_FwkSrvRegisterLowPowerCallbacks(const FwkSrv_LowPowerConstraintCallbacks_t *callbacks)
387 {
388     pLowPowerConstraintCallbacks = callbacks;
389 }
390 
PLATFORM_FwkSrvSetRfSfcConfig(void * config,uint16_t size)391 void PLATFORM_FwkSrvSetRfSfcConfig(void *config, uint16_t size)
392 {
393     assert(config != NULL);
394 
395     (void)PLATFORM_FwkSrvSendPacket(gFwkSrvNbuSetRfSfcConfig_c, config, size);
396 }
397 
PLATFORM_EnableFroNotification(int8_t enable)398 void PLATFORM_EnableFroNotification(int8_t enable)
399 {
400     (void)PLATFORM_FwkSrvSendPacket(gFwkSrvFroEnableNotification_c, (void *)&enable, (uint16_t)sizeof(enable));
401 }
402 
PLATFORM_RegisterFroNotificationCallback(PLATFORM_FroDebugCallback_t cb)403 void PLATFORM_RegisterFroNotificationCallback(PLATFORM_FroDebugCallback_t cb)
404 {
405     pfPlatformDebugCallback = cb;
406 }
407 
PLATFORM_RegisterNbuIssueCb(nbu_issue_callback_t cb)408 void PLATFORM_RegisterNbuIssueCb(nbu_issue_callback_t cb)
409 {
410     nbu_issue_callback = cb;
411 }
412 
PLATFORM_RegisterSecurityEventCb(nbu_security_event_callback_t cb)413 void PLATFORM_RegisterSecurityEventCb(nbu_security_event_callback_t cb)
414 {
415     nbu_security_event_callback = cb;
416 }
417 
418 /* -------------------------------------------------------------------------- */
419 /*                              Private functions                             */
420 /* -------------------------------------------------------------------------- */
421 
PLATFORM_FwkSrv_RxCallBack(void * param,uint8_t * data,uint32_t len)422 static hal_rpmsg_return_status_t PLATFORM_FwkSrv_RxCallBack(void *param, uint8_t *data, uint32_t len)
423 {
424     hal_rpmsg_return_status_t res = kStatus_HAL_RL_RELEASE;
425     uint8_t                   msg_type;
426     msg_type = data[0];
427 
428     if (FwkSrv_MsgTypeInExpectedSet(msg_type))
429     {
430         PLATFORM_RxCallbackService[msg_type - 1U](data, len);
431     }
432     return res;
433 }
434 
PLATFORM_RxNbuVersionIndicationService(uint8_t * data,uint32_t len)435 static void PLATFORM_RxNbuVersionIndicationService(uint8_t *data, uint32_t len)
436 {
437     if (g_nbu_info_p != NULL)
438     {
439         g_nbu_info_resp_received = true;
440         memcpy(g_nbu_info_p, &data[1], sizeof(NbuInfo_t));
441 
442 #if defined(NBU_VERSION_DBG) && (NBU_VERSION_DBG == 1)
443         PRINTF("NBU v%d.%d.%d\r\n", g_nbu_info_p->versionNumber[0], g_nbu_info_p->versionNumber[1],
444                g_nbu_info_p->versionNumber[2]);
445         PRINTF("NBU SHA %02x%02x%02x%02x\r\n", g_nbu_info_p->repo_digest[0], g_nbu_info_p->repo_digest[1],
446                g_nbu_info_p->repo_digest[2], g_nbu_info_p->repo_digest[3]);
447 #endif
448         /* no longer required to hold since copy is done in allocated pointer */
449     }
450     NOT_USED(len);
451 }
452 
PLATFORM_RxNbuInitDoneService(uint8_t * data,uint32_t len)453 static void PLATFORM_RxNbuInitDoneService(uint8_t *data, uint32_t len)
454 {
455     g_nbu_init_done = true;
456 #if defined(NBU_VERSION_DBG) && (NBU_VERSION_DBG == 1)
457     PRINTF("NBU Init Done\r\n");
458 #endif
459     NOT_USED(data);
460     NOT_USED(len);
461 }
462 
PLATFORM_RxNbuMemFullIndicationService(uint8_t * data,uint32_t len)463 static void PLATFORM_RxNbuMemFullIndicationService(uint8_t *data, uint32_t len)
464 {
465     if (nbu_mem_error_callback != NULL)
466     {
467         NbuDbgMemInfo_t memInfo;
468         memcpy(&memInfo, &data[1], sizeof(NbuDbgMemInfo_t));
469         (*nbu_mem_error_callback)((void *)&memInfo);
470     }
471     NOT_USED(len);
472 }
473 
PLATFORM_RxNbuApiIndicationService(uint8_t * data,uint32_t len)474 static void PLATFORM_RxNbuApiIndicationService(uint8_t *data, uint32_t len)
475 {
476     /* NBU API response received, most of the case 6 bytes */
477     assert(len >= 6U && len <= (uint32_t)(2U + NBU_API_MAX_RETURN_PARAM_LENGTH));
478     m_nbu_api_ind_received = true;
479     m_nbu_api_rpmsg_status = (data[1] == 0U) ? false : true;
480 
481     m_nbu_api_return_param_len = len - 2U;
482     memcpy((void *)&m_nbu_api_return_param[0U], &data[2U], m_nbu_api_return_param_len);
483 }
484 
PLATFORM_RxHostSetLowPowerConstraintService(uint8_t * data,uint32_t len)485 static void PLATFORM_RxHostSetLowPowerConstraintService(uint8_t *data, uint32_t len)
486 {
487     if (pLowPowerConstraintCallbacks != NULL)
488     {
489         if (pLowPowerConstraintCallbacks->fwkSrvSetLowPowerConstraint != NULL)
490         {
491             (void)pLowPowerConstraintCallbacks->fwkSrvSetLowPowerConstraint((int32_t)(data[1]));
492         }
493     }
494     NOT_USED(len);
495 }
496 
PLATFORM_RxHostReleaseLowPowerConstraintService(uint8_t * data,uint32_t len)497 static void PLATFORM_RxHostReleaseLowPowerConstraintService(uint8_t *data, uint32_t len)
498 {
499     if (pLowPowerConstraintCallbacks != NULL)
500     {
501         if (pLowPowerConstraintCallbacks->fwkSrvReleaseLowPowerConstraint != NULL)
502         {
503             (void)pLowPowerConstraintCallbacks->fwkSrvReleaseLowPowerConstraint((int32_t)(data[1]));
504         }
505     }
506     NOT_USED(len);
507 }
508 
PLATFORM_RxFroNotificationService(uint8_t * data,uint32_t len)509 static void PLATFORM_RxFroNotificationService(uint8_t *data, uint32_t len)
510 {
511     uint16_t freq     = (((uint16_t)(data[2]) << 8U) & 0xFF00U) + ((uint16_t)(data[1]) & 0xFFU);
512     uint16_t ppm_mean = (((uint16_t)(data[4]) << 8U) & 0xFF00U) + ((uint16_t)(data[3]) & 0xFFU);
513     uint16_t ppm      = (((uint16_t)(data[6]) << 8U) & 0xFF00U) + ((uint16_t)(data[5]) & 0xFFU);
514     uint16_t fro_trim = (((uint16_t)(data[8]) << 8U) & 0xFF00U) + ((uint16_t)(data[7]) & 0xFFU);
515     pfPlatformDebugCallback(freq, (int16_t)ppm_mean, (int16_t)ppm, fro_trim);
516     NOT_USED(len);
517 }
PLATFORM_RxFwkSrvNbuIssueIndicationService(uint8_t * data,uint32_t len)518 static void PLATFORM_RxFwkSrvNbuIssueIndicationService(uint8_t *data, uint32_t len)
519 {
520     if (nbu_issue_callback != NULL)
521     {
522         (*nbu_issue_callback)();
523     }
524     NOT_USED(data);
525     NOT_USED(len);
526 }
527 
PLATFORM_RxNbuSecurityEventIndicationService(uint8_t * data,uint32_t len)528 static void PLATFORM_RxNbuSecurityEventIndicationService(uint8_t *data, uint32_t len)
529 {
530     if (nbu_security_event_callback != NULL)
531     {
532         uint32_t securityEventBitmask;
533         memcpy(&securityEventBitmask, &data[1], sizeof(uint32_t));
534         (*nbu_security_event_callback)(securityEventBitmask);
535     }
536     NOT_USED(len);
537 }
538 
PLATFORM_RxNbuRequestRngSeedService(uint8_t * data,uint32_t len)539 static void PLATFORM_RxNbuRequestRngSeedService(uint8_t *data, uint32_t len)
540 {
541     RNG_TriggerReseed();
542     NOT_USED(data);
543     NOT_USED(len);
544 }
545 
FwkSrv_MsgTypeInExpectedSet(uint8_t msg_type)546 static bool FwkSrv_MsgTypeInExpectedSet(uint8_t msg_type)
547 {
548     return (msg_type > (uint8_t)gFwkSrvNbu2HostFirst_c && msg_type < (uint8_t)gFwkSrvNbu2HostLast_c);
549 }
550