1 /*******************************************************************************
2 * Copyright (C) 2018 Cadence Design Systems, Inc.
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining
5 * a copy of this software and associated documentation files (the
6 * "Software"), to use this Software with Cadence processor cores only and
7 * not with any other processors and platforms, subject to
8 * the following conditions:
9 *
10 * The above copyright notice and this permission notice shall be included
11 * in all copies or substantial portions of the Software.
12 *
13 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
14 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
15 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
16 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
17 * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
18 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
19 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
20
21 ******************************************************************************/
22
23 /*******************************************************************************
24 * xf-ipc.h
25 *
26 * Xtensa IPC mechanism
27 *
28 *******************************************************************************/
29
30 #ifndef __XF_H
31 #error "xf-ipc.h mustn't be included directly"
32 #endif
33
34 /*******************************************************************************
35 * Includes
36 ******************************************************************************/
37
38 /* ...system-specific shared memory configuration */
39 #include "xf-shmem.h"
40 #ifndef XAF_ENABLE_NON_HIKEY
41 #include <xtensa/xtruntime.h>
42 extern volatile int waitstate;
43 #endif
44
45 #ifdef XAF_ENABLE_NON_HIKEY
46 /*******************************************************************************
47 * Macros definitions (should better go to some other header)
48 ******************************************************************************/
49
50 /*
51 * Execute WAITI 0 (enabling interrupts) only if *(ptr) is zero.
52 * The decision to execute WAITI is done atomically by disabling
53 * interrupts at level 'level' (level must be a constant)
54 * before checking the pointer. Interrupts are always re-enabled
55 * on exit from this macro.
56 */
57 #define _WAITI_ON_PTR(ptr, level) \
58 do { \
59 int __tmp; \
60 __asm__ (" rsil %0, " #level " \n" \
61 " l32i %0, %1, 0 \n" \
62 " bnez %0, 1f \n" \
63 " waiti 0 \n" \
64 "1:rsil %0, 0 \n" \
65 : "=a" (__tmp) : "a" (ptr) : "memory"); \
66 } while(0)
67
68 /* ...enable gdbstub */
69 //#define XF_CFG_USE_GDBSTUB 0
70
71 #ifndef XF_CFG_USE_GDBSTUB
72 /* ...maybe "level" should be hidden here - we always magically set 15 */
73 #define WAITI_ON_PTR(ptr, level) _WAITI_ON_PTR(ptr, level)
74 #else
75 /* ...if debugger is enabled, do polling instead of waiting */
WAITI_ON_PTR(volatile u32 * ptr,u32 level)76 static inline void WAITI_ON_PTR(volatile u32 *ptr, u32 level)
77 {
78 extern void poll_debug_ring(void);
79
80 while (*ptr == 0)
81 {
82 /* ...should be called with interrupts disabled - tbd */
83 poll_debug_ring();
84 }
85 }
86 #endif
87
88 /*******************************************************************************
89 * Remote IPI interrupt mode
90 ******************************************************************************/
91
92 /* ...enable/disable IPI interrupt */
xf_ipi_enable(u32 core,int on)93 static inline void xf_ipi_enable(u32 core, int on)
94 {
95 if (on)
96 _xtos_ints_on(1 << XF_PROXY_IPI_NUM(core));
97 else
98 _xtos_ints_off(1 << XF_PROXY_IPI_NUM(core));
99 }
100
101 /* ...wait in low-power mode for interrupt arrival if "ptr" is 0 */
xf_ipi_wait(u32 core)102 static inline void xf_ipi_wait(u32 core)
103 {
104 xf_core_ro_data_t *ro = XF_CORE_RO_DATA(core);
105
106 /* ...enable IPI interrupt before sleeping */
107 xf_ipi_enable(core, 1);
108
109 /* ...wait in low-power mode, atomically checking *ipc != 0 */
110 WAITI_ON_PTR(&ro->ipc.wait, 15);
111
112 /* ...force disabling of IPI interrupts */
113 xf_ipi_enable(core, 0);
114
115 /* ...reset waiting object upon leaving */
116 ro->ipc.wait = 0;
117 }
118 #else
119 #define _WAITI_ON_PTR(ptr, level) \
120 do { \
121 int __tmp; \
122 __asm__ (" rsil %0, " #level " \n" \
123 " l32i %0, %1, 0 \n" \
124 " bnez %0, 1f \n" \
125 " waiti 0 \n" \
126 "1:rsil %0, 0 \n" \
127 : "=a" (__tmp) : "a" (ptr) : "memory"); \
128 } while(0)
129
130 #define WAITI_ON_PTR(ptr, level) _WAITI_ON_PTR(ptr, level)
xf_ipi_wait(u32 core)131 static inline void xf_ipi_wait(u32 core)
132 {
133 #if 0
134 // VOS_EnableInterrupt(DSP_IPC_FROM_AP_INT_NO);
135 _xtos_ints_on(1 << DSP_IPC_FROM_AP_INT_NO);
136 while(1)
137 {
138 if(waitstate ==1)
139 {
140 // VOS_DisableInterrupt(DSP_IPC_FROM_AP_INT_NO);
141 _xtos_ints_off(1 << DSP_IPC_FROM_AP_INT_NO);
142 waitstate = 0;
143 break;
144 }
145 }
146 #else
147
148 _xtos_ints_on(1 << DSP_IPC_FROM_AP_INT_NO);
149 /* ...wait in low-power mode, atomically checking *ipc != 0 */
150 WAITI_ON_PTR(&waitstate, 15);
151
152 /* ...force disabling of IPI interrupts */
153
154 _xtos_ints_off(1 << DSP_IPC_FROM_AP_INT_NO);
155 /* ...reset waiting object upon leaving */
156 waitstate = 0;
157
158 #endif
159 }
160 #endif
161 #ifdef XAF_ENABLE_NON_HIKEY
162 /* ...complete IPI waiting (may be called from any context on local core) */
xf_ipi_resume(u32 core)163 static inline void xf_ipi_resume(u32 core)
164 {
165 xf_core_ro_data_t *ro = XF_CORE_RO_DATA(core);
166
167 /* ...single instruction is written atomically; no need to mask interrupts */
168 ro->ipc.wait = 1;
169 }
170 #else
171 /* ...complete IPI waiting (may be called from any context on local core) */
xf_ipi_resume(u32 core)172 static inline void xf_ipi_resume(u32 core)
173 {
174 unsigned int ipc_int_state = 0;
175 unsigned int ipc_data = 0;
176
177 _xtos_ints_off(1 << DSP_IPC_FROM_AP_INT_NO);
178
179 //process message
180 ipc_int_state = SYS_IPC_CPUIRST(DSP_SYS_IPC_BASE_ADDR_NS, SYS_IPC_CORE_HIFI);
181
182 if (ipc_int_state & BIT_MASK(DSP_AP_TO_DSP_MAILBOX_NO)) { //mailbox-18
183 SYS_IPC_ICLR(DSP_SYS_IPC_BASE_ADDR_NS, DSP_AP_TO_DSP_MAILBOX_NO) = BIT_MASK(SYS_IPC_CORE_HIFI);
184 waitstate = 1;
185 }
186
187 //_xtos_ints_on(1 << DSP_IPC_FROM_AP_INT_NO);
188
189 return;
190 }
191 #endif
192 #if 0//ndef HIKEY_XAF_IPC_COMMENT_OUT
193 /* ...notify remote side about status change */
194 //#define XF_PROXY_NOTIFY_PEER(core) dsp_ipc_send_irq_to_ap()
195
196 static inline void dsp_ipc_send_irq_to_ap(void)
197 {
198 unsigned int mode = 0;
199 unsigned int mode_1 = 0;
200
201 mode = SYS_IPC_MODE(DSP_SYS_IPC_BASE_ADDR_NS, DSP_DSP_TO_AP_MAILBOX_NO);
202
203 if (mode & BIT_MASK(SYS_IPC_MODE_IDLE)) {
204 mode_1=0;
205 } else {
206 return;
207 }
208
209
210 SYS_IPC_SOURCE(DSP_SYS_IPC_BASE_ADDR_NS, DSP_DSP_TO_AP_MAILBOX_NO) = BIT_MASK(SYS_IPC_CORE_HIFI);
211 SYS_IPC_IMASK(DSP_SYS_IPC_BASE_ADDR_NS, DSP_DSP_TO_AP_MAILBOX_NO) = ~((unsigned int)(BIT_MASK(SYS_IPC_CORE_HIFI)|BIT_MASK(SYS_IPC_CORE_A15)));
212 SYS_IPC_DATA(DSP_SYS_IPC_BASE_ADDR_NS, DSP_DSP_TO_AP_MAILBOX_NO, 0) = IPC_ACPU_INT_SRC_HIFI_MSG;
213 SYS_IPC_MODE(DSP_SYS_IPC_BASE_ADDR_NS, DSP_DSP_TO_AP_MAILBOX_NO) = BIT_MASK(SYS_IPC_MODE_AUTOACK);
214 SYS_IPC_SEND(DSP_SYS_IPC_BASE_ADDR_NS, DSP_DSP_TO_AP_MAILBOX_NO) = BIT_MASK(SYS_IPC_CORE_HIFI);
215
216 return;
217 }
218 #endif
219 /* ...assert IPI interrupt on remote core - board-specific */
xf_ipi_assert(u32 core)220 static inline void xf_ipi_assert(u32 core)
221 {
222 XF_PROXY_NOTIFY_PEER(core);
223 }
224
225 #ifdef XAF_ENABLE_NON_HIKEY
226 /* ...initialize IPI subsystem */
xf_ipi_init(u32 core)227 static inline int xf_ipi_init(u32 core)
228 {
229 xf_core_ro_data_t *ro = XF_CORE_RO_DATA(core);
230 extern void (* const xf_ipi_handlers[])(void);
231
232 /* ...reset IPC data - no interrupt yet */
233 ro->ipc.wait = 0;
234
235 /* ...install interrupt handler */
236 _xtos_set_interrupt_handler(XF_PROXY_IPI_NUM(core), xf_ipi_handlers[core]);
237
238 return 0;
239 }
240 #else
241 /* ...initialize IPI subsystem */
xf_ipi_init(u32 core)242 static inline int xf_ipi_init(u32 core)
243 {
244
245 waitstate =0;
246
247 dsp_debug_init();
248 //dsp_init_share_mem(HIKEY_AP2DSP_MSG_QUEUE_ADDR,HIKEY_DSP2AP_MSG_QUEUE_SIZE);
249 /* unlock reg */
250 SYS_IPC_LOCK(DSP_SYS_IPC_BASE_ADDR_NS) = 0x1ACCE551;
251 //VOS_ConnectInterrupt(DSP_IPC_FROM_AP_INT_NO, _ap_to_dsp_ipc_irq_proc);
252 VOS_ConnectInterrupt(DSP_IPC_FROM_AP_INT_NO, xf_ipi_resume);
253
254 // VOS_EnableInterrupt(DSP_IPC_FROM_AP_INT_NO);
255
256 return;
257 }
258 #endif
259
260 /*******************************************************************************
261 * Shared memory operations
262 ******************************************************************************/
263
264 /* ...NULL-address specification */
265 #define XF_PROXY_NULL (~0U)
266
267 /* ...invalid proxy address */
268 #define XF_PROXY_BADADDR XF_CFG_REMOTE_IPC_POOL_SIZE
269 /* ...translate buffer address to shared proxy address */
xf_ipc_b2a(u32 core,void * b)270 static inline u32 xf_ipc_b2a(u32 core, void *b)
271 {
272 xf_shmem_data_t *shmem = XF_CORE_DATA(core)->shmem;
273 void *start = shmem->buffer;
274
275 if (b == NULL)
276 return XF_PROXY_NULL;
277 else if ((s32)(b - start) < XF_CFG_REMOTE_IPC_POOL_SIZE)
278 return (u32)(b - start);
279 else
280 return XF_PROXY_BADADDR;
281 }
282 /* ...translate shared proxy address to local pointer */
xf_ipc_a2b(u32 core,u32 address)283 static inline void * xf_ipc_a2b(u32 core, u32 address)
284 {
285 xf_shmem_data_t *shmem = XF_CORE_DATA(core)->shmem;
286 void *start = shmem->buffer;
287
288 if (address < XF_CFG_REMOTE_IPC_POOL_SIZE)
289 return start + address;
290 else if (address == XF_PROXY_NULL)
291 return NULL;
292 else
293 return (void *)-1;
294 }
295
296 /* ...component association with remote IPC client */
xf_ipc_component_addref(u32 session)297 static inline void xf_ipc_component_addref(u32 session)
298 {
299 }
300
301 /* ...delete record about component association with remote IPC client */
xf_ipc_component_rmref(u32 id)302 static inline void xf_ipc_component_rmref(u32 id)
303 {
304 }
305
306 /* ...system-specific IPC layer initialization */
307 extern int xf_ipc_init(u32 core);
308
309 /*******************************************************************************
310 * Mutex definitions
311 ******************************************************************************/
312
313 /* ...export shared memory access macros */
314 #define MUTEX_SHARED_READ(core) \
315 ({ xf_core_ro_data_t *__ro = XF_CORE_RO_DATA(core); __ro->lock[0]; })
316
317 #define MUTEX_SHARED_WRITE(core, val) \
318 ({ xf_core_ro_data_t *__ro = XF_CORE_RO_DATA(core); __ro->lock[0] = (val); })
319
320 /* ...include library header */
321 #include "lib/mutex.h"
322
323 #if XF_CFG_CORES_NUM > 1
324 /* ...rename API functions */
xf_mutex_lock(u32 core)325 static inline void xf_mutex_lock(u32 core)
326 {
327 mutex_lock(core);
328 }
329
xf_mutex_unlock(u32 core)330 static inline void xf_mutex_unlock(u32 core)
331 {
332 mutex_unlock(core);
333 }
334
335 #else
336 /* ...for single-core setting no locking is actually needed */
xf_mutex_lock(u32 core)337 static inline void xf_mutex_lock(u32 core)
338 {
339 }
340
xf_mutex_unlock(u32 core)341 static inline void xf_mutex_unlock(u32 core)
342 {
343 }
344
345 #endif /* XF_CFG_CORES_NUM > 1 */
346