1 /*
2  * Copyright 2020-2024 NXP
3  *
4  * SPDX-License-Identifier: BSD-3-Clause
5  */
6 #include <stdio.h>
7 #include <string.h>
8 
9 #include "rpmsg_platform.h"
10 #include "rpmsg_default_config.h"
11 #include "rpmsg_lite.h"
12 
13 #include "rpmsg_env.h"
14 
15 #include "fsl_device_registers.h"
16 #include "fsl_imu.h"
17 
18 #if defined(RL_USE_MCMGR_IPC_ISR_HANDLER) && (RL_USE_MCMGR_IPC_ISR_HANDLER == 1)
19 #include "mcmgr.h"
20 #endif
21 
22 #if defined(RL_USE_ENVIRONMENT_CONTEXT) && (RL_USE_ENVIRONMENT_CONTEXT == 1)
23 #error "This RPMsg-Lite port requires RL_USE_ENVIRONMENT_CONTEXT set to 0"
24 #endif
25 
26 #define APP_MU_IRQ_PRIORITY (3U)
27 
28 #if defined(IMU_CPU_INDEX) && (IMU_CPU_INDEX == 1U)
29 #define APP_MU_IRQn  RF_IMU0_IRQn
30 #define APP_IMU_LINK kIMU_LinkCpu1Cpu2
31 #elif defined(IMU_CPU_INDEX) && (IMU_CPU_INDEX == 2U)
32 #define APP_MU_IRQn  CPU2_MSG_RDY_INT_IRQn
33 #define APP_IMU_LINK kIMU_LinkCpu2Cpu1
34 #endif
35 
36 /* Generator for CRC calculations. */
37 #define POLGEN 0x1021U
38 
39 static int32_t isr_counter     = 0;
40 static int32_t disable_counter = 0;
41 static void *platform_lock;
42 #if defined(RL_USE_STATIC_API) && (RL_USE_STATIC_API == 1)
43 static LOCK_STATIC_CONTEXT platform_lock_static_ctxt;
44 #endif
45 
46 /* This structure is used to validate that shmem config that is stored in SMU2 is valid */
47 typedef struct rpmsg_platform_shmem_config_protected
48 {
49     uint8_t identificationWord[10];
50     rpmsg_platform_shmem_config_t config;
51     uint16_t shmemConfigCrc;
52 } rpmsg_platform_shmem_config_protected_t;
53 
54 static const uint8_t ShmemConfigIdentifier[12] = {"SMEM_CONFIG:"};
55 
56 /* Compute CRC to protect shared memory strcuture stored in RAM by application core and retrieve by NBU */
57 static uint16_t platform_compute_crc_over_shmem_struct(rpmsg_platform_shmem_config_protected_t *protected_structure);
58 
59 static uint32_t first_time                        = RL_TRUE;
60 static rpmsg_platform_shmem_config_t shmem_config = {0U};
61 
62 #if defined(RL_USE_MCMGR_IPC_ISR_HANDLER) && (RL_USE_MCMGR_IPC_ISR_HANDLER == 1)
mcmgr_event_handler(uint16_t vring_idx,void * context)63 static void mcmgr_event_handler(uint16_t vring_idx, void *context)
64 {
65     env_isr((uint32_t)vring_idx);
66 }
67 #else
68 
69 /* MU ISR router */
imu_rx_isr()70 static void imu_rx_isr()
71 {
72     env_isr(0);
73     IMU_ClearPendingInterrupts(APP_IMU_LINK, IMU_MSG_FIFO_CNTL_MSG_RDY_INT_CLR_MASK);
74 }
75 
76 #if defined(IMU_CPU_INDEX) && (IMU_CPU_INDEX == 1U)
RF_IMU0_IRQHandler(void)77 int32_t RF_IMU0_IRQHandler(void)
78 {
79     imu_rx_isr();
80     SDK_ISR_EXIT_BARRIER;
81     return 0;
82 }
83 #endif
84 
85 #if defined(IMU_CPU_INDEX) && (IMU_CPU_INDEX == 2U)
CPU2_MSG_RDY_INT_IRQHandler(void)86 int32_t CPU2_MSG_RDY_INT_IRQHandler(void)
87 {
88     imu_rx_isr();
89     SDK_ISR_EXIT_BARRIER;
90     return 0;
91 }
92 #endif /* IMU_CPU_INDEX */
93 #endif
94 
platform_global_isr_disable(void)95 static void platform_global_isr_disable(void)
96 {
97     __asm volatile("cpsid i");
98 }
99 
platform_global_isr_enable(void)100 static void platform_global_isr_enable(void)
101 {
102     __asm volatile("cpsie i");
103 }
104 
platform_init_interrupt(uint32_t vector_id,void * isr_data)105 int32_t platform_init_interrupt(uint32_t vector_id, void *isr_data)
106 {
107     if (platform_lock != ((void *)0))
108     {
109         /* Register ISR to environment layer */
110         env_register_isr(vector_id, isr_data);
111 
112         env_lock_mutex(platform_lock);
113 
114         RL_ASSERT(0 <= isr_counter);
115         if (isr_counter < 2)
116         {
117             (void)EnableIRQ(APP_MU_IRQn);
118         }
119         isr_counter++;
120 
121         env_unlock_mutex(platform_lock);
122         return 0;
123     }
124     else
125     {
126         return -1;
127     }
128 }
129 
platform_deinit_interrupt(uint32_t vector_id)130 int32_t platform_deinit_interrupt(uint32_t vector_id)
131 {
132     if (platform_lock != ((void *)0))
133     {
134         env_lock_mutex(platform_lock);
135 
136         RL_ASSERT(0 < isr_counter);
137         isr_counter--;
138         if (isr_counter < 2)
139         {
140             (void)DisableIRQ(APP_MU_IRQn);
141         }
142 
143         /* Unregister ISR from environment layer */
144         env_unregister_isr(vector_id);
145 
146         env_unlock_mutex(platform_lock);
147 
148         return 0;
149     }
150     else
151     {
152         return -1;
153     }
154 }
155 
platform_notify(uint32_t vector_id)156 void platform_notify(uint32_t vector_id)
157 {
158     env_lock_mutex(platform_lock);
159 #if defined(RL_USE_MCMGR_IPC_ISR_HANDLER) && (RL_USE_MCMGR_IPC_ISR_HANDLER == 1)
160     (void)MCMGR_TriggerEvent(kMCMGR_RemoteRPMsgEvent, (uint16_t)RL_GET_Q_ID(vector_id));
161 #else
162     /* TO Not support*/
163 #endif
164     env_unlock_mutex(platform_lock);
165 }
166 
167 /**
168  * platform_time_delay
169  *
170  * @param num_msec Delay time in ms.
171  *
172  * This is not an accurate delay, it ensures at least num_msec passed when return.
173  */
platform_time_delay(uint32_t num_msec)174 void platform_time_delay(uint32_t num_msec)
175 {
176     uint32_t loop;
177 
178     /* Recalculate the CPU frequency */
179     SystemCoreClockUpdate();
180 
181     /* Calculate the CPU loops to delay, each loop has 3 cycles */
182     loop = SystemCoreClock / 3U / 1000U * num_msec;
183 
184     /* There's some difference among toolchains, 3 or 4 cycles each loop */
185     while (loop > 0U)
186     {
187         __NOP();
188         loop--;
189     }
190 }
191 
192 /**
193  * platform_in_isr
194  *
195  * Return whether CPU is processing IRQ
196  *
197  * @return True for IRQ, false otherwise.
198  *
199  */
platform_in_isr(void)200 int32_t platform_in_isr(void)
201 {
202     /* coco begin validated: This platform-dependent function is used in OS-based environments only, not used in
203      * baremetal app */
204     return (((SCB->ICSR & SCB_ICSR_VECTACTIVE_Msk) != 0UL) ? 1 : 0);
205 }
206 /* coco end */
207 
208 /**
209  * platform_interrupt_enable
210  *
211  * Enable peripheral-related interrupt
212  *
213  * @param vector_id Virtual vector ID that needs to be converted to IRQ number
214  *
215  * @return vector_id Return value is never checked.
216  *
217  */
platform_interrupt_enable(uint32_t vector_id)218 int32_t platform_interrupt_enable(uint32_t vector_id)
219 {
220     RL_ASSERT(0 < disable_counter);
221 
222     platform_global_isr_disable();
223     disable_counter--;
224 
225     if (disable_counter == 0)
226     {
227         NVIC_EnableIRQ(APP_MU_IRQn);
228     }
229     platform_global_isr_enable();
230     return ((int32_t)vector_id);
231 }
232 
233 /**
234  * platform_interrupt_disable
235  *
236  * Disable peripheral-related interrupt.
237  *
238  * @param vector_id Virtual vector ID that needs to be converted to IRQ number
239  *
240  * @return vector_id Return value is never checked.
241  *
242  */
platform_interrupt_disable(uint32_t vector_id)243 int32_t platform_interrupt_disable(uint32_t vector_id)
244 {
245     RL_ASSERT(0 <= disable_counter);
246 
247     platform_global_isr_disable();
248     /* virtqueues use the same NVIC vector
249        if counter is set - the interrupts are disabled */
250     if (disable_counter == 0)
251     {
252         NVIC_DisableIRQ(APP_MU_IRQn);
253     }
254     disable_counter++;
255     platform_global_isr_enable();
256     return ((int32_t)vector_id);
257 }
258 
259 /**
260  * platform_map_mem_region
261  *
262  * Dummy implementation
263  *
264  */
platform_map_mem_region(uint32_t vrt_addr,uint32_t phy_addr,uint32_t size,uint32_t flags)265 void platform_map_mem_region(uint32_t vrt_addr, uint32_t phy_addr, uint32_t size, uint32_t flags)
266 {
267 }
268 
269 /**
270  * platform_cache_all_flush_invalidate
271  *
272  * Dummy implementation
273  *
274  */
platform_cache_all_flush_invalidate(void)275 void platform_cache_all_flush_invalidate(void)
276 {
277 }
278 
279 /**
280  * platform_cache_disable
281  *
282  * Dummy implementation
283  *
284  */
platform_cache_disable(void)285 void platform_cache_disable(void)
286 {
287 }
288 
289 /**
290  * platform_init
291  *
292  * platform/environment init
293  */
platform_init(void)294 int32_t platform_init(void)
295 {
296 #if defined(RL_USE_MCMGR_IPC_ISR_HANDLER) && (RL_USE_MCMGR_IPC_ISR_HANDLER == 1)
297     mcmgr_status_t retval = kStatus_MCMGR_Error;
298     retval                = MCMGR_RegisterEvent(kMCMGR_RemoteRPMsgEvent, mcmgr_event_handler, ((void *)0));
299     if (kStatus_MCMGR_Success != retval)
300     {
301         return -1; /* coco validated: line never reached, MCMGR_RegisterEvent() fails only when the type parameter is
302                       out of scope, here the correct kMCMGR_RemoteRPMsgEvent is passed */
303     }
304 #else
305     IMU_Init(APP_IMU_LINK);
306     NVIC_SetPriority(APP_MU_IRQn, APP_MU_IRQ_PRIORITY);
307     NVIC_EnableIRQ(APP_MU_IRQn);
308 #endif
309 
310     /* Create lock used in multi-instanced RPMsg */
311 #if defined(RL_USE_STATIC_API) && (RL_USE_STATIC_API == 1)
312     if (0 != env_create_mutex(&platform_lock, 1, &platform_lock_static_ctxt))
313 #else
314     if (0 != env_create_mutex(&platform_lock, 1))
315 #endif
316     {
317         return -1; /* coco validated: not able to force the application to reach this line */
318     }
319 
320     return 0;
321 }
322 
323 /**
324  * platform_deinit
325  *
326  * platform/environment deinit process
327  */
platform_deinit(void)328 int32_t platform_deinit(void)
329 {
330     IMU_Deinit(APP_IMU_LINK);
331 
332     /* Delete lock used in multi-instanced RPMsg */
333     env_delete_mutex(platform_lock);
334     platform_lock = ((void *)0);
335     return 0;
336 }
337 
platform_set_static_shmem_config(void)338 void platform_set_static_shmem_config(void)
339 {
340     extern uint32_t rpmsg_sh_mem_start[];
341     rpmsg_platform_shmem_config_protected_t protec_shmem_struct;
342 
343     /* Identifier at the beginning of the structure that will be used to verify on nbu side validity of the structure */
344     memcpy(&(protec_shmem_struct.identificationWord), ShmemConfigIdentifier, sizeof(ShmemConfigIdentifier));
345 
346     /* Fill shared memory structure with setting from the app core */
347     protec_shmem_struct.config.buffer_payload_size = RL_BUFFER_PAYLOAD_SIZE;
348     protec_shmem_struct.config.buffer_count        = RL_BUFFER_COUNT;
349     protec_shmem_struct.config.vring_size          = VRING_SIZE;
350     protec_shmem_struct.config.vring_align         = VRING_ALIGN;
351 
352     /* Calculate and set CRC of the strucuture */
353     protec_shmem_struct.shmemConfigCrc = platform_compute_crc_over_shmem_struct(&protec_shmem_struct);
354 
355     /* Store in SMU2 the all structure */
356     memcpy(rpmsg_sh_mem_start, &protec_shmem_struct, sizeof(rpmsg_platform_shmem_config_protected_t));
357 }
358 
platform_get_custom_shmem_config(uint32_t link_id,rpmsg_platform_shmem_config_t * config)359 uint32_t platform_get_custom_shmem_config(uint32_t link_id, rpmsg_platform_shmem_config_t *config)
360 {
361     extern uint32_t rpmsg_sh_mem_start[];
362     rpmsg_platform_shmem_config_protected_t protec_shmem_struct = {0U};
363 
364     do
365     {
366         if (first_time == RL_FALSE)
367         {
368             /* Variable shmem_config is already set if this is not the fisrt call */
369             break;
370         }
371 
372         first_time = RL_FALSE;
373 
374         /* Copy the full structure in local variable */
375         memcpy(&protec_shmem_struct, rpmsg_sh_mem_start, sizeof(rpmsg_platform_shmem_config_protected_t));
376 
377         /* By default set the values of the MR3 connectivity release */
378         shmem_config.buffer_payload_size = 496U;
379         shmem_config.buffer_count        = 4U;
380         shmem_config.vring_size          = 0x80U;
381         shmem_config.vring_align         = 0x10U;
382 
383         if (memcmp(&(protec_shmem_struct.identificationWord), ShmemConfigIdentifier, sizeof(ShmemConfigIdentifier)) !=
384             0U)
385         {
386             break;
387         }
388         if (platform_compute_crc_over_shmem_struct(&protec_shmem_struct) != protec_shmem_struct.shmemConfigCrc)
389         {
390             break;
391         }
392         /* If the identifier and the CRC are correct we can copy the shared memory config stored in SMU2 in local
393          * variable */
394         memcpy(&shmem_config, &(protec_shmem_struct.config), sizeof(rpmsg_platform_shmem_config_t));
395 
396     } while (false);
397 
398     memcpy(config, &shmem_config, sizeof(rpmsg_platform_shmem_config_t));
399 
400     (void)link_id;
401 
402     return 0U;
403 }
404 
platform_compute_crc_over_shmem_struct(rpmsg_platform_shmem_config_protected_t * protec_shmem_struct)405 static uint16_t platform_compute_crc_over_shmem_struct(rpmsg_platform_shmem_config_protected_t *protec_shmem_struct)
406 {
407     uint16_t computedCRC = 0U;
408     uint8_t crcA;
409     uint8_t byte = 0U;
410 
411     uint8_t *ptr = (uint8_t *)(&protec_shmem_struct->config);
412     uint16_t len = (uint16_t)((uint32_t)(uint8_t *)(&protec_shmem_struct->shmemConfigCrc) -
413                               (uint32_t)(uint8_t *)(&protec_shmem_struct->config));
414     while (len != 0U)
415     {
416         byte = *ptr;
417         computedCRC ^= ((uint16_t)byte << 8U);
418         for (crcA = 8U; crcA != 0U; crcA--)
419         {
420             if ((computedCRC & 0x8000U) != 0U)
421             {
422                 computedCRC <<= 1U;
423                 computedCRC ^= POLGEN;
424             }
425             else
426             {
427                 computedCRC <<= 1U;
428             }
429         }
430         --len;
431         ++ptr;
432     }
433     return computedCRC;
434 }
435