1 /*
2  * Copyright (c) 2019-2021, Arm Limited. All rights reserved.
3  * Copyright (c) 2019-2024 Cypress Semiconductor Corporation (an Infineon company)
4  * or an affiliate of Cypress Semiconductor Corporation. All rights reserved.
5  *
6  * SPDX-License-Identifier: BSD-3-Clause
7  */
8 
9 /* -------------------------------------- Includes ----------------------------------- */
10 #include <limits.h>
11 #include <string.h>
12 
13 #include "cmsis_compiler.h"
14 
15 #include "cy_ipc_drv.h"
16 #include "cy_sysint.h"
17 
18 #include "ns_ipc_config.h"
19 #include "tfm_ns_mailbox.h"
20 #include "platform_multicore.h"
21 
22 static uint8_t saved_irq_state = 1;
23 
24 /* -------------------------------------- HAL API ------------------------------------ */
25 
mailbox_ipc_init(void)26 static void mailbox_ipc_init(void)
27 {
28     Cy_IPC_Drv_SetInterruptMask(Cy_IPC_Drv_GetIntrBaseAddr(IPC_RX_INTR_STRUCT),
29                                 0, IPC_RX_INT_MASK);
30 }
31 
mailbox_ipc_config(void)32 static void mailbox_ipc_config(void)
33 {
34     NVIC_SetPriority(PSA_CLIENT_REPLY_NVIC_IRQn, PSA_CLIENT_REPLY_IRQ_PRIORITY);
35 
36     NVIC_EnableIRQ(PSA_CLIENT_REPLY_NVIC_IRQn);
37 }
38 
tfm_ns_mailbox_hal_notify_peer(void)39 int32_t tfm_ns_mailbox_hal_notify_peer(void)
40 {
41     cy_en_ipcdrv_status_t status;
42 
43     status = Cy_IPC_Drv_SendMsgWord(Cy_IPC_Drv_GetIpcBaseAddress(IPC_TX_CHAN),
44                                     IPC_TX_NOTIFY_MASK,
45                                     PSA_CLIENT_CALL_REQ_MAGIC);
46 
47     if (status == CY_IPC_DRV_SUCCESS) {
48         return MAILBOX_SUCCESS;
49     } else {
50         return MAILBOX_CHAN_BUSY;
51     }
52 }
53 
tfm_ns_mailbox_hal_init(struct ns_mailbox_queue_t * queue)54 int32_t tfm_ns_mailbox_hal_init(struct ns_mailbox_queue_t *queue)
55 {
56     uint32_t stage;
57 
58     if (!queue) {
59         return MAILBOX_INVAL_PARAMS;
60     }
61 
62     /*
63      * FIXME
64      * Further verification of mailbox queue address may be required according
65      * to diverse NSPE implementations.
66      */
67 
68     mailbox_ipc_init();
69 
70     /*
71      * Wait until SPE mailbox library is ready to receive NSPE mailbox queue
72      * address.
73      */
74     while (1) {
75         platform_mailbox_wait_for_notify();
76 
77         platform_mailbox_fetch_msg_data(&stage);
78         if  (stage == NS_MAILBOX_INIT_ENABLE) {
79             break;
80         }
81     }
82 
83     /* Send out the address */
84     struct mailbox_init_t ns_init;
85     ns_init.status = &queue->status;
86     ns_init.slot_count = NUM_MAILBOX_QUEUE_SLOT;
87     ns_init.slots = &queue->slots[0];
88     platform_mailbox_send_msg_ptr(&ns_init);
89 
90     /* Wait until SPE mailbox service is ready */
91     while (1) {
92         platform_mailbox_wait_for_notify();
93 
94         platform_mailbox_fetch_msg_data(&stage);
95         if  (stage == S_MAILBOX_READY) {
96             break;
97         }
98     }
99 
100     mailbox_ipc_config();
101 
102     return MAILBOX_SUCCESS;
103 }
104 
tfm_ns_mailbox_hal_enter_critical(void)105 void tfm_ns_mailbox_hal_enter_critical(void)
106 {
107     saved_irq_state = Cy_SysLib_EnterCriticalSection();
108 
109     IPC_STRUCT_Type* ipc_struct =
110         Cy_IPC_Drv_GetIpcBaseAddress(IPC_PSA_MAILBOX_LOCK_CHAN);
111     while(CY_IPC_DRV_SUCCESS != Cy_IPC_Drv_LockAcquire (ipc_struct))
112     {
113     }
114 }
115 
tfm_ns_mailbox_hal_exit_critical(void)116 void tfm_ns_mailbox_hal_exit_critical(void)
117 {
118     IPC_STRUCT_Type* ipc_struct =
119         Cy_IPC_Drv_GetIpcBaseAddress(IPC_PSA_MAILBOX_LOCK_CHAN);
120     Cy_IPC_Drv_LockRelease(ipc_struct, CY_IPC_NO_NOTIFICATION);
121     Cy_SysLib_ExitCriticalSection(saved_irq_state);
122 }
123 
tfm_ns_mailbox_hal_enter_critical_isr(void)124 void tfm_ns_mailbox_hal_enter_critical_isr(void)
125 {
126     IPC_STRUCT_Type* ipc_struct =
127         Cy_IPC_Drv_GetIpcBaseAddress(IPC_PSA_MAILBOX_LOCK_CHAN);
128     while(CY_IPC_DRV_SUCCESS != Cy_IPC_Drv_LockAcquire (ipc_struct))
129     {
130     }
131 }
132 
tfm_ns_mailbox_hal_exit_critical_isr(void)133 void tfm_ns_mailbox_hal_exit_critical_isr(void)
134 {
135     IPC_STRUCT_Type* ipc_struct =
136         Cy_IPC_Drv_GetIpcBaseAddress(IPC_PSA_MAILBOX_LOCK_CHAN);
137     Cy_IPC_Drv_LockRelease(ipc_struct, CY_IPC_NO_NOTIFICATION);
138 }
139 
mailbox_clear_intr(void)140 static bool mailbox_clear_intr(void)
141 {
142     uint32_t status;
143 
144     status = Cy_IPC_Drv_GetInterruptStatusMasked(
145                             Cy_IPC_Drv_GetIntrBaseAddr(IPC_RX_INTR_STRUCT));
146     status >>= CY_IPC_NOTIFY_SHIFT;
147     if ((status & IPC_RX_INT_MASK) == 0) {
148         return false;
149     }
150 
151     Cy_IPC_Drv_ClearInterrupt(Cy_IPC_Drv_GetIntrBaseAddr(IPC_RX_INTR_STRUCT),
152                               0, IPC_RX_INT_MASK);
153     return true;
154 }
155 
cpuss_interrupts_ipc_8_IRQHandler(void)156 void cpuss_interrupts_ipc_8_IRQHandler(void)
157 {
158     uint32_t magic;
159 
160     if (!mailbox_clear_intr())
161         return;
162 
163     platform_mailbox_fetch_msg_data(&magic);
164     if (magic == PSA_CLIENT_CALL_REPLY_MAGIC) {
165         /* Handle all the pending replies */
166         tfm_ns_mailbox_wake_reply_owner_isr();
167     }
168 }
169