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