summaryrefslogtreecommitdiff
path: root/sound
diff options
context:
space:
mode:
authorWeiguang Kong <weiguang.kong@nxp.com>2018-04-04 11:56:10 +0800
committerDong Aisheng <aisheng.dong@nxp.com>2019-11-25 15:51:49 +0800
commit12d419bbb1c9f8b47b45073c881c61b99ee8b717 (patch)
tree56518402778f6c8363b4706b91912092aa058eb8 /sound
parentd69e9a1786d3e1787d68a2572f6a4d7e4e94e35d (diff)
MLK-17635-1: ASoC: fsl_dsp: change dsp driver to support new dsp framework
The architecture of dsp framework has been changed, the role of dsp driver is transferring messages between dsp framework and user space application, so change dsp driver to support this function. Signed-off-by: Weiguang Kong <weiguang.kong@nxp.com>
Diffstat (limited to 'sound')
-rw-r--r--sound/soc/fsl/Makefile2
-rw-r--r--sound/soc/fsl/fsl_hifi4.c2143
-rw-r--r--sound/soc/fsl/fsl_hifi4.h257
-rw-r--r--sound/soc/fsl/fsl_hifi4_proxy.c641
-rw-r--r--sound/soc/fsl/fsl_hifi4_proxy.h381
5 files changed, 1392 insertions, 2032 deletions
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, &reg);
- 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, &reg);
+ 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