summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/uapi/linux/mxc_hifi4.h67
-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
6 files changed, 1408 insertions, 2083 deletions
diff --git a/include/uapi/linux/mxc_hifi4.h b/include/uapi/linux/mxc_hifi4.h
index e22f7f5808e1..5078537f86fa 100644
--- a/include/uapi/linux/mxc_hifi4.h
+++ b/include/uapi/linux/mxc_hifi4.h
@@ -25,18 +25,12 @@
#ifndef __MXC_HIFI4_UAPI_H__
#define __MXC_HIFI4_UAPI_H__
-#define HIFI4_IOC_MAGIC 'H'
-#define HIFI4_LOAD_CODEC _IOWR(HIFI4_IOC_MAGIC, 0, unsigned int)
-#define HIFI4_INIT_CODEC _IOWR(HIFI4_IOC_MAGIC, 1, unsigned int)
-#define HIFI4_CODEC_OPEN _IOWR(HIFI4_IOC_MAGIC, 2, unsigned int)
-#define HIFI4_CODEC_CLOSE _IOWR(HIFI4_IOC_MAGIC, 3, unsigned int)
-#define HIFI4_DECODE_ONE_FRAME _IOW(HIFI4_IOC_MAGIC, 4, unsigned int)
-#define HIFI4_UNLOAD_CODEC _IOW(HIFI4_IOC_MAGIC, 5, unsigned int)
-#define HIFI4_GET_PCM_PROP _IOW(HIFI4_IOC_MAGIC, 6, unsigned int)
-#define HIFI4_SET_CONFIG _IOW(HIFI4_IOC_MAGIC, 7, unsigned int)
-#define HIFI4_RESET_CODEC _IOW(HIFI4_IOC_MAGIC, 8, unsigned int)
-#define HIFI4_CLIENT_REGISTER _IOW(HIFI4_IOC_MAGIC, 9, unsigned int)
-#define HIFI4_CLIENT_UNREGISTER _IOW(HIFI4_IOC_MAGIC, 10, unsigned int)
+#define DSP_IOC_MAGIC 'H'
+#define DSP_CLIENT_REGISTER _IOW(DSP_IOC_MAGIC, 0, unsigned int)
+#define DSP_CLIENT_UNREGISTER _IOW(DSP_IOC_MAGIC, 1, unsigned int)
+#define DSP_IPC_MSG_SEND _IOW(DSP_IOC_MAGIC, 2, unsigned int)
+#define DSP_IPC_MSG_RECV _IOW(DSP_IOC_MAGIC, 3, unsigned int)
+#define DSP_GET_SHMEM_INFO _IOW(DSP_IOC_MAGIC, 4, unsigned int)
#define CODEC_MP3_DEC 1
#define CODEC_AAC_DEC 2
@@ -105,6 +99,13 @@ enum HIFI_ParaType {
XA_SBC_ENC_BITPOOL,
XA_SBC_ENC_CHMODE,
+/* Get parmameters */
+ XA_CODEC_DESCRIPTION = 0x200,
+ XA_OUTPUT_PCM_FORMAT,
+ XA_CONSUMED_LENGTH,
+ XA_OUTBUF_ALLOC_SIZE,
+ XA_CONSUMED_CYCLES,
+
};
#define HIFI_STREAM_DABPLUS_BASE 0x30
@@ -136,45 +137,9 @@ enum HIFI_SbcEncChmode {
XA_CHMODE_JOINT = 3,
};
-enum lib_type {
- HIFI_CODEC_LIB = 1,
- HIFI_CODEC_WRAP_LIB,
-};
-
-struct decode_info {
- void *in_buf_addr;
- int in_buf_size;
- int in_buf_off;
- void *out_buf_addr;
- int out_buf_size;
- int out_buf_off;
- unsigned int input_over;
- unsigned int process_id;
-};
-
-struct prop_info {
- int samplerate;
- int channels;
- int bits;
- unsigned int consumed_bytes;
- unsigned int cycles;
-
- unsigned int process_id;
-};
-
-struct binary_info {
- int type;
- char *file;
- unsigned int process_id;
- unsigned int lib_type;
-};
-
-struct prop_config {
- int codec_id; /* codec id */
- int cmd; /* command value */
- int val; /* parameter value */
- int ret; /* executed status of function */
- unsigned int process_id;
+struct shmem_info {
+ unsigned int phys_addr;
+ unsigned int size;
};
#endif/* __MXC_HIFI4_UAPI_H__ */
diff --git a/sound/soc/fsl/Makefile b/sound/soc/fsl/Makefile
index 8f09c3cd5238..d1ffc9eaf9f7 100644
--- a/sound/soc/fsl/Makefile
+++ b/sound/soc/fsl/Makefile
@@ -15,7 +15,7 @@ obj-$(CONFIG_SND_SOC_P1022_RDK) += snd-soc-p1022-rdk.o
snd-soc-fsl-audmix-objs := fsl_audmix.o
snd-soc-fsl-asoc-card-objs := fsl-asoc-card.o
snd-soc-fsl-asrc-objs := fsl_asrc.o fsl_asrc_dma.o
-snd-soc-fsl-hifi4-objs := fsl_hifi4.o
+snd-soc-fsl-hifi4-objs := fsl_hifi4.o fsl_hifi4_proxy.o
snd-soc-fsl-sai-objs := fsl_sai.o
snd-soc-fsl-ssi-y := fsl_ssi.o
snd-soc-fsl-ssi-$(CONFIG_DEBUG_FS) += fsl_ssi_dbg.o
diff --git a/sound/soc/fsl/fsl_hifi4.c b/sound/soc/fsl/fsl_hifi4.c
index 756a697e570a..e4e826de6c69 100644
--- a/sound/soc/fsl/fsl_hifi4.c
+++ b/sound/soc/fsl/fsl_hifi4.c
@@ -54,6 +54,7 @@
#include <linux/pm_runtime.h>
#include <linux/mx8_mu.h>
#include <linux/uaccess.h>
+#include <linux/poll.h>
#ifdef CONFIG_COMPAT
#include <linux/compat.h>
#endif
@@ -64,1430 +65,212 @@
#include "fsl_hifi4.h"
-#ifdef CONFIG_COMPAT
-struct decode_info_compat32 {
- compat_long_t in_buf_addr;
- __s32 in_buf_size;
- __s32 in_buf_off;
- compat_long_t out_buf_addr;
- __s32 out_buf_size;
- __s32 out_buf_off;
- __u32 input_over;
- __u32 process_id;
-};
-
-struct binary_info_compat32 {
- __s32 type;
- compat_long_t file;
- __u32 process_id;
- __u32 lib_type;
-};
-
-static int get_binary_info_compat32(struct binary_info *kp,
- struct binary_info_compat32 __user *up) {
- void __user *up_ptr;
- compat_long_t p;
-
- if (!access_ok(VERIFY_READ, up, sizeof(struct binary_info_compat32)) ||
- get_user(kp->type, &up->type) ||
- get_user(p, &up->file) ||
- get_user(kp->process_id, &up->process_id) ||
- get_user(kp->lib_type, &up->lib_type)
- ) {
- return -EFAULT;
- }
-
- up_ptr = compat_ptr(p);
- kp->file = (char *)up_ptr;
-
- return 0;
-}
-
-static int get_decode_info_compat32(struct decode_info *kp,
- struct decode_info_compat32 *up) {
- void __user *up_ptr1;
- void __user *up_ptr2;
- compat_long_t p1;
- compat_long_t p2;
-
- if (!access_ok(VERIFY_READ, up, sizeof(struct decode_info_compat32)) ||
- get_user(p1, &up->in_buf_addr) ||
- get_user(kp->in_buf_size, &up->in_buf_size) ||
- get_user(kp->in_buf_off, &up->in_buf_off) ||
- get_user(p2, &up->out_buf_addr) ||
- get_user(kp->out_buf_size, &up->out_buf_size) ||
- get_user(kp->out_buf_off, &up->out_buf_off) ||
- get_user(kp->input_over, &up->input_over) ||
- get_user(kp->process_id, &up->process_id)
- ) {
- return -EFAULT;
- }
-
- up_ptr1 = compat_ptr(p1);
- up_ptr2 = compat_ptr(p2);
-
- kp->in_buf_addr = (void *)up_ptr1;
- kp->out_buf_addr = (void *)up_ptr2;
-
- return 0;
-}
-
-static int put_decode_info_compat32(struct decode_info *kp,
- struct decode_info_compat32 *up) {
-
- if (!access_ok(VERIFY_WRITE, up, sizeof(struct decode_info_compat32)) ||
- put_user(kp->in_buf_off, &up->in_buf_off) ||
- put_user(kp->out_buf_off, &up->out_buf_off) ||
- put_user(kp->input_over, &up->input_over)
- ) {
- return -EFAULT;
- }
-
- return 0;
-}
-#endif
-
-long hifi4_buf_alloc(struct fsl_hifi4 *hifi4_priv,
- unsigned int size)
-{
- union icm_header_t apu_icm;
- struct hifi4_ext_msg ext_msg;
- struct icm_pilib_size_t icm_pilib_size_t;
- struct icm_pilib_size_t *pilib_buffer_info =
- &hifi4_priv->pilib_buffer_info;
- long ret = 0;
-
- if (size <= 0)
- return 0;
-
- /* For shared memory between hifi driver and framework,
- * it is managed by hifi framework, so when hifi driver
- * wants to get shard memory, it should send
- * ICM_PI_LIB_MEM_ALLOC command to hifi framework to request
- * memory. If memory request is ok, hifi framework will send
- * a message which includes the physical address of memory to
- * hifi driver. If not, the physical address will be zero.
- */
- init_completion(&hifi4_priv->cmd_complete);
- hifi4_priv->is_done = 0;
-
- apu_icm.allbits = 0; /* clear all bits;*/
- apu_icm.ack = 0;
- apu_icm.intr = 1;
- apu_icm.msg = ICM_PI_LIB_MEM_ALLOC;
- apu_icm.size = 8;
-
- ext_msg.phys = hifi4_priv->msg_buf_phys;
- ext_msg.size = sizeof(struct icm_pilib_size_t);
-
- icm_pilib_size_t.buffer_addr = 0;
- icm_pilib_size_t.buffer_size = size;
- icm_pilib_size_t.ret = 0;
-
- memcpy(hifi4_priv->msg_buf_virt, &icm_pilib_size_t,
- sizeof(struct icm_pilib_size_t));
- icm_intr_extended_send(hifi4_priv, apu_icm.allbits, &ext_msg);
-
- /* wait for response here */
- ret = icm_ack_wait(hifi4_priv, apu_icm.allbits);
- if (ret)
- return 0;
-
- if (pilib_buffer_info->buffer_addr)
- return (long)pilib_buffer_info->buffer_addr;
-
- return 0;
-}
-
-long hifi4_buf_free(struct fsl_hifi4 *hifi4_priv, long ptr)
+/* ...allocate new client */
+static inline struct xf_client *xf_client_alloc(struct fsl_hifi4 *hifi4_priv)
{
- union icm_header_t apu_icm;
- struct hifi4_ext_msg ext_msg;
- struct icm_pilib_size_t icm_pilib_size_t;
- long ret = 0;
+ struct xf_client *client;
+ u32 id;
- if (ptr == 0)
- return 0;
-
- /* If hifi driver wants to release the shared memory which
- * has been allocated by hifi4_buf_alloc(), it should send
- * ICM_PI_LIB_MEM_FREE command to hifi framework. The message
- * in this command should include the physical address of
- * current memory.
- */
- init_completion(&hifi4_priv->cmd_complete);
- hifi4_priv->is_done = 0;
+ id = hifi4_priv->xf_client_map[0].next;
- apu_icm.allbits = 0; /* clear all bits;*/
- apu_icm.ack = 0;
- apu_icm.intr = 1;
- apu_icm.msg = ICM_PI_LIB_MEM_FREE;
- apu_icm.size = 8;
+ /* ...try to allocate a client handle */
+ if (id != 0) {
+ /* ...allocate client memory */
+ client = kmalloc(sizeof(*client), GFP_KERNEL);
+ if (!client)
+ return ERR_PTR(-ENOMEM);
- ext_msg.phys = hifi4_priv->msg_buf_phys;
- ext_msg.size = sizeof(struct icm_pilib_size_t);
+ /* ...advance the head of free clients */
+ hifi4_priv->xf_client_map[0].next =
+ hifi4_priv->xf_client_map[id].next;
- icm_pilib_size_t.buffer_addr = (u32)ptr;
- icm_pilib_size_t.buffer_size = 0;
- icm_pilib_size_t.ret = 0;
+ /* ...put associate client id with given object */
+ hifi4_priv->xf_client_map[id].client = client;
- memcpy(hifi4_priv->msg_buf_virt, &icm_pilib_size_t,
- sizeof(struct icm_pilib_size_t));
- icm_intr_extended_send(hifi4_priv, apu_icm.allbits, &ext_msg);
+ /* ...mark client is not yet bound to proxy */
+ client->proxy = NULL;
- /* wait for response here */
- ret = icm_ack_wait(hifi4_priv, apu_icm.allbits);
- if (ret)
- return ret;
-
- ret = hifi4_priv->ret_status;
-
- return ret;
-}
-
-Elf32_Half xtlib_host_half(Elf32_Half v, int byteswap)
-{
- return (byteswap) ? (v >> 8) | (v << 8) : v;
-}
+ /* ...save global proxy client identifier */
+ client->id = id;
-Elf32_Word xtlib_host_word(Elf32_Word v, int byteswap)
-{
- if (byteswap) {
- v = ((v & 0x00FF00FF) << 8) | ((v & 0xFF00FF00) >> 8);
- v = (v >> 16) | (v << 16);
- }
- return v;
-}
-
-int xtlib_verify_magic(Elf32_Ehdr *header,
- struct icm_process_info *process_info)
-{
- struct xtlib_loader_globals *xtlib_globals =
- &process_info->xtlib_globals;
- Elf32_Byte magic_no;
-
- magic_no = header->e_ident[EI_MAG0];
- if (magic_no != 0x7f)
- return -1;
-
- magic_no = header->e_ident[EI_MAG1];
- if (magic_no != 'E')
- return -1;
-
- magic_no = header->e_ident[EI_MAG2];
- if (magic_no != 'L')
- return -1;
-
- magic_no = header->e_ident[EI_MAG3];
- if (magic_no != 'F')
- return -1;
-
- if (header->e_ident[EI_CLASS] != ELFCLASS32)
- return -1;
-
- {
- /* determine byte order */
- union {
- short s;
- char c[sizeof(short)];
- } u;
-
- u.s = 1;
-
- if (header->e_ident[EI_DATA] == ELFDATA2LSB)
- xtlib_globals->byteswap = u.c[sizeof(short) - 1] == 1;
- else if (header->e_ident[EI_DATA] == ELFDATA2MSB)
- xtlib_globals->byteswap = u.c[0] == 1;
- else
- return -1;
+ return client;
}
- return 0;
-}
-
-void xtlib_load_seg(Elf32_Phdr *pheader, void *src_addr, xt_ptr dst_addr,
- memcpy_func mcpy, memset_func mset,
- struct icm_process_info *process_info)
-{
- struct xtlib_loader_globals *xtlib_globals =
- &process_info->xtlib_globals;
- Elf32_Word bytes_to_copy = xtlib_host_word(pheader->p_filesz,
- xtlib_globals->byteswap);
- Elf32_Word bytes_to_zero = xtlib_host_word(pheader->p_memsz,
- xtlib_globals->byteswap)
- - bytes_to_copy;
-
- void *zero_addr = (void *)dst_addr + bytes_to_copy;
-
- if (bytes_to_copy > 0)
- mcpy((void *)(dst_addr), src_addr, bytes_to_copy);
-
- if (bytes_to_zero > 0)
- mset(zero_addr, 0, bytes_to_zero);
+ /* ...number of clients exceeded */
+ return ERR_PTR(-EBUSY);
}
-#define xtlib_xt_half xtlib_host_half
-#define xtlib_xt_word xtlib_host_word
-
-static xt_ptr align_ptr(xt_ptr ptr, xt_uint align)
+/* ...recycle client object */
+static inline void xf_client_free(struct xf_client *client)
{
- return (xt_ptr)(((xt_uint)ptr + align - 1) & ~(align - 1));
-}
-
-static xt_ptr xt_ptr_offs(xt_ptr base, Elf32_Word offs,
- struct icm_process_info *process_info)
-{
- struct xtlib_loader_globals *xtlib_globals =
- &process_info->xtlib_globals;
-
- return (xt_ptr) xtlib_xt_word((xt_uint)base +
- xtlib_host_word(offs, xtlib_globals->byteswap),
- xtlib_globals->byteswap);
-}
-
-static Elf32_Dyn *find_dynamic_info(Elf32_Ehdr *eheader,
- struct icm_process_info *process_info)
-{
- char *base_addr = (char *)eheader;
- struct xtlib_loader_globals *xtlib_globals =
- &process_info->xtlib_globals;
- Elf32_Phdr *pheader = (Elf32_Phdr *)(base_addr +
- xtlib_host_word(eheader->e_phoff,
- xtlib_globals->byteswap));
-
- int seg = 0;
- int num = xtlib_host_half(eheader->e_phnum, xtlib_globals->byteswap);
-
- while (seg < num) {
- if (xtlib_host_word(pheader[seg].p_type,
- xtlib_globals->byteswap) == PT_DYNAMIC) {
- return (Elf32_Dyn *) (base_addr +
- xtlib_host_word(pheader[seg].p_offset,
- xtlib_globals->byteswap));
- }
- seg++;
- }
- return 0;
-}
-
-static int find_align(Elf32_Ehdr *header,
- struct icm_process_info *process_info)
-{
- struct xtlib_loader_globals *xtlib_globals =
- &process_info->xtlib_globals;
- Elf32_Shdr *sheader = (Elf32_Shdr *) (((char *)header) +
- xtlib_host_word(header->e_shoff, xtlib_globals->byteswap));
-
- int sec = 0;
- int num = xtlib_host_half(header->e_shnum, xtlib_globals->byteswap);
-
- int align = 0;
-
- while (sec < num) {
- if (sheader[sec].sh_type != SHT_NULL &&
- xtlib_host_word(sheader[sec].sh_size,
- xtlib_globals->byteswap) > 0) {
- int sec_align =
- xtlib_host_word(sheader[sec].sh_addralign,
- xtlib_globals->byteswap);
- if (sec_align > align)
- align = sec_align;
- }
- sec++;
- }
-
- return align;
-}
-
-static int validate_dynamic(Elf32_Ehdr *header,
- struct icm_process_info *process_info)
-{
- struct xtlib_loader_globals *xtlib_globals =
- &process_info->xtlib_globals;
-
- if (xtlib_verify_magic(header, process_info) != 0)
- return XTLIB_NOT_ELF;
-
- if (xtlib_host_half(header->e_type,
- xtlib_globals->byteswap) != ET_DYN)
- return XTLIB_NOT_DYNAMIC;
-
- return XTLIB_NO_ERR;
-}
-
-static int validate_dynamic_splitload(Elf32_Ehdr *header,
- struct icm_process_info *process_info)
-{
- struct xtlib_loader_globals *xtlib_globals =
- &process_info->xtlib_globals;
- Elf32_Phdr *pheader;
- int err = validate_dynamic(header, process_info);
-
- if (err != XTLIB_NO_ERR)
- return err;
-
- /* make sure it's split load pi library, expecting three headers,
- * code, data and dynamic, for example:
- *
- *LOAD off 0x00000094 vaddr 0x00000000 paddr 0x00000000 align 2**0
- * filesz 0x00000081 memsz 0x00000081 flags r-x
- *LOAD off 0x00000124 vaddr 0x00000084 paddr 0x00000084 align 2**0
- * filesz 0x000001ab memsz 0x000011bc flags rwx
- *DYNAMIC off 0x00000124 vaddr 0x00000084 paddr 0x00000084 align 2**2
- * filesz 0x000000a0 memsz 0x000000a0 flags rw-
- */
-
- if (xtlib_host_half(header->e_phnum, xtlib_globals->byteswap) != 3)
- return XTLIB_NOT_SPLITLOAD;
-
- pheader = (Elf32_Phdr *) ((char *)header +
- xtlib_host_word(header->e_phoff, xtlib_globals->byteswap));
-
- /* LOAD R-X */
- if (xtlib_host_word(pheader[0].p_type,
- xtlib_globals->byteswap) != PT_LOAD
- || (xtlib_host_word(pheader[0].p_flags, xtlib_globals->byteswap)
- & (PF_R | PF_W | PF_X)) != (PF_R | PF_X))
- return XTLIB_NOT_SPLITLOAD;
-
- /* LOAD RWX */
- if (xtlib_host_word(pheader[1].p_type,
- xtlib_globals->byteswap) != PT_LOAD
- || (xtlib_host_word(pheader[1].p_flags,
- xtlib_globals->byteswap)
- & (PF_R | PF_W | PF_X)) != (PF_R | PF_W | PF_X))
- return XTLIB_NOT_SPLITLOAD;
-
- /* DYNAMIC RW- */
- if (xtlib_host_word(pheader[2].p_type,
- xtlib_globals->byteswap) != PT_DYNAMIC
- || (xtlib_host_word(pheader[2].p_flags,
- xtlib_globals->byteswap)
- & (PF_R | PF_W | PF_X)) != (PF_R | PF_W))
- return XTLIB_NOT_SPLITLOAD;
-
- return XTLIB_NO_ERR;
-}
-
-
-
-unsigned int xtlib_split_pi_library_size(
- struct xtlib_packaged_library *library,
- unsigned int *code_size,
- unsigned int *data_size,
- struct icm_process_info *process_info)
-{
- struct xtlib_loader_globals *xtlib_globals =
- &process_info->xtlib_globals;
- Elf32_Phdr *pheader;
- Elf32_Ehdr *header = (Elf32_Ehdr *) library;
- int align;
- int err = validate_dynamic_splitload(header, process_info);
-
- if (err != XTLIB_NO_ERR) {
- xtlib_globals->err = err;
- return err;
- }
-
- align = find_align(header, process_info);
-
- pheader = (Elf32_Phdr *) ((char *)library +
- xtlib_host_word(header->e_phoff, xtlib_globals->byteswap));
-
- *code_size = xtlib_host_word(pheader[0].p_memsz,
- xtlib_globals->byteswap) + align;
- *data_size = xtlib_host_word(pheader[1].p_memsz,
- xtlib_globals->byteswap) + align;
-
- return XTLIB_NO_ERR;
-}
-
-
-
-static int get_dyn_info(Elf32_Ehdr *eheader,
- xt_ptr dst_addr,
- xt_uint src_offs,
- xt_ptr dst_data_addr,
- xt_uint src_data_offs,
- struct xtlib_pil_info *info,
- struct icm_process_info *process_info)
-{
- unsigned int jmprel = 0;
- unsigned int pltrelsz = 0;
- struct xtlib_loader_globals *xtlib_globals =
- &process_info->xtlib_globals;
- Elf32_Dyn *dyn_entry = find_dynamic_info(eheader, process_info);
-
- if (dyn_entry == 0)
- return XTLIB_NO_DYNAMIC_SEGMENT;
-
- info->dst_addr = (xt_uint) xtlib_xt_word((Elf32_Word) dst_addr,
- xtlib_globals->byteswap);
- info->src_offs = xtlib_xt_word(src_offs, xtlib_globals->byteswap);
- info->dst_data_addr = (xt_uint) xtlib_xt_word(
- (Elf32_Word) dst_data_addr + src_data_offs,
- xtlib_globals->byteswap);
- info->src_data_offs = xtlib_xt_word(src_data_offs,
- xtlib_globals->byteswap);
-
- dst_addr -= src_offs;
- dst_data_addr = dst_data_addr + src_data_offs - src_data_offs;
-
- info->start_sym = xt_ptr_offs(dst_addr, eheader->e_entry, process_info);
-
- info->align = xtlib_xt_word(find_align(eheader, process_info),
- xtlib_globals->byteswap);
-
- info->text_addr = 0;
-
- while (dyn_entry->d_tag != DT_NULL) {
- switch ((Elf32_Sword) xtlib_host_word(
- (Elf32_Word)dyn_entry->d_tag,
- xtlib_globals->byteswap)) {
- case DT_RELA:
- info->rel = xt_ptr_offs(dst_data_addr,
- dyn_entry->d_un.d_ptr, process_info);
- break;
- case DT_RELASZ:
- info->rela_count = xtlib_xt_word(
- xtlib_host_word(dyn_entry->d_un.d_val,
- xtlib_globals->byteswap) / sizeof(Elf32_Rela),
- xtlib_globals->byteswap);
- break;
- case DT_INIT:
- info->init = xt_ptr_offs(dst_addr,
- dyn_entry->d_un.d_ptr, process_info);
- break;
- case DT_FINI:
- info->fini = xt_ptr_offs(dst_addr,
- dyn_entry->d_un.d_ptr, process_info);
- break;
- case DT_HASH:
- info->hash = xt_ptr_offs(dst_data_addr,
- dyn_entry->d_un.d_ptr, process_info);
- break;
- case DT_SYMTAB:
- info->symtab = xt_ptr_offs(dst_data_addr,
- dyn_entry->d_un.d_ptr, process_info);
- break;
- case DT_STRTAB:
- info->strtab = xt_ptr_offs(dst_data_addr,
- dyn_entry->d_un.d_ptr, process_info);
- break;
- case DT_JMPREL:
- jmprel = dyn_entry->d_un.d_val;
- break;
- case DT_PLTRELSZ:
- pltrelsz = dyn_entry->d_un.d_val;
- break;
- case DT_LOPROC + 2:
- info->text_addr = xt_ptr_offs(dst_addr,
- dyn_entry->d_un.d_ptr, process_info);
- break;
-
- default:
- /* do nothing */
- break;
- }
- dyn_entry++;
- }
-
- return XTLIB_NO_ERR;
-}
-
-
-static xt_ptr xtlib_load_split_pi_library_common(
- struct xtlib_packaged_library *library,
- xt_ptr destination_code_address,
- xt_ptr destination_data_address,
- struct xtlib_pil_info *lib_info,
- memcpy_func mcpy_fn,
- memset_func mset_fn,
- struct icm_process_info *process_info)
-{
- struct xtlib_loader_globals *xtlib_globals =
- &process_info->xtlib_globals;
- Elf32_Ehdr *header = (Elf32_Ehdr *) library;
- Elf32_Phdr *pheader;
- unsigned int align;
- int err = validate_dynamic_splitload(header, process_info);
- xt_ptr destination_code_address_back;
- xt_ptr destination_data_address_back;
-
- if (err != XTLIB_NO_ERR) {
- xtlib_globals->err = err;
- return 0;
- }
-
- align = find_align(header, process_info);
-
- destination_code_address_back = destination_code_address;
- destination_data_address_back = destination_data_address;
-
- destination_code_address = align_ptr(destination_code_address, align);
- destination_data_address = align_ptr(destination_data_address, align);
- process_info->code_buf_virt += (destination_code_address -
- destination_code_address_back);
- process_info->data_buf_virt += (destination_data_address -
- destination_data_address_back);
-
- pheader = (Elf32_Phdr *) ((char *)library +
- xtlib_host_word(header->e_phoff,
- xtlib_globals->byteswap));
-
- err = get_dyn_info(header,
- destination_code_address,
- xtlib_host_word(pheader[0].p_paddr,
- xtlib_globals->byteswap),
- destination_data_address,
- xtlib_host_word(pheader[1].p_paddr,
- xtlib_globals->byteswap),
- lib_info,
- process_info);
-
- if (err != XTLIB_NO_ERR) {
- xtlib_globals->err = err;
- return 0;
- }
-
- /* loading code */
- xtlib_load_seg(&pheader[0],
- (char *)library + xtlib_host_word(pheader[0].p_offset,
- xtlib_globals->byteswap),
- (xt_ptr)process_info->code_buf_virt,
- mcpy_fn, mset_fn, process_info);
-
- if (lib_info->text_addr == 0)
- lib_info->text_addr =
- (xt_ptr) xtlib_xt_word((Elf32_Word) destination_code_address,
- xtlib_globals->byteswap);
-
- /* loading data */
- xtlib_load_seg(&pheader[1],
- (char *)library + xtlib_host_word(pheader[1].p_offset,
- xtlib_globals->byteswap),
- (xt_ptr)process_info->data_buf_virt +
- xtlib_host_word(pheader[1].p_paddr,
- xtlib_globals->byteswap),
- mcpy_fn, mset_fn, process_info);
-
- if (err != XTLIB_NO_ERR) {
- xtlib_globals->err = err;
- return 0;
- }
-
- return (xt_ptr) xtlib_host_word((Elf32_Word) lib_info->start_sym,
- xtlib_globals->byteswap);
-}
-
-xt_ptr xtlib_host_load_split_pi_library(struct xtlib_packaged_library *library,
- xt_ptr destination_code_address,
- xt_ptr destination_data_address,
- struct xtlib_pil_info *lib_info,
- memcpy_func mcpy_fn,
- memset_func mset_fn,
- struct icm_process_info *process_info)
-{
- return xtlib_load_split_pi_library_common(library,
- destination_code_address,
- destination_data_address,
- lib_info,
- mcpy_fn,
- mset_fn,
- process_info);
-}
-
-
-long load_dpu_with_library(struct fsl_hifi4 *hifi4_priv,
- struct icm_process_info *process_info)
-{
- struct device *dev = hifi4_priv->dev;
- struct file *fpInfile;
- unsigned char *srambuf = NULL;
- struct lib_dnld_info_t dpulib;
- Elf32_Phdr *pheader;
- Elf32_Ehdr *header;
- unsigned int align;
- int filesize = 0;
- long ret_val = 0;
-
- /* Load DPU's main program to System memory */
- fpInfile = file_open_name(process_info->objfile, O_RDONLY, 0);
- if (IS_ERR(fpInfile))
- return PTR_ERR(fpInfile);
-
- vfs_llseek(fpInfile, 0, SEEK_END);
- filesize = (int)fpInfile->f_pos;
-
- srambuf = kmalloc(filesize, GFP_KERNEL);
- vfs_llseek(fpInfile, 0, SEEK_SET);
-
- kernel_read(fpInfile, srambuf, filesize, NULL);
- filp_close(fpInfile, NULL);
-
- ret_val = xtlib_split_pi_library_size(
- (struct xtlib_packaged_library *)(srambuf),
- (unsigned int *)&(dpulib.size_code),
- (unsigned int *)&(dpulib.size_data),
- process_info);
- if (ret_val != XTLIB_NO_ERR)
- return ret_val;
-
- process_info->code_buf_size = dpulib.size_code;
- process_info->data_buf_size = dpulib.size_data;
-
- header = (Elf32_Ehdr *)srambuf;
- pheader = (Elf32_Phdr *) ((char *)srambuf +
- xtlib_host_word(header->e_phoff,
- process_info->xtlib_globals.byteswap));
-
- align = find_align(header, process_info);
-
- process_info->code_buf_phys = hifi4_buf_alloc(hifi4_priv,
- dpulib.size_code + align);
- if (!process_info->code_buf_phys) {
- kfree(srambuf);
- dev_err(dev, "not enough buffer when loading codec lib\n");
- return -ENOMEM;
- }
- process_info->array_alloc_mem[process_info->alloc_count++] =
- process_info->code_buf_phys;
-
- process_info->data_buf_phys = hifi4_buf_alloc(hifi4_priv,
- dpulib.size_data + pheader[1].p_paddr + align);
- if (!process_info->data_buf_phys) {
- kfree(srambuf);
- dev_err(dev, "not enough buffer when loading codec lib\n");
- return -ENOMEM;
- }
- process_info->array_alloc_mem[process_info->alloc_count++] =
- process_info->data_buf_phys;
-
- dpulib.pbuf_code = (unsigned long)process_info->code_buf_phys;
- dpulib.pbuf_data = (unsigned long)process_info->data_buf_phys;
-
- process_info->code_buf_virt = hifi4_priv->sdram_vir_addr +
- (process_info->code_buf_phys - hifi4_priv->sdram_phys_addr);
- process_info->data_buf_virt = hifi4_priv->sdram_vir_addr +
- (process_info->data_buf_phys - hifi4_priv->sdram_phys_addr);
-
- dpulib.ppil_inf = &process_info->pil_info;
- xtlib_host_load_split_pi_library(
- (struct xtlib_packaged_library *) (srambuf),
- (xt_ptr) (dpulib.pbuf_code),
- (xt_ptr) (dpulib.pbuf_data),
- (struct xtlib_pil_info *)dpulib.ppil_inf,
- (memcpy_func)&memcpy_hifi,
- (memset_func)&memset_hifi,
- (void *)process_info);
-
- kfree(srambuf);
-
- return ret_val;
-}
-
-static long fsl_hifi4_init_codec(struct fsl_hifi4 *hifi4_priv,
- void __user *user)
-{
- struct device *dev = hifi4_priv->dev;
- union icm_header_t apu_icm;
- struct hifi4_ext_msg ext_msg;
- struct icm_base_info_t icm_base_info_t;
- struct icm_process_info *process_info;
- int id;
- long ret = 0;
-
- ret = copy_from_user(&id, user, sizeof(int));
- if (ret) {
- dev_err(dev, "failed to get para from user space\n");
- return -EFAULT;
- }
-
- process_info = &hifi4_priv->process_info[id];
+ int id = client->id;
+ struct fsl_hifi4 *hifi4_priv = (struct fsl_hifi4 *)client->global;
- init_completion(&hifi4_priv->cmd_complete);
- hifi4_priv->is_done = 0;
+ /* ...put proxy client id into free clients list */
+ hifi4_priv->xf_client_map[id].next = hifi4_priv->xf_client_map[0].next;
+ hifi4_priv->xf_client_map[0].next = id;
- apu_icm.allbits = 0; /* clear all bits;*/
- apu_icm.ack = 0;
- apu_icm.intr = 1;
- apu_icm.msg = ICM_PI_LIB_INIT;
- apu_icm.size = 8;
-
- ext_msg.phys = hifi4_priv->msg_buf_phys;
- ext_msg.size = sizeof(struct icm_base_info_t);
-
- memset(&icm_base_info_t, 0, sizeof(struct icm_base_info_t));
- icm_base_info_t.process_id = id;
- icm_base_info_t.codec_id = process_info->codec_id;
-
- memcpy(hifi4_priv->msg_buf_virt, &icm_base_info_t,
- sizeof(struct icm_base_info_t));
- icm_intr_extended_send(hifi4_priv, apu_icm.allbits, &ext_msg);
-
- /* wait for response here */
- ret = icm_ack_wait(hifi4_priv, apu_icm.allbits);
- if (ret)
- return ret;
-
- /* allocate input and output buffer from dsp framework */
- process_info->in_buf_phys = hifi4_buf_alloc(hifi4_priv,
- INPUT_BUF_SIZE);
- if (!process_info->in_buf_phys) {
- dev_err(dev, "Fail to alloc input buffer\n");
- return -ENOMEM;
- }
- process_info->array_alloc_mem[process_info->alloc_count++] =
- process_info->in_buf_phys;
-
- process_info->out_buf_phys = hifi4_buf_alloc(hifi4_priv,
- OUTPUT_BUF_SIZE);
- if (!process_info->out_buf_phys) {
- dev_err(dev, "Fail to alloc output buffer\n");
- return -ENOMEM;
- }
- process_info->array_alloc_mem[process_info->alloc_count++] =
- process_info->out_buf_phys;
-
- /* caculate the virtual address based on physical address */
- process_info->in_buf_virt = hifi4_priv->sdram_vir_addr +
- (process_info->in_buf_phys - hifi4_priv->sdram_phys_addr);
- process_info->out_buf_virt = hifi4_priv->sdram_vir_addr +
- (process_info->out_buf_phys - hifi4_priv->sdram_phys_addr);
-
- return hifi4_priv->ret_status;
+ /* ...destroy client data */
+ kfree(client);
}
-static long fsl_hifi4_decode_frame(struct fsl_hifi4 *hifi4_priv,
- void __user *user)
+/* ...lookup client basing on id */
+struct xf_client *xf_client_lookup(struct fsl_hifi4 *hifi4_priv, u32 id)
{
- struct device *dev = hifi4_priv->dev;
- union icm_header_t apu_icm;
- struct hifi4_ext_msg ext_msg;
- struct decode_info decode_info;
- struct icm_process_info *process_info;
- struct icm_cdc_iobuf_t *codec_iobuf_info =
- &hifi4_priv->codec_iobuf_info;
- int id;
- long ret;
-
- ret = copy_from_user(&decode_info, user, sizeof(decode_info));
- if (ret) {
- dev_err(dev, "failed to get para from user space\n");
- return -EFAULT;
- }
-
- id = decode_info.process_id;
- process_info = &hifi4_priv->process_info[id];
-
- if (decode_info.in_buf_size > INPUT_BUF_SIZE ||
- decode_info.out_buf_size != OUTPUT_BUF_SIZE) {
- dev_err(dev, "param error\n");
- return -EINVAL;
- }
-
- if (decode_info.in_buf_off == 0) {
- ret = copy_from_user(process_info->in_buf_virt,
- (void __user *)decode_info.in_buf_addr,
- decode_info.in_buf_size);
- if (ret) {
- dev_err(dev, "failed to copy from user\n");
- return -EFAULT;
- }
- codec_iobuf_info->inp_cur_offset = 0;
- }
-
- codec_iobuf_info->inp_addr_sysram = process_info->in_buf_phys;
- codec_iobuf_info->inp_buf_size_max = decode_info.in_buf_size;
- codec_iobuf_info->inp_cur_offset = decode_info.in_buf_off;
-
- codec_iobuf_info->out_addr_sysram = process_info->out_buf_phys;
- codec_iobuf_info->out_buf_size_max = process_info->out_buf_size;
- codec_iobuf_info->out_cur_offset = 0;
-
- codec_iobuf_info->input_over = decode_info.input_over;
- codec_iobuf_info->base_info.process_id = decode_info.process_id;
-
- init_completion(&hifi4_priv->cmd_complete);
- hifi4_priv->is_done = 0;
-
- apu_icm.allbits = 0; /* clear all bits; */
- apu_icm.ack = 0;
- apu_icm.intr = 1;
- apu_icm.msg = ICM_EMPTY_THIS_BUFFER;
- apu_icm.size = 8;
- ext_msg.phys = hifi4_priv->msg_buf_phys;
- ext_msg.size = sizeof(struct icm_cdc_iobuf_t);
-
- memcpy(hifi4_priv->msg_buf_virt, codec_iobuf_info,
- sizeof(struct icm_cdc_iobuf_t));
- icm_intr_extended_send(hifi4_priv, apu_icm.allbits, &ext_msg);
-
- /* wait for response here */
- ret = icm_ack_wait(hifi4_priv, apu_icm.allbits);
- if (ret)
- return ret;
-
- ret = copy_to_user((void __user *)decode_info.out_buf_addr,
- process_info->out_buf_virt,
- codec_iobuf_info->out_cur_offset);
- if (ret) {
- dev_err(dev, "failed to copy to user\n");
- return -EFAULT;
- }
-
- decode_info.in_buf_off = codec_iobuf_info->inp_cur_offset;
- decode_info.out_buf_off = codec_iobuf_info->out_cur_offset;
-
- ret = copy_to_user(user, &decode_info, sizeof(decode_info));
- if (ret) {
- dev_err(dev, "failed to send para to user space\n");
- return -EFAULT;
- }
-
- ret = hifi4_priv->ret_status;
- return ret;
+ if ((id >= XF_CFG_MAX_IPC_CLIENTS) ||
+ (hifi4_priv->xf_client_map[id].next < XF_CFG_MAX_IPC_CLIENTS)
+ )
+ return NULL;
+ else
+ return hifi4_priv->xf_client_map[id].client;
}
-#ifdef CONFIG_COMPAT
-static long fsl_hifi4_decode_frame_compat32(struct fsl_hifi4 *hifi4_priv,
- void __user *user)
+/* ...helper function for retrieving the client handle */
+static inline struct xf_client *xf_get_client(struct file *file)
{
- struct device *dev = hifi4_priv->dev;
- union icm_header_t apu_icm;
- struct hifi4_ext_msg ext_msg;
- struct decode_info decode_info;
- struct icm_process_info *process_info;
- struct icm_cdc_iobuf_t *codec_iobuf_info =
- &hifi4_priv->codec_iobuf_info;
- int id;
- long ret;
-
- ret = get_decode_info_compat32(&decode_info, user);
- if (ret) {
- dev_err(dev, "failed to get para from user space in compat32 mode\n");
- return ret;
- }
+ struct xf_client *client;
+ u32 id;
- id = decode_info.process_id;
- process_info = &hifi4_priv->process_info[id];
+ client = (struct xf_client *)file->private_data;
+ if (!client)
+ return ERR_PTR(-EINVAL);
- if (decode_info.in_buf_size > INPUT_BUF_SIZE ||
- decode_info.out_buf_size != OUTPUT_BUF_SIZE) {
- dev_err(dev, "param error\n");
- return -EINVAL;
- }
+ id = client->id;
+ if (id >= XF_CFG_MAX_IPC_CLIENTS)
+ return ERR_PTR(-EINVAL);
- if (decode_info.in_buf_off == 0) {
- ret = copy_from_user(process_info->in_buf_virt,
- (void __user *)decode_info.in_buf_addr,
- decode_info.in_buf_size);
- if (ret) {
- dev_err(dev, "failed to copy from user\n");
- return -EFAULT;
- }
- codec_iobuf_info->inp_cur_offset = 0;
- }
-
- codec_iobuf_info->inp_addr_sysram = process_info->in_buf_phys;
- codec_iobuf_info->inp_buf_size_max = decode_info.in_buf_size;
- codec_iobuf_info->inp_cur_offset = decode_info.in_buf_off;
-
- codec_iobuf_info->out_addr_sysram = process_info->out_buf_phys;
- codec_iobuf_info->out_buf_size_max = process_info->out_buf_size;
- codec_iobuf_info->out_cur_offset = 0;
-
- codec_iobuf_info->input_over = decode_info.input_over;
- codec_iobuf_info->base_info.process_id = decode_info.process_id;
-
- init_completion(&hifi4_priv->cmd_complete);
- hifi4_priv->is_done = 0;
-
- apu_icm.allbits = 0; /* clear all bits; */
- apu_icm.ack = 0;
- apu_icm.intr = 1;
- apu_icm.msg = ICM_EMPTY_THIS_BUFFER;
- apu_icm.size = 8;
- ext_msg.phys = hifi4_priv->msg_buf_phys;
- ext_msg.size = sizeof(struct icm_cdc_iobuf_t);
-
- memcpy(hifi4_priv->msg_buf_virt, codec_iobuf_info,
- sizeof(struct icm_cdc_iobuf_t));
- icm_intr_extended_send(hifi4_priv, apu_icm.allbits, &ext_msg);
-
- /* wait for response here */
- ret = icm_ack_wait(hifi4_priv, apu_icm.allbits);
- if (ret)
- return ret;
-
- ret = copy_to_user((void __user *)decode_info.out_buf_addr,
- process_info->out_buf_virt,
- codec_iobuf_info->out_cur_offset);
- if (ret) {
- dev_err(dev, "failed to copy to user\n");
- return -EFAULT;
- }
-
- decode_info.in_buf_off = codec_iobuf_info->inp_cur_offset;
- decode_info.out_buf_off = codec_iobuf_info->out_cur_offset;
-
- ret = put_decode_info_compat32(&decode_info, user);
- if (ret) {
- dev_err(dev, "failed to send para to user space in compat32 mode\n");
- return ret;
- }
-
- ret = hifi4_priv->ret_status;
- return ret;
+ return client;
}
-#endif
-static long fsl_hifi4_get_pcm_prop(struct fsl_hifi4 *hifi4_priv,
- void __user *user)
+static int fsl_dsp_client_register(struct xf_client *client)
{
- struct device *dev = hifi4_priv->dev;
- union icm_header_t apu_icm;
- struct hifi4_ext_msg ext_msg;
- struct icm_pcm_prop_t *pcm_prop_info = &hifi4_priv->pcm_prop_info;
- struct prop_info prop_info;
- long ret = 0;
-
- ret = copy_from_user(&prop_info, user, sizeof(prop_info));
- if (ret) {
- dev_err(dev, "failed to get para from user space\n");
- return -EFAULT;
- }
-
- init_completion(&hifi4_priv->cmd_complete);
- hifi4_priv->is_done = 0;
-
- apu_icm.allbits = 0; /* clear all bits;*/
- apu_icm.ack = 0;
- apu_icm.intr = 1;
- apu_icm.msg = ICM_GET_PCM_PROP;
- apu_icm.size = 8;
-
- ext_msg.phys = hifi4_priv->msg_buf_phys;
- ext_msg.size = sizeof(struct icm_pcm_prop_t);
-
- pcm_prop_info->base_info.process_id = prop_info.process_id;
-
- memcpy(hifi4_priv->msg_buf_virt, pcm_prop_info,
- sizeof(struct icm_pcm_prop_t));
- icm_intr_extended_send(hifi4_priv, apu_icm.allbits, &ext_msg);
-
- /* wait for response here */
- ret = icm_ack_wait(hifi4_priv, apu_icm.allbits);
- if (ret)
- return ret;
-
- prop_info.samplerate = pcm_prop_info->sfreq;
- prop_info.channels = pcm_prop_info->channels;
- prop_info.bits = pcm_prop_info->bits;
- prop_info.consumed_bytes = pcm_prop_info->consumed_bytes;
- prop_info.cycles = pcm_prop_info->cycles;
-
- ret = copy_to_user(user, &prop_info, sizeof(prop_info));
- if (ret) {
- dev_err(dev, "failed to send para to user space\n");
- return -EFAULT;
- }
-
- ret = hifi4_priv->ret_status;
- return ret;
-}
+ struct fsl_hifi4 *hifi4_priv;
+ struct device *dev;
-static int fsl_hifi4_set_config(struct fsl_hifi4 *hifi4_priv, void __user *user)
-{
- struct device *dev = hifi4_priv->dev;
- union icm_header_t apu_icm;
- struct hifi4_ext_msg ext_msg;
- struct prop_config prop_config;
- struct icm_prop_config icm_prop_config;
- int ret;
+ hifi4_priv = (struct fsl_hifi4 *)client->global;
+ dev = hifi4_priv->dev;
- ret = copy_from_user(&prop_config, user, sizeof(prop_config));
- if (ret) {
- dev_err(dev, "failed to get para from user space: %d\n", ret);
- return -EFAULT;
+ /* ...make sure client is not registered yet */
+ if (client->proxy != NULL) {
+ pr_err("client-%x already registered", client->id);
+ return -EBUSY;
}
- init_completion(&hifi4_priv->cmd_complete);
- hifi4_priv->is_done = 0;
+ /* ...complete association (no communication with remote proxy here) */
+ client->proxy = &hifi4_priv->proxy;
- apu_icm.allbits = 0;
- apu_icm.ack = 0;
- apu_icm.intr = 1;
- apu_icm.msg = ICM_SET_PARA_CONFIG;
- apu_icm.size = 8;
+ pr_debug("client-%x registered within proxy", client->id);
- ext_msg.phys = hifi4_priv->msg_buf_phys;
- ext_msg.size = sizeof(struct icm_prop_config);
-
- icm_prop_config.base_info.process_id = prop_config.process_id;
- icm_prop_config.cmd = prop_config.cmd;
- icm_prop_config.val = prop_config.val;
-
- memcpy(hifi4_priv->msg_buf_virt, &icm_prop_config,
- sizeof(struct icm_prop_config));
- icm_intr_extended_send(hifi4_priv, apu_icm.allbits, &ext_msg);
-
- icm_ack_wait(hifi4_priv, apu_icm.allbits);
- if (ret)
- return ret;
-
- ret = hifi4_priv->ret_status;
-
- return ret;
+ return 0;
}
-static long fsl_hifi4_load_codec(struct fsl_hifi4 *hifi4_priv,
- void __user *user)
+/* ...unregister client from shared memory interface */
+static int fsl_dsp_client_unregister(struct xf_client *client)
{
- struct device *dev = hifi4_priv->dev;
- struct filename *fpInfile;
- union icm_header_t apu_icm;
- struct binary_info binary_info;
- struct hifi4_ext_msg ext_msg;
- struct icm_xtlib_pil_info icm_xtlib_pil_info;
- long ret = 0;
- long id;
-
- ret = copy_from_user(&binary_info, user, sizeof(binary_info));
- if (ret) {
- dev_err(dev, "failed to get para from user space\n");
- return -EFAULT;
- }
+ struct xf_proxy *proxy = client->proxy;
- fpInfile = getname(binary_info.file);
- if (IS_ERR(fpInfile)) {
- dev_err(dev, "failed to getname(), err = %ld\n",
- PTR_ERR(fpInfile));
- return PTR_ERR(fpInfile);
+ /* ...make sure client is registered */
+ if (proxy == NULL) {
+ pr_err("client-%x is not registered", client->id);
+ return -EBUSY;
}
- id = binary_info.process_id;
-
- hifi4_priv->process_info[id].objfile = fpInfile;
- hifi4_priv->process_info[id].objtype = binary_info.type;
- hifi4_priv->process_info[id].codec_id = binary_info.type;
- ret = load_dpu_with_library(hifi4_priv, &hifi4_priv->process_info[id]);
- if (ret) {
- dev_err(dev, "failed to load code binary, err = %ld\n", ret);
- return ret;
- }
-
- init_completion(&hifi4_priv->cmd_complete);
- hifi4_priv->is_done = 0;
-
- apu_icm.allbits = 0; /* clear all bits;*/
- apu_icm.ack = 0;
- apu_icm.intr = 1;
- apu_icm.msg = ICM_PI_LIB_LOAD;
- apu_icm.size = 8;
-
- ext_msg.phys = hifi4_priv->msg_buf_phys;
- ext_msg.size = sizeof(struct icm_xtlib_pil_info);
- memcpy(&icm_xtlib_pil_info.pil_info,
- &hifi4_priv->process_info[id].pil_info,
- sizeof(struct xtlib_pil_info));
- icm_xtlib_pil_info.process_id = id;
- icm_xtlib_pil_info.lib_type = binary_info.lib_type;
+ /* ...just clean proxy reference */
+ client->proxy = NULL;
- memcpy(hifi4_priv->msg_buf_virt, &icm_xtlib_pil_info,
- sizeof(struct icm_xtlib_pil_info));
- icm_intr_extended_send(hifi4_priv, apu_icm.allbits, &ext_msg);
+ pr_debug("client-%x registered within proxy", client->id);
- /* wait for response here */
- ret = icm_ack_wait(hifi4_priv, apu_icm.allbits);
- if (ret)
- return ret;
-
- ret = hifi4_priv->ret_status;
-
- dev_dbg(dev, "code binary is loaded\n");
-
- return ret;
-}
-
-#ifdef CONFIG_COMPAT
-static long fsl_hifi4_load_codec_compat32(struct fsl_hifi4 *hifi4_priv,
- void __user *user)
-{
- struct device *dev = hifi4_priv->dev;
- struct filename *fpInfile;
- union icm_header_t apu_icm;
- struct binary_info binary_info;
- struct hifi4_ext_msg ext_msg;
- struct icm_xtlib_pil_info icm_xtlib_pil_info;
- long ret = 0;
- long id;
-
- ret = get_binary_info_compat32(&binary_info, user);
- if (ret) {
- dev_err(dev, "failed to get para from user space in compat32 mode\n");
- return ret;
- }
-
- fpInfile = getname(binary_info.file);
- if (IS_ERR(fpInfile)) {
- dev_err(dev, "failed to getname(), err = %ld\n",
- PTR_ERR(fpInfile));
- return PTR_ERR(fpInfile);
- }
- id = binary_info.process_id;
-
- hifi4_priv->process_info[id].objfile = fpInfile;
- hifi4_priv->process_info[id].objtype = binary_info.type;
- hifi4_priv->process_info[id].codec_id = binary_info.type;
- ret = load_dpu_with_library(hifi4_priv, &hifi4_priv->process_info[id]);
- if (ret) {
- dev_err(dev, "failed to load code binary, err = %ld\n", ret);
- return ret;
- }
-
- init_completion(&hifi4_priv->cmd_complete);
- hifi4_priv->is_done = 0;
-
- apu_icm.allbits = 0; /* clear all bits; */
- apu_icm.ack = 0;
- apu_icm.intr = 1;
- apu_icm.msg = ICM_PI_LIB_LOAD;
- apu_icm.size = 8;
-
- ext_msg.phys = hifi4_priv->msg_buf_phys;
- ext_msg.size = sizeof(struct icm_xtlib_pil_info);
-
- memcpy(&icm_xtlib_pil_info.pil_info,
- &hifi4_priv->process_info[id].pil_info,
- sizeof(struct xtlib_pil_info));
- icm_xtlib_pil_info.process_id = id;
- icm_xtlib_pil_info.lib_type = binary_info.lib_type;
-
- memcpy(hifi4_priv->msg_buf_virt, &icm_xtlib_pil_info,
- sizeof(struct icm_xtlib_pil_info));
- icm_intr_extended_send(hifi4_priv, apu_icm.allbits, &ext_msg);
-
- /* wait for response here */
- ret = icm_ack_wait(hifi4_priv, apu_icm.allbits);
- if (ret)
- return ret;
-
- ret = hifi4_priv->ret_status;
-
- dev_dbg(dev, "code binary is loaded\n");
-
- return ret;
+ return 0;
}
-#endif
-static long fsl_hifi4_codec_open(struct fsl_hifi4 *hifi4_priv,
+static int fsl_dsp_ipc_msg_to_dsp(struct xf_client *client,
void __user *user)
{
+ struct fsl_hifi4 *hifi4_priv = (struct fsl_hifi4 *)client->global;
struct device *dev = hifi4_priv->dev;
- union icm_header_t apu_icm;
- struct hifi4_ext_msg ext_msg;
- struct icm_base_info_t icm_base_info_t;
- struct icm_process_info *process_info;
- int id;
- long ret = 0;
+ struct xf_proxy_message msg;
+ void *buffer;
+ unsigned long ret = 0;
- ret = copy_from_user(&id, user, sizeof(int));
+ ret = copy_from_user(&msg, user, sizeof(struct xf_proxy_message));
if (ret) {
- dev_err(dev, "failed to get para from user space\n");
+ dev_err(dev, "failed to get message from user space\n");
return -EFAULT;
}
- process_info = &hifi4_priv->process_info[id];
-
- init_completion(&hifi4_priv->cmd_complete);
- hifi4_priv->is_done = 0;
-
- apu_icm.allbits = 0; /* clear all bits;*/
- apu_icm.ack = 0;
- apu_icm.intr = 1;
- apu_icm.msg = ICM_OPEN;
- apu_icm.size = 8;
-
- ext_msg.phys = hifi4_priv->msg_buf_phys;
- ext_msg.size = sizeof(struct icm_base_info_t);
-
- memset(&icm_base_info_t, 0, sizeof(struct icm_base_info_t));
- icm_base_info_t.process_id = id;
-
- memcpy(hifi4_priv->msg_buf_virt, &icm_base_info_t,
- sizeof(struct icm_base_info_t));
- icm_intr_extended_send(hifi4_priv, apu_icm.allbits, &ext_msg);
-
- /* wait for response here */
- ret = icm_ack_wait(hifi4_priv, apu_icm.allbits);
- if (ret)
- return ret;
-
- ret = hifi4_priv->ret_status;
-
- return ret;
-}
-
-static int fsl_hifi4_codec_close(struct fsl_hifi4 *hifi4_priv,
- void __user *user)
-{
- struct device *dev = hifi4_priv->dev;
- union icm_header_t apu_icm;
- struct hifi4_ext_msg ext_msg;
- struct icm_base_info_t icm_base_info_t;
- int id;
- long ret = 0;
-
- ret = copy_from_user(&id, user, sizeof(int));
- if (ret) {
- dev_err(dev, "failed to get para from user space\n");
+ /* ...make sure message pointer is sane */
+ buffer = xf_proxy_a2b(&hifi4_priv->proxy, msg.address);
+ if (buffer == (void *)-1)
return -EFAULT;
- }
-
- init_completion(&hifi4_priv->cmd_complete);
- hifi4_priv->is_done = 0;
-
- apu_icm.allbits = 0; /* clear all bits;*/
- apu_icm.ack = 0;
- apu_icm.intr = 1;
- apu_icm.msg = ICM_CLOSE;
- apu_icm.size = 8;
- ext_msg.phys = hifi4_priv->msg_buf_phys;
- ext_msg.size = sizeof(struct icm_base_info_t);
-
- memset(&icm_base_info_t, 0, sizeof(struct icm_base_info_t));
- icm_base_info_t.process_id = id;
-
- memcpy(hifi4_priv->msg_buf_virt, &icm_base_info_t,
- sizeof(struct icm_base_info_t));
- icm_intr_extended_send(hifi4_priv, apu_icm.allbits, &ext_msg);
-
- /* wait for response here */
- ret = icm_ack_wait(hifi4_priv, apu_icm.allbits);
- if (ret)
- return ret;
+ /* ...put current proxy client into message session id */
+ msg.session_id = XF_MSG_AP_FROM_USER(msg.session_id, client->id);
- ret = hifi4_priv->ret_status;
+ xf_cmd_send(&hifi4_priv->proxy,
+ msg.session_id,
+ msg.opcode,
+ buffer,
+ msg.length);
- return ret;
+ return 0;
}
-static int fsl_hifi4_codec_reset(struct fsl_hifi4 *hifi4_priv,
+static int fsl_dsp_ipc_msg_from_dsp(struct xf_client *client,
void __user *user)
{
+ struct fsl_hifi4 *hifi4_priv = (struct fsl_hifi4 *)client->global;
struct device *dev = hifi4_priv->dev;
- union icm_header_t apu_icm;
- struct hifi4_ext_msg ext_msg;
- struct icm_cdc_iobuf_t *codec_iobuf_info =
- &hifi4_priv->codec_iobuf_info;
- struct icm_base_info_t icm_base_info_t;
- int id;
- long err = 0;
+ struct xf_message *m;
+ struct xf_proxy_message msg;
unsigned long ret = 0;
- ret = copy_from_user(&id, user, sizeof(int));
- if (ret) {
- dev_err(dev, "failed to get para from user space\n");
- return -EFAULT;
+ m = xf_cmd_recv(&hifi4_priv->proxy, &client->wait, &client->queue, 0);
+ if (IS_ERR(m)) {
+ dev_err(dev, "receiving failed: %d", (int)PTR_ERR(m));
+ return PTR_ERR(m);
}
- init_completion(&hifi4_priv->cmd_complete);
- hifi4_priv->is_done = 0;
-
- apu_icm.allbits = 0; /* clear all bits;*/
- apu_icm.ack = 0;
- apu_icm.intr = 1;
- apu_icm.msg = ICM_RESET;
- apu_icm.size = 8;
-
- ext_msg.phys = hifi4_priv->msg_buf_phys;
- ext_msg.size = sizeof(struct icm_base_info_t);
-
- memset(&icm_base_info_t, 0, sizeof(struct icm_base_info_t));
- icm_base_info_t.process_id = id;
-
- memcpy(hifi4_priv->msg_buf_virt, &icm_base_info_t,
- sizeof(struct icm_base_info_t));
- icm_intr_extended_send(hifi4_priv, apu_icm.allbits, &ext_msg);
-
- /* wait for response here */
- err = icm_ack_wait(hifi4_priv, apu_icm.allbits);
- if (err)
- return err;
+ /* ...check if there is a response available */
+ if (m == NULL)
+ return -EAGAIN;
- /* reset codec_iobuf_info */
- codec_iobuf_info->inp_buf_size_max = 0;
- codec_iobuf_info->inp_cur_offset = 0;
+ /* ...prepare message parameters (lock is taken) */
+ msg.session_id = XF_MSG_AP_TO_USER(m->id);
+ msg.opcode = m->opcode;
+ msg.length = m->length;
+ msg.address = xf_proxy_b2a(&hifi4_priv->proxy, m->buffer);
+ msg.ret = m->ret;
- codec_iobuf_info->out_buf_size_max = 0;
- codec_iobuf_info->out_cur_offset = 0;
+ /* ...return the message back to a pool and release lock */
+ xf_msg_free(&hifi4_priv->proxy, m);
- err = hifi4_priv->ret_status;
-
- return err;
-}
-
-static int fsl_hifi4_client_register(struct fsl_hifi4 *hifi4_priv,
- void __user *user)
-{
- struct device *dev = hifi4_priv->dev;
- int id, i;
- unsigned long ret = 0;
-
- for (i = 0; i < MULTI_CODEC_NUM; i++) {
- if (hifi4_priv->process_info[i].used == 0) {
- hifi4_priv->process_info[i].used = 1;
- id = i;
- break;
- }
- }
- if (i >= MULTI_CODEC_NUM) {
- dev_err(dev, "out of range of multi codec max number\n");
- return -EINVAL;
- }
-
- ret = copy_to_user(user, &id, sizeof(int));
+ ret = copy_to_user(user, &msg, sizeof(struct xf_proxy_message));
if (ret) {
- dev_err(dev, "failed to send para to user space\n");
+ dev_err(dev, "failed to response message to user space\n");
return -EFAULT;
}
return 0;
}
-static int fsl_hifi4_client_unregister(struct fsl_hifi4 *hifi4_priv,
+static int fsl_dsp_get_shmem_info(struct xf_client *client,
void __user *user)
{
+ struct fsl_hifi4 *hifi4_priv = (struct fsl_hifi4 *)client->global;
struct device *dev = hifi4_priv->dev;
- struct icm_process_info *process_info;
- int id, i;
+ struct shmem_info mem_info;
unsigned long ret = 0;
- ret = copy_from_user(&id, user, sizeof(int));
+ mem_info.phys_addr = hifi4_priv->scratch_buf_phys;
+ mem_info.size = hifi4_priv->scratch_buf_size;
+
+ ret = copy_to_user(user, &mem_info, sizeof(struct shmem_info));
if (ret) {
- dev_err(dev, "failed to get para from user space\n");
+ dev_err(dev, "failed to response message to user space\n");
return -EFAULT;
}
- if (id >= MULTI_CODEC_NUM) {
- dev_err(dev, "invalid process id from user space\n");
- return -EINVAL;
- }
-
- process_info = &hifi4_priv->process_info[id];
-
- /* free buffers which are occupied by this process */
- for (i = 0; i < process_info->alloc_count; i++) {
- hifi4_buf_free(hifi4_priv,
- process_info->array_alloc_mem[i]);
- process_info->array_alloc_mem[i] = 0;
- }
-
- memset(process_info, 0, sizeof(struct icm_process_info));
-
- return 0;
+ return ret;
}
static struct miscdevice hifi4_miscdev = {
@@ -1498,120 +281,46 @@ static struct miscdevice hifi4_miscdev = {
static long fsl_hifi4_ioctl(struct file *file, unsigned int cmd,
unsigned long arg)
{
- struct fsl_hifi4_engine *hifi4_engine;
+ struct xf_client *client;
struct fsl_hifi4 *hifi4_priv;
+ struct xf_proxy *proxy;
struct device *dev;
void __user *user;
long ret = 0;
- hifi4_engine = file->private_data;
- hifi4_priv = hifi4_engine->hifi4_priv;
+ /* ...basic sanity checks */
+ client = xf_get_client(file);
+ if (IS_ERR(client))
+ return PTR_ERR(client);
+
+ hifi4_priv = (struct fsl_hifi4 *)client->global;
+ proxy = &hifi4_priv->proxy;
dev = hifi4_priv->dev;
user = (void __user *)arg;
- if (!hifi4_priv->is_ready) {
- dev_err(dev, "hifi firmware is not ready\n");
- return -EFAULT;
- }
-
mutex_lock(&hifi4_priv->hifi4_mutex);
- switch (cmd) {
- case HIFI4_CLIENT_REGISTER:
- ret = fsl_hifi4_client_register(hifi4_priv, user);
- break;
- case HIFI4_CLIENT_UNREGISTER:
- ret = fsl_hifi4_client_unregister(hifi4_priv, user);
- break;
- case HIFI4_LOAD_CODEC:
- ret = fsl_hifi4_load_codec(hifi4_priv, user);
- break;
- case HIFI4_INIT_CODEC:
- ret = fsl_hifi4_init_codec(hifi4_priv, user);
- break;
- case HIFI4_CODEC_OPEN:
- ret = fsl_hifi4_codec_open(hifi4_priv, user);
- break;
- case HIFI4_DECODE_ONE_FRAME:
- ret = fsl_hifi4_decode_frame(hifi4_priv, user);
- break;
- case HIFI4_CODEC_CLOSE:
- ret = fsl_hifi4_codec_close(hifi4_priv, user);
- break;
- case HIFI4_UNLOAD_CODEC:
- break;
- case HIFI4_GET_PCM_PROP:
- ret = fsl_hifi4_get_pcm_prop(hifi4_priv, user);
- break;
- case HIFI4_SET_CONFIG:
- ret = fsl_hifi4_set_config(hifi4_priv, user);
- break;
- case HIFI4_RESET_CODEC:
- ret = fsl_hifi4_codec_reset(hifi4_priv, user);
- break;
- default:
- break;
- }
-
- mutex_unlock(&hifi4_priv->hifi4_mutex);
-
- return ret;
-}
-
-#ifdef CONFIG_COMPAT
-static long fsl_hifi4_compat_ioctl(struct file *file, unsigned int cmd,
- unsigned long arg)
-{
- struct fsl_hifi4_engine *hifi4_engine;
- struct fsl_hifi4 *hifi4_priv;
- struct device *dev;
- void __user *user;
- long ret = 0;
-
- hifi4_engine = file->private_data;
- hifi4_priv = hifi4_engine->hifi4_priv;
- dev = hifi4_priv->dev;
- user = compat_ptr(arg);
-
- if (!hifi4_priv->is_ready) {
+ if (!proxy->is_ready) {
+ mutex_unlock(&hifi4_priv->hifi4_mutex);
dev_err(dev, "hifi firmware is not ready\n");
return -EFAULT;
}
- mutex_lock(&hifi4_priv->hifi4_mutex);
-
switch (cmd) {
- case HIFI4_CLIENT_REGISTER:
- ret = fsl_hifi4_client_register(hifi4_priv, user);
- break;
- case HIFI4_CLIENT_UNREGISTER:
- ret = fsl_hifi4_client_unregister(hifi4_priv, user);
- break;
- case HIFI4_LOAD_CODEC:
- ret = fsl_hifi4_load_codec_compat32(hifi4_priv, user);
- break;
- case HIFI4_INIT_CODEC:
- ret = fsl_hifi4_init_codec(hifi4_priv, user);
+ case DSP_CLIENT_REGISTER:
+ ret = fsl_dsp_client_register(client);
break;
- case HIFI4_CODEC_OPEN:
- ret = fsl_hifi4_codec_open(hifi4_priv, user);
+ case DSP_CLIENT_UNREGISTER:
+ ret = fsl_dsp_client_unregister(client);
break;
- case HIFI4_DECODE_ONE_FRAME:
- ret = fsl_hifi4_decode_frame_compat32(hifi4_priv, user);
+ case DSP_IPC_MSG_SEND:
+ ret = fsl_dsp_ipc_msg_to_dsp(client, user);
break;
- case HIFI4_CODEC_CLOSE:
- ret = fsl_hifi4_codec_close(hifi4_priv, user);
+ case DSP_IPC_MSG_RECV:
+ ret = fsl_dsp_ipc_msg_from_dsp(client, user);
break;
- case HIFI4_UNLOAD_CODEC:
- break;
- case HIFI4_GET_PCM_PROP:
- ret = fsl_hifi4_get_pcm_prop(hifi4_priv, user);
- break;
- case HIFI4_SET_CONFIG:
- ret = fsl_hifi4_set_config(hifi4_priv, user);
- break;
- case HIFI4_RESET_CODEC:
- ret = fsl_hifi4_codec_reset(hifi4_priv, user);
+ case DSP_GET_SHMEM_INFO:
+ ret = fsl_dsp_get_shmem_info(client, user);
break;
default:
break;
@@ -1621,49 +330,62 @@ static long fsl_hifi4_compat_ioctl(struct file *file, unsigned int cmd,
return ret;
}
-#endif
void resource_release(struct fsl_hifi4 *hifi4_priv)
{
int i;
- for (i = 0; i < MULTI_CODEC_NUM; i++)
- memset(&hifi4_priv->process_info[i], 0,
- sizeof(struct icm_process_info));
+ /* ...initialize client association map */
+ for (i = 0; i < XF_CFG_MAX_IPC_CLIENTS - 1; i++)
+ hifi4_priv->xf_client_map[i].next = i + 1;
+ /* ...set list terminator */
+ hifi4_priv->xf_client_map[i].next = 0;
- if (hifi4_priv->is_ready)
- send_dpu_ext_msg_addr(hifi4_priv);
+ /* ...set pointer to shared memory */
+ xf_proxy_init(&hifi4_priv->proxy);
}
static int fsl_hifi4_open(struct inode *inode, struct file *file)
{
- struct fsl_hifi4 *hifi4_priv;
- struct device *dev;
- struct fsl_hifi4_engine *hifi4_engine;
+ struct fsl_hifi4 *hifi4_priv = dev_get_drvdata(hifi4_miscdev.parent);
+ struct device *dev = hifi4_priv->dev;
+ struct xf_client *client;
int ret = 0;
- hifi4_priv = dev_get_drvdata(hifi4_miscdev.parent);
- dev = hifi4_priv->dev;
+ /* ...basic sanity checks */
+ if (!inode || !file)
+ return -EINVAL;
- pm_runtime_get_sync(dev);
- mutex_lock(&hifi4_priv->hifi4_mutex);
+ /* ...allocate new proxy client object */
+ client = xf_client_alloc(hifi4_priv);
+ if (IS_ERR(client))
+ return PTR_ERR(client);
- hifi4_engine = devm_kzalloc(dev,
- sizeof(struct fsl_hifi4_engine), GFP_KERNEL);
- if (!hifi4_engine) {
- mutex_unlock(&hifi4_priv->hifi4_mutex);
- return -ENOMEM;
- }
+ /* ...initialize waiting queue */
+ init_waitqueue_head(&client->wait);
+
+ /* ...initialize client pending message queue */
+ xf_msg_queue_init(&client->queue);
+
+ /* ...mark user data is not mapped */
+ client->vm_start = 0;
+
+ /* ...reset mappings counter */
+ atomic_set(&client->vm_use, 0);
+
+ client->global = (void *)hifi4_priv;
- hifi4_engine->hifi4_priv = hifi4_priv;
+ file->private_data = (void *)client;
- file->private_data = hifi4_engine;
+ pm_runtime_get_sync(dev);
+ mutex_lock(&hifi4_priv->hifi4_mutex);
/* increase reference counter when opening device */
atomic_long_inc(&hifi4_priv->refcnt);
-
mutex_unlock(&hifi4_priv->hifi4_mutex);
+ pr_info("client-%x created\n", client->id);
+
return ret;
}
@@ -1671,15 +393,30 @@ static int fsl_hifi4_close(struct inode *inode, struct file *file)
{
struct fsl_hifi4 *hifi4_priv;
struct device *dev;
- struct fsl_hifi4_engine *hifi4_engine;
+ struct xf_proxy *proxy;
+ struct xf_client *client;
- hifi4_priv = dev_get_drvdata(hifi4_miscdev.parent);
- mutex_lock(&hifi4_priv->hifi4_mutex);
+ /* ...basic sanity checks */
+ client = xf_get_client(file);
+ if (IS_ERR(client))
+ return PTR_ERR(client);
+
+ pr_info("client-%x released\n", client->id);
+
+ proxy = client->proxy;
+ if (proxy) {
+ /* ...release all pending messages */
+ xf_msg_free_all(proxy, &client->queue);
+
+ /* ...recycle client id and release memory */
+ xf_client_free(client);
+ }
+ hifi4_priv = (struct fsl_hifi4 *)client->global;
dev = hifi4_priv->dev;
- hifi4_engine = file->private_data;
- devm_kfree(dev, hifi4_engine);
+ pm_runtime_put_sync(dev);
+ mutex_lock(&hifi4_priv->hifi4_mutex);
/* decrease reference counter when closing device */
atomic_long_dec(&hifi4_priv->refcnt);
/* If device is free, reinitialize the resource of
@@ -1689,11 +426,123 @@ static int fsl_hifi4_close(struct inode *inode, struct file *file)
resource_release(hifi4_priv);
mutex_unlock(&hifi4_priv->hifi4_mutex);
- pm_runtime_put_sync(dev);
return 0;
}
+/* ...wait until data is available in the response queue */
+static unsigned int fsl_hifi4_poll(struct file *file, poll_table *wait)
+{
+ struct xf_proxy *proxy;
+ struct xf_client *client;
+ int mask;
+
+ /* ...basic sanity checks */
+ client = xf_get_client(file);
+ if (IS_ERR(client))
+ return PTR_ERR(client);
+
+ /* ...get proxy interface */
+ proxy = client->proxy;
+ if (!proxy)
+ return -EPERM;
+
+ /* ...register client waiting queue */
+ poll_wait(file, &client->wait, wait);
+
+ /* ...return current queue state */
+ mask = (xf_msg_queue_head(&client->queue) ? POLLIN | POLLRDNORM : 0);
+
+ return mask;
+}
+
+/*******************************************************************************
+ * Low-level mmap interface
+ ******************************************************************************/
+
+/* ...add reference to shared buffer */
+static void hifi4_mmap_open(struct vm_area_struct *vma)
+{
+ struct xf_client *client = vma->vm_private_data;
+
+ /* ...probably just increase counter of open references? - tbd */
+ atomic_inc(&client->vm_use);
+
+ pr_debug("xf_mmap_open: vma = %p, client = %p", vma, client);
+}
+
+/* ...close reference to shared buffer */
+static void hifi4_mmap_close(struct vm_area_struct *vma)
+{
+ struct xf_client *client = vma->vm_private_data;
+
+ pr_debug("xf_mmap_close: vma = %p, b = %p", vma, client);
+
+ /* ...decrement number of mapping */
+ atomic_dec_return(&client->vm_use);
+}
+
+/* ...memory map operations */
+static const struct vm_operations_struct hifi4_mmap_ops = {
+ .open = hifi4_mmap_open,
+ .close = hifi4_mmap_close,
+};
+
+/* ...shared memory mapping */
+static int fsl_hifi4_mmap(struct file *file, struct vm_area_struct *vma)
+{
+ struct xf_proxy *proxy;
+ struct xf_client *client;
+ unsigned long size;
+ unsigned long pfn;
+ int r;
+ struct fsl_hifi4 *hifi4_priv;
+
+ /* ...basic sanity checks */
+ client = xf_get_client(file);
+ if (IS_ERR(client))
+ return PTR_ERR(client);
+
+ /* ...get proxy interface */
+ proxy = client->proxy;
+ if (!proxy)
+ return -EPERM;
+
+ /* ...check it was not mapped already */
+ if (client->vm_start != 0)
+ return -EBUSY;
+
+ /* ...check mapping flags (tbd) */
+ if ((vma->vm_flags & (VM_READ | VM_WRITE | VM_SHARED))
+ != (VM_READ | VM_WRITE | VM_SHARED))
+ return -EPERM;
+
+ /* ...set memory map operations */
+ vma->vm_ops = &hifi4_mmap_ops;
+
+ /* ...assign private data */
+ client->vm_start = vma->vm_start;
+
+ /* ...set private memory data */
+ vma->vm_private_data = client;
+
+ /* ...set page number of shared memory */
+ hifi4_priv = (struct fsl_hifi4 *)client->global;
+ pfn = hifi4_priv->scratch_buf_phys >> PAGE_SHIFT;
+ size = hifi4_priv->scratch_buf_size;
+
+ /* ...remap shared memory to user-space */
+ vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
+ r = remap_pfn_range(vma, vma->vm_start, pfn, size, vma->vm_page_prot);
+ if (r != 0) {
+ pr_err("mapping failed: %d", r);
+ return r;
+ }
+
+ /* ...system-specific hook for registering shared memory mapping */
+ return 0;
+}
+
void *memset_hifi(void *dest, int c, size_t count)
{
uint *dl = (uint *)dest;
@@ -1761,278 +610,6 @@ void *memcpy_hifi(void *dest, const void *src, size_t count)
return dest;
}
-u32 icm_intr_send(struct fsl_hifi4 *hifi4_priv, u32 msg)
-{
- MU_SendMessage(hifi4_priv->mu_base_virtaddr, 0, msg);
- return 0;
-}
-
-u32 icm_intr_extended_send(struct fsl_hifi4 *hifi4_priv, u32 msg,
- struct hifi4_ext_msg *ext_msg)
-{
- struct device *dev = hifi4_priv->dev;
- union icm_header_t lmsg;
-
- lmsg.allbits = msg;
- if (lmsg.size != 8)
- dev_err(dev, "too much ext msg\n");
-
- MU_SendMessage(hifi4_priv->mu_base_virtaddr, 1, ext_msg->phys);
- MU_SendMessage(hifi4_priv->mu_base_virtaddr, 2, ext_msg->size);
- MU_SendMessage(hifi4_priv->mu_base_virtaddr, 0, msg);
-
- return 0;
-}
-
-long icm_ack_wait(struct fsl_hifi4 *hifi4_priv, u32 msg)
-{
- struct device *dev = hifi4_priv->dev;
- union icm_header_t ref_msg;
- int err;
-
- ref_msg.allbits = msg;
- /* wait response from mu */
- err = wait_for_completion_timeout(&hifi4_priv->cmd_complete,
- msecs_to_jiffies(1000));
- if (!err) {
- dev_err(dev, "icm ack timeout! %x\n", msg);
- return -ETIMEDOUT;
- }
-
- dev_dbg(dev, "Ack recd for message 0x%08x\n", ref_msg.allbits);
-
- return 0;
-}
-
-int process_act_complete(struct fsl_hifi4 *hifi4_priv, u32 msg)
-{
- union icm_header_t recd_msg;
- u32 ext_msg_addr;
- u32 ext_msg_size = 0;
- u32 *pmsg_apu = (u32 *) hifi4_priv->msg_buf_virt + 2048/4;
- struct icm_cdc_iobuf_t *codec_iobuf_info =
- &hifi4_priv->codec_iobuf_info;
- struct icm_pcm_prop_t *pcm_prop_info = &hifi4_priv->pcm_prop_info;
- struct icm_pilib_size_t *pilib_buffer_info =
- &hifi4_priv->pilib_buffer_info;
- int ret_val = 0;
-
- recd_msg.allbits = msg;
-
- if (recd_msg.size == 8) {
- MU_ReceiveMsg(hifi4_priv->mu_base_virtaddr, 1, &ext_msg_addr);
- MU_ReceiveMsg(hifi4_priv->mu_base_virtaddr, 2, &ext_msg_size);
- }
-
- switch (recd_msg.sub_msg) {
- case ICM_PI_LIB_MEM_ALLOC:
- {
- struct icm_pilib_size_t *pext_msg =
- (struct icm_pilib_size_t *)pmsg_apu;
- pilib_buffer_info->buffer_addr = pext_msg->buffer_addr;
- pilib_buffer_info->buffer_size = pext_msg->buffer_size;
- hifi4_priv->ret_status = pext_msg->ret;
- hifi4_priv->is_done = 1;
- complete(&hifi4_priv->cmd_complete);
- }
- break;
-
- case ICM_PI_LIB_MEM_FREE:
- {
- struct icm_pilib_size_t *pext_msg =
- (struct icm_pilib_size_t *)pmsg_apu;
- hifi4_priv->ret_status = pext_msg->ret;
- hifi4_priv->is_done = 1;
- complete(&hifi4_priv->cmd_complete);
- }
- break;
-
- case ICM_OPEN:
- {
- struct icm_base_info_t *ext_msg =
- (struct icm_base_info_t *)pmsg_apu;
- hifi4_priv->ret_status = ext_msg->ret;
- hifi4_priv->is_done = 1;
- complete(&hifi4_priv->cmd_complete);
- }
- break;
-
- case ICM_EMPTY_THIS_BUFFER:
- {
- struct icm_cdc_iobuf_t *ext_msg =
- (struct icm_cdc_iobuf_t *)pmsg_apu;
- codec_iobuf_info->inp_cur_offset =
- ext_msg->inp_cur_offset;
- codec_iobuf_info->out_cur_offset =
- ext_msg->out_cur_offset;
- hifi4_priv->ret_status = ext_msg->base_info.ret;
- hifi4_priv->is_done = 1;
- complete(&hifi4_priv->cmd_complete);
- }
- break;
-
- case ICM_GET_PCM_PROP:
- {
- struct icm_pcm_prop_t *ext_msg =
- (struct icm_pcm_prop_t *)pmsg_apu;
- pcm_prop_info->pcmbytes = ext_msg->pcmbytes;
- pcm_prop_info->sfreq = ext_msg->sfreq;
- pcm_prop_info->channels = ext_msg->channels;
- pcm_prop_info->bits = ext_msg->bits;
- pcm_prop_info->consumed_bytes =
- ext_msg->consumed_bytes;
- hifi4_priv->ret_status = ext_msg->base_info.ret;
-
- hifi4_priv->is_done = 1;
- complete(&hifi4_priv->cmd_complete);
- }
- break;
-
- case ICM_SET_PARA_CONFIG:
- {
- struct icm_prop_config *ext_msg =
- (struct icm_prop_config *)pmsg_apu;
- hifi4_priv->ret_status = ext_msg->base_info.ret;
- hifi4_priv->is_done = 1;
- complete(&hifi4_priv->cmd_complete);
- }
- break;
-
- case ICM_PI_LIB_INIT:
- {
- struct icm_base_info_t *ext_msg =
- (struct icm_base_info_t *)pmsg_apu;
- hifi4_priv->ret_status = ext_msg->ret;
- hifi4_priv->is_done = 1;
- complete(&hifi4_priv->cmd_complete);
- }
- break;
-
- case ICM_CLOSE:
- {
- struct icm_base_info_t *ext_msg =
- (struct icm_base_info_t *)pmsg_apu;
- hifi4_priv->ret_status = ext_msg->ret;
- hifi4_priv->is_done = 1;
- complete(&hifi4_priv->cmd_complete);
- }
- break;
-
- case ICM_PI_LIB_LOAD:
- {
- struct icm_base_info_t *ext_msg =
- (struct icm_base_info_t *)pmsg_apu;
- hifi4_priv->ret_status = ext_msg->ret;
- hifi4_priv->is_done = 1;
- complete(&hifi4_priv->cmd_complete);
- }
- break;
-
- case ICM_RESET:
- {
- struct icm_base_info_t *ext_msg =
- (struct icm_base_info_t *)pmsg_apu;
- hifi4_priv->ret_status = ext_msg->ret;
- hifi4_priv->is_done = 1;
- complete(&hifi4_priv->cmd_complete);
- }
- break;
- case ICM_CORE_EXIT:
- hifi4_priv->is_done = 1;
- complete(&hifi4_priv->cmd_complete);
- break;
- case ICM_SUSPEND:
- hifi4_priv->is_done = 1;
- complete(&hifi4_priv->cmd_complete);
- break;
- case ICM_RESUME:
- hifi4_priv->is_done = 1;
- complete(&hifi4_priv->cmd_complete);
- break;
- default:
- ret_val = -1;
- break;
- }
- return ret_val;
-}
-
-int send_dpu_ext_msg_addr(struct fsl_hifi4 *hifi4_priv)
-{
- union icm_header_t apu_icm;
- struct hifi4_ext_msg ext_msg;
- struct hifi4_mem_msg *dpu_ext_msg =
- (struct hifi4_mem_msg *)hifi4_priv->msg_buf_virt;
- int ret_val = 0;
-
- apu_icm.allbits = 0; /* clear all bits; */
- apu_icm.ack = 0;
- apu_icm.intr = 1;
- apu_icm.msg = ICM_EXT_MSG_ADDR;
- apu_icm.size = 8;
- ext_msg.phys = hifi4_priv->msg_buf_phys;
- /* 6 means element numbers that need to be transferred
- * in struct hifi4_mem_msg
- */
- ext_msg.size = 6*4; /* 6 * sizeof(int) */
- dpu_ext_msg->ext_msg_phys = hifi4_priv->msg_buf_phys + 2048;
- dpu_ext_msg->ext_msg_size = 2048;
- dpu_ext_msg->scratch_phys = hifi4_priv->scratch_buf_phys;
- dpu_ext_msg->scratch_size = hifi4_priv->scratch_buf_size;
- dpu_ext_msg->hifi_config_phys = hifi4_priv->hifi_config_phys;
- dpu_ext_msg->hifi_config_size = hifi4_priv->hifi_config_size;
-
- icm_intr_extended_send(hifi4_priv, apu_icm.allbits, &ext_msg);
-
- return ret_val;
-}
-
-static irqreturn_t fsl_hifi4_mu_isr(int irq, void *dev_id)
-{
- struct fsl_hifi4 *hifi4_priv = dev_id;
- struct device *dev = hifi4_priv->dev;
- union icm_header_t recd_msg;
- int ret_val;
- u32 reg;
-
- MU_ReceiveMsg(hifi4_priv->mu_base_virtaddr, 0, &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