diff options
-rw-r--r-- | include/uapi/linux/mxc_hifi4.h | 67 | ||||
-rw-r--r-- | sound/soc/fsl/Makefile | 2 | ||||
-rw-r--r-- | sound/soc/fsl/fsl_hifi4.c | 2143 | ||||
-rw-r--r-- | sound/soc/fsl/fsl_hifi4.h | 257 | ||||
-rw-r--r-- | sound/soc/fsl/fsl_hifi4_proxy.c | 641 | ||||
-rw-r--r-- | sound/soc/fsl/fsl_hifi4_proxy.h | 381 |
6 files changed, 1408 insertions, 2083 deletions
diff --git a/include/uapi/linux/mxc_hifi4.h b/include/uapi/linux/mxc_hifi4.h index e22f7f5808e1..5078537f86fa 100644 --- a/include/uapi/linux/mxc_hifi4.h +++ b/include/uapi/linux/mxc_hifi4.h @@ -25,18 +25,12 @@ #ifndef __MXC_HIFI4_UAPI_H__ #define __MXC_HIFI4_UAPI_H__ -#define HIFI4_IOC_MAGIC 'H' -#define HIFI4_LOAD_CODEC _IOWR(HIFI4_IOC_MAGIC, 0, unsigned int) -#define HIFI4_INIT_CODEC _IOWR(HIFI4_IOC_MAGIC, 1, unsigned int) -#define HIFI4_CODEC_OPEN _IOWR(HIFI4_IOC_MAGIC, 2, unsigned int) -#define HIFI4_CODEC_CLOSE _IOWR(HIFI4_IOC_MAGIC, 3, unsigned int) -#define HIFI4_DECODE_ONE_FRAME _IOW(HIFI4_IOC_MAGIC, 4, unsigned int) -#define HIFI4_UNLOAD_CODEC _IOW(HIFI4_IOC_MAGIC, 5, unsigned int) -#define HIFI4_GET_PCM_PROP _IOW(HIFI4_IOC_MAGIC, 6, unsigned int) -#define HIFI4_SET_CONFIG _IOW(HIFI4_IOC_MAGIC, 7, unsigned int) -#define HIFI4_RESET_CODEC _IOW(HIFI4_IOC_MAGIC, 8, unsigned int) -#define HIFI4_CLIENT_REGISTER _IOW(HIFI4_IOC_MAGIC, 9, unsigned int) -#define HIFI4_CLIENT_UNREGISTER _IOW(HIFI4_IOC_MAGIC, 10, unsigned int) +#define DSP_IOC_MAGIC 'H' +#define DSP_CLIENT_REGISTER _IOW(DSP_IOC_MAGIC, 0, unsigned int) +#define DSP_CLIENT_UNREGISTER _IOW(DSP_IOC_MAGIC, 1, unsigned int) +#define DSP_IPC_MSG_SEND _IOW(DSP_IOC_MAGIC, 2, unsigned int) +#define DSP_IPC_MSG_RECV _IOW(DSP_IOC_MAGIC, 3, unsigned int) +#define DSP_GET_SHMEM_INFO _IOW(DSP_IOC_MAGIC, 4, unsigned int) #define CODEC_MP3_DEC 1 #define CODEC_AAC_DEC 2 @@ -105,6 +99,13 @@ enum HIFI_ParaType { XA_SBC_ENC_BITPOOL, XA_SBC_ENC_CHMODE, +/* Get parmameters */ + XA_CODEC_DESCRIPTION = 0x200, + XA_OUTPUT_PCM_FORMAT, + XA_CONSUMED_LENGTH, + XA_OUTBUF_ALLOC_SIZE, + XA_CONSUMED_CYCLES, + }; #define HIFI_STREAM_DABPLUS_BASE 0x30 @@ -136,45 +137,9 @@ enum HIFI_SbcEncChmode { XA_CHMODE_JOINT = 3, }; -enum lib_type { - HIFI_CODEC_LIB = 1, - HIFI_CODEC_WRAP_LIB, -}; - -struct decode_info { - void *in_buf_addr; - int in_buf_size; - int in_buf_off; - void *out_buf_addr; - int out_buf_size; - int out_buf_off; - unsigned int input_over; - unsigned int process_id; -}; - -struct prop_info { - int samplerate; - int channels; - int bits; - unsigned int consumed_bytes; - unsigned int cycles; - - unsigned int process_id; -}; - -struct binary_info { - int type; - char *file; - unsigned int process_id; - unsigned int lib_type; -}; - -struct prop_config { - int codec_id; /* codec id */ - int cmd; /* command value */ - int val; /* parameter value */ - int ret; /* executed status of function */ - unsigned int process_id; +struct shmem_info { + unsigned int phys_addr; + unsigned int size; }; #endif/* __MXC_HIFI4_UAPI_H__ */ diff --git a/sound/soc/fsl/Makefile b/sound/soc/fsl/Makefile index 8f09c3cd5238..d1ffc9eaf9f7 100644 --- a/sound/soc/fsl/Makefile +++ b/sound/soc/fsl/Makefile @@ -15,7 +15,7 @@ obj-$(CONFIG_SND_SOC_P1022_RDK) += snd-soc-p1022-rdk.o snd-soc-fsl-audmix-objs := fsl_audmix.o snd-soc-fsl-asoc-card-objs := fsl-asoc-card.o snd-soc-fsl-asrc-objs := fsl_asrc.o fsl_asrc_dma.o -snd-soc-fsl-hifi4-objs := fsl_hifi4.o +snd-soc-fsl-hifi4-objs := fsl_hifi4.o fsl_hifi4_proxy.o snd-soc-fsl-sai-objs := fsl_sai.o snd-soc-fsl-ssi-y := fsl_ssi.o snd-soc-fsl-ssi-$(CONFIG_DEBUG_FS) += fsl_ssi_dbg.o diff --git a/sound/soc/fsl/fsl_hifi4.c b/sound/soc/fsl/fsl_hifi4.c index 756a697e570a..e4e826de6c69 100644 --- a/sound/soc/fsl/fsl_hifi4.c +++ b/sound/soc/fsl/fsl_hifi4.c @@ -54,6 +54,7 @@ #include <linux/pm_runtime.h> #include <linux/mx8_mu.h> #include <linux/uaccess.h> +#include <linux/poll.h> #ifdef CONFIG_COMPAT #include <linux/compat.h> #endif @@ -64,1430 +65,212 @@ #include "fsl_hifi4.h" -#ifdef CONFIG_COMPAT -struct decode_info_compat32 { - compat_long_t in_buf_addr; - __s32 in_buf_size; - __s32 in_buf_off; - compat_long_t out_buf_addr; - __s32 out_buf_size; - __s32 out_buf_off; - __u32 input_over; - __u32 process_id; -}; - -struct binary_info_compat32 { - __s32 type; - compat_long_t file; - __u32 process_id; - __u32 lib_type; -}; - -static int get_binary_info_compat32(struct binary_info *kp, - struct binary_info_compat32 __user *up) { - void __user *up_ptr; - compat_long_t p; - - if (!access_ok(VERIFY_READ, up, sizeof(struct binary_info_compat32)) || - get_user(kp->type, &up->type) || - get_user(p, &up->file) || - get_user(kp->process_id, &up->process_id) || - get_user(kp->lib_type, &up->lib_type) - ) { - return -EFAULT; - } - - up_ptr = compat_ptr(p); - kp->file = (char *)up_ptr; - - return 0; -} - -static int get_decode_info_compat32(struct decode_info *kp, - struct decode_info_compat32 *up) { - void __user *up_ptr1; - void __user *up_ptr2; - compat_long_t p1; - compat_long_t p2; - - if (!access_ok(VERIFY_READ, up, sizeof(struct decode_info_compat32)) || - get_user(p1, &up->in_buf_addr) || - get_user(kp->in_buf_size, &up->in_buf_size) || - get_user(kp->in_buf_off, &up->in_buf_off) || - get_user(p2, &up->out_buf_addr) || - get_user(kp->out_buf_size, &up->out_buf_size) || - get_user(kp->out_buf_off, &up->out_buf_off) || - get_user(kp->input_over, &up->input_over) || - get_user(kp->process_id, &up->process_id) - ) { - return -EFAULT; - } - - up_ptr1 = compat_ptr(p1); - up_ptr2 = compat_ptr(p2); - - kp->in_buf_addr = (void *)up_ptr1; - kp->out_buf_addr = (void *)up_ptr2; - - return 0; -} - -static int put_decode_info_compat32(struct decode_info *kp, - struct decode_info_compat32 *up) { - - if (!access_ok(VERIFY_WRITE, up, sizeof(struct decode_info_compat32)) || - put_user(kp->in_buf_off, &up->in_buf_off) || - put_user(kp->out_buf_off, &up->out_buf_off) || - put_user(kp->input_over, &up->input_over) - ) { - return -EFAULT; - } - - return 0; -} -#endif - -long hifi4_buf_alloc(struct fsl_hifi4 *hifi4_priv, - unsigned int size) -{ - union icm_header_t apu_icm; - struct hifi4_ext_msg ext_msg; - struct icm_pilib_size_t icm_pilib_size_t; - struct icm_pilib_size_t *pilib_buffer_info = - &hifi4_priv->pilib_buffer_info; - long ret = 0; - - if (size <= 0) - return 0; - - /* For shared memory between hifi driver and framework, - * it is managed by hifi framework, so when hifi driver - * wants to get shard memory, it should send - * ICM_PI_LIB_MEM_ALLOC command to hifi framework to request - * memory. If memory request is ok, hifi framework will send - * a message which includes the physical address of memory to - * hifi driver. If not, the physical address will be zero. - */ - init_completion(&hifi4_priv->cmd_complete); - hifi4_priv->is_done = 0; - - apu_icm.allbits = 0; /* clear all bits;*/ - apu_icm.ack = 0; - apu_icm.intr = 1; - apu_icm.msg = ICM_PI_LIB_MEM_ALLOC; - apu_icm.size = 8; - - ext_msg.phys = hifi4_priv->msg_buf_phys; - ext_msg.size = sizeof(struct icm_pilib_size_t); - - icm_pilib_size_t.buffer_addr = 0; - icm_pilib_size_t.buffer_size = size; - icm_pilib_size_t.ret = 0; - - memcpy(hifi4_priv->msg_buf_virt, &icm_pilib_size_t, - sizeof(struct icm_pilib_size_t)); - icm_intr_extended_send(hifi4_priv, apu_icm.allbits, &ext_msg); - - /* wait for response here */ - ret = icm_ack_wait(hifi4_priv, apu_icm.allbits); - if (ret) - return 0; - - if (pilib_buffer_info->buffer_addr) - return (long)pilib_buffer_info->buffer_addr; - - return 0; -} - -long hifi4_buf_free(struct fsl_hifi4 *hifi4_priv, long ptr) +/* ...allocate new client */ +static inline struct xf_client *xf_client_alloc(struct fsl_hifi4 *hifi4_priv) { - union icm_header_t apu_icm; - struct hifi4_ext_msg ext_msg; - struct icm_pilib_size_t icm_pilib_size_t; - long ret = 0; + struct xf_client *client; + u32 id; - if (ptr == 0) - return 0; - - /* If hifi driver wants to release the shared memory which - * has been allocated by hifi4_buf_alloc(), it should send - * ICM_PI_LIB_MEM_FREE command to hifi framework. The message - * in this command should include the physical address of - * current memory. - */ - init_completion(&hifi4_priv->cmd_complete); - hifi4_priv->is_done = 0; + id = hifi4_priv->xf_client_map[0].next; - apu_icm.allbits = 0; /* clear all bits;*/ - apu_icm.ack = 0; - apu_icm.intr = 1; - apu_icm.msg = ICM_PI_LIB_MEM_FREE; - apu_icm.size = 8; + /* ...try to allocate a client handle */ + if (id != 0) { + /* ...allocate client memory */ + client = kmalloc(sizeof(*client), GFP_KERNEL); + if (!client) + return ERR_PTR(-ENOMEM); - ext_msg.phys = hifi4_priv->msg_buf_phys; - ext_msg.size = sizeof(struct icm_pilib_size_t); + /* ...advance the head of free clients */ + hifi4_priv->xf_client_map[0].next = + hifi4_priv->xf_client_map[id].next; - icm_pilib_size_t.buffer_addr = (u32)ptr; - icm_pilib_size_t.buffer_size = 0; - icm_pilib_size_t.ret = 0; + /* ...put associate client id with given object */ + hifi4_priv->xf_client_map[id].client = client; - memcpy(hifi4_priv->msg_buf_virt, &icm_pilib_size_t, - sizeof(struct icm_pilib_size_t)); - icm_intr_extended_send(hifi4_priv, apu_icm.allbits, &ext_msg); + /* ...mark client is not yet bound to proxy */ + client->proxy = NULL; - /* wait for response here */ - ret = icm_ack_wait(hifi4_priv, apu_icm.allbits); - if (ret) - return ret; - - ret = hifi4_priv->ret_status; - - return ret; -} - -Elf32_Half xtlib_host_half(Elf32_Half v, int byteswap) -{ - return (byteswap) ? (v >> 8) | (v << 8) : v; -} + /* ...save global proxy client identifier */ + client->id = id; -Elf32_Word xtlib_host_word(Elf32_Word v, int byteswap) -{ - if (byteswap) { - v = ((v & 0x00FF00FF) << 8) | ((v & 0xFF00FF00) >> 8); - v = (v >> 16) | (v << 16); - } - return v; -} - -int xtlib_verify_magic(Elf32_Ehdr *header, - struct icm_process_info *process_info) -{ - struct xtlib_loader_globals *xtlib_globals = - &process_info->xtlib_globals; - Elf32_Byte magic_no; - - magic_no = header->e_ident[EI_MAG0]; - if (magic_no != 0x7f) - return -1; - - magic_no = header->e_ident[EI_MAG1]; - if (magic_no != 'E') - return -1; - - magic_no = header->e_ident[EI_MAG2]; - if (magic_no != 'L') - return -1; - - magic_no = header->e_ident[EI_MAG3]; - if (magic_no != 'F') - return -1; - - if (header->e_ident[EI_CLASS] != ELFCLASS32) - return -1; - - { - /* determine byte order */ - union { - short s; - char c[sizeof(short)]; - } u; - - u.s = 1; - - if (header->e_ident[EI_DATA] == ELFDATA2LSB) - xtlib_globals->byteswap = u.c[sizeof(short) - 1] == 1; - else if (header->e_ident[EI_DATA] == ELFDATA2MSB) - xtlib_globals->byteswap = u.c[0] == 1; - else - return -1; + return client; } - return 0; -} - -void xtlib_load_seg(Elf32_Phdr *pheader, void *src_addr, xt_ptr dst_addr, - memcpy_func mcpy, memset_func mset, - struct icm_process_info *process_info) -{ - struct xtlib_loader_globals *xtlib_globals = - &process_info->xtlib_globals; - Elf32_Word bytes_to_copy = xtlib_host_word(pheader->p_filesz, - xtlib_globals->byteswap); - Elf32_Word bytes_to_zero = xtlib_host_word(pheader->p_memsz, - xtlib_globals->byteswap) - - bytes_to_copy; - - void *zero_addr = (void *)dst_addr + bytes_to_copy; - - if (bytes_to_copy > 0) - mcpy((void *)(dst_addr), src_addr, bytes_to_copy); - - if (bytes_to_zero > 0) - mset(zero_addr, 0, bytes_to_zero); + /* ...number of clients exceeded */ + return ERR_PTR(-EBUSY); } -#define xtlib_xt_half xtlib_host_half -#define xtlib_xt_word xtlib_host_word - -static xt_ptr align_ptr(xt_ptr ptr, xt_uint align) +/* ...recycle client object */ +static inline void xf_client_free(struct xf_client *client) { - return (xt_ptr)(((xt_uint)ptr + align - 1) & ~(align - 1)); -} - -static xt_ptr xt_ptr_offs(xt_ptr base, Elf32_Word offs, - struct icm_process_info *process_info) -{ - struct xtlib_loader_globals *xtlib_globals = - &process_info->xtlib_globals; - - return (xt_ptr) xtlib_xt_word((xt_uint)base + - xtlib_host_word(offs, xtlib_globals->byteswap), - xtlib_globals->byteswap); -} - -static Elf32_Dyn *find_dynamic_info(Elf32_Ehdr *eheader, - struct icm_process_info *process_info) -{ - char *base_addr = (char *)eheader; - struct xtlib_loader_globals *xtlib_globals = - &process_info->xtlib_globals; - Elf32_Phdr *pheader = (Elf32_Phdr *)(base_addr + - xtlib_host_word(eheader->e_phoff, - xtlib_globals->byteswap)); - - int seg = 0; - int num = xtlib_host_half(eheader->e_phnum, xtlib_globals->byteswap); - - while (seg < num) { - if (xtlib_host_word(pheader[seg].p_type, - xtlib_globals->byteswap) == PT_DYNAMIC) { - return (Elf32_Dyn *) (base_addr + - xtlib_host_word(pheader[seg].p_offset, - xtlib_globals->byteswap)); - } - seg++; - } - return 0; -} - -static int find_align(Elf32_Ehdr *header, - struct icm_process_info *process_info) -{ - struct xtlib_loader_globals *xtlib_globals = - &process_info->xtlib_globals; - Elf32_Shdr *sheader = (Elf32_Shdr *) (((char *)header) + - xtlib_host_word(header->e_shoff, xtlib_globals->byteswap)); - - int sec = 0; - int num = xtlib_host_half(header->e_shnum, xtlib_globals->byteswap); - - int align = 0; - - while (sec < num) { - if (sheader[sec].sh_type != SHT_NULL && - xtlib_host_word(sheader[sec].sh_size, - xtlib_globals->byteswap) > 0) { - int sec_align = - xtlib_host_word(sheader[sec].sh_addralign, - xtlib_globals->byteswap); - if (sec_align > align) - align = sec_align; - } - sec++; - } - - return align; -} - -static int validate_dynamic(Elf32_Ehdr *header, - struct icm_process_info *process_info) -{ - struct xtlib_loader_globals *xtlib_globals = - &process_info->xtlib_globals; - - if (xtlib_verify_magic(header, process_info) != 0) - return XTLIB_NOT_ELF; - - if (xtlib_host_half(header->e_type, - xtlib_globals->byteswap) != ET_DYN) - return XTLIB_NOT_DYNAMIC; - - return XTLIB_NO_ERR; -} - -static int validate_dynamic_splitload(Elf32_Ehdr *header, - struct icm_process_info *process_info) -{ - struct xtlib_loader_globals *xtlib_globals = - &process_info->xtlib_globals; - Elf32_Phdr *pheader; - int err = validate_dynamic(header, process_info); - - if (err != XTLIB_NO_ERR) - return err; - - /* make sure it's split load pi library, expecting three headers, - * code, data and dynamic, for example: - * - *LOAD off 0x00000094 vaddr 0x00000000 paddr 0x00000000 align 2**0 - * filesz 0x00000081 memsz 0x00000081 flags r-x - *LOAD off 0x00000124 vaddr 0x00000084 paddr 0x00000084 align 2**0 - * filesz 0x000001ab memsz 0x000011bc flags rwx - *DYNAMIC off 0x00000124 vaddr 0x00000084 paddr 0x00000084 align 2**2 - * filesz 0x000000a0 memsz 0x000000a0 flags rw- - */ - - if (xtlib_host_half(header->e_phnum, xtlib_globals->byteswap) != 3) - return XTLIB_NOT_SPLITLOAD; - - pheader = (Elf32_Phdr *) ((char *)header + - xtlib_host_word(header->e_phoff, xtlib_globals->byteswap)); - - /* LOAD R-X */ - if (xtlib_host_word(pheader[0].p_type, - xtlib_globals->byteswap) != PT_LOAD - || (xtlib_host_word(pheader[0].p_flags, xtlib_globals->byteswap) - & (PF_R | PF_W | PF_X)) != (PF_R | PF_X)) - return XTLIB_NOT_SPLITLOAD; - - /* LOAD RWX */ - if (xtlib_host_word(pheader[1].p_type, - xtlib_globals->byteswap) != PT_LOAD - || (xtlib_host_word(pheader[1].p_flags, - xtlib_globals->byteswap) - & (PF_R | PF_W | PF_X)) != (PF_R | PF_W | PF_X)) - return XTLIB_NOT_SPLITLOAD; - - /* DYNAMIC RW- */ - if (xtlib_host_word(pheader[2].p_type, - xtlib_globals->byteswap) != PT_DYNAMIC - || (xtlib_host_word(pheader[2].p_flags, - xtlib_globals->byteswap) - & (PF_R | PF_W | PF_X)) != (PF_R | PF_W)) - return XTLIB_NOT_SPLITLOAD; - - return XTLIB_NO_ERR; -} - - - -unsigned int xtlib_split_pi_library_size( - struct xtlib_packaged_library *library, - unsigned int *code_size, - unsigned int *data_size, - struct icm_process_info *process_info) -{ - struct xtlib_loader_globals *xtlib_globals = - &process_info->xtlib_globals; - Elf32_Phdr *pheader; - Elf32_Ehdr *header = (Elf32_Ehdr *) library; - int align; - int err = validate_dynamic_splitload(header, process_info); - - if (err != XTLIB_NO_ERR) { - xtlib_globals->err = err; - return err; - } - - align = find_align(header, process_info); - - pheader = (Elf32_Phdr *) ((char *)library + - xtlib_host_word(header->e_phoff, xtlib_globals->byteswap)); - - *code_size = xtlib_host_word(pheader[0].p_memsz, - xtlib_globals->byteswap) + align; - *data_size = xtlib_host_word(pheader[1].p_memsz, - xtlib_globals->byteswap) + align; - - return XTLIB_NO_ERR; -} - - - -static int get_dyn_info(Elf32_Ehdr *eheader, - xt_ptr dst_addr, - xt_uint src_offs, - xt_ptr dst_data_addr, - xt_uint src_data_offs, - struct xtlib_pil_info *info, - struct icm_process_info *process_info) -{ - unsigned int jmprel = 0; - unsigned int pltrelsz = 0; - struct xtlib_loader_globals *xtlib_globals = - &process_info->xtlib_globals; - Elf32_Dyn *dyn_entry = find_dynamic_info(eheader, process_info); - - if (dyn_entry == 0) - return XTLIB_NO_DYNAMIC_SEGMENT; - - info->dst_addr = (xt_uint) xtlib_xt_word((Elf32_Word) dst_addr, - xtlib_globals->byteswap); - info->src_offs = xtlib_xt_word(src_offs, xtlib_globals->byteswap); - info->dst_data_addr = (xt_uint) xtlib_xt_word( - (Elf32_Word) dst_data_addr + src_data_offs, - xtlib_globals->byteswap); - info->src_data_offs = xtlib_xt_word(src_data_offs, - xtlib_globals->byteswap); - - dst_addr -= src_offs; - dst_data_addr = dst_data_addr + src_data_offs - src_data_offs; - - info->start_sym = xt_ptr_offs(dst_addr, eheader->e_entry, process_info); - - info->align = xtlib_xt_word(find_align(eheader, process_info), - xtlib_globals->byteswap); - - info->text_addr = 0; - - while (dyn_entry->d_tag != DT_NULL) { - switch ((Elf32_Sword) xtlib_host_word( - (Elf32_Word)dyn_entry->d_tag, - xtlib_globals->byteswap)) { - case DT_RELA: - info->rel = xt_ptr_offs(dst_data_addr, - dyn_entry->d_un.d_ptr, process_info); - break; - case DT_RELASZ: - info->rela_count = xtlib_xt_word( - xtlib_host_word(dyn_entry->d_un.d_val, - xtlib_globals->byteswap) / sizeof(Elf32_Rela), - xtlib_globals->byteswap); - break; - case DT_INIT: - info->init = xt_ptr_offs(dst_addr, - dyn_entry->d_un.d_ptr, process_info); - break; - case DT_FINI: - info->fini = xt_ptr_offs(dst_addr, - dyn_entry->d_un.d_ptr, process_info); - break; - case DT_HASH: - info->hash = xt_ptr_offs(dst_data_addr, - dyn_entry->d_un.d_ptr, process_info); - break; - case DT_SYMTAB: - info->symtab = xt_ptr_offs(dst_data_addr, - dyn_entry->d_un.d_ptr, process_info); - break; - case DT_STRTAB: - info->strtab = xt_ptr_offs(dst_data_addr, - dyn_entry->d_un.d_ptr, process_info); - break; - case DT_JMPREL: - jmprel = dyn_entry->d_un.d_val; - break; - case DT_PLTRELSZ: - pltrelsz = dyn_entry->d_un.d_val; - break; - case DT_LOPROC + 2: - info->text_addr = xt_ptr_offs(dst_addr, - dyn_entry->d_un.d_ptr, process_info); - break; - - default: - /* do nothing */ - break; - } - dyn_entry++; - } - - return XTLIB_NO_ERR; -} - - -static xt_ptr xtlib_load_split_pi_library_common( - struct xtlib_packaged_library *library, - xt_ptr destination_code_address, - xt_ptr destination_data_address, - struct xtlib_pil_info *lib_info, - memcpy_func mcpy_fn, - memset_func mset_fn, - struct icm_process_info *process_info) -{ - struct xtlib_loader_globals *xtlib_globals = - &process_info->xtlib_globals; - Elf32_Ehdr *header = (Elf32_Ehdr *) library; - Elf32_Phdr *pheader; - unsigned int align; - int err = validate_dynamic_splitload(header, process_info); - xt_ptr destination_code_address_back; - xt_ptr destination_data_address_back; - - if (err != XTLIB_NO_ERR) { - xtlib_globals->err = err; - return 0; - } - - align = find_align(header, process_info); - - destination_code_address_back = destination_code_address; - destination_data_address_back = destination_data_address; - - destination_code_address = align_ptr(destination_code_address, align); - destination_data_address = align_ptr(destination_data_address, align); - process_info->code_buf_virt += (destination_code_address - - destination_code_address_back); - process_info->data_buf_virt += (destination_data_address - - destination_data_address_back); - - pheader = (Elf32_Phdr *) ((char *)library + - xtlib_host_word(header->e_phoff, - xtlib_globals->byteswap)); - - err = get_dyn_info(header, - destination_code_address, - xtlib_host_word(pheader[0].p_paddr, - xtlib_globals->byteswap), - destination_data_address, - xtlib_host_word(pheader[1].p_paddr, - xtlib_globals->byteswap), - lib_info, - process_info); - - if (err != XTLIB_NO_ERR) { - xtlib_globals->err = err; - return 0; - } - - /* loading code */ - xtlib_load_seg(&pheader[0], - (char *)library + xtlib_host_word(pheader[0].p_offset, - xtlib_globals->byteswap), - (xt_ptr)process_info->code_buf_virt, - mcpy_fn, mset_fn, process_info); - - if (lib_info->text_addr == 0) - lib_info->text_addr = - (xt_ptr) xtlib_xt_word((Elf32_Word) destination_code_address, - xtlib_globals->byteswap); - - /* loading data */ - xtlib_load_seg(&pheader[1], - (char *)library + xtlib_host_word(pheader[1].p_offset, - xtlib_globals->byteswap), - (xt_ptr)process_info->data_buf_virt + - xtlib_host_word(pheader[1].p_paddr, - xtlib_globals->byteswap), - mcpy_fn, mset_fn, process_info); - - if (err != XTLIB_NO_ERR) { - xtlib_globals->err = err; - return 0; - } - - return (xt_ptr) xtlib_host_word((Elf32_Word) lib_info->start_sym, - xtlib_globals->byteswap); -} - -xt_ptr xtlib_host_load_split_pi_library(struct xtlib_packaged_library *library, - xt_ptr destination_code_address, - xt_ptr destination_data_address, - struct xtlib_pil_info *lib_info, - memcpy_func mcpy_fn, - memset_func mset_fn, - struct icm_process_info *process_info) -{ - return xtlib_load_split_pi_library_common(library, - destination_code_address, - destination_data_address, - lib_info, - mcpy_fn, - mset_fn, - process_info); -} - - -long load_dpu_with_library(struct fsl_hifi4 *hifi4_priv, - struct icm_process_info *process_info) -{ - struct device *dev = hifi4_priv->dev; - struct file *fpInfile; - unsigned char *srambuf = NULL; - struct lib_dnld_info_t dpulib; - Elf32_Phdr *pheader; - Elf32_Ehdr *header; - unsigned int align; - int filesize = 0; - long ret_val = 0; - - /* Load DPU's main program to System memory */ - fpInfile = file_open_name(process_info->objfile, O_RDONLY, 0); - if (IS_ERR(fpInfile)) - return PTR_ERR(fpInfile); - - vfs_llseek(fpInfile, 0, SEEK_END); - filesize = (int)fpInfile->f_pos; - - srambuf = kmalloc(filesize, GFP_KERNEL); - vfs_llseek(fpInfile, 0, SEEK_SET); - - kernel_read(fpInfile, srambuf, filesize, NULL); - filp_close(fpInfile, NULL); - - ret_val = xtlib_split_pi_library_size( - (struct xtlib_packaged_library *)(srambuf), - (unsigned int *)&(dpulib.size_code), - (unsigned int *)&(dpulib.size_data), - process_info); - if (ret_val != XTLIB_NO_ERR) - return ret_val; - - process_info->code_buf_size = dpulib.size_code; - process_info->data_buf_size = dpulib.size_data; - - header = (Elf32_Ehdr *)srambuf; - pheader = (Elf32_Phdr *) ((char *)srambuf + - xtlib_host_word(header->e_phoff, - process_info->xtlib_globals.byteswap)); - - align = find_align(header, process_info); - - process_info->code_buf_phys = hifi4_buf_alloc(hifi4_priv, - dpulib.size_code + align); - if (!process_info->code_buf_phys) { - kfree(srambuf); - dev_err(dev, "not enough buffer when loading codec lib\n"); - return -ENOMEM; - } - process_info->array_alloc_mem[process_info->alloc_count++] = - process_info->code_buf_phys; - - process_info->data_buf_phys = hifi4_buf_alloc(hifi4_priv, - dpulib.size_data + pheader[1].p_paddr + align); - if (!process_info->data_buf_phys) { - kfree(srambuf); - dev_err(dev, "not enough buffer when loading codec lib\n"); - return -ENOMEM; - } - process_info->array_alloc_mem[process_info->alloc_count++] = - process_info->data_buf_phys; - - dpulib.pbuf_code = (unsigned long)process_info->code_buf_phys; - dpulib.pbuf_data = (unsigned long)process_info->data_buf_phys; - - process_info->code_buf_virt = hifi4_priv->sdram_vir_addr + - (process_info->code_buf_phys - hifi4_priv->sdram_phys_addr); - process_info->data_buf_virt = hifi4_priv->sdram_vir_addr + - (process_info->data_buf_phys - hifi4_priv->sdram_phys_addr); - - dpulib.ppil_inf = &process_info->pil_info; - xtlib_host_load_split_pi_library( - (struct xtlib_packaged_library *) (srambuf), - (xt_ptr) (dpulib.pbuf_code), - (xt_ptr) (dpulib.pbuf_data), - (struct xtlib_pil_info *)dpulib.ppil_inf, - (memcpy_func)&memcpy_hifi, - (memset_func)&memset_hifi, - (void *)process_info); - - kfree(srambuf); - - return ret_val; -} - -static long fsl_hifi4_init_codec(struct fsl_hifi4 *hifi4_priv, - void __user *user) -{ - struct device *dev = hifi4_priv->dev; - union icm_header_t apu_icm; - struct hifi4_ext_msg ext_msg; - struct icm_base_info_t icm_base_info_t; - struct icm_process_info *process_info; - int id; - long ret = 0; - - ret = copy_from_user(&id, user, sizeof(int)); - if (ret) { - dev_err(dev, "failed to get para from user space\n"); - return -EFAULT; - } - - process_info = &hifi4_priv->process_info[id]; + int id = client->id; + struct fsl_hifi4 *hifi4_priv = (struct fsl_hifi4 *)client->global; - init_completion(&hifi4_priv->cmd_complete); - hifi4_priv->is_done = 0; + /* ...put proxy client id into free clients list */ + hifi4_priv->xf_client_map[id].next = hifi4_priv->xf_client_map[0].next; + hifi4_priv->xf_client_map[0].next = id; - apu_icm.allbits = 0; /* clear all bits;*/ - apu_icm.ack = 0; - apu_icm.intr = 1; - apu_icm.msg = ICM_PI_LIB_INIT; - apu_icm.size = 8; - - ext_msg.phys = hifi4_priv->msg_buf_phys; - ext_msg.size = sizeof(struct icm_base_info_t); - - memset(&icm_base_info_t, 0, sizeof(struct icm_base_info_t)); - icm_base_info_t.process_id = id; - icm_base_info_t.codec_id = process_info->codec_id; - - memcpy(hifi4_priv->msg_buf_virt, &icm_base_info_t, - sizeof(struct icm_base_info_t)); - icm_intr_extended_send(hifi4_priv, apu_icm.allbits, &ext_msg); - - /* wait for response here */ - ret = icm_ack_wait(hifi4_priv, apu_icm.allbits); - if (ret) - return ret; - - /* allocate input and output buffer from dsp framework */ - process_info->in_buf_phys = hifi4_buf_alloc(hifi4_priv, - INPUT_BUF_SIZE); - if (!process_info->in_buf_phys) { - dev_err(dev, "Fail to alloc input buffer\n"); - return -ENOMEM; - } - process_info->array_alloc_mem[process_info->alloc_count++] = - process_info->in_buf_phys; - - process_info->out_buf_phys = hifi4_buf_alloc(hifi4_priv, - OUTPUT_BUF_SIZE); - if (!process_info->out_buf_phys) { - dev_err(dev, "Fail to alloc output buffer\n"); - return -ENOMEM; - } - process_info->array_alloc_mem[process_info->alloc_count++] = - process_info->out_buf_phys; - - /* caculate the virtual address based on physical address */ - process_info->in_buf_virt = hifi4_priv->sdram_vir_addr + - (process_info->in_buf_phys - hifi4_priv->sdram_phys_addr); - process_info->out_buf_virt = hifi4_priv->sdram_vir_addr + - (process_info->out_buf_phys - hifi4_priv->sdram_phys_addr); - - return hifi4_priv->ret_status; + /* ...destroy client data */ + kfree(client); } -static long fsl_hifi4_decode_frame(struct fsl_hifi4 *hifi4_priv, - void __user *user) +/* ...lookup client basing on id */ +struct xf_client *xf_client_lookup(struct fsl_hifi4 *hifi4_priv, u32 id) { - struct device *dev = hifi4_priv->dev; - union icm_header_t apu_icm; - struct hifi4_ext_msg ext_msg; - struct decode_info decode_info; - struct icm_process_info *process_info; - struct icm_cdc_iobuf_t *codec_iobuf_info = - &hifi4_priv->codec_iobuf_info; - int id; - long ret; - - ret = copy_from_user(&decode_info, user, sizeof(decode_info)); - if (ret) { - dev_err(dev, "failed to get para from user space\n"); - return -EFAULT; - } - - id = decode_info.process_id; - process_info = &hifi4_priv->process_info[id]; - - if (decode_info.in_buf_size > INPUT_BUF_SIZE || - decode_info.out_buf_size != OUTPUT_BUF_SIZE) { - dev_err(dev, "param error\n"); - return -EINVAL; - } - - if (decode_info.in_buf_off == 0) { - ret = copy_from_user(process_info->in_buf_virt, - (void __user *)decode_info.in_buf_addr, - decode_info.in_buf_size); - if (ret) { - dev_err(dev, "failed to copy from user\n"); - return -EFAULT; - } - codec_iobuf_info->inp_cur_offset = 0; - } - - codec_iobuf_info->inp_addr_sysram = process_info->in_buf_phys; - codec_iobuf_info->inp_buf_size_max = decode_info.in_buf_size; - codec_iobuf_info->inp_cur_offset = decode_info.in_buf_off; - - codec_iobuf_info->out_addr_sysram = process_info->out_buf_phys; - codec_iobuf_info->out_buf_size_max = process_info->out_buf_size; - codec_iobuf_info->out_cur_offset = 0; - - codec_iobuf_info->input_over = decode_info.input_over; - codec_iobuf_info->base_info.process_id = decode_info.process_id; - - init_completion(&hifi4_priv->cmd_complete); - hifi4_priv->is_done = 0; - - apu_icm.allbits = 0; /* clear all bits; */ - apu_icm.ack = 0; - apu_icm.intr = 1; - apu_icm.msg = ICM_EMPTY_THIS_BUFFER; - apu_icm.size = 8; - ext_msg.phys = hifi4_priv->msg_buf_phys; - ext_msg.size = sizeof(struct icm_cdc_iobuf_t); - - memcpy(hifi4_priv->msg_buf_virt, codec_iobuf_info, - sizeof(struct icm_cdc_iobuf_t)); - icm_intr_extended_send(hifi4_priv, apu_icm.allbits, &ext_msg); - - /* wait for response here */ - ret = icm_ack_wait(hifi4_priv, apu_icm.allbits); - if (ret) - return ret; - - ret = copy_to_user((void __user *)decode_info.out_buf_addr, - process_info->out_buf_virt, - codec_iobuf_info->out_cur_offset); - if (ret) { - dev_err(dev, "failed to copy to user\n"); - return -EFAULT; - } - - decode_info.in_buf_off = codec_iobuf_info->inp_cur_offset; - decode_info.out_buf_off = codec_iobuf_info->out_cur_offset; - - ret = copy_to_user(user, &decode_info, sizeof(decode_info)); - if (ret) { - dev_err(dev, "failed to send para to user space\n"); - return -EFAULT; - } - - ret = hifi4_priv->ret_status; - return ret; + if ((id >= XF_CFG_MAX_IPC_CLIENTS) || + (hifi4_priv->xf_client_map[id].next < XF_CFG_MAX_IPC_CLIENTS) + ) + return NULL; + else + return hifi4_priv->xf_client_map[id].client; } -#ifdef CONFIG_COMPAT -static long fsl_hifi4_decode_frame_compat32(struct fsl_hifi4 *hifi4_priv, - void __user *user) +/* ...helper function for retrieving the client handle */ +static inline struct xf_client *xf_get_client(struct file *file) { - struct device *dev = hifi4_priv->dev; - union icm_header_t apu_icm; - struct hifi4_ext_msg ext_msg; - struct decode_info decode_info; - struct icm_process_info *process_info; - struct icm_cdc_iobuf_t *codec_iobuf_info = - &hifi4_priv->codec_iobuf_info; - int id; - long ret; - - ret = get_decode_info_compat32(&decode_info, user); - if (ret) { - dev_err(dev, "failed to get para from user space in compat32 mode\n"); - return ret; - } + struct xf_client *client; + u32 id; - id = decode_info.process_id; - process_info = &hifi4_priv->process_info[id]; + client = (struct xf_client *)file->private_data; + if (!client) + return ERR_PTR(-EINVAL); - if (decode_info.in_buf_size > INPUT_BUF_SIZE || - decode_info.out_buf_size != OUTPUT_BUF_SIZE) { - dev_err(dev, "param error\n"); - return -EINVAL; - } + id = client->id; + if (id >= XF_CFG_MAX_IPC_CLIENTS) + return ERR_PTR(-EINVAL); - if (decode_info.in_buf_off == 0) { - ret = copy_from_user(process_info->in_buf_virt, - (void __user *)decode_info.in_buf_addr, - decode_info.in_buf_size); - if (ret) { - dev_err(dev, "failed to copy from user\n"); - return -EFAULT; - } - codec_iobuf_info->inp_cur_offset = 0; - } - - codec_iobuf_info->inp_addr_sysram = process_info->in_buf_phys; - codec_iobuf_info->inp_buf_size_max = decode_info.in_buf_size; - codec_iobuf_info->inp_cur_offset = decode_info.in_buf_off; - - codec_iobuf_info->out_addr_sysram = process_info->out_buf_phys; - codec_iobuf_info->out_buf_size_max = process_info->out_buf_size; - codec_iobuf_info->out_cur_offset = 0; - - codec_iobuf_info->input_over = decode_info.input_over; - codec_iobuf_info->base_info.process_id = decode_info.process_id; - - init_completion(&hifi4_priv->cmd_complete); - hifi4_priv->is_done = 0; - - apu_icm.allbits = 0; /* clear all bits; */ - apu_icm.ack = 0; - apu_icm.intr = 1; - apu_icm.msg = ICM_EMPTY_THIS_BUFFER; - apu_icm.size = 8; - ext_msg.phys = hifi4_priv->msg_buf_phys; - ext_msg.size = sizeof(struct icm_cdc_iobuf_t); - - memcpy(hifi4_priv->msg_buf_virt, codec_iobuf_info, - sizeof(struct icm_cdc_iobuf_t)); - icm_intr_extended_send(hifi4_priv, apu_icm.allbits, &ext_msg); - - /* wait for response here */ - ret = icm_ack_wait(hifi4_priv, apu_icm.allbits); - if (ret) - return ret; - - ret = copy_to_user((void __user *)decode_info.out_buf_addr, - process_info->out_buf_virt, - codec_iobuf_info->out_cur_offset); - if (ret) { - dev_err(dev, "failed to copy to user\n"); - return -EFAULT; - } - - decode_info.in_buf_off = codec_iobuf_info->inp_cur_offset; - decode_info.out_buf_off = codec_iobuf_info->out_cur_offset; - - ret = put_decode_info_compat32(&decode_info, user); - if (ret) { - dev_err(dev, "failed to send para to user space in compat32 mode\n"); - return ret; - } - - ret = hifi4_priv->ret_status; - return ret; + return client; } -#endif -static long fsl_hifi4_get_pcm_prop(struct fsl_hifi4 *hifi4_priv, - void __user *user) +static int fsl_dsp_client_register(struct xf_client *client) { - struct device *dev = hifi4_priv->dev; - union icm_header_t apu_icm; - struct hifi4_ext_msg ext_msg; - struct icm_pcm_prop_t *pcm_prop_info = &hifi4_priv->pcm_prop_info; - struct prop_info prop_info; - long ret = 0; - - ret = copy_from_user(&prop_info, user, sizeof(prop_info)); - if (ret) { - dev_err(dev, "failed to get para from user space\n"); - return -EFAULT; - } - - init_completion(&hifi4_priv->cmd_complete); - hifi4_priv->is_done = 0; - - apu_icm.allbits = 0; /* clear all bits;*/ - apu_icm.ack = 0; - apu_icm.intr = 1; - apu_icm.msg = ICM_GET_PCM_PROP; - apu_icm.size = 8; - - ext_msg.phys = hifi4_priv->msg_buf_phys; - ext_msg.size = sizeof(struct icm_pcm_prop_t); - - pcm_prop_info->base_info.process_id = prop_info.process_id; - - memcpy(hifi4_priv->msg_buf_virt, pcm_prop_info, - sizeof(struct icm_pcm_prop_t)); - icm_intr_extended_send(hifi4_priv, apu_icm.allbits, &ext_msg); - - /* wait for response here */ - ret = icm_ack_wait(hifi4_priv, apu_icm.allbits); - if (ret) - return ret; - - prop_info.samplerate = pcm_prop_info->sfreq; - prop_info.channels = pcm_prop_info->channels; - prop_info.bits = pcm_prop_info->bits; - prop_info.consumed_bytes = pcm_prop_info->consumed_bytes; - prop_info.cycles = pcm_prop_info->cycles; - - ret = copy_to_user(user, &prop_info, sizeof(prop_info)); - if (ret) { - dev_err(dev, "failed to send para to user space\n"); - return -EFAULT; - } - - ret = hifi4_priv->ret_status; - return ret; -} + struct fsl_hifi4 *hifi4_priv; + struct device *dev; -static int fsl_hifi4_set_config(struct fsl_hifi4 *hifi4_priv, void __user *user) -{ - struct device *dev = hifi4_priv->dev; - union icm_header_t apu_icm; - struct hifi4_ext_msg ext_msg; - struct prop_config prop_config; - struct icm_prop_config icm_prop_config; - int ret; + hifi4_priv = (struct fsl_hifi4 *)client->global; + dev = hifi4_priv->dev; - ret = copy_from_user(&prop_config, user, sizeof(prop_config)); - if (ret) { - dev_err(dev, "failed to get para from user space: %d\n", ret); - return -EFAULT; + /* ...make sure client is not registered yet */ + if (client->proxy != NULL) { + pr_err("client-%x already registered", client->id); + return -EBUSY; } - init_completion(&hifi4_priv->cmd_complete); - hifi4_priv->is_done = 0; + /* ...complete association (no communication with remote proxy here) */ + client->proxy = &hifi4_priv->proxy; - apu_icm.allbits = 0; - apu_icm.ack = 0; - apu_icm.intr = 1; - apu_icm.msg = ICM_SET_PARA_CONFIG; - apu_icm.size = 8; + pr_debug("client-%x registered within proxy", client->id); - ext_msg.phys = hifi4_priv->msg_buf_phys; - ext_msg.size = sizeof(struct icm_prop_config); - - icm_prop_config.base_info.process_id = prop_config.process_id; - icm_prop_config.cmd = prop_config.cmd; - icm_prop_config.val = prop_config.val; - - memcpy(hifi4_priv->msg_buf_virt, &icm_prop_config, - sizeof(struct icm_prop_config)); - icm_intr_extended_send(hifi4_priv, apu_icm.allbits, &ext_msg); - - icm_ack_wait(hifi4_priv, apu_icm.allbits); - if (ret) - return ret; - - ret = hifi4_priv->ret_status; - - return ret; + return 0; } -static long fsl_hifi4_load_codec(struct fsl_hifi4 *hifi4_priv, - void __user *user) +/* ...unregister client from shared memory interface */ +static int fsl_dsp_client_unregister(struct xf_client *client) { - struct device *dev = hifi4_priv->dev; - struct filename *fpInfile; - union icm_header_t apu_icm; - struct binary_info binary_info; - struct hifi4_ext_msg ext_msg; - struct icm_xtlib_pil_info icm_xtlib_pil_info; - long ret = 0; - long id; - - ret = copy_from_user(&binary_info, user, sizeof(binary_info)); - if (ret) { - dev_err(dev, "failed to get para from user space\n"); - return -EFAULT; - } + struct xf_proxy *proxy = client->proxy; - fpInfile = getname(binary_info.file); - if (IS_ERR(fpInfile)) { - dev_err(dev, "failed to getname(), err = %ld\n", - PTR_ERR(fpInfile)); - return PTR_ERR(fpInfile); + /* ...make sure client is registered */ + if (proxy == NULL) { + pr_err("client-%x is not registered", client->id); + return -EBUSY; } - id = binary_info.process_id; - - hifi4_priv->process_info[id].objfile = fpInfile; - hifi4_priv->process_info[id].objtype = binary_info.type; - hifi4_priv->process_info[id].codec_id = binary_info.type; - ret = load_dpu_with_library(hifi4_priv, &hifi4_priv->process_info[id]); - if (ret) { - dev_err(dev, "failed to load code binary, err = %ld\n", ret); - return ret; - } - - init_completion(&hifi4_priv->cmd_complete); - hifi4_priv->is_done = 0; - - apu_icm.allbits = 0; /* clear all bits;*/ - apu_icm.ack = 0; - apu_icm.intr = 1; - apu_icm.msg = ICM_PI_LIB_LOAD; - apu_icm.size = 8; - - ext_msg.phys = hifi4_priv->msg_buf_phys; - ext_msg.size = sizeof(struct icm_xtlib_pil_info); - memcpy(&icm_xtlib_pil_info.pil_info, - &hifi4_priv->process_info[id].pil_info, - sizeof(struct xtlib_pil_info)); - icm_xtlib_pil_info.process_id = id; - icm_xtlib_pil_info.lib_type = binary_info.lib_type; + /* ...just clean proxy reference */ + client->proxy = NULL; - memcpy(hifi4_priv->msg_buf_virt, &icm_xtlib_pil_info, - sizeof(struct icm_xtlib_pil_info)); - icm_intr_extended_send(hifi4_priv, apu_icm.allbits, &ext_msg); + pr_debug("client-%x registered within proxy", client->id); - /* wait for response here */ - ret = icm_ack_wait(hifi4_priv, apu_icm.allbits); - if (ret) - return ret; - - ret = hifi4_priv->ret_status; - - dev_dbg(dev, "code binary is loaded\n"); - - return ret; -} - -#ifdef CONFIG_COMPAT -static long fsl_hifi4_load_codec_compat32(struct fsl_hifi4 *hifi4_priv, - void __user *user) -{ - struct device *dev = hifi4_priv->dev; - struct filename *fpInfile; - union icm_header_t apu_icm; - struct binary_info binary_info; - struct hifi4_ext_msg ext_msg; - struct icm_xtlib_pil_info icm_xtlib_pil_info; - long ret = 0; - long id; - - ret = get_binary_info_compat32(&binary_info, user); - if (ret) { - dev_err(dev, "failed to get para from user space in compat32 mode\n"); - return ret; - } - - fpInfile = getname(binary_info.file); - if (IS_ERR(fpInfile)) { - dev_err(dev, "failed to getname(), err = %ld\n", - PTR_ERR(fpInfile)); - return PTR_ERR(fpInfile); - } - id = binary_info.process_id; - - hifi4_priv->process_info[id].objfile = fpInfile; - hifi4_priv->process_info[id].objtype = binary_info.type; - hifi4_priv->process_info[id].codec_id = binary_info.type; - ret = load_dpu_with_library(hifi4_priv, &hifi4_priv->process_info[id]); - if (ret) { - dev_err(dev, "failed to load code binary, err = %ld\n", ret); - return ret; - } - - init_completion(&hifi4_priv->cmd_complete); - hifi4_priv->is_done = 0; - - apu_icm.allbits = 0; /* clear all bits; */ - apu_icm.ack = 0; - apu_icm.intr = 1; - apu_icm.msg = ICM_PI_LIB_LOAD; - apu_icm.size = 8; - - ext_msg.phys = hifi4_priv->msg_buf_phys; - ext_msg.size = sizeof(struct icm_xtlib_pil_info); - - memcpy(&icm_xtlib_pil_info.pil_info, - &hifi4_priv->process_info[id].pil_info, - sizeof(struct xtlib_pil_info)); - icm_xtlib_pil_info.process_id = id; - icm_xtlib_pil_info.lib_type = binary_info.lib_type; - - memcpy(hifi4_priv->msg_buf_virt, &icm_xtlib_pil_info, - sizeof(struct icm_xtlib_pil_info)); - icm_intr_extended_send(hifi4_priv, apu_icm.allbits, &ext_msg); - - /* wait for response here */ - ret = icm_ack_wait(hifi4_priv, apu_icm.allbits); - if (ret) - return ret; - - ret = hifi4_priv->ret_status; - - dev_dbg(dev, "code binary is loaded\n"); - - return ret; + return 0; } -#endif -static long fsl_hifi4_codec_open(struct fsl_hifi4 *hifi4_priv, +static int fsl_dsp_ipc_msg_to_dsp(struct xf_client *client, void __user *user) { + struct fsl_hifi4 *hifi4_priv = (struct fsl_hifi4 *)client->global; struct device *dev = hifi4_priv->dev; - union icm_header_t apu_icm; - struct hifi4_ext_msg ext_msg; - struct icm_base_info_t icm_base_info_t; - struct icm_process_info *process_info; - int id; - long ret = 0; + struct xf_proxy_message msg; + void *buffer; + unsigned long ret = 0; - ret = copy_from_user(&id, user, sizeof(int)); + ret = copy_from_user(&msg, user, sizeof(struct xf_proxy_message)); if (ret) { - dev_err(dev, "failed to get para from user space\n"); + dev_err(dev, "failed to get message from user space\n"); return -EFAULT; } - process_info = &hifi4_priv->process_info[id]; - - init_completion(&hifi4_priv->cmd_complete); - hifi4_priv->is_done = 0; - - apu_icm.allbits = 0; /* clear all bits;*/ - apu_icm.ack = 0; - apu_icm.intr = 1; - apu_icm.msg = ICM_OPEN; - apu_icm.size = 8; - - ext_msg.phys = hifi4_priv->msg_buf_phys; - ext_msg.size = sizeof(struct icm_base_info_t); - - memset(&icm_base_info_t, 0, sizeof(struct icm_base_info_t)); - icm_base_info_t.process_id = id; - - memcpy(hifi4_priv->msg_buf_virt, &icm_base_info_t, - sizeof(struct icm_base_info_t)); - icm_intr_extended_send(hifi4_priv, apu_icm.allbits, &ext_msg); - - /* wait for response here */ - ret = icm_ack_wait(hifi4_priv, apu_icm.allbits); - if (ret) - return ret; - - ret = hifi4_priv->ret_status; - - return ret; -} - -static int fsl_hifi4_codec_close(struct fsl_hifi4 *hifi4_priv, - void __user *user) -{ - struct device *dev = hifi4_priv->dev; - union icm_header_t apu_icm; - struct hifi4_ext_msg ext_msg; - struct icm_base_info_t icm_base_info_t; - int id; - long ret = 0; - - ret = copy_from_user(&id, user, sizeof(int)); - if (ret) { - dev_err(dev, "failed to get para from user space\n"); + /* ...make sure message pointer is sane */ + buffer = xf_proxy_a2b(&hifi4_priv->proxy, msg.address); + if (buffer == (void *)-1) return -EFAULT; - } - - init_completion(&hifi4_priv->cmd_complete); - hifi4_priv->is_done = 0; - - apu_icm.allbits = 0; /* clear all bits;*/ - apu_icm.ack = 0; - apu_icm.intr = 1; - apu_icm.msg = ICM_CLOSE; - apu_icm.size = 8; - ext_msg.phys = hifi4_priv->msg_buf_phys; - ext_msg.size = sizeof(struct icm_base_info_t); - - memset(&icm_base_info_t, 0, sizeof(struct icm_base_info_t)); - icm_base_info_t.process_id = id; - - memcpy(hifi4_priv->msg_buf_virt, &icm_base_info_t, - sizeof(struct icm_base_info_t)); - icm_intr_extended_send(hifi4_priv, apu_icm.allbits, &ext_msg); - - /* wait for response here */ - ret = icm_ack_wait(hifi4_priv, apu_icm.allbits); - if (ret) - return ret; + /* ...put current proxy client into message session id */ + msg.session_id = XF_MSG_AP_FROM_USER(msg.session_id, client->id); - ret = hifi4_priv->ret_status; + xf_cmd_send(&hifi4_priv->proxy, + msg.session_id, + msg.opcode, + buffer, + msg.length); - return ret; + return 0; } -static int fsl_hifi4_codec_reset(struct fsl_hifi4 *hifi4_priv, +static int fsl_dsp_ipc_msg_from_dsp(struct xf_client *client, void __user *user) { + struct fsl_hifi4 *hifi4_priv = (struct fsl_hifi4 *)client->global; struct device *dev = hifi4_priv->dev; - union icm_header_t apu_icm; - struct hifi4_ext_msg ext_msg; - struct icm_cdc_iobuf_t *codec_iobuf_info = - &hifi4_priv->codec_iobuf_info; - struct icm_base_info_t icm_base_info_t; - int id; - long err = 0; + struct xf_message *m; + struct xf_proxy_message msg; unsigned long ret = 0; - ret = copy_from_user(&id, user, sizeof(int)); - if (ret) { - dev_err(dev, "failed to get para from user space\n"); - return -EFAULT; + m = xf_cmd_recv(&hifi4_priv->proxy, &client->wait, &client->queue, 0); + if (IS_ERR(m)) { + dev_err(dev, "receiving failed: %d", (int)PTR_ERR(m)); + return PTR_ERR(m); } - init_completion(&hifi4_priv->cmd_complete); - hifi4_priv->is_done = 0; - - apu_icm.allbits = 0; /* clear all bits;*/ - apu_icm.ack = 0; - apu_icm.intr = 1; - apu_icm.msg = ICM_RESET; - apu_icm.size = 8; - - ext_msg.phys = hifi4_priv->msg_buf_phys; - ext_msg.size = sizeof(struct icm_base_info_t); - - memset(&icm_base_info_t, 0, sizeof(struct icm_base_info_t)); - icm_base_info_t.process_id = id; - - memcpy(hifi4_priv->msg_buf_virt, &icm_base_info_t, - sizeof(struct icm_base_info_t)); - icm_intr_extended_send(hifi4_priv, apu_icm.allbits, &ext_msg); - - /* wait for response here */ - err = icm_ack_wait(hifi4_priv, apu_icm.allbits); - if (err) - return err; + /* ...check if there is a response available */ + if (m == NULL) + return -EAGAIN; - /* reset codec_iobuf_info */ - codec_iobuf_info->inp_buf_size_max = 0; - codec_iobuf_info->inp_cur_offset = 0; + /* ...prepare message parameters (lock is taken) */ + msg.session_id = XF_MSG_AP_TO_USER(m->id); + msg.opcode = m->opcode; + msg.length = m->length; + msg.address = xf_proxy_b2a(&hifi4_priv->proxy, m->buffer); + msg.ret = m->ret; - codec_iobuf_info->out_buf_size_max = 0; - codec_iobuf_info->out_cur_offset = 0; + /* ...return the message back to a pool and release lock */ + xf_msg_free(&hifi4_priv->proxy, m); - err = hifi4_priv->ret_status; - - return err; -} - -static int fsl_hifi4_client_register(struct fsl_hifi4 *hifi4_priv, - void __user *user) -{ - struct device *dev = hifi4_priv->dev; - int id, i; - unsigned long ret = 0; - - for (i = 0; i < MULTI_CODEC_NUM; i++) { - if (hifi4_priv->process_info[i].used == 0) { - hifi4_priv->process_info[i].used = 1; - id = i; - break; - } - } - if (i >= MULTI_CODEC_NUM) { - dev_err(dev, "out of range of multi codec max number\n"); - return -EINVAL; - } - - ret = copy_to_user(user, &id, sizeof(int)); + ret = copy_to_user(user, &msg, sizeof(struct xf_proxy_message)); if (ret) { - dev_err(dev, "failed to send para to user space\n"); + dev_err(dev, "failed to response message to user space\n"); return -EFAULT; } return 0; } -static int fsl_hifi4_client_unregister(struct fsl_hifi4 *hifi4_priv, +static int fsl_dsp_get_shmem_info(struct xf_client *client, void __user *user) { + struct fsl_hifi4 *hifi4_priv = (struct fsl_hifi4 *)client->global; struct device *dev = hifi4_priv->dev; - struct icm_process_info *process_info; - int id, i; + struct shmem_info mem_info; unsigned long ret = 0; - ret = copy_from_user(&id, user, sizeof(int)); + mem_info.phys_addr = hifi4_priv->scratch_buf_phys; + mem_info.size = hifi4_priv->scratch_buf_size; + + ret = copy_to_user(user, &mem_info, sizeof(struct shmem_info)); if (ret) { - dev_err(dev, "failed to get para from user space\n"); + dev_err(dev, "failed to response message to user space\n"); return -EFAULT; } - if (id >= MULTI_CODEC_NUM) { - dev_err(dev, "invalid process id from user space\n"); - return -EINVAL; - } - - process_info = &hifi4_priv->process_info[id]; - - /* free buffers which are occupied by this process */ - for (i = 0; i < process_info->alloc_count; i++) { - hifi4_buf_free(hifi4_priv, - process_info->array_alloc_mem[i]); - process_info->array_alloc_mem[i] = 0; - } - - memset(process_info, 0, sizeof(struct icm_process_info)); - - return 0; + return ret; } static struct miscdevice hifi4_miscdev = { @@ -1498,120 +281,46 @@ static struct miscdevice hifi4_miscdev = { static long fsl_hifi4_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { - struct fsl_hifi4_engine *hifi4_engine; + struct xf_client *client; struct fsl_hifi4 *hifi4_priv; + struct xf_proxy *proxy; struct device *dev; void __user *user; long ret = 0; - hifi4_engine = file->private_data; - hifi4_priv = hifi4_engine->hifi4_priv; + /* ...basic sanity checks */ + client = xf_get_client(file); + if (IS_ERR(client)) + return PTR_ERR(client); + + hifi4_priv = (struct fsl_hifi4 *)client->global; + proxy = &hifi4_priv->proxy; dev = hifi4_priv->dev; user = (void __user *)arg; - if (!hifi4_priv->is_ready) { - dev_err(dev, "hifi firmware is not ready\n"); - return -EFAULT; - } - mutex_lock(&hifi4_priv->hifi4_mutex); - switch (cmd) { - case HIFI4_CLIENT_REGISTER: - ret = fsl_hifi4_client_register(hifi4_priv, user); - break; - case HIFI4_CLIENT_UNREGISTER: - ret = fsl_hifi4_client_unregister(hifi4_priv, user); - break; - case HIFI4_LOAD_CODEC: - ret = fsl_hifi4_load_codec(hifi4_priv, user); - break; - case HIFI4_INIT_CODEC: - ret = fsl_hifi4_init_codec(hifi4_priv, user); - break; - case HIFI4_CODEC_OPEN: - ret = fsl_hifi4_codec_open(hifi4_priv, user); - break; - case HIFI4_DECODE_ONE_FRAME: - ret = fsl_hifi4_decode_frame(hifi4_priv, user); - break; - case HIFI4_CODEC_CLOSE: - ret = fsl_hifi4_codec_close(hifi4_priv, user); - break; - case HIFI4_UNLOAD_CODEC: - break; - case HIFI4_GET_PCM_PROP: - ret = fsl_hifi4_get_pcm_prop(hifi4_priv, user); - break; - case HIFI4_SET_CONFIG: - ret = fsl_hifi4_set_config(hifi4_priv, user); - break; - case HIFI4_RESET_CODEC: - ret = fsl_hifi4_codec_reset(hifi4_priv, user); - break; - default: - break; - } - - mutex_unlock(&hifi4_priv->hifi4_mutex); - - return ret; -} - -#ifdef CONFIG_COMPAT -static long fsl_hifi4_compat_ioctl(struct file *file, unsigned int cmd, - unsigned long arg) -{ - struct fsl_hifi4_engine *hifi4_engine; - struct fsl_hifi4 *hifi4_priv; - struct device *dev; - void __user *user; - long ret = 0; - - hifi4_engine = file->private_data; - hifi4_priv = hifi4_engine->hifi4_priv; - dev = hifi4_priv->dev; - user = compat_ptr(arg); - - if (!hifi4_priv->is_ready) { + if (!proxy->is_ready) { + mutex_unlock(&hifi4_priv->hifi4_mutex); dev_err(dev, "hifi firmware is not ready\n"); return -EFAULT; } - mutex_lock(&hifi4_priv->hifi4_mutex); - switch (cmd) { - case HIFI4_CLIENT_REGISTER: - ret = fsl_hifi4_client_register(hifi4_priv, user); - break; - case HIFI4_CLIENT_UNREGISTER: - ret = fsl_hifi4_client_unregister(hifi4_priv, user); - break; - case HIFI4_LOAD_CODEC: - ret = fsl_hifi4_load_codec_compat32(hifi4_priv, user); - break; - case HIFI4_INIT_CODEC: - ret = fsl_hifi4_init_codec(hifi4_priv, user); + case DSP_CLIENT_REGISTER: + ret = fsl_dsp_client_register(client); break; - case HIFI4_CODEC_OPEN: - ret = fsl_hifi4_codec_open(hifi4_priv, user); + case DSP_CLIENT_UNREGISTER: + ret = fsl_dsp_client_unregister(client); break; - case HIFI4_DECODE_ONE_FRAME: - ret = fsl_hifi4_decode_frame_compat32(hifi4_priv, user); + case DSP_IPC_MSG_SEND: + ret = fsl_dsp_ipc_msg_to_dsp(client, user); break; - case HIFI4_CODEC_CLOSE: - ret = fsl_hifi4_codec_close(hifi4_priv, user); + case DSP_IPC_MSG_RECV: + ret = fsl_dsp_ipc_msg_from_dsp(client, user); break; - case HIFI4_UNLOAD_CODEC: - break; - case HIFI4_GET_PCM_PROP: - ret = fsl_hifi4_get_pcm_prop(hifi4_priv, user); - break; - case HIFI4_SET_CONFIG: - ret = fsl_hifi4_set_config(hifi4_priv, user); - break; - case HIFI4_RESET_CODEC: - ret = fsl_hifi4_codec_reset(hifi4_priv, user); + case DSP_GET_SHMEM_INFO: + ret = fsl_dsp_get_shmem_info(client, user); break; default: break; @@ -1621,49 +330,62 @@ static long fsl_hifi4_compat_ioctl(struct file *file, unsigned int cmd, return ret; } -#endif void resource_release(struct fsl_hifi4 *hifi4_priv) { int i; - for (i = 0; i < MULTI_CODEC_NUM; i++) - memset(&hifi4_priv->process_info[i], 0, - sizeof(struct icm_process_info)); + /* ...initialize client association map */ + for (i = 0; i < XF_CFG_MAX_IPC_CLIENTS - 1; i++) + hifi4_priv->xf_client_map[i].next = i + 1; + /* ...set list terminator */ + hifi4_priv->xf_client_map[i].next = 0; - if (hifi4_priv->is_ready) - send_dpu_ext_msg_addr(hifi4_priv); + /* ...set pointer to shared memory */ + xf_proxy_init(&hifi4_priv->proxy); } static int fsl_hifi4_open(struct inode *inode, struct file *file) { - struct fsl_hifi4 *hifi4_priv; - struct device *dev; - struct fsl_hifi4_engine *hifi4_engine; + struct fsl_hifi4 *hifi4_priv = dev_get_drvdata(hifi4_miscdev.parent); + struct device *dev = hifi4_priv->dev; + struct xf_client *client; int ret = 0; - hifi4_priv = dev_get_drvdata(hifi4_miscdev.parent); - dev = hifi4_priv->dev; + /* ...basic sanity checks */ + if (!inode || !file) + return -EINVAL; - pm_runtime_get_sync(dev); - mutex_lock(&hifi4_priv->hifi4_mutex); + /* ...allocate new proxy client object */ + client = xf_client_alloc(hifi4_priv); + if (IS_ERR(client)) + return PTR_ERR(client); - hifi4_engine = devm_kzalloc(dev, - sizeof(struct fsl_hifi4_engine), GFP_KERNEL); - if (!hifi4_engine) { - mutex_unlock(&hifi4_priv->hifi4_mutex); - return -ENOMEM; - } + /* ...initialize waiting queue */ + init_waitqueue_head(&client->wait); + + /* ...initialize client pending message queue */ + xf_msg_queue_init(&client->queue); + + /* ...mark user data is not mapped */ + client->vm_start = 0; + + /* ...reset mappings counter */ + atomic_set(&client->vm_use, 0); + + client->global = (void *)hifi4_priv; - hifi4_engine->hifi4_priv = hifi4_priv; + file->private_data = (void *)client; - file->private_data = hifi4_engine; + pm_runtime_get_sync(dev); + mutex_lock(&hifi4_priv->hifi4_mutex); /* increase reference counter when opening device */ atomic_long_inc(&hifi4_priv->refcnt); - mutex_unlock(&hifi4_priv->hifi4_mutex); + pr_info("client-%x created\n", client->id); + return ret; } @@ -1671,15 +393,30 @@ static int fsl_hifi4_close(struct inode *inode, struct file *file) { struct fsl_hifi4 *hifi4_priv; struct device *dev; - struct fsl_hifi4_engine *hifi4_engine; + struct xf_proxy *proxy; + struct xf_client *client; - hifi4_priv = dev_get_drvdata(hifi4_miscdev.parent); - mutex_lock(&hifi4_priv->hifi4_mutex); + /* ...basic sanity checks */ + client = xf_get_client(file); + if (IS_ERR(client)) + return PTR_ERR(client); + + pr_info("client-%x released\n", client->id); + + proxy = client->proxy; + if (proxy) { + /* ...release all pending messages */ + xf_msg_free_all(proxy, &client->queue); + + /* ...recycle client id and release memory */ + xf_client_free(client); + } + hifi4_priv = (struct fsl_hifi4 *)client->global; dev = hifi4_priv->dev; - hifi4_engine = file->private_data; - devm_kfree(dev, hifi4_engine); + pm_runtime_put_sync(dev); + mutex_lock(&hifi4_priv->hifi4_mutex); /* decrease reference counter when closing device */ atomic_long_dec(&hifi4_priv->refcnt); /* If device is free, reinitialize the resource of @@ -1689,11 +426,123 @@ static int fsl_hifi4_close(struct inode *inode, struct file *file) resource_release(hifi4_priv); mutex_unlock(&hifi4_priv->hifi4_mutex); - pm_runtime_put_sync(dev); return 0; } +/* ...wait until data is available in the response queue */ +static unsigned int fsl_hifi4_poll(struct file *file, poll_table *wait) +{ + struct xf_proxy *proxy; + struct xf_client *client; + int mask; + + /* ...basic sanity checks */ + client = xf_get_client(file); + if (IS_ERR(client)) + return PTR_ERR(client); + + /* ...get proxy interface */ + proxy = client->proxy; + if (!proxy) + return -EPERM; + + /* ...register client waiting queue */ + poll_wait(file, &client->wait, wait); + + /* ...return current queue state */ + mask = (xf_msg_queue_head(&client->queue) ? POLLIN | POLLRDNORM : 0); + + return mask; +} + +/******************************************************************************* + * Low-level mmap interface + ******************************************************************************/ + +/* ...add reference to shared buffer */ +static void hifi4_mmap_open(struct vm_area_struct *vma) +{ + struct xf_client *client = vma->vm_private_data; + + /* ...probably just increase counter of open references? - tbd */ + atomic_inc(&client->vm_use); + + pr_debug("xf_mmap_open: vma = %p, client = %p", vma, client); +} + +/* ...close reference to shared buffer */ +static void hifi4_mmap_close(struct vm_area_struct *vma) +{ + struct xf_client *client = vma->vm_private_data; + + pr_debug("xf_mmap_close: vma = %p, b = %p", vma, client); + + /* ...decrement number of mapping */ + atomic_dec_return(&client->vm_use); +} + +/* ...memory map operations */ +static const struct vm_operations_struct hifi4_mmap_ops = { + .open = hifi4_mmap_open, + .close = hifi4_mmap_close, +}; + +/* ...shared memory mapping */ +static int fsl_hifi4_mmap(struct file *file, struct vm_area_struct *vma) +{ + struct xf_proxy *proxy; + struct xf_client *client; + unsigned long size; + unsigned long pfn; + int r; + struct fsl_hifi4 *hifi4_priv; + + /* ...basic sanity checks */ + client = xf_get_client(file); + if (IS_ERR(client)) + return PTR_ERR(client); + + /* ...get proxy interface */ + proxy = client->proxy; + if (!proxy) + return -EPERM; + + /* ...check it was not mapped already */ + if (client->vm_start != 0) + return -EBUSY; + + /* ...check mapping flags (tbd) */ + if ((vma->vm_flags & (VM_READ | VM_WRITE | VM_SHARED)) + != (VM_READ | VM_WRITE | VM_SHARED)) + return -EPERM; + + /* ...set memory map operations */ + vma->vm_ops = &hifi4_mmap_ops; + + /* ...assign private data */ + client->vm_start = vma->vm_start; + + /* ...set private memory data */ + vma->vm_private_data = client; + + /* ...set page number of shared memory */ + hifi4_priv = (struct fsl_hifi4 *)client->global; + pfn = hifi4_priv->scratch_buf_phys >> PAGE_SHIFT; + size = hifi4_priv->scratch_buf_size; + + /* ...remap shared memory to user-space */ + vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); + r = remap_pfn_range(vma, vma->vm_start, pfn, size, vma->vm_page_prot); + if (r != 0) { + pr_err("mapping failed: %d", r); + return r; + } + + /* ...system-specific hook for registering shared memory mapping */ + return 0; +} + void *memset_hifi(void *dest, int c, size_t count) { uint *dl = (uint *)dest; @@ -1761,278 +610,6 @@ void *memcpy_hifi(void *dest, const void *src, size_t count) return dest; } -u32 icm_intr_send(struct fsl_hifi4 *hifi4_priv, u32 msg) -{ - MU_SendMessage(hifi4_priv->mu_base_virtaddr, 0, msg); - return 0; -} - -u32 icm_intr_extended_send(struct fsl_hifi4 *hifi4_priv, u32 msg, - struct hifi4_ext_msg *ext_msg) -{ - struct device *dev = hifi4_priv->dev; - union icm_header_t lmsg; - - lmsg.allbits = msg; - if (lmsg.size != 8) - dev_err(dev, "too much ext msg\n"); - - MU_SendMessage(hifi4_priv->mu_base_virtaddr, 1, ext_msg->phys); - MU_SendMessage(hifi4_priv->mu_base_virtaddr, 2, ext_msg->size); - MU_SendMessage(hifi4_priv->mu_base_virtaddr, 0, msg); - - return 0; -} - -long icm_ack_wait(struct fsl_hifi4 *hifi4_priv, u32 msg) -{ - struct device *dev = hifi4_priv->dev; - union icm_header_t ref_msg; - int err; - - ref_msg.allbits = msg; - /* wait response from mu */ - err = wait_for_completion_timeout(&hifi4_priv->cmd_complete, - msecs_to_jiffies(1000)); - if (!err) { - dev_err(dev, "icm ack timeout! %x\n", msg); - return -ETIMEDOUT; - } - - dev_dbg(dev, "Ack recd for message 0x%08x\n", ref_msg.allbits); - - return 0; -} - -int process_act_complete(struct fsl_hifi4 *hifi4_priv, u32 msg) -{ - union icm_header_t recd_msg; - u32 ext_msg_addr; - u32 ext_msg_size = 0; - u32 *pmsg_apu = (u32 *) hifi4_priv->msg_buf_virt + 2048/4; - struct icm_cdc_iobuf_t *codec_iobuf_info = - &hifi4_priv->codec_iobuf_info; - struct icm_pcm_prop_t *pcm_prop_info = &hifi4_priv->pcm_prop_info; - struct icm_pilib_size_t *pilib_buffer_info = - &hifi4_priv->pilib_buffer_info; - int ret_val = 0; - - recd_msg.allbits = msg; - - if (recd_msg.size == 8) { - MU_ReceiveMsg(hifi4_priv->mu_base_virtaddr, 1, &ext_msg_addr); - MU_ReceiveMsg(hifi4_priv->mu_base_virtaddr, 2, &ext_msg_size); - } - - switch (recd_msg.sub_msg) { - case ICM_PI_LIB_MEM_ALLOC: - { - struct icm_pilib_size_t *pext_msg = - (struct icm_pilib_size_t *)pmsg_apu; - pilib_buffer_info->buffer_addr = pext_msg->buffer_addr; - pilib_buffer_info->buffer_size = pext_msg->buffer_size; - hifi4_priv->ret_status = pext_msg->ret; - hifi4_priv->is_done = 1; - complete(&hifi4_priv->cmd_complete); - } - break; - - case ICM_PI_LIB_MEM_FREE: - { - struct icm_pilib_size_t *pext_msg = - (struct icm_pilib_size_t *)pmsg_apu; - hifi4_priv->ret_status = pext_msg->ret; - hifi4_priv->is_done = 1; - complete(&hifi4_priv->cmd_complete); - } - break; - - case ICM_OPEN: - { - struct icm_base_info_t *ext_msg = - (struct icm_base_info_t *)pmsg_apu; - hifi4_priv->ret_status = ext_msg->ret; - hifi4_priv->is_done = 1; - complete(&hifi4_priv->cmd_complete); - } - break; - - case ICM_EMPTY_THIS_BUFFER: - { - struct icm_cdc_iobuf_t *ext_msg = - (struct icm_cdc_iobuf_t *)pmsg_apu; - codec_iobuf_info->inp_cur_offset = - ext_msg->inp_cur_offset; - codec_iobuf_info->out_cur_offset = - ext_msg->out_cur_offset; - hifi4_priv->ret_status = ext_msg->base_info.ret; - hifi4_priv->is_done = 1; - complete(&hifi4_priv->cmd_complete); - } - break; - - case ICM_GET_PCM_PROP: - { - struct icm_pcm_prop_t *ext_msg = - (struct icm_pcm_prop_t *)pmsg_apu; - pcm_prop_info->pcmbytes = ext_msg->pcmbytes; - pcm_prop_info->sfreq = ext_msg->sfreq; - pcm_prop_info->channels = ext_msg->channels; - pcm_prop_info->bits = ext_msg->bits; - pcm_prop_info->consumed_bytes = - ext_msg->consumed_bytes; - hifi4_priv->ret_status = ext_msg->base_info.ret; - - hifi4_priv->is_done = 1; - complete(&hifi4_priv->cmd_complete); - } - break; - - case ICM_SET_PARA_CONFIG: - { - struct icm_prop_config *ext_msg = - (struct icm_prop_config *)pmsg_apu; - hifi4_priv->ret_status = ext_msg->base_info.ret; - hifi4_priv->is_done = 1; - complete(&hifi4_priv->cmd_complete); - } - break; - - case ICM_PI_LIB_INIT: - { - struct icm_base_info_t *ext_msg = - (struct icm_base_info_t *)pmsg_apu; - hifi4_priv->ret_status = ext_msg->ret; - hifi4_priv->is_done = 1; - complete(&hifi4_priv->cmd_complete); - } - break; - - case ICM_CLOSE: - { - struct icm_base_info_t *ext_msg = - (struct icm_base_info_t *)pmsg_apu; - hifi4_priv->ret_status = ext_msg->ret; - hifi4_priv->is_done = 1; - complete(&hifi4_priv->cmd_complete); - } - break; - - case ICM_PI_LIB_LOAD: - { - struct icm_base_info_t *ext_msg = - (struct icm_base_info_t *)pmsg_apu; - hifi4_priv->ret_status = ext_msg->ret; - hifi4_priv->is_done = 1; - complete(&hifi4_priv->cmd_complete); - } - break; - - case ICM_RESET: - { - struct icm_base_info_t *ext_msg = - (struct icm_base_info_t *)pmsg_apu; - hifi4_priv->ret_status = ext_msg->ret; - hifi4_priv->is_done = 1; - complete(&hifi4_priv->cmd_complete); - } - break; - case ICM_CORE_EXIT: - hifi4_priv->is_done = 1; - complete(&hifi4_priv->cmd_complete); - break; - case ICM_SUSPEND: - hifi4_priv->is_done = 1; - complete(&hifi4_priv->cmd_complete); - break; - case ICM_RESUME: - hifi4_priv->is_done = 1; - complete(&hifi4_priv->cmd_complete); - break; - default: - ret_val = -1; - break; - } - return ret_val; -} - -int send_dpu_ext_msg_addr(struct fsl_hifi4 *hifi4_priv) -{ - union icm_header_t apu_icm; - struct hifi4_ext_msg ext_msg; - struct hifi4_mem_msg *dpu_ext_msg = - (struct hifi4_mem_msg *)hifi4_priv->msg_buf_virt; - int ret_val = 0; - - apu_icm.allbits = 0; /* clear all bits; */ - apu_icm.ack = 0; - apu_icm.intr = 1; - apu_icm.msg = ICM_EXT_MSG_ADDR; - apu_icm.size = 8; - ext_msg.phys = hifi4_priv->msg_buf_phys; - /* 6 means element numbers that need to be transferred - * in struct hifi4_mem_msg - */ - ext_msg.size = 6*4; /* 6 * sizeof(int) */ - dpu_ext_msg->ext_msg_phys = hifi4_priv->msg_buf_phys + 2048; - dpu_ext_msg->ext_msg_size = 2048; - dpu_ext_msg->scratch_phys = hifi4_priv->scratch_buf_phys; - dpu_ext_msg->scratch_size = hifi4_priv->scratch_buf_size; - dpu_ext_msg->hifi_config_phys = hifi4_priv->hifi_config_phys; - dpu_ext_msg->hifi_config_size = hifi4_priv->hifi_config_size; - - icm_intr_extended_send(hifi4_priv, apu_icm.allbits, &ext_msg); - - return ret_val; -} - -static irqreturn_t fsl_hifi4_mu_isr(int irq, void *dev_id) -{ - struct fsl_hifi4 *hifi4_priv = dev_id; - struct device *dev = hifi4_priv->dev; - union icm_header_t recd_msg; - int ret_val; - u32 reg; - - MU_ReceiveMsg(hifi4_priv->mu_base_virtaddr, 0, ®); - recd_msg = (union icm_header_t)reg; - if (recd_msg.intr == 1) { - dev_dbg(dev, "INTR: Received ICM intr, msg 0x%08x\n", - recd_msg.allbits); - switch (recd_msg.msg) { - case ICM_CORE_EXIT: - break; - case ICM_CORE_READY: - send_dpu_ext_msg_addr(hifi4_priv); - hifi4_priv->is_ready = 1; - complete(&hifi4_priv->cmd_complete); - break; - case ICM_EXT_MSG_ADDR: - break; - - case ICM_EMPTY_THIS_BUFFER: - case ICM_CLOSE: - break; - - case ICM_DPU_ACTION_COMPLETE: - ret_val = process_act_complete(hifi4_priv, - recd_msg.allbits); - break; - - default: - break; - } - } else if (recd_msg.ack == 1) { - dev_dbg(dev, "INTR: Received ICM ack 0x%08x\n", recd_msg.size); - recd_msg.ack = 0; - } else { - dev_dbg(dev, "Received false ICM intr 0x%08x\n", - recd_msg.allbits); - } - - return IRQ_HANDLED; -} - static void hifi4_load_firmware(const struct firmware *fw, void *context) { struct fsl_hifi4 *hifi4_priv = context; @@ -2141,7 +718,7 @@ int hifi4_mu_init(struct fsl_hifi4 *hifi4_priv) irq = of_irq_get(np, 0); ret = devm_request_irq(hifi4_priv->dev, irq, fsl_hifi4_mu_isr, - IRQF_EARLY_RESUME, "hifi4_mu_isr", hifi4_priv); + IRQF_EARLY_RESUME, "hifi4_mu_isr", &hifi4_priv->proxy); if (ret) { dev_err(dev, "request_irq failed %d, err = %d\n", irq, ret); return -EINVAL; @@ -2160,9 +737,11 @@ static const struct file_operations hifi4_fops = { .owner = THIS_MODULE, .unlocked_ioctl = fsl_hifi4_ioctl, #ifdef CONFIG_COMPAT - .compat_ioctl = fsl_hifi4_compat_ioctl, + .compat_ioctl = fsl_hifi4_ioctl, #endif .open = fsl_hifi4_open, + .poll = fsl_hifi4_poll, + .mmap = fsl_hifi4_mmap, .release = fsl_hifi4_close, }; @@ -2267,34 +846,39 @@ static int fsl_hifi4_probe(struct platform_device *pdev) return -ENOMEM; } - /* msg buffer */ + /* msg ring buffer memory */ hifi4_priv->msg_buf_virt = buf_virt; hifi4_priv->msg_buf_phys = buf_phys; hifi4_priv->msg_buf_size = MSG_BUF_SIZE; offset = MSG_BUF_SIZE; + /* keep dsp framework's global data when suspend/resume */ hifi4_priv->hifi_config_virt = buf_virt + offset; hifi4_priv->hifi_config_phys = buf_phys + offset; hifi4_priv->hifi_config_size = HIFI_CONFIG_SIZE; + /* scratch memory for dsp framework */ hifi4_priv->scratch_buf_virt = hifi4_priv->sdram_vir_addr + SDRAM_CODEC_LIB_OFFSET; hifi4_priv->scratch_buf_phys = hifi4_priv->sdram_phys_addr + SDRAM_CODEC_LIB_OFFSET; hifi4_priv->scratch_buf_size = SDRAM_BASE_SIZE - SDRAM_CODEC_LIB_OFFSET; - /* initialize the resources of multi codec - * MULTI_CODEC_NUM is the max codec number that dsp - * driver and framework can support. - */ - for (i = 0; i < MULTI_CODEC_NUM; i++) - memset(&hifi4_priv->process_info[i], 0, - sizeof(struct icm_process_info)); - /* initialize the reference counter for hifi4_priv * structure */ atomic_long_set(&hifi4_priv->refcnt, 0); + + /* ...initialize client association map */ + for (i = 0; i < XF_CFG_MAX_IPC_CLIENTS - 1; i++) + hifi4_priv->xf_client_map[i].next = i + 1; + /* ...set list terminator */ + hifi4_priv->xf_client_map[i].next = 0; + + /* ...set pointer to shared memory */ + xf_proxy_init(&hifi4_priv->proxy); + + /* ...initialize mutex */ mutex_init(&hifi4_priv->hifi4_mutex); return 0; @@ -2320,6 +904,7 @@ static int fsl_hifi4_remove(struct platform_device *pdev) static int fsl_hifi4_runtime_resume(struct device *dev) { struct fsl_hifi4 *hifi4_priv = dev_get_drvdata(dev); + struct xf_proxy *proxy = &hifi4_priv->proxy; int ret; if (sc_pm_set_resource_power_mode(hifi4_priv->hifi_ipcHandle, @@ -2328,10 +913,8 @@ static int fsl_hifi4_runtime_resume(struct device *dev) return -EIO; } - mutex_lock(&hifi4_priv->hifi4_mutex); - - if (!hifi4_priv->is_ready) { - init_completion(&hifi4_priv->cmd_complete); + if (!proxy->is_ready) { + init_completion(&proxy->cmd_complete); ret = request_firmware_nowait(THIS_MODULE, FW_ACTION_HOTPLUG, hifi4_priv->fw_name, @@ -2340,33 +923,30 @@ static int fsl_hifi4_runtime_resume(struct device *dev) if (ret) { dev_err(dev, "failed to load firmware\n"); - mutex_unlock(&hifi4_priv->hifi4_mutex); return ret; } - ret = icm_ack_wait(hifi4_priv, 0); + ret = icm_ack_wait(proxy, 0); if (ret) { - mutex_unlock(&hifi4_priv->hifi4_mutex); return ret; } dev_info(dev, "hifi driver registered\n"); } - mutex_unlock(&hifi4_priv->hifi4_mutex); - return 0; } static int fsl_hifi4_runtime_suspend(struct device *dev) { struct fsl_hifi4 *hifi4_priv = dev_get_drvdata(dev); + struct xf_proxy *proxy = &hifi4_priv->proxy; if (sc_pm_set_resource_power_mode(hifi4_priv->hifi_ipcHandle, SC_R_DSP_RAM, SC_PM_PW_MODE_OFF) != SC_ERR_NONE) { dev_err(dev, "Error power off HIFI RAM\n"); return -EIO; } - hifi4_priv->is_ready = 0; + proxy->is_ready = 0; return 0; } #endif /* CONFIG_PM */ @@ -2375,33 +955,8 @@ static int fsl_hifi4_runtime_suspend(struct device *dev) #ifdef CONFIG_PM_SLEEP static int fsl_hifi4_suspend(struct device *dev) { - union icm_header_t apu_icm; - struct fsl_hifi4 *hifi4_priv = dev_get_drvdata(dev); int ret = 0; - mutex_lock(&hifi4_priv->hifi4_mutex); - - if (hifi4_priv->is_ready) { - init_completion(&hifi4_priv->cmd_complete); - hifi4_priv->is_done = 0; - - apu_icm.allbits = 0; /* clear all bits;*/ - apu_icm.ack = 0; - apu_icm.intr = 1; - apu_icm.msg = ICM_SUSPEND; - apu_icm.size = 0; - icm_intr_send(hifi4_priv, apu_icm.allbits); - - /* wait for response here */ - ret = icm_ack_wait(hifi4_priv, apu_icm.allbits); - if (ret) { - mutex_unlock(&hifi4_priv->hifi4_mutex); - return ret; - } - } - - mutex_unlock(&hifi4_priv->hifi4_mutex); - ret = pm_runtime_force_suspend(dev); return ret; @@ -2409,36 +964,12 @@ static int fsl_hifi4_suspend(struct device *dev) static int fsl_hifi4_resume(struct device *dev) { - union icm_header_t apu_icm; - struct fsl_hifi4 *hifi4_priv = dev_get_drvdata(dev); int ret = 0; ret = pm_runtime_force_resume(dev); if (ret) return ret; - mutex_lock(&hifi4_priv->hifi4_mutex); - - if (hifi4_priv->is_ready) { - init_completion(&hifi4_priv->cmd_complete); - hifi4_priv->is_done = 0; - - apu_icm.allbits = 0; /* clear all bits;*/ - apu_icm.ack = 0; - apu_icm.intr = 1; - apu_icm.msg = ICM_RESUME; - apu_icm.size = 0; - icm_intr_send(hifi4_priv, apu_icm.allbits); - - /* wait for response here */ - ret = icm_ack_wait(hifi4_priv, apu_icm.allbits); - if (ret) { - mutex_unlock(&hifi4_priv->hifi4_mutex); - return ret; - } - } - mutex_unlock(&hifi4_priv->hifi4_mutex); - return 0; } #endif /* CONFIG_PM_SLEEP */ diff --git a/sound/soc/fsl/fsl_hifi4.h b/sound/soc/fsl/fsl_hifi4.h index 43b98592e1c0..61592d1657d8 100644 --- a/sound/soc/fsl/fsl_hifi4.h +++ b/sound/soc/fsl/fsl_hifi4.h @@ -9,197 +9,46 @@ */ #include <uapi/linux/mxc_hifi4.h> +#include "fsl_hifi4_proxy.h" -#define Elf32_Byte unsigned char -#define xt_ptr unsigned long -#define xt_int int -#define xt_uint unsigned int -#define xt_ulong unsigned long - typedef void (*memcpy_func) (void *dest, const void *src, size_t n); typedef void (*memset_func) (void *s, int c, size_t n); -struct xtlib_packaged_library; - -#define MULTI_CODEC_NUM 5 -#define MAX_MEM_ALLOCS 50 - -enum { - XTLIB_NO_ERR = 0, - XTLIB_NOT_ELF = 1, - XTLIB_NOT_DYNAMIC = 2, - XTLIB_NOT_STATIC = 3, - XTLIB_NO_DYNAMIC_SEGMENT = 4, - XTLIB_UNKNOWN_SYMBOL = 5, - XTLIB_NOT_ALIGNED = 6, - XTLIB_NOT_SPLITLOAD = 7, - XTLIB_RELOCATION_ERR = 8 -}; - -struct xtlib_loader_globals { - int err; - int byteswap; -}; - -struct icm_base_info_t { - u32 process_id; /* process id of current task */ - u32 codec_id; /* codec id */ - s32 ret; /* executed status of function */ -}; - -struct icm_cdc_iobuf_t { - struct icm_base_info_t base_info; - - u32 inp_addr_sysram; /* init by APU */ - u32 inp_buf_size_max; /* init by APU */ - u32 inp_cur_offset; /* init by APU, updated by DPU */ - u32 out_addr_sysram; /* init by APU */ - u32 out_buf_size_max; /* init by APU */ - u32 out_cur_offset; /* init by APU, updated by DPU */ - u32 input_over; /* indicate external stream is over*/ -}; - -struct icm_prop_config { - struct icm_base_info_t base_info; - u32 cmd; /*set parameter command value*/ - u32 val; /*set parameter value*/ -}; - -struct icm_pcm_prop_t { - struct icm_base_info_t base_info; - - u32 pcmbytes; /* total bytes in the wav file */ - u32 sfreq; /* sample rate */ - u32 channels; /* output channels */ - u32 bits; /* bits per sample */ - u32 consumed_bytes; - u32 cycles; -}; - -struct xtlib_overlay_info { - u32 start_addr; - u32 codec_type; -}; - -struct xtlib_pil_info { - xt_uint dst_addr; - xt_uint src_offs; - xt_uint dst_data_addr; - xt_uint src_data_offs; - xt_uint start_sym; - xt_uint text_addr; - xt_uint init; - xt_uint fini; - xt_uint rel; - xt_int rela_count; - xt_uint hash; - xt_uint symtab; - xt_uint strtab; - xt_int align; -}; - -struct icm_xtlib_pil_info { - struct xtlib_pil_info pil_info; - u32 process_id; - u32 lib_type; -}; - -union icm_header_t { - struct { - u32 msg:6; - u32 sub_msg:6; /* sub_msg will have ICM_MSG when - * msg=ICM_XXX_ACTION_COMPLETE - */ - u32 rsvd:3; /* reserved */ - u32 intr:1; /* intr = 1 when sending msg. */ - u32 size:15; /* =size in bytes (excluding header) - * to follow when intr=1, - * =response message when ack=1 - */ - u32 ack:1; - }; - u32 allbits; -} icm_header_t; - -enum icm_action_t { - ICM_CORE_READY = 1, - ICM_PI_LIB_MEM_ALLOC, - ICM_PI_LIB_MEM_FREE, - ICM_PI_LIB_INIT, - ICM_PI_LIB_LOAD, - ICM_PI_LIB_UNLOAD, +/* ...maximal number of IPC clients per proxy */ +#define XF_CFG_MAX_IPC_CLIENTS (1 << 4) - ICM_DPU_ACTION_COMPLETE, - ICM_APU_ACTION_COMPLETE, - ICM_OPEN, - ICM_EMPTY_THIS_BUFFER, - ICM_FILL_THIS_BUFFER, - ICM_PAUSE, - ICM_CLOSE, +/* ...proxy client data */ +struct xf_client { + /* ...pointer to proxy interface */ + struct xf_proxy *proxy; - ICM_GET_PCM_PROP, - ICM_SET_PARA_CONFIG, + /* ...allocated proxy client id */ + u32 id; - ICM_CORE_EXIT, - ICM_EXT_MSG_ADDR, + /* ...pending response queue */ + struct xf_msg_queue queue; - ICM_RESET, - ICM_SUSPEND, - ICM_RESUME, -}; + /* ...response waiting queue */ + wait_queue_head_t wait; -enum aud_status_t { - AUD_IDLE = 0, - AUD_STOPPED, - AUD_DECODING, - AUD_PAUSED -}; + /* ...virtual memory mapping */ + unsigned long vm_start; -struct lib_dnld_info_t { - unsigned long pbuf_code; - unsigned long pbuf_data; - unsigned int size_code; - unsigned int size_data; - struct xtlib_pil_info *ppil_inf; - unsigned int lib_on_dpu; /* 0: not loaded, 1: loaded. */ -}; + /* ...counter of memory mappings (no real use of it yet - tbd) */ + atomic_t vm_use; -struct icm_pilib_size_t { - u32 buffer_addr; - u32 buffer_size; - s32 ret; + /* ...global structure pointer */ + void *global; }; -struct icm_process_info { - unsigned int process_id; - unsigned int codec_id; - - struct xtlib_pil_info pil_info; - struct xtlib_loader_globals xtlib_globals; - - void *in_buf_virt; - dma_addr_t in_buf_phys; - int in_buf_size; - void *out_buf_virt; - dma_addr_t out_buf_phys; - int out_buf_size; - - void *code_buf_virt; - dma_addr_t code_buf_phys; - int code_buf_size; - void *data_buf_virt; - dma_addr_t data_buf_phys; - int data_buf_size; - - dma_addr_t array_alloc_mem[MAX_MEM_ALLOCS]; - int alloc_count; - - struct filename *objfile; - char objtype; +union xf_client_link { + /* ...index of next client in free list */ + u32 next; - unsigned int used; + /* ...reference to proxy data for allocated client */ + struct xf_client *client; }; struct fsl_hifi4 { @@ -228,36 +77,14 @@ struct fsl_hifi4 { dma_addr_t hifi_config_phys; int hifi_config_size; - int is_ready; - int is_done; - int ret_status; + /* ...proxy data structures */ + struct xf_proxy proxy; - struct icm_cdc_iobuf_t codec_iobuf_info; - struct icm_pcm_prop_t pcm_prop_info; - struct icm_pilib_size_t pilib_buffer_info; - - struct completion cmd_complete; + /* ...mutex lock */ struct mutex hifi4_mutex; - struct icm_process_info process_info[MULTI_CODEC_NUM]; -}; - -struct fsl_hifi4_engine { - struct fsl_hifi4 *hifi4_priv; -}; - -struct hifi4_ext_msg { - u32 phys; - u32 size; -}; - -struct hifi4_mem_msg { - u32 ext_msg_phys; - u32 ext_msg_size; - u32 scratch_phys; - u32 scratch_size; - u32 hifi_config_phys; - u32 hifi_config_size; + /* ...global clients pool (item[0] serves as list terminator) */ + union xf_client_link xf_client_map[XF_CFG_MAX_IPC_CLIENTS]; }; #define IRAM_OFFSET 0x10000 @@ -275,7 +102,7 @@ struct hifi4_mem_msg { #define SYSROM_OFFSET 0x58000 #define SYSROM_SIZE 0x30000 -#define MSG_BUF_SIZE 4096 +#define MSG_BUF_SIZE 8192 #define INPUT_BUF_SIZE 4096 #define OUTPUT_BUF_SIZE 16384 #define HIFI_CONFIG_SIZE 4096 @@ -299,33 +126,13 @@ struct hifi4_mem_msg { #define SDRAM_BASE_ADDR 0x8e000000 #define SDRAM_BASE_SIZE 0x1ffffff #define SDRAM_CODEC_LIB_OFFSET 0x1000000 +#define SDRAM_SCRATCH_BUF_SIZE 0xffffff #define SC_C_OFS_SEL 39 #define SC_C_OFS_AUDIO 40 #define SC_C_OFS_PERIPH 41 #define SC_C_OFS_IRQ 42 -static void hifi4_load_firmware(const struct firmware *fw, void *context); -u32 icm_intr_send(struct fsl_hifi4 *hifi4_priv, u32 msg); -u32 icm_intr_extended_send(struct fsl_hifi4 *hifi4_priv, u32 msg, - struct hifi4_ext_msg *ext_msg); -int send_dpu_ext_msg_addr(struct fsl_hifi4 *hifi4_priv); -long icm_ack_wait(struct fsl_hifi4 *hifi4_priv, u32 msg); - -unsigned int xtlib_split_pi_library_size( - struct xtlib_packaged_library *library, - unsigned int *code_size, - unsigned int *data_size, - struct icm_process_info *process_info); - -xt_ptr xtlib_host_load_split_pi_library( - struct xtlib_packaged_library *library, - xt_ptr destination_code_address, - xt_ptr destination_data_address, - struct xtlib_pil_info *lib_info, - memcpy_func mcpy_fn, - memset_func mset_fn, - struct icm_process_info *process_info); - void *memcpy_hifi(void *dest, const void *src, size_t count); void *memset_hifi(void *dest, int c, size_t count); +struct xf_client *xf_client_lookup(struct fsl_hifi4 *hifi4_priv, u32 id); diff --git a/sound/soc/fsl/fsl_hifi4_proxy.c b/sound/soc/fsl/fsl_hifi4_proxy.c new file mode 100644 index 000000000000..931faec8c7fc --- /dev/null +++ b/sound/soc/fsl/fsl_hifi4_proxy.c @@ -0,0 +1,641 @@ +/******************************************************************************* + * + * This file is licensed under the terms of the GNU General Public License + * version 2. This program is licensed "as is" without any warranty of any + * kind, whether express or implied. + * + * Copyright (C) 2017 Cadence Design Systems, Inc. + * Copyright 2018 NXP + * + ******************************************************************************/ +/******************************************************************************* + * fsl_hifi4_proxy.c + * + * DSP proxy driver + * + * DSP proxy driver is used to transfer messages between dsp driver + * and dsp framework + ******************************************************************************/ + +#include <soc/imx8/sc/ipc.h> +#include "fsl_hifi4_proxy.h" +#include "fsl_hifi4.h" + + +/* ...initialize message queue */ +void xf_msg_queue_init(struct xf_msg_queue *queue) +{ + queue->head = queue->tail = NULL; +} + +/* ...get message queue head */ +struct xf_message *xf_msg_queue_head(struct xf_msg_queue *queue) +{ + return queue->head; +} + +/* ...allocate new message from the pool */ +struct xf_message *xf_msg_alloc(struct xf_proxy *proxy) +{ + struct xf_message *m = proxy->free; + + /* ...make sure we have a free message item */ + if (m != NULL) { + /* ...get message from the pool */ + proxy->free = m->next, m->next = NULL; + } + + return m; +} + +/* ...return message to the pool of free items */ +void xf_msg_free(struct xf_proxy *proxy, struct xf_message *m) +{ + /* ...put message into the head of free items list */ + m->next = proxy->free, proxy->free = m; + + /* ...notify potential client waiting for message */ + wake_up(&proxy->busy); +} + +/* ...return all messages from the queue to the pool of free items */ +void xf_msg_free_all(struct xf_proxy *proxy, struct xf_msg_queue *queue) +{ + struct xf_message *m = queue->head; + + /* ...check if there is anything in the queue */ + if (m != NULL) { + queue->tail->next = proxy->free; + proxy->free = queue->head; + queue->head = queue->tail = NULL; + + /* ...notify potential client waiting for message */ + wake_up(&proxy->busy); + } +} + +/* ...submit message to a queue */ +int xf_msg_enqueue(struct xf_msg_queue *queue, struct xf_message *m) +{ + int first = (queue->head == NULL); + + /* ...set pointer to next item */ + m->next = NULL; + + /* ...advance head/tail pointer as required */ + if (first) + queue->head = m; + else + queue->tail->next = m; + + /* ...new tail points to this message */ + queue->tail = m; + + return first; +} + +/* ...retrieve next message from the per-task queue */ +struct xf_message *xf_msg_dequeue(struct xf_msg_queue *queue) +{ + struct xf_message *m = queue->head; + + /* ...check if there is anything in the queue */ + if (m != NULL) { + /* ...pop message from the head of the list */ + queue->head = m->next; + if (queue->head == NULL) + queue->tail = NULL; + } + + return m; +} + +/* ...helper function for requesting execution message from a pool */ +struct xf_message *xf_msg_available(struct xf_proxy *proxy) +{ + struct xf_message *m; + + /* ...acquire global lock */ + xf_lock(&proxy->lock); + + /* ...try to allocate the message */ + m = xf_msg_alloc(proxy); + if (m == NULL) { + /* ...failed to allocate message; release lock */ + xf_unlock(&proxy->lock); + } + + /* ...if successfully allocated */ + return m; +} + +/* ...helper function for receiving a message from per-client queue */ +struct xf_message *xf_msg_received(struct xf_proxy *proxy, + struct xf_msg_queue *queue) +{ + struct xf_message *m; + + /* ...try to peek message from the queue */ + m = xf_msg_dequeue(queue); + + /* ...if message is non-null, lock is held */ + return m; +} + +/* + * MU related functions + */ +u32 icm_intr_send(struct xf_proxy *proxy, u32 msg) +{ + struct fsl_hifi4 *hifi4_priv = container_of(proxy, + struct fsl_hifi4, proxy); + + MU_SendMessage(hifi4_priv->mu_base_virtaddr, 0, msg); + return 0; +} + +int icm_intr_extended_send(struct xf_proxy *proxy, + u32 msg, + struct hifi4_ext_msg *ext_msg) +{ + struct fsl_hifi4 *hifi4_priv = container_of(proxy, + struct fsl_hifi4, proxy); + struct device *dev = hifi4_priv->dev; + union icm_header_t msghdr; + + msghdr.allbits = msg; + if (msghdr.size != 8) + dev_err(dev, "too much ext msg\n"); + + MU_SendMessage(hifi4_priv->mu_base_virtaddr, 1, ext_msg->phys); + MU_SendMessage(hifi4_priv->mu_base_virtaddr, 2, ext_msg->size); + MU_SendMessage(hifi4_priv->mu_base_virtaddr, 0, msg); + + return 0; +} + +int send_dpu_ext_msg_addr(struct xf_proxy *proxy) +{ + struct fsl_hifi4 *hifi4_priv = container_of(proxy, + struct fsl_hifi4, proxy); + union icm_header_t msghdr; + struct hifi4_ext_msg ext_msg; + struct hifi4_mem_msg *dpu_ext_msg = + (struct hifi4_mem_msg *)((unsigned char *)hifi4_priv->msg_buf_virt + + (MSG_BUF_SIZE / 2)); + int ret_val = 0; + + msghdr.allbits = 0; /* clear all bits; */ + msghdr.ack = 0; + msghdr.intr = 1; + msghdr.msg = ICM_CORE_INIT; + msghdr.size = 8; + ext_msg.phys = hifi4_priv->msg_buf_phys + (MSG_BUF_SIZE / 2); + ext_msg.size = sizeof(struct hifi4_mem_msg); + + dpu_ext_msg->ext_msg_phys = hifi4_priv->msg_buf_phys; + dpu_ext_msg->ext_msg_size = MSG_BUF_SIZE; + dpu_ext_msg->scratch_phys = hifi4_priv->scratch_buf_phys; + dpu_ext_msg->scratch_size = hifi4_priv->scratch_buf_size; + dpu_ext_msg->hifi_config_phys = hifi4_priv->hifi_config_phys; + dpu_ext_msg->hifi_config_size = hifi4_priv->hifi_config_size; + + icm_intr_extended_send(proxy, msghdr.allbits, &ext_msg); + + return ret_val; +} + +long icm_ack_wait(struct xf_proxy *proxy, u32 msg) +{ + struct fsl_hifi4 *hifi4_priv = container_of(proxy, + struct fsl_hifi4, proxy); + struct device *dev = hifi4_priv->dev; + union icm_header_t msghdr; + int err; + + msghdr.allbits = msg; + /* wait response from mu */ + err = wait_for_completion_timeout(&proxy->cmd_complete, + msecs_to_jiffies(1000)); + if (!err) { + dev_err(dev, "icm ack timeout! %x\n", msg); + return -ETIMEDOUT; + } + + dev_dbg(dev, "Ack recd for message 0x%08x\n", msghdr.allbits); + + return 0; +} + +irqreturn_t fsl_hifi4_mu_isr(int irq, void *dev_id) +{ + struct xf_proxy *proxy = dev_id; + struct fsl_hifi4 *hifi4_priv = container_of(proxy, + struct fsl_hifi4, proxy); + struct device *dev = hifi4_priv->dev; + union icm_header_t msghdr; + u32 reg; + + MU_ReceiveMsg(hifi4_priv->mu_base_virtaddr, 0, ®); + msghdr = (union icm_header_t)reg; + + if (msghdr.intr == 1) { + dev_dbg(dev, "INTR: Received ICM intr, msg 0x%08x\n", + msghdr.allbits); + switch (msghdr.msg) { + case ICM_CORE_EXIT: + break; + case ICM_CORE_READY: + send_dpu_ext_msg_addr(proxy); + proxy->is_ready = 1; + complete(&proxy->cmd_complete); + break; + default: + schedule_work(&proxy->work); + break; + } + } else if (msghdr.ack == 1) { + dev_dbg(dev, "INTR: Received ICM ack 0x%08x\n", msghdr.size); + msghdr.ack = 0; + } else { + dev_dbg(dev, "Received false ICM intr 0x%08x\n", + msghdr.allbits); + } + + return IRQ_HANDLED; +} + +/* + * Proxy related functions + */ +/* ...NULL-address specification */ +#define XF_PROXY_NULL (~0U) + +#define XF_PROXY_BADADDR SDRAM_SCRATCH_BUF_SIZE + +/* ...shared memory translation - kernel virtual address to shared address */ +u32 xf_proxy_b2a(struct xf_proxy *proxy, void *b) +{ + struct fsl_hifi4 *hifi4_priv = container_of(proxy, + struct fsl_hifi4, proxy); + + if (b == NULL) + return XF_PROXY_NULL; + else if ((u32)(b - hifi4_priv->scratch_buf_virt) < + SDRAM_SCRATCH_BUF_SIZE) + return (u32)(b - hifi4_priv->scratch_buf_virt); + else + return XF_PROXY_BADADDR; +} + +/* ...shared memory translation - shared address to kernel virtual address */ +void *xf_proxy_a2b(struct xf_proxy *proxy, u32 address) +{ + struct fsl_hifi4 *hifi4_priv = container_of(proxy, + struct fsl_hifi4, proxy); + + if (address < SDRAM_SCRATCH_BUF_SIZE) + return hifi4_priv->scratch_buf_virt + address; + else if (address == XF_PROXY_NULL) + return NULL; + else + return (void *) -1; +} + +/* ...process association between response received and intended client */ +static void xf_cmap(struct xf_proxy *proxy, struct xf_message *m) +{ + struct fsl_hifi4 *hifi4_priv = container_of(proxy, + struct fsl_hifi4, proxy); + u32 id = XF_AP_IPC_CLIENT(m->id); + struct xf_client *client; + + /* ...process messages addressed to proxy itself */ + if (id == 0) { + /* ...place message into local response queue */ + xf_msg_enqueue(&proxy->response, m); + wake_up(&proxy->wait); + return; + } + + /* ...make sure the client ID is sane */ + client = xf_client_lookup(hifi4_priv, id); + if (!client) { + pr_err("rsp[id:%08x]: client lookup failed", m->id); + xf_msg_free(proxy, m); + return; + } + + /* ...make sure client is bound to this proxy interface */ + if (client->proxy != proxy) { + pr_err("rsp[id:%08x]: wrong proxy interface", m->id); + xf_msg_free(proxy, m); + return; + } + + /* ...place message into local response queue */ + if (xf_msg_enqueue(&client->queue, m)) + wake_up(&client->wait); +} + +/* ...retrieve pending responses from shared memory ring-buffer */ +static u32 xf_shmem_process_responses(struct xf_proxy *proxy) +{ + struct xf_message *m; + u32 read_idx, write_idx; + int status; + + status = 0; + + /* ...get current values of read/write pointers in response queue */ + read_idx = XF_PROXY_READ(proxy, rsp_read_idx); + write_idx = XF_PROXY_READ(proxy, rsp_write_idx); + + /* ...process all committed responses */ + while (!XF_QUEUE_EMPTY(read_idx, write_idx)) { + struct xf_proxy_message *response; + + /* ...allocate execution message */ + m = xf_msg_alloc(proxy); + if (m == NULL) + break; + + /* ...mark the interface status has changed */ + status |= (XF_QUEUE_FULL(read_idx, write_idx) ? 0x3 : 0x1); + + /* ...get oldest not yet processed response */ + response = XF_PROXY_RESPONSE(proxy, XF_QUEUE_IDX(read_idx)); + + /* ...fill message parameters */ + m->id = response->session_id; + m->opcode = response->opcode; + m->length = response->length; + m->buffer = xf_proxy_a2b(proxy, response->address); + + /* ...advance local reading index copy */ + read_idx = XF_QUEUE_ADVANCE_IDX(read_idx); + + /* ...update shadow copy of reading index */ + XF_PROXY_WRITE(proxy, rsp_read_idx, read_idx); + + /* ...submit message to proper client */ + xf_cmap(proxy, m); + } + + return status; +} + +/* ...put pending commands into shared memory ring-buffer */ +static u32 xf_shmem_process_commands(struct xf_proxy *proxy) +{ + struct xf_message *m; + u32 read_idx, write_idx; + int status = 0; + + /* ...get current value of peer read pointer */ + write_idx = XF_PROXY_READ(proxy, cmd_write_idx); + read_idx = XF_PROXY_READ(proxy, cmd_read_idx); + + /* ...submit any pending commands */ + while (!XF_QUEUE_FULL(read_idx, write_idx)) { + struct xf_proxy_message *command; + + /* ...check if we have a pending command */ + m = xf_msg_dequeue(&proxy->command); + if (m == NULL) + break; + + /* ...always mark the interface status has changed */ + status |= 0x3; + + /* ...select the place for the command */ + command = XF_PROXY_COMMAND(proxy, XF_QUEUE_IDX(write_idx)); + + /* ...put the response message fields */ + command->session_id = m->id; + command->opcode = m->opcode; + command->length = m->length; + command->address = xf_proxy_b2a(proxy, m->buffer); + + /* ...return message back to the pool */ + xf_msg_free(proxy, m); + + /* ...advance local writing index copy */ + write_idx = XF_QUEUE_ADVANCE_IDX(write_idx); + + /* ...update shared copy of queue write pointer */ + XF_PROXY_WRITE(proxy, cmd_write_idx, write_idx); + } + + return status; +} + +/* ...shared memory interface maintenance routine */ +void xf_proxy_process(struct work_struct *w) +{ + struct xf_proxy *proxy = container_of(w, struct xf_proxy, work); + int status = 0; + + /* ...get exclusive access to internal data */ + xf_lock(&proxy->lock); + + do { + /* ...process outgoing commands first */ + status = xf_shmem_process_commands(proxy); + + /* ...process all pending responses */ + status |= xf_shmem_process_responses(proxy); + + } while (status); + + /* ...unlock internal proxy data */ + xf_unlock(&proxy->lock); +} + +/* ...initialize shared memory interface */ +int xf_proxy_init(struct xf_proxy *proxy) +{ + struct fsl_hifi4 *hifi4_priv = container_of(proxy, + struct fsl_hifi4, proxy); + struct xf_message *m; + int i; + + /* ...create a list of all messages in a pool; set head pointer */ + proxy->free = &proxy->pool[0]; + + /* ...put all messages into a single-linked list */ + for (i = 0, m = proxy->free; i < XF_CFG_MESSAGE_POOL_SIZE - 1; i++, m++) + m->next = m + 1; + + /* ...set list tail pointer */ + m->next = NULL; + + /* ...initialize proxy lock */ + xf_lock_init(&proxy->lock); + + /* ...initialize proxy thread message queues */ + xf_msg_queue_init(&proxy->command); + xf_msg_queue_init(&proxy->response); + + /* ...initialize global busy queue */ + init_waitqueue_head(&proxy->busy); + init_waitqueue_head(&proxy->wait); + + /* ...create work structure */ + INIT_WORK(&proxy->work, xf_proxy_process); + + /* ...set pointer to shared memory */ + proxy->ipc.shmem = (struct xf_shmem_data *)hifi4_priv->msg_buf_virt; + + /* ...initialize shared memory interface */ + XF_PROXY_WRITE(proxy, cmd_read_idx, 0); + XF_PROXY_WRITE(proxy, cmd_write_idx, 0); + XF_PROXY_WRITE(proxy, rsp_read_idx, 0); + XF_PROXY_WRITE(proxy, rsp_write_idx, 0); + + return 0; +} + +/* ...trigger shared memory interface processing */ +void xf_proxy_notify(struct xf_proxy *proxy) +{ + schedule_work(&proxy->work); +} + +/* ...submit a command to proxy pending queue (lock released upon return) */ +void xf_proxy_command(struct xf_proxy *proxy, struct xf_message *m) +{ + int first; + + /* ...submit message to proxy thread */ + first = xf_msg_enqueue(&proxy->command, m); + + /* ...release the lock */ + xf_unlock(&proxy->lock); + + /* ...notify thread about command reception */ + (first ? xf_proxy_notify(proxy), 1 : 0); +} + +/* + * Proxy cmd send and receive functions + */ +int xf_cmd_send(struct xf_proxy *proxy, + u32 id, + u32 opcode, + void *buffer, + u32 length) +{ + struct xf_message *m; + int ret; + + /* ...retrieve message handle (take the lock on success) */ + ret = wait_event_interruptible(proxy->busy, + (m = xf_msg_available(proxy)) != NULL); + if (ret) + return -EINTR; + + /* ...fill-in message parameters (lock is taken) */ + m->id = id; + m->opcode = opcode; + m->length = length; + m->buffer = buffer; + m->ret = 0; + + /* ...submit command to the proxy */ + xf_proxy_command(proxy, m); + + return 0; +} + +struct xf_message *xf_cmd_recv(struct xf_proxy *proxy, + wait_queue_head_t *wq, + struct xf_msg_queue *queue, + int wait) +{ + struct xf_message *m; + int ret; + + /* ...wait for message reception (take lock on success) */ + ret = wait_event_interruptible(*wq, + (m = xf_msg_received(proxy, queue)) != NULL || !wait); + if (ret) + return ERR_PTR(-EINTR); + + /* ...return message with a lock taken */ + return m; +} + +/* ...helper function for synchronous command execution */ +struct xf_message *xf_cmd_send_recv(struct xf_proxy *proxy, + u32 id, u32 opcode, + void *buffer, + u32 length) +{ + int ret; + + /* ...send command to remote proxy */ + ret = xf_cmd_send(proxy, id, opcode, buffer, length); + if (ret) + return ERR_PTR(ret); + + /* ...wait for message delivery */ + return xf_cmd_recv(proxy, &proxy->wait, &proxy->response, 1); +} + +/* + * Proxy allocate and free memory functions + */ +/* ...allocate memory buffer for kernel use */ +int xf_cmd_alloc(struct xf_proxy *proxy, void **buffer, u32 length) +{ + struct xf_message *m; + u32 id = 0; + int ret; + + /* ...send command to remote proxy */ + m = xf_cmd_send_recv(proxy, id, XF_ALLOC, NULL, length); + if (IS_ERR(m)) { + ret = PTR_ERR(m); + return ret; + } + + /* ...check if response is expected */ + if (m->opcode == XF_ALLOC && m->buffer != NULL) { + *buffer = m->buffer; + ret = 0; + } else { + ret = -ENOMEM; + } + + /* ...free message and release proxy lock */ + xf_msg_free(proxy, m); + + return ret; +} + +/* ...free memory buffer */ +int xf_cmd_free(struct xf_proxy *proxy, void *buffer, u32 length) +{ + struct xf_message *m; + u32 id = 0; + int ret; + + /* ...synchronously execute freeing command */ + m = xf_cmd_send_recv(proxy, id, XF_FREE, buffer, length); + if (IS_ERR(m)) { + ret = PTR_ERR(m); + return ret; + } + + /* ...check if response is expected */ + if (m->opcode == XF_FREE) + ret = 0; + else + ret = -EINVAL; + + /* ...free message and release proxy lock */ + xf_msg_free(proxy, m); + + return ret; +} diff --git a/sound/soc/fsl/fsl_hifi4_proxy.h b/sound/soc/fsl/fsl_hifi4_proxy.h new file mode 100644 index 000000000000..f89e974ab596 --- /dev/null +++ b/sound/soc/fsl/fsl_hifi4_proxy.h @@ -0,0 +1,381 @@ +/******************************************************************************* + * + * This file is licensed under the terms of the GNU General Public License + * version 2. This program is licensed "as is" without any warranty of any + * kind, whether express or implied. + * + * Copyright (c) 2017 Cadence Design Systems, Inc. + * Copyright 2018 NXP + * + ************************************************************/ +/************************************************************ + * fsl_hifi4_proxy.h + * + * Proxy commmand/response messages + ************************************************************/ + +#ifndef __FSL_HIFI4_PROXY_H +#define __FSL_HIFI4_PROXY_H + +#include <linux/wait.h> +#include <linux/device.h> +#include <linux/workqueue.h> +#include <linux/spinlock.h> +#include <linux/compiler.h> +#include <linux/dma-mapping.h> +#include <linux/platform_data/dma-imx.h> +#include <linux/mx8_mu.h> +#include <linux/interrupt.h> + +#define XF_CFG_MESSAGE_POOL_SIZE 256 + +/******************************************************************************* + * Local proxy data + ******************************************************************************/ + +/* ...execution message */ +struct xf_message { + /* ...pointer to next message in a list */ + struct xf_message *next; + + /* ...session-id */ + u32 id; + + /* ...operation code */ + u32 opcode; + + /* ...length of data buffer */ + u32 length; + + /* ...translated data pointer */ + void *buffer; + + /* ...return message status */ + u32 ret; +}; + +/* ...message queue */ +struct xf_msg_queue { + /* ...pointer to list head */ + struct xf_message *head; + + /* ...pointer to list tail */ + struct xf_message *tail; +}; + +struct xf_proxy_message { + /* ...session ID */ + u32 session_id; + + /* ...proxy API command/response code */ + u32 opcode; + + /* ...length of attached buffer */ + u32 length; + + /* ...physical address of message buffer */ + u32 address; + + /* ...return message status */ + u32 ret; +}; +/**********************************************************************/ + +enum icm_action_t { + ICM_CORE_READY = 1, + ICM_CORE_INIT, + ICM_CORE_EXIT, + ICM_SUSPEND, + ICM_RESUME, +}; + +/* ...adjust IPC client of message going from user-space */ +#define XF_MSG_AP_FROM_USER(id, client) (((id) & ~(0xF << 2)) | (client << 2)) + +/* ...wipe out IPC client from message going to user-space */ +#define XF_MSG_AP_TO_USER(id) ((id) & ~(0xF << 18)) + +/* ...message id contains source and destination ports specification */ +#define __XF_MSG_ID(src, dst) (((src) & 0xFFFF) | (((dst) & 0xFFFF) << 16)) +#define XF_MSG_SRC_CLIENT(id) (((id) >> 2) & 0x3F) +#define XF_MSG_DST_CLIENT(id) (((id) >> 18) & 0x3F) + +/* ...special treatment of AP-proxy destination field */ +#define XF_AP_IPC_CLIENT(id) (((id) >> 18) & 0xF) +#define __XF_AP_PROXY(core) ((core) | 0x8000) +#define __XF_DSP_PROXY(core) ((core) | 0x8000) + +/* ...opcode composition with command/response data tags */ +#define __XF_OPCODE(c, r, op) (((c) << 31) | ((r) << 30) | ((op) & 0x3F)) + +/* ...shared buffer allocation */ +#define XF_ALLOC __XF_OPCODE(0, 0, 4) + +/* ...shared buffer freeing */ +#define XF_FREE __XF_OPCODE(0, 0, 5) + +/* ...resume component operation */ +#define XF_RESUME __XF_OPCODE(0, 0, 14) + +/* ...resume component operation */ +#define XF_SUSPEND __XF_OPCODE(0, 0, 15) + + +/******************************************************************************* + * Ring buffer support + ******************************************************************************/ +/* ...cache-line size on DSP */ +#define XF_PROXY_ALIGNMENT 64 + +/* ...total length of shared memory queue (for commands and responses) */ +#define XF_PROXY_MESSAGE_QUEUE_LENGTH (1 << 6) + +/* ...index mask */ +#define XF_PROXY_MESSAGE_QUEUE_MASK 0x3F + +/* ...ring-buffer index */ +#define __XF_QUEUE_IDX(idx, counter) \ + (((idx) & XF_PROXY_MESSAGE_QUEUE_MASK) | ((counter) << 16)) + +/* ...retrieve ring-buffer index */ +#define XF_QUEUE_IDX(idx) \ + ((idx) & XF_PROXY_MESSAGE_QUEUE_MASK) + +/* ...increment ring-buffer index */ +#define XF_QUEUE_ADVANCE_IDX(idx) \ + (((idx) + 1) & (0xFFFF0000 | XF_PROXY_MESSAGE_QUEUE_MASK)) + +/* ...test if ring buffer is empty */ +#define XF_QUEUE_EMPTY(read, write) \ + ((read) == (write)) + +/* ...test if ring buffer is full */ +#define XF_QUEUE_FULL(read, write) \ + ((write) == (read) + (XF_PROXY_MESSAGE_QUEUE_LENGTH << 16)) + +/* ...basic cache operations */ +#define XF_PROXY_INVALIDATE(addr, len) { } + +#define XF_PROXY_FLUSH(addr, len) { } + +/* ...data managed by host CPU (remote) - in case of shunt it is a IPC layer */ +struct xf_proxy_host_data { + /* ...command queue */ + struct xf_proxy_message command[XF_PROXY_MESSAGE_QUEUE_LENGTH]; + + /* ...writing index into command queue */ + u32 cmd_write_idx; + + /* ...reading index for response queue */ + u32 rsp_read_idx; +}; + +/* ...data managed by DSP (local) */ +struct xf_proxy_dsp_data { + /* ...response queue */ + struct xf_proxy_message response[XF_PROXY_MESSAGE_QUEUE_LENGTH]; + + /* ...writing index into response queue */ + u32 rsp_write_idx; + + /* ...reading index for command queue */ + u32 cmd_read_idx; + +}; + +/* ...shared memory data */ +struct xf_shmem_data { + /* ...ingoing data (maintained by DSP (local side)) */ + struct xf_proxy_host_data local; + + /* ...outgoing data (maintained by host CPU (remote side)) */ + struct xf_proxy_dsp_data remote; + +}; + +/* ...shared memory data accessor */ +#define XF_SHMEM_DATA(proxy) \ + ((proxy)->ipc.shmem) + +/* ...atomic reading */ +#define __XF_PROXY_READ_ATOMIC(var) \ + ({ XF_PROXY_INVALIDATE(&(var), sizeof(var)); \ + *(u32 *)&(var); }) + +/* ...atomic writing */ +#define __XF_PROXY_WRITE_ATOMIC(var, value) \ + ({*(u32 *)&(var) = (value); \ + XF_PROXY_FLUSH(&(var), sizeof(var)); \ + (value); }) + +/* ...accessors */ +#define XF_PROXY_READ(proxy, field) \ + __XF_PROXY_READ_##field(XF_SHMEM_DATA(proxy)) + +#define XF_PROXY_WRITE(proxy, field, v) \ + __XF_PROXY_WRITE_##field(XF_SHMEM_DATA(proxy), (v)) + +/* ...individual fields reading */ +#define __XF_PROXY_READ_cmd_write_idx(shmem) \ + __XF_PROXY_READ_ATOMIC(shmem->local.cmd_write_idx) + +#define __XF_PROXY_READ_cmd_read_idx(shmem) \ + shmem->remote.cmd_read_idx + +#define __XF_PROXY_READ_rsp_write_idx(shmem) \ + __XF_PROXY_READ_ATOMIC(shmem->remote.rsp_write_idx) + +#define __XF_PROXY_READ_rsp_read_idx(shmem) \ + shmem->local.rsp_read_idx + +/* ...individual fields writings */ +#define __XF_PROXY_WRITE_cmd_write_idx(shmem, v) \ + __XF_PROXY_WRITE_ATOMIC(shmem->local.cmd_write_idx, v) + +#define __XF_PROXY_WRITE_cmd_read_idx(shmem, v) \ + __XF_PROXY_WRITE_ATOMIC(shmem->remote.cmd_read_idx, v) + +#define __XF_PROXY_WRITE_rsp_read_idx(shmem, v) \ + __XF_PROXY_WRITE_ATOMIC(shmem->local.rsp_read_idx, v) + +#define __XF_PROXY_WRITE_rsp_write_idx(shmem, v) \ + __XF_PROXY_WRITE_ATOMIC(shmem->remote.rsp_write_idx, v) + +/* ...command buffer accessor */ +#define XF_PROXY_COMMAND(proxy, idx) \ + (&XF_SHMEM_DATA(proxy)->local.command[(idx)]) + +/* ...response buffer accessor */ +#define XF_PROXY_RESPONSE(proxy, idx) \ + (&XF_SHMEM_DATA(proxy)->remote.response[(idx)]) + +/******************************************************************************* + * Local proxy data + ******************************************************************************/ + +struct xf_proxy_ipc_data { + /* ...shared memory data pointer */ + struct xf_shmem_data __iomem *shmem; + + /* ...core identifier */ + u32 core; + + /* ...IPC registers memory */ + void __iomem *regs; +}; + +/* ...proxy data */ +struct xf_proxy { + /* ...IPC layer data */ + struct xf_proxy_ipc_data ipc; + + /* ...shared memory status change processing item */ + struct work_struct work; + + struct completion cmd_complete; + int is_ready; + + /* ...internal lock */ + spinlock_t lock; + + /* ...busy queue (for clients waiting ON NOTIFIcation) */ + wait_queue_head_t busy; + + /* ...waiting queue for synchronous proxy operations */ + wait_queue_head_t wait; + + /* ...submitted commands queue */ + struct xf_msg_queue command; + + /* ...pending responses queue */ + struct xf_msg_queue response; + + /* ...global message pool */ + struct xf_message pool[XF_CFG_MESSAGE_POOL_SIZE]; + + /* ...pointer to first free message in the pool */ + struct xf_message *free; +}; + +union icm_header_t { + struct { + u32 msg:6; + u32 sub_msg:6; // sub_msg will have ICM_MSG + u32 rsvd:3; /* reserved */ + u32 intr:1; /* intr = 1 when sending msg. */ + u32 size:15; /* =size in bytes (excluding header) */ + u32 ack:1; /* response message when ack=1 */ + }; + u32 allbits; +}; + +struct hifi4_ext_msg { + u32 phys; + u32 size; +}; + +struct hifi4_mem_msg { + u32 ext_msg_phys; + u32 ext_msg_size; + u32 scratch_phys; + u32 scratch_size; + u32 hifi_config_phys; + u32 hifi_config_size; +}; + +static inline void xf_lock_init(spinlock_t *lock) +{ + spin_lock_init(lock); +} + +static inline void xf_lock(spinlock_t *lock) +{ + spin_lock(lock); +} + +static inline void xf_unlock(spinlock_t *lock) +{ + spin_unlock(lock); +} + +/* ...init proxy */ +int xf_proxy_init(struct xf_proxy *proxy); + +/* ...send message to proxy */ +int xf_cmd_send(struct xf_proxy *proxy, + u32 id, + u32 opcode, + void *buffer, + u32 length); + +/* ...get message from proxy */ +struct xf_message *xf_cmd_recv(struct xf_proxy *proxy, + wait_queue_head_t *wq, + struct xf_msg_queue *queue, + int wait); + +/* ...mu interrupt handle */ +irqreturn_t fsl_hifi4_mu_isr(int irq, void *dev_id); + +/* ...initialize client pending message queue */ +void xf_msg_queue_init(struct xf_msg_queue *queue); + +/* ...return current queue state */ +struct xf_message *xf_msg_queue_head(struct xf_msg_queue *queue); + +/* ...return the message back to a pool */ +void xf_msg_free(struct xf_proxy *proxy, struct xf_message *m); + +/* ...release all pending messages */ +void xf_msg_free_all(struct xf_proxy *proxy, struct xf_msg_queue *queue); + +/* ...wait mu interrupt */ +long icm_ack_wait(struct xf_proxy *proxy, u32 msg); + +/* ...shared memory translation - kernel virtual address to shared address */ +u32 xf_proxy_b2a(struct xf_proxy *proxy, void *b); + +/* ...shared memory translation - shared address to kernel virtual address */ +void *xf_proxy_a2b(struct xf_proxy *proxy, u32 address); + +#endif |