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