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 */ 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 */ 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 */ 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) 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) */ 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) */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 297 static inline void xf_ipc_component_addref(u32 session) 298 { 299 } 300 301 /* ...delete record about component association with remote IPC client */ 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 */ 325 static inline void xf_mutex_lock(u32 core) 326 { 327 mutex_lock(core); 328 } 329 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 */ 337 static inline void xf_mutex_lock(u32 core) 338 { 339 } 340 341 static inline void xf_mutex_unlock(u32 core) 342 { 343 } 344 345 #endif /* XF_CFG_CORES_NUM > 1 */ 346