1 /* -------------------------------------------------------------------------- */
2 /* Copyright 2021-2024 NXP */
3 /* All rights reserved. */
4 /* SPDX-License-Identifier: BSD-3-Clause */
5 /* -------------------------------------------------------------------------- */
6
7 /* -------------------------------------------------------------------------- */
8 /* Includes */
9 /* -------------------------------------------------------------------------- */
10
11 #include <stdarg.h>
12 #include "fwk_platform.h"
13 #include "fwk_platform_ics.h"
14 #if defined(FPGA_SUPPORT) && (FPGA_SUPPORT == 1)
15 #include "fwk_platform_fpga.h"
16 #endif
17
18 #include "fsl_os_abstraction.h"
19 #include "fsl_adapter_rpmsg.h"
20 #include "fsl_spc.h"
21
22 #include "rpmsg_platform.h"
23
24 #include "mcmgr_imu_internal.h"
25
26 /* -------------------------------------------------------------------------- */
27 /* Private macros */
28 /* -------------------------------------------------------------------------- */
29
30 /*! @brief XTAL 32Mhz clock source start up timeout */
31 #ifndef FWK_PLATFORM_XTAL32M_STARTUP_TIMEOUT
32 #define FWK_PLATFORM_XTAL32M_STARTUP_TIMEOUT 1000000
33 #endif /* FWK_PLATFORM_XTAL32M_STARTUP_TIMEOUT */
34
35 /*! @brief Delay from the 32MHz wake up of the LL to wake up the radio domain in number of 30.5us period */
36 #if !defined(BOARD_RADIO_DOMAIN_WAKE_UP_DELAY)
37 #define BOARD_RADIO_DOMAIN_WAKE_UP_DELAY 0x10U
38 #endif
39
40 /*! @brief Remote active request timeout */
41 #ifndef FWK_PLATFORM_ACTIVE_REQ_TIMEOUT_US
42 #define FWK_PLATFORM_ACTIVE_REQ_TIMEOUT_US 10000U
43 #endif /* FWK_PLATFORM_ACTIVE_REQ_TIMEOUT_US */
44
45 /* Raise error with status update , shift previous status by 4 bits and OR with new error code.
46 * the returned status will be negative
47 * Note: this macros is defined in sss_crypto.h, we need to undef it to make sure we use our implementation */
48 #undef RAISE_ERROR
49 #define RAISE_ERROR(__st, __error_code) -(int)((uint32_t)(((uint32_t)(__st) << 4) | (uint32_t)(__error_code)));
50
51 /* -------------------------------------------------------------------------- */
52 /* Private memory declarations */
53 /* -------------------------------------------------------------------------- */
54
55 static int nbu_init = 0;
56
57 /****************** LOWPOWER ***********************/
58 /* Number of request for CM3 to remain active */
59 static int8_t active_request_nb = 0;
60
61 extern PLATFORM_ErrorCallback_t pfPlatformErrorCallback;
62 PLATFORM_ErrorCallback_t pfPlatformErrorCallback = (void *)0;
63
64 /* -------------------------------------------------------------------------- */
65 /* Private functions */
66 /* -------------------------------------------------------------------------- */
67
u64ReadTimeStamp(void)68 static uint64_t u64ReadTimeStamp(void)
69 {
70 uint32_t reg_l;
71 uint32_t reg_h;
72 uint32_t regPrimask = DisableGlobalIRQ();
73 /* A complete read operation should include both TSTMR LOW and HIGH reads. If a HIGH read does not follow a LOW
74 * read, then any other Time Stamp value read will be locked at a fixed value. The TSTMR LOW read should occur
75 * first, followed by the TSTMR HIGH read.
76 * */
77 reg_l = TSTMR0->L;
78 __DMB();
79 reg_h = TSTMR0->H;
80
81 EnableGlobalIRQ(regPrimask);
82
83 return (uint64_t)reg_l | (((uint64_t)reg_h) << 32U);
84 }
85 /* -------------------------------------------------------------------------- */
86 /* Public functions */
87 /* -------------------------------------------------------------------------- */
PLATFORM_IsNbuStarted(void)88 int PLATFORM_IsNbuStarted(void)
89 {
90 return nbu_init;
91 }
PLATFORM_InitNbu(void)92 int PLATFORM_InitNbu(void)
93 {
94 int status = 0;
95
96 if (nbu_init == 0)
97 {
98 uint32_t rfmc_ctrl;
99 int cnt = 0;
100
101 rfmc_ctrl = RFMC->RF2P4GHZ_CTRL;
102
103 /* Enables BLE Power Controller on NBU side AND sets LP mode to DeepSleep */
104 rfmc_ctrl &= ~(RFMC_RF2P4GHZ_CTRL_LP_WKUP_DLY_MASK | RFMC_RF2P4GHZ_CTRL_LP_MODE_MASK);
105 rfmc_ctrl |=
106 (RFMC_RF2P4GHZ_CTRL_LP_MODE(0x3) | RFMC_RF2P4GHZ_CTRL_LP_WKUP_DLY(BOARD_RADIO_DOMAIN_WAKE_UP_DELAY) |
107 RFMC_RF2P4GHZ_CTRL_BLE_LP_EN(0x1U) | RFMC_RF2P4GHZ_CTRL_SFA_TRIG_EN(0x7U));
108
109 RFMC->RF2P4GHZ_CTRL = rfmc_ctrl;
110 RFMC->RF2P4GHZ_TIMER |= RFMC_RF2P4GHZ_TIMER_TIM_EN(0x1U);
111
112 /* Enabling BLE Power Controller (BLE_LP_EN) will automatically start the XTAL
113 * According to RM, we need to wait for the XTAL to be ready before accessing
114 * Radio domain ressources.
115 * Here, we make sure the XTAL is ready before releasing the CM3 from reset
116 * it will prevent any access issue when the CM3 is starting up.
117 * CM3 is released in HAL_RpmsgMcmgrInit */
118 while ((cnt++ < FWK_PLATFORM_XTAL32M_STARTUP_TIMEOUT) && ((RFMC->XO_STAT & RFMC_XO_STAT_XTAL_RDY_MASK) == 0U))
119 {
120 __ASM("NOP");
121 }
122
123 if (cnt > FWK_PLATFORM_XTAL32M_STARTUP_TIMEOUT)
124 {
125 status = RAISE_ERROR(0, 1);
126 }
127 else
128 {
129 /* nbu initialization completed */
130 nbu_init = 1;
131 }
132 }
133 else
134 {
135 /* Initialization already done */
136 status = 1;
137 }
138
139 return status;
140 }
141
PLATFORM_InitMulticore(void)142 int PLATFORM_InitMulticore(void)
143 {
144 int status = 0;
145 hal_rpmsg_status_t rpmsg_status;
146 static bool first_call = true;
147 if (first_call)
148 {
149 /* Write in SMU2 the static shared memory config that we have for NBU to use it */
150 platform_set_static_shmem_config();
151 }
152
153 first_call = false;
154
155 /* Start CM3 core and Initializes the RPMSG adapter module for dual core communication */
156 rpmsg_status = HAL_RpmsgMcmgrInit();
157 if (rpmsg_status != kStatus_HAL_RpmsgSuccess)
158 {
159 status = RAISE_ERROR(rpmsg_status, 1);
160 assert(0);
161 }
162
163 #if defined(FPGA_SUPPORT) && (FPGA_SUPPORT == 1)
164 PLATFORM_InitRadio();
165 #endif
166
167 return status;
168 }
169
170 /* get 4 words of information that uniquely identifies the MCU */
PLATFORM_GetMCUUid(uint8_t * aOutUid16B,uint8_t * pOutLen)171 void PLATFORM_GetMCUUid(uint8_t *aOutUid16B, uint8_t *pOutLen)
172 {
173 uint32_t uid[4] = {0};
174
175 /* Get the MCU uid */
176 uid[0] = MSCM->UID[0];
177 uid[1] = MSCM->UID[1];
178 uid[2] = MSCM->UID[2];
179 uid[3] = MSCM->UID[3];
180
181 memcpy(aOutUid16B, (uint8_t *)uid, sizeof(uid));
182 /* Get the uid length */
183 *pOutLen = (uint8_t)sizeof(uid);
184
185 return;
186 }
187
PLATFORM_GetTimeStamp(void)188 uint64_t PLATFORM_GetTimeStamp(void)
189 {
190 /* u64ReadTimeStamp mimics TSTMR_ReadTimeStamp(TSTMR0) but copied to avoid dependency
191 * with fsl_tstmr.h not present in include path
192 */
193 return u64ReadTimeStamp();
194 }
195
PLATFORM_GetMaxTimeStamp(void)196 uint64_t PLATFORM_GetMaxTimeStamp(void)
197 {
198 /* Max timestamp counter value (56 bits)
199 * No conversion to us is needed since the timestamp timer runs off the 1 MHz clock*/
200 return ((uint64_t)0xFFFFFFFFFFFFFFU);
201 }
202
PLATFORM_IsTimeoutExpired(uint64_t timestamp,uint64_t delayUs)203 bool PLATFORM_IsTimeoutExpired(uint64_t timestamp, uint64_t delayUs)
204 {
205 uint64_t now, duration;
206
207 now = PLATFORM_GetTimeStamp();
208
209 if (now < timestamp)
210 {
211 /* Handle counter wrapping */
212 duration = PLATFORM_GetMaxTimeStamp() - timestamp + now;
213 }
214 else
215 {
216 duration = now - timestamp;
217 }
218 return (duration >= delayUs);
219 }
220
PLATFORM_WaitTimeout(uint64_t timestamp,uint64_t delayUs)221 void PLATFORM_WaitTimeout(uint64_t timestamp, uint64_t delayUs)
222 {
223 while (!(PLATFORM_IsTimeoutExpired(timestamp, delayUs)))
224 {
225 }
226 }
227
PLATFORM_Delay(uint64_t delayUs)228 void PLATFORM_Delay(uint64_t delayUs)
229 {
230 /* PLATFORM_Delay() is similar to PLATFORM_WaitTimeout() but timestamp is taken right now */
231 PLATFORM_WaitTimeout(PLATFORM_GetTimeStamp(), delayUs);
232 }
233
PLATFORM_RemoteActiveReq(void)234 void PLATFORM_RemoteActiveReq(void)
235 {
236 OSA_InterruptDisable();
237
238 if (active_request_nb == 0)
239 {
240 uint32_t rfmc_ctrl = RFMC->RF2P4GHZ_CTRL;
241 bool remote_in_lp = false;
242 uint64_t timestamp = PLATFORM_GetTimeStamp();
243
244 /* Set lp wakeup delay to 0 to reduce time of execution on host side, NBU will wait XTAL to be ready before
245 * starting execution */
246 uint32_t lp_wakeup_delay;
247 lp_wakeup_delay = (rfmc_ctrl & RFMC_RF2P4GHZ_CTRL_LP_WKUP_DLY_MASK) >> RFMC_RF2P4GHZ_CTRL_LP_WKUP_DLY_SHIFT;
248 rfmc_ctrl &= ~(RFMC_RF2P4GHZ_CTRL_LP_WKUP_DLY_MASK);
249 rfmc_ctrl |= RFMC_RF2P4GHZ_CTRL_LP_WKUP_DLY(0U);
250 RFMC->RF2P4GHZ_CTRL = rfmc_ctrl;
251
252 /* CM3 writes to WKUP_TIME register to notify CM33 it's going to low
253 * power, this is a software protocol to sync both cores */
254 while ((RFMC->RF2P4GHZ_MAN2 & RFMC_RF2P4GHZ_MAN2_WKUP_TIME_MASK) != 0U)
255 {
256 /* CM3 started low power entry, to workaround HW issues, we need to
257 * wait for the radio to fully enter low power before waking it up */
258 if ((RFMC->RF2P4GHZ_STAT & RFMC_RF2P4GHZ_STAT_BLE_STATE_MASK) == RFMC_RF2P4GHZ_STAT_BLE_STATE(0x2U))
259 {
260 /* Radio is in low power, we can exit the loop and wake it up */
261 remote_in_lp = true;
262 break;
263 }
264 /* Error callback set by PLATFORM_RegisterBleErrorCallback() */
265 if (PLATFORM_IsTimeoutExpired(timestamp, FWK_PLATFORM_ACTIVE_REQ_TIMEOUT_US) &&
266 (pfPlatformErrorCallback != NULL))
267 {
268 pfPlatformErrorCallback(PLATFORM_REMOTE_ACTIVE_REQ_ID, -1);
269 break;
270 }
271 }
272
273 rfmc_ctrl |= RFMC_RF2P4GHZ_CTRL_BLE_WKUP(0x1U);
274 RFMC->RF2P4GHZ_CTRL = rfmc_ctrl;
275
276 __DSB();
277
278 if (remote_in_lp == true)
279 {
280 /* Wake up time is around 5 periods of 32khz clock (160us)
281 * Adding a delay of 120us shouldn't impact waiting time, and will
282 * make sure the BLE_STATE is reliable */
283 PLATFORM_Delay(120U);
284 }
285
286 timestamp = PLATFORM_GetTimeStamp();
287 /* Wait for the NBU to become active */
288 while ((RFMC->RF2P4GHZ_STAT & RFMC_RF2P4GHZ_STAT_BLE_STATE_MASK) != RFMC_RF2P4GHZ_STAT_BLE_STATE(0x1U))
289 {
290 __ASM("NOP");
291 /* Error callback set by PLATFORM_RegisterBleErrorCallback() */
292 if (PLATFORM_IsTimeoutExpired(timestamp, FWK_PLATFORM_ACTIVE_REQ_TIMEOUT_US) &&
293 (pfPlatformErrorCallback != NULL))
294 {
295 pfPlatformErrorCallback(PLATFORM_REMOTE_ACTIVE_REQ_ID, -2);
296 break;
297 }
298 }
299 rfmc_ctrl |= RFMC_RF2P4GHZ_CTRL_LP_WKUP_DLY(lp_wakeup_delay);
300 RFMC->RF2P4GHZ_CTRL = rfmc_ctrl;
301 }
302 else
303 {
304 ;
305 }
306
307 active_request_nb++;
308
309 OSA_InterruptEnable();
310
311 }
312
PLATFORM_RemoteActiveRel(void)313 void PLATFORM_RemoteActiveRel(void)
314 {
315 OSA_InterruptDisable();
316
317 assert(active_request_nb > 0);
318 active_request_nb--;
319
320 if (active_request_nb == 0)
321 {
322 uint32_t rfmc_ctrl;
323 rfmc_ctrl = RFMC->RF2P4GHZ_CTRL;
324 rfmc_ctrl &= ~RFMC_RF2P4GHZ_CTRL_BLE_WKUP_MASK;
325 RFMC->RF2P4GHZ_CTRL = rfmc_ctrl;
326 }
327
328 OSA_InterruptEnable();
329 }
330
mcmgr_imu_remote_active_rel(void)331 void mcmgr_imu_remote_active_rel(void)
332 {
333 PLATFORM_RemoteActiveRel();
334 }
335
mcmgr_imu_remote_active_req(void)336 void mcmgr_imu_remote_active_req(void)
337 {
338 PLATFORM_RemoteActiveReq();
339 }
340
PLATFORM_SetNbuConstraintFrequency(PLATFORM_NbuConstraintFrequency_t freq_constraint)341 void PLATFORM_SetNbuConstraintFrequency(PLATFORM_NbuConstraintFrequency_t freq_constraint)
342 {
343 (void)PLATFORM_FwkSrvSendPacket(gFwkSrvNbuUpdateFrequencyConstraintFromHost, &freq_constraint,
344 (uint16_t)sizeof(freq_constraint));
345 }
346
PLATFORM_RegisterErrorCallback(PLATFORM_ErrorCallback_t cb)347 void PLATFORM_RegisterErrorCallback(PLATFORM_ErrorCallback_t cb)
348 {
349 pfPlatformErrorCallback = cb;
350 }
351
PLATFORM_ClearIoIsolationFromLowPower(void)352 int PLATFORM_ClearIoIsolationFromLowPower(void)
353 {
354 int ret = 0;
355 if ((SPC_CheckPowerDomainLowPowerRequest(SPC0, kSPC_PowerDomain0) == true) &&
356 (SPC_GetPowerDomainLowPowerMode(SPC0, kSPC_PowerDomain0) >= kSPC_PowerDownWithSysClockOff))
357 {
358 /* We need to release IO isolation when exiting from Power Down mode
359 * This is done here after all peripherals have been reinitialized, to
360 * avoid any glitch on IOs */
361 SPC_ClearPeriphIOIsolationFlag(SPC0);
362
363 ret = 1;
364 }
365 return ret;
366 }
367