/******************************************************************************* * Copyright (C) 2018 Cadence Design Systems, Inc. * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the * "Software"), to use this Software with Cadence processor cores only and * not with any other processors and platforms, subject to * the following conditions: * * The above copyright notice and this permission notice shall be included * in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ******************************************************************************/ /******************************************************************************* * xf-ipc.h * * Xtensa IPC mechanism * *******************************************************************************/ #ifndef __XF_H #error "xf-ipc.h mustn't be included directly" #endif /******************************************************************************* * Includes ******************************************************************************/ /* ...system-specific shared memory configuration */ #include "xf-shmem.h" #ifndef XAF_ENABLE_NON_HIKEY #include extern volatile int waitstate; #endif #ifdef XAF_ENABLE_NON_HIKEY /******************************************************************************* * Macros definitions (should better go to some other header) ******************************************************************************/ /* * Execute WAITI 0 (enabling interrupts) only if *(ptr) is zero. * The decision to execute WAITI is done atomically by disabling * interrupts at level 'level' (level must be a constant) * before checking the pointer. Interrupts are always re-enabled * on exit from this macro. */ #define _WAITI_ON_PTR(ptr, level) \ do { \ int __tmp; \ __asm__ (" rsil %0, " #level " \n" \ " l32i %0, %1, 0 \n" \ " bnez %0, 1f \n" \ " waiti 0 \n" \ "1:rsil %0, 0 \n" \ : "=a" (__tmp) : "a" (ptr) : "memory"); \ } while(0) /* ...enable gdbstub */ //#define XF_CFG_USE_GDBSTUB 0 #ifndef XF_CFG_USE_GDBSTUB /* ...maybe "level" should be hidden here - we always magically set 15 */ #define WAITI_ON_PTR(ptr, level) _WAITI_ON_PTR(ptr, level) #else /* ...if debugger is enabled, do polling instead of waiting */ static inline void WAITI_ON_PTR(volatile u32 *ptr, u32 level) { extern void poll_debug_ring(void); while (*ptr == 0) { /* ...should be called with interrupts disabled - tbd */ poll_debug_ring(); } } #endif /******************************************************************************* * Remote IPI interrupt mode ******************************************************************************/ /* ...enable/disable IPI interrupt */ static inline void xf_ipi_enable(u32 core, int on) { if (on) _xtos_ints_on(1 << XF_PROXY_IPI_NUM(core)); else _xtos_ints_off(1 << XF_PROXY_IPI_NUM(core)); } /* ...wait in low-power mode for interrupt arrival if "ptr" is 0 */ static inline void xf_ipi_wait(u32 core) { xf_core_ro_data_t *ro = XF_CORE_RO_DATA(core); /* ...enable IPI interrupt before sleeping */ xf_ipi_enable(core, 1); /* ...wait in low-power mode, atomically checking *ipc != 0 */ WAITI_ON_PTR(&ro->ipc.wait, 15); /* ...force disabling of IPI interrupts */ xf_ipi_enable(core, 0); /* ...reset waiting object upon leaving */ ro->ipc.wait = 0; } #else #define _WAITI_ON_PTR(ptr, level) \ do { \ int __tmp; \ __asm__ (" rsil %0, " #level " \n" \ " l32i %0, %1, 0 \n" \ " bnez %0, 1f \n" \ " waiti 0 \n" \ "1:rsil %0, 0 \n" \ : "=a" (__tmp) : "a" (ptr) : "memory"); \ } while(0) #define WAITI_ON_PTR(ptr, level) _WAITI_ON_PTR(ptr, level) static inline void xf_ipi_wait(u32 core) { #if 0 // VOS_EnableInterrupt(DSP_IPC_FROM_AP_INT_NO); _xtos_ints_on(1 << DSP_IPC_FROM_AP_INT_NO); while(1) { if(waitstate ==1) { // VOS_DisableInterrupt(DSP_IPC_FROM_AP_INT_NO); _xtos_ints_off(1 << DSP_IPC_FROM_AP_INT_NO); waitstate = 0; break; } } #else _xtos_ints_on(1 << DSP_IPC_FROM_AP_INT_NO); /* ...wait in low-power mode, atomically checking *ipc != 0 */ WAITI_ON_PTR(&waitstate, 15); /* ...force disabling of IPI interrupts */ _xtos_ints_off(1 << DSP_IPC_FROM_AP_INT_NO); /* ...reset waiting object upon leaving */ waitstate = 0; #endif } #endif #ifdef XAF_ENABLE_NON_HIKEY /* ...complete IPI waiting (may be called from any context on local core) */ static inline void xf_ipi_resume(u32 core) { xf_core_ro_data_t *ro = XF_CORE_RO_DATA(core); /* ...single instruction is written atomically; no need to mask interrupts */ ro->ipc.wait = 1; } #else /* ...complete IPI waiting (may be called from any context on local core) */ static inline void xf_ipi_resume(u32 core) { unsigned int ipc_int_state = 0; unsigned int ipc_data = 0; _xtos_ints_off(1 << DSP_IPC_FROM_AP_INT_NO); //process message ipc_int_state = SYS_IPC_CPUIRST(DSP_SYS_IPC_BASE_ADDR_NS, SYS_IPC_CORE_HIFI); if (ipc_int_state & BIT_MASK(DSP_AP_TO_DSP_MAILBOX_NO)) { //mailbox-18 SYS_IPC_ICLR(DSP_SYS_IPC_BASE_ADDR_NS, DSP_AP_TO_DSP_MAILBOX_NO) = BIT_MASK(SYS_IPC_CORE_HIFI); waitstate = 1; } //_xtos_ints_on(1 << DSP_IPC_FROM_AP_INT_NO); return; } #endif #if 0//ndef HIKEY_XAF_IPC_COMMENT_OUT /* ...notify remote side about status change */ //#define XF_PROXY_NOTIFY_PEER(core) dsp_ipc_send_irq_to_ap() static inline void dsp_ipc_send_irq_to_ap(void) { unsigned int mode = 0; unsigned int mode_1 = 0; mode = SYS_IPC_MODE(DSP_SYS_IPC_BASE_ADDR_NS, DSP_DSP_TO_AP_MAILBOX_NO); if (mode & BIT_MASK(SYS_IPC_MODE_IDLE)) { mode_1=0; } else { return; } SYS_IPC_SOURCE(DSP_SYS_IPC_BASE_ADDR_NS, DSP_DSP_TO_AP_MAILBOX_NO) = BIT_MASK(SYS_IPC_CORE_HIFI); 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))); SYS_IPC_DATA(DSP_SYS_IPC_BASE_ADDR_NS, DSP_DSP_TO_AP_MAILBOX_NO, 0) = IPC_ACPU_INT_SRC_HIFI_MSG; SYS_IPC_MODE(DSP_SYS_IPC_BASE_ADDR_NS, DSP_DSP_TO_AP_MAILBOX_NO) = BIT_MASK(SYS_IPC_MODE_AUTOACK); SYS_IPC_SEND(DSP_SYS_IPC_BASE_ADDR_NS, DSP_DSP_TO_AP_MAILBOX_NO) = BIT_MASK(SYS_IPC_CORE_HIFI); return; } #endif /* ...assert IPI interrupt on remote core - board-specific */ static inline void xf_ipi_assert(u32 core) { XF_PROXY_NOTIFY_PEER(core); } #ifdef XAF_ENABLE_NON_HIKEY /* ...initialize IPI subsystem */ static inline int xf_ipi_init(u32 core) { xf_core_ro_data_t *ro = XF_CORE_RO_DATA(core); extern void (* const xf_ipi_handlers[])(void); /* ...reset IPC data - no interrupt yet */ ro->ipc.wait = 0; /* ...install interrupt handler */ _xtos_set_interrupt_handler(XF_PROXY_IPI_NUM(core), xf_ipi_handlers[core]); return 0; } #else /* ...initialize IPI subsystem */ static inline int xf_ipi_init(u32 core) { waitstate =0; dsp_debug_init(); //dsp_init_share_mem(HIKEY_AP2DSP_MSG_QUEUE_ADDR,HIKEY_DSP2AP_MSG_QUEUE_SIZE); /* unlock reg */ SYS_IPC_LOCK(DSP_SYS_IPC_BASE_ADDR_NS) = 0x1ACCE551; //VOS_ConnectInterrupt(DSP_IPC_FROM_AP_INT_NO, _ap_to_dsp_ipc_irq_proc); VOS_ConnectInterrupt(DSP_IPC_FROM_AP_INT_NO, xf_ipi_resume); // VOS_EnableInterrupt(DSP_IPC_FROM_AP_INT_NO); return; } #endif /******************************************************************************* * Shared memory operations ******************************************************************************/ /* ...NULL-address specification */ #define XF_PROXY_NULL (~0U) /* ...invalid proxy address */ #define XF_PROXY_BADADDR XF_CFG_REMOTE_IPC_POOL_SIZE /* ...translate buffer address to shared proxy address */ static inline u32 xf_ipc_b2a(u32 core, void *b) { xf_shmem_data_t *shmem = XF_CORE_DATA(core)->shmem; void *start = shmem->buffer; if (b == NULL) return XF_PROXY_NULL; else if ((s32)(b - start) < XF_CFG_REMOTE_IPC_POOL_SIZE) return (u32)(b - start); else return XF_PROXY_BADADDR; } /* ...translate shared proxy address to local pointer */ static inline void * xf_ipc_a2b(u32 core, u32 address) { xf_shmem_data_t *shmem = XF_CORE_DATA(core)->shmem; void *start = shmem->buffer; if (address < XF_CFG_REMOTE_IPC_POOL_SIZE) return start + address; else if (address == XF_PROXY_NULL) return NULL; else return (void *)-1; } /* ...component association with remote IPC client */ static inline void xf_ipc_component_addref(u32 session) { } /* ...delete record about component association with remote IPC client */ static inline void xf_ipc_component_rmref(u32 id) { } /* ...system-specific IPC layer initialization */ extern int xf_ipc_init(u32 core); /******************************************************************************* * Mutex definitions ******************************************************************************/ /* ...export shared memory access macros */ #define MUTEX_SHARED_READ(core) \ ({ xf_core_ro_data_t *__ro = XF_CORE_RO_DATA(core); __ro->lock[0]; }) #define MUTEX_SHARED_WRITE(core, val) \ ({ xf_core_ro_data_t *__ro = XF_CORE_RO_DATA(core); __ro->lock[0] = (val); }) /* ...include library header */ #include "lib/mutex.h" #if XF_CFG_CORES_NUM > 1 /* ...rename API functions */ static inline void xf_mutex_lock(u32 core) { mutex_lock(core); } static inline void xf_mutex_unlock(u32 core) { mutex_unlock(core); } #else /* ...for single-core setting no locking is actually needed */ static inline void xf_mutex_lock(u32 core) { } static inline void xf_mutex_unlock(u32 core) { } #endif /* XF_CFG_CORES_NUM > 1 */