1 /*
2 * Copyright (c) 2020 - 2024 Renesas Electronics Corporation and/or its affiliates
3 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 */
6 
7 /***********************************************************************************************************************
8  * Includes
9  **********************************************************************************************************************/
10 #include "r_mhu_ns.h"
11 
12 /***********************************************************************************************************************
13  * Macro definitions
14  **********************************************************************************************************************/
15 
16 /** "MHU" in ASCII, used to determine if channel is open. */
17 #define MHU_NS_OPEN                (0x00774855ULL)
18 
19 #define MHU_NS_SHMEM_CH_SIZE       (0x8)
20 #define MHU_NS_RSP_TXD_OFFSET      (0x0)
21 #define MHU_NS_MSG_TXD_OFFSET      (0x4)
22 
23 /**********************************************************************************************************************
24  * Typedef definitions
25  **********************************************************************************************************************/
26 #if defined(__ARMCC_VERSION) || defined(__ICCARM__)
27 typedef void (BSP_CMSE_NONSECURE_CALL * mhu_ns_prv_ns_callback)(mhu_callback_args_t * p_args);
28 #elif defined(__GNUC__)
29 typedef BSP_CMSE_NONSECURE_CALL void (*volatile mhu_ns_prv_ns_callback)(mhu_callback_args_t * p_args);
30 #endif
31 
32 /***********************************************************************************************************************
33  * Private function prototypes
34  **********************************************************************************************************************/
35 static void r_mhu_ns_set_send_data(mhu_ns_instance_ctrl_t * p_instance_ctrl, uint32_t msg);
36 
37 static fsp_err_t r_mhu_ns_common_preamble(mhu_ns_instance_ctrl_t * p_instance_ctrl);
38 
39 #if MHU_NS_CFG_PARAM_CHECKING_ENABLE
40 static fsp_err_t r_mhu_ns_open_param_checking(mhu_ns_instance_ctrl_t * p_instance_ctrl, mhu_cfg_t const * const p_cfg);
41 
42 #endif
43 
44 /* ISRs. */
45 void mhu_ns_int_isr(void);
46 void metal_irq_isr_wrapper(void);
47 void metal_irq_isr(uint32_t vector);
48 
49 /***********************************************************************************************************************
50  * Private global variables
51  **********************************************************************************************************************/
52 
53 /** Version data structure. */
54 
55 extern uint32_t __mhu_shmem_start;
56 
57 static const uint32_t g_shmem_base = (uint32_t) &__mhu_shmem_start;
58 
59 /***********************************************************************************************************************
60  * Global Variables
61  **********************************************************************************************************************/
62 
63 /** MHU_NS Implementation of MHU Driver  */
64 const mhu_api_t g_mhu_ns_on_mhu_ns =
65 {
66     .open        = R_MHU_NS_Open,
67     .msgSend     = R_MHU_NS_MsgSend,
68     .callbackSet = R_MHU_NS_CallbackSet,
69     .close       = R_MHU_NS_Close,
70 };
71 
72 /*******************************************************************************************************************//**
73  * @addtogroup MHU_NS
74  * @{
75  **********************************************************************************************************************/
76 
77 /***********************************************************************************************************************
78  * Functions
79  **********************************************************************************************************************/
80 
81 /*******************************************************************************************************************//**
82  * Initializes the MHU_NS module instance. Implements @ref mhu_api_t::open.
83  *
84  * @retval FSP_SUCCESS                 Initialization was successful.
85  * @retval FSP_ERR_ASSERTION           A required input pointer is NULL.
86  * @retval FSP_ERR_ALREADY_OPEN        R_MHU_NS_Open has already been called for this p_ctrl.
87  * @retval FSP_ERR_INVALID_ARGUMENT    The specified IRQ number is invalid.
88  * @retval FSP_ERR_INVALID_CHANNEL     Requested channel number is not available on MHU_NS.
89  **********************************************************************************************************************/
R_MHU_NS_Open(mhu_ctrl_t * const p_ctrl,mhu_cfg_t const * const p_cfg)90 fsp_err_t R_MHU_NS_Open (mhu_ctrl_t * const p_ctrl, mhu_cfg_t const * const p_cfg)
91 {
92     mhu_ns_instance_ctrl_t * p_instance_ctrl = (mhu_ns_instance_ctrl_t *) p_ctrl;
93 
94 #if MHU_NS_CFG_PARAM_CHECKING_ENABLE
95     fsp_err_t err = r_mhu_ns_open_param_checking(p_instance_ctrl, p_cfg);
96     FSP_ERROR_RETURN(FSP_SUCCESS == err, err);
97 #endif
98 
99     p_instance_ctrl->p_regs = (R_MHU0_Type *) (R_MHU_NS0_BASE +
100                                                (p_cfg->channel *
101                                                 ((intptr_t) R_MHU_NS1_BASE - (intptr_t) R_MHU_NS0_BASE)));
102     p_instance_ctrl->p_cfg   = p_cfg;
103     p_instance_ctrl->channel = p_cfg->channel;
104 
105     p_instance_ctrl->send_type =
106         ((1U << p_cfg->channel) &
107          BSP_FEATURE_MHU_NS_SEND_TYPE_RSP_VALID_CHANNEL_MASK) ? MHU_SEND_TYPE_RSP : MHU_SEND_TYPE_MSG;
108 
109     if (0 != p_cfg->p_shared_memory)
110     {
111         /* Use specified address */
112         if (p_instance_ctrl->send_type == MHU_SEND_TYPE_RSP)
113         {
114             p_instance_ctrl->p_shared_memory_tx = (uint32_t *) (((uint32_t) p_cfg->p_shared_memory) +
115                                                                 MHU_NS_RSP_TXD_OFFSET);
116             p_instance_ctrl->p_shared_memory_rx = (uint32_t *) (((uint32_t) p_cfg->p_shared_memory) +
117                                                                 MHU_NS_MSG_TXD_OFFSET);
118         }
119         else
120         {
121             p_instance_ctrl->p_shared_memory_tx = (uint32_t *) (((uint32_t) p_cfg->p_shared_memory) +
122                                                                 MHU_NS_MSG_TXD_OFFSET);
123             p_instance_ctrl->p_shared_memory_rx = (uint32_t *) (((uint32_t) p_cfg->p_shared_memory) +
124                                                                 MHU_NS_RSP_TXD_OFFSET);
125         }
126     }
127     else
128     {
129         /* Use default location */
130         if (p_instance_ctrl->send_type == MHU_SEND_TYPE_RSP)
131         {
132             p_instance_ctrl->p_shared_memory_tx =
133                 (uint32_t *) (g_shmem_base + (MHU_NS_SHMEM_CH_SIZE * p_cfg->channel) +
134                               MHU_NS_RSP_TXD_OFFSET);
135             p_instance_ctrl->p_shared_memory_rx =
136                 (uint32_t *) (g_shmem_base + (MHU_NS_SHMEM_CH_SIZE * p_cfg->channel) +
137                               MHU_NS_MSG_TXD_OFFSET);
138         }
139         else
140         {
141             p_instance_ctrl->p_shared_memory_tx =
142                 (uint32_t *) (g_shmem_base + (MHU_NS_SHMEM_CH_SIZE * p_cfg->channel) +
143                               MHU_NS_MSG_TXD_OFFSET);
144             p_instance_ctrl->p_shared_memory_rx =
145                 (uint32_t *) (g_shmem_base + (MHU_NS_SHMEM_CH_SIZE * p_cfg->channel) +
146                               MHU_NS_RSP_TXD_OFFSET);
147         }
148     }
149 
150     /* Power on the MHU_NS channel. */
151     R_BSP_MODULE_START(FSP_IP_MHU, p_cfg->channel);
152 
153     R_BSP_IrqCfgEnable(p_cfg->rx_irq, p_cfg->rx_ipl, p_instance_ctrl);
154 
155     /* Set callback and context pointers */
156 
157 #if BSP_TZ_SECURE_BUILD
158 
159     /* If this is a secure build, the callback provided in p_cfg must be secure. */
160     p_instance_ctrl->callback_is_secure = true;
161 #endif
162     p_instance_ctrl->p_callback        = p_cfg->p_callback;
163     p_instance_ctrl->p_context         = p_cfg->p_context;
164     p_instance_ctrl->p_callback_memory = NULL;
165 
166     p_instance_ctrl->open = MHU_NS_OPEN;
167 
168     /* All done.  */
169     return FSP_SUCCESS;
170 }
171 
172 /**********************************************************************************************************************
173  * End of function R_MHU_NS_Open
174  *********************************************************************************************************************/
175 
176 /*******************************************************************************************************************//**
177  * Send message via MHU.
178  * Implements @ref mhu_api_t::msgSend.
179  *
180  * @retval FSP_SUCCESS                 Send message successfully.
181  * @retval FSP_ERR_ASSERTION           A required pointer was NULL.
182  * @retval FSP_ERR_NOT_OPEN            The instance control structure is not opened.
183  **********************************************************************************************************************/
R_MHU_NS_MsgSend(mhu_ctrl_t * const p_ctrl,uint32_t const msg)184 fsp_err_t R_MHU_NS_MsgSend (mhu_ctrl_t * const p_ctrl, uint32_t const msg)
185 {
186     mhu_ns_instance_ctrl_t * p_instance_ctrl = (mhu_ns_instance_ctrl_t *) p_ctrl;
187 #if MHU_NS_CFG_PARAM_CHECKING_ENABLE
188 #endif
189 
190     fsp_err_t err = r_mhu_ns_common_preamble(p_instance_ctrl);
191     FSP_ERROR_RETURN(FSP_SUCCESS == err, err);
192 
193     /* Set msg. */
194     r_mhu_ns_set_send_data(p_instance_ctrl, msg);
195 
196     return FSP_SUCCESS;
197 }
198 
199 /**********************************************************************************************************************
200  * End of function R_MHU_NS_MsgSend
201  *********************************************************************************************************************/
202 
203 /*******************************************************************************************************************//**
204  * Updates the user callback with the option to provide memory for the callback argument structure.
205  * Implements @ref mhu_api_t::callbackSet.
206  *
207  * @retval  FSP_SUCCESS                  Callback updated successfully.
208  * @retval  FSP_ERR_ASSERTION            A required pointer is NULL.
209  * @retval  FSP_ERR_NOT_OPEN             The control block has not been opened.
210  * @retval  FSP_ERR_NO_CALLBACK_MEMORY   p_callback is non-secure and p_callback_memory is either secure or NULL.
211  **********************************************************************************************************************/
R_MHU_NS_CallbackSet(mhu_ctrl_t * const p_api_ctrl,void (* p_callback)(mhu_callback_args_t *),void const * const p_context,mhu_callback_args_t * const p_callback_memory)212 fsp_err_t R_MHU_NS_CallbackSet (mhu_ctrl_t * const          p_api_ctrl,
213                                 void (                    * p_callback)(mhu_callback_args_t *),
214                                 void const * const          p_context,
215                                 mhu_callback_args_t * const p_callback_memory)
216 {
217     mhu_ns_instance_ctrl_t * p_ctrl = (mhu_ns_instance_ctrl_t *) p_api_ctrl;
218 
219 #if MHU_NS_CFG_PARAM_CHECKING_ENABLE
220     FSP_ASSERT(p_ctrl);
221     FSP_ASSERT(p_callback);
222     FSP_ERROR_RETURN(MHU_NS_OPEN == p_ctrl->open, FSP_ERR_NOT_OPEN);
223 #endif
224 
225 #if BSP_TZ_SECURE_BUILD
226 
227     /* Get security state of p_callback */
228     p_ctrl->callback_is_secure =
229         (NULL == cmse_check_address_range((void *) p_callback, sizeof(void *), CMSE_AU_NONSECURE));
230 
231  #if MHU_NS_CFG_PARAM_CHECKING_ENABLE
232 
233     /* In secure projects, p_callback_memory must be provided in non-secure space if p_callback is non-secure */
234     mhu_callback_args_t * const p_callback_memory_checked = cmse_check_pointed_object(p_callback_memory,
235                                                                                       CMSE_AU_NONSECURE);
236     FSP_ERROR_RETURN(p_ctrl->callback_is_secure || (NULL != p_callback_memory_checked), FSP_ERR_NO_CALLBACK_MEMORY);
237  #endif
238 #endif
239 
240     /* Store callback and context */
241 
242 #if BSP_TZ_SECURE_BUILD
243 
244     /* cmse_check_address_range returns NULL if p_callback is located in secure memory */
245     p_ctrl->callback_is_secure =
246         (NULL == cmse_check_address_range((void *) p_callback, sizeof(void *), CMSE_AU_NONSECURE));
247 #endif
248     p_ctrl->p_callback        = p_callback;
249     p_ctrl->p_context         = p_context;
250     p_ctrl->p_callback_memory = p_callback_memory;
251 
252     return FSP_SUCCESS;
253 }
254 
255 /**********************************************************************************************************************
256  * End of function R_MHU_NS_CallbackSet
257  *********************************************************************************************************************/
258 
259 /*******************************************************************************************************************//**
260  * Disables interrupts, clears internal driver data.
261  * @ref mhu_api_t::close.
262  *
263  * @retval FSP_SUCCESS                 MHU_NS closed.
264  * @retval FSP_ERR_ASSERTION           p_ctrl is NULL.
265  * @retval FSP_ERR_NOT_OPEN            The instance control structure is not opened.
266  **********************************************************************************************************************/
R_MHU_NS_Close(mhu_ctrl_t * const p_ctrl)267 fsp_err_t R_MHU_NS_Close (mhu_ctrl_t * const p_ctrl)
268 {
269     mhu_ns_instance_ctrl_t * p_instance_ctrl = (mhu_ns_instance_ctrl_t *) p_ctrl;
270 
271     fsp_err_t err = r_mhu_ns_common_preamble(p_instance_ctrl);
272     FSP_ERROR_RETURN(FSP_SUCCESS == err, err);
273 
274     /* Cleanup the device: disable interrupts */
275 
276     NVIC_DisableIRQ(p_instance_ctrl->p_cfg->rx_irq);
277     R_FSP_IsrContextSet(p_instance_ctrl->p_cfg->rx_irq, p_instance_ctrl);
278 
279     p_instance_ctrl->open = 0U;
280 
281     return FSP_SUCCESS;
282 }
283 
284 /**********************************************************************************************************************
285  * End of function R_MHU_NS_Close
286  *********************************************************************************************************************/
287 
288 /** @} (end addtogroup MHU_NS) */
289 
290 /***********************************************************************************************************************
291  * Private Functions
292  **********************************************************************************************************************/
293 
294 #if MHU_NS_CFG_PARAM_CHECKING_ENABLE
295 
296 /*******************************************************************************************************************//**
297  * Parameter checking for R_MHU_NS_Open.
298  *
299  * @param[in] p_instance_ctrl          Pointer to instance control structure.
300  * @param[in]  p_cfg              Configuration structure for this instance
301  *
302  * @retval FSP_SUCCESS                 Initialization was successful.
303  * @retval FSP_ERR_ASSERTION           A required input pointer is NULL.
304  * @retval FSP_ERR_ALREADY_OPEN        R_MHU_NS_Open has already been called for this p_ctrl.
305  * @retval FSP_ERR_INVALID_ARGUMENT    The specified IRQ number is invalid.
306  * @retval FSP_ERR_INVALID_CHANNEL     Requested channel number is not available on MHU_NS.
307  **********************************************************************************************************************/
r_mhu_ns_open_param_checking(mhu_ns_instance_ctrl_t * p_instance_ctrl,mhu_cfg_t const * const p_cfg)308 static fsp_err_t r_mhu_ns_open_param_checking (mhu_ns_instance_ctrl_t * p_instance_ctrl, mhu_cfg_t const * const p_cfg)
309 {
310     FSP_ASSERT(NULL != p_instance_ctrl);
311     FSP_ASSERT(NULL != p_cfg);
312     FSP_ERROR_RETURN(MHU_NS_OPEN != p_instance_ctrl->open, FSP_ERR_ALREADY_OPEN);
313 
314     /* Validate channel number. */
315     FSP_ERROR_RETURN(((1U << p_cfg->channel) & BSP_FEATURE_MHU_NS_VALID_CHANNEL_MASK), FSP_ERR_INVALID_CHANNEL);
316 
317     FSP_ERROR_RETURN(FSP_INVALID_VECTOR != p_cfg->rx_irq, FSP_ERR_INVALID_ARGUMENT);
318 
319     return FSP_SUCCESS;
320 }
321 
322 #endif
323 
324 /*******************************************************************************************************************//**
325  * Common code at the beginning of all MHU_NS functions except open.
326  *
327  * @param[in] p_instance_ctrl          Pointer to instance control structure.
328  *
329  * @retval FSP_SUCCESS                 No invalid conditions detected, MHU_NS state matches expected state.
330  * @retval FSP_ERR_ASSERTION           p_ctrl is null.
331  * @retval FSP_ERR_NOT_OPEN            The instance control structure is not opened.
332  **********************************************************************************************************************/
r_mhu_ns_common_preamble(mhu_ns_instance_ctrl_t * p_instance_ctrl)333 static fsp_err_t r_mhu_ns_common_preamble (mhu_ns_instance_ctrl_t * p_instance_ctrl)
334 {
335 #if MHU_NS_CFG_PARAM_CHECKING_ENABLE
336     FSP_ASSERT(NULL != p_instance_ctrl);
337     FSP_ERROR_RETURN(MHU_NS_OPEN == p_instance_ctrl->open, FSP_ERR_NOT_OPEN);
338 #else
339     FSP_PARAMETER_NOT_USED(p_instance_ctrl);
340 #endif
341 
342     return FSP_SUCCESS;
343 }
344 
345 /**********************************************************************************************************************
346  * End of function r_mhu_ns_common_preamble
347  *********************************************************************************************************************/
348 
349 /*******************************************************************************************************************//**
350  * Write a message to shared memory and generate inter-core interrupt
351  *
352  * @param[in]  p_instance_ctrl    Control block for this instance
353  * @param[in]  msg                32bit send data
354  **********************************************************************************************************************/
r_mhu_ns_set_send_data(mhu_ns_instance_ctrl_t * p_instance_ctrl,uint32_t msg)355 static void r_mhu_ns_set_send_data (mhu_ns_instance_ctrl_t * p_instance_ctrl, uint32_t msg)
356 {
357     if (MHU_SEND_TYPE_MSG == p_instance_ctrl->send_type)
358     {
359         /* Check interrupt status: Has the previous message been received? */
360         do
361         {
362             /* Do Nothing */
363         } while (0 != p_instance_ctrl->p_regs->MSG_INT_STSn);
364 
365         /* Store the message data. */
366         *p_instance_ctrl->p_shared_memory_tx = msg;
367 
368         /* Assert interrupt. */
369         p_instance_ctrl->p_regs->MSG_INT_SETn = 1;
370     }
371     else
372     {
373         /* Check interrupt status: Has the previous message been received? */
374         do
375         {
376             /* Do Nothing */
377         } while (0 != p_instance_ctrl->p_regs->RSP_INT_STSn);
378 
379         /* Store the message data. */
380         *p_instance_ctrl->p_shared_memory_tx = msg;
381 
382         /* Assert interrupt. */
383         p_instance_ctrl->p_regs->RSP_INT_SETn = 1;
384     }
385 }
386 
387 /**********************************************************************************************************************
388  * End of function r_mhu_ns_set_send_data
389  *********************************************************************************************************************/
390 
391 /*********************************************************************************************************************
392  * MHU_NS receive interrupt (for OpenAMP)
393  **********************************************************************************************************************/
metal_irq_isr_wrapper(void)394 void metal_irq_isr_wrapper (void)
395 {
396     /* Save context if RTOS is used */
397     FSP_CONTEXT_SAVE
398 
399     IRQn_Type irq = R_FSP_CurrentIrqGet();
400 
401     metal_irq_isr(irq);
402 
403     /* Restore context if RTOS is used */
404     FSP_CONTEXT_RESTORE
405 }
406 
407 /**********************************************************************************************************************
408  * End of function metal_irq_isr_wrapper
409  *********************************************************************************************************************/
410 
411 /*********************************************************************************************************************
412  * MHU_NS receive interrupt (for bere mhu_ns application).
413  **********************************************************************************************************************/
mhu_ns_int_isr(void)414 void mhu_ns_int_isr (void)
415 {
416     /* Save context if RTOS is used */
417     FSP_CONTEXT_SAVE
418 
419     IRQn_Type irq = R_FSP_CurrentIrqGet();
420 
421     R_MHU_NS_IsrSub(irq);
422 
423     /* Restore context if RTOS is used */
424     FSP_CONTEXT_RESTORE
425 }
426 
427 /**********************************************************************************************************************
428  * End of function mhu_ns_int_isr
429  *********************************************************************************************************************/
430 
431 /*******************************************************************************************************************//**
432  * MHU_NS receive interrupt sub function (for OpenAMP)
433  *
434  * @param[in]  irq    irq number for inter-core interrupt
435  **********************************************************************************************************************/
R_MHU_NS_IsrSub(uint32_t irq)436 void R_MHU_NS_IsrSub (uint32_t irq)
437 {
438     uint32_t msg;
439 
440     /* Clear pending IRQ to make sure it doesn't fire again after exiting */
441     R_BSP_IrqStatusClear(irq);
442 
443     /* Recover ISR context saved in open. */
444     mhu_ns_instance_ctrl_t * p_instance_ctrl = (mhu_ns_instance_ctrl_t *) R_FSP_IsrContextGet(irq);
445 
446     /* Check interrupt reason */
447     if (
448         ((MHU_SEND_TYPE_RSP == p_instance_ctrl->send_type) && (0 != p_instance_ctrl->p_regs->MSG_INT_STSn)) ||
449         ((MHU_SEND_TYPE_MSG == p_instance_ctrl->send_type) && (0 != p_instance_ctrl->p_regs->RSP_INT_STSn)))
450     {
451         /* Read data */
452         msg = *p_instance_ctrl->p_shared_memory_rx;
453 
454         /* Clear interrupt */
455         if (MHU_SEND_TYPE_RSP == p_instance_ctrl->send_type)
456         {
457             p_instance_ctrl->p_regs->MSG_INT_CLRn = 1;
458         }
459         else
460         {
461             p_instance_ctrl->p_regs->RSP_INT_CLRn = 1;
462         }
463 
464         /* Invoke the callback function if it is set. */
465         if (NULL != p_instance_ctrl->p_callback)
466         {
467             /* Setup parameters for the user-supplied callback function. */
468             mhu_callback_args_t callback_args;
469 
470             /* Store callback arguments in memory provided by user if available.  This allows callback arguments to be
471              * stored in non-secure memory so they can be accessed by a non-secure callback function. */
472             mhu_callback_args_t * p_args = p_instance_ctrl->p_callback_memory;
473             if (NULL == p_args)
474             {
475                 /* Store on stack */
476                 p_args = &callback_args;
477             }
478             else
479             {
480                 /* Save current arguments on the stack in case this is a nested interrupt. */
481                 callback_args = *p_args;
482             }
483 
484             p_args->p_context = p_instance_ctrl->p_context;
485 
486             p_args->channel = p_instance_ctrl->channel;
487             p_args->msg     = msg;
488 
489 #if BSP_TZ_SECURE_BUILD
490 
491             /* p_callback can point to a secure function or a non-secure function. */
492             if (p_instance_ctrl->callback_is_secure)
493             {
494                 /* If p_callback is secure, then the project does not need to change security state. */
495                 p_instance_ctrl->p_callback(p_args);
496             }
497             else
498             {
499                 /* If p_callback is Non-secure, then the project must change to Non-secure state
500                  * in order to call the callback. */
501                 mhu_ns_prv_ns_callback p_callback = (mhu_ns_prv_ns_callback) (p_instance_ctrl->p_callback);
502                 p_callback(p_args);
503             }
504 
505 #else
506 
507             /* If the project is not Trustzone Secure, then it will never need to change security state
508              * in order to call the callback. */
509             p_instance_ctrl->p_callback(p_args);
510 #endif
511 
512             if (NULL != p_instance_ctrl->p_callback_memory)
513             {
514                 /* Restore callback memory in case this is a nested interrupt. */
515                 *p_instance_ctrl->p_callback_memory = callback_args;
516             }
517         }
518     }
519 }
520 
521 /**********************************************************************************************************************
522  * End of function R_MHU_NS_IsrSub
523  *********************************************************************************************************************/
524