From 4520379e9ce7b7b6eec76e83b555be8e0dc4ff2e Mon Sep 17 00:00:00 2001 From: Shengjiu Wang Date: Thu, 1 Jun 2017 15:17:01 +0800 Subject: [PATCH 01/78] MLK-14997-4: ASoC: fsl: add hifi4 dsp driver The function of driver is to communicate with hifi firmware. The mu13 is dedicated for hifi communication, driver allocate a share memory for message transfer between driver and firmware. The calling sequence is that LOAD_CODEC,INIT_CODEC,CODEC_OPEN, DECODE_ONE_FRAME, CODEC_CLOSE. Signed-off-by: Shengjiu Wang [ Aisheng: clean up for a new base ] Signed-off-by: Dong Aisheng --- sound/soc/fsl/Kconfig | 8 + sound/soc/fsl/Makefile | 2 + sound/soc/fsl/fsl_hifi4.c | 1439 +++++++++++++++++++++++++++++++++++++ sound/soc/fsl/fsl_hifi4.h | 281 ++++++++ 4 files changed, 1730 insertions(+) create mode 100644 sound/soc/fsl/fsl_hifi4.c create mode 100644 sound/soc/fsl/fsl_hifi4.h diff --git a/sound/soc/fsl/Kconfig b/sound/soc/fsl/Kconfig index aa99c008a925..c7b378c6d3f5 100644 --- a/sound/soc/fsl/Kconfig +++ b/sound/soc/fsl/Kconfig @@ -74,6 +74,14 @@ config SND_SOC_FSL_MICFIL Say Y if you want to add Pulse Density Modulation microphone interface (MICFIL) support for NXP. +config SND_SOC_FSL_HIFI4 + tristate "hifi 4 module support" + help + Say Y if you want to add hifi 4 support for the Freescale CPUs. + which is a DSP core for audio processing. + This option is only useful for out-of-tree drivers since + in-tree drivers select it automatically. + config SND_SOC_FSL_UTILS tristate diff --git a/sound/soc/fsl/Makefile b/sound/soc/fsl/Makefile index c0dd04422fe9..8f09c3cd5238 100644 --- a/sound/soc/fsl/Makefile +++ b/sound/soc/fsl/Makefile @@ -15,6 +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-sai-objs := fsl_sai.o snd-soc-fsl-ssi-y := fsl_ssi.o snd-soc-fsl-ssi-$(CONFIG_DEBUG_FS) += fsl_ssi_dbg.o @@ -27,6 +28,7 @@ snd-soc-fsl-dma-objs := fsl_dma.o obj-$(CONFIG_SND_SOC_FSL_AUDMIX) += snd-soc-fsl-audmix.o obj-$(CONFIG_SND_SOC_FSL_ASOC_CARD) += snd-soc-fsl-asoc-card.o obj-$(CONFIG_SND_SOC_FSL_ASRC) += snd-soc-fsl-asrc.o +obj-$(CONFIG_SND_SOC_FSL_HIFI4) += snd-soc-fsl-hifi4.o obj-$(CONFIG_SND_SOC_FSL_SAI) += snd-soc-fsl-sai.o obj-$(CONFIG_SND_SOC_FSL_SSI) += snd-soc-fsl-ssi.o obj-$(CONFIG_SND_SOC_FSL_SPDIF) += snd-soc-fsl-spdif.o diff --git a/sound/soc/fsl/fsl_hifi4.c b/sound/soc/fsl/fsl_hifi4.c new file mode 100644 index 000000000000..8e1d1e0cba05 --- /dev/null +++ b/sound/soc/fsl/fsl_hifi4.c @@ -0,0 +1,1439 @@ +/* + * Freescale HIFI 4 driver + * + * Copyright (c) 2012-2013 by Tensilica Inc. ALL RIGHTS RESERVED. + * Copyright (C) 2017 NXP. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "fsl_hifi4.h" + +long load_dpu_with_library(struct fsl_hifi4 *hifi4_priv) +{ + struct file *fpInfile; + unsigned char *srambuf = NULL; + struct lib_dnld_info_t dpulib; + int filesize = 0; + long ret_val = 0; + + /* Load DPU's main program to System memory */ + fpInfile = file_open_name(hifi4_priv->objfile, O_RDONLY, 0); + if (!fpInfile) + return -1; + + 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, 0, srambuf, filesize); + 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), + hifi4_priv); + if (ret_val != XTLIB_NO_ERR) + return ret_val; + + dpulib.pbuf_code = (unsigned long)hifi4_priv->code_buf_phys; + dpulib.pbuf_data = (unsigned long)hifi4_priv->data_buf_phys; + + dpulib.ppil_inf = &hifi4_priv->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 *)hifi4_priv); + + kfree(srambuf); + + return ret_val; +} + +Elf32_Half xtlib_host_half(Elf32_Half v, int byteswap) +{ + return (byteswap) ? (v >> 8) | (v << 8) : v; +} + +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 fsl_hifi4 *hifi4_priv) +{ + struct xtlib_loader_globals *xtlib_globals = &hifi4_priv->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 0; +} + +void xtlib_load_seg(Elf32_Phdr *pheader, void *src_addr, xt_ptr dst_addr, + memcpy_func mcpy, memset_func mset, + struct fsl_hifi4 *hifi4_priv) +{ + struct xtlib_loader_globals *xtlib_globals = &hifi4_priv->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); +} + +#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) +{ + return (xt_ptr)(((xt_uint)ptr + align - 1) & ~(align - 1)); +} + +static xt_ptr xt_ptr_offs(xt_ptr base, Elf32_Word offs, + struct fsl_hifi4 *hifi4_priv) +{ + struct xtlib_loader_globals *xtlib_globals = &hifi4_priv->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 fsl_hifi4 *hifi4_priv) +{ + char *base_addr = (char *)eheader; + struct xtlib_loader_globals *xtlib_globals = &hifi4_priv->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 fsl_hifi4 *hifi4_priv) +{ + struct xtlib_loader_globals *xtlib_globals = &hifi4_priv->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 fsl_hifi4 *hifi4_priv) +{ + struct xtlib_loader_globals *xtlib_globals = &hifi4_priv->xtlib_globals; + + if (xtlib_verify_magic(header, hifi4_priv) != 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 fsl_hifi4 *hifi4_priv) +{ + struct xtlib_loader_globals *xtlib_globals = &hifi4_priv->xtlib_globals; + Elf32_Phdr *pheader; + int err = validate_dynamic(header, hifi4_priv); + + 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 fsl_hifi4 *hifi4_priv) +{ + struct xtlib_loader_globals *xtlib_globals = &hifi4_priv->xtlib_globals; + Elf32_Phdr *pheader; + Elf32_Ehdr *header = (Elf32_Ehdr *) library; + int align; + int err = validate_dynamic_splitload(header, hifi4_priv); + + if (err != XTLIB_NO_ERR) { + xtlib_globals->err = err; + return err; + } + + align = find_align(header, hifi4_priv); + + 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 fsl_hifi4 *hifi4_priv) +{ + unsigned int jmprel = 0; + unsigned int pltrelsz = 0; + struct xtlib_loader_globals *xtlib_globals = &hifi4_priv->xtlib_globals; + Elf32_Dyn *dyn_entry = find_dynamic_info(eheader, hifi4_priv); + + 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, hifi4_priv); + + info->align = xtlib_xt_word(find_align(eheader, hifi4_priv), + 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, hifi4_priv); + 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, hifi4_priv); + break; + case DT_FINI: + info->fini = xt_ptr_offs(dst_addr, + dyn_entry->d_un.d_ptr, hifi4_priv); + break; + case DT_HASH: + info->hash = xt_ptr_offs(dst_data_addr, + dyn_entry->d_un.d_ptr, hifi4_priv); + break; + case DT_SYMTAB: + info->symtab = xt_ptr_offs(dst_data_addr, + dyn_entry->d_un.d_ptr, hifi4_priv); + break; + case DT_STRTAB: + info->strtab = xt_ptr_offs(dst_data_addr, + dyn_entry->d_un.d_ptr, hifi4_priv); + 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, hifi4_priv); + 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 fsl_hifi4 *hifi4_priv) +{ + struct xtlib_loader_globals *xtlib_globals = &hifi4_priv->xtlib_globals; + Elf32_Ehdr *header = (Elf32_Ehdr *) library; + Elf32_Phdr *pheader; + unsigned int align; + int err = validate_dynamic_splitload(header, hifi4_priv); + + if (err != XTLIB_NO_ERR) { + xtlib_globals->err = err; + return 0; + } + + align = find_align(header, hifi4_priv); + + destination_code_address = align_ptr(destination_code_address, align); + destination_data_address = align_ptr(destination_data_address, align); + + 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, + hifi4_priv); + + 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)hifi4_priv->code_buf_virt, + mcpy_fn, mset_fn, hifi4_priv); + + 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)hifi4_priv->data_buf_virt + + xtlib_host_word(pheader[1].p_paddr, + xtlib_globals->byteswap), + mcpy_fn, mset_fn, hifi4_priv); + + + 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 fsl_hifi4 *hifi4_priv) +{ + return xtlib_load_split_pi_library_common(library, + destination_code_address, + destination_data_address, + lib_info, + mcpy_fn, + mset_fn, + hifi4_priv); +} + + +static long fsl_hifi4_init_codec(struct fsl_hifi4 *hifi4_priv) +{ + union icm_header_t apu_icm; + struct hifi4_ext_msg ext_msg; + struct icm_pilib_size_t lib_alloc_mem; + long ret = 0; + + 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); + + lib_alloc_mem.codec_type = hifi4_priv->objtype; + + memcpy(hifi4_priv->msg_buf_virt, &lib_alloc_mem, + 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 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_INIT; + apu_icm.size = 8; + + ext_msg.phys = hifi4_priv->msg_buf_phys; + ext_msg.size = sizeof(struct xtlib_pil_info); + + memcpy(hifi4_priv->msg_buf_virt, &hifi4_priv->pil_info, + sizeof(struct 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; + + return 0; +} + +static long fsl_hifi4_decode_frame(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 decode_info decode_info; + struct icm_cdc_iobuf_t *codec_iobuf_info = + &hifi4_priv->codec_iobuf_info; + 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 ret; + } + + 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) { + memcpy(hifi4_priv->in_buf_virt, decode_info.in_buf_addr, + decode_info.in_buf_size); + codec_iobuf_info->inp_cur_offset = 0; + } + + codec_iobuf_info->inp_addr_sysram = hifi4_priv->in_buf_phys; + codec_iobuf_info->inp_buf_size_max = decode_info.in_buf_size; + + codec_iobuf_info->out_addr_sysram = hifi4_priv->out_buf_phys; + codec_iobuf_info->out_buf_size_max = hifi4_priv->out_buf_size; + codec_iobuf_info->out_cur_offset = 0; + + 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; + + memcpy(decode_info.out_buf_addr, hifi4_priv->out_buf_virt, + codec_iobuf_info->out_cur_offset); + + 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 ret; + } + + ret = hifi4_priv->ret_status; + return ret; +} + +static long fsl_hifi4_get_pcm_prop(struct fsl_hifi4 *hifi4_priv, + void __user *user) +{ + struct device *dev = hifi4_priv->dev; + union icm_header_t apu_icm; + 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 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_GET_PCM_PROP; + 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) + 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; + + ret = copy_to_user(user, &prop_info, sizeof(prop_info)); + if (ret) { + dev_err(dev, "failed to send para to user space\n"); + return ret; + } + + ret = hifi4_priv->ret_status; + return ret; +} + +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; + int ret; + + 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 ret; + } + + init_completion(&hifi4_priv->cmd_complete); + hifi4_priv->is_done = 0; + + apu_icm.allbits = 0; + apu_icm.ack = 0; + apu_icm.intr = 1; + apu_icm.msg = ICM_SET_PARA_CONFIG; + apu_icm.size = 8; + + ext_msg.phys = hifi4_priv->msg_buf_phys; + ext_msg.size = sizeof(prop_config); + + memcpy(hifi4_priv->msg_buf_virt, &prop_config, sizeof(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; +} + +static long fsl_hifi4_load_codec(struct fsl_hifi4 *hifi4_priv, + void __user *user) +{ + struct device *dev = hifi4_priv->dev; + struct binary_info binary_info; + long ret = 0; + + ret = copy_from_user(&binary_info, user, sizeof(binary_info)); + if (ret) { + dev_err(dev, "failed to get para from user space\n"); + return ret; + } + + hifi4_priv->objfile = getname(binary_info.file); + hifi4_priv->objtype = binary_info.type; + + ret = load_dpu_with_library(hifi4_priv); + + hifi4_priv->ret_status = 0; + + dev_err(dev, "code binary is loaded\n"); + + return ret; +} + +static long fsl_hifi4_codec_open(struct fsl_hifi4 *hifi4_priv) +{ + union icm_header_t apu_icm; + struct icm_cdc_uinp_t cdc_user_inp; + struct hifi4_ext_msg ext_msg; + long ret = 0; + + cdc_user_inp.proc_id = 0; + cdc_user_inp.codec_id = hifi4_priv->objtype; + cdc_user_inp.crc_check = 0; + cdc_user_inp.pcm_wd_sz = 16; + + 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_cdc_uinp_t); + memcpy(hifi4_priv->msg_buf_virt, &cdc_user_inp, + sizeof(struct icm_cdc_uinp_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) +{ + union icm_header_t apu_icm; + long ret = 0; + + 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 = 0; + icm_intr_send(hifi4_priv, apu_icm.allbits); + + /* wait for response here */ + ret = icm_ack_wait(hifi4_priv, apu_icm.allbits); + + return ret; +} + +static struct miscdevice hifi4_miscdev = { + .name = "mxc_hifi4", + .minor = MISC_DYNAMIC_MINOR, +}; + +static long fsl_hifi4_ioctl(struct file *file, unsigned int cmd, + unsigned long arg) +{ + struct fsl_hifi4_engine *hifi4_engine = file->private_data; + struct fsl_hifi4 *hifi4_priv = hifi4_engine->hifi4_priv; + void __user *user = (void __user *)arg; + long ret = 0; + + switch (cmd) { + case HIFI4_LOAD_CODEC: + ret = fsl_hifi4_load_codec(hifi4_priv, user); + break; + case HIFI4_INIT_CODEC: + ret = fsl_hifi4_init_codec(hifi4_priv); + break; + case HIFI4_CODEC_OPEN: + ret = fsl_hifi4_codec_open(hifi4_priv); + 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); + 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; + default: + break; + } + + return ret; +} + +static int fsl_hifi4_open(struct inode *inode, struct file *file) +{ + struct fsl_hifi4 *hifi4_priv = dev_get_drvdata(hifi4_miscdev.parent); + struct device *dev = hifi4_priv->dev; + struct fsl_hifi4_engine *hifi4_engine; + int ret = 0; + + hifi4_engine = devm_kzalloc(dev, + sizeof(struct fsl_hifi4_engine), GFP_KERNEL); + if (!hifi4_engine) + return -ENOMEM; + + hifi4_engine->hifi4_priv = hifi4_priv; + + file->private_data = hifi4_engine; + return ret; +} + +static int fsl_hifi4_close(struct inode *inode, struct file *file) +{ + return 0; +} + +void *memset_hifi(void *dest, int c, size_t count) +{ + unsigned int *dl = (unsigned int *)dest; + size_t n = round_up(count, 4) / 4; + + /* while all data is aligned (common case), copy a word at a time */ + if ((((ulong)dest) & (sizeof(*dl) - 1)) != 0) + pr_info("dest %p not 4 bytes aligned\n", dest); + + while (n--) { + writel_relaxed(0, dl); + dl++; + } + + return dest; +} + +void *memcpy_hifi(void *dest, const void *src, size_t count) +{ + unsigned int *dl = (unsigned int *)dest, *sl = (unsigned int *)src; + size_t n = round_up(count, 4) / 4; + + if (src == dest) + return dest; + + /* while all data is aligned (common case), copy a word at a time */ + if ((((ulong)dest | (ulong)src) & (sizeof(*dl) - 1)) != 0) + pr_info("dest %p src %p not 4 bytes aligned\n", dest, src); + + while (n--) { + writel_relaxed(*sl, dl); + dl++; + sl++; + } + + 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!\n"); + 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; + 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: + hifi4_priv->is_done = 1; + complete(&hifi4_priv->cmd_complete); + break; + + case ICM_OPEN: + { + struct icm_open_resp_info_t *pext_msg = + (struct icm_open_resp_info_t *)pmsg_apu; + codec_iobuf_info->proc_id = pext_msg->proc_id; + hifi4_priv->is_done = 1; + hifi4_priv->ret_status = pext_msg->ret; + 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; + if (codec_iobuf_info->proc_id == ext_msg->proc_id) { + codec_iobuf_info->inp_cur_offset = + ext_msg->inp_cur_offset; + codec_iobuf_info->out_cur_offset = + ext_msg->out_cur_offset; + } + complete(&hifi4_priv->cmd_complete); + hifi4_priv->is_done = 1; + hifi4_priv->ret_status = ext_msg->ret; + } + break; + + case ICM_GET_PCM_PROP: + { + struct icm_pcm_prop_t *ext_msg = + (struct icm_pcm_prop_t *)pmsg_apu; + pcm_prop_info->proc_id = ext_msg->proc_id; + 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; + + complete(&hifi4_priv->cmd_complete); + hifi4_priv->is_done = 1; + hifi4_priv->ret_status = ext_msg->ret; + } + break; + + case ICM_SET_PARA_CONFIG: + { + struct prop_config *ext_msg = + (struct prop_config *)pmsg_apu; + complete(&hifi4_priv->cmd_complete); + hifi4_priv->is_done = 1; + hifi4_priv->ret_status = ext_msg->ret; + } + break; + + case ICM_PI_LIB_INIT: + complete(&hifi4_priv->cmd_complete); + hifi4_priv->is_done = 1; + break; + + case ICM_CLOSE: + complete(&hifi4_priv->cmd_complete); + hifi4_priv->is_done = 1; + 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; + ext_msg.size = 8*4; + dpu_ext_msg->ext_msg_phys = hifi4_priv->msg_buf_phys + 2048; + dpu_ext_msg->ext_msg_size = 2048; + dpu_ext_msg->code_phys = hifi4_priv->code_buf_phys; + dpu_ext_msg->code_size = hifi4_priv->code_buf_size; + dpu_ext_msg->data_phys = hifi4_priv->data_buf_phys; + dpu_ext_msg->data_size = hifi4_priv->data_buf_size; + dpu_ext_msg->scratch_phys = hifi4_priv->scratch_buf_phys; + dpu_ext_msg->scratch_size = hifi4_priv->scratch_buf_size; + + icm_intr_extended_send(hifi4_priv, apu_icm.allbits, &ext_msg); + + return ret_val; +} + +static irqreturn_t fsl_hifi4_mu_isr(int irq, void *dev_id) +{ + struct fsl_hifi4 *hifi4_priv = dev_id; + struct device *dev = hifi4_priv->dev; + union icm_header_t recd_msg; + int ret_val; + u32 reg; + + MU_ReceiveMsg(hifi4_priv->mu_base_virtaddr, 0, ®); + recd_msg = (union icm_header_t)reg; + if (recd_msg.intr == 1) { + dev_dbg(dev, "INTR: Received ICM intr, msg 0x%08x\n", + recd_msg.allbits); + switch (recd_msg.msg) { + case ICM_CORE_EXIT: + break; + case ICM_CORE_READY: + send_dpu_ext_msg_addr(hifi4_priv); + hifi4_priv->is_ready = 1; + complete(&hifi4_priv->cmd_complete); + break; + case ICM_EXT_MSG_ADDR: + break; + + case ICM_OPEN: + 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; + struct device *dev = hifi4_priv->dev; + Elf32_Ehdr *ehdr; /* Elf header structure pointer */ + Elf32_Shdr *shdr; /* Section header structure pointer */ + unsigned char *strtab = 0; /* String table pointer */ + unsigned char *image; /* Binary image pointer */ + int i; /* Loop counter */ + unsigned long addr = (unsigned long)fw->data; + + ehdr = (Elf32_Ehdr *)addr; + + /* Find the section header string table for output info */ + shdr = (Elf32_Shdr *)(addr + ehdr->e_shoff + + (ehdr->e_shstrndx * sizeof(Elf32_Shdr))); + + if (shdr->sh_type == SHT_STRTAB) + strtab = (unsigned char *)(addr + shdr->sh_offset); + + /* Load each appropriate section */ + for (i = 0; i < ehdr->e_shnum; ++i) { + shdr = (Elf32_Shdr *)(addr + ehdr->e_shoff + + (i * sizeof(Elf32_Shdr))); + + if (!(shdr->sh_flags & SHF_ALLOC) || + shdr->sh_addr == 0 || shdr->sh_size == 0) + continue; + + if (strtab) + dev_dbg(dev, "%sing %s @ 0x%08lx (%ld bytes)\n", + (shdr->sh_type == SHT_NOBITS) ? "Clear" : "Load", + &strtab[shdr->sh_name], + (unsigned long)shdr->sh_addr, + (long)shdr->sh_size); + + if (shdr->sh_type == SHT_NOBITS) { + memset_hifi((void *)(hifi4_priv->regs + + (shdr->sh_addr - hifi4_priv->paddr)), + 0, + shdr->sh_size); + } else { + image = (unsigned char *)addr + shdr->sh_offset; + memcpy_hifi((void *)(hifi4_priv->regs + + (shdr->sh_addr - hifi4_priv->paddr)), + (const void *)image, + shdr->sh_size); + } + } + + /* start the core */ + imx_sc_pm_cpu_start(hifi4_priv->hifi_ipcHandle, + IMX_SC_R_DSP, true, hifi4_priv->iram); +} + +/* Initialization of the MU code. */ +int hifi4_mu_init(struct fsl_hifi4 *hifi4_priv) +{ + struct device *dev = hifi4_priv->dev; + struct device_node *np; + unsigned int hifi_mu_id; + u32 irq; + int ret = 0; + + /* + * Get the address of MU to be used for communication with the hifi + */ + np = of_find_compatible_node(NULL, NULL, "fsl,imx8-mu-hifi"); + if (!np) { + dev_err(dev, "Cannot find MU entry in device tree\n"); + return -EINVAL; + } + hifi4_priv->mu_base_virtaddr = of_iomap(np, 0); + WARN_ON(!hifi4_priv->mu_base_virtaddr); + + ret = of_property_read_u32_index(np, + "fsl,hifi_ap_mu_id", 0, &hifi_mu_id); + if (ret) { + dev_err(dev, "Cannot get mu_id %d\n", ret); + return -EINVAL; + } + + hifi4_priv->hifi_mu_id = hifi_mu_id; + + 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); + if (ret) { + dev_err(dev, "request_irq failed %d, err = %d\n", irq, ret); + return -EINVAL; + } + + if (!hifi4_priv->hifi_mu_init) { + MU_Init(hifi4_priv->mu_base_virtaddr); + MU_EnableRxFullInt(hifi4_priv->mu_base_virtaddr, 0); + hifi4_priv->hifi_mu_init = 1; + } + + return ret; +} + +static const struct file_operations hifi4_fops = { + .owner = THIS_MODULE, + .unlocked_ioctl = fsl_hifi4_ioctl, + .open = fsl_hifi4_open, + .release = fsl_hifi4_close, +}; + +static int fsl_hifi4_probe(struct platform_device *pdev) +{ + struct device_node *np = pdev->dev.of_node; + struct fsl_hifi4 *hifi4_priv; + const char *fw_name; + struct resource *res; + void __iomem *regs; + void *buf_virt; + dma_addr_t buf_phys; + int size, offset; + int ret; + + hifi4_priv = devm_kzalloc(&pdev->dev, sizeof(*hifi4_priv), GFP_KERNEL); + if (!hifi4_priv) + return -ENOMEM; + + hifi4_priv->dev = &pdev->dev; + + /* Get the addresses and IRQ */ + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + regs = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(regs)) + return PTR_ERR(regs); + + hifi4_priv->paddr = res->start; + hifi4_priv->regs = regs; + + hifi4_priv->dram0 = hifi4_priv->paddr + DRAM0_OFFSET; + hifi4_priv->dram1 = hifi4_priv->paddr + DRAM1_OFFSET; + hifi4_priv->iram = hifi4_priv->paddr + IRAM_OFFSET; + hifi4_priv->sram = hifi4_priv->paddr + SYSRAM_OFFSET; + + ret = imx_scu_get_handle(&hifi4_priv->hifi_ipcHandle); + if (ret) { + dev_err(&pdev->dev, "Cannot get scu handle %d\n", ret); + return ret; + }; + + ret = hifi4_mu_init(hifi4_priv); + if (ret) + return ret; + + ret = of_property_read_string(np, "fsl,hifi4-firmware", &fw_name); + hifi4_priv->fw_name = fw_name; + + platform_set_drvdata(pdev, hifi4_priv); + pm_runtime_enable(&pdev->dev); + + hifi4_miscdev.fops = &hifi4_fops, + hifi4_miscdev.parent = &pdev->dev, + ret = misc_register(&hifi4_miscdev); + if (ret) { + dev_err(&pdev->dev, "failed to register misc device %d\n", ret); + return ret; + } + + /* code buffer */ + hifi4_priv->code_buf_virt = hifi4_priv->regs + LIBRARY_CODE_OFFSET; + hifi4_priv->code_buf_phys = hifi4_priv->paddr + LIBRARY_CODE_OFFSET; + hifi4_priv->code_buf_size = LIBRARY_CODE_SIZE; + + size = MSG_BUF_SIZE + INPUT_BUF_SIZE + + OUTPUT_BUF_SIZE + FIRMWARE_DATA_BUF_SIZE + + SCRATCH_DATA_BUF_SIZE; + + buf_virt = dma_alloc_coherent(&pdev->dev, size, &buf_phys, GFP_KERNEL); + if (!buf_virt) { + dev_err(&pdev->dev, "failed alloc memory.\n"); + return -ENOMEM; + } + + /* msg buffer */ + 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; + + /* input buffer */ + hifi4_priv->in_buf_virt = buf_virt + offset; + hifi4_priv->in_buf_phys = buf_phys + offset; + hifi4_priv->in_buf_size = INPUT_BUF_SIZE; + offset += INPUT_BUF_SIZE; + + /* output buffer */ + hifi4_priv->out_buf_virt = buf_virt + offset; + hifi4_priv->out_buf_phys = buf_phys + offset; + hifi4_priv->out_buf_size = OUTPUT_BUF_SIZE; + offset += OUTPUT_BUF_SIZE; + + /* codec library data section */ + hifi4_priv->data_buf_virt = buf_virt + offset; + hifi4_priv->data_buf_phys = buf_phys + offset; + hifi4_priv->data_buf_size = FIRMWARE_DATA_BUF_SIZE; + offset += FIRMWARE_DATA_BUF_SIZE; + + hifi4_priv->scratch_buf_virt = buf_virt + offset; + hifi4_priv->scratch_buf_phys = buf_phys + offset; + hifi4_priv->scratch_buf_size = SCRATCH_DATA_BUF_SIZE; + + init_completion(&hifi4_priv->cmd_complete); + hifi4_priv->is_ready = 0; + + ret = request_firmware_nowait(THIS_MODULE, + FW_ACTION_HOTPLUG, fw_name, hifi4_priv->dev, + GFP_KERNEL, hifi4_priv, hifi4_load_firmware); + + if (ret) { + dev_err(&pdev->dev, "failed to load firmware\n"); + return ret; + } + + ret = icm_ack_wait(hifi4_priv, 0); + if (ret) + return ret; + + dev_info(&pdev->dev, "hifi driver registered\n"); + return 0; +} + +static int fsl_hifi4_remove(struct platform_device *pdev) +{ + struct fsl_hifi4 *hifi4_priv = platform_get_drvdata(pdev); + int size; + + misc_deregister(&hifi4_miscdev); + + size = MSG_BUF_SIZE + INPUT_BUF_SIZE + + OUTPUT_BUF_SIZE + FIRMWARE_DATA_BUF_SIZE; + dma_free_coherent(&pdev->dev, size, hifi4_priv->msg_buf_virt, + hifi4_priv->msg_buf_phys); + + return 0; +} + +#ifdef CONFIG_PM +static int fsl_hifi4_runtime_resume(struct device *dev) +{ + return 0; +} + +static int fsl_hifi4_runtime_suspend(struct device *dev) +{ + return 0; +} +#endif /* CONFIG_PM */ + +#ifdef CONFIG_PM_SLEEP +static int fsl_hifi4_suspend(struct device *dev) +{ + return 0; +} + +static int fsl_hifi4_resume(struct device *dev) +{ + return 0; +} +#endif /* CONFIG_PM_SLEEP */ + +static const struct dev_pm_ops fsl_hifi4_pm = { + SET_RUNTIME_PM_OPS(fsl_hifi4_runtime_suspend, + fsl_hifi4_runtime_resume, NULL) + SET_SYSTEM_SLEEP_PM_OPS(fsl_hifi4_suspend, fsl_hifi4_resume) +}; + +static const struct of_device_id fsl_hifi4_ids[] = { + { .compatible = "fsl,imx8qxp-hifi4", }, + {} +}; +MODULE_DEVICE_TABLE(of, fsl_hifi4_ids); + +static struct platform_driver fsl_hifi4_driver = { + .probe = fsl_hifi4_probe, + .remove = fsl_hifi4_remove, + .driver = { + .name = "fsl-hifi4", + .of_match_table = fsl_hifi4_ids, + .pm = &fsl_hifi4_pm, + }, +}; +module_platform_driver(fsl_hifi4_driver); + +MODULE_DESCRIPTION("Freescale HIFI 4 driver"); +MODULE_ALIAS("platform:fsl-hifi4"); +MODULE_LICENSE("GPL v2"); diff --git a/sound/soc/fsl/fsl_hifi4.h b/sound/soc/fsl/fsl_hifi4.h new file mode 100644 index 000000000000..cabdd7758b56 --- /dev/null +++ b/sound/soc/fsl/fsl_hifi4.h @@ -0,0 +1,281 @@ +/* + * Freescale HIFI 4 driver + * + * Copyright (C) 2017 NXP. + * + * 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. + */ + +#include + + +#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; + + +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 timestamp_info_t { + u32 offset_last_inp_byt_read_frm_sysram; + u32 offset_last_inp_byt_decoded; + u32 samples_produced; + u32 sample_rate; +}; + +struct icm_cdc_iobuf_t { + u32 proc_id; /* non-zero indicates success; */ + 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 */ + s32 ret; +}; + +struct icm_cdc_uinp_t { + u32 proc_id; /* audio id */ + u32 codec_id; /* codec identifier */ + u32 pcm_wd_sz; /* pcm word size; only 16 or 24 */ + u32 crc_check; /* 0: disable, 1: enable */ +}; + +struct icm_pcm_prop_t { + u32 proc_id; /* audio id */ + u32 pcmbytes; /* total bytes in the wav file */ + u32 sfreq; /* sample rate */ + u32 channels; /* output channels */ + u32 bits; /* bits per sample */ + u32 consumed_bytes; + s32 ret; +}; + +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; +}; + +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_INIT, + ICM_PI_LIB_UNLOAD, + + ICM_DPU_ACTION_COMPLETE, + ICM_APU_ACTION_COMPLETE, + + ICM_OPEN, + ICM_EMPTY_THIS_BUFFER, + ICM_FILL_THIS_BUFFER, + ICM_PAUSE, + ICM_CLOSE, + + ICM_GET_PCM_PROP, + ICM_SET_PARA_CONFIG, + + ICM_CORE_EXIT, + ICM_EXT_MSG_ADDR, +}; + +enum aud_status_t { + AUD_IDLE = 0, + AUD_STOPPED, + AUD_DECODING, + AUD_PAUSED +}; + +struct icm_open_resp_info_t { + u32 proc_id; + struct timestamp_info_t *dtstamp; + s32 ret; +}; + +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. */ +}; + + +struct icm_pilib_size_t { + u32 codec_type; + u32 text_size; + u32 data_size; +}; + +struct fsl_hifi4 { + struct device *dev; + const char *fw_name; + void __iomem *regs; + void __iomem *mu_base_virtaddr; + struct imx_sc_ipc *hifi_ipcHandle; + unsigned int hifi_mu_id; + int hifi_mu_init; + unsigned long paddr; + unsigned long dram0; + unsigned long dram1; + unsigned long iram; + unsigned long sram; + void *msg_buf_virt; + dma_addr_t msg_buf_phys; + int msg_buf_size; + 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; + void *scratch_buf_virt; + dma_addr_t scratch_buf_phys; + int scratch_buf_size; + + int is_ready; + int is_done; + + struct completion cmd_complete; + char *objmem; + struct filename *objfile; + char objtype; + unsigned int start_addr; + int ret_status; + struct icm_cdc_iobuf_t codec_iobuf_info; + struct icm_pcm_prop_t pcm_prop_info; + struct xtlib_pil_info pil_info; + struct xtlib_loader_globals xtlib_globals; +}; + +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 code_phys; + u32 code_size; + u32 data_phys; + u32 data_size; + u32 scratch_phys; + u32 scratch_size; +}; + +#define IRAM_OFFSET 0x10000 +#define IRAM_SIZE 2048 + +#define DRAM0_OFFSET 0x0 +#define DRAM0_SIZE 0x8000 + +#define DRAM1_OFFSET 0x8000 +#define DRAM1_SIZE 0x8000 + +#define SYSRAM_OFFSET 0x18000 +#define SYSRAM_SIZE 0x40000 + +#define SYSROM_OFFSET 0x58000 +#define SYSROM_SIZE 0x30000 + +#define LIBRARY_CODE_OFFSET 0x38000 +#define LIBRARY_CODE_SIZE 0x50000 + +#define MSG_BUF_SIZE 4096 +#define INPUT_BUF_SIZE 4096 +#define OUTPUT_BUF_SIZE 16384 +#define FIRMWARE_DATA_BUF_SIZE 0x100000 +#define SCRATCH_DATA_BUF_SIZE 0x100000 + +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); +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 fsl_hifi4 *hifi4_priv); + +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 fsl_hifi4 *hifi4_priv); + +void *memcpy_hifi(void *dest, const void *src, size_t count); +void *memset_hifi(void *dest, int c, size_t count); From 72473479d1552917279474819515d928419b7b0c Mon Sep 17 00:00:00 2001 From: Shengjiu Wang Date: Thu, 1 Jun 2017 15:19:31 +0800 Subject: [PATCH 02/78] MLK-14997-6: ARM64: defconfig: built-in hifi driver built-in hifi driver Signed-off-by: Shengjiu Wang --- sound/soc/fsl/fsl_hifi4.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/fsl/fsl_hifi4.c b/sound/soc/fsl/fsl_hifi4.c index 8e1d1e0cba05..05aa2a924eed 100644 --- a/sound/soc/fsl/fsl_hifi4.c +++ b/sound/soc/fsl/fsl_hifi4.c @@ -65,7 +65,7 @@ long load_dpu_with_library(struct fsl_hifi4 *hifi4_priv) srambuf = kmalloc(filesize, GFP_KERNEL); vfs_llseek(fpInfile, 0, SEEK_SET); - kernel_read(fpInfile, 0, srambuf, filesize); + kernel_read(fpInfile, srambuf, filesize, NULL); filp_close(fpInfile, NULL); ret_val = xtlib_split_pi_library_size( From f4fa46fed6abbe798a0c1e96a37de26f5919c450 Mon Sep 17 00:00:00 2001 From: Weiguang Kong Date: Wed, 28 Jun 2017 13:06:19 +0800 Subject: [PATCH 03/78] MLK-15296-3: ASoc: fsl: remap the dsp firmware In order to use the hifi4's Cache to cache the firmware's .rodata, .text, .data, .bss section and hifi4 core lib's .text section, the firmware's .rodata, .text, .data and .bss section should be remaped to 0x20700000 - 0x20FFFFFF address range. This patch is used to parse the firmware and load each section to corresponding address range. This patch also set csr_gpr_control to 0x515A2080 to remap the hifi4's address range in SCFW. In addtion, add cases to support hifi4 framework's performance test. Signed-off-by: Weiguang Kong --- sound/soc/fsl/fsl_hifi4.c | 45 +++++++++++++++++++++++++++++++++++++-- sound/soc/fsl/fsl_hifi4.h | 8 +++++++ 2 files changed, 51 insertions(+), 2 deletions(-) diff --git a/sound/soc/fsl/fsl_hifi4.c b/sound/soc/fsl/fsl_hifi4.c index 05aa2a924eed..4e50348b1fd3 100644 --- a/sound/soc/fsl/fsl_hifi4.c +++ b/sound/soc/fsl/fsl_hifi4.c @@ -646,6 +646,7 @@ static long fsl_hifi4_decode_frame(struct fsl_hifi4 *hifi4_priv, decode_info.in_buf_off = codec_iobuf_info->inp_cur_offset; decode_info.out_buf_off = codec_iobuf_info->out_cur_offset; + decode_info.cycles = codec_iobuf_info->cycles; ret = copy_to_user(user, &decode_info, sizeof(decode_info)); if (ret) { @@ -1015,6 +1016,8 @@ int process_act_complete(struct fsl_hifi4 *hifi4_priv, u32 msg) ext_msg->inp_cur_offset; codec_iobuf_info->out_cur_offset = ext_msg->out_cur_offset; + codec_iobuf_info->cycles = + ext_msg->cycles; } complete(&hifi4_priv->cmd_complete); hifi4_priv->is_done = 1; @@ -1173,12 +1176,21 @@ static void hifi4_load_firmware(const struct firmware *fw, void *context) shdr->sh_addr == 0 || shdr->sh_size == 0) continue; - if (strtab) + if (strtab) { dev_dbg(dev, "%sing %s @ 0x%08lx (%ld bytes)\n", (shdr->sh_type == SHT_NOBITS) ? "Clear" : "Load", &strtab[shdr->sh_name], (unsigned long)shdr->sh_addr, (long)shdr->sh_size); + } + + if ((!strcmp(&strtab[shdr->sh_name], ".rodata")) || + (!strcmp(&strtab[shdr->sh_name], ".text")) || + (!strcmp(&strtab[shdr->sh_name], ".data")) || + (!strcmp(&strtab[shdr->sh_name], ".bss")) + ) { + shdr->sh_addr = shdr->sh_addr + MEMORY_REMAP_OFFSET; + } if (shdr->sh_type == SHT_NOBITS) { memset_hifi((void *)(hifi4_priv->regs + @@ -1291,6 +1303,34 @@ static int fsl_hifi4_probe(struct platform_device *pdev) return ret; }; + ret = imx_sc_misc_set_control(hifi4_priv->hifi_ipcHandle, IMX_SC_R_DSP, + IMX_SC_C_OFS_SEL, 1); + if (ret) { + dev_err(&pdev->dev, "Error system address offset source select\n"); + return -EIO; + } + + ret = imx_sc_misc_set_control(hifi4_priv->hifi_ipcHandle, IMX_SC_R_DSP, + IMX_SC_C_OFS_AUDIO, 0x20); + if (ret) { + dev_err(&pdev->dev, "Error system address offset of AUDIO\n"); + return -EIO; + } + + ret = imx_sc_misc_set_control(hifi4_priv->hifi_ipcHandle, IMX_SC_R_DSP, + IMX_SC_C_OFS_PERIPH, 0x5A); + if (ret) { + dev_err(&pdev->dev, "Error system address offset of PERIPH\n"); + return -EIO; + } + + ret = imx_sc_misc_set_control(hifi4_priv->hifi_ipcHandle, IMX_SC_R_DSP, + IMX_SC_C_OFS_IRQ, 0x51); + if (ret) { + dev_err(&pdev->dev, "Error system address offset of IRQ\n"); + return -EIO; + } + ret = hifi4_mu_init(hifi4_priv); if (ret) return ret; @@ -1311,7 +1351,8 @@ static int fsl_hifi4_probe(struct platform_device *pdev) /* code buffer */ hifi4_priv->code_buf_virt = hifi4_priv->regs + LIBRARY_CODE_OFFSET; - hifi4_priv->code_buf_phys = hifi4_priv->paddr + LIBRARY_CODE_OFFSET; + hifi4_priv->code_buf_phys = hifi4_priv->paddr + LIBRARY_CODE_OFFSET - + MEMORY_REMAP_OFFSET; hifi4_priv->code_buf_size = LIBRARY_CODE_SIZE; size = MSG_BUF_SIZE + INPUT_BUF_SIZE + diff --git a/sound/soc/fsl/fsl_hifi4.h b/sound/soc/fsl/fsl_hifi4.h index cabdd7758b56..01e0fd380c86 100644 --- a/sound/soc/fsl/fsl_hifi4.h +++ b/sound/soc/fsl/fsl_hifi4.h @@ -55,6 +55,7 @@ struct icm_cdc_iobuf_t { u32 out_buf_size_max; /* init by APU */ u32 out_cur_offset; /* init by APU, updated by DPU */ s32 ret; + u32 cycles; /* consumed cycles during executing */ }; struct icm_cdc_uinp_t { @@ -256,6 +257,13 @@ struct hifi4_mem_msg { #define FIRMWARE_DATA_BUF_SIZE 0x100000 #define SCRATCH_DATA_BUF_SIZE 0x100000 +#define MEMORY_REMAP_OFFSET 0x39000000 + +#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, From f28efa9c492aae83387a45f3fb74941099d4a72b Mon Sep 17 00:00:00 2001 From: Weiguang Kong Date: Mon, 10 Jul 2017 12:03:53 +0800 Subject: [PATCH 04/78] MLK-15934-2: ASoc: fsl: different pointer length issue for hifi4 when transferring struct icm_open_resp_info_t type between hifi4 framework and hifi4 driver, because this struct has an element "*dtstamp" which is a pointer, but for hifi4 firmware, this pointer occupies 4 bytes, for hifi4 driver, this pointer occupies 8 bytes. different pointer length will cause issue when reading this structure's content in hifi4 driver. By changing the pointer type to unsigned int type to fix this issue. Signed-off-by: Weiguang Kong --- sound/soc/fsl/fsl_hifi4.c | 2 ++ sound/soc/fsl/fsl_hifi4.h | 4 +++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/sound/soc/fsl/fsl_hifi4.c b/sound/soc/fsl/fsl_hifi4.c index 4e50348b1fd3..38b63cb6f06f 100644 --- a/sound/soc/fsl/fsl_hifi4.c +++ b/sound/soc/fsl/fsl_hifi4.c @@ -1003,6 +1003,8 @@ int process_act_complete(struct fsl_hifi4 *hifi4_priv, u32 msg) (struct icm_open_resp_info_t *)pmsg_apu; codec_iobuf_info->proc_id = pext_msg->proc_id; hifi4_priv->is_done = 1; + hifi4_priv->dpu_tstamp = + (struct timestamp_info_t *)pext_msg->dtstamp; hifi4_priv->ret_status = pext_msg->ret; complete(&hifi4_priv->cmd_complete); } diff --git a/sound/soc/fsl/fsl_hifi4.h b/sound/soc/fsl/fsl_hifi4.h index 01e0fd380c86..49b6c1250a02 100644 --- a/sound/soc/fsl/fsl_hifi4.h +++ b/sound/soc/fsl/fsl_hifi4.h @@ -145,7 +145,8 @@ enum aud_status_t { struct icm_open_resp_info_t { u32 proc_id; - struct timestamp_info_t *dtstamp; + u32 dtstamp; /* address value of timestamp_info_t */ + s32 ret; }; @@ -211,6 +212,7 @@ struct fsl_hifi4 { struct icm_pcm_prop_t pcm_prop_info; struct xtlib_pil_info pil_info; struct xtlib_loader_globals xtlib_globals; + struct timestamp_info_t *dpu_tstamp; }; struct fsl_hifi4_engine { From 0c35f92e947f51fb5e9e1970b8bd19b657c61f14 Mon Sep 17 00:00:00 2001 From: Shengjiu Wang Date: Thu, 1 Jun 2017 15:16:25 +0800 Subject: [PATCH 05/78] MLK-14997-2: include: uapi: add hifi header file add hifi header file, which is used by user space. Signed-off-by: Shengjiu Wang --- include/uapi/linux/mxc_hifi4.h | 75 ++++++++++++++++++++++++++++++++++ 1 file changed, 75 insertions(+) create mode 100644 include/uapi/linux/mxc_hifi4.h diff --git a/include/uapi/linux/mxc_hifi4.h b/include/uapi/linux/mxc_hifi4.h new file mode 100644 index 000000000000..7194290f025e --- /dev/null +++ b/include/uapi/linux/mxc_hifi4.h @@ -0,0 +1,75 @@ +/* + * Copyright 2017 NXP + * + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + * + * @file mxc_hifi4.h + * + * @ingroup Audio + */ + +#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 CODEC_MP3_DEC 1 +#define CODEC_AAC_DEC 2 +#define CODEC_DAB_DEC 3 +#define CODEC_MP2_DEC 4 +#define CODEC_BSAC_DEC 5 +#define CODEC_DRM_DEC 6 +#define CODEC_SBC_DEC 7 +#define CODEC_SBC_ENC 8 +#define CODEC_DEMO_DEC 9 + +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; +}; + +struct prop_info { + int samplerate; + int channels; + int bits; + unsigned int consumed_bytes; + + /* dedicate for drm dec */ + int frame_size; + + /* dedicate for bsac, aacplus and dabplus dec */ + int aac_samplerate; + int sbr_type; + int mpeg_surr_present; +}; + +struct binary_info { + int type; + char *file; +}; + +struct prop_config { + int codec_id; /* codec id */ + int cmd; /* command value */ + int val; /* parameter value */ + int ret; /* executed status of function */ +}; + +#endif/* __MXC_HIFI4_UAPI_H__ */ From 64d0b8c10f6b56060f960485a3241a477e8ae20c Mon Sep 17 00:00:00 2001 From: Weiguang Kong Date: Wed, 28 Jun 2017 13:02:16 +0800 Subject: [PATCH 06/78] MLK-15296-2: include: uapi: add consumed cycles add a new structure element(cycles) to save the consumed cycles that returned from dsp framework Signed-off-by: Weiguang Kong --- include/uapi/linux/mxc_hifi4.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/uapi/linux/mxc_hifi4.h b/include/uapi/linux/mxc_hifi4.h index 7194290f025e..b1d631baa543 100644 --- a/include/uapi/linux/mxc_hifi4.h +++ b/include/uapi/linux/mxc_hifi4.h @@ -43,6 +43,7 @@ struct decode_info { void *out_buf_addr; int out_buf_size; int out_buf_off; + unsigned int cycles; }; struct prop_info { From 81973d10d2b11b4143aea3bd1cc354744828914a Mon Sep 17 00:00:00 2001 From: Weiguang Kong Date: Fri, 7 Jul 2017 12:38:09 +0800 Subject: [PATCH 07/78] MLK-15934-3: ASoc: fsl: add hifi4 firmware's status transfer support 1. add cases to receive error value from hifi4 firmware and return this error to hifi4 driver's caller. 2. add cases to receive input over indicator variable from hifi4 dirver's caller and pass this value to hifi4 firmware Signed-off-by: Weiguang Kong --- include/uapi/linux/mxc_hifi4.h | 1 + sound/soc/fsl/fsl_hifi4.c | 3 +++ sound/soc/fsl/fsl_hifi4.h | 1 + 3 files changed, 5 insertions(+) diff --git a/include/uapi/linux/mxc_hifi4.h b/include/uapi/linux/mxc_hifi4.h index b1d631baa543..8e0189059168 100644 --- a/include/uapi/linux/mxc_hifi4.h +++ b/include/uapi/linux/mxc_hifi4.h @@ -44,6 +44,7 @@ struct decode_info { int out_buf_size; int out_buf_off; unsigned int cycles; + unsigned int input_over; }; struct prop_info { diff --git a/sound/soc/fsl/fsl_hifi4.c b/sound/soc/fsl/fsl_hifi4.c index 38b63cb6f06f..1715a46431ff 100644 --- a/sound/soc/fsl/fsl_hifi4.c +++ b/sound/soc/fsl/fsl_hifi4.c @@ -621,6 +621,8 @@ static long fsl_hifi4_decode_frame(struct fsl_hifi4 *hifi4_priv, codec_iobuf_info->out_buf_size_max = hifi4_priv->out_buf_size; codec_iobuf_info->out_cur_offset = 0; + codec_iobuf_info->input_over = decode_info.input_over; + init_completion(&hifi4_priv->cmd_complete); hifi4_priv->is_done = 0; @@ -647,6 +649,7 @@ static long fsl_hifi4_decode_frame(struct fsl_hifi4 *hifi4_priv, decode_info.in_buf_off = codec_iobuf_info->inp_cur_offset; decode_info.out_buf_off = codec_iobuf_info->out_cur_offset; decode_info.cycles = codec_iobuf_info->cycles; + decode_info.input_over = codec_iobuf_info->input_over; ret = copy_to_user(user, &decode_info, sizeof(decode_info)); if (ret) { diff --git a/sound/soc/fsl/fsl_hifi4.h b/sound/soc/fsl/fsl_hifi4.h index 49b6c1250a02..7756d694c122 100644 --- a/sound/soc/fsl/fsl_hifi4.h +++ b/sound/soc/fsl/fsl_hifi4.h @@ -56,6 +56,7 @@ struct icm_cdc_iobuf_t { u32 out_cur_offset; /* init by APU, updated by DPU */ s32 ret; u32 cycles; /* consumed cycles during executing */ + u32 input_over; /* indicate external stream is over*/ }; struct icm_cdc_uinp_t { From 15a76b231cbb268e0623b5a6ddc9439f75268b0c Mon Sep 17 00:00:00 2001 From: Weiguang Kong Date: Wed, 12 Jul 2017 17:31:48 +0800 Subject: [PATCH 08/78] MLK-15959: ASoc: fsl: fix hifi4 driver build warning When building sound/soc/fsl/fsl_hifi4.c file, a warning occurs: warning: cast to pointer from integer of different size [-Wint-to-pointer-cast] (struct timestamp_info_t *)pext_msg->dtstamp; By forced conversing int type to long type to fix this issue. Signed-off-by: Weiguang Kong --- sound/soc/fsl/fsl_hifi4.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/fsl/fsl_hifi4.c b/sound/soc/fsl/fsl_hifi4.c index 1715a46431ff..e9bb5d06e61b 100644 --- a/sound/soc/fsl/fsl_hifi4.c +++ b/sound/soc/fsl/fsl_hifi4.c @@ -1007,7 +1007,7 @@ int process_act_complete(struct fsl_hifi4 *hifi4_priv, u32 msg) codec_iobuf_info->proc_id = pext_msg->proc_id; hifi4_priv->is_done = 1; hifi4_priv->dpu_tstamp = - (struct timestamp_info_t *)pext_msg->dtstamp; + (struct timestamp_info_t *)((long)pext_msg->dtstamp); hifi4_priv->ret_status = pext_msg->ret; complete(&hifi4_priv->cmd_complete); } From 6035676ebe61cb88e49616688ed8fd4c894be95b Mon Sep 17 00:00:00 2001 From: Weiguang Kong Date: Fri, 14 Jul 2017 09:00:11 +0800 Subject: [PATCH 09/78] MLK-16010: ASoc: fsl: support 32-bit application for hifi4 add cases to support 32-bit application for hifi4 when kernel is running on 64-bit cpu mode. Signed-off-by: Weiguang Kong --- sound/soc/fsl/fsl_hifi4.c | 234 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 234 insertions(+) diff --git a/sound/soc/fsl/fsl_hifi4.c b/sound/soc/fsl/fsl_hifi4.c index e9bb5d06e61b..726bf9a6aa50 100644 --- a/sound/soc/fsl/fsl_hifi4.c +++ b/sound/soc/fsl/fsl_hifi4.c @@ -40,12 +40,97 @@ #include #include #include +#ifdef CONFIG_COMPAT +#include +#endif #include #include #include #include #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 cycles; + __u32 input_over; +}; + +struct binary_info_compat32 { + __s32 type; + compat_long_t file; +}; + +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) + ) { + 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->cycles, &up->cycles) || + get_user(kp->input_over, &up->input_over) + ) { + 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->cycles, &up->cycles) || + put_user(kp->input_over, &up->input_over) + ) { + return -EFAULT; + } + + return 0; +} +#endif + + long load_dpu_with_library(struct fsl_hifi4 *hifi4_priv) { struct file *fpInfile; @@ -661,6 +746,84 @@ static long fsl_hifi4_decode_frame(struct fsl_hifi4 *hifi4_priv, return ret; } +#ifdef CONFIG_COMPAT +static long fsl_hifi4_decode_frame_compat32(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 decode_info decode_info; + struct icm_cdc_iobuf_t *codec_iobuf_info = + &hifi4_priv->codec_iobuf_info; + 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; + } + + 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) { + memcpy(hifi4_priv->in_buf_virt, decode_info.in_buf_addr, + decode_info.in_buf_size); + codec_iobuf_info->inp_cur_offset = 0; + } + + codec_iobuf_info->inp_addr_sysram = hifi4_priv->in_buf_phys; + codec_iobuf_info->inp_buf_size_max = decode_info.in_buf_size; + + codec_iobuf_info->out_addr_sysram = hifi4_priv->out_buf_phys; + codec_iobuf_info->out_buf_size_max = hifi4_priv->out_buf_size; + codec_iobuf_info->out_cur_offset = 0; + + codec_iobuf_info->input_over = decode_info.input_over; + + 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; + + memcpy(decode_info.out_buf_addr, hifi4_priv->out_buf_virt, + codec_iobuf_info->out_cur_offset); + + decode_info.in_buf_off = codec_iobuf_info->inp_cur_offset; + decode_info.out_buf_off = codec_iobuf_info->out_cur_offset; + decode_info.cycles = codec_iobuf_info->cycles; + decode_info.input_over = codec_iobuf_info->input_over; + + 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; +} +#endif + static long fsl_hifi4_get_pcm_prop(struct fsl_hifi4 *hifi4_priv, void __user *user) { @@ -769,6 +932,33 @@ static long fsl_hifi4_load_codec(struct fsl_hifi4 *hifi4_priv, 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 binary_info binary_info; + long ret = 0; + + 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; + } + + hifi4_priv->objfile = getname(binary_info.file); + hifi4_priv->objtype = binary_info.type; + + ret = load_dpu_with_library(hifi4_priv); + + hifi4_priv->ret_status = 0; + + dev_err(dev, "code binary is loaded\n"); + + return ret; +} +#endif + static long fsl_hifi4_codec_open(struct fsl_hifi4 *hifi4_priv) { union icm_header_t apu_icm; @@ -872,6 +1062,47 @@ static long fsl_hifi4_ioctl(struct file *file, unsigned int cmd, 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 = file->private_data; + struct fsl_hifi4 *hifi4_priv = hifi4_engine->hifi4_priv; + void __user *user = compat_ptr(arg); + long ret = 0; + + switch (cmd) { + 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); + break; + case HIFI4_CODEC_OPEN: + ret = fsl_hifi4_codec_open(hifi4_priv); + break; + case HIFI4_DECODE_ONE_FRAME: + ret = fsl_hifi4_decode_frame_compat32(hifi4_priv, user); + break; + case HIFI4_CODEC_CLOSE: + ret = fsl_hifi4_codec_close(hifi4_priv); + 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; + default: + break; + } + + return ret; +} +#endif + static int fsl_hifi4_open(struct inode *inode, struct file *file) { struct fsl_hifi4 *hifi4_priv = dev_get_drvdata(hifi4_miscdev.parent); @@ -1266,6 +1497,9 @@ int hifi4_mu_init(struct fsl_hifi4 *hifi4_priv) static const struct file_operations hifi4_fops = { .owner = THIS_MODULE, .unlocked_ioctl = fsl_hifi4_ioctl, +#ifdef CONFIG_COMPAT + .compat_ioctl = fsl_hifi4_compat_ioctl, +#endif .open = fsl_hifi4_open, .release = fsl_hifi4_close, }; From 2634b1938beb372b2d43b80751d53c0ac6079f11 Mon Sep 17 00:00:00 2001 From: Weiguang Kong Date: Fri, 28 Jul 2017 16:42:32 +0800 Subject: [PATCH 10/78] MLK-16099-1: ASoc: fsl: fix crash issue when no dsp core lib When dsp driver can't find the dsp core lib in loading codec process, the kernel will be crashed. This issue is caused by unreasonable way of error handling. By changing the way of error handling to fix this issue. Signed-off-by: Weiguang Kong --- sound/soc/fsl/fsl_hifi4.c | 32 ++++++++++++++++++++++++++++---- 1 file changed, 28 insertions(+), 4 deletions(-) diff --git a/sound/soc/fsl/fsl_hifi4.c b/sound/soc/fsl/fsl_hifi4.c index 726bf9a6aa50..ed4a5497aac5 100644 --- a/sound/soc/fsl/fsl_hifi4.c +++ b/sound/soc/fsl/fsl_hifi4.c @@ -141,8 +141,8 @@ long load_dpu_with_library(struct fsl_hifi4 *hifi4_priv) /* Load DPU's main program to System memory */ fpInfile = file_open_name(hifi4_priv->objfile, O_RDONLY, 0); - if (!fpInfile) - return -1; + if (IS_ERR(fpInfile)) + return PTR_ERR(fpInfile); vfs_llseek(fpInfile, 0, SEEK_END); filesize = (int)fpInfile->f_pos; @@ -911,6 +911,7 @@ static long fsl_hifi4_load_codec(struct fsl_hifi4 *hifi4_priv, void __user *user) { struct device *dev = hifi4_priv->dev; + struct filename *fpInfile; struct binary_info binary_info; long ret = 0; @@ -920,10 +921,21 @@ static long fsl_hifi4_load_codec(struct fsl_hifi4 *hifi4_priv, return ret; } - hifi4_priv->objfile = getname(binary_info.file); + 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); + } + + hifi4_priv->objfile = fpInfile; hifi4_priv->objtype = binary_info.type; ret = load_dpu_with_library(hifi4_priv); + if (ret) { + dev_err(dev, "failed to load code binary, err = %ld\n", ret); + return ret; + } hifi4_priv->ret_status = 0; @@ -937,6 +949,7 @@ static long fsl_hifi4_load_codec_compat32(struct fsl_hifi4 *hifi4_priv, void __user *user) { struct device *dev = hifi4_priv->dev; + struct filename *fpInfile; struct binary_info binary_info; long ret = 0; @@ -946,10 +959,21 @@ static long fsl_hifi4_load_codec_compat32(struct fsl_hifi4 *hifi4_priv, return ret; } - hifi4_priv->objfile = getname(binary_info.file); + 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); + } + + hifi4_priv->objfile = fpInfile; hifi4_priv->objtype = binary_info.type; ret = load_dpu_with_library(hifi4_priv); + if (ret) { + dev_err(dev, "failed to load code binary, err = %ld\n", ret); + return ret; + } hifi4_priv->ret_status = 0; From bc2b6918bafb35d785a5960d844355a67c2fda7e Mon Sep 17 00:00:00 2001 From: Weiguang Kong Date: Mon, 31 Jul 2017 09:43:29 +0800 Subject: [PATCH 11/78] MLK-16099-2: ASoc: fsl: length is not same for alloc and free memory In fsl_hifi4_probe(), the length for dma_alloc_coherent() is MSG_BUF_SIZE + INPUT_BUF_SIZE + OUTPUT_BUF_SIZE + FIRMWARE_DATA_BUF_SIZE + SCRATCH_DATA_BUF_SIZE; However, in fsl_hifi4_remove(), the length for dma_free_coherent() is MSG_BUF_SIZE + INPUT_BUF_SIZE + OUTPUT_BUF_SIZE + FIRMWARE_DATA_BUF_SIZE; By keeping the same length between dma_alloc_coherent() and dma_free_coherent() to fix this issue. Signed-off-by: Weiguang Kong --- sound/soc/fsl/fsl_hifi4.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sound/soc/fsl/fsl_hifi4.c b/sound/soc/fsl/fsl_hifi4.c index ed4a5497aac5..6249c698e8b4 100644 --- a/sound/soc/fsl/fsl_hifi4.c +++ b/sound/soc/fsl/fsl_hifi4.c @@ -1684,7 +1684,8 @@ static int fsl_hifi4_remove(struct platform_device *pdev) misc_deregister(&hifi4_miscdev); size = MSG_BUF_SIZE + INPUT_BUF_SIZE + - OUTPUT_BUF_SIZE + FIRMWARE_DATA_BUF_SIZE; + OUTPUT_BUF_SIZE + FIRMWARE_DATA_BUF_SIZE + + SCRATCH_DATA_BUF_SIZE; dma_free_coherent(&pdev->dev, size, hifi4_priv->msg_buf_virt, hifi4_priv->msg_buf_phys); From 3bd60dcafcc7b299bfff60b808ed3901544df3dd Mon Sep 17 00:00:00 2001 From: Shengjiu Wang Date: Thu, 3 Aug 2017 10:05:45 +0800 Subject: [PATCH 12/78] MLK-16129: ASoC: fsl_hifi4: refine the copyright As the fsl_hifi4.c uses the function from uboot/cmd/elf.c, so need to add the copyright of elf.c, and change licence to Dual BSD/GPL. And mxc_hifi4.h is used by user space, so change license to BSD. Signed-off-by: Shengjiu Wang Reviewed-by: Frank Li --- include/uapi/linux/mxc_hifi4.h | 25 +++++++++++++++++-------- sound/soc/fsl/fsl_hifi4.c | 18 ++++++++++++++++-- sound/soc/fsl/fsl_hifi4.h | 2 +- 3 files changed, 34 insertions(+), 11 deletions(-) diff --git a/include/uapi/linux/mxc_hifi4.h b/include/uapi/linux/mxc_hifi4.h index 8e0189059168..f8db59889387 100644 --- a/include/uapi/linux/mxc_hifi4.h +++ b/include/uapi/linux/mxc_hifi4.h @@ -1,16 +1,25 @@ /* * Copyright 2017 NXP * - * The code contained herein is licensed under the GNU General Public - * License. You may obtain a copy of the GNU General Public License - * Version 2 or later at the following locations: + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: * - * http://www.opensource.org/licenses/gpl-license.html - * http://www.gnu.org/copyleft/gpl.html + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. * - * @file mxc_hifi4.h - * - * @ingroup Audio + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef __MXC_HIFI4_UAPI_H__ diff --git a/sound/soc/fsl/fsl_hifi4.c b/sound/soc/fsl/fsl_hifi4.c index 6249c698e8b4..6a7a0482763b 100644 --- a/sound/soc/fsl/fsl_hifi4.c +++ b/sound/soc/fsl/fsl_hifi4.c @@ -2,7 +2,7 @@ * Freescale HIFI 4 driver * * Copyright (c) 2012-2013 by Tensilica Inc. ALL RIGHTS RESERVED. - * Copyright (C) 2017 NXP. + * Copyright 2017 NXP. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -21,6 +21,20 @@ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. + * + * Copyright (c) 2001 William L. Pitts + * All rights reserved. + * + * Redistribution and use in source and binary forms are freely + * permitted provided that the above copyright notice and this + * paragraph and the following disclaimer are duplicated in all + * such forms. + * + * This software is provided "AS IS" and without any express or + * implied warranties, including, without limitation, the implied + * warranties of merchantability and fitness for a particular + * purpose. + * */ #include @@ -1741,4 +1755,4 @@ module_platform_driver(fsl_hifi4_driver); MODULE_DESCRIPTION("Freescale HIFI 4 driver"); MODULE_ALIAS("platform:fsl-hifi4"); -MODULE_LICENSE("GPL v2"); +MODULE_LICENSE("Dual BSD/GPL"); diff --git a/sound/soc/fsl/fsl_hifi4.h b/sound/soc/fsl/fsl_hifi4.h index 7756d694c122..9c1126d98f7f 100644 --- a/sound/soc/fsl/fsl_hifi4.h +++ b/sound/soc/fsl/fsl_hifi4.h @@ -1,7 +1,7 @@ /* * Freescale HIFI 4 driver * - * Copyright (C) 2017 NXP. + * Copyright 2017 NXP. * * 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 From 62bd3cf20387861b49e249a819783f0b8d11bedc Mon Sep 17 00:00:00 2001 From: Shengjiu Wang Date: Wed, 9 Aug 2017 15:25:47 +0800 Subject: [PATCH 13/78] MLK-16174: ASoC: fsl_hifi4: load firmware in device open phase. Move the load firmware operation from probe function to open, Then firmware can be loaded from rootfs. Signed-off-by: Shengjiu Wang --- sound/soc/fsl/fsl_hifi4.c | 49 +++++++++++++++++++++++---------------- 1 file changed, 29 insertions(+), 20 deletions(-) diff --git a/sound/soc/fsl/fsl_hifi4.c b/sound/soc/fsl/fsl_hifi4.c index 6a7a0482763b..3a32cb810104 100644 --- a/sound/soc/fsl/fsl_hifi4.c +++ b/sound/soc/fsl/fsl_hifi4.c @@ -953,7 +953,7 @@ static long fsl_hifi4_load_codec(struct fsl_hifi4 *hifi4_priv, hifi4_priv->ret_status = 0; - dev_err(dev, "code binary is loaded\n"); + dev_dbg(dev, "code binary is loaded\n"); return ret; } @@ -991,7 +991,7 @@ static long fsl_hifi4_load_codec_compat32(struct fsl_hifi4 *hifi4_priv, hifi4_priv->ret_status = 0; - dev_err(dev, "code binary is loaded\n"); + dev_dbg(dev, "code binary is loaded\n"); return ret; } @@ -1156,6 +1156,26 @@ static int fsl_hifi4_open(struct inode *inode, struct file *file) hifi4_engine->hifi4_priv = hifi4_priv; file->private_data = hifi4_engine; + + if (!hifi4_priv->is_ready) { + init_completion(&hifi4_priv->cmd_complete); + + ret = request_firmware_nowait(THIS_MODULE, + FW_ACTION_HOTPLUG, hifi4_priv->fw_name, + dev, + GFP_KERNEL, hifi4_priv, hifi4_load_firmware); + + if (ret) { + dev_err(dev, "failed to load firmware\n"); + return ret; + } + + ret = icm_ack_wait(hifi4_priv, 0); + if (ret) + return ret; + dev_info(dev, "hifi driver registered\n"); + } + return ret; } @@ -1430,8 +1450,14 @@ static void hifi4_load_firmware(const struct firmware *fw, void *context) unsigned char *strtab = 0; /* String table pointer */ unsigned char *image; /* Binary image pointer */ int i; /* Loop counter */ - unsigned long addr = (unsigned long)fw->data; + unsigned long addr; + if (!fw) { + dev_info(dev, "external firmware not found\n"); + return; + } + + addr = (unsigned long)fw->data; ehdr = (Elf32_Ehdr *)addr; /* Find the section header string table for output info */ @@ -1670,23 +1696,6 @@ static int fsl_hifi4_probe(struct platform_device *pdev) hifi4_priv->scratch_buf_phys = buf_phys + offset; hifi4_priv->scratch_buf_size = SCRATCH_DATA_BUF_SIZE; - init_completion(&hifi4_priv->cmd_complete); - hifi4_priv->is_ready = 0; - - ret = request_firmware_nowait(THIS_MODULE, - FW_ACTION_HOTPLUG, fw_name, hifi4_priv->dev, - GFP_KERNEL, hifi4_priv, hifi4_load_firmware); - - if (ret) { - dev_err(&pdev->dev, "failed to load firmware\n"); - return ret; - } - - ret = icm_ack_wait(hifi4_priv, 0); - if (ret) - return ret; - - dev_info(&pdev->dev, "hifi driver registered\n"); return 0; } From 8dfa0f87315214c3eb7c7aca66b1b97e73bde2c6 Mon Sep 17 00:00:00 2001 From: Weiguang Kong Date: Wed, 13 Sep 2017 15:24:38 +0800 Subject: [PATCH 14/78] MLK-16450-1: ASoC: fsl_hifi4: fix crash issue caused by memcpy() When loop testing the hifi4 dirver, a random crash issue always occur when doing memcpy() in decode function. Have found that memcpy() is not suited to transfer data between kernel space and user space, so use copy_from_user() and copy_ to_user() function to replace memcpy() to fix this issue. Signed-off-by: Weiguang Kong --- sound/soc/fsl/fsl_hifi4.c | 36 ++++++++++++++++++++++++++++-------- 1 file changed, 28 insertions(+), 8 deletions(-) diff --git a/sound/soc/fsl/fsl_hifi4.c b/sound/soc/fsl/fsl_hifi4.c index 3a32cb810104..d1052d99cd7d 100644 --- a/sound/soc/fsl/fsl_hifi4.c +++ b/sound/soc/fsl/fsl_hifi4.c @@ -708,8 +708,13 @@ static long fsl_hifi4_decode_frame(struct fsl_hifi4 *hifi4_priv, } if (decode_info.in_buf_off == 0) { - memcpy(hifi4_priv->in_buf_virt, decode_info.in_buf_addr, - decode_info.in_buf_size); + ret = copy_from_user(hifi4_priv->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; } @@ -742,8 +747,13 @@ static long fsl_hifi4_decode_frame(struct fsl_hifi4 *hifi4_priv, if (ret) return ret; - memcpy(decode_info.out_buf_addr, hifi4_priv->out_buf_virt, - codec_iobuf_info->out_cur_offset); + ret = copy_to_user((void __user *)decode_info.out_buf_addr, + hifi4_priv->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; @@ -785,8 +795,13 @@ static long fsl_hifi4_decode_frame_compat32(struct fsl_hifi4 *hifi4_priv, } if (decode_info.in_buf_off == 0) { - memcpy(hifi4_priv->in_buf_virt, decode_info.in_buf_addr, - decode_info.in_buf_size); + ret = copy_from_user(hifi4_priv->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; } @@ -819,8 +834,13 @@ static long fsl_hifi4_decode_frame_compat32(struct fsl_hifi4 *hifi4_priv, if (ret) return ret; - memcpy(decode_info.out_buf_addr, hifi4_priv->out_buf_virt, - codec_iobuf_info->out_cur_offset); + ret = copy_to_user((void __user *)decode_info.out_buf_addr, + hifi4_priv->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; From db15cd2f98001063a91561e1a4346e02722fccbb Mon Sep 17 00:00:00 2001 From: Weiguang Kong Date: Wed, 13 Sep 2017 19:11:02 +0800 Subject: [PATCH 15/78] MLK-16450-2: ASoC: fsl_hifi4: free unused memory when closing device free unused memory which is allocated in fsl_hifi4_open() function when closing the hifi4 device. Signed-off-by: Weiguang Kong --- sound/soc/fsl/fsl_hifi4.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/sound/soc/fsl/fsl_hifi4.c b/sound/soc/fsl/fsl_hifi4.c index d1052d99cd7d..63deb668c79d 100644 --- a/sound/soc/fsl/fsl_hifi4.c +++ b/sound/soc/fsl/fsl_hifi4.c @@ -1201,6 +1201,13 @@ static int fsl_hifi4_open(struct inode *inode, struct file *file) static int fsl_hifi4_close(struct inode *inode, struct file *file) { + struct fsl_hifi4 *hifi4_priv = dev_get_drvdata(hifi4_miscdev.parent); + struct device *dev = hifi4_priv->dev; + struct fsl_hifi4_engine *hifi4_engine; + + hifi4_engine = file->private_data; + devm_kfree(dev, hifi4_engine); + return 0; } From 3afb3b413dbcf4cf19f942237918b38f19c78020 Mon Sep 17 00:00:00 2001 From: Weiguang Kong Date: Thu, 14 Sep 2017 13:32:20 +0800 Subject: [PATCH 16/78] MLK-16468-2: ASoC: fsl_hifi4: add multi-codec support for hifi4 The previous hifi4 driver and framework code can't support multi-codec decoding or encoding together, so change the driver code to support this feature. Currently, the hifi4 driver and framework can support at most 5 codec working together. Signed-off-by: Weiguang Kong Reviewed-by: Mihai Serban --- sound/soc/fsl/fsl_hifi4.c | 499 ++++++++++++++++++++++++++++++++------ sound/soc/fsl/fsl_hifi4.h | 40 ++- 2 files changed, 464 insertions(+), 75 deletions(-) diff --git a/sound/soc/fsl/fsl_hifi4.c b/sound/soc/fsl/fsl_hifi4.c index 63deb668c79d..e3b290749ac4 100644 --- a/sound/soc/fsl/fsl_hifi4.c +++ b/sound/soc/fsl/fsl_hifi4.c @@ -74,11 +74,13 @@ struct decode_info_compat32 { __s32 out_buf_off; __u32 cycles; __u32 input_over; + __u32 process_id; }; struct binary_info_compat32 { __s32 type; compat_long_t file; + __u32 process_id; }; static int get_binary_info_compat32(struct binary_info *kp, @@ -88,7 +90,8 @@ static int get_binary_info_compat32(struct binary_info *kp, if (!access_ok(VERIFY_READ, up, sizeof(struct binary_info_compat32)) || get_user(kp->type, &up->type) || - get_user(p, &up->file) + get_user(p, &up->file) || + get_user(kp->process_id, &up->process_id) ) { return -EFAULT; } @@ -99,6 +102,18 @@ static int get_binary_info_compat32(struct binary_info *kp, return 0; } +static int put_binary_info_compat32(struct binary_info *kp, + struct binary_info_compat32 *up) { + + if (!access_ok(VERIFY_WRITE, up, sizeof(struct binary_info_compat32)) || + put_user(kp->process_id, &up->process_id) + ) { + return -EFAULT; + } + + return 0; +} + static int get_decode_info_compat32(struct decode_info *kp, struct decode_info_compat32 *up) { void __user *up_ptr1; @@ -114,7 +129,8 @@ static int get_decode_info_compat32(struct decode_info *kp, get_user(kp->out_buf_size, &up->out_buf_size) || get_user(kp->out_buf_off, &up->out_buf_off) || get_user(kp->cycles, &up->cycles) || - get_user(kp->input_over, &up->input_over) + get_user(kp->input_over, &up->input_over) || + get_user(kp->process_id, &up->process_id) ) { return -EFAULT; } @@ -144,6 +160,66 @@ static int put_decode_info_compat32(struct decode_info *kp, } #endif +long switch_codec(struct fsl_hifi4 *hifi4_priv, int id) +{ + union icm_header_t apu_icm; + struct hifi4_ext_msg ext_msg; + struct icm_switch_info_t switch_info; + int i; + long ret = 0; + + switch_info.proc_id = id; + switch_info.status = 0; + + 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_SWITCH_CODEC; + apu_icm.size = 8; + + ext_msg.phys = hifi4_priv->msg_buf_phys; + ext_msg.size = sizeof(struct icm_switch_info_t); + memcpy(hifi4_priv->msg_buf_virt, &switch_info, + sizeof(struct icm_switch_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; + + /* check whether the dsp framework switches successfully or not */ + ret = hifi4_priv->ret_status; + if (ret) + return ret; + + /* Because this variables are shared for every codec, so when + * switching, need to recover it value for current codec. + */ + for (i = 0; i < MULTI_CODEC_NUM; i++) { + if (hifi4_priv->process_info[i].process_id == id) { + if (hifi4_priv->process_info[i].status) { + hifi4_priv->cur_res_id = i; + hifi4_priv->pil_info = + hifi4_priv->process_info[i].pil_info_info; + hifi4_priv->objtype = + hifi4_priv->process_info[i].codec_id; + hifi4_priv->codec_iobuf_info.proc_id = + hifi4_priv->process_info[i].proc_id; + break; + } + } + } + /* update the current process id to the new process id */ + hifi4_priv->process_id = id; + + return ret; +} long load_dpu_with_library(struct fsl_hifi4 *hifi4_priv) { @@ -151,8 +227,11 @@ long load_dpu_with_library(struct fsl_hifi4 *hifi4_priv) unsigned char *srambuf = NULL; struct lib_dnld_info_t dpulib; int filesize = 0; + unsigned int id; long ret_val = 0; + id = hifi4_priv->cur_res_id; + /* Load DPU's main program to System memory */ fpInfile = file_open_name(hifi4_priv->objfile, O_RDONLY, 0); if (IS_ERR(fpInfile)) @@ -175,8 +254,12 @@ long load_dpu_with_library(struct fsl_hifi4 *hifi4_priv) if (ret_val != XTLIB_NO_ERR) return ret_val; + hifi4_priv->size_code = dpulib.size_code; + hifi4_priv->size_data = dpulib.size_data; + dpulib.pbuf_code = (unsigned long)hifi4_priv->code_buf_phys; - dpulib.pbuf_data = (unsigned long)hifi4_priv->data_buf_phys; + dpulib.pbuf_data = + (unsigned long)hifi4_priv->process_info[id].data_buf_phys; dpulib.ppil_inf = &hifi4_priv->pil_info; xtlib_host_load_split_pi_library( @@ -548,13 +631,14 @@ static xt_ptr xtlib_load_split_pi_library_common( struct xtlib_loader_globals *xtlib_globals = &hifi4_priv->xtlib_globals; Elf32_Ehdr *header = (Elf32_Ehdr *) library; Elf32_Phdr *pheader; - unsigned int align; + unsigned int align, id; int err = validate_dynamic_splitload(header, hifi4_priv); if (err != XTLIB_NO_ERR) { xtlib_globals->err = err; return 0; } + id = hifi4_priv->cur_res_id; align = find_align(header, hifi4_priv); @@ -596,7 +680,7 @@ static xt_ptr xtlib_load_split_pi_library_common( xtlib_load_seg(&pheader[1], (char *)library + xtlib_host_word(pheader[1].p_offset, xtlib_globals->byteswap), - (xt_ptr)hifi4_priv->data_buf_virt + + (xt_ptr)hifi4_priv->process_info[id].data_buf_virt + xtlib_host_word(pheader[1].p_paddr, xtlib_globals->byteswap), mcpy_fn, mset_fn, hifi4_priv); @@ -629,36 +713,28 @@ xt_ptr xtlib_host_load_split_pi_library(struct xtlib_packaged_library *library, } -static long fsl_hifi4_init_codec(struct fsl_hifi4 *hifi4_priv) +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_pilib_size_t lib_alloc_mem; + int id; long ret = 0; - 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); - - lib_alloc_mem.codec_type = hifi4_priv->objtype; - - memcpy(hifi4_priv->msg_buf_virt, &lib_alloc_mem, - 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 ret; + ret = copy_from_user(&id, user, sizeof(int)); + if (ret) { + dev_err(dev, "failed to get para from user space\n"); + return -EFAULT; + } + if (hifi4_priv->process_id != id) { + ret = switch_codec(hifi4_priv, id); + if (ret) { + dev_err(dev, "failed to switch codec in codec init\n"); + return ret; + } + } init_completion(&hifi4_priv->cmd_complete); hifi4_priv->is_done = 0; @@ -698,7 +774,15 @@ static long fsl_hifi4_decode_frame(struct fsl_hifi4 *hifi4_priv, ret = copy_from_user(&decode_info, user, sizeof(decode_info)); if (ret) { dev_err(dev, "failed to get para from user space\n"); - return ret; + return -EFAULT; + } + + if (hifi4_priv->process_id != decode_info.process_id) { + ret = switch_codec(hifi4_priv, decode_info.process_id); + if (ret) { + dev_err(dev, "failed to switch codec in codec decode frame\n"); + return ret; + } } if (decode_info.in_buf_size > INPUT_BUF_SIZE || @@ -720,6 +804,7 @@ static long fsl_hifi4_decode_frame(struct fsl_hifi4 *hifi4_priv, codec_iobuf_info->inp_addr_sysram = hifi4_priv->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 = hifi4_priv->out_buf_phys; codec_iobuf_info->out_buf_size_max = hifi4_priv->out_buf_size; @@ -758,12 +843,11 @@ static long fsl_hifi4_decode_frame(struct fsl_hifi4 *hifi4_priv, decode_info.in_buf_off = codec_iobuf_info->inp_cur_offset; decode_info.out_buf_off = codec_iobuf_info->out_cur_offset; decode_info.cycles = codec_iobuf_info->cycles; - decode_info.input_over = codec_iobuf_info->input_over; ret = copy_to_user(user, &decode_info, sizeof(decode_info)); if (ret) { dev_err(dev, "failed to send para to user space\n"); - return ret; + return -EFAULT; } ret = hifi4_priv->ret_status; @@ -788,6 +872,14 @@ static long fsl_hifi4_decode_frame_compat32(struct fsl_hifi4 *hifi4_priv, return ret; } + if (hifi4_priv->process_id != decode_info.process_id) { + ret = switch_codec(hifi4_priv, decode_info.process_id); + if (ret) { + dev_err(dev, "failed to switch codec in codec decode frame in compat32 mode\n"); + return ret; + } + } + if (decode_info.in_buf_size > INPUT_BUF_SIZE || decode_info.out_buf_size != OUTPUT_BUF_SIZE) { dev_err(dev, "param error\n"); @@ -807,6 +899,7 @@ static long fsl_hifi4_decode_frame_compat32(struct fsl_hifi4 *hifi4_priv, codec_iobuf_info->inp_addr_sysram = hifi4_priv->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 = hifi4_priv->out_buf_phys; codec_iobuf_info->out_buf_size_max = hifi4_priv->out_buf_size; @@ -845,7 +938,6 @@ static long fsl_hifi4_decode_frame_compat32(struct fsl_hifi4 *hifi4_priv, decode_info.in_buf_off = codec_iobuf_info->inp_cur_offset; decode_info.out_buf_off = codec_iobuf_info->out_cur_offset; decode_info.cycles = codec_iobuf_info->cycles; - decode_info.input_over = codec_iobuf_info->input_over; ret = put_decode_info_compat32(&decode_info, user); if (ret) { @@ -870,7 +962,15 @@ static long fsl_hifi4_get_pcm_prop(struct fsl_hifi4 *hifi4_priv, ret = copy_from_user(&prop_info, user, sizeof(prop_info)); if (ret) { dev_err(dev, "failed to get para from user space\n"); - return ret; + return -EFAULT; + } + + if (hifi4_priv->process_id != prop_info.process_id) { + ret = switch_codec(hifi4_priv, prop_info.process_id); + if (ret) { + dev_err(dev, "failed to switch codec in codec get param\n"); + return ret; + } } init_completion(&hifi4_priv->cmd_complete); @@ -897,7 +997,7 @@ static long fsl_hifi4_get_pcm_prop(struct fsl_hifi4 *hifi4_priv, ret = copy_to_user(user, &prop_info, sizeof(prop_info)); if (ret) { dev_err(dev, "failed to send para to user space\n"); - return ret; + return -EFAULT; } ret = hifi4_priv->ret_status; @@ -915,7 +1015,15 @@ static int fsl_hifi4_set_config(struct fsl_hifi4 *hifi4_priv, void __user *user) 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 ret; + return -EFAULT; + } + + if (hifi4_priv->process_id != prop_config.process_id) { + ret = switch_codec(hifi4_priv, prop_config.process_id); + if (ret) { + dev_err(dev, "failed to switch codec in codec set param\n"); + return ret; + } } init_completion(&hifi4_priv->cmd_complete); @@ -936,6 +1044,7 @@ static int fsl_hifi4_set_config(struct fsl_hifi4 *hifi4_priv, void __user *user) icm_ack_wait(hifi4_priv, apu_icm.allbits); if (ret) return ret; + ret = hifi4_priv->ret_status; return ret; @@ -946,13 +1055,17 @@ static long fsl_hifi4_load_codec(struct fsl_hifi4 *hifi4_priv, { struct device *dev = hifi4_priv->dev; struct filename *fpInfile; + union icm_header_t apu_icm; struct binary_info binary_info; + struct icm_pilib_size_t lib_alloc_mem; + struct hifi4_ext_msg ext_msg; long ret = 0; + long i; ret = copy_from_user(&binary_info, user, sizeof(binary_info)); if (ret) { dev_err(dev, "failed to get para from user space\n"); - return ret; + return -EFAULT; } fpInfile = getname(binary_info.file); @@ -962,13 +1075,75 @@ static long fsl_hifi4_load_codec(struct fsl_hifi4 *hifi4_priv, return PTR_ERR(fpInfile); } + /* check whether the dsp driver has available resource or not */ + for (i = 0; i < MULTI_CODEC_NUM; i++) { + if (!(hifi4_priv->process_info[i].status)) { + hifi4_priv->process_info[i].status = 1; + hifi4_priv->available_resource--; + break; + } + } + if (i >= MULTI_CODEC_NUM) { + dev_err(dev, "out of range of multi codec max number\n"); + return -EINVAL; + } + + /* If dsp driver has available resource, produce a new process + * for the new codec. + */ + hifi4_priv->process_id_count++; + + ret = switch_codec(hifi4_priv, hifi4_priv->process_id_count); + if (ret) { + dev_err(dev, "failed to switch codec in codec load\n"); + return ret; + } + hifi4_priv->objfile = fpInfile; hifi4_priv->objtype = binary_info.type; + hifi4_priv->cur_res_id = i; ret = load_dpu_with_library(hifi4_priv); if (ret) { dev_err(dev, "failed to load code binary, err = %ld\n", 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_MEM_ALLOC; + apu_icm.size = 8; + + ext_msg.phys = hifi4_priv->msg_buf_phys; + ext_msg.size = sizeof(struct icm_pilib_size_t); + + lib_alloc_mem.codec_type = hifi4_priv->objtype; + lib_alloc_mem.text_size = hifi4_priv->size_code; + lib_alloc_mem.data_size = hifi4_priv->size_data; + + memcpy(hifi4_priv->msg_buf_virt, &lib_alloc_mem, + 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 ret; + + /* save current codec information */ + hifi4_priv->process_info[i].process_id = hifi4_priv->process_id; + hifi4_priv->process_info[i].codec_id = hifi4_priv->objtype; + hifi4_priv->process_info[i].pil_info_info = hifi4_priv->pil_info; + + /* return process id of this codec to user space */ + binary_info.process_id = hifi4_priv->process_id; + ret = copy_to_user(user, &binary_info, sizeof(struct binary_info)); + if (ret) { + dev_err(dev, "failed to send para to user space\n"); + return -EFAULT; } hifi4_priv->ret_status = 0; @@ -984,8 +1159,12 @@ static long fsl_hifi4_load_codec_compat32(struct fsl_hifi4 *hifi4_priv, { struct device *dev = hifi4_priv->dev; struct filename *fpInfile; + union icm_header_t apu_icm; struct binary_info binary_info; + struct icm_pilib_size_t lib_alloc_mem; + struct hifi4_ext_msg ext_msg; long ret = 0; + long i; ret = get_binary_info_compat32(&binary_info, user); if (ret) { @@ -1000,15 +1179,78 @@ static long fsl_hifi4_load_codec_compat32(struct fsl_hifi4 *hifi4_priv, return PTR_ERR(fpInfile); } + /* check whether the dsp driver has available resource or not */ + for (i = 0; i < MULTI_CODEC_NUM; i++) { + if (!(hifi4_priv->process_info[i].status)) { + hifi4_priv->process_info[i].status = 1; + hifi4_priv->available_resource--; + break; + } + } + if (i >= MULTI_CODEC_NUM) { + dev_err(dev, "out of range of multi codec max number\n"); + return -EINVAL; + } + + /* If dsp driver has available resource, produce a new process + * for the new codec. + */ + hifi4_priv->process_id_count++; + + ret = switch_codec(hifi4_priv, hifi4_priv->process_id_count); + if (ret) { + dev_err(dev, "failed to switch codec in codec load\n"); + return ret; + } + hifi4_priv->objfile = fpInfile; hifi4_priv->objtype = binary_info.type; + hifi4_priv->cur_res_id = i; ret = load_dpu_with_library(hifi4_priv); 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_MEM_ALLOC; + apu_icm.size = 8; + + ext_msg.phys = hifi4_priv->msg_buf_phys; + ext_msg.size = sizeof(struct icm_pilib_size_t); + + lib_alloc_mem.codec_type = hifi4_priv->objtype; + lib_alloc_mem.text_size = hifi4_priv->size_code; + lib_alloc_mem.data_size = hifi4_priv->size_data; + + memcpy(hifi4_priv->msg_buf_virt, &lib_alloc_mem, + 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 ret; + + /* save current codec information */ + hifi4_priv->process_info[i].process_id = hifi4_priv->process_id; + hifi4_priv->process_info[i].codec_id = hifi4_priv->objtype; + hifi4_priv->process_info[i].pil_info_info = hifi4_priv->pil_info; + + /* return process id of this codec to user space */ + binary_info.process_id = hifi4_priv->process_id; + ret = put_binary_info_compat32(&binary_info, user); + if (ret) { + dev_err(dev, "failed to send para to user space\n"); + return ret; + } + hifi4_priv->ret_status = 0; dev_dbg(dev, "code binary is loaded\n"); @@ -1017,17 +1259,32 @@ static long fsl_hifi4_load_codec_compat32(struct fsl_hifi4 *hifi4_priv, } #endif -static long fsl_hifi4_codec_open(struct fsl_hifi4 *hifi4_priv) +static long fsl_hifi4_codec_open(struct fsl_hifi4 *hifi4_priv, + void __user *user) { + struct device *dev = hifi4_priv->dev; union icm_header_t apu_icm; struct icm_cdc_uinp_t cdc_user_inp; struct hifi4_ext_msg ext_msg; + 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; + } + + if (hifi4_priv->process_id != id) { + ret = switch_codec(hifi4_priv, id); + if (ret) { + dev_err(dev, "failed to switch codec in codec open\n"); + return ret; + } + } + cdc_user_inp.proc_id = 0; cdc_user_inp.codec_id = hifi4_priv->objtype; - cdc_user_inp.crc_check = 0; - cdc_user_inp.pcm_wd_sz = 16; init_completion(&hifi4_priv->cmd_complete); hifi4_priv->is_done = 0; @@ -1051,15 +1308,36 @@ static long fsl_hifi4_codec_open(struct fsl_hifi4 *hifi4_priv) if (ret) return ret; + /* save current codec information */ + hifi4_priv->process_info[hifi4_priv->cur_res_id].proc_id = + hifi4_priv->codec_iobuf_info.proc_id; + ret = hifi4_priv->ret_status; return ret; } -static int fsl_hifi4_codec_close(struct fsl_hifi4 *hifi4_priv) +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; + 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; + } + + if (hifi4_priv->process_id != id) { + ret = switch_codec(hifi4_priv, id); + if (ret) { + dev_err(dev, "failed to switch codec in codec close\n"); + return ret; + } + } + init_completion(&hifi4_priv->cmd_complete); hifi4_priv->is_done = 0; @@ -1072,6 +1350,18 @@ static int fsl_hifi4_codec_close(struct fsl_hifi4 *hifi4_priv) /* wait for response here */ ret = icm_ack_wait(hifi4_priv, apu_icm.allbits); + if (ret) + return ret; + + /* Making status to 0 means releasing the resource that + * current codec occupies. + */ + hifi4_priv->process_info[hifi4_priv->cur_res_id].status = 0; + hifi4_priv->available_resource++; + + /* If no codec occupies the resource, zero the process id count */ + if (hifi4_priv->available_resource >= MULTI_CODEC_NUM) + hifi4_priv->process_id_count = 0; return ret; } @@ -1084,26 +1374,32 @@ 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 = file->private_data; - struct fsl_hifi4 *hifi4_priv = hifi4_engine->hifi4_priv; - void __user *user = (void __user *)arg; + struct fsl_hifi4_engine *hifi4_engine; + struct fsl_hifi4 *hifi4_priv; + void __user *user; long ret = 0; + hifi4_engine = file->private_data; + hifi4_priv = hifi4_engine->hifi4_priv; + user = (void __user *)arg; + + mutex_lock(&hifi4_priv->hifi4_mutex); + switch (cmd) { case HIFI4_LOAD_CODEC: ret = fsl_hifi4_load_codec(hifi4_priv, user); break; case HIFI4_INIT_CODEC: - ret = fsl_hifi4_init_codec(hifi4_priv); + ret = fsl_hifi4_init_codec(hifi4_priv, user); break; case HIFI4_CODEC_OPEN: - ret = fsl_hifi4_codec_open(hifi4_priv); + 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); + ret = fsl_hifi4_codec_close(hifi4_priv, user); break; case HIFI4_UNLOAD_CODEC: break; @@ -1117,6 +1413,8 @@ static long fsl_hifi4_ioctl(struct file *file, unsigned int cmd, break; } + mutex_unlock(&hifi4_priv->hifi4_mutex); + return ret; } @@ -1124,26 +1422,32 @@ static long fsl_hifi4_ioctl(struct file *file, unsigned int cmd, static long fsl_hifi4_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { - struct fsl_hifi4_engine *hifi4_engine = file->private_data; - struct fsl_hifi4 *hifi4_priv = hifi4_engine->hifi4_priv; - void __user *user = compat_ptr(arg); + struct fsl_hifi4_engine *hifi4_engine; + struct fsl_hifi4 *hifi4_priv; + void __user *user; long ret = 0; + hifi4_engine = file->private_data; + hifi4_priv = hifi4_engine->hifi4_priv; + user = compat_ptr(arg); + + mutex_lock(&hifi4_priv->hifi4_mutex); + switch (cmd) { 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); + ret = fsl_hifi4_init_codec(hifi4_priv, user); break; case HIFI4_CODEC_OPEN: - ret = fsl_hifi4_codec_open(hifi4_priv); + ret = fsl_hifi4_codec_open(hifi4_priv, user); break; case HIFI4_DECODE_ONE_FRAME: ret = fsl_hifi4_decode_frame_compat32(hifi4_priv, user); break; case HIFI4_CODEC_CLOSE: - ret = fsl_hifi4_codec_close(hifi4_priv); + ret = fsl_hifi4_codec_close(hifi4_priv, user); break; case HIFI4_UNLOAD_CODEC: break; @@ -1157,17 +1461,24 @@ static long fsl_hifi4_compat_ioctl(struct file *file, unsigned int cmd, break; } + mutex_unlock(&hifi4_priv->hifi4_mutex); + return ret; } #endif static int fsl_hifi4_open(struct inode *inode, struct file *file) { - struct fsl_hifi4 *hifi4_priv = dev_get_drvdata(hifi4_miscdev.parent); - struct device *dev = hifi4_priv->dev; + struct fsl_hifi4 *hifi4_priv; + struct device *dev; struct fsl_hifi4_engine *hifi4_engine; int ret = 0; + hifi4_priv = dev_get_drvdata(hifi4_miscdev.parent); + dev = hifi4_priv->dev; + + mutex_lock(&hifi4_priv->hifi4_mutex); + hifi4_engine = devm_kzalloc(dev, sizeof(struct fsl_hifi4_engine), GFP_KERNEL); if (!hifi4_engine) @@ -1195,19 +1506,26 @@ static int fsl_hifi4_open(struct inode *inode, struct file *file) return ret; dev_info(dev, "hifi driver registered\n"); } + mutex_unlock(&hifi4_priv->hifi4_mutex); return ret; } static int fsl_hifi4_close(struct inode *inode, struct file *file) { - struct fsl_hifi4 *hifi4_priv = dev_get_drvdata(hifi4_miscdev.parent); - struct device *dev = hifi4_priv->dev; + struct fsl_hifi4 *hifi4_priv; + struct device *dev; struct fsl_hifi4_engine *hifi4_engine; + hifi4_priv = dev_get_drvdata(hifi4_miscdev.parent); + mutex_lock(&hifi4_priv->hifi4_mutex); + + dev = hifi4_priv->dev; hifi4_engine = file->private_data; devm_kfree(dev, hifi4_engine); + mutex_unlock(&hifi4_priv->hifi4_mutex); + return 0; } @@ -1312,8 +1630,10 @@ int process_act_complete(struct fsl_hifi4 *hifi4_priv, u32 msg) switch (recd_msg.sub_msg) { case ICM_PI_LIB_MEM_ALLOC: - hifi4_priv->is_done = 1; - complete(&hifi4_priv->cmd_complete); + { + hifi4_priv->is_done = 1; + complete(&hifi4_priv->cmd_complete); + } break; case ICM_OPEN: @@ -1321,10 +1641,10 @@ int process_act_complete(struct fsl_hifi4 *hifi4_priv, u32 msg) struct icm_open_resp_info_t *pext_msg = (struct icm_open_resp_info_t *)pmsg_apu; codec_iobuf_info->proc_id = pext_msg->proc_id; - hifi4_priv->is_done = 1; hifi4_priv->dpu_tstamp = (struct timestamp_info_t *)((long)pext_msg->dtstamp); hifi4_priv->ret_status = pext_msg->ret; + hifi4_priv->is_done = 1; complete(&hifi4_priv->cmd_complete); } break; @@ -1340,9 +1660,9 @@ int process_act_complete(struct fsl_hifi4 *hifi4_priv, u32 msg) codec_iobuf_info->cycles = ext_msg->cycles; } - complete(&hifi4_priv->cmd_complete); - hifi4_priv->is_done = 1; hifi4_priv->ret_status = ext_msg->ret; + hifi4_priv->is_done = 1; + complete(&hifi4_priv->cmd_complete); } break; @@ -1357,10 +1677,10 @@ int process_act_complete(struct fsl_hifi4 *hifi4_priv, u32 msg) pcm_prop_info->bits = ext_msg->bits; pcm_prop_info->consumed_bytes = ext_msg->consumed_bytes; - - complete(&hifi4_priv->cmd_complete); - hifi4_priv->is_done = 1; hifi4_priv->ret_status = ext_msg->ret; + + hifi4_priv->is_done = 1; + complete(&hifi4_priv->cmd_complete); } break; @@ -1368,20 +1688,30 @@ int process_act_complete(struct fsl_hifi4 *hifi4_priv, u32 msg) { struct prop_config *ext_msg = (struct prop_config *)pmsg_apu; - complete(&hifi4_priv->cmd_complete); - hifi4_priv->is_done = 1; hifi4_priv->ret_status = ext_msg->ret; + hifi4_priv->is_done = 1; + complete(&hifi4_priv->cmd_complete); } break; case ICM_PI_LIB_INIT: - complete(&hifi4_priv->cmd_complete); hifi4_priv->is_done = 1; + complete(&hifi4_priv->cmd_complete); break; case ICM_CLOSE: - complete(&hifi4_priv->cmd_complete); hifi4_priv->is_done = 1; + complete(&hifi4_priv->cmd_complete); + break; + + case ICM_SWITCH_CODEC: + { + struct icm_switch_info_t *ext_msg = + (struct icm_switch_info_t *)pmsg_apu; + hifi4_priv->ret_status = ext_msg->status; + hifi4_priv->is_done = 1; + complete(&hifi4_priv->cmd_complete); + } break; default: @@ -1405,7 +1735,8 @@ int send_dpu_ext_msg_addr(struct fsl_hifi4 *hifi4_priv) apu_icm.msg = ICM_EXT_MSG_ADDR; apu_icm.size = 8; ext_msg.phys = hifi4_priv->msg_buf_phys; - ext_msg.size = 8*4; + /* 10 means variable numbers that need to be transferred */ + ext_msg.size = 10*4; /* 10 * sizeof(int) */ dpu_ext_msg->ext_msg_phys = hifi4_priv->msg_buf_phys + 2048; dpu_ext_msg->ext_msg_size = 2048; dpu_ext_msg->code_phys = hifi4_priv->code_buf_phys; @@ -1414,6 +1745,8 @@ int send_dpu_ext_msg_addr(struct fsl_hifi4 *hifi4_priv) dpu_ext_msg->data_size = hifi4_priv->data_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->system_input_buf_phys = hifi4_priv->in_buf_phys; + dpu_ext_msg->system_input_buf_size = hifi4_priv->in_buf_size; icm_intr_extended_send(hifi4_priv, apu_icm.allbits, &ext_msg); @@ -1604,7 +1937,7 @@ static int fsl_hifi4_probe(struct platform_device *pdev) void __iomem *regs; void *buf_virt; dma_addr_t buf_phys; - int size, offset; + int size, offset, i; int ret; hifi4_priv = devm_kzalloc(&pdev->dev, sizeof(*hifi4_priv), GFP_KERNEL); @@ -1723,6 +2056,30 @@ static int fsl_hifi4_probe(struct platform_device *pdev) hifi4_priv->scratch_buf_phys = buf_phys + offset; hifi4_priv->scratch_buf_size = SCRATCH_DATA_BUF_SIZE; + /* process_id_count is a counter to produce new id + * process_id is current codec's id + */ + hifi4_priv->process_id_count = 0; + hifi4_priv->process_id = 0; + + /* initialize the resources of multi codec + * MULTI_CODEC_NUM is the max codec number that dsp + * driver and framework can support. + */ + hifi4_priv->available_resource = MULTI_CODEC_NUM; + for (i = 0; i < MULTI_CODEC_NUM; i++) { + hifi4_priv->process_info[i].data_buf_virt = + hifi4_priv->data_buf_virt + + i * hifi4_priv->data_buf_size / MULTI_CODEC_NUM; + hifi4_priv->process_info[i].data_buf_phys = + hifi4_priv->data_buf_phys + + i * hifi4_priv->data_buf_size / MULTI_CODEC_NUM; + + hifi4_priv->process_info[i].status = 0; + } + + mutex_init(&hifi4_priv->hifi4_mutex); + return 0; } diff --git a/sound/soc/fsl/fsl_hifi4.h b/sound/soc/fsl/fsl_hifi4.h index 9c1126d98f7f..6ccae9684588 100644 --- a/sound/soc/fsl/fsl_hifi4.h +++ b/sound/soc/fsl/fsl_hifi4.h @@ -21,6 +21,7 @@ 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 enum { XTLIB_NO_ERR = 0, @@ -62,8 +63,6 @@ struct icm_cdc_iobuf_t { struct icm_cdc_uinp_t { u32 proc_id; /* audio id */ u32 codec_id; /* codec identifier */ - u32 pcm_wd_sz; /* pcm word size; only 16 or 24 */ - u32 crc_check; /* 0: disable, 1: enable */ }; struct icm_pcm_prop_t { @@ -135,6 +134,8 @@ enum icm_action_t { ICM_CORE_EXIT, ICM_EXT_MSG_ADDR, + + ICM_SWITCH_CODEC, }; enum aud_status_t { @@ -151,6 +152,11 @@ struct icm_open_resp_info_t { s32 ret; }; +struct icm_switch_info_t { + u32 proc_id; /* audio id */ + u32 status; /* codec status */ +}; + struct lib_dnld_info_t { unsigned long pbuf_code; unsigned long pbuf_data; @@ -167,6 +173,18 @@ struct icm_pilib_size_t { u32 data_size; }; +struct icm_process_info { + unsigned int process_id; + unsigned int codec_id; + unsigned int proc_id; + + void *data_buf_virt; + dma_addr_t data_buf_phys; + + struct xtlib_pil_info pil_info_info; + unsigned int status; +}; + struct fsl_hifi4 { struct device *dev; const char *fw_name; @@ -214,6 +232,18 @@ struct fsl_hifi4 { struct xtlib_pil_info pil_info; struct xtlib_loader_globals xtlib_globals; struct timestamp_info_t *dpu_tstamp; + + struct mutex hifi4_mutex; + + unsigned int process_id; + unsigned int process_id_count; + + unsigned int size_code; + unsigned int size_data; + + struct icm_process_info process_info[MULTI_CODEC_NUM]; + unsigned int available_resource; + unsigned int cur_res_id; }; struct fsl_hifi4_engine { @@ -234,6 +264,8 @@ struct hifi4_mem_msg { u32 data_size; u32 scratch_phys; u32 scratch_size; + u32 system_input_buf_phys; + u32 system_input_buf_size; }; #define IRAM_OFFSET 0x10000 @@ -257,8 +289,8 @@ struct hifi4_mem_msg { #define MSG_BUF_SIZE 4096 #define INPUT_BUF_SIZE 4096 #define OUTPUT_BUF_SIZE 16384 -#define FIRMWARE_DATA_BUF_SIZE 0x100000 -#define SCRATCH_DATA_BUF_SIZE 0x100000 +#define FIRMWARE_DATA_BUF_SIZE (MULTI_CODEC_NUM * 0x80000) +#define SCRATCH_DATA_BUF_SIZE (MULTI_CODEC_NUM * 0x80000) #define MEMORY_REMAP_OFFSET 0x39000000 From 47903b06afa216ad034c45958a6ce70dd3ae6363 Mon Sep 17 00:00:00 2001 From: Weiguang Kong Date: Fri, 29 Sep 2017 14:24:59 +0800 Subject: [PATCH 17/78] MLK-16558: ASoC: fsl_hifi4: add reference counter for hifi4 device When abnormal situation occurs and the current process terminates abnormally, the hifi4 driver can't get the HIFI4_CODEC_CLOSE CMD from user space to release the multi-codec resource, so the current resource can't be used again. Have found that the fsl_hifi4_close() function can be called implicitly when process terminates abnormally, so add a reference counter in fsl_hifi4_open() and fsl_hifi4_close() to check this abnormal situation, when the number is same for opening and closing hifi4 device, the multi-codec should be reinitialized again and the hifi4 driver should send ICM_EXT_MSG_ADDR CMD to hifi4 framework to initialize the multi-codec resources too. Signed-off-by: Weiguang Kong --- sound/soc/fsl/fsl_hifi4.c | 34 ++++++++++++++++++++++++++++++++++ sound/soc/fsl/fsl_hifi4.h | 2 ++ 2 files changed, 36 insertions(+) diff --git a/sound/soc/fsl/fsl_hifi4.c b/sound/soc/fsl/fsl_hifi4.c index e3b290749ac4..207ed3a53155 100644 --- a/sound/soc/fsl/fsl_hifi4.c +++ b/sound/soc/fsl/fsl_hifi4.c @@ -1467,6 +1467,24 @@ static long fsl_hifi4_compat_ioctl(struct file *file, unsigned int cmd, } #endif +void resource_release(struct fsl_hifi4 *hifi4_priv) +{ + int i; + + hifi4_priv->available_resource = MULTI_CODEC_NUM; + for (i = 0; i < MULTI_CODEC_NUM; i++) { + hifi4_priv->process_info[i].data_buf_virt = + hifi4_priv->data_buf_virt + + i * hifi4_priv->data_buf_size / MULTI_CODEC_NUM; + hifi4_priv->process_info[i].data_buf_phys = + hifi4_priv->data_buf_phys + + i * hifi4_priv->data_buf_size / MULTI_CODEC_NUM; + + hifi4_priv->process_info[i].status = 0; + } + send_dpu_ext_msg_addr(hifi4_priv); +} + static int fsl_hifi4_open(struct inode *inode, struct file *file) { struct fsl_hifi4 *hifi4_priv; @@ -1506,6 +1524,10 @@ static int fsl_hifi4_open(struct inode *inode, struct file *file) return ret; dev_info(dev, "hifi driver registered\n"); } + + /* increase reference counter when opening device */ + atomic_long_inc(&hifi4_priv->refcnt); + mutex_unlock(&hifi4_priv->hifi4_mutex); return ret; @@ -1524,6 +1546,14 @@ static int fsl_hifi4_close(struct inode *inode, struct file *file) hifi4_engine = file->private_data; devm_kfree(dev, hifi4_engine); + /* decrease reference counter when closing device */ + atomic_long_dec(&hifi4_priv->refcnt); + /* If device is free, reinitialize the resource of + * hifi4 driver and framework + */ + if (atomic_long_read(&hifi4_priv->refcnt) <= 0) + resource_release(hifi4_priv); + mutex_unlock(&hifi4_priv->hifi4_mutex); return 0; @@ -2078,6 +2108,10 @@ static int fsl_hifi4_probe(struct platform_device *pdev) hifi4_priv->process_info[i].status = 0; } + /* initialize the reference counter for hifi4_priv + * structure + */ + atomic_long_set(&hifi4_priv->refcnt, 0); mutex_init(&hifi4_priv->hifi4_mutex); return 0; diff --git a/sound/soc/fsl/fsl_hifi4.h b/sound/soc/fsl/fsl_hifi4.h index 6ccae9684588..3ec452532f34 100644 --- a/sound/soc/fsl/fsl_hifi4.h +++ b/sound/soc/fsl/fsl_hifi4.h @@ -193,6 +193,7 @@ struct fsl_hifi4 { struct imx_sc_ipc *hifi_ipcHandle; unsigned int hifi_mu_id; int hifi_mu_init; + atomic_long_t refcnt; unsigned long paddr; unsigned long dram0; unsigned long dram1; @@ -303,6 +304,7 @@ 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( From cd0e89c920c27028d989a65d19cc829177822c3e Mon Sep 17 00:00:00 2001 From: Weiguang Kong Date: Thu, 28 Sep 2017 12:49:49 +0800 Subject: [PATCH 18/78] MLK-16545-2: ASoC: fsl_hifi4: add support to reset hifi4 codec add cases to support resetting the hifi4 codec when receiving HIFI4_RESET_CODEC command from the user space. Signed-off-by: Weiguang Kong Reviewed-by: Daniel Baluta Signed-off-by: Dong Aisheng --- sound/soc/fsl/fsl_hifi4.c | 68 +++++++++++++++++++++++++++++++++++++++ sound/soc/fsl/fsl_hifi4.h | 6 ++++ 2 files changed, 74 insertions(+) diff --git a/sound/soc/fsl/fsl_hifi4.c b/sound/soc/fsl/fsl_hifi4.c index 207ed3a53155..cc48cb1cd0f4 100644 --- a/sound/soc/fsl/fsl_hifi4.c +++ b/sound/soc/fsl/fsl_hifi4.c @@ -1366,6 +1366,58 @@ static int fsl_hifi4_codec_close(struct fsl_hifi4 *hifi4_priv, return ret; } +static int fsl_hifi4_codec_reset(struct fsl_hifi4 *hifi4_priv, + void __user *user) +{ + struct device *dev = hifi4_priv->dev; + union icm_header_t apu_icm; + struct icm_cdc_iobuf_t *codec_iobuf_info = + &hifi4_priv->codec_iobuf_info; + int id; + long err = 0; + 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; + } + + if (hifi4_priv->process_id != id) { + err = switch_codec(hifi4_priv, id); + if (err) { + dev_err(dev, "failed to switch codec in codec reset\n"); + return err; + } + } + + 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 = 0; + icm_intr_send(hifi4_priv, apu_icm.allbits); + + /* wait for response here */ + err = icm_ack_wait(hifi4_priv, apu_icm.allbits); + if (err) + return err; + + /* reset codec_iobuf_info */ + codec_iobuf_info->inp_buf_size_max = 0; + codec_iobuf_info->inp_cur_offset = 0; + + codec_iobuf_info->out_buf_size_max = 0; + codec_iobuf_info->out_cur_offset = 0; + + err = hifi4_priv->ret_status; + + return err; +} + static struct miscdevice hifi4_miscdev = { .name = "mxc_hifi4", .minor = MISC_DYNAMIC_MINOR, @@ -1409,6 +1461,9 @@ static long fsl_hifi4_ioctl(struct file *file, unsigned int cmd, 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; } @@ -1457,6 +1512,9 @@ static long fsl_hifi4_compat_ioctl(struct file *file, unsigned int cmd, 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; } @@ -1744,6 +1802,16 @@ int process_act_complete(struct fsl_hifi4 *hifi4_priv, u32 msg) } break; + case ICM_RESET: + { + struct icm_reset_info_t *ext_msg = + (struct icm_reset_info_t *)pmsg_apu; + hifi4_priv->ret_status = ext_msg->ret; + hifi4_priv->is_done = 1; + complete(&hifi4_priv->cmd_complete); + } + break; + default: ret_val = -1; break; diff --git a/sound/soc/fsl/fsl_hifi4.h b/sound/soc/fsl/fsl_hifi4.h index 3ec452532f34..6ec239824544 100644 --- a/sound/soc/fsl/fsl_hifi4.h +++ b/sound/soc/fsl/fsl_hifi4.h @@ -136,6 +136,7 @@ enum icm_action_t { ICM_EXT_MSG_ADDR, ICM_SWITCH_CODEC, + ICM_RESET, }; enum aud_status_t { @@ -152,6 +153,11 @@ struct icm_open_resp_info_t { s32 ret; }; +struct icm_reset_info_t { + u32 codec_id; + s32 ret; /* executed status of reset function */ +}; + struct icm_switch_info_t { u32 proc_id; /* audio id */ u32 status; /* codec status */ From c20260581b086b50137ee9cf5d98ac8b9b4d4e01 Mon Sep 17 00:00:00 2001 From: Shengjiu Wang Date: Thu, 19 Oct 2017 15:06:37 +0800 Subject: [PATCH 19/78] MLK-16674: ASoC: fsl_hifi4: enable pm runtime for hifi4 Enable pm runtime for hifi4, so the firmware may load many times, The shdr->sh_addr can't be refined in hifi4_load_firmware, otherwise it should impact the load operation in next time. Signed-off-by: Shengjiu Wang --- sound/soc/fsl/fsl_hifi4.c | 27 ++++++++++++++++++++++++--- 1 file changed, 24 insertions(+), 3 deletions(-) diff --git a/sound/soc/fsl/fsl_hifi4.c b/sound/soc/fsl/fsl_hifi4.c index cc48cb1cd0f4..5daf9a36ab31 100644 --- a/sound/soc/fsl/fsl_hifi4.c +++ b/sound/soc/fsl/fsl_hifi4.c @@ -1553,6 +1553,7 @@ static int fsl_hifi4_open(struct inode *inode, struct file *file) hifi4_priv = dev_get_drvdata(hifi4_miscdev.parent); dev = hifi4_priv->dev; + pm_runtime_get_sync(dev); mutex_lock(&hifi4_priv->hifi4_mutex); hifi4_engine = devm_kzalloc(dev, @@ -1613,6 +1614,7 @@ 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; } @@ -1905,6 +1907,7 @@ static void hifi4_load_firmware(const struct firmware *fw, void *context) struct device *dev = hifi4_priv->dev; Elf32_Ehdr *ehdr; /* Elf header structure pointer */ Elf32_Shdr *shdr; /* Section header structure pointer */ + Elf32_Addr sh_addr; unsigned char *strtab = 0; /* String table pointer */ unsigned char *image; /* Binary image pointer */ int i; /* Loop counter */ @@ -1942,23 +1945,25 @@ static void hifi4_load_firmware(const struct firmware *fw, void *context) (long)shdr->sh_size); } + sh_addr = shdr->sh_addr; + if ((!strcmp(&strtab[shdr->sh_name], ".rodata")) || (!strcmp(&strtab[shdr->sh_name], ".text")) || (!strcmp(&strtab[shdr->sh_name], ".data")) || (!strcmp(&strtab[shdr->sh_name], ".bss")) ) { - shdr->sh_addr = shdr->sh_addr + MEMORY_REMAP_OFFSET; + sh_addr = shdr->sh_addr + MEMORY_REMAP_OFFSET; } if (shdr->sh_type == SHT_NOBITS) { memset_hifi((void *)(hifi4_priv->regs + - (shdr->sh_addr - hifi4_priv->paddr)), + (sh_addr - hifi4_priv->paddr)), 0, shdr->sh_size); } else { image = (unsigned char *)addr + shdr->sh_offset; memcpy_hifi((void *)(hifi4_priv->regs + - (shdr->sh_addr - hifi4_priv->paddr)), + (sh_addr - hifi4_priv->paddr)), (const void *)image, shdr->sh_size); } @@ -2204,11 +2209,27 @@ static int fsl_hifi4_remove(struct platform_device *pdev) #ifdef CONFIG_PM static int fsl_hifi4_runtime_resume(struct device *dev) { + struct fsl_hifi4 *hifi4_priv = dev_get_drvdata(dev); + + if (sc_pm_set_resource_power_mode(hifi4_priv->hifi_ipcHandle, + SC_R_DSP_RAM, SC_PM_PW_MODE_ON) != SC_ERR_NONE) { + dev_err(dev, "Error power on HIFI RAM\n"); + return -EIO; + } + return 0; } static int fsl_hifi4_runtime_suspend(struct device *dev) { + struct fsl_hifi4 *hifi4_priv = dev_get_drvdata(dev); + + 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; return 0; } #endif /* CONFIG_PM */ From 55981e9f8d6fd3a8fae58b6d6f180d76286f33fd Mon Sep 17 00:00:00 2001 From: Weiguang Kong Date: Wed, 25 Oct 2017 18:16:21 +0800 Subject: [PATCH 20/78] MLK-16691: ASoC: fsl_hifi4: unlock mutex before return error When error occurs in fsl_hifi4_open() function, before this function exists, "hifi4_priv->hifi4_mutex" should be unlocked. If not, when the device is opened next time, the kernel will be hanged. Signed-off-by: Weiguang Kong --- sound/soc/fsl/fsl_hifi4.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/sound/soc/fsl/fsl_hifi4.c b/sound/soc/fsl/fsl_hifi4.c index 5daf9a36ab31..d451e89c28ce 100644 --- a/sound/soc/fsl/fsl_hifi4.c +++ b/sound/soc/fsl/fsl_hifi4.c @@ -1558,8 +1558,10 @@ static int fsl_hifi4_open(struct inode *inode, struct file *file) hifi4_engine = devm_kzalloc(dev, sizeof(struct fsl_hifi4_engine), GFP_KERNEL); - if (!hifi4_engine) + if (!hifi4_engine) { + mutex_unlock(&hifi4_priv->hifi4_mutex); return -ENOMEM; + } hifi4_engine->hifi4_priv = hifi4_priv; @@ -1575,12 +1577,15 @@ static int fsl_hifi4_open(struct inode *inode, struct file *file) 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); - if (ret) + if (ret) { + mutex_unlock(&hifi4_priv->hifi4_mutex); return ret; + } dev_info(dev, "hifi driver registered\n"); } From a3101ecf1ae97ca69096d7a2619b7a623941a2d4 Mon Sep 17 00:00:00 2001 From: Weiguang Kong Date: Mon, 23 Oct 2017 09:42:08 +0800 Subject: [PATCH 21/78] MLK-16678-2: ASoC: fsl_hifi4: move hifi4 firmware to SDRAM move hifi4 dsp firmware's code and data section to SDRAM space move hifi4 dsp codec lib's code section to SDRAM space Signed-off-by: Weiguang Kong --- sound/soc/fsl/fsl_hifi4.c | 55 +++++++++++++++++++++++++-------------- sound/soc/fsl/fsl_hifi4.h | 10 +++++++ 2 files changed, 45 insertions(+), 20 deletions(-) diff --git a/sound/soc/fsl/fsl_hifi4.c b/sound/soc/fsl/fsl_hifi4.c index d451e89c28ce..fc59526b9528 100644 --- a/sound/soc/fsl/fsl_hifi4.c +++ b/sound/soc/fsl/fsl_hifi4.c @@ -1952,25 +1952,28 @@ static void hifi4_load_firmware(const struct firmware *fw, void *context) sh_addr = shdr->sh_addr; - if ((!strcmp(&strtab[shdr->sh_name], ".rodata")) || - (!strcmp(&strtab[shdr->sh_name], ".text")) || - (!strcmp(&strtab[shdr->sh_name], ".data")) || - (!strcmp(&strtab[shdr->sh_name], ".bss")) - ) { - sh_addr = shdr->sh_addr + MEMORY_REMAP_OFFSET; - } - if (shdr->sh_type == SHT_NOBITS) { - memset_hifi((void *)(hifi4_priv->regs + - (sh_addr - hifi4_priv->paddr)), - 0, - shdr->sh_size); + memset_hifi((void *)(hifi4_priv->sdram_vir_addr + + (sh_addr - hifi4_priv->sdram_phys_addr)), + 0, + shdr->sh_size); } else { image = (unsigned char *)addr + shdr->sh_offset; - memcpy_hifi((void *)(hifi4_priv->regs + - (sh_addr - hifi4_priv->paddr)), - (const void *)image, - shdr->sh_size); + if ((!strcmp(&strtab[shdr->sh_name], ".rodata")) || + (!strcmp(&strtab[shdr->sh_name], ".text")) || + (!strcmp(&strtab[shdr->sh_name], ".data")) || + (!strcmp(&strtab[shdr->sh_name], ".bss")) + ) { + memcpy_hifi((void *)(hifi4_priv->sdram_vir_addr + + (sh_addr - hifi4_priv->sdram_phys_addr)), + (const void *)image, + shdr->sh_size); + } else { + memcpy_hifi((void *)(hifi4_priv->regs + + (sh_addr - hifi4_priv->paddr)), + (const void *)image, + shdr->sh_size); + } } } @@ -2082,7 +2085,7 @@ static int fsl_hifi4_probe(struct platform_device *pdev) } ret = imx_sc_misc_set_control(hifi4_priv->hifi_ipcHandle, IMX_SC_R_DSP, - IMX_SC_C_OFS_AUDIO, 0x20); + IMX_SC_C_OFS_AUDIO, 0x80); if (ret) { dev_err(&pdev->dev, "Error system address offset of AUDIO\n"); return -EIO; @@ -2120,10 +2123,20 @@ static int fsl_hifi4_probe(struct platform_device *pdev) return ret; } + hifi4_priv->sdram_phys_addr = SDRAM_BASE_ADDR; + hifi4_priv->sdram_vir_addr = ioremap(hifi4_priv->sdram_phys_addr, + SDRAM_BASE_SIZE); + if (!hifi4_priv->sdram_vir_addr) { + dev_err(&pdev->dev, "failed to remap sdram space for hifi4 firmware\n"); + return -ENXIO; + } + memset_io(hifi4_priv->sdram_vir_addr, 0, SDRAM_BASE_SIZE); + /* code buffer */ - hifi4_priv->code_buf_virt = hifi4_priv->regs + LIBRARY_CODE_OFFSET; - hifi4_priv->code_buf_phys = hifi4_priv->paddr + LIBRARY_CODE_OFFSET - - MEMORY_REMAP_OFFSET; + hifi4_priv->code_buf_virt = hifi4_priv->sdram_vir_addr + + SDRAM_CODEC_LIB_OFFSET; + hifi4_priv->code_buf_phys = hifi4_priv->sdram_phys_addr + + SDRAM_CODEC_LIB_OFFSET; hifi4_priv->code_buf_size = LIBRARY_CODE_SIZE; size = MSG_BUF_SIZE + INPUT_BUF_SIZE + @@ -2207,6 +2220,8 @@ static int fsl_hifi4_remove(struct platform_device *pdev) SCRATCH_DATA_BUF_SIZE; dma_free_coherent(&pdev->dev, size, hifi4_priv->msg_buf_virt, hifi4_priv->msg_buf_phys); + if (hifi4_priv->sdram_vir_addr) + iounmap(hifi4_priv->sdram_vir_addr); return 0; } diff --git a/sound/soc/fsl/fsl_hifi4.h b/sound/soc/fsl/fsl_hifi4.h index 6ec239824544..0f4bb7a499a8 100644 --- a/sound/soc/fsl/fsl_hifi4.h +++ b/sound/soc/fsl/fsl_hifi4.h @@ -205,6 +205,8 @@ struct fsl_hifi4 { unsigned long dram1; unsigned long iram; unsigned long sram; + void *sdram_vir_addr; + unsigned long sdram_phys_addr; void *msg_buf_virt; dma_addr_t msg_buf_phys; int msg_buf_size; @@ -301,6 +303,14 @@ struct hifi4_mem_msg { #define MEMORY_REMAP_OFFSET 0x39000000 +/* reserved memory for hifi4 firmware and core libs to + * save their instruction/data section in SDRAM, the physical + * address range is 0x8e000000 ~ 0x8fffffff (32M bytes). + */ +#define SDRAM_BASE_ADDR 0x8e000000 +#define SDRAM_BASE_SIZE 0x1ffffff +#define SDRAM_CODEC_LIB_OFFSET 0x1000000 + #define SC_C_OFS_SEL 39 #define SC_C_OFS_AUDIO 40 #define SC_C_OFS_PERIPH 41 From 8da839128ba96862b90d9dd0fc5263f2baef9757 Mon Sep 17 00:00:00 2001 From: Shengjiu Wang Date: Fri, 8 Dec 2017 15:50:35 +0800 Subject: [PATCH 22/78] MLK-17152: ASoC: fsl_hifi: support suspend and resume For hifi need to enter runtime suspend state in suspend, then the power of HIFI can be down. In this case content in internal RAM will be lost, and need to be recovered in resume. Move the loading firmware to runtime resume function, and define ICM_SUSPEND and ICM_RESUME command, with ICM_SUSPEND the hifi framework will store the data in RAM and with ICM_RESUME the hifi framework will restore the data to RAM. Signed-off-by: Shengjiu Wang --- sound/soc/fsl/fsl_hifi4.c | 126 ++++++++++++++++++++++++++++++-------- sound/soc/fsl/fsl_hifi4.h | 36 ++++++++++- 2 files changed, 136 insertions(+), 26 deletions(-) diff --git a/sound/soc/fsl/fsl_hifi4.c b/sound/soc/fsl/fsl_hifi4.c index fc59526b9528..97726ea14006 100644 --- a/sound/soc/fsl/fsl_hifi4.c +++ b/sound/soc/fsl/fsl_hifi4.c @@ -1567,28 +1567,6 @@ static int fsl_hifi4_open(struct inode *inode, struct file *file) file->private_data = hifi4_engine; - if (!hifi4_priv->is_ready) { - init_completion(&hifi4_priv->cmd_complete); - - ret = request_firmware_nowait(THIS_MODULE, - FW_ACTION_HOTPLUG, hifi4_priv->fw_name, - dev, - GFP_KERNEL, hifi4_priv, hifi4_load_firmware); - - 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); - if (ret) { - mutex_unlock(&hifi4_priv->hifi4_mutex); - return ret; - } - dev_info(dev, "hifi driver registered\n"); - } - /* increase reference counter when opening device */ atomic_long_inc(&hifi4_priv->refcnt); @@ -1696,7 +1674,7 @@ long icm_ack_wait(struct fsl_hifi4 *hifi4_priv, u32 msg) err = wait_for_completion_timeout(&hifi4_priv->cmd_complete, msecs_to_jiffies(1000)); if (!err) { - dev_err(dev, "icm ack timeout!\n"); + dev_err(dev, "icm ack timeout! %x\n", msg); return -ETIMEDOUT; } @@ -1818,7 +1796,18 @@ int process_act_complete(struct fsl_hifi4 *hifi4_priv, u32 msg) 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; @@ -2230,6 +2219,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); + int ret; if (sc_pm_set_resource_power_mode(hifi4_priv->hifi_ipcHandle, SC_R_DSP_RAM, SC_PM_PW_MODE_ON) != SC_ERR_NONE) { @@ -2237,6 +2227,32 @@ 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); + + ret = request_firmware_nowait(THIS_MODULE, + FW_ACTION_HOTPLUG, hifi4_priv->fw_name, + dev, + GFP_KERNEL, hifi4_priv, hifi4_load_firmware); + + 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); + 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; } @@ -2254,14 +2270,74 @@ static int fsl_hifi4_runtime_suspend(struct device *dev) } #endif /* CONFIG_PM */ + #ifdef CONFIG_PM_SLEEP static int fsl_hifi4_suspend(struct device *dev) { - return 0; + 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; } 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 0f4bb7a499a8..787d35f3cb88 100644 --- a/sound/soc/fsl/fsl_hifi4.h +++ b/sound/soc/fsl/fsl_hifi4.h @@ -137,6 +137,8 @@ enum icm_action_t { ICM_SWITCH_CODEC, ICM_RESET, + ICM_SUSPEND, + ICM_RESUME, }; enum aud_status_t { @@ -299,7 +301,39 @@ struct hifi4_mem_msg { #define INPUT_BUF_SIZE 4096 #define OUTPUT_BUF_SIZE 16384 #define FIRMWARE_DATA_BUF_SIZE (MULTI_CODEC_NUM * 0x80000) -#define SCRATCH_DATA_BUF_SIZE (MULTI_CODEC_NUM * 0x80000) + + +/*scratch buf structure + * ---------------------------------------------------------------------- + * | name | size | description | + * ----------------------------------------------------------------------- + * | CODEC 0 | 0x80000 | Total support 5 instance. + * ----------------------------------- Each instance has 0x80000 size + * | CODEC 1 | 0x80000 | buffer for store the code section + * ----------------------------------- and input/output buffer. + * | CODEC 2 | 0x80000 | + * ----------------------------------- + * | CODEC 3 | 0x80000 | + * ----------------------------------- + * | CODEC 4 | 0x80000 | + * ------------------------------------------------------------------------ + * | codec info buf | 4096 | For alloc the codec info structure + * ------------------------------------------------------------------------ + * | global structure | 4096 | For store hifi config structure + * ------------------------------------------------------------------------ + * | DRAM | 64k | For store DRAM buffer in suspend + * ------------------------------------------------------------------------ + */ + +#define EACH_CODEC_BUF_SIZE 0x80000 +#define CODEC_INFO_BUF_OFF (MULTI_CODEC_NUM * EACH_CODEC_BUF_SIZE) +#define CODEC_INFO_BUF_SIZE 4096 +#define SUSPEND_GLOBAL_BUF_OFF (CODEC_INFO_BUF_OFF + CODEC_INFO_BUF_SIZE) +#define SUSPEND_GLOBAL_BUF_SIZE 4096 +#define SUSPEND_DRAM_BUF_OFF (SUSPEND_GLOBAL_BUF_OFF + SUSPEND_GLOBAL_BUF_SIZE) +#define SUSPEND_DRAM_BUF_SIZE 65536 + +#define SCRATCH_DATA_BUF_SIZE (SUSPEND_DRAM_BUF_OFF + SUSPEND_DRAM_BUF_SIZE) #define MEMORY_REMAP_OFFSET 0x39000000 From 72ac226ce93c0ff44ccee94f0951b73186cc16d4 Mon Sep 17 00:00:00 2001 From: Weiguang Kong Date: Tue, 26 Dec 2017 18:57:27 +0800 Subject: [PATCH 23/78] MLK-17309-2: ASoC: fsl_hifi: use new way to realize multi-codec In current hifi driver, some resources are shared when multi codec decodes together. When switching between multi-codec, the hifi driver and framework need to save and restore the shared resources,this will waster time and complicate the hifi driver. So by distributing private resources for each codec to avoid this problem. When the user space wants to enable a new codec, it can send "HIFI4_CLIENT_REGISTER" command to hifi driver to apply an available resource, the driver will send a client id to user space. When the user space wants to release the resource, it can send "HIFI4_CLIENT_UNREGISTER" command to hifi driver, then the driver will mark this resource available. Signed-off-by: Weiguang Kong --- sound/soc/fsl/fsl_hifi4.c | 771 ++++++++++++++++---------------------- sound/soc/fsl/fsl_hifi4.h | 169 +++------ 2 files changed, 378 insertions(+), 562 deletions(-) diff --git a/sound/soc/fsl/fsl_hifi4.c b/sound/soc/fsl/fsl_hifi4.c index 97726ea14006..f423eb71f326 100644 --- a/sound/soc/fsl/fsl_hifi4.c +++ b/sound/soc/fsl/fsl_hifi4.c @@ -2,7 +2,7 @@ * Freescale HIFI 4 driver * * Copyright (c) 2012-2013 by Tensilica Inc. ALL RIGHTS RESERVED. - * Copyright 2017 NXP. + * Copyright 2018 NXP * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -72,7 +72,6 @@ struct decode_info_compat32 { compat_long_t out_buf_addr; __s32 out_buf_size; __s32 out_buf_off; - __u32 cycles; __u32 input_over; __u32 process_id; }; @@ -81,6 +80,7 @@ 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, @@ -91,7 +91,8 @@ static int get_binary_info_compat32(struct binary_info *kp, 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->process_id, &up->process_id) || + get_user(kp->lib_type, &up->lib_type) ) { return -EFAULT; } @@ -102,18 +103,6 @@ static int get_binary_info_compat32(struct binary_info *kp, return 0; } -static int put_binary_info_compat32(struct binary_info *kp, - struct binary_info_compat32 *up) { - - if (!access_ok(VERIFY_WRITE, up, sizeof(struct binary_info_compat32)) || - put_user(kp->process_id, &up->process_id) - ) { - return -EFAULT; - } - - return 0; -} - static int get_decode_info_compat32(struct decode_info *kp, struct decode_info_compat32 *up) { void __user *up_ptr1; @@ -128,7 +117,6 @@ static int get_decode_info_compat32(struct decode_info *kp, 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->cycles, &up->cycles) || get_user(kp->input_over, &up->input_over) || get_user(kp->process_id, &up->process_id) ) { @@ -150,7 +138,6 @@ static int put_decode_info_compat32(struct decode_info *kp, 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->cycles, &up->cycles) || put_user(kp->input_over, &up->input_over) ) { return -EFAULT; @@ -160,80 +147,17 @@ static int put_decode_info_compat32(struct decode_info *kp, } #endif -long switch_codec(struct fsl_hifi4 *hifi4_priv, int id) -{ - union icm_header_t apu_icm; - struct hifi4_ext_msg ext_msg; - struct icm_switch_info_t switch_info; - int i; - long ret = 0; - - switch_info.proc_id = id; - switch_info.status = 0; - - 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_SWITCH_CODEC; - apu_icm.size = 8; - - ext_msg.phys = hifi4_priv->msg_buf_phys; - ext_msg.size = sizeof(struct icm_switch_info_t); - memcpy(hifi4_priv->msg_buf_virt, &switch_info, - sizeof(struct icm_switch_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; - - /* check whether the dsp framework switches successfully or not */ - ret = hifi4_priv->ret_status; - if (ret) - return ret; - - /* Because this variables are shared for every codec, so when - * switching, need to recover it value for current codec. - */ - for (i = 0; i < MULTI_CODEC_NUM; i++) { - if (hifi4_priv->process_info[i].process_id == id) { - if (hifi4_priv->process_info[i].status) { - hifi4_priv->cur_res_id = i; - hifi4_priv->pil_info = - hifi4_priv->process_info[i].pil_info_info; - hifi4_priv->objtype = - hifi4_priv->process_info[i].codec_id; - hifi4_priv->codec_iobuf_info.proc_id = - hifi4_priv->process_info[i].proc_id; - break; - } - } - } - /* update the current process id to the new process id */ - hifi4_priv->process_id = id; - - return ret; -} - -long load_dpu_with_library(struct fsl_hifi4 *hifi4_priv) +long load_dpu_with_library(struct fsl_hifi4 *hifi4_priv, + struct icm_process_info *process_info) { struct file *fpInfile; unsigned char *srambuf = NULL; struct lib_dnld_info_t dpulib; int filesize = 0; - unsigned int id; long ret_val = 0; - id = hifi4_priv->cur_res_id; - /* Load DPU's main program to System memory */ - fpInfile = file_open_name(hifi4_priv->objfile, O_RDONLY, 0); + fpInfile = file_open_name(process_info->objfile, O_RDONLY, 0); if (IS_ERR(fpInfile)) return PTR_ERR(fpInfile); @@ -250,18 +174,17 @@ long load_dpu_with_library(struct fsl_hifi4 *hifi4_priv) (struct xtlib_packaged_library *)(srambuf), (unsigned int *)&(dpulib.size_code), (unsigned int *)&(dpulib.size_data), - hifi4_priv); + process_info); if (ret_val != XTLIB_NO_ERR) return ret_val; - hifi4_priv->size_code = dpulib.size_code; - hifi4_priv->size_data = dpulib.size_data; + process_info->code_buf_size = dpulib.size_code; + process_info->data_buf_size = dpulib.size_data; - dpulib.pbuf_code = (unsigned long)hifi4_priv->code_buf_phys; - dpulib.pbuf_data = - (unsigned long)hifi4_priv->process_info[id].data_buf_phys; + dpulib.pbuf_code = (unsigned long)process_info->code_buf_phys; + dpulib.pbuf_data = (unsigned long)process_info->data_buf_phys; - dpulib.ppil_inf = &hifi4_priv->pil_info; + dpulib.ppil_inf = &process_info->pil_info; xtlib_host_load_split_pi_library( (struct xtlib_packaged_library *) (srambuf), (xt_ptr) (dpulib.pbuf_code), @@ -269,7 +192,7 @@ long load_dpu_with_library(struct fsl_hifi4 *hifi4_priv) (struct xtlib_pil_info *)dpulib.ppil_inf, (memcpy_func)&memcpy_hifi, (memset_func)&memset_hifi, - (void *)hifi4_priv); + (void *)process_info); kfree(srambuf); @@ -291,9 +214,10 @@ Elf32_Word xtlib_host_word(Elf32_Word v, int byteswap) } int xtlib_verify_magic(Elf32_Ehdr *header, - struct fsl_hifi4 *hifi4_priv) + struct icm_process_info *process_info) { - struct xtlib_loader_globals *xtlib_globals = &hifi4_priv->xtlib_globals; + struct xtlib_loader_globals *xtlib_globals = + &process_info->xtlib_globals; Elf32_Byte magic_no; magic_no = header->e_ident[EI_MAG0]; @@ -337,9 +261,10 @@ int xtlib_verify_magic(Elf32_Ehdr *header, void xtlib_load_seg(Elf32_Phdr *pheader, void *src_addr, xt_ptr dst_addr, memcpy_func mcpy, memset_func mset, - struct fsl_hifi4 *hifi4_priv) + struct icm_process_info *process_info) { - struct xtlib_loader_globals *xtlib_globals = &hifi4_priv->xtlib_globals; + 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, @@ -364,9 +289,10 @@ static xt_ptr align_ptr(xt_ptr ptr, xt_uint align) } static xt_ptr xt_ptr_offs(xt_ptr base, Elf32_Word offs, - struct fsl_hifi4 *hifi4_priv) + struct icm_process_info *process_info) { - struct xtlib_loader_globals *xtlib_globals = &hifi4_priv->xtlib_globals; + 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), @@ -374,10 +300,11 @@ static xt_ptr xt_ptr_offs(xt_ptr base, Elf32_Word offs, } static Elf32_Dyn *find_dynamic_info(Elf32_Ehdr *eheader, - struct fsl_hifi4 *hifi4_priv) + struct icm_process_info *process_info) { char *base_addr = (char *)eheader; - struct xtlib_loader_globals *xtlib_globals = &hifi4_priv->xtlib_globals; + 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)); @@ -398,9 +325,10 @@ static Elf32_Dyn *find_dynamic_info(Elf32_Ehdr *eheader, } static int find_align(Elf32_Ehdr *header, - struct fsl_hifi4 *hifi4_priv) + struct icm_process_info *process_info) { - struct xtlib_loader_globals *xtlib_globals = &hifi4_priv->xtlib_globals; + 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)); @@ -425,13 +353,13 @@ static int find_align(Elf32_Ehdr *header, return align; } - static int validate_dynamic(Elf32_Ehdr *header, - struct fsl_hifi4 *hifi4_priv) + struct icm_process_info *process_info) { - struct xtlib_loader_globals *xtlib_globals = &hifi4_priv->xtlib_globals; + struct xtlib_loader_globals *xtlib_globals = + &process_info->xtlib_globals; - if (xtlib_verify_magic(header, hifi4_priv) != 0) + if (xtlib_verify_magic(header, process_info) != 0) return XTLIB_NOT_ELF; if (xtlib_host_half(header->e_type, @@ -442,11 +370,12 @@ static int validate_dynamic(Elf32_Ehdr *header, } static int validate_dynamic_splitload(Elf32_Ehdr *header, - struct fsl_hifi4 *hifi4_priv) + struct icm_process_info *process_info) { - struct xtlib_loader_globals *xtlib_globals = &hifi4_priv->xtlib_globals; + struct xtlib_loader_globals *xtlib_globals = + &process_info->xtlib_globals; Elf32_Phdr *pheader; - int err = validate_dynamic(header, hifi4_priv); + int err = validate_dynamic(header, process_info); if (err != XTLIB_NO_ERR) return err; @@ -500,20 +429,21 @@ unsigned int xtlib_split_pi_library_size( struct xtlib_packaged_library *library, unsigned int *code_size, unsigned int *data_size, - struct fsl_hifi4 *hifi4_priv) + struct icm_process_info *process_info) { - struct xtlib_loader_globals *xtlib_globals = &hifi4_priv->xtlib_globals; + 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, hifi4_priv); + int err = validate_dynamic_splitload(header, process_info); if (err != XTLIB_NO_ERR) { xtlib_globals->err = err; return err; } - align = find_align(header, hifi4_priv); + align = find_align(header, process_info); pheader = (Elf32_Phdr *) ((char *)library + xtlib_host_word(header->e_phoff, xtlib_globals->byteswap)); @@ -534,12 +464,13 @@ static int get_dyn_info(Elf32_Ehdr *eheader, xt_ptr dst_data_addr, xt_uint src_data_offs, struct xtlib_pil_info *info, - struct fsl_hifi4 *hifi4_priv) + struct icm_process_info *process_info) { unsigned int jmprel = 0; unsigned int pltrelsz = 0; - struct xtlib_loader_globals *xtlib_globals = &hifi4_priv->xtlib_globals; - Elf32_Dyn *dyn_entry = find_dynamic_info(eheader, hifi4_priv); + 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; @@ -556,9 +487,9 @@ static int get_dyn_info(Elf32_Ehdr *eheader, 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, hifi4_priv); + info->start_sym = xt_ptr_offs(dst_addr, eheader->e_entry, process_info); - info->align = xtlib_xt_word(find_align(eheader, hifi4_priv), + info->align = xtlib_xt_word(find_align(eheader, process_info), xtlib_globals->byteswap); info->text_addr = 0; @@ -569,7 +500,7 @@ static int get_dyn_info(Elf32_Ehdr *eheader, xtlib_globals->byteswap)) { case DT_RELA: info->rel = xt_ptr_offs(dst_data_addr, - dyn_entry->d_un.d_ptr, hifi4_priv); + dyn_entry->d_un.d_ptr, process_info); break; case DT_RELASZ: info->rela_count = xtlib_xt_word( @@ -579,23 +510,23 @@ static int get_dyn_info(Elf32_Ehdr *eheader, break; case DT_INIT: info->init = xt_ptr_offs(dst_addr, - dyn_entry->d_un.d_ptr, hifi4_priv); + 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, hifi4_priv); + 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, hifi4_priv); + 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, hifi4_priv); + 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, hifi4_priv); + dyn_entry->d_un.d_ptr, process_info); break; case DT_JMPREL: jmprel = dyn_entry->d_un.d_val; @@ -605,7 +536,7 @@ static int get_dyn_info(Elf32_Ehdr *eheader, break; case DT_LOPROC + 2: info->text_addr = xt_ptr_offs(dst_addr, - dyn_entry->d_un.d_ptr, hifi4_priv); + dyn_entry->d_un.d_ptr, process_info); break; default: @@ -626,21 +557,21 @@ static xt_ptr xtlib_load_split_pi_library_common( struct xtlib_pil_info *lib_info, memcpy_func mcpy_fn, memset_func mset_fn, - struct fsl_hifi4 *hifi4_priv) + struct icm_process_info *process_info) { - struct xtlib_loader_globals *xtlib_globals = &hifi4_priv->xtlib_globals; + struct xtlib_loader_globals *xtlib_globals = + &process_info->xtlib_globals; Elf32_Ehdr *header = (Elf32_Ehdr *) library; Elf32_Phdr *pheader; - unsigned int align, id; - int err = validate_dynamic_splitload(header, hifi4_priv); + unsigned int align; + int err = validate_dynamic_splitload(header, process_info); if (err != XTLIB_NO_ERR) { xtlib_globals->err = err; return 0; } - id = hifi4_priv->cur_res_id; - align = find_align(header, hifi4_priv); + align = find_align(header, process_info); destination_code_address = align_ptr(destination_code_address, align); destination_data_address = align_ptr(destination_data_address, align); @@ -657,7 +588,7 @@ static xt_ptr xtlib_load_split_pi_library_common( xtlib_host_word(pheader[1].p_paddr, xtlib_globals->byteswap), lib_info, - hifi4_priv); + process_info); if (err != XTLIB_NO_ERR) { xtlib_globals->err = err; @@ -668,8 +599,8 @@ static xt_ptr xtlib_load_split_pi_library_common( xtlib_load_seg(&pheader[0], (char *)library + xtlib_host_word(pheader[0].p_offset, xtlib_globals->byteswap), - (xt_ptr)hifi4_priv->code_buf_virt, - mcpy_fn, mset_fn, hifi4_priv); + (xt_ptr)process_info->code_buf_virt, + mcpy_fn, mset_fn, process_info); if (lib_info->text_addr == 0) lib_info->text_addr = @@ -680,11 +611,10 @@ static xt_ptr xtlib_load_split_pi_library_common( xtlib_load_seg(&pheader[1], (char *)library + xtlib_host_word(pheader[1].p_offset, xtlib_globals->byteswap), - (xt_ptr)hifi4_priv->process_info[id].data_buf_virt + + (xt_ptr)process_info->data_buf_virt + xtlib_host_word(pheader[1].p_paddr, xtlib_globals->byteswap), - mcpy_fn, mset_fn, hifi4_priv); - + mcpy_fn, mset_fn, process_info); if (err != XTLIB_NO_ERR) { xtlib_globals->err = err; @@ -701,7 +631,7 @@ xt_ptr xtlib_host_load_split_pi_library(struct xtlib_packaged_library *library, struct xtlib_pil_info *lib_info, memcpy_func mcpy_fn, memset_func mset_fn, - struct fsl_hifi4 *hifi4_priv) + struct icm_process_info *process_info) { return xtlib_load_split_pi_library_common(library, destination_code_address, @@ -709,7 +639,7 @@ xt_ptr xtlib_host_load_split_pi_library(struct xtlib_packaged_library *library, lib_info, mcpy_fn, mset_fn, - hifi4_priv); + process_info); } @@ -719,6 +649,8 @@ static long fsl_hifi4_init_codec(struct fsl_hifi4 *hifi4_priv, 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; @@ -728,13 +660,7 @@ static long fsl_hifi4_init_codec(struct fsl_hifi4 *hifi4_priv, return -EFAULT; } - if (hifi4_priv->process_id != id) { - ret = switch_codec(hifi4_priv, id); - if (ret) { - dev_err(dev, "failed to switch codec in codec init\n"); - return ret; - } - } + process_info = &hifi4_priv->process_info[id]; init_completion(&hifi4_priv->cmd_complete); hifi4_priv->is_done = 0; @@ -746,10 +672,13 @@ static long fsl_hifi4_init_codec(struct fsl_hifi4 *hifi4_priv, apu_icm.size = 8; ext_msg.phys = hifi4_priv->msg_buf_phys; - ext_msg.size = sizeof(struct xtlib_pil_info); + ext_msg.size = sizeof(struct icm_base_info_t); - memcpy(hifi4_priv->msg_buf_virt, &hifi4_priv->pil_info, - sizeof(struct xtlib_pil_info)); + 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 */ @@ -757,7 +686,7 @@ static long fsl_hifi4_init_codec(struct fsl_hifi4 *hifi4_priv, if (ret) return ret; - return 0; + return hifi4_priv->ret_status; } static long fsl_hifi4_decode_frame(struct fsl_hifi4 *hifi4_priv, @@ -767,8 +696,10 @@ static long fsl_hifi4_decode_frame(struct fsl_hifi4 *hifi4_priv, 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)); @@ -777,13 +708,8 @@ static long fsl_hifi4_decode_frame(struct fsl_hifi4 *hifi4_priv, return -EFAULT; } - if (hifi4_priv->process_id != decode_info.process_id) { - ret = switch_codec(hifi4_priv, decode_info.process_id); - if (ret) { - dev_err(dev, "failed to switch codec in codec decode frame\n"); - return ret; - } - } + 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) { @@ -792,7 +718,7 @@ static long fsl_hifi4_decode_frame(struct fsl_hifi4 *hifi4_priv, } if (decode_info.in_buf_off == 0) { - ret = copy_from_user(hifi4_priv->in_buf_virt, + ret = copy_from_user(process_info->in_buf_virt, (void __user *)decode_info.in_buf_addr, decode_info.in_buf_size); if (ret) { @@ -802,15 +728,16 @@ static long fsl_hifi4_decode_frame(struct fsl_hifi4 *hifi4_priv, codec_iobuf_info->inp_cur_offset = 0; } - codec_iobuf_info->inp_addr_sysram = hifi4_priv->in_buf_phys; + 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 = hifi4_priv->out_buf_phys; - codec_iobuf_info->out_buf_size_max = hifi4_priv->out_buf_size; + 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; @@ -833,7 +760,7 @@ static long fsl_hifi4_decode_frame(struct fsl_hifi4 *hifi4_priv, return ret; ret = copy_to_user((void __user *)decode_info.out_buf_addr, - hifi4_priv->out_buf_virt, + process_info->out_buf_virt, codec_iobuf_info->out_cur_offset); if (ret) { dev_err(dev, "failed to copy to user\n"); @@ -842,7 +769,6 @@ static long fsl_hifi4_decode_frame(struct fsl_hifi4 *hifi4_priv, decode_info.in_buf_off = codec_iobuf_info->inp_cur_offset; decode_info.out_buf_off = codec_iobuf_info->out_cur_offset; - decode_info.cycles = codec_iobuf_info->cycles; ret = copy_to_user(user, &decode_info, sizeof(decode_info)); if (ret) { @@ -862,8 +788,10 @@ static long fsl_hifi4_decode_frame_compat32(struct fsl_hifi4 *hifi4_priv, 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); @@ -872,13 +800,8 @@ static long fsl_hifi4_decode_frame_compat32(struct fsl_hifi4 *hifi4_priv, return ret; } - if (hifi4_priv->process_id != decode_info.process_id) { - ret = switch_codec(hifi4_priv, decode_info.process_id); - if (ret) { - dev_err(dev, "failed to switch codec in codec decode frame in compat32 mode\n"); - return ret; - } - } + 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) { @@ -887,7 +810,7 @@ static long fsl_hifi4_decode_frame_compat32(struct fsl_hifi4 *hifi4_priv, } if (decode_info.in_buf_off == 0) { - ret = copy_from_user(hifi4_priv->in_buf_virt, + ret = copy_from_user(process_info->in_buf_virt, (void __user *)decode_info.in_buf_addr, decode_info.in_buf_size); if (ret) { @@ -897,15 +820,16 @@ static long fsl_hifi4_decode_frame_compat32(struct fsl_hifi4 *hifi4_priv, codec_iobuf_info->inp_cur_offset = 0; } - codec_iobuf_info->inp_addr_sysram = hifi4_priv->in_buf_phys; + 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 = hifi4_priv->out_buf_phys; - codec_iobuf_info->out_buf_size_max = hifi4_priv->out_buf_size; + 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; @@ -928,7 +852,7 @@ static long fsl_hifi4_decode_frame_compat32(struct fsl_hifi4 *hifi4_priv, return ret; ret = copy_to_user((void __user *)decode_info.out_buf_addr, - hifi4_priv->out_buf_virt, + process_info->out_buf_virt, codec_iobuf_info->out_cur_offset); if (ret) { dev_err(dev, "failed to copy to user\n"); @@ -937,7 +861,6 @@ static long fsl_hifi4_decode_frame_compat32(struct fsl_hifi4 *hifi4_priv, decode_info.in_buf_off = codec_iobuf_info->inp_cur_offset; decode_info.out_buf_off = codec_iobuf_info->out_cur_offset; - decode_info.cycles = codec_iobuf_info->cycles; ret = put_decode_info_compat32(&decode_info, user); if (ret) { @@ -955,6 +878,7 @@ static long fsl_hifi4_get_pcm_prop(struct fsl_hifi4 *hifi4_priv, { 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; @@ -965,14 +889,6 @@ static long fsl_hifi4_get_pcm_prop(struct fsl_hifi4 *hifi4_priv, return -EFAULT; } - if (hifi4_priv->process_id != prop_info.process_id) { - ret = switch_codec(hifi4_priv, prop_info.process_id); - if (ret) { - dev_err(dev, "failed to switch codec in codec get param\n"); - return ret; - } - } - init_completion(&hifi4_priv->cmd_complete); hifi4_priv->is_done = 0; @@ -980,9 +896,16 @@ static long fsl_hifi4_get_pcm_prop(struct fsl_hifi4 *hifi4_priv, apu_icm.ack = 0; apu_icm.intr = 1; apu_icm.msg = ICM_GET_PCM_PROP; - apu_icm.size = 0; + apu_icm.size = 8; - icm_intr_send(hifi4_priv, apu_icm.allbits); + 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); @@ -993,6 +916,7 @@ static long fsl_hifi4_get_pcm_prop(struct fsl_hifi4 *hifi4_priv, 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) { @@ -1010,6 +934,7 @@ static int fsl_hifi4_set_config(struct fsl_hifi4 *hifi4_priv, void __user *user) 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; ret = copy_from_user(&prop_config, user, sizeof(prop_config)); @@ -1018,14 +943,6 @@ static int fsl_hifi4_set_config(struct fsl_hifi4 *hifi4_priv, void __user *user) return -EFAULT; } - if (hifi4_priv->process_id != prop_config.process_id) { - ret = switch_codec(hifi4_priv, prop_config.process_id); - if (ret) { - dev_err(dev, "failed to switch codec in codec set param\n"); - return ret; - } - } - init_completion(&hifi4_priv->cmd_complete); hifi4_priv->is_done = 0; @@ -1036,9 +953,14 @@ static int fsl_hifi4_set_config(struct fsl_hifi4 *hifi4_priv, void __user *user) apu_icm.size = 8; ext_msg.phys = hifi4_priv->msg_buf_phys; - ext_msg.size = sizeof(prop_config); + ext_msg.size = sizeof(struct icm_prop_config); - memcpy(hifi4_priv->msg_buf_virt, &prop_config, sizeof(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); @@ -1057,10 +979,10 @@ static long fsl_hifi4_load_codec(struct fsl_hifi4 *hifi4_priv, struct filename *fpInfile; union icm_header_t apu_icm; struct binary_info binary_info; - struct icm_pilib_size_t lib_alloc_mem; struct hifi4_ext_msg ext_msg; + struct icm_xtlib_pil_info icm_xtlib_pil_info; long ret = 0; - long i; + long id; ret = copy_from_user(&binary_info, user, sizeof(binary_info)); if (ret) { @@ -1074,58 +996,37 @@ static long fsl_hifi4_load_codec(struct fsl_hifi4 *hifi4_priv, PTR_ERR(fpInfile)); return PTR_ERR(fpInfile); } + id = binary_info.process_id; - /* check whether the dsp driver has available resource or not */ - for (i = 0; i < MULTI_CODEC_NUM; i++) { - if (!(hifi4_priv->process_info[i].status)) { - hifi4_priv->process_info[i].status = 1; - hifi4_priv->available_resource--; - break; - } - } - if (i >= MULTI_CODEC_NUM) { - dev_err(dev, "out of range of multi codec max number\n"); - return -EINVAL; - } - - /* If dsp driver has available resource, produce a new process - * for the new codec. - */ - hifi4_priv->process_id_count++; - - ret = switch_codec(hifi4_priv, hifi4_priv->process_id_count); - if (ret) { - dev_err(dev, "failed to switch codec in codec load\n"); - return ret; - } - - hifi4_priv->objfile = fpInfile; - hifi4_priv->objtype = binary_info.type; - - hifi4_priv->cur_res_id = i; - ret = load_dpu_with_library(hifi4_priv); + 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.allbits = 0; /* clear all bits;*/ apu_icm.ack = 0; apu_icm.intr = 1; - apu_icm.msg = ICM_PI_LIB_MEM_ALLOC; + 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_pilib_size_t); + ext_msg.size = sizeof(struct icm_xtlib_pil_info); - lib_alloc_mem.codec_type = hifi4_priv->objtype; - lib_alloc_mem.text_size = hifi4_priv->size_code; - lib_alloc_mem.data_size = hifi4_priv->size_data; + 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, &lib_alloc_mem, - sizeof(struct icm_pilib_size_t)); + 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 */ @@ -1133,20 +1034,7 @@ static long fsl_hifi4_load_codec(struct fsl_hifi4 *hifi4_priv, if (ret) return ret; - /* save current codec information */ - hifi4_priv->process_info[i].process_id = hifi4_priv->process_id; - hifi4_priv->process_info[i].codec_id = hifi4_priv->objtype; - hifi4_priv->process_info[i].pil_info_info = hifi4_priv->pil_info; - - /* return process id of this codec to user space */ - binary_info.process_id = hifi4_priv->process_id; - ret = copy_to_user(user, &binary_info, sizeof(struct binary_info)); - if (ret) { - dev_err(dev, "failed to send para to user space\n"); - return -EFAULT; - } - - hifi4_priv->ret_status = 0; + ret = hifi4_priv->ret_status; dev_dbg(dev, "code binary is loaded\n"); @@ -1161,10 +1049,10 @@ static long fsl_hifi4_load_codec_compat32(struct fsl_hifi4 *hifi4_priv, struct filename *fpInfile; union icm_header_t apu_icm; struct binary_info binary_info; - struct icm_pilib_size_t lib_alloc_mem; struct hifi4_ext_msg ext_msg; + struct icm_xtlib_pil_info icm_xtlib_pil_info; long ret = 0; - long i; + long id; ret = get_binary_info_compat32(&binary_info, user); if (ret) { @@ -1178,36 +1066,11 @@ static long fsl_hifi4_load_codec_compat32(struct fsl_hifi4 *hifi4_priv, PTR_ERR(fpInfile)); return PTR_ERR(fpInfile); } + id = binary_info.process_id; - /* check whether the dsp driver has available resource or not */ - for (i = 0; i < MULTI_CODEC_NUM; i++) { - if (!(hifi4_priv->process_info[i].status)) { - hifi4_priv->process_info[i].status = 1; - hifi4_priv->available_resource--; - break; - } - } - if (i >= MULTI_CODEC_NUM) { - dev_err(dev, "out of range of multi codec max number\n"); - return -EINVAL; - } - - /* If dsp driver has available resource, produce a new process - * for the new codec. - */ - hifi4_priv->process_id_count++; - - ret = switch_codec(hifi4_priv, hifi4_priv->process_id_count); - if (ret) { - dev_err(dev, "failed to switch codec in codec load\n"); - return ret; - } - - hifi4_priv->objfile = fpInfile; - hifi4_priv->objtype = binary_info.type; - - hifi4_priv->cur_res_id = i; - ret = load_dpu_with_library(hifi4_priv); + hifi4_priv->process_info[id].objfile = fpInfile; + hifi4_priv->process_info[id].objtype = 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; @@ -1219,18 +1082,20 @@ static long fsl_hifi4_load_codec_compat32(struct fsl_hifi4 *hifi4_priv, 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.msg = ICM_PI_LIB_LOAD; apu_icm.size = 8; ext_msg.phys = hifi4_priv->msg_buf_phys; - ext_msg.size = sizeof(struct icm_pilib_size_t); + ext_msg.size = sizeof(struct icm_xtlib_pil_info); - lib_alloc_mem.codec_type = hifi4_priv->objtype; - lib_alloc_mem.text_size = hifi4_priv->size_code; - lib_alloc_mem.data_size = hifi4_priv->size_data; + 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, &lib_alloc_mem, - sizeof(struct icm_pilib_size_t)); + 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 */ @@ -1238,20 +1103,7 @@ static long fsl_hifi4_load_codec_compat32(struct fsl_hifi4 *hifi4_priv, if (ret) return ret; - /* save current codec information */ - hifi4_priv->process_info[i].process_id = hifi4_priv->process_id; - hifi4_priv->process_info[i].codec_id = hifi4_priv->objtype; - hifi4_priv->process_info[i].pil_info_info = hifi4_priv->pil_info; - - /* return process id of this codec to user space */ - binary_info.process_id = hifi4_priv->process_id; - ret = put_binary_info_compat32(&binary_info, user); - if (ret) { - dev_err(dev, "failed to send para to user space\n"); - return ret; - } - - hifi4_priv->ret_status = 0; + ret = hifi4_priv->ret_status; dev_dbg(dev, "code binary is loaded\n"); @@ -1264,8 +1116,9 @@ static long fsl_hifi4_codec_open(struct fsl_hifi4 *hifi4_priv, { struct device *dev = hifi4_priv->dev; union icm_header_t apu_icm; - struct icm_cdc_uinp_t cdc_user_inp; 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; @@ -1275,32 +1128,24 @@ static long fsl_hifi4_codec_open(struct fsl_hifi4 *hifi4_priv, return -EFAULT; } - if (hifi4_priv->process_id != id) { - ret = switch_codec(hifi4_priv, id); - if (ret) { - dev_err(dev, "failed to switch codec in codec open\n"); - return ret; - } - } - - cdc_user_inp.proc_id = 0; - cdc_user_inp.codec_id = hifi4_priv->objtype; + 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.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_cdc_uinp_t); - memcpy(hifi4_priv->msg_buf_virt, &cdc_user_inp, - sizeof(struct icm_cdc_uinp_t)); + ext_msg.size = 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 */ @@ -1308,11 +1153,8 @@ static long fsl_hifi4_codec_open(struct fsl_hifi4 *hifi4_priv, if (ret) return ret; - /* save current codec information */ - hifi4_priv->process_info[hifi4_priv->cur_res_id].proc_id = - hifi4_priv->codec_iobuf_info.proc_id; - ret = hifi4_priv->ret_status; + return ret; } @@ -1321,6 +1163,8 @@ static int fsl_hifi4_codec_close(struct fsl_hifi4 *hifi4_priv, { 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; @@ -1330,14 +1174,6 @@ static int fsl_hifi4_codec_close(struct fsl_hifi4 *hifi4_priv, return -EFAULT; } - if (hifi4_priv->process_id != id) { - ret = switch_codec(hifi4_priv, id); - if (ret) { - dev_err(dev, "failed to switch codec in codec close\n"); - return ret; - } - } - init_completion(&hifi4_priv->cmd_complete); hifi4_priv->is_done = 0; @@ -1345,23 +1181,23 @@ static int fsl_hifi4_codec_close(struct fsl_hifi4 *hifi4_priv, apu_icm.ack = 0; apu_icm.intr = 1; apu_icm.msg = ICM_CLOSE; - apu_icm.size = 0; - icm_intr_send(hifi4_priv, apu_icm.allbits); + apu_icm.size = 8; + + ext_msg.phys = hifi4_priv->msg_buf_phys; + ext_msg.size = 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; - /* Making status to 0 means releasing the resource that - * current codec occupies. - */ - hifi4_priv->process_info[hifi4_priv->cur_res_id].status = 0; - hifi4_priv->available_resource++; - - /* If no codec occupies the resource, zero the process id count */ - if (hifi4_priv->available_resource >= MULTI_CODEC_NUM) - hifi4_priv->process_id_count = 0; + ret = hifi4_priv->ret_status; return ret; } @@ -1371,8 +1207,10 @@ static int fsl_hifi4_codec_reset(struct fsl_hifi4 *hifi4_priv, { 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; unsigned long ret = 0; @@ -1383,14 +1221,6 @@ static int fsl_hifi4_codec_reset(struct fsl_hifi4 *hifi4_priv, return -EFAULT; } - if (hifi4_priv->process_id != id) { - err = switch_codec(hifi4_priv, id); - if (err) { - dev_err(dev, "failed to switch codec in codec reset\n"); - return err; - } - } - init_completion(&hifi4_priv->cmd_complete); hifi4_priv->is_done = 0; @@ -1398,8 +1228,16 @@ static int fsl_hifi4_codec_reset(struct fsl_hifi4 *hifi4_priv, apu_icm.ack = 0; apu_icm.intr = 1; apu_icm.msg = ICM_RESET; - apu_icm.size = 0; - icm_intr_send(hifi4_priv, apu_icm.allbits); + apu_icm.size = 8; + + ext_msg.phys = hifi4_priv->msg_buf_phys; + ext_msg.size = 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); @@ -1418,6 +1256,58 @@ static int fsl_hifi4_codec_reset(struct fsl_hifi4 *hifi4_priv, 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)); + if (ret) { + dev_err(dev, "failed to send para to user space\n"); + return -EFAULT; + } + + return 0; +} + +static int fsl_hifi4_client_unregister(struct fsl_hifi4 *hifi4_priv, + void __user *user) +{ + struct device *dev = hifi4_priv->dev; + int id; + 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; + } + + if (id >= MULTI_CODEC_NUM) { + dev_err(dev, "invalid process id from user space\n"); + return -EINVAL; + } + + memset(&hifi4_priv->process_info[id], 0, + sizeof(struct icm_process_info)); + + return 0; +} + static struct miscdevice hifi4_miscdev = { .name = "mxc_hifi4", .minor = MISC_DYNAMIC_MINOR, @@ -1428,16 +1318,29 @@ static long fsl_hifi4_ioctl(struct file *file, unsigned int cmd, { 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 = (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; @@ -1479,16 +1382,29 @@ static long fsl_hifi4_compat_ioctl(struct file *file, unsigned int cmd, { 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) { + 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; @@ -1529,18 +1445,12 @@ void resource_release(struct fsl_hifi4 *hifi4_priv) { int i; - hifi4_priv->available_resource = MULTI_CODEC_NUM; - for (i = 0; i < MULTI_CODEC_NUM; i++) { - hifi4_priv->process_info[i].data_buf_virt = - hifi4_priv->data_buf_virt + - i * hifi4_priv->data_buf_size / MULTI_CODEC_NUM; - hifi4_priv->process_info[i].data_buf_phys = - hifi4_priv->data_buf_phys + - i * hifi4_priv->data_buf_size / MULTI_CODEC_NUM; + for (i = 0; i < MULTI_CODEC_NUM; i++) + memset(&hifi4_priv->process_info[i], 0, + sizeof(struct icm_process_info)); - hifi4_priv->process_info[i].status = 0; - } - send_dpu_ext_msg_addr(hifi4_priv); + if (hifi4_priv->is_ready) + send_dpu_ext_msg_addr(hifi4_priv); } static int fsl_hifi4_open(struct inode *inode, struct file *file) @@ -1711,29 +1621,23 @@ int process_act_complete(struct fsl_hifi4 *hifi4_priv, u32 msg) case ICM_OPEN: { - struct icm_open_resp_info_t *pext_msg = - (struct icm_open_resp_info_t *)pmsg_apu; - codec_iobuf_info->proc_id = pext_msg->proc_id; - hifi4_priv->dpu_tstamp = - (struct timestamp_info_t *)((long)pext_msg->dtstamp); - hifi4_priv->ret_status = pext_msg->ret; + 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; - if (codec_iobuf_info->proc_id == ext_msg->proc_id) { - codec_iobuf_info->inp_cur_offset = - ext_msg->inp_cur_offset; - codec_iobuf_info->out_cur_offset = - ext_msg->out_cur_offset; - codec_iobuf_info->cycles = - ext_msg->cycles; - } - hifi4_priv->ret_status = ext_msg->ret; + 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); } @@ -1743,14 +1647,13 @@ int process_act_complete(struct fsl_hifi4 *hifi4_priv, u32 msg) { struct icm_pcm_prop_t *ext_msg = (struct icm_pcm_prop_t *)pmsg_apu; - pcm_prop_info->proc_id = ext_msg->proc_id; 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->ret; + hifi4_priv->ret_status = ext_msg->base_info.ret; hifi4_priv->is_done = 1; complete(&hifi4_priv->cmd_complete); @@ -1759,29 +1662,39 @@ int process_act_complete(struct fsl_hifi4 *hifi4_priv, u32 msg) case ICM_SET_PARA_CONFIG: { - struct prop_config *ext_msg = - (struct prop_config *)pmsg_apu; - hifi4_priv->ret_status = ext_msg->ret; + 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: - hifi4_priv->is_done = 1; - complete(&hifi4_priv->cmd_complete); + { + 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: - hifi4_priv->is_done = 1; - complete(&hifi4_priv->cmd_complete); + { + 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_SWITCH_CODEC: + case ICM_PI_LIB_LOAD: { - struct icm_switch_info_t *ext_msg = - (struct icm_switch_info_t *)pmsg_apu; - hifi4_priv->ret_status = ext_msg->status; + 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); } @@ -1789,8 +1702,8 @@ int process_act_complete(struct fsl_hifi4 *hifi4_priv, u32 msg) case ICM_RESET: { - struct icm_reset_info_t *ext_msg = - (struct icm_reset_info_t *)pmsg_apu; + 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); @@ -1829,18 +1742,16 @@ int send_dpu_ext_msg_addr(struct fsl_hifi4 *hifi4_priv) apu_icm.msg = ICM_EXT_MSG_ADDR; apu_icm.size = 8; ext_msg.phys = hifi4_priv->msg_buf_phys; - /* 10 means variable numbers that need to be transferred */ - ext_msg.size = 10*4; /* 10 * sizeof(int) */ + /* 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->code_phys = hifi4_priv->code_buf_phys; - dpu_ext_msg->code_size = hifi4_priv->code_buf_size; - dpu_ext_msg->data_phys = hifi4_priv->data_buf_phys; - dpu_ext_msg->data_size = hifi4_priv->data_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->system_input_buf_phys = hifi4_priv->in_buf_phys; - dpu_ext_msg->system_input_buf_size = hifi4_priv->in_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); @@ -1871,7 +1782,6 @@ static irqreturn_t fsl_hifi4_mu_isr(int irq, void *dev_id) case ICM_EXT_MSG_ADDR: break; - case ICM_OPEN: case ICM_EMPTY_THIS_BUFFER: case ICM_CLOSE: break; @@ -2121,16 +2031,7 @@ static int fsl_hifi4_probe(struct platform_device *pdev) } memset_io(hifi4_priv->sdram_vir_addr, 0, SDRAM_BASE_SIZE); - /* code buffer */ - hifi4_priv->code_buf_virt = hifi4_priv->sdram_vir_addr - + SDRAM_CODEC_LIB_OFFSET; - hifi4_priv->code_buf_phys = hifi4_priv->sdram_phys_addr - + SDRAM_CODEC_LIB_OFFSET; - hifi4_priv->code_buf_size = LIBRARY_CODE_SIZE; - - size = MSG_BUF_SIZE + INPUT_BUF_SIZE + - OUTPUT_BUF_SIZE + FIRMWARE_DATA_BUF_SIZE + - SCRATCH_DATA_BUF_SIZE; + size = MSG_BUF_SIZE + HIFI_CONFIG_SIZE; buf_virt = dma_alloc_coherent(&pdev->dev, size, &buf_phys, GFP_KERNEL); if (!buf_virt) { @@ -2144,49 +2045,23 @@ static int fsl_hifi4_probe(struct platform_device *pdev) hifi4_priv->msg_buf_size = MSG_BUF_SIZE; offset = MSG_BUF_SIZE; - /* input buffer */ - hifi4_priv->in_buf_virt = buf_virt + offset; - hifi4_priv->in_buf_phys = buf_phys + offset; - hifi4_priv->in_buf_size = INPUT_BUF_SIZE; - offset += INPUT_BUF_SIZE; + hifi4_priv->hifi_config_virt = buf_virt + offset; + hifi4_priv->hifi_config_phys = buf_phys + offset; + hifi4_priv->hifi_config_size = HIFI_CONFIG_SIZE; - /* output buffer */ - hifi4_priv->out_buf_virt = buf_virt + offset; - hifi4_priv->out_buf_phys = buf_phys + offset; - hifi4_priv->out_buf_size = OUTPUT_BUF_SIZE; - offset += OUTPUT_BUF_SIZE; - - /* codec library data section */ - hifi4_priv->data_buf_virt = buf_virt + offset; - hifi4_priv->data_buf_phys = buf_phys + offset; - hifi4_priv->data_buf_size = FIRMWARE_DATA_BUF_SIZE; - offset += FIRMWARE_DATA_BUF_SIZE; - - hifi4_priv->scratch_buf_virt = buf_virt + offset; - hifi4_priv->scratch_buf_phys = buf_phys + offset; - hifi4_priv->scratch_buf_size = SCRATCH_DATA_BUF_SIZE; - - /* process_id_count is a counter to produce new id - * process_id is current codec's id - */ - hifi4_priv->process_id_count = 0; - hifi4_priv->process_id = 0; + 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. */ - hifi4_priv->available_resource = MULTI_CODEC_NUM; - for (i = 0; i < MULTI_CODEC_NUM; i++) { - hifi4_priv->process_info[i].data_buf_virt = - hifi4_priv->data_buf_virt + - i * hifi4_priv->data_buf_size / MULTI_CODEC_NUM; - hifi4_priv->process_info[i].data_buf_phys = - hifi4_priv->data_buf_phys + - i * hifi4_priv->data_buf_size / MULTI_CODEC_NUM; - - hifi4_priv->process_info[i].status = 0; - } + 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 @@ -2204,9 +2079,7 @@ static int fsl_hifi4_remove(struct platform_device *pdev) misc_deregister(&hifi4_miscdev); - size = MSG_BUF_SIZE + INPUT_BUF_SIZE + - OUTPUT_BUF_SIZE + FIRMWARE_DATA_BUF_SIZE + - SCRATCH_DATA_BUF_SIZE; + size = MSG_BUF_SIZE + HIFI_CONFIG_SIZE; dma_free_coherent(&pdev->dev, size, hifi4_priv->msg_buf_virt, hifi4_priv->msg_buf_phys); if (hifi4_priv->sdram_vir_addr) diff --git a/sound/soc/fsl/fsl_hifi4.h b/sound/soc/fsl/fsl_hifi4.h index 787d35f3cb88..221d05a4092c 100644 --- a/sound/soc/fsl/fsl_hifi4.h +++ b/sound/soc/fsl/fsl_hifi4.h @@ -1,7 +1,7 @@ /* * Freescale HIFI 4 driver * - * Copyright 2017 NXP. + * Copyright 2018 NXP * * 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 @@ -40,39 +40,39 @@ struct xtlib_loader_globals { int byteswap; }; -struct timestamp_info_t { - u32 offset_last_inp_byt_read_frm_sysram; - u32 offset_last_inp_byt_decoded; - u32 samples_produced; - u32 sample_rate; +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 { - u32 proc_id; /* non-zero indicates success; */ + 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 */ - s32 ret; - u32 cycles; /* consumed cycles during executing */ u32 input_over; /* indicate external stream is over*/ }; -struct icm_cdc_uinp_t { - u32 proc_id; /* audio id */ - u32 codec_id; /* codec identifier */ +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 { - u32 proc_id; /* audio id */ + 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; - s32 ret; + u32 cycles; }; struct xtlib_overlay_info { @@ -97,6 +97,13 @@ struct xtlib_pil_info { 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; @@ -118,6 +125,7 @@ enum icm_action_t { ICM_CORE_READY = 1, ICM_PI_LIB_MEM_ALLOC, ICM_PI_LIB_INIT, + ICM_PI_LIB_LOAD, ICM_PI_LIB_UNLOAD, ICM_DPU_ACTION_COMPLETE, @@ -135,7 +143,6 @@ enum icm_action_t { ICM_CORE_EXIT, ICM_EXT_MSG_ADDR, - ICM_SWITCH_CODEC, ICM_RESET, ICM_SUSPEND, ICM_RESUME, @@ -148,23 +155,6 @@ enum aud_status_t { AUD_PAUSED }; -struct icm_open_resp_info_t { - u32 proc_id; - u32 dtstamp; /* address value of timestamp_info_t */ - - s32 ret; -}; - -struct icm_reset_info_t { - u32 codec_id; - s32 ret; /* executed status of reset function */ -}; - -struct icm_switch_info_t { - u32 proc_id; /* audio id */ - u32 status; /* codec status */ -}; - struct lib_dnld_info_t { unsigned long pbuf_code; unsigned long pbuf_data; @@ -174,23 +164,31 @@ struct lib_dnld_info_t { unsigned int lib_on_dpu; /* 0: not loaded, 1: loaded. */ }; - -struct icm_pilib_size_t { - u32 codec_type; - u32 text_size; - u32 data_size; -}; - struct icm_process_info { unsigned int process_id; unsigned int codec_id; - unsigned int proc_id; - void *data_buf_virt; - dma_addr_t data_buf_phys; + struct xtlib_pil_info pil_info; + struct xtlib_loader_globals xtlib_globals; - struct xtlib_pil_info pil_info_info; - unsigned int status; + 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; + + struct filename *objfile; + char objtype; + + unsigned int used; }; struct fsl_hifi4 { @@ -212,49 +210,24 @@ struct fsl_hifi4 { void *msg_buf_virt; dma_addr_t msg_buf_phys; int msg_buf_size; - 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; void *scratch_buf_virt; dma_addr_t scratch_buf_phys; int scratch_buf_size; + void *hifi_config_virt; + dma_addr_t hifi_config_phys; + int hifi_config_size; int is_ready; int is_done; - - struct completion cmd_complete; - char *objmem; - struct filename *objfile; - char objtype; - unsigned int start_addr; int ret_status; + struct icm_cdc_iobuf_t codec_iobuf_info; struct icm_pcm_prop_t pcm_prop_info; - struct xtlib_pil_info pil_info; - struct xtlib_loader_globals xtlib_globals; - struct timestamp_info_t *dpu_tstamp; + struct completion cmd_complete; struct mutex hifi4_mutex; - unsigned int process_id; - unsigned int process_id_count; - - unsigned int size_code; - unsigned int size_data; - struct icm_process_info process_info[MULTI_CODEC_NUM]; - unsigned int available_resource; - unsigned int cur_res_id; }; struct fsl_hifi4_engine { @@ -269,14 +242,10 @@ struct hifi4_ext_msg { struct hifi4_mem_msg { u32 ext_msg_phys; u32 ext_msg_size; - u32 code_phys; - u32 code_size; - u32 data_phys; - u32 data_size; u32 scratch_phys; u32 scratch_size; - u32 system_input_buf_phys; - u32 system_input_buf_size; + u32 hifi_config_phys; + u32 hifi_config_size; }; #define IRAM_OFFSET 0x10000 @@ -294,47 +263,21 @@ struct hifi4_mem_msg { #define SYSROM_OFFSET 0x58000 #define SYSROM_SIZE 0x30000 -#define LIBRARY_CODE_OFFSET 0x38000 -#define LIBRARY_CODE_SIZE 0x50000 - #define MSG_BUF_SIZE 4096 #define INPUT_BUF_SIZE 4096 #define OUTPUT_BUF_SIZE 16384 -#define FIRMWARE_DATA_BUF_SIZE (MULTI_CODEC_NUM * 0x80000) +#define HIFI_CONFIG_SIZE 4096 - -/*scratch buf structure +/*external buffer * ---------------------------------------------------------------------- - * | name | size | description | + * | name | size | description | * ----------------------------------------------------------------------- - * | CODEC 0 | 0x80000 | Total support 5 instance. - * ----------------------------------- Each instance has 0x80000 size - * | CODEC 1 | 0x80000 | buffer for store the code section - * ----------------------------------- and input/output buffer. - * | CODEC 2 | 0x80000 | - * ----------------------------------- - * | CODEC 3 | 0x80000 | - * ----------------------------------- - * | CODEC 4 | 0x80000 | + * | scratch buffer for malloc | 0xffffff | For MEM_scratch_malloc() * ------------------------------------------------------------------------ - * | codec info buf | 4096 | For alloc the codec info structure - * ------------------------------------------------------------------------ - * | global structure | 4096 | For store hifi config structure - * ------------------------------------------------------------------------ - * | DRAM | 64k | For store DRAM buffer in suspend + * | global structure | 4096 | For store hifi config structure * ------------------------------------------------------------------------ */ -#define EACH_CODEC_BUF_SIZE 0x80000 -#define CODEC_INFO_BUF_OFF (MULTI_CODEC_NUM * EACH_CODEC_BUF_SIZE) -#define CODEC_INFO_BUF_SIZE 4096 -#define SUSPEND_GLOBAL_BUF_OFF (CODEC_INFO_BUF_OFF + CODEC_INFO_BUF_SIZE) -#define SUSPEND_GLOBAL_BUF_SIZE 4096 -#define SUSPEND_DRAM_BUF_OFF (SUSPEND_GLOBAL_BUF_OFF + SUSPEND_GLOBAL_BUF_SIZE) -#define SUSPEND_DRAM_BUF_SIZE 65536 - -#define SCRATCH_DATA_BUF_SIZE (SUSPEND_DRAM_BUF_OFF + SUSPEND_DRAM_BUF_SIZE) - #define MEMORY_REMAP_OFFSET 0x39000000 /* reserved memory for hifi4 firmware and core libs to @@ -361,7 +304,7 @@ unsigned int xtlib_split_pi_library_size( struct xtlib_packaged_library *library, unsigned int *code_size, unsigned int *data_size, - struct fsl_hifi4 *hifi4_priv); + struct icm_process_info *process_info); xt_ptr xtlib_host_load_split_pi_library( struct xtlib_packaged_library *library, @@ -370,7 +313,7 @@ xt_ptr xtlib_host_load_split_pi_library( struct xtlib_pil_info *lib_info, memcpy_func mcpy_fn, memset_func mset_fn, - struct fsl_hifi4 *hifi4_priv); + 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); From 4c599d4b5c167ccb34e3f016458248db662f12d5 Mon Sep 17 00:00:00 2001 From: Weiguang Kong Date: Tue, 26 Dec 2017 18:37:14 +0800 Subject: [PATCH 24/78] MLK-17309-3: ASoC: fsl_hifi: get free memory from hifi framework In order to manage the memory simply, all the memory which is shared between hifi driver and hifi framework are managed by hifi framework. So when the driver wants to get free memory, it can send "ICM_PI_LIB_MEM_ALLOC" command to hifi framework, then hifi framework will return the address of available memory to driver. When the driver wants to release the memory, it can send "ICM_PI_LIB_MEM_FREE" command to hifi framework, the hifi framework will mark this memory available. Signed-off-by: Weiguang Kong --- sound/soc/fsl/fsl_hifi4.c | 270 ++++++++++++++++++++++++++++++++------ sound/soc/fsl/fsl_hifi4.h | 12 ++ 2 files changed, 240 insertions(+), 42 deletions(-) diff --git a/sound/soc/fsl/fsl_hifi4.c b/sound/soc/fsl/fsl_hifi4.c index f423eb71f326..75988877e683 100644 --- a/sound/soc/fsl/fsl_hifi4.c +++ b/sound/soc/fsl/fsl_hifi4.c @@ -147,56 +147,102 @@ static int put_decode_info_compat32(struct decode_info *kp, } #endif -long load_dpu_with_library(struct fsl_hifi4 *hifi4_priv, - struct icm_process_info *process_info) +long hifi4_buf_alloc(struct fsl_hifi4 *hifi4_priv, + unsigned int size) { - struct file *fpInfile; - unsigned char *srambuf = NULL; - struct lib_dnld_info_t dpulib; - int filesize = 0; - long ret_val = 0; + 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; - /* 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); + if (size <= 0) + return 0; - vfs_llseek(fpInfile, 0, SEEK_END); - filesize = (int)fpInfile->f_pos; + /* 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; - srambuf = kmalloc(filesize, GFP_KERNEL); - vfs_llseek(fpInfile, 0, SEEK_SET); + 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; - kernel_read(fpInfile, srambuf, filesize, NULL); - filp_close(fpInfile, NULL); + ext_msg.phys = hifi4_priv->msg_buf_phys; + ext_msg.size = sizeof(struct icm_pilib_size_t); - 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; + icm_pilib_size_t.buffer_addr = 0; + icm_pilib_size_t.buffer_size = size; + icm_pilib_size_t.ret = 0; - process_info->code_buf_size = dpulib.size_code; - process_info->data_buf_size = dpulib.size_data; + 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); - dpulib.pbuf_code = (unsigned long)process_info->code_buf_phys; - dpulib.pbuf_data = (unsigned long)process_info->data_buf_phys; + /* wait for response here */ + ret = icm_ack_wait(hifi4_priv, apu_icm.allbits); + if (ret) + return 0; - 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); + if (pilib_buffer_info->buffer_addr) + return (long)pilib_buffer_info->buffer_addr; - kfree(srambuf); + return 0; +} - return ret_val; +long hifi4_buf_free(struct fsl_hifi4 *hifi4_priv, long ptr) +{ + union icm_header_t apu_icm; + struct hifi4_ext_msg ext_msg; + struct icm_pilib_size_t icm_pilib_size_t; + long ret = 0; + + 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; + + 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; + + ext_msg.phys = hifi4_priv->msg_buf_phys; + ext_msg.size = sizeof(struct icm_pilib_size_t); + + icm_pilib_size_t.buffer_addr = (u32)ptr; + icm_pilib_size_t.buffer_size = 0; + 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 ret; + + ret = hifi4_priv->ret_status; + + return ret; } Elf32_Half xtlib_host_half(Elf32_Half v, int byteswap) @@ -643,6 +689,94 @@ xt_ptr xtlib_host_load_split_pi_library(struct xtlib_packaged_library *library, } +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) { @@ -686,6 +820,31 @@ static long fsl_hifi4_init_codec(struct fsl_hifi4 *hifi4_priv, 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; } @@ -1070,6 +1229,7 @@ static long fsl_hifi4_load_codec_compat32(struct fsl_hifi4 *hifi4_priv, 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); @@ -1288,7 +1448,8 @@ static int fsl_hifi4_client_unregister(struct fsl_hifi4 *hifi4_priv, void __user *user) { struct device *dev = hifi4_priv->dev; - int id; + struct icm_process_info *process_info; + int id, i; unsigned long ret = 0; ret = copy_from_user(&id, user, sizeof(int)); @@ -1302,8 +1463,16 @@ static int fsl_hifi4_client_unregister(struct fsl_hifi4 *hifi4_priv, return -EINVAL; } - memset(&hifi4_priv->process_info[id], 0, - sizeof(struct icm_process_info)); + 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; } @@ -1602,6 +1771,8 @@ int process_act_complete(struct fsl_hifi4 *hifi4_priv, u32 msg) 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; @@ -1614,6 +1785,21 @@ int process_act_complete(struct fsl_hifi4 *hifi4_priv, u32 msg) 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); } diff --git a/sound/soc/fsl/fsl_hifi4.h b/sound/soc/fsl/fsl_hifi4.h index 221d05a4092c..43b98592e1c0 100644 --- a/sound/soc/fsl/fsl_hifi4.h +++ b/sound/soc/fsl/fsl_hifi4.h @@ -22,6 +22,7 @@ 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, @@ -124,6 +125,7 @@ union 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, @@ -164,6 +166,12 @@ struct lib_dnld_info_t { unsigned int lib_on_dpu; /* 0: not loaded, 1: loaded. */ }; +struct icm_pilib_size_t { + u32 buffer_addr; + u32 buffer_size; + s32 ret; +}; + struct icm_process_info { unsigned int process_id; unsigned int codec_id; @@ -185,6 +193,9 @@ struct icm_process_info { 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; @@ -223,6 +234,7 @@ struct fsl_hifi4 { 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; struct mutex hifi4_mutex; From 7d877756ebf7732bba0b08e97e93d10a297587d0 Mon Sep 17 00:00:00 2001 From: Weiguang Kong Date: Tue, 26 Dec 2017 18:50:31 +0800 Subject: [PATCH 25/78] MLK-17309-4: ASoC: fsl_hifi: fix crash issue when destination not align When loading the codec libs in driver, if the destination is not 4-bytes alignment when doing memset_hifi(), the driver will print a warning message and the driver may crash in some cases. So by changing the memset() function and aligning the virtual address based on the physical address to fix this issue. Signed-off-by: Weiguang Kong --- sound/soc/fsl/fsl_hifi4.c | 52 +++++++++++++++++++++++++++++++++------ 1 file changed, 45 insertions(+), 7 deletions(-) diff --git a/sound/soc/fsl/fsl_hifi4.c b/sound/soc/fsl/fsl_hifi4.c index 75988877e683..4d4fce93d3bb 100644 --- a/sound/soc/fsl/fsl_hifi4.c +++ b/sound/soc/fsl/fsl_hifi4.c @@ -611,6 +611,8 @@ static xt_ptr xtlib_load_split_pi_library_common( 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; @@ -619,8 +621,15 @@ static xt_ptr xtlib_load_split_pi_library_common( 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, @@ -1683,16 +1692,45 @@ static int fsl_hifi4_close(struct inode *inode, struct file *file) void *memset_hifi(void *dest, int c, size_t count) { - unsigned int *dl = (unsigned int *)dest; - size_t n = round_up(count, 4) / 4; + uint *dl = (uint *)dest; + void *dl_1, *dl_2; + size_t align = 4; + size_t n, n1, n2; /* while all data is aligned (common case), copy a word at a time */ - if ((((ulong)dest) & (sizeof(*dl) - 1)) != 0) - pr_info("dest %p not 4 bytes aligned\n", dest); + if ((((ulong)dest) & (sizeof(*dl) - 1)) != 0) { + dl = (unsigned int *)(((ulong)dest + align - 1) & + (~(align - 1))); + dl_1 = dest; + dl_2 = (void *)(((ulong)dest + count) & (~(align - 1))); + n1 = (ulong)dl - (ulong)dl_1; + n2 = (ulong)dest + count - (ulong)dl_2; + n = (count - n1 - n2) / align; - while (n--) { - writel_relaxed(0, dl); - dl++; + while (n--) { + writel_relaxed(0, dl); + dl++; + } + while (n1--) { + writeb_relaxed(0, dl_1); + dl_1++; + } + while (n2--) { + writeb_relaxed(0, dl_2); + dl_2++; + } + } else { + n = count / align; + n1 = count - n * align; + dl_1 = dest + n * align; + while (n--) { + writel_relaxed(0, dl); + dl++; + } + while (n1--) { + writeb_relaxed(0, dl_1); + dl_1++; + } } return dest; From d4a9dadb61c86188ce4a943a9c1cb75868fbe446 Mon Sep 17 00:00:00 2001 From: Weiguang Kong Date: Wed, 18 Apr 2018 16:54:57 +0800 Subject: [PATCH 26/78] MLK-18073: ASoC: fsl_dsp: fix uninitialized scalar variable issue This patch is used to fix Coverity-1793874, Coverity-1793875, Coverity-1793876, Coverity-1793877 issue. The icm_base_info_t is not initialized before using, so use memset() to initialize it to fix these issues. Signed-off-by: Weiguang Kong --- sound/soc/fsl/fsl_hifi4.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/sound/soc/fsl/fsl_hifi4.c b/sound/soc/fsl/fsl_hifi4.c index 4d4fce93d3bb..756a697e570a 100644 --- a/sound/soc/fsl/fsl_hifi4.c +++ b/sound/soc/fsl/fsl_hifi4.c @@ -817,6 +817,7 @@ static long fsl_hifi4_init_codec(struct fsl_hifi4 *hifi4_priv, 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; @@ -1311,6 +1312,7 @@ static long fsl_hifi4_codec_open(struct fsl_hifi4 *hifi4_priv, 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, @@ -1355,6 +1357,7 @@ static int fsl_hifi4_codec_close(struct fsl_hifi4 *hifi4_priv, 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, @@ -1402,6 +1405,7 @@ static int fsl_hifi4_codec_reset(struct fsl_hifi4 *hifi4_priv, 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, From 94894c677517315d92c11388cb31f698636b6549 Mon Sep 17 00:00:00 2001 From: Weiguang Kong Date: Thu, 14 Sep 2017 13:31:22 +0800 Subject: [PATCH 27/78] MLK-16468-1: include: uapi: add multi-codec support for hifi4 update the mxc_hifi4.h header file to support multi-codec decoding or encoding together for hifi4 dsp. Signed-off-by: Weiguang Kong Reviewed-by: Mihai Serban --- include/uapi/linux/mxc_hifi4.h | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/include/uapi/linux/mxc_hifi4.h b/include/uapi/linux/mxc_hifi4.h index f8db59889387..4da17005506f 100644 --- a/include/uapi/linux/mxc_hifi4.h +++ b/include/uapi/linux/mxc_hifi4.h @@ -33,7 +33,7 @@ #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_SET_CONFIG _IOW(HIFI4_IOC_MAGIC, 7, unsigned int) #define CODEC_MP3_DEC 1 #define CODEC_AAC_DEC 2 @@ -54,6 +54,7 @@ struct decode_info { int out_buf_off; unsigned int cycles; unsigned int input_over; + unsigned int process_id; }; struct prop_info { @@ -69,11 +70,14 @@ struct prop_info { int aac_samplerate; int sbr_type; int mpeg_surr_present; + + unsigned int process_id; }; struct binary_info { int type; char *file; + unsigned int process_id; }; struct prop_config { @@ -81,6 +85,7 @@ struct prop_config { int cmd; /* command value */ int val; /* parameter value */ int ret; /* executed status of function */ + unsigned int process_id; }; #endif/* __MXC_HIFI4_UAPI_H__ */ From 3b3a0bf665d04a5dc322d9bd27fec8433d5e8f38 Mon Sep 17 00:00:00 2001 From: Weiguang Kong Date: Thu, 28 Sep 2017 12:44:17 +0800 Subject: [PATCH 28/78] MLK-16545-1: uapi: mxc_hifi4: add reset command for hifi4 add reset command declaration into mxc_hifi4.h file, this command is used to reset hifi4 codec when seeking Signed-off-by: Weiguang Kong Reviewed-by: Daniel Baluta --- include/uapi/linux/mxc_hifi4.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/uapi/linux/mxc_hifi4.h b/include/uapi/linux/mxc_hifi4.h index 4da17005506f..27a3c4fab27a 100644 --- a/include/uapi/linux/mxc_hifi4.h +++ b/include/uapi/linux/mxc_hifi4.h @@ -34,6 +34,7 @@ #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 CODEC_MP3_DEC 1 #define CODEC_AAC_DEC 2 From d69e9a1786d3e1787d68a2572f6a4d7e4e94e35d Mon Sep 17 00:00:00 2001 From: Weiguang Kong Date: Tue, 26 Dec 2017 18:57:10 +0800 Subject: [PATCH 29/78] MLK-17309-1: uapi: mxc_hifi4: provide new interface for user space In order to avoid license problem of Cadence header files, these license files has been wrappered into a library and new interface has been abstracted to replace the interface of Cadence header files. So update the mxc_hifi4.h file to provide new interface for user space to use. Signed-off-by: Weiguang Kong --- include/uapi/linux/mxc_hifi4.h | 108 ++++++++++++++++++++++++++++++--- 1 file changed, 98 insertions(+), 10 deletions(-) diff --git a/include/uapi/linux/mxc_hifi4.h b/include/uapi/linux/mxc_hifi4.h index 27a3c4fab27a..e22f7f5808e1 100644 --- a/include/uapi/linux/mxc_hifi4.h +++ b/include/uapi/linux/mxc_hifi4.h @@ -1,5 +1,5 @@ /* - * Copyright 2017 NXP + * Copyright 2018 NXP * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -35,6 +35,8 @@ #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 CODEC_MP3_DEC 1 #define CODEC_AAC_DEC 2 @@ -46,6 +48,99 @@ #define CODEC_SBC_ENC 8 #define CODEC_DEMO_DEC 9 +enum HIFI_ERROR_TYPE { + XA_SUCCESS = 0, + + XA_ERROR_STREAM, + XA_PARA_ERROR, + XA_INSUFFICIENT_MEM, + XA_ERR_UNKNOWN, + XA_PROFILE_NOT_SUPPORT, + XA_INIT_ERR, + XA_NO_OUTPUT, + + XA_NOT_ENOUGH_DATA = 0x100, + XA_CAPIBILITY_CHANGE = 0x200, + XA_END_OF_STREAM = 0x300, /* no output */ +}; + +/* Parameter type to Set /Get */ +enum HIFI_ParaType { +/* Set parmameters */ +/* common */ + XA_SAMPLERATE = 0, + XA_CHANNEL, + XA_FRAMED, /* one whole frame input */ + XA_DEPTH, + XA_CODEC_DATA, + XA_BITRATE, + XA_DOWNMIX_STEREO, + XA_STREAM_TYPE, + XA_CHAN_MAP_TABLE, + //UNIA_CHANNEL_MASK, + XA_TO_STEREO, + +/* dedicate for mp3 dec */ + XA_MP3_DEC_CRC_CHECK = 0x120, + XA_MP3_DEC_MCH_ENABLE, + XA_MP3_DEC_NONSTD_STRM_SUPPORT, + +/* dedicate for bsac dec */ + XA_BSAC_DEC_DECODELAYERS = 0x130, + +/* dedicate for aacplus dec */ + XA_AACPLUS_DEC_BDOWNSAMPLE = 0x140, + XA_AACPLUS_DEC_BBITSTREAMDOWNMIX, + XA_AACPLUS_DEC_CHANROUTING, + +/* dedicate for dabplus dec */ + XA_DABPLUS_DEC_BDOWNSAMPLE = 0x150, + XA_DABPLUS_DEC_BBITSTREAMDOWNMIX, + XA_DABPLUS_DEC_CHANROUTING, + +/* dedicate for sbc enc */ + XA_SBC_ENC_SUBBANDS = 0x160, + XA_SBC_ENC_BLOCKS, + XA_SBC_ENC_SNR, + XA_SBC_ENC_BITPOOL, + XA_SBC_ENC_CHMODE, + +}; + +#define HIFI_STREAM_DABPLUS_BASE 0x30 +enum HIFI_StreamType { + /* AAC/AACPLUS file format */ + XA_STREAM_UNKNOWN = 0, + XA_STREAM_ADTS, + XA_STREAM_ADIF, + XA_STREAM_RAW, + + XA_STREAM_LATM, + XA_STREAM_LATM_OUTOFBAND_CONFIG, + XA_STREAM_LOAS, + + /* DABPLUS file format */ + XA_STREAM_DABPLUS_RAW_SIDEINFO = HIFI_STREAM_DABPLUS_BASE, + XA_STREAM_DABPLUS, + + /* BSAC file raw format */ + XA_STREAM_BSAC_RAW, + +}; + +/* sbc_enc-specific channel modes */ +enum HIFI_SbcEncChmode { + XA_CHMODE_MONO = 0, + XA_CHMODE_DUAL = 1, + XA_CHMODE_STEREO = 2, + 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; @@ -53,7 +148,6 @@ struct decode_info { void *out_buf_addr; int out_buf_size; int out_buf_off; - unsigned int cycles; unsigned int input_over; unsigned int process_id; }; @@ -63,14 +157,7 @@ struct prop_info { int channels; int bits; unsigned int consumed_bytes; - - /* dedicate for drm dec */ - int frame_size; - - /* dedicate for bsac, aacplus and dabplus dec */ - int aac_samplerate; - int sbr_type; - int mpeg_surr_present; + unsigned int cycles; unsigned int process_id; }; @@ -79,6 +166,7 @@ struct binary_info { int type; char *file; unsigned int process_id; + unsigned int lib_type; }; struct prop_config { From 12d419bbb1c9f8b47b45073c881c61b99ee8b717 Mon Sep 17 00:00:00 2001 From: Weiguang Kong Date: Wed, 4 Apr 2018 11:56:10 +0800 Subject: [PATCH 30/78] MLK-17635-1: ASoC: fsl_dsp: change dsp driver to support new dsp framework The architecture of dsp framework has been changed, the role of dsp driver is transferring messages between dsp framework and user space application, so change dsp driver to support this function. Signed-off-by: Weiguang Kong --- include/uapi/linux/mxc_hifi4.h | 67 +- sound/soc/fsl/Makefile | 2 +- sound/soc/fsl/fsl_hifi4.c | 2209 ++++++------------------------- sound/soc/fsl/fsl_hifi4.h | 271 +--- sound/soc/fsl/fsl_hifi4_proxy.c | 641 +++++++++ sound/soc/fsl/fsl_hifi4_proxy.h | 381 ++++++ 6 files changed, 1448 insertions(+), 2123 deletions(-) create mode 100644 sound/soc/fsl/fsl_hifi4_proxy.c create mode 100644 sound/soc/fsl/fsl_hifi4_proxy.h 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 #include #include +#include #ifdef CONFIG_COMPAT #include #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; -}; +/* ...allocate new client */ +static inline struct xf_client *xf_client_alloc(struct fsl_hifi4 *hifi4_priv) +{ + struct xf_client *client; + u32 id; -struct binary_info_compat32 { - __s32 type; - compat_long_t file; - __u32 process_id; - __u32 lib_type; -}; + id = hifi4_priv->xf_client_map[0].next; -static int get_binary_info_compat32(struct binary_info *kp, - struct binary_info_compat32 __user *up) { - void __user *up_ptr; - compat_long_t p; + /* ...try to allocate a client handle */ + if (id != 0) { + /* ...allocate client memory */ + client = kmalloc(sizeof(*client), GFP_KERNEL); + if (!client) + return ERR_PTR(-ENOMEM); - 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; + /* ...advance the head of free clients */ + hifi4_priv->xf_client_map[0].next = + hifi4_priv->xf_client_map[id].next; + + /* ...put associate client id with given object */ + hifi4_priv->xf_client_map[id].client = client; + + /* ...mark client is not yet bound to proxy */ + client->proxy = NULL; + + /* ...save global proxy client identifier */ + client->id = id; + + return client; } - up_ptr = compat_ptr(p); - kp->file = (char *)up_ptr; + /* ...number of clients exceeded */ + return ERR_PTR(-EBUSY); +} + +/* ...recycle client object */ +static inline void xf_client_free(struct xf_client *client) +{ + int id = client->id; + struct fsl_hifi4 *hifi4_priv = (struct fsl_hifi4 *)client->global; + + /* ...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; + + /* ...destroy client data */ + kfree(client); +} + +/* ...lookup client basing on id */ +struct xf_client *xf_client_lookup(struct fsl_hifi4 *hifi4_priv, u32 id) +{ + 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; +} + +/* ...helper function for retrieving the client handle */ +static inline struct xf_client *xf_get_client(struct file *file) +{ + struct xf_client *client; + u32 id; + + client = (struct xf_client *)file->private_data; + if (!client) + return ERR_PTR(-EINVAL); + + id = client->id; + if (id >= XF_CFG_MAX_IPC_CLIENTS) + return ERR_PTR(-EINVAL); + + return client; +} + +static int fsl_dsp_client_register(struct xf_client *client) +{ + struct fsl_hifi4 *hifi4_priv; + struct device *dev; + + hifi4_priv = (struct fsl_hifi4 *)client->global; + dev = hifi4_priv->dev; + + /* ...make sure client is not registered yet */ + if (client->proxy != NULL) { + pr_err("client-%x already registered", client->id); + return -EBUSY; + } + + /* ...complete association (no communication with remote proxy here) */ + client->proxy = &hifi4_priv->proxy; + + pr_debug("client-%x registered within proxy", client->id); 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; +/* ...unregister client from shared memory interface */ +static int fsl_dsp_client_unregister(struct xf_client *client) +{ + struct xf_proxy *proxy = client->proxy; - 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; + /* ...make sure client is registered */ + if (proxy == NULL) { + pr_err("client-%x is not registered", client->id); + return -EBUSY; } - up_ptr1 = compat_ptr(p1); - up_ptr2 = compat_ptr(p2); + /* ...just clean proxy reference */ + client->proxy = NULL; - kp->in_buf_addr = (void *)up_ptr1; - kp->out_buf_addr = (void *)up_ptr2; + pr_debug("client-%x registered within proxy", client->id); 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) -{ - union icm_header_t apu_icm; - struct hifi4_ext_msg ext_msg; - struct icm_pilib_size_t icm_pilib_size_t; - long ret = 0; - - 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; - - 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; - - ext_msg.phys = hifi4_priv->msg_buf_phys; - ext_msg.size = sizeof(struct icm_pilib_size_t); - - icm_pilib_size_t.buffer_addr = (u32)ptr; - icm_pilib_size_t.buffer_size = 0; - 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 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; -} - -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 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); -} - -#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) -{ - 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, +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; - - 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]; - - 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_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; -} - -static long fsl_hifi4_decode_frame(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 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; -} - -#ifdef CONFIG_COMPAT -static long fsl_hifi4_decode_frame_compat32(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 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; - } - - 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 = 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; -} -#endif - -static long fsl_hifi4_get_pcm_prop(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_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; -} - -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; - - 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; - } - - init_completion(&hifi4_priv->cmd_complete); - hifi4_priv->is_done = 0; - - apu_icm.allbits = 0; - apu_icm.ack = 0; - apu_icm.intr = 1; - apu_icm.msg = ICM_SET_PARA_CONFIG; - apu_icm.size = 8; - - 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; -} - -static long fsl_hifi4_load_codec(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 = copy_from_user(&binary_info, user, sizeof(binary_info)); - if (ret) { - dev_err(dev, "failed to get para from user space\n"); - return -EFAULT; - } - - 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; -} - -#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; -} -#endif - -static long fsl_hifi4_codec_open(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]; - - 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"); - 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; - - ret = hifi4_priv->ret_status; - - return ret; -} - -static int fsl_hifi4_codec_reset(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_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_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; } - init_completion(&hifi4_priv->cmd_complete); - hifi4_priv->is_done = 0; + /* ...make sure message pointer is sane */ + buffer = xf_proxy_a2b(&hifi4_priv->proxy, msg.address); + if (buffer == (void *)-1) + return -EFAULT; - apu_icm.allbits = 0; /* clear all bits;*/ - apu_icm.ack = 0; - apu_icm.intr = 1; - apu_icm.msg = ICM_RESET; - apu_icm.size = 8; + /* ...put current proxy client into message session id */ + msg.session_id = XF_MSG_AP_FROM_USER(msg.session_id, client->id); - ext_msg.phys = hifi4_priv->msg_buf_phys; - ext_msg.size = sizeof(struct icm_base_info_t); + xf_cmd_send(&hifi4_priv->proxy, + msg.session_id, + msg.opcode, + buffer, + msg.length); - 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; - - /* reset codec_iobuf_info */ - codec_iobuf_info->inp_buf_size_max = 0; - codec_iobuf_info->inp_cur_offset = 0; - - codec_iobuf_info->out_buf_size_max = 0; - codec_iobuf_info->out_cur_offset = 0; - - err = hifi4_priv->ret_status; - - return err; + return 0; } -static int fsl_hifi4_client_register(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; - int id, i; + struct xf_message *m; + struct xf_proxy_message msg; 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; + 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); } - ret = copy_to_user(user, &id, sizeof(int)); + /* ...check if there is a response available */ + if (m == NULL) + return -EAGAIN; + + /* ...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; + + /* ...return the message back to a pool and release lock */ + xf_msg_free(&hifi4_priv->proxy, m); + + 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,56 +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) { + mutex_lock(&hifi4_priv->hifi4_mutex); + + 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); + case DSP_CLIENT_REGISTER: + ret = fsl_dsp_client_register(client); break; - case HIFI4_CLIENT_UNREGISTER: - ret = fsl_hifi4_client_unregister(hifi4_priv, user); + case DSP_CLIENT_UNREGISTER: + ret = fsl_dsp_client_unregister(client); break; - case HIFI4_LOAD_CODEC: - ret = fsl_hifi4_load_codec(hifi4_priv, user); + case DSP_IPC_MSG_SEND: + ret = fsl_dsp_ipc_msg_to_dsp(client, user); break; - case HIFI4_INIT_CODEC: - ret = fsl_hifi4_init_codec(hifi4_priv, user); + case DSP_IPC_MSG_RECV: + ret = fsl_dsp_ipc_msg_from_dsp(client, 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); + case DSP_GET_SHMEM_INFO: + ret = fsl_dsp_get_shmem_info(client, user); break; default: break; @@ -1558,112 +331,61 @@ static long fsl_hifi4_ioctl(struct file *file, unsigned int cmd, 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) { - 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); - break; - case HIFI4_CODEC_OPEN: - ret = fsl_hifi4_codec_open(hifi4_priv, user); - break; - case HIFI4_DECODE_ONE_FRAME: - ret = fsl_hifi4_decode_frame_compat32(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; -} -#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; + + /* ...allocate new proxy client object */ + client = xf_client_alloc(hifi4_priv); + if (IS_ERR(client)) + return PTR_ERR(client); + + /* ...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; + + file->private_data = (void *)client; pm_runtime_get_sync(dev); + mutex_lock(&hifi4_priv->hifi4_mutex); - - hifi4_engine = devm_kzalloc(dev, - sizeof(struct fsl_hifi4_engine), GFP_KERNEL); - if (!hifi4_engine) { - mutex_unlock(&hifi4_priv->hifi4_mutex); - return -ENOMEM; - } - - hifi4_engine->hifi4_priv = hifi4_priv; - - file->private_data = hifi4_engine; - /* increase reference counter when opening device */ atomic_long_inc(&hifi4_priv->refcnt); - mutex_unlock(&hifi4_priv->hifi4_mutex); + pr_info("client-%x created\n", client->id); + return ret; } @@ -1671,15 +393,30 @@ static int fsl_hifi4_close(struct inode *inode, struct file *file) { struct fsl_hifi4 *hifi4_priv; struct device *dev; - struct fsl_hifi4_engine *hifi4_engine; + struct xf_proxy *proxy; + struct xf_client *client; - hifi4_priv = dev_get_drvdata(hifi4_miscdev.parent); - mutex_lock(&hifi4_priv->hifi4_mutex); + /* ...basic sanity checks */ + client = xf_get_client(file); + if (IS_ERR(client)) + return PTR_ERR(client); + pr_info("client-%x released\n", client->id); + + proxy = client->proxy; + if (proxy) { + /* ...release all pending messages */ + xf_msg_free_all(proxy, &client->queue); + + /* ...recycle client id and release memory */ + xf_client_free(client); + } + + hifi4_priv = (struct fsl_hifi4 *)client->global; dev = hifi4_priv->dev; - hifi4_engine = file->private_data; - devm_kfree(dev, hifi4_engine); + pm_runtime_put_sync(dev); + mutex_lock(&hifi4_priv->hifi4_mutex); /* decrease reference counter when closing device */ atomic_long_dec(&hifi4_priv->refcnt); /* If device is free, reinitialize the resource of @@ -1689,11 +426,123 @@ static int fsl_hifi4_close(struct inode *inode, struct file *file) resource_release(hifi4_priv); mutex_unlock(&hifi4_priv->hifi4_mutex); - pm_runtime_put_sync(dev); return 0; } +/* ...wait until data is available in the response queue */ +static unsigned int fsl_hifi4_poll(struct file *file, poll_table *wait) +{ + struct xf_proxy *proxy; + struct xf_client *client; + int mask; + + /* ...basic sanity checks */ + client = xf_get_client(file); + if (IS_ERR(client)) + return PTR_ERR(client); + + /* ...get proxy interface */ + proxy = client->proxy; + if (!proxy) + return -EPERM; + + /* ...register client waiting queue */ + poll_wait(file, &client->wait, wait); + + /* ...return current queue state */ + mask = (xf_msg_queue_head(&client->queue) ? POLLIN | POLLRDNORM : 0); + + return mask; +} + +/******************************************************************************* + * Low-level mmap interface + ******************************************************************************/ + +/* ...add reference to shared buffer */ +static void hifi4_mmap_open(struct vm_area_struct *vma) +{ + struct xf_client *client = vma->vm_private_data; + + /* ...probably just increase counter of open references? - tbd */ + atomic_inc(&client->vm_use); + + pr_debug("xf_mmap_open: vma = %p, client = %p", vma, client); +} + +/* ...close reference to shared buffer */ +static void hifi4_mmap_close(struct vm_area_struct *vma) +{ + struct xf_client *client = vma->vm_private_data; + + pr_debug("xf_mmap_close: vma = %p, b = %p", vma, client); + + /* ...decrement number of mapping */ + atomic_dec_return(&client->vm_use); +} + +/* ...memory map operations */ +static const struct vm_operations_struct hifi4_mmap_ops = { + .open = hifi4_mmap_open, + .close = hifi4_mmap_close, +}; + +/* ...shared memory mapping */ +static int fsl_hifi4_mmap(struct file *file, struct vm_area_struct *vma) +{ + struct xf_proxy *proxy; + struct xf_client *client; + unsigned long size; + unsigned long pfn; + int r; + struct fsl_hifi4 *hifi4_priv; + + /* ...basic sanity checks */ + client = xf_get_client(file); + if (IS_ERR(client)) + return PTR_ERR(client); + + /* ...get proxy interface */ + proxy = client->proxy; + if (!proxy) + return -EPERM; + + /* ...check it was not mapped already */ + if (client->vm_start != 0) + return -EBUSY; + + /* ...check mapping flags (tbd) */ + if ((vma->vm_flags & (VM_READ | VM_WRITE | VM_SHARED)) + != (VM_READ | VM_WRITE | VM_SHARED)) + return -EPERM; + + /* ...set memory map operations */ + vma->vm_ops = &hifi4_mmap_ops; + + /* ...assign private data */ + client->vm_start = vma->vm_start; + + /* ...set private memory data */ + vma->vm_private_data = client; + + /* ...set page number of shared memory */ + hifi4_priv = (struct fsl_hifi4 *)client->global; + pfn = hifi4_priv->scratch_buf_phys >> PAGE_SHIFT; + size = hifi4_priv->scratch_buf_size; + + /* ...remap shared memory to user-space */ + vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); + r = remap_pfn_range(vma, vma->vm_start, pfn, size, vma->vm_page_prot); + if (r != 0) { + pr_err("mapping failed: %d", r); + return r; + } + + /* ...system-specific hook for registering shared memory mapping */ + return 0; +} + void *memset_hifi(void *dest, int c, size_t count) { uint *dl = (uint *)dest; @@ -1761,278 +610,6 @@ void *memcpy_hifi(void *dest, const void *src, size_t count) return dest; } -u32 icm_intr_send(struct fsl_hifi4 *hifi4_priv, u32 msg) -{ - MU_SendMessage(hifi4_priv->mu_base_virtaddr, 0, msg); - return 0; -} - -u32 icm_intr_extended_send(struct fsl_hifi4 *hifi4_priv, u32 msg, - struct hifi4_ext_msg *ext_msg) -{ - struct device *dev = hifi4_priv->dev; - union icm_header_t lmsg; - - lmsg.allbits = msg; - if (lmsg.size != 8) - dev_err(dev, "too much ext msg\n"); - - MU_SendMessage(hifi4_priv->mu_base_virtaddr, 1, ext_msg->phys); - MU_SendMessage(hifi4_priv->mu_base_virtaddr, 2, ext_msg->size); - MU_SendMessage(hifi4_priv->mu_base_virtaddr, 0, msg); - - return 0; -} - -long icm_ack_wait(struct fsl_hifi4 *hifi4_priv, u32 msg) -{ - struct device *dev = hifi4_priv->dev; - union icm_header_t ref_msg; - int err; - - ref_msg.allbits = msg; - /* wait response from mu */ - err = wait_for_completion_timeout(&hifi4_priv->cmd_complete, - msecs_to_jiffies(1000)); - if (!err) { - dev_err(dev, "icm ack timeout! %x\n", msg); - return -ETIMEDOUT; - } - - dev_dbg(dev, "Ack recd for message 0x%08x\n", ref_msg.allbits); - - return 0; -} - -int process_act_complete(struct fsl_hifi4 *hifi4_priv, u32 msg) -{ - union icm_header_t recd_msg; - u32 ext_msg_addr; - u32 ext_msg_size = 0; - u32 *pmsg_apu = (u32 *) hifi4_priv->msg_buf_virt + 2048/4; - struct icm_cdc_iobuf_t *codec_iobuf_info = - &hifi4_priv->codec_iobuf_info; - struct icm_pcm_prop_t *pcm_prop_info = &hifi4_priv->pcm_prop_info; - struct icm_pilib_size_t *pilib_buffer_info = - &hifi4_priv->pilib_buffer_info; - int ret_val = 0; - - recd_msg.allbits = msg; - - if (recd_msg.size == 8) { - MU_ReceiveMsg(hifi4_priv->mu_base_virtaddr, 1, &ext_msg_addr); - MU_ReceiveMsg(hifi4_priv->mu_base_virtaddr, 2, &ext_msg_size); - } - - switch (recd_msg.sub_msg) { - case ICM_PI_LIB_MEM_ALLOC: - { - struct icm_pilib_size_t *pext_msg = - (struct icm_pilib_size_t *)pmsg_apu; - pilib_buffer_info->buffer_addr = pext_msg->buffer_addr; - pilib_buffer_info->buffer_size = pext_msg->buffer_size; - hifi4_priv->ret_status = pext_msg->ret; - hifi4_priv->is_done = 1; - complete(&hifi4_priv->cmd_complete); - } - break; - - case ICM_PI_LIB_MEM_FREE: - { - struct icm_pilib_size_t *pext_msg = - (struct icm_pilib_size_t *)pmsg_apu; - hifi4_priv->ret_status = pext_msg->ret; - hifi4_priv->is_done = 1; - complete(&hifi4_priv->cmd_complete); - } - break; - - case ICM_OPEN: - { - struct icm_base_info_t *ext_msg = - (struct icm_base_info_t *)pmsg_apu; - hifi4_priv->ret_status = ext_msg->ret; - hifi4_priv->is_done = 1; - complete(&hifi4_priv->cmd_complete); - } - break; - - case ICM_EMPTY_THIS_BUFFER: - { - struct icm_cdc_iobuf_t *ext_msg = - (struct icm_cdc_iobuf_t *)pmsg_apu; - codec_iobuf_info->inp_cur_offset = - ext_msg->inp_cur_offset; - codec_iobuf_info->out_cur_offset = - ext_msg->out_cur_offset; - hifi4_priv->ret_status = ext_msg->base_info.ret; - hifi4_priv->is_done = 1; - complete(&hifi4_priv->cmd_complete); - } - break; - - case ICM_GET_PCM_PROP: - { - struct icm_pcm_prop_t *ext_msg = - (struct icm_pcm_prop_t *)pmsg_apu; - pcm_prop_info->pcmbytes = ext_msg->pcmbytes; - pcm_prop_info->sfreq = ext_msg->sfreq; - pcm_prop_info->channels = ext_msg->channels; - pcm_prop_info->bits = ext_msg->bits; - pcm_prop_info->consumed_bytes = - ext_msg->consumed_bytes; - hifi4_priv->ret_status = ext_msg->base_info.ret; - - hifi4_priv->is_done = 1; - complete(&hifi4_priv->cmd_complete); - } - break; - - case ICM_SET_PARA_CONFIG: - { - struct icm_prop_config *ext_msg = - (struct icm_prop_config *)pmsg_apu; - hifi4_priv->ret_status = ext_msg->base_info.ret; - hifi4_priv->is_done = 1; - complete(&hifi4_priv->cmd_complete); - } - break; - - case ICM_PI_LIB_INIT: - { - struct icm_base_info_t *ext_msg = - (struct icm_base_info_t *)pmsg_apu; - hifi4_priv->ret_status = ext_msg->ret; - hifi4_priv->is_done = 1; - complete(&hifi4_priv->cmd_complete); - } - break; - - case ICM_CLOSE: - { - struct icm_base_info_t *ext_msg = - (struct icm_base_info_t *)pmsg_apu; - hifi4_priv->ret_status = ext_msg->ret; - hifi4_priv->is_done = 1; - complete(&hifi4_priv->cmd_complete); - } - break; - - case ICM_PI_LIB_LOAD: - { - struct icm_base_info_t *ext_msg = - (struct icm_base_info_t *)pmsg_apu; - hifi4_priv->ret_status = ext_msg->ret; - hifi4_priv->is_done = 1; - complete(&hifi4_priv->cmd_complete); - } - break; - - case ICM_RESET: - { - struct icm_base_info_t *ext_msg = - (struct icm_base_info_t *)pmsg_apu; - hifi4_priv->ret_status = ext_msg->ret; - hifi4_priv->is_done = 1; - complete(&hifi4_priv->cmd_complete); - } - break; - case ICM_CORE_EXIT: - hifi4_priv->is_done = 1; - complete(&hifi4_priv->cmd_complete); - break; - case ICM_SUSPEND: - hifi4_priv->is_done = 1; - complete(&hifi4_priv->cmd_complete); - break; - case ICM_RESUME: - hifi4_priv->is_done = 1; - complete(&hifi4_priv->cmd_complete); - break; - default: - ret_val = -1; - break; - } - return ret_val; -} - -int send_dpu_ext_msg_addr(struct fsl_hifi4 *hifi4_priv) -{ - union icm_header_t apu_icm; - struct hifi4_ext_msg ext_msg; - struct hifi4_mem_msg *dpu_ext_msg = - (struct hifi4_mem_msg *)hifi4_priv->msg_buf_virt; - int ret_val = 0; - - apu_icm.allbits = 0; /* clear all bits; */ - apu_icm.ack = 0; - apu_icm.intr = 1; - apu_icm.msg = ICM_EXT_MSG_ADDR; - apu_icm.size = 8; - ext_msg.phys = hifi4_priv->msg_buf_phys; - /* 6 means element numbers that need to be transferred - * in struct hifi4_mem_msg - */ - ext_msg.size = 6*4; /* 6 * sizeof(int) */ - dpu_ext_msg->ext_msg_phys = hifi4_priv->msg_buf_phys + 2048; - dpu_ext_msg->ext_msg_size = 2048; - dpu_ext_msg->scratch_phys = hifi4_priv->scratch_buf_phys; - dpu_ext_msg->scratch_size = hifi4_priv->scratch_buf_size; - dpu_ext_msg->hifi_config_phys = hifi4_priv->hifi_config_phys; - dpu_ext_msg->hifi_config_size = hifi4_priv->hifi_config_size; - - icm_intr_extended_send(hifi4_priv, apu_icm.allbits, &ext_msg); - - return ret_val; -} - -static irqreturn_t fsl_hifi4_mu_isr(int irq, void *dev_id) -{ - struct fsl_hifi4 *hifi4_priv = dev_id; - struct device *dev = hifi4_priv->dev; - union icm_header_t recd_msg; - int ret_val; - u32 reg; - - MU_ReceiveMsg(hifi4_priv->mu_base_virtaddr, 0, ®); - recd_msg = (union icm_header_t)reg; - if (recd_msg.intr == 1) { - dev_dbg(dev, "INTR: Received ICM intr, msg 0x%08x\n", - recd_msg.allbits); - switch (recd_msg.msg) { - case ICM_CORE_EXIT: - break; - case ICM_CORE_READY: - send_dpu_ext_msg_addr(hifi4_priv); - hifi4_priv->is_ready = 1; - complete(&hifi4_priv->cmd_complete); - break; - case ICM_EXT_MSG_ADDR: - break; - - case ICM_EMPTY_THIS_BUFFER: - case ICM_CLOSE: - break; - - case ICM_DPU_ACTION_COMPLETE: - ret_val = process_act_complete(hifi4_priv, - recd_msg.allbits); - break; - - default: - break; - } - } else if (recd_msg.ack == 1) { - dev_dbg(dev, "INTR: Received ICM ack 0x%08x\n", recd_msg.size); - recd_msg.ack = 0; - } else { - dev_dbg(dev, "Received false ICM intr 0x%08x\n", - recd_msg.allbits); - } - - return IRQ_HANDLED; -} - static void hifi4_load_firmware(const struct firmware *fw, void *context) { struct fsl_hifi4 *hifi4_priv = context; @@ -2141,7 +718,7 @@ int hifi4_mu_init(struct fsl_hifi4 *hifi4_priv) irq = of_irq_get(np, 0); ret = devm_request_irq(hifi4_priv->dev, irq, fsl_hifi4_mu_isr, - IRQF_EARLY_RESUME, "hifi4_mu_isr", hifi4_priv); + IRQF_EARLY_RESUME, "hifi4_mu_isr", &hifi4_priv->proxy); if (ret) { dev_err(dev, "request_irq failed %d, err = %d\n", irq, ret); return -EINVAL; @@ -2160,9 +737,11 @@ static const struct file_operations hifi4_fops = { .owner = THIS_MODULE, .unlocked_ioctl = fsl_hifi4_ioctl, #ifdef CONFIG_COMPAT - .compat_ioctl = fsl_hifi4_compat_ioctl, + .compat_ioctl = fsl_hifi4_ioctl, #endif .open = fsl_hifi4_open, + .poll = fsl_hifi4_poll, + .mmap = fsl_hifi4_mmap, .release = fsl_hifi4_close, }; @@ -2267,34 +846,39 @@ static int fsl_hifi4_probe(struct platform_device *pdev) return -ENOMEM; } - /* msg buffer */ + /* msg ring buffer memory */ hifi4_priv->msg_buf_virt = buf_virt; hifi4_priv->msg_buf_phys = buf_phys; hifi4_priv->msg_buf_size = MSG_BUF_SIZE; offset = MSG_BUF_SIZE; + /* keep dsp framework's global data when suspend/resume */ hifi4_priv->hifi_config_virt = buf_virt + offset; hifi4_priv->hifi_config_phys = buf_phys + offset; hifi4_priv->hifi_config_size = HIFI_CONFIG_SIZE; + /* scratch memory for dsp framework */ hifi4_priv->scratch_buf_virt = hifi4_priv->sdram_vir_addr + SDRAM_CODEC_LIB_OFFSET; hifi4_priv->scratch_buf_phys = hifi4_priv->sdram_phys_addr + SDRAM_CODEC_LIB_OFFSET; hifi4_priv->scratch_buf_size = SDRAM_BASE_SIZE - SDRAM_CODEC_LIB_OFFSET; - /* initialize the resources of multi codec - * MULTI_CODEC_NUM is the max codec number that dsp - * driver and framework can support. - */ - for (i = 0; i < MULTI_CODEC_NUM; i++) - memset(&hifi4_priv->process_info[i], 0, - sizeof(struct icm_process_info)); - /* initialize the reference counter for hifi4_priv * structure */ atomic_long_set(&hifi4_priv->refcnt, 0); + + /* ...initialize client association map */ + for (i = 0; i < XF_CFG_MAX_IPC_CLIENTS - 1; i++) + hifi4_priv->xf_client_map[i].next = i + 1; + /* ...set list terminator */ + hifi4_priv->xf_client_map[i].next = 0; + + /* ...set pointer to shared memory */ + xf_proxy_init(&hifi4_priv->proxy); + + /* ...initialize mutex */ mutex_init(&hifi4_priv->hifi4_mutex); return 0; @@ -2320,6 +904,7 @@ static int fsl_hifi4_remove(struct platform_device *pdev) static int fsl_hifi4_runtime_resume(struct device *dev) { struct fsl_hifi4 *hifi4_priv = dev_get_drvdata(dev); + struct xf_proxy *proxy = &hifi4_priv->proxy; int ret; if (sc_pm_set_resource_power_mode(hifi4_priv->hifi_ipcHandle, @@ -2328,10 +913,8 @@ static int fsl_hifi4_runtime_resume(struct device *dev) return -EIO; } - mutex_lock(&hifi4_priv->hifi4_mutex); - - if (!hifi4_priv->is_ready) { - init_completion(&hifi4_priv->cmd_complete); + if (!proxy->is_ready) { + init_completion(&proxy->cmd_complete); ret = request_firmware_nowait(THIS_MODULE, FW_ACTION_HOTPLUG, hifi4_priv->fw_name, @@ -2340,33 +923,30 @@ static int fsl_hifi4_runtime_resume(struct device *dev) if (ret) { dev_err(dev, "failed to load firmware\n"); - mutex_unlock(&hifi4_priv->hifi4_mutex); return ret; } - ret = icm_ack_wait(hifi4_priv, 0); + ret = icm_ack_wait(proxy, 0); if (ret) { - mutex_unlock(&hifi4_priv->hifi4_mutex); return ret; } dev_info(dev, "hifi driver registered\n"); } - mutex_unlock(&hifi4_priv->hifi4_mutex); - return 0; } static int fsl_hifi4_runtime_suspend(struct device *dev) { struct fsl_hifi4 *hifi4_priv = dev_get_drvdata(dev); + struct xf_proxy *proxy = &hifi4_priv->proxy; if (sc_pm_set_resource_power_mode(hifi4_priv->hifi_ipcHandle, SC_R_DSP_RAM, SC_PM_PW_MODE_OFF) != SC_ERR_NONE) { dev_err(dev, "Error power off HIFI RAM\n"); return -EIO; } - hifi4_priv->is_ready = 0; + proxy->is_ready = 0; return 0; } #endif /* CONFIG_PM */ @@ -2375,33 +955,8 @@ static int fsl_hifi4_runtime_suspend(struct device *dev) #ifdef CONFIG_PM_SLEEP static int fsl_hifi4_suspend(struct device *dev) { - union icm_header_t apu_icm; - struct fsl_hifi4 *hifi4_priv = dev_get_drvdata(dev); int ret = 0; - mutex_lock(&hifi4_priv->hifi4_mutex); - - if (hifi4_priv->is_ready) { - init_completion(&hifi4_priv->cmd_complete); - hifi4_priv->is_done = 0; - - apu_icm.allbits = 0; /* clear all bits;*/ - apu_icm.ack = 0; - apu_icm.intr = 1; - apu_icm.msg = ICM_SUSPEND; - apu_icm.size = 0; - icm_intr_send(hifi4_priv, apu_icm.allbits); - - /* wait for response here */ - ret = icm_ack_wait(hifi4_priv, apu_icm.allbits); - if (ret) { - mutex_unlock(&hifi4_priv->hifi4_mutex); - return ret; - } - } - - mutex_unlock(&hifi4_priv->hifi4_mutex); - ret = pm_runtime_force_suspend(dev); return ret; @@ -2409,36 +964,12 @@ static int fsl_hifi4_suspend(struct device *dev) static int fsl_hifi4_resume(struct device *dev) { - union icm_header_t apu_icm; - struct fsl_hifi4 *hifi4_priv = dev_get_drvdata(dev); int ret = 0; ret = pm_runtime_force_resume(dev); if (ret) return ret; - mutex_lock(&hifi4_priv->hifi4_mutex); - - if (hifi4_priv->is_ready) { - init_completion(&hifi4_priv->cmd_complete); - hifi4_priv->is_done = 0; - - apu_icm.allbits = 0; /* clear all bits;*/ - apu_icm.ack = 0; - apu_icm.intr = 1; - apu_icm.msg = ICM_RESUME; - apu_icm.size = 0; - icm_intr_send(hifi4_priv, apu_icm.allbits); - - /* wait for response here */ - ret = icm_ack_wait(hifi4_priv, apu_icm.allbits); - if (ret) { - mutex_unlock(&hifi4_priv->hifi4_mutex); - return ret; - } - } - mutex_unlock(&hifi4_priv->hifi4_mutex); - return 0; } #endif /* CONFIG_PM_SLEEP */ diff --git a/sound/soc/fsl/fsl_hifi4.h b/sound/soc/fsl/fsl_hifi4.h index 43b98592e1c0..61592d1657d8 100644 --- a/sound/soc/fsl/fsl_hifi4.h +++ b/sound/soc/fsl/fsl_hifi4.h @@ -9,197 +9,46 @@ */ #include +#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 +/* ...maximal number of IPC clients per proxy */ +#define XF_CFG_MAX_IPC_CLIENTS (1 << 4) -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 + +/* ...proxy client data */ +struct xf_client { + /* ...pointer to proxy interface */ + struct xf_proxy *proxy; + + /* ...allocated proxy client id */ + u32 id; + + /* ...pending response queue */ + struct xf_msg_queue queue; + + /* ...response waiting queue */ + wait_queue_head_t wait; + + /* ...virtual memory mapping */ + unsigned long vm_start; + + /* ...counter of memory mappings (no real use of it yet - tbd) */ + atomic_t vm_use; + + /* ...global structure pointer */ + void *global; }; -struct xtlib_loader_globals { - int err; - int byteswap; -}; +union xf_client_link { + /* ...index of next client in free list */ + u32 next; -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, - - ICM_DPU_ACTION_COMPLETE, - ICM_APU_ACTION_COMPLETE, - - ICM_OPEN, - ICM_EMPTY_THIS_BUFFER, - ICM_FILL_THIS_BUFFER, - ICM_PAUSE, - ICM_CLOSE, - - ICM_GET_PCM_PROP, - ICM_SET_PARA_CONFIG, - - ICM_CORE_EXIT, - ICM_EXT_MSG_ADDR, - - ICM_RESET, - ICM_SUSPEND, - ICM_RESUME, -}; - -enum aud_status_t { - AUD_IDLE = 0, - AUD_STOPPED, - AUD_DECODING, - AUD_PAUSED -}; - -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. */ -}; - -struct icm_pilib_size_t { - u32 buffer_addr; - u32 buffer_size; - s32 ret; -}; - -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; - - 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 +#include "fsl_hifi4_proxy.h" +#include "fsl_hifi4.h" + + +/* ...initialize message queue */ +void xf_msg_queue_init(struct xf_msg_queue *queue) +{ + queue->head = queue->tail = NULL; +} + +/* ...get message queue head */ +struct xf_message *xf_msg_queue_head(struct xf_msg_queue *queue) +{ + return queue->head; +} + +/* ...allocate new message from the pool */ +struct xf_message *xf_msg_alloc(struct xf_proxy *proxy) +{ + struct xf_message *m = proxy->free; + + /* ...make sure we have a free message item */ + if (m != NULL) { + /* ...get message from the pool */ + proxy->free = m->next, m->next = NULL; + } + + return m; +} + +/* ...return message to the pool of free items */ +void xf_msg_free(struct xf_proxy *proxy, struct xf_message *m) +{ + /* ...put message into the head of free items list */ + m->next = proxy->free, proxy->free = m; + + /* ...notify potential client waiting for message */ + wake_up(&proxy->busy); +} + +/* ...return all messages from the queue to the pool of free items */ +void xf_msg_free_all(struct xf_proxy *proxy, struct xf_msg_queue *queue) +{ + struct xf_message *m = queue->head; + + /* ...check if there is anything in the queue */ + if (m != NULL) { + queue->tail->next = proxy->free; + proxy->free = queue->head; + queue->head = queue->tail = NULL; + + /* ...notify potential client waiting for message */ + wake_up(&proxy->busy); + } +} + +/* ...submit message to a queue */ +int xf_msg_enqueue(struct xf_msg_queue *queue, struct xf_message *m) +{ + int first = (queue->head == NULL); + + /* ...set pointer to next item */ + m->next = NULL; + + /* ...advance head/tail pointer as required */ + if (first) + queue->head = m; + else + queue->tail->next = m; + + /* ...new tail points to this message */ + queue->tail = m; + + return first; +} + +/* ...retrieve next message from the per-task queue */ +struct xf_message *xf_msg_dequeue(struct xf_msg_queue *queue) +{ + struct xf_message *m = queue->head; + + /* ...check if there is anything in the queue */ + if (m != NULL) { + /* ...pop message from the head of the list */ + queue->head = m->next; + if (queue->head == NULL) + queue->tail = NULL; + } + + return m; +} + +/* ...helper function for requesting execution message from a pool */ +struct xf_message *xf_msg_available(struct xf_proxy *proxy) +{ + struct xf_message *m; + + /* ...acquire global lock */ + xf_lock(&proxy->lock); + + /* ...try to allocate the message */ + m = xf_msg_alloc(proxy); + if (m == NULL) { + /* ...failed to allocate message; release lock */ + xf_unlock(&proxy->lock); + } + + /* ...if successfully allocated */ + return m; +} + +/* ...helper function for receiving a message from per-client queue */ +struct xf_message *xf_msg_received(struct xf_proxy *proxy, + struct xf_msg_queue *queue) +{ + struct xf_message *m; + + /* ...try to peek message from the queue */ + m = xf_msg_dequeue(queue); + + /* ...if message is non-null, lock is held */ + return m; +} + +/* + * MU related functions + */ +u32 icm_intr_send(struct xf_proxy *proxy, u32 msg) +{ + struct fsl_hifi4 *hifi4_priv = container_of(proxy, + struct fsl_hifi4, proxy); + + MU_SendMessage(hifi4_priv->mu_base_virtaddr, 0, msg); + return 0; +} + +int icm_intr_extended_send(struct xf_proxy *proxy, + u32 msg, + struct hifi4_ext_msg *ext_msg) +{ + struct fsl_hifi4 *hifi4_priv = container_of(proxy, + struct fsl_hifi4, proxy); + struct device *dev = hifi4_priv->dev; + union icm_header_t msghdr; + + msghdr.allbits = msg; + if (msghdr.size != 8) + dev_err(dev, "too much ext msg\n"); + + MU_SendMessage(hifi4_priv->mu_base_virtaddr, 1, ext_msg->phys); + MU_SendMessage(hifi4_priv->mu_base_virtaddr, 2, ext_msg->size); + MU_SendMessage(hifi4_priv->mu_base_virtaddr, 0, msg); + + return 0; +} + +int send_dpu_ext_msg_addr(struct xf_proxy *proxy) +{ + struct fsl_hifi4 *hifi4_priv = container_of(proxy, + struct fsl_hifi4, proxy); + union icm_header_t msghdr; + struct hifi4_ext_msg ext_msg; + struct hifi4_mem_msg *dpu_ext_msg = + (struct hifi4_mem_msg *)((unsigned char *)hifi4_priv->msg_buf_virt + + (MSG_BUF_SIZE / 2)); + int ret_val = 0; + + msghdr.allbits = 0; /* clear all bits; */ + msghdr.ack = 0; + msghdr.intr = 1; + msghdr.msg = ICM_CORE_INIT; + msghdr.size = 8; + ext_msg.phys = hifi4_priv->msg_buf_phys + (MSG_BUF_SIZE / 2); + ext_msg.size = sizeof(struct hifi4_mem_msg); + + dpu_ext_msg->ext_msg_phys = hifi4_priv->msg_buf_phys; + dpu_ext_msg->ext_msg_size = MSG_BUF_SIZE; + dpu_ext_msg->scratch_phys = hifi4_priv->scratch_buf_phys; + dpu_ext_msg->scratch_size = hifi4_priv->scratch_buf_size; + dpu_ext_msg->hifi_config_phys = hifi4_priv->hifi_config_phys; + dpu_ext_msg->hifi_config_size = hifi4_priv->hifi_config_size; + + icm_intr_extended_send(proxy, msghdr.allbits, &ext_msg); + + return ret_val; +} + +long icm_ack_wait(struct xf_proxy *proxy, u32 msg) +{ + struct fsl_hifi4 *hifi4_priv = container_of(proxy, + struct fsl_hifi4, proxy); + struct device *dev = hifi4_priv->dev; + union icm_header_t msghdr; + int err; + + msghdr.allbits = msg; + /* wait response from mu */ + err = wait_for_completion_timeout(&proxy->cmd_complete, + msecs_to_jiffies(1000)); + if (!err) { + dev_err(dev, "icm ack timeout! %x\n", msg); + return -ETIMEDOUT; + } + + dev_dbg(dev, "Ack recd for message 0x%08x\n", msghdr.allbits); + + return 0; +} + +irqreturn_t fsl_hifi4_mu_isr(int irq, void *dev_id) +{ + struct xf_proxy *proxy = dev_id; + struct fsl_hifi4 *hifi4_priv = container_of(proxy, + struct fsl_hifi4, proxy); + struct device *dev = hifi4_priv->dev; + union icm_header_t msghdr; + u32 reg; + + MU_ReceiveMsg(hifi4_priv->mu_base_virtaddr, 0, ®); + msghdr = (union icm_header_t)reg; + + if (msghdr.intr == 1) { + dev_dbg(dev, "INTR: Received ICM intr, msg 0x%08x\n", + msghdr.allbits); + switch (msghdr.msg) { + case ICM_CORE_EXIT: + break; + case ICM_CORE_READY: + send_dpu_ext_msg_addr(proxy); + proxy->is_ready = 1; + complete(&proxy->cmd_complete); + break; + default: + schedule_work(&proxy->work); + break; + } + } else if (msghdr.ack == 1) { + dev_dbg(dev, "INTR: Received ICM ack 0x%08x\n", msghdr.size); + msghdr.ack = 0; + } else { + dev_dbg(dev, "Received false ICM intr 0x%08x\n", + msghdr.allbits); + } + + return IRQ_HANDLED; +} + +/* + * Proxy related functions + */ +/* ...NULL-address specification */ +#define XF_PROXY_NULL (~0U) + +#define XF_PROXY_BADADDR SDRAM_SCRATCH_BUF_SIZE + +/* ...shared memory translation - kernel virtual address to shared address */ +u32 xf_proxy_b2a(struct xf_proxy *proxy, void *b) +{ + struct fsl_hifi4 *hifi4_priv = container_of(proxy, + struct fsl_hifi4, proxy); + + if (b == NULL) + return XF_PROXY_NULL; + else if ((u32)(b - hifi4_priv->scratch_buf_virt) < + SDRAM_SCRATCH_BUF_SIZE) + return (u32)(b - hifi4_priv->scratch_buf_virt); + else + return XF_PROXY_BADADDR; +} + +/* ...shared memory translation - shared address to kernel virtual address */ +void *xf_proxy_a2b(struct xf_proxy *proxy, u32 address) +{ + struct fsl_hifi4 *hifi4_priv = container_of(proxy, + struct fsl_hifi4, proxy); + + if (address < SDRAM_SCRATCH_BUF_SIZE) + return hifi4_priv->scratch_buf_virt + address; + else if (address == XF_PROXY_NULL) + return NULL; + else + return (void *) -1; +} + +/* ...process association between response received and intended client */ +static void xf_cmap(struct xf_proxy *proxy, struct xf_message *m) +{ + struct fsl_hifi4 *hifi4_priv = container_of(proxy, + struct fsl_hifi4, proxy); + u32 id = XF_AP_IPC_CLIENT(m->id); + struct xf_client *client; + + /* ...process messages addressed to proxy itself */ + if (id == 0) { + /* ...place message into local response queue */ + xf_msg_enqueue(&proxy->response, m); + wake_up(&proxy->wait); + return; + } + + /* ...make sure the client ID is sane */ + client = xf_client_lookup(hifi4_priv, id); + if (!client) { + pr_err("rsp[id:%08x]: client lookup failed", m->id); + xf_msg_free(proxy, m); + return; + } + + /* ...make sure client is bound to this proxy interface */ + if (client->proxy != proxy) { + pr_err("rsp[id:%08x]: wrong proxy interface", m->id); + xf_msg_free(proxy, m); + return; + } + + /* ...place message into local response queue */ + if (xf_msg_enqueue(&client->queue, m)) + wake_up(&client->wait); +} + +/* ...retrieve pending responses from shared memory ring-buffer */ +static u32 xf_shmem_process_responses(struct xf_proxy *proxy) +{ + struct xf_message *m; + u32 read_idx, write_idx; + int status; + + status = 0; + + /* ...get current values of read/write pointers in response queue */ + read_idx = XF_PROXY_READ(proxy, rsp_read_idx); + write_idx = XF_PROXY_READ(proxy, rsp_write_idx); + + /* ...process all committed responses */ + while (!XF_QUEUE_EMPTY(read_idx, write_idx)) { + struct xf_proxy_message *response; + + /* ...allocate execution message */ + m = xf_msg_alloc(proxy); + if (m == NULL) + break; + + /* ...mark the interface status has changed */ + status |= (XF_QUEUE_FULL(read_idx, write_idx) ? 0x3 : 0x1); + + /* ...get oldest not yet processed response */ + response = XF_PROXY_RESPONSE(proxy, XF_QUEUE_IDX(read_idx)); + + /* ...fill message parameters */ + m->id = response->session_id; + m->opcode = response->opcode; + m->length = response->length; + m->buffer = xf_proxy_a2b(proxy, response->address); + + /* ...advance local reading index copy */ + read_idx = XF_QUEUE_ADVANCE_IDX(read_idx); + + /* ...update shadow copy of reading index */ + XF_PROXY_WRITE(proxy, rsp_read_idx, read_idx); + + /* ...submit message to proper client */ + xf_cmap(proxy, m); + } + + return status; +} + +/* ...put pending commands into shared memory ring-buffer */ +static u32 xf_shmem_process_commands(struct xf_proxy *proxy) +{ + struct xf_message *m; + u32 read_idx, write_idx; + int status = 0; + + /* ...get current value of peer read pointer */ + write_idx = XF_PROXY_READ(proxy, cmd_write_idx); + read_idx = XF_PROXY_READ(proxy, cmd_read_idx); + + /* ...submit any pending commands */ + while (!XF_QUEUE_FULL(read_idx, write_idx)) { + struct xf_proxy_message *command; + + /* ...check if we have a pending command */ + m = xf_msg_dequeue(&proxy->command); + if (m == NULL) + break; + + /* ...always mark the interface status has changed */ + status |= 0x3; + + /* ...select the place for the command */ + command = XF_PROXY_COMMAND(proxy, XF_QUEUE_IDX(write_idx)); + + /* ...put the response message fields */ + command->session_id = m->id; + command->opcode = m->opcode; + command->length = m->length; + command->address = xf_proxy_b2a(proxy, m->buffer); + + /* ...return message back to the pool */ + xf_msg_free(proxy, m); + + /* ...advance local writing index copy */ + write_idx = XF_QUEUE_ADVANCE_IDX(write_idx); + + /* ...update shared copy of queue write pointer */ + XF_PROXY_WRITE(proxy, cmd_write_idx, write_idx); + } + + return status; +} + +/* ...shared memory interface maintenance routine */ +void xf_proxy_process(struct work_struct *w) +{ + struct xf_proxy *proxy = container_of(w, struct xf_proxy, work); + int status = 0; + + /* ...get exclusive access to internal data */ + xf_lock(&proxy->lock); + + do { + /* ...process outgoing commands first */ + status = xf_shmem_process_commands(proxy); + + /* ...process all pending responses */ + status |= xf_shmem_process_responses(proxy); + + } while (status); + + /* ...unlock internal proxy data */ + xf_unlock(&proxy->lock); +} + +/* ...initialize shared memory interface */ +int xf_proxy_init(struct xf_proxy *proxy) +{ + struct fsl_hifi4 *hifi4_priv = container_of(proxy, + struct fsl_hifi4, proxy); + struct xf_message *m; + int i; + + /* ...create a list of all messages in a pool; set head pointer */ + proxy->free = &proxy->pool[0]; + + /* ...put all messages into a single-linked list */ + for (i = 0, m = proxy->free; i < XF_CFG_MESSAGE_POOL_SIZE - 1; i++, m++) + m->next = m + 1; + + /* ...set list tail pointer */ + m->next = NULL; + + /* ...initialize proxy lock */ + xf_lock_init(&proxy->lock); + + /* ...initialize proxy thread message queues */ + xf_msg_queue_init(&proxy->command); + xf_msg_queue_init(&proxy->response); + + /* ...initialize global busy queue */ + init_waitqueue_head(&proxy->busy); + init_waitqueue_head(&proxy->wait); + + /* ...create work structure */ + INIT_WORK(&proxy->work, xf_proxy_process); + + /* ...set pointer to shared memory */ + proxy->ipc.shmem = (struct xf_shmem_data *)hifi4_priv->msg_buf_virt; + + /* ...initialize shared memory interface */ + XF_PROXY_WRITE(proxy, cmd_read_idx, 0); + XF_PROXY_WRITE(proxy, cmd_write_idx, 0); + XF_PROXY_WRITE(proxy, rsp_read_idx, 0); + XF_PROXY_WRITE(proxy, rsp_write_idx, 0); + + return 0; +} + +/* ...trigger shared memory interface processing */ +void xf_proxy_notify(struct xf_proxy *proxy) +{ + schedule_work(&proxy->work); +} + +/* ...submit a command to proxy pending queue (lock released upon return) */ +void xf_proxy_command(struct xf_proxy *proxy, struct xf_message *m) +{ + int first; + + /* ...submit message to proxy thread */ + first = xf_msg_enqueue(&proxy->command, m); + + /* ...release the lock */ + xf_unlock(&proxy->lock); + + /* ...notify thread about command reception */ + (first ? xf_proxy_notify(proxy), 1 : 0); +} + +/* + * Proxy cmd send and receive functions + */ +int xf_cmd_send(struct xf_proxy *proxy, + u32 id, + u32 opcode, + void *buffer, + u32 length) +{ + struct xf_message *m; + int ret; + + /* ...retrieve message handle (take the lock on success) */ + ret = wait_event_interruptible(proxy->busy, + (m = xf_msg_available(proxy)) != NULL); + if (ret) + return -EINTR; + + /* ...fill-in message parameters (lock is taken) */ + m->id = id; + m->opcode = opcode; + m->length = length; + m->buffer = buffer; + m->ret = 0; + + /* ...submit command to the proxy */ + xf_proxy_command(proxy, m); + + return 0; +} + +struct xf_message *xf_cmd_recv(struct xf_proxy *proxy, + wait_queue_head_t *wq, + struct xf_msg_queue *queue, + int wait) +{ + struct xf_message *m; + int ret; + + /* ...wait for message reception (take lock on success) */ + ret = wait_event_interruptible(*wq, + (m = xf_msg_received(proxy, queue)) != NULL || !wait); + if (ret) + return ERR_PTR(-EINTR); + + /* ...return message with a lock taken */ + return m; +} + +/* ...helper function for synchronous command execution */ +struct xf_message *xf_cmd_send_recv(struct xf_proxy *proxy, + u32 id, u32 opcode, + void *buffer, + u32 length) +{ + int ret; + + /* ...send command to remote proxy */ + ret = xf_cmd_send(proxy, id, opcode, buffer, length); + if (ret) + return ERR_PTR(ret); + + /* ...wait for message delivery */ + return xf_cmd_recv(proxy, &proxy->wait, &proxy->response, 1); +} + +/* + * Proxy allocate and free memory functions + */ +/* ...allocate memory buffer for kernel use */ +int xf_cmd_alloc(struct xf_proxy *proxy, void **buffer, u32 length) +{ + struct xf_message *m; + u32 id = 0; + int ret; + + /* ...send command to remote proxy */ + m = xf_cmd_send_recv(proxy, id, XF_ALLOC, NULL, length); + if (IS_ERR(m)) { + ret = PTR_ERR(m); + return ret; + } + + /* ...check if response is expected */ + if (m->opcode == XF_ALLOC && m->buffer != NULL) { + *buffer = m->buffer; + ret = 0; + } else { + ret = -ENOMEM; + } + + /* ...free message and release proxy lock */ + xf_msg_free(proxy, m); + + return ret; +} + +/* ...free memory buffer */ +int xf_cmd_free(struct xf_proxy *proxy, void *buffer, u32 length) +{ + struct xf_message *m; + u32 id = 0; + int ret; + + /* ...synchronously execute freeing command */ + m = xf_cmd_send_recv(proxy, id, XF_FREE, buffer, length); + if (IS_ERR(m)) { + ret = PTR_ERR(m); + return ret; + } + + /* ...check if response is expected */ + if (m->opcode == XF_FREE) + ret = 0; + else + ret = -EINVAL; + + /* ...free message and release proxy lock */ + xf_msg_free(proxy, m); + + return ret; +} diff --git a/sound/soc/fsl/fsl_hifi4_proxy.h b/sound/soc/fsl/fsl_hifi4_proxy.h new file mode 100644 index 000000000000..f89e974ab596 --- /dev/null +++ b/sound/soc/fsl/fsl_hifi4_proxy.h @@ -0,0 +1,381 @@ +/******************************************************************************* + * + * This file is licensed under the terms of the GNU General Public License + * version 2. This program is licensed "as is" without any warranty of any + * kind, whether express or implied. + * + * Copyright (c) 2017 Cadence Design Systems, Inc. + * Copyright 2018 NXP + * + ************************************************************/ +/************************************************************ + * fsl_hifi4_proxy.h + * + * Proxy commmand/response messages + ************************************************************/ + +#ifndef __FSL_HIFI4_PROXY_H +#define __FSL_HIFI4_PROXY_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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 From e45c12e9468ab8ea4e7226aa5a6dc5b5c4112fce Mon Sep 17 00:00:00 2001 From: Weiguang Kong Date: Tue, 13 Mar 2018 18:40:06 +0800 Subject: [PATCH 31/78] MLK-17635-2: ASoC: fsl_dsp: fix unhandled alignment fault in user space When using memcpy() or fread() function in dsp unit test or wrapper code, an unhandled alignment fault error will occur randomly, this issue is caused by the setting of mmap(). After using pgprot_writecombine() function instead of pgprot_noncached() function, this error will not occur. Signed-off-by: Weiguang Kong --- sound/soc/fsl/fsl_hifi4.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/fsl/fsl_hifi4.c b/sound/soc/fsl/fsl_hifi4.c index e4e826de6c69..a1e555865e36 100644 --- a/sound/soc/fsl/fsl_hifi4.c +++ b/sound/soc/fsl/fsl_hifi4.c @@ -532,7 +532,7 @@ static int fsl_hifi4_mmap(struct file *file, struct vm_area_struct *vma) size = hifi4_priv->scratch_buf_size; /* ...remap shared memory to user-space */ - vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); + vma->vm_page_prot = pgprot_writecombine(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); @@ -830,7 +830,7 @@ static int fsl_hifi4_probe(struct platform_device *pdev) } hifi4_priv->sdram_phys_addr = SDRAM_BASE_ADDR; - hifi4_priv->sdram_vir_addr = ioremap(hifi4_priv->sdram_phys_addr, + hifi4_priv->sdram_vir_addr = ioremap_wc(hifi4_priv->sdram_phys_addr, SDRAM_BASE_SIZE); if (!hifi4_priv->sdram_vir_addr) { dev_err(&pdev->dev, "failed to remap sdram space for hifi4 firmware\n"); From 19644166180066401291c7cc8235260fd0169155 Mon Sep 17 00:00:00 2001 From: Weiguang Kong Date: Wed, 4 Apr 2018 11:11:11 +0800 Subject: [PATCH 32/78] MLK-17635-3: ASoC: fsl_dsp: add suspend & resume support for new framework The architecture of dsp framework has been changed, so update dsp driver to support suspend & resume test of new dsp framework. Signed-off-by: Weiguang Kong --- sound/soc/fsl/fsl_hifi4.c | 25 +++++++++++--- sound/soc/fsl/fsl_hifi4_proxy.c | 61 +++++++++++++++++++++++++++++++++ sound/soc/fsl/fsl_hifi4_proxy.h | 31 ++++++++++++++--- 3 files changed, 109 insertions(+), 8 deletions(-) diff --git a/sound/soc/fsl/fsl_hifi4.c b/sound/soc/fsl/fsl_hifi4.c index a1e555865e36..7e9b12298892 100644 --- a/sound/soc/fsl/fsl_hifi4.c +++ b/sound/soc/fsl/fsl_hifi4.c @@ -243,6 +243,7 @@ static int fsl_dsp_ipc_msg_from_dsp(struct xf_client *client, /* ...return the message back to a pool and release lock */ xf_msg_free(&hifi4_priv->proxy, m); + xf_unlock(&hifi4_priv->proxy.lock); ret = copy_to_user(user, &msg, sizeof(struct xf_proxy_message)); if (ret) { @@ -384,8 +385,6 @@ static int fsl_hifi4_open(struct inode *inode, struct file *file) atomic_long_inc(&hifi4_priv->refcnt); mutex_unlock(&hifi4_priv->hifi4_mutex); - pr_info("client-%x created\n", client->id); - return ret; } @@ -401,8 +400,6 @@ static int fsl_hifi4_close(struct inode *inode, struct file *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 */ @@ -955,8 +952,18 @@ static int fsl_hifi4_runtime_suspend(struct device *dev) #ifdef CONFIG_PM_SLEEP static int fsl_hifi4_suspend(struct device *dev) { + struct fsl_hifi4 *hifi4_priv = dev_get_drvdata(dev); + struct xf_proxy *proxy = &hifi4_priv->proxy; int ret = 0; + if (proxy->is_ready) { + ret = xf_cmd_send_suspend(proxy); + if (ret) { + dev_err(dev, "hifi4 suspend fail\n"); + return ret; + } + } + ret = pm_runtime_force_suspend(dev); return ret; @@ -964,12 +971,22 @@ static int fsl_hifi4_suspend(struct device *dev) static int fsl_hifi4_resume(struct device *dev) { + struct fsl_hifi4 *hifi4_priv = dev_get_drvdata(dev); + struct xf_proxy *proxy = &hifi4_priv->proxy; int ret = 0; ret = pm_runtime_force_resume(dev); if (ret) return ret; + if (proxy->is_ready) { + ret = xf_cmd_send_resume(proxy); + if (ret) { + dev_err(dev, "hifi4 resume fail\n"); + return ret; + } + } + return 0; } #endif /* CONFIG_PM_SLEEP */ diff --git a/sound/soc/fsl/fsl_hifi4_proxy.c b/sound/soc/fsl/fsl_hifi4_proxy.c index 931faec8c7fc..27aece79580a 100644 --- a/sound/soc/fsl/fsl_hifi4_proxy.c +++ b/sound/soc/fsl/fsl_hifi4_proxy.c @@ -135,8 +135,15 @@ struct xf_message *xf_msg_received(struct xf_proxy *proxy, { struct xf_message *m; + /* ...acquire global lock */ + xf_lock(&proxy->lock); + /* ...try to peek message from the queue */ m = xf_msg_dequeue(queue); + if (m == NULL) { + /* ...queue is empty; release lock */ + xf_unlock(&proxy->lock); + } /* ...if message is non-null, lock is held */ return m; @@ -250,6 +257,10 @@ irqreturn_t fsl_hifi4_mu_isr(int irq, void *dev_id) proxy->is_ready = 1; complete(&proxy->cmd_complete); break; + case XF_SUSPEND: + case XF_RESUME: + complete(&proxy->cmd_complete); + break; default: schedule_work(&proxy->work); break; @@ -371,6 +382,7 @@ static u32 xf_shmem_process_responses(struct xf_proxy *proxy) m->opcode = response->opcode; m->length = response->length; m->buffer = xf_proxy_a2b(proxy, response->address); + m->ret = response->ret; /* ...advance local reading index copy */ read_idx = XF_QUEUE_ADVANCE_IDX(read_idx); @@ -416,6 +428,7 @@ static u32 xf_shmem_process_commands(struct xf_proxy *proxy) command->opcode = m->opcode; command->length = m->length; command->address = xf_proxy_b2a(proxy, m->buffer); + command->ret = m->ret; /* ...return message back to the pool */ xf_msg_free(proxy, m); @@ -427,6 +440,9 @@ static u32 xf_shmem_process_commands(struct xf_proxy *proxy) XF_PROXY_WRITE(proxy, cmd_write_idx, write_idx); } + if (status) + icm_intr_send(proxy, 0); + return status; } @@ -490,8 +506,10 @@ int xf_proxy_init(struct xf_proxy *proxy) /* ...initialize shared memory interface */ XF_PROXY_WRITE(proxy, cmd_read_idx, 0); XF_PROXY_WRITE(proxy, cmd_write_idx, 0); + XF_PROXY_WRITE(proxy, cmd_invalid, 0); XF_PROXY_WRITE(proxy, rsp_read_idx, 0); XF_PROXY_WRITE(proxy, rsp_write_idx, 0); + XF_PROXY_WRITE(proxy, rsp_invalid, 0); return 0; } @@ -639,3 +657,46 @@ int xf_cmd_free(struct xf_proxy *proxy, void *buffer, u32 length) return ret; } + +/* + * suspend & resume functions + */ +int xf_cmd_send_suspend(struct xf_proxy *proxy) +{ + union icm_header_t msghdr; + int ret = 0; + + init_completion(&proxy->cmd_complete); + + msghdr.allbits = 0; /* clear all bits; */ + msghdr.ack = 0; + msghdr.intr = 1; + msghdr.msg = XF_SUSPEND; + msghdr.size = 0; + icm_intr_send(proxy, msghdr.allbits); + + /* wait for response here */ + ret = icm_ack_wait(proxy, msghdr.allbits); + + return ret; +} + +int xf_cmd_send_resume(struct xf_proxy *proxy) +{ + union icm_header_t msghdr; + int ret = 0; + + init_completion(&proxy->cmd_complete); + + msghdr.allbits = 0; /* clear all bits; */ + msghdr.ack = 0; + msghdr.intr = 1; + msghdr.msg = XF_RESUME; + msghdr.size = 0; + icm_intr_send(proxy, msghdr.allbits); + + /* wait for response here */ + ret = icm_ack_wait(proxy, msghdr.allbits); + + return ret; +} diff --git a/sound/soc/fsl/fsl_hifi4_proxy.h b/sound/soc/fsl/fsl_hifi4_proxy.h index f89e974ab596..03d2b55c4749 100644 --- a/sound/soc/fsl/fsl_hifi4_proxy.h +++ b/sound/soc/fsl/fsl_hifi4_proxy.h @@ -85,15 +85,18 @@ 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)) +/* ...message id contains source and destination ports specification */ +#define __XF_MSG_ID(src, dst) (((src) & 0xFFFF) | (((dst) & 0xFFFF) << 16)) + /* ...wipe out IPC client from message going to user-space */ -#define XF_MSG_AP_TO_USER(id) ((id) & ~(0xF << 18)) +#define XF_MSG_AP_TO_USER(id) ((id) & ~(0xF << 18)) +#define __XF_AP_PROXY(core) ((core) | 0x8000) +#define __XF_DSP_PROXY(core) ((core) | 0x8000) /* ...message id contains source and destination ports specification */ #define __XF_MSG_ID(src, dst) (((src) & 0xFFFF) | (((dst) & 0xFFFF) << 16)) @@ -143,7 +146,7 @@ enum icm_action_t { /* ...increment ring-buffer index */ #define XF_QUEUE_ADVANCE_IDX(idx) \ - (((idx) + 1) & (0xFFFF0000 | XF_PROXY_MESSAGE_QUEUE_MASK)) + (((idx) + 0x10001) & (0xFFFF0000 | XF_PROXY_MESSAGE_QUEUE_MASK)) /* ...test if ring buffer is empty */ #define XF_QUEUE_EMPTY(read, write) \ @@ -168,6 +171,9 @@ struct xf_proxy_host_data { /* ...reading index for response queue */ u32 rsp_read_idx; + + /* ...indicate command queue is valid or not */ + u32 cmd_invalid; }; /* ...data managed by DSP (local) */ @@ -181,6 +187,8 @@ struct xf_proxy_dsp_data { /* ...reading index for command queue */ u32 cmd_read_idx; + /* ...indicate response queue is valid or not */ + u32 rsp_invalid; }; /* ...shared memory data */ @@ -222,12 +230,18 @@ struct xf_shmem_data { #define __XF_PROXY_READ_cmd_read_idx(shmem) \ shmem->remote.cmd_read_idx +#define __XF_PROXY_READ_cmd_invalid(shmem) \ + __XF_PROXY_READ_ATOMIC(shmem->local.cmd_invalid) + #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 +#define __XF_PROXY_READ_rsp_invalid(shmem) \ + __XF_PROXY_READ_ATOMIC(shmem->remote.rsp_invalid) + /* ...individual fields writings */ #define __XF_PROXY_WRITE_cmd_write_idx(shmem, v) \ __XF_PROXY_WRITE_ATOMIC(shmem->local.cmd_write_idx, v) @@ -235,12 +249,18 @@ struct xf_shmem_data { #define __XF_PROXY_WRITE_cmd_read_idx(shmem, v) \ __XF_PROXY_WRITE_ATOMIC(shmem->remote.cmd_read_idx, v) +#define __XF_PROXY_WRITE_cmd_invalid(shmem, v) \ + __XF_PROXY_WRITE_ATOMIC(shmem->local.cmd_invalid, 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) +#define __XF_PROXY_WRITE_rsp_invalid(shmem, v) \ + __XF_PROXY_WRITE_ATOMIC(shmem->remote.rsp_invalid, v) + /* ...command buffer accessor */ #define XF_PROXY_COMMAND(proxy, idx) \ (&XF_SHMEM_DATA(proxy)->local.command[(idx)]) @@ -378,4 +398,7 @@ 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); +int xf_cmd_send_suspend(struct xf_proxy *proxy); +int xf_cmd_send_resume(struct xf_proxy *proxy); + #endif From 7d17cbca3791f2b64983bd23058076267cc62faa Mon Sep 17 00:00:00 2001 From: Shengjiu Wang Date: Fri, 2 Jun 2017 10:35:35 +0800 Subject: [PATCH 33/78] MLK-14997-3: Document: Add fsl,hifi4 compatibility document add hifi4 document Signed-off-by: Shengjiu Wang --- .../devicetree/bindings/sound/fsl,hifi4.txt | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) create mode 100644 Documentation/devicetree/bindings/sound/fsl,hifi4.txt diff --git a/Documentation/devicetree/bindings/sound/fsl,hifi4.txt b/Documentation/devicetree/bindings/sound/fsl,hifi4.txt new file mode 100644 index 000000000000..a82b25a6de43 --- /dev/null +++ b/Documentation/devicetree/bindings/sound/fsl,hifi4.txt @@ -0,0 +1,16 @@ +NXP HIFI4 DSP (HIFI4) + +The IP is from Cadence. + +Required properties: + + - compatible : Contains "fsl,imx8qxp-hifi4". + - reg : Offset and length of the register set for the device. + +Example: + +hifi4: hifi4@596e8000 { + compatible = "fsl,imx8qxp-hifi4"; + reg = <0x0 0x596e8000 0x0 0x88000>; + status = "okay"; +}; From 6b7b1ae0ecddc26b44c1510370ed27511dbb1fdb Mon Sep 17 00:00:00 2001 From: Weiguang Kong Date: Wed, 18 Apr 2018 23:36:37 +0800 Subject: [PATCH 34/78] MLK-17747: dsp: use the name of dsp instead of hifi In order to avoid the name problem going forward with integration with Qcom, Qcom has their own dsp and hifi is competitor, so the hifi name should not be used in our code. So use the name of dsp instead of hifi to fix this problem. Signed-off-by: Weiguang Kong --- .../sound/{fsl,hifi4.txt => fsl,dsp.txt} | 8 +- include/uapi/linux/{mxc_hifi4.h => mxc_dsp.h} | 43 +- sound/soc/fsl/Kconfig | 4 +- sound/soc/fsl/Makefile | 4 +- sound/soc/fsl/{fsl_hifi4.c => fsl_dsp.c} | 404 +++++++++--------- sound/soc/fsl/{fsl_hifi4.h => fsl_dsp.h} | 34 +- .../{fsl_hifi4_proxy.c => fsl_dsp_proxy.c} | 93 ++-- .../{fsl_hifi4_proxy.h => fsl_dsp_proxy.h} | 16 +- 8 files changed, 303 insertions(+), 303 deletions(-) rename Documentation/devicetree/bindings/sound/{fsl,hifi4.txt => fsl,dsp.txt} (58%) rename include/uapi/linux/{mxc_hifi4.h => mxc_dsp.h} (72%) rename sound/soc/fsl/{fsl_hifi4.c => fsl_dsp.c} (64%) rename sound/soc/fsl/{fsl_hifi4.h => fsl_dsp.h} (82%) rename sound/soc/fsl/{fsl_hifi4_proxy.c => fsl_dsp_proxy.c} (87%) rename sound/soc/fsl/{fsl_hifi4_proxy.h => fsl_dsp_proxy.h} (98%) diff --git a/Documentation/devicetree/bindings/sound/fsl,hifi4.txt b/Documentation/devicetree/bindings/sound/fsl,dsp.txt similarity index 58% rename from Documentation/devicetree/bindings/sound/fsl,hifi4.txt rename to Documentation/devicetree/bindings/sound/fsl,dsp.txt index a82b25a6de43..84bc228b4e32 100644 --- a/Documentation/devicetree/bindings/sound/fsl,hifi4.txt +++ b/Documentation/devicetree/bindings/sound/fsl,dsp.txt @@ -1,16 +1,16 @@ -NXP HIFI4 DSP (HIFI4) +NXP DSP The IP is from Cadence. Required properties: - - compatible : Contains "fsl,imx8qxp-hifi4". + - compatible : Contains "fsl,imx8qxp-dsp". - reg : Offset and length of the register set for the device. Example: -hifi4: hifi4@596e8000 { - compatible = "fsl,imx8qxp-hifi4"; +dsp: dsp@596e8000 { + compatible = "fsl,imx8qxp-dsp"; reg = <0x0 0x596e8000 0x0 0x88000>; status = "okay"; }; diff --git a/include/uapi/linux/mxc_hifi4.h b/include/uapi/linux/mxc_dsp.h similarity index 72% rename from include/uapi/linux/mxc_hifi4.h rename to include/uapi/linux/mxc_dsp.h index 5078537f86fa..aa721f31d403 100644 --- a/include/uapi/linux/mxc_hifi4.h +++ b/include/uapi/linux/mxc_dsp.h @@ -4,26 +4,27 @@ * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * - * 1. Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef __MXC_HIFI4_UAPI_H__ -#define __MXC_HIFI4_UAPI_H__ +#ifndef __MXC_DSP_UAPI_H__ +#define __MXC_DSP_UAPI_H__ #define DSP_IOC_MAGIC 'H' #define DSP_CLIENT_REGISTER _IOW(DSP_IOC_MAGIC, 0, unsigned int) @@ -42,7 +43,7 @@ #define CODEC_SBC_ENC 8 #define CODEC_DEMO_DEC 9 -enum HIFI_ERROR_TYPE { +enum DSP_ERROR_TYPE { XA_SUCCESS = 0, XA_ERROR_STREAM, @@ -59,7 +60,7 @@ enum HIFI_ERROR_TYPE { }; /* Parameter type to Set /Get */ -enum HIFI_ParaType { +enum DSP_ParaType { /* Set parmameters */ /* common */ XA_SAMPLERATE = 0, @@ -108,8 +109,8 @@ enum HIFI_ParaType { }; -#define HIFI_STREAM_DABPLUS_BASE 0x30 -enum HIFI_StreamType { +#define XA_STREAM_DABPLUS_BASE 0x30 +enum DSP_StreamType { /* AAC/AACPLUS file format */ XA_STREAM_UNKNOWN = 0, XA_STREAM_ADTS, @@ -121,7 +122,7 @@ enum HIFI_StreamType { XA_STREAM_LOAS, /* DABPLUS file format */ - XA_STREAM_DABPLUS_RAW_SIDEINFO = HIFI_STREAM_DABPLUS_BASE, + XA_STREAM_DABPLUS_RAW_SIDEINFO = XA_STREAM_DABPLUS_BASE, XA_STREAM_DABPLUS, /* BSAC file raw format */ @@ -130,7 +131,7 @@ enum HIFI_StreamType { }; /* sbc_enc-specific channel modes */ -enum HIFI_SbcEncChmode { +enum DSP_SbcEncChmode { XA_CHMODE_MONO = 0, XA_CHMODE_DUAL = 1, XA_CHMODE_STEREO = 2, @@ -142,4 +143,4 @@ struct shmem_info { unsigned int size; }; -#endif/* __MXC_HIFI4_UAPI_H__ */ +#endif/* __MXC_DSP_UAPI_H__ */ diff --git a/sound/soc/fsl/Kconfig b/sound/soc/fsl/Kconfig index c7b378c6d3f5..60aef56522ad 100644 --- a/sound/soc/fsl/Kconfig +++ b/sound/soc/fsl/Kconfig @@ -74,8 +74,8 @@ config SND_SOC_FSL_MICFIL Say Y if you want to add Pulse Density Modulation microphone interface (MICFIL) support for NXP. -config SND_SOC_FSL_HIFI4 - tristate "hifi 4 module support" +config SND_SOC_FSL_DSP + tristate "dsp module support" help Say Y if you want to add hifi 4 support for the Freescale CPUs. which is a DSP core for audio processing. diff --git a/sound/soc/fsl/Makefile b/sound/soc/fsl/Makefile index d1ffc9eaf9f7..cb3ea47d507c 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 fsl_hifi4_proxy.o +snd-soc-fsl-dsp-objs := fsl_dsp.o fsl_dsp_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 @@ -28,7 +28,7 @@ snd-soc-fsl-dma-objs := fsl_dma.o obj-$(CONFIG_SND_SOC_FSL_AUDMIX) += snd-soc-fsl-audmix.o obj-$(CONFIG_SND_SOC_FSL_ASOC_CARD) += snd-soc-fsl-asoc-card.o obj-$(CONFIG_SND_SOC_FSL_ASRC) += snd-soc-fsl-asrc.o -obj-$(CONFIG_SND_SOC_FSL_HIFI4) += snd-soc-fsl-hifi4.o +obj-$(CONFIG_SND_SOC_FSL_DSP) += snd-soc-fsl-dsp.o obj-$(CONFIG_SND_SOC_FSL_SAI) += snd-soc-fsl-sai.o obj-$(CONFIG_SND_SOC_FSL_SSI) += snd-soc-fsl-ssi.o obj-$(CONFIG_SND_SOC_FSL_SPDIF) += snd-soc-fsl-spdif.o diff --git a/sound/soc/fsl/fsl_hifi4.c b/sound/soc/fsl/fsl_dsp.c similarity index 64% rename from sound/soc/fsl/fsl_hifi4.c rename to sound/soc/fsl/fsl_dsp.c index 7e9b12298892..2719b1b2c376 100644 --- a/sound/soc/fsl/fsl_hifi4.c +++ b/sound/soc/fsl/fsl_dsp.c @@ -1,5 +1,5 @@ /* - * Freescale HIFI 4 driver + * Freescale DSP driver * * Copyright (c) 2012-2013 by Tensilica Inc. ALL RIGHTS RESERVED. * Copyright 2018 NXP @@ -58,20 +58,20 @@ #ifdef CONFIG_COMPAT #include #endif -#include +#include #include #include #include -#include "fsl_hifi4.h" +#include "fsl_dsp.h" /* ...allocate new client */ -static inline struct xf_client *xf_client_alloc(struct fsl_hifi4 *hifi4_priv) +static inline struct xf_client *xf_client_alloc(struct fsl_dsp *dsp_priv) { struct xf_client *client; u32 id; - id = hifi4_priv->xf_client_map[0].next; + id = dsp_priv->xf_client_map[0].next; /* ...try to allocate a client handle */ if (id != 0) { @@ -81,11 +81,11 @@ static inline struct xf_client *xf_client_alloc(struct fsl_hifi4 *hifi4_priv) return ERR_PTR(-ENOMEM); /* ...advance the head of free clients */ - hifi4_priv->xf_client_map[0].next = - hifi4_priv->xf_client_map[id].next; + dsp_priv->xf_client_map[0].next = + dsp_priv->xf_client_map[id].next; /* ...put associate client id with given object */ - hifi4_priv->xf_client_map[id].client = client; + dsp_priv->xf_client_map[id].client = client; /* ...mark client is not yet bound to proxy */ client->proxy = NULL; @@ -104,25 +104,25 @@ static inline struct xf_client *xf_client_alloc(struct fsl_hifi4 *hifi4_priv) static inline void xf_client_free(struct xf_client *client) { int id = client->id; - struct fsl_hifi4 *hifi4_priv = (struct fsl_hifi4 *)client->global; + struct fsl_dsp *dsp_priv = (struct fsl_dsp *)client->global; /* ...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; + dsp_priv->xf_client_map[id].next = dsp_priv->xf_client_map[0].next; + dsp_priv->xf_client_map[0].next = id; /* ...destroy client data */ kfree(client); } /* ...lookup client basing on id */ -struct xf_client *xf_client_lookup(struct fsl_hifi4 *hifi4_priv, u32 id) +struct xf_client *xf_client_lookup(struct fsl_dsp *dsp_priv, u32 id) { if ((id >= XF_CFG_MAX_IPC_CLIENTS) || - (hifi4_priv->xf_client_map[id].next < XF_CFG_MAX_IPC_CLIENTS) + (dsp_priv->xf_client_map[id].next < XF_CFG_MAX_IPC_CLIENTS) ) return NULL; else - return hifi4_priv->xf_client_map[id].client; + return dsp_priv->xf_client_map[id].client; } /* ...helper function for retrieving the client handle */ @@ -144,11 +144,11 @@ static inline struct xf_client *xf_get_client(struct file *file) static int fsl_dsp_client_register(struct xf_client *client) { - struct fsl_hifi4 *hifi4_priv; + struct fsl_dsp *dsp_priv; struct device *dev; - hifi4_priv = (struct fsl_hifi4 *)client->global; - dev = hifi4_priv->dev; + dsp_priv = (struct fsl_dsp *)client->global; + dev = dsp_priv->dev; /* ...make sure client is not registered yet */ if (client->proxy != NULL) { @@ -157,7 +157,7 @@ static int fsl_dsp_client_register(struct xf_client *client) } /* ...complete association (no communication with remote proxy here) */ - client->proxy = &hifi4_priv->proxy; + client->proxy = &dsp_priv->proxy; pr_debug("client-%x registered within proxy", client->id); @@ -186,8 +186,8 @@ static int fsl_dsp_client_unregister(struct xf_client *client) 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; + struct fsl_dsp *dsp_priv = (struct fsl_dsp *)client->global; + struct device *dev = dsp_priv->dev; struct xf_proxy_message msg; void *buffer; unsigned long ret = 0; @@ -199,14 +199,14 @@ static int fsl_dsp_ipc_msg_to_dsp(struct xf_client *client, } /* ...make sure message pointer is sane */ - buffer = xf_proxy_a2b(&hifi4_priv->proxy, msg.address); + buffer = xf_proxy_a2b(&dsp_priv->proxy, msg.address); if (buffer == (void *)-1) return -EFAULT; /* ...put current proxy client into message session id */ msg.session_id = XF_MSG_AP_FROM_USER(msg.session_id, client->id); - xf_cmd_send(&hifi4_priv->proxy, + xf_cmd_send(&dsp_priv->proxy, msg.session_id, msg.opcode, buffer, @@ -218,13 +218,13 @@ static int fsl_dsp_ipc_msg_to_dsp(struct xf_client *client, 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; + struct fsl_dsp *dsp_priv = (struct fsl_dsp *)client->global; + struct device *dev = dsp_priv->dev; struct xf_message *m; struct xf_proxy_message msg; unsigned long ret = 0; - m = xf_cmd_recv(&hifi4_priv->proxy, &client->wait, &client->queue, 0); + m = xf_cmd_recv(&dsp_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); @@ -238,12 +238,12 @@ static int fsl_dsp_ipc_msg_from_dsp(struct xf_client *client, 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.address = xf_proxy_b2a(&dsp_priv->proxy, m->buffer); msg.ret = m->ret; /* ...return the message back to a pool and release lock */ - xf_msg_free(&hifi4_priv->proxy, m); - xf_unlock(&hifi4_priv->proxy.lock); + xf_msg_free(&dsp_priv->proxy, m); + xf_unlock(&dsp_priv->proxy.lock); ret = copy_to_user(user, &msg, sizeof(struct xf_proxy_message)); if (ret) { @@ -257,13 +257,13 @@ static int fsl_dsp_ipc_msg_from_dsp(struct xf_client *client, 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 fsl_dsp *dsp_priv = (struct fsl_dsp *)client->global; + struct device *dev = dsp_priv->dev; struct shmem_info mem_info; unsigned long ret = 0; - mem_info.phys_addr = hifi4_priv->scratch_buf_phys; - mem_info.size = hifi4_priv->scratch_buf_size; + mem_info.phys_addr = dsp_priv->scratch_buf_phys; + mem_info.size = dsp_priv->scratch_buf_size; ret = copy_to_user(user, &mem_info, sizeof(struct shmem_info)); if (ret) { @@ -274,16 +274,16 @@ static int fsl_dsp_get_shmem_info(struct xf_client *client, return ret; } -static struct miscdevice hifi4_miscdev = { +static struct miscdevice dsp_miscdev = { .name = "mxc_hifi4", .minor = MISC_DYNAMIC_MINOR, }; -static long fsl_hifi4_ioctl(struct file *file, unsigned int cmd, +static long fsl_dsp_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { struct xf_client *client; - struct fsl_hifi4 *hifi4_priv; + struct fsl_dsp *dsp_priv; struct xf_proxy *proxy; struct device *dev; void __user *user; @@ -294,16 +294,16 @@ static long fsl_hifi4_ioctl(struct file *file, unsigned int cmd, if (IS_ERR(client)) return PTR_ERR(client); - hifi4_priv = (struct fsl_hifi4 *)client->global; - proxy = &hifi4_priv->proxy; - dev = hifi4_priv->dev; + dsp_priv = (struct fsl_dsp *)client->global; + proxy = &dsp_priv->proxy; + dev = dsp_priv->dev; user = (void __user *)arg; - mutex_lock(&hifi4_priv->hifi4_mutex); + mutex_lock(&dsp_priv->dsp_mutex); if (!proxy->is_ready) { - mutex_unlock(&hifi4_priv->hifi4_mutex); - dev_err(dev, "hifi firmware is not ready\n"); + mutex_unlock(&dsp_priv->dsp_mutex); + dev_err(dev, "dsp firmware is not ready\n"); return -EFAULT; } @@ -327,29 +327,29 @@ static long fsl_hifi4_ioctl(struct file *file, unsigned int cmd, break; } - mutex_unlock(&hifi4_priv->hifi4_mutex); + mutex_unlock(&dsp_priv->dsp_mutex); return ret; } -void resource_release(struct fsl_hifi4 *hifi4_priv) +void resource_release(struct fsl_dsp *dsp_priv) { int i; /* ...initialize client association map */ for (i = 0; i < XF_CFG_MAX_IPC_CLIENTS - 1; i++) - hifi4_priv->xf_client_map[i].next = i + 1; + dsp_priv->xf_client_map[i].next = i + 1; /* ...set list terminator */ - hifi4_priv->xf_client_map[i].next = 0; + dsp_priv->xf_client_map[i].next = 0; /* ...set pointer to shared memory */ - xf_proxy_init(&hifi4_priv->proxy); + xf_proxy_init(&dsp_priv->proxy); } -static int fsl_hifi4_open(struct inode *inode, struct file *file) +static int fsl_dsp_open(struct inode *inode, struct file *file) { - struct fsl_hifi4 *hifi4_priv = dev_get_drvdata(hifi4_miscdev.parent); - struct device *dev = hifi4_priv->dev; + struct fsl_dsp *dsp_priv = dev_get_drvdata(dsp_miscdev.parent); + struct device *dev = dsp_priv->dev; struct xf_client *client; int ret = 0; @@ -358,7 +358,7 @@ static int fsl_hifi4_open(struct inode *inode, struct file *file) return -EINVAL; /* ...allocate new proxy client object */ - client = xf_client_alloc(hifi4_priv); + client = xf_client_alloc(dsp_priv); if (IS_ERR(client)) return PTR_ERR(client); @@ -374,23 +374,23 @@ static int fsl_hifi4_open(struct inode *inode, struct file *file) /* ...reset mappings counter */ atomic_set(&client->vm_use, 0); - client->global = (void *)hifi4_priv; + client->global = (void *)dsp_priv; file->private_data = (void *)client; pm_runtime_get_sync(dev); - mutex_lock(&hifi4_priv->hifi4_mutex); + mutex_lock(&dsp_priv->dsp_mutex); /* increase reference counter when opening device */ - atomic_long_inc(&hifi4_priv->refcnt); - mutex_unlock(&hifi4_priv->hifi4_mutex); + atomic_long_inc(&dsp_priv->refcnt); + mutex_unlock(&dsp_priv->dsp_mutex); return ret; } -static int fsl_hifi4_close(struct inode *inode, struct file *file) +static int fsl_dsp_close(struct inode *inode, struct file *file) { - struct fsl_hifi4 *hifi4_priv; + struct fsl_dsp *dsp_priv; struct device *dev; struct xf_proxy *proxy; struct xf_client *client; @@ -409,26 +409,26 @@ static int fsl_hifi4_close(struct inode *inode, struct file *file) xf_client_free(client); } - hifi4_priv = (struct fsl_hifi4 *)client->global; - dev = hifi4_priv->dev; + dsp_priv = (struct fsl_dsp *)client->global; + dev = dsp_priv->dev; pm_runtime_put_sync(dev); - mutex_lock(&hifi4_priv->hifi4_mutex); + mutex_lock(&dsp_priv->dsp_mutex); /* decrease reference counter when closing device */ - atomic_long_dec(&hifi4_priv->refcnt); + atomic_long_dec(&dsp_priv->refcnt); /* If device is free, reinitialize the resource of - * hifi4 driver and framework + * dsp driver and framework */ - if (atomic_long_read(&hifi4_priv->refcnt) <= 0) - resource_release(hifi4_priv); + if (atomic_long_read(&dsp_priv->refcnt) <= 0) + resource_release(dsp_priv); - mutex_unlock(&hifi4_priv->hifi4_mutex); + mutex_unlock(&dsp_priv->dsp_mutex); return 0; } /* ...wait until data is available in the response queue */ -static unsigned int fsl_hifi4_poll(struct file *file, poll_table *wait) +static unsigned int fsl_dsp_poll(struct file *file, poll_table *wait) { struct xf_proxy *proxy; struct xf_client *client; @@ -458,7 +458,7 @@ static unsigned int fsl_hifi4_poll(struct file *file, poll_table *wait) ******************************************************************************/ /* ...add reference to shared buffer */ -static void hifi4_mmap_open(struct vm_area_struct *vma) +static void dsp_mmap_open(struct vm_area_struct *vma) { struct xf_client *client = vma->vm_private_data; @@ -469,7 +469,7 @@ static void hifi4_mmap_open(struct vm_area_struct *vma) } /* ...close reference to shared buffer */ -static void hifi4_mmap_close(struct vm_area_struct *vma) +static void dsp_mmap_close(struct vm_area_struct *vma) { struct xf_client *client = vma->vm_private_data; @@ -480,20 +480,20 @@ static void hifi4_mmap_close(struct vm_area_struct *vma) } /* ...memory map operations */ -static const struct vm_operations_struct hifi4_mmap_ops = { - .open = hifi4_mmap_open, - .close = hifi4_mmap_close, +static const struct vm_operations_struct dsp_mmap_ops = { + .open = dsp_mmap_open, + .close = dsp_mmap_close, }; /* ...shared memory mapping */ -static int fsl_hifi4_mmap(struct file *file, struct vm_area_struct *vma) +static int fsl_dsp_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; + struct fsl_dsp *dsp_priv; /* ...basic sanity checks */ client = xf_get_client(file); @@ -515,7 +515,7 @@ static int fsl_hifi4_mmap(struct file *file, struct vm_area_struct *vma) return -EPERM; /* ...set memory map operations */ - vma->vm_ops = &hifi4_mmap_ops; + vma->vm_ops = &dsp_mmap_ops; /* ...assign private data */ client->vm_start = vma->vm_start; @@ -524,9 +524,9 @@ static int fsl_hifi4_mmap(struct file *file, struct vm_area_struct *vma) 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; + dsp_priv = (struct fsl_dsp *)client->global; + pfn = dsp_priv->scratch_buf_phys >> PAGE_SHIFT; + size = dsp_priv->scratch_buf_size; /* ...remap shared memory to user-space */ vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot); @@ -540,7 +540,7 @@ static int fsl_hifi4_mmap(struct file *file, struct vm_area_struct *vma) return 0; } -void *memset_hifi(void *dest, int c, size_t count) +void *memset_dsp(void *dest, int c, size_t count) { uint *dl = (uint *)dest; void *dl_1, *dl_2; @@ -586,7 +586,7 @@ void *memset_hifi(void *dest, int c, size_t count) return dest; } -void *memcpy_hifi(void *dest, const void *src, size_t count) +void *memcpy_dsp(void *dest, const void *src, size_t count) { unsigned int *dl = (unsigned int *)dest, *sl = (unsigned int *)src; size_t n = round_up(count, 4) / 4; @@ -607,10 +607,10 @@ void *memcpy_hifi(void *dest, const void *src, size_t count) return dest; } -static void hifi4_load_firmware(const struct firmware *fw, void *context) +static void dsp_load_firmware(const struct firmware *fw, void *context) { - struct fsl_hifi4 *hifi4_priv = context; - struct device *dev = hifi4_priv->dev; + struct fsl_dsp *dsp_priv = context; + struct device *dev = dsp_priv->dev; Elf32_Ehdr *ehdr; /* Elf header structure pointer */ Elf32_Shdr *shdr; /* Section header structure pointer */ Elf32_Addr sh_addr; @@ -654,8 +654,8 @@ static void hifi4_load_firmware(const struct firmware *fw, void *context) sh_addr = shdr->sh_addr; if (shdr->sh_type == SHT_NOBITS) { - memset_hifi((void *)(hifi4_priv->sdram_vir_addr + - (sh_addr - hifi4_priv->sdram_phys_addr)), + memset_dsp((void *)(dsp_priv->sdram_vir_addr + + (sh_addr - dsp_priv->sdram_phys_addr)), 0, shdr->sh_size); } else { @@ -665,13 +665,13 @@ static void hifi4_load_firmware(const struct firmware *fw, void *context) (!strcmp(&strtab[shdr->sh_name], ".data")) || (!strcmp(&strtab[shdr->sh_name], ".bss")) ) { - memcpy_hifi((void *)(hifi4_priv->sdram_vir_addr - + (sh_addr - hifi4_priv->sdram_phys_addr)), + memcpy_dsp((void *)(dsp_priv->sdram_vir_addr + + (sh_addr - dsp_priv->sdram_phys_addr)), (const void *)image, shdr->sh_size); } else { - memcpy_hifi((void *)(hifi4_priv->regs + - (sh_addr - hifi4_priv->paddr)), + memcpy_dsp((void *)(dsp_priv->regs + + (sh_addr - dsp_priv->paddr)), (const void *)image, shdr->sh_size); } @@ -679,73 +679,73 @@ static void hifi4_load_firmware(const struct firmware *fw, void *context) } /* start the core */ - imx_sc_pm_cpu_start(hifi4_priv->hifi_ipcHandle, - IMX_SC_R_DSP, true, hifi4_priv->iram); + imx_sc_pm_cpu_start(dsp_priv->dsp_ipcHandle, + IMX_SC_R_DSP, true, dsp_priv->iram); } /* Initialization of the MU code. */ -int hifi4_mu_init(struct fsl_hifi4 *hifi4_priv) +int dsp_mu_init(struct fsl_dsp *dsp_priv) { - struct device *dev = hifi4_priv->dev; + struct device *dev = dsp_priv->dev; struct device_node *np; - unsigned int hifi_mu_id; + unsigned int dsp_mu_id; u32 irq; int ret = 0; /* - * Get the address of MU to be used for communication with the hifi + * Get the address of MU to be used for communication with the dsp */ - np = of_find_compatible_node(NULL, NULL, "fsl,imx8-mu-hifi"); + np = of_find_compatible_node(NULL, NULL, "fsl,imx8-mu-dsp"); if (!np) { dev_err(dev, "Cannot find MU entry in device tree\n"); return -EINVAL; } - hifi4_priv->mu_base_virtaddr = of_iomap(np, 0); - WARN_ON(!hifi4_priv->mu_base_virtaddr); + dsp_priv->mu_base_virtaddr = of_iomap(np, 0); + WARN_ON(!dsp_priv->mu_base_virtaddr); ret = of_property_read_u32_index(np, - "fsl,hifi_ap_mu_id", 0, &hifi_mu_id); + "fsl,dsp_ap_mu_id", 0, &dsp_mu_id); if (ret) { dev_err(dev, "Cannot get mu_id %d\n", ret); return -EINVAL; } - hifi4_priv->hifi_mu_id = hifi_mu_id; + dsp_priv->dsp_mu_id = dsp_mu_id; 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->proxy); + ret = devm_request_irq(dsp_priv->dev, irq, fsl_dsp_mu_isr, + IRQF_EARLY_RESUME, "dsp_mu_isr", &dsp_priv->proxy); if (ret) { dev_err(dev, "request_irq failed %d, err = %d\n", irq, ret); return -EINVAL; } - if (!hifi4_priv->hifi_mu_init) { - MU_Init(hifi4_priv->mu_base_virtaddr); - MU_EnableRxFullInt(hifi4_priv->mu_base_virtaddr, 0); - hifi4_priv->hifi_mu_init = 1; + if (!dsp_priv->dsp_mu_init) { + MU_Init(dsp_priv->mu_base_virtaddr); + MU_EnableRxFullInt(dsp_priv->mu_base_virtaddr, 0); + dsp_priv->dsp_mu_init = 1; } return ret; } -static const struct file_operations hifi4_fops = { +static const struct file_operations dsp_fops = { .owner = THIS_MODULE, - .unlocked_ioctl = fsl_hifi4_ioctl, + .unlocked_ioctl = fsl_dsp_ioctl, #ifdef CONFIG_COMPAT - .compat_ioctl = fsl_hifi4_ioctl, + .compat_ioctl = fsl_dsp_ioctl, #endif - .open = fsl_hifi4_open, - .poll = fsl_hifi4_poll, - .mmap = fsl_hifi4_mmap, - .release = fsl_hifi4_close, + .open = fsl_dsp_open, + .poll = fsl_dsp_poll, + .mmap = fsl_dsp_mmap, + .release = fsl_dsp_close, }; -static int fsl_hifi4_probe(struct platform_device *pdev) +static int fsl_dsp_probe(struct platform_device *pdev) { struct device_node *np = pdev->dev.of_node; - struct fsl_hifi4 *hifi4_priv; + struct fsl_dsp *dsp_priv; const char *fw_name; struct resource *res; void __iomem *regs; @@ -754,11 +754,11 @@ static int fsl_hifi4_probe(struct platform_device *pdev) int size, offset, i; int ret; - hifi4_priv = devm_kzalloc(&pdev->dev, sizeof(*hifi4_priv), GFP_KERNEL); - if (!hifi4_priv) + dsp_priv = devm_kzalloc(&pdev->dev, sizeof(*dsp_priv), GFP_KERNEL); + if (!dsp_priv) return -ENOMEM; - hifi4_priv->dev = &pdev->dev; + dsp_priv->dev = &pdev->dev; /* Get the addresses and IRQ */ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); @@ -766,76 +766,76 @@ static int fsl_hifi4_probe(struct platform_device *pdev) if (IS_ERR(regs)) return PTR_ERR(regs); - hifi4_priv->paddr = res->start; - hifi4_priv->regs = regs; + dsp_priv->paddr = res->start; + dsp_priv->regs = regs; - hifi4_priv->dram0 = hifi4_priv->paddr + DRAM0_OFFSET; - hifi4_priv->dram1 = hifi4_priv->paddr + DRAM1_OFFSET; - hifi4_priv->iram = hifi4_priv->paddr + IRAM_OFFSET; - hifi4_priv->sram = hifi4_priv->paddr + SYSRAM_OFFSET; + dsp_priv->dram0 = dsp_priv->paddr + DRAM0_OFFSET; + dsp_priv->dram1 = dsp_priv->paddr + DRAM1_OFFSET; + dsp_priv->iram = dsp_priv->paddr + IRAM_OFFSET; + dsp_priv->sram = dsp_priv->paddr + SYSRAM_OFFSET; - ret = imx_scu_get_handle(&hifi4_priv->hifi_ipcHandle); + ret = imx_scu_get_handle(&dsp_priv->dsp_ipcHandle); if (ret) { dev_err(&pdev->dev, "Cannot get scu handle %d\n", ret); return ret; }; - ret = imx_sc_misc_set_control(hifi4_priv->hifi_ipcHandle, IMX_SC_R_DSP, + ret = imx_sc_misc_set_control(dsp_priv->dsp_ipcHandle, IMX_SC_R_DSP, IMX_SC_C_OFS_SEL, 1); if (ret) { dev_err(&pdev->dev, "Error system address offset source select\n"); return -EIO; } - ret = imx_sc_misc_set_control(hifi4_priv->hifi_ipcHandle, IMX_SC_R_DSP, + ret = imx_sc_misc_set_control(dsp_priv->dsp_ipcHandle, IMX_SC_R_DSP, IMX_SC_C_OFS_AUDIO, 0x80); if (ret) { dev_err(&pdev->dev, "Error system address offset of AUDIO\n"); return -EIO; } - ret = imx_sc_misc_set_control(hifi4_priv->hifi_ipcHandle, IMX_SC_R_DSP, + ret = imx_sc_misc_set_control(dsp_priv->dsp_ipcHandle, IMX_SC_R_DSP, IMX_SC_C_OFS_PERIPH, 0x5A); if (ret) { dev_err(&pdev->dev, "Error system address offset of PERIPH\n"); return -EIO; } - ret = imx_sc_misc_set_control(hifi4_priv->hifi_ipcHandle, IMX_SC_R_DSP, + ret = imx_sc_misc_set_control(dsp_priv->dsp_ipcHandle, IMX_SC_R_DSP, IMX_SC_C_OFS_IRQ, 0x51); if (ret) { dev_err(&pdev->dev, "Error system address offset of IRQ\n"); return -EIO; } - ret = hifi4_mu_init(hifi4_priv); + ret = dsp_mu_init(dsp_priv); if (ret) return ret; - ret = of_property_read_string(np, "fsl,hifi4-firmware", &fw_name); - hifi4_priv->fw_name = fw_name; + ret = of_property_read_string(np, "fsl,dsp-firmware", &fw_name); + dsp_priv->fw_name = fw_name; - platform_set_drvdata(pdev, hifi4_priv); + platform_set_drvdata(pdev, dsp_priv); pm_runtime_enable(&pdev->dev); - hifi4_miscdev.fops = &hifi4_fops, - hifi4_miscdev.parent = &pdev->dev, - ret = misc_register(&hifi4_miscdev); + dsp_miscdev.fops = &dsp_fops, + dsp_miscdev.parent = &pdev->dev, + ret = misc_register(&dsp_miscdev); if (ret) { dev_err(&pdev->dev, "failed to register misc device %d\n", ret); return ret; } - hifi4_priv->sdram_phys_addr = SDRAM_BASE_ADDR; - hifi4_priv->sdram_vir_addr = ioremap_wc(hifi4_priv->sdram_phys_addr, + dsp_priv->sdram_phys_addr = SDRAM_BASE_ADDR; + dsp_priv->sdram_vir_addr = ioremap_wc(dsp_priv->sdram_phys_addr, SDRAM_BASE_SIZE); - if (!hifi4_priv->sdram_vir_addr) { - dev_err(&pdev->dev, "failed to remap sdram space for hifi4 firmware\n"); + if (!dsp_priv->sdram_vir_addr) { + dev_err(&pdev->dev, "failed to remap sdram space for dsp firmware\n"); return -ENXIO; } - memset_io(hifi4_priv->sdram_vir_addr, 0, SDRAM_BASE_SIZE); + memset_io(dsp_priv->sdram_vir_addr, 0, SDRAM_BASE_SIZE); - size = MSG_BUF_SIZE + HIFI_CONFIG_SIZE; + size = MSG_BUF_SIZE + DSP_CONFIG_SIZE; buf_virt = dma_alloc_coherent(&pdev->dev, size, &buf_phys, GFP_KERNEL); if (!buf_virt) { @@ -844,69 +844,69 @@ static int fsl_hifi4_probe(struct platform_device *pdev) } /* 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; + dsp_priv->msg_buf_virt = buf_virt; + dsp_priv->msg_buf_phys = buf_phys; + dsp_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; + dsp_priv->dsp_config_virt = buf_virt + offset; + dsp_priv->dsp_config_phys = buf_phys + offset; + dsp_priv->dsp_config_size = DSP_CONFIG_SIZE; /* scratch memory for dsp framework */ - hifi4_priv->scratch_buf_virt = hifi4_priv->sdram_vir_addr + + dsp_priv->scratch_buf_virt = dsp_priv->sdram_vir_addr + SDRAM_CODEC_LIB_OFFSET; - hifi4_priv->scratch_buf_phys = hifi4_priv->sdram_phys_addr + + dsp_priv->scratch_buf_phys = dsp_priv->sdram_phys_addr + SDRAM_CODEC_LIB_OFFSET; - hifi4_priv->scratch_buf_size = SDRAM_BASE_SIZE - SDRAM_CODEC_LIB_OFFSET; + dsp_priv->scratch_buf_size = SDRAM_BASE_SIZE - SDRAM_CODEC_LIB_OFFSET; - /* initialize the reference counter for hifi4_priv + /* initialize the reference counter for dsp_priv * structure */ - atomic_long_set(&hifi4_priv->refcnt, 0); + atomic_long_set(&dsp_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; + dsp_priv->xf_client_map[i].next = i + 1; /* ...set list terminator */ - hifi4_priv->xf_client_map[i].next = 0; + dsp_priv->xf_client_map[i].next = 0; /* ...set pointer to shared memory */ - xf_proxy_init(&hifi4_priv->proxy); + xf_proxy_init(&dsp_priv->proxy); /* ...initialize mutex */ - mutex_init(&hifi4_priv->hifi4_mutex); + mutex_init(&dsp_priv->dsp_mutex); return 0; } -static int fsl_hifi4_remove(struct platform_device *pdev) +static int fsl_dsp_remove(struct platform_device *pdev) { - struct fsl_hifi4 *hifi4_priv = platform_get_drvdata(pdev); + struct fsl_dsp *dsp_priv = platform_get_drvdata(pdev); int size; - misc_deregister(&hifi4_miscdev); + misc_deregister(&dsp_miscdev); - size = MSG_BUF_SIZE + HIFI_CONFIG_SIZE; - dma_free_coherent(&pdev->dev, size, hifi4_priv->msg_buf_virt, - hifi4_priv->msg_buf_phys); - if (hifi4_priv->sdram_vir_addr) - iounmap(hifi4_priv->sdram_vir_addr); + size = MSG_BUF_SIZE + DSP_CONFIG_SIZE; + dma_free_coherent(&pdev->dev, size, dsp_priv->msg_buf_virt, + dsp_priv->msg_buf_phys); + if (dsp_priv->sdram_vir_addr) + iounmap(dsp_priv->sdram_vir_addr); return 0; } #ifdef CONFIG_PM -static int fsl_hifi4_runtime_resume(struct device *dev) +static int fsl_dsp_runtime_resume(struct device *dev) { - struct fsl_hifi4 *hifi4_priv = dev_get_drvdata(dev); - struct xf_proxy *proxy = &hifi4_priv->proxy; + struct fsl_dsp *dsp_priv = dev_get_drvdata(dev); + struct xf_proxy *proxy = &dsp_priv->proxy; int ret; - if (sc_pm_set_resource_power_mode(hifi4_priv->hifi_ipcHandle, + if (sc_pm_set_resource_power_mode(dsp_priv->dsp_ipcHandle, SC_R_DSP_RAM, SC_PM_PW_MODE_ON) != SC_ERR_NONE) { - dev_err(dev, "Error power on HIFI RAM\n"); + dev_err(dev, "Error power on DSP RAM\n"); return -EIO; } @@ -914,9 +914,9 @@ static int fsl_hifi4_runtime_resume(struct device *dev) init_completion(&proxy->cmd_complete); ret = request_firmware_nowait(THIS_MODULE, - FW_ACTION_HOTPLUG, hifi4_priv->fw_name, + FW_ACTION_HOTPLUG, dsp_priv->fw_name, dev, - GFP_KERNEL, hifi4_priv, hifi4_load_firmware); + GFP_KERNEL, dsp_priv, dsp_load_firmware); if (ret) { dev_err(dev, "failed to load firmware\n"); @@ -924,23 +924,23 @@ static int fsl_hifi4_runtime_resume(struct device *dev) } ret = icm_ack_wait(proxy, 0); - if (ret) { + if (ret) return ret; - } - dev_info(dev, "hifi driver registered\n"); + + dev_info(dev, "dsp driver registered\n"); } return 0; } -static int fsl_hifi4_runtime_suspend(struct device *dev) +static int fsl_dsp_runtime_suspend(struct device *dev) { - struct fsl_hifi4 *hifi4_priv = dev_get_drvdata(dev); - struct xf_proxy *proxy = &hifi4_priv->proxy; + struct fsl_dsp *dsp_priv = dev_get_drvdata(dev); + struct xf_proxy *proxy = &dsp_priv->proxy; - if (sc_pm_set_resource_power_mode(hifi4_priv->hifi_ipcHandle, + if (sc_pm_set_resource_power_mode(dsp_priv->dsp_ipcHandle, SC_R_DSP_RAM, SC_PM_PW_MODE_OFF) != SC_ERR_NONE) { - dev_err(dev, "Error power off HIFI RAM\n"); + dev_err(dev, "Error power off DSP RAM\n"); return -EIO; } proxy->is_ready = 0; @@ -950,16 +950,16 @@ static int fsl_hifi4_runtime_suspend(struct device *dev) #ifdef CONFIG_PM_SLEEP -static int fsl_hifi4_suspend(struct device *dev) +static int fsl_dsp_suspend(struct device *dev) { - struct fsl_hifi4 *hifi4_priv = dev_get_drvdata(dev); - struct xf_proxy *proxy = &hifi4_priv->proxy; + struct fsl_dsp *dsp_priv = dev_get_drvdata(dev); + struct xf_proxy *proxy = &dsp_priv->proxy; int ret = 0; if (proxy->is_ready) { ret = xf_cmd_send_suspend(proxy); if (ret) { - dev_err(dev, "hifi4 suspend fail\n"); + dev_err(dev, "dsp suspend fail\n"); return ret; } } @@ -969,10 +969,10 @@ static int fsl_hifi4_suspend(struct device *dev) return ret; } -static int fsl_hifi4_resume(struct device *dev) +static int fsl_dsp_resume(struct device *dev) { - struct fsl_hifi4 *hifi4_priv = dev_get_drvdata(dev); - struct xf_proxy *proxy = &hifi4_priv->proxy; + struct fsl_dsp *dsp_priv = dev_get_drvdata(dev); + struct xf_proxy *proxy = &dsp_priv->proxy; int ret = 0; ret = pm_runtime_force_resume(dev); @@ -982,7 +982,7 @@ static int fsl_hifi4_resume(struct device *dev) if (proxy->is_ready) { ret = xf_cmd_send_resume(proxy); if (ret) { - dev_err(dev, "hifi4 resume fail\n"); + dev_err(dev, "dsp resume fail\n"); return ret; } } @@ -991,29 +991,29 @@ static int fsl_hifi4_resume(struct device *dev) } #endif /* CONFIG_PM_SLEEP */ -static const struct dev_pm_ops fsl_hifi4_pm = { - SET_RUNTIME_PM_OPS(fsl_hifi4_runtime_suspend, - fsl_hifi4_runtime_resume, NULL) - SET_SYSTEM_SLEEP_PM_OPS(fsl_hifi4_suspend, fsl_hifi4_resume) +static const struct dev_pm_ops fsl_dsp_pm = { + SET_RUNTIME_PM_OPS(fsl_dsp_runtime_suspend, + fsl_dsp_runtime_resume, NULL) + SET_SYSTEM_SLEEP_PM_OPS(fsl_dsp_suspend, fsl_dsp_resume) }; -static const struct of_device_id fsl_hifi4_ids[] = { - { .compatible = "fsl,imx8qxp-hifi4", }, +static const struct of_device_id fsl_dsp_ids[] = { + { .compatible = "fsl,imx8qxp-dsp", }, {} }; -MODULE_DEVICE_TABLE(of, fsl_hifi4_ids); +MODULE_DEVICE_TABLE(of, fsl_dsp_ids); -static struct platform_driver fsl_hifi4_driver = { - .probe = fsl_hifi4_probe, - .remove = fsl_hifi4_remove, +static struct platform_driver fsl_dsp_driver = { + .probe = fsl_dsp_probe, + .remove = fsl_dsp_remove, .driver = { - .name = "fsl-hifi4", - .of_match_table = fsl_hifi4_ids, - .pm = &fsl_hifi4_pm, + .name = "fsl-dsp", + .of_match_table = fsl_dsp_ids, + .pm = &fsl_dsp_pm, }, }; -module_platform_driver(fsl_hifi4_driver); +module_platform_driver(fsl_dsp_driver); -MODULE_DESCRIPTION("Freescale HIFI 4 driver"); -MODULE_ALIAS("platform:fsl-hifi4"); +MODULE_DESCRIPTION("Freescale DSP driver"); +MODULE_ALIAS("platform:fsl-dsp"); MODULE_LICENSE("Dual BSD/GPL"); diff --git a/sound/soc/fsl/fsl_hifi4.h b/sound/soc/fsl/fsl_dsp.h similarity index 82% rename from sound/soc/fsl/fsl_hifi4.h rename to sound/soc/fsl/fsl_dsp.h index 61592d1657d8..3824641c2f93 100644 --- a/sound/soc/fsl/fsl_hifi4.h +++ b/sound/soc/fsl/fsl_dsp.h @@ -1,5 +1,5 @@ /* - * Freescale HIFI 4 driver + * Freescale DSP driver * * Copyright 2018 NXP * @@ -8,8 +8,8 @@ * kind, whether express or implied. */ -#include -#include "fsl_hifi4_proxy.h" +#include +#include "fsl_dsp_proxy.h" typedef void (*memcpy_func) (void *dest, const void *src, size_t n); @@ -51,14 +51,14 @@ union xf_client_link { struct xf_client *client; }; -struct fsl_hifi4 { +struct fsl_dsp { struct device *dev; const char *fw_name; void __iomem *regs; void __iomem *mu_base_virtaddr; - struct imx_sc_ipc *hifi_ipcHandle; - unsigned int hifi_mu_id; - int hifi_mu_init; + struct imx_sc_ipc *dsp_ipcHandle; + unsigned int dsp_mu_id; + int dsp_mu_init; atomic_long_t refcnt; unsigned long paddr; unsigned long dram0; @@ -73,15 +73,15 @@ struct fsl_hifi4 { void *scratch_buf_virt; dma_addr_t scratch_buf_phys; int scratch_buf_size; - void *hifi_config_virt; - dma_addr_t hifi_config_phys; - int hifi_config_size; + void *dsp_config_virt; + dma_addr_t dsp_config_phys; + int dsp_config_size; /* ...proxy data structures */ struct xf_proxy proxy; /* ...mutex lock */ - struct mutex hifi4_mutex; + struct mutex dsp_mutex; /* ...global clients pool (item[0] serves as list terminator) */ union xf_client_link xf_client_map[XF_CFG_MAX_IPC_CLIENTS]; @@ -105,7 +105,7 @@ struct fsl_hifi4 { #define MSG_BUF_SIZE 8192 #define INPUT_BUF_SIZE 4096 #define OUTPUT_BUF_SIZE 16384 -#define HIFI_CONFIG_SIZE 4096 +#define DSP_CONFIG_SIZE 4096 /*external buffer * ---------------------------------------------------------------------- @@ -113,13 +113,13 @@ struct fsl_hifi4 { * ----------------------------------------------------------------------- * | scratch buffer for malloc | 0xffffff | For MEM_scratch_malloc() * ------------------------------------------------------------------------ - * | global structure | 4096 | For store hifi config structure + * | global structure | 4096 | For store dsp config structure * ------------------------------------------------------------------------ */ #define MEMORY_REMAP_OFFSET 0x39000000 -/* reserved memory for hifi4 firmware and core libs to +/* reserved memory for dsp firmware and core libs to * save their instruction/data section in SDRAM, the physical * address range is 0x8e000000 ~ 0x8fffffff (32M bytes). */ @@ -133,6 +133,6 @@ struct fsl_hifi4 { #define SC_C_OFS_PERIPH 41 #define SC_C_OFS_IRQ 42 -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); +void *memcpy_dsp(void *dest, const void *src, size_t count); +void *memset_dsp(void *dest, int c, size_t count); +struct xf_client *xf_client_lookup(struct fsl_dsp *dsp_priv, u32 id); diff --git a/sound/soc/fsl/fsl_hifi4_proxy.c b/sound/soc/fsl/fsl_dsp_proxy.c similarity index 87% rename from sound/soc/fsl/fsl_hifi4_proxy.c rename to sound/soc/fsl/fsl_dsp_proxy.c index 27aece79580a..f9a226d1f577 100644 --- a/sound/soc/fsl/fsl_hifi4_proxy.c +++ b/sound/soc/fsl/fsl_dsp_proxy.c @@ -9,7 +9,7 @@ * ******************************************************************************/ /******************************************************************************* - * fsl_hifi4_proxy.c + * fsl_dsp_proxy.c * * DSP proxy driver * @@ -17,9 +17,8 @@ * and dsp framework ******************************************************************************/ -#include -#include "fsl_hifi4_proxy.h" -#include "fsl_hifi4.h" +#include "fsl_dsp_proxy.h" +#include "fsl_dsp.h" /* ...initialize message queue */ @@ -154,41 +153,41 @@ struct xf_message *xf_msg_received(struct xf_proxy *proxy, */ u32 icm_intr_send(struct xf_proxy *proxy, u32 msg) { - struct fsl_hifi4 *hifi4_priv = container_of(proxy, - struct fsl_hifi4, proxy); + struct fsl_dsp *dsp_priv = container_of(proxy, + struct fsl_dsp, proxy); - MU_SendMessage(hifi4_priv->mu_base_virtaddr, 0, msg); + MU_SendMessage(dsp_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 dsp_ext_msg *ext_msg) { - struct fsl_hifi4 *hifi4_priv = container_of(proxy, - struct fsl_hifi4, proxy); - struct device *dev = hifi4_priv->dev; + struct fsl_dsp *dsp_priv = container_of(proxy, + struct fsl_dsp, proxy); + struct device *dev = dsp_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); + MU_SendMessage(dsp_priv->mu_base_virtaddr, 1, ext_msg->phys); + MU_SendMessage(dsp_priv->mu_base_virtaddr, 2, ext_msg->size); + MU_SendMessage(dsp_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); + struct fsl_dsp *dsp_priv = container_of(proxy, + struct fsl_dsp, 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 + struct dsp_ext_msg ext_msg; + struct dsp_mem_msg *dpu_ext_msg = + (struct dsp_mem_msg *)((unsigned char *)dsp_priv->msg_buf_virt + (MSG_BUF_SIZE / 2)); int ret_val = 0; @@ -197,15 +196,15 @@ int send_dpu_ext_msg_addr(struct xf_proxy *proxy) 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); + ext_msg.phys = dsp_priv->msg_buf_phys + (MSG_BUF_SIZE / 2); + ext_msg.size = sizeof(struct dsp_mem_msg); - dpu_ext_msg->ext_msg_phys = hifi4_priv->msg_buf_phys; + dpu_ext_msg->ext_msg_phys = dsp_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; + dpu_ext_msg->scratch_phys = dsp_priv->scratch_buf_phys; + dpu_ext_msg->scratch_size = dsp_priv->scratch_buf_size; + dpu_ext_msg->dsp_config_phys = dsp_priv->dsp_config_phys; + dpu_ext_msg->dsp_config_size = dsp_priv->dsp_config_size; icm_intr_extended_send(proxy, msghdr.allbits, &ext_msg); @@ -214,9 +213,9 @@ int send_dpu_ext_msg_addr(struct xf_proxy *proxy) 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; + struct fsl_dsp *dsp_priv = container_of(proxy, + struct fsl_dsp, proxy); + struct device *dev = dsp_priv->dev; union icm_header_t msghdr; int err; @@ -234,16 +233,16 @@ long icm_ack_wait(struct xf_proxy *proxy, u32 msg) return 0; } -irqreturn_t fsl_hifi4_mu_isr(int irq, void *dev_id) +irqreturn_t fsl_dsp_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; + struct fsl_dsp *dsp_priv = container_of(proxy, + struct fsl_dsp, proxy); + struct device *dev = dsp_priv->dev; union icm_header_t msghdr; u32 reg; - MU_ReceiveMsg(hifi4_priv->mu_base_virtaddr, 0, ®); + MU_ReceiveMsg(dsp_priv->mu_base_virtaddr, 0, ®); msghdr = (union icm_header_t)reg; if (msghdr.intr == 1) { @@ -287,14 +286,14 @@ irqreturn_t fsl_hifi4_mu_isr(int irq, void *dev_id) /* ...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); + struct fsl_dsp *dsp_priv = container_of(proxy, + struct fsl_dsp, proxy); if (b == NULL) return XF_PROXY_NULL; - else if ((u32)(b - hifi4_priv->scratch_buf_virt) < + else if ((u32)(b - dsp_priv->scratch_buf_virt) < SDRAM_SCRATCH_BUF_SIZE) - return (u32)(b - hifi4_priv->scratch_buf_virt); + return (u32)(b - dsp_priv->scratch_buf_virt); else return XF_PROXY_BADADDR; } @@ -302,11 +301,11 @@ 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) { - struct fsl_hifi4 *hifi4_priv = container_of(proxy, - struct fsl_hifi4, proxy); + struct fsl_dsp *dsp_priv = container_of(proxy, + struct fsl_dsp, proxy); if (address < SDRAM_SCRATCH_BUF_SIZE) - return hifi4_priv->scratch_buf_virt + address; + return dsp_priv->scratch_buf_virt + address; else if (address == XF_PROXY_NULL) return NULL; else @@ -316,8 +315,8 @@ void *xf_proxy_a2b(struct xf_proxy *proxy, u32 address) /* ...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); + struct fsl_dsp *dsp_priv = container_of(proxy, + struct fsl_dsp, proxy); u32 id = XF_AP_IPC_CLIENT(m->id); struct xf_client *client; @@ -330,7 +329,7 @@ static void xf_cmap(struct xf_proxy *proxy, struct xf_message *m) } /* ...make sure the client ID is sane */ - client = xf_client_lookup(hifi4_priv, id); + client = xf_client_lookup(dsp_priv, id); if (!client) { pr_err("rsp[id:%08x]: client lookup failed", m->id); xf_msg_free(proxy, m); @@ -471,8 +470,8 @@ void xf_proxy_process(struct work_struct *w) /* ...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 fsl_dsp *dsp_priv = container_of(proxy, + struct fsl_dsp, proxy); struct xf_message *m; int i; @@ -501,7 +500,7 @@ int xf_proxy_init(struct xf_proxy *proxy) INIT_WORK(&proxy->work, xf_proxy_process); /* ...set pointer to shared memory */ - proxy->ipc.shmem = (struct xf_shmem_data *)hifi4_priv->msg_buf_virt; + proxy->ipc.shmem = (struct xf_shmem_data *)dsp_priv->msg_buf_virt; /* ...initialize shared memory interface */ XF_PROXY_WRITE(proxy, cmd_read_idx, 0); diff --git a/sound/soc/fsl/fsl_hifi4_proxy.h b/sound/soc/fsl/fsl_dsp_proxy.h similarity index 98% rename from sound/soc/fsl/fsl_hifi4_proxy.h rename to sound/soc/fsl/fsl_dsp_proxy.h index 03d2b55c4749..4c3ec9b17e37 100644 --- a/sound/soc/fsl/fsl_hifi4_proxy.h +++ b/sound/soc/fsl/fsl_dsp_proxy.h @@ -9,13 +9,13 @@ * ************************************************************/ /************************************************************ - * fsl_hifi4_proxy.h + * fsl_dsp_proxy.h * * Proxy commmand/response messages ************************************************************/ -#ifndef __FSL_HIFI4_PROXY_H -#define __FSL_HIFI4_PROXY_H +#ifndef __FSL_DSP_PROXY_H +#define __FSL_DSP_PROXY_H #include #include @@ -329,18 +329,18 @@ union icm_header_t { u32 allbits; }; -struct hifi4_ext_msg { +struct dsp_ext_msg { u32 phys; u32 size; }; -struct hifi4_mem_msg { +struct dsp_mem_msg { u32 ext_msg_phys; u32 ext_msg_size; u32 scratch_phys; u32 scratch_size; - u32 hifi_config_phys; - u32 hifi_config_size; + u32 dsp_config_phys; + u32 dsp_config_size; }; static inline void xf_lock_init(spinlock_t *lock) @@ -375,7 +375,7 @@ struct xf_message *xf_cmd_recv(struct xf_proxy *proxy, int wait); /* ...mu interrupt handle */ -irqreturn_t fsl_hifi4_mu_isr(int irq, void *dev_id); +irqreturn_t fsl_dsp_mu_isr(int irq, void *dev_id); /* ...initialize client pending message queue */ void xf_msg_queue_init(struct xf_msg_queue *queue); From 6b034c90fbccceebf4a009b4334d4450c8a161cc Mon Sep 17 00:00:00 2001 From: Shengjiu Wang Date: Wed, 9 May 2018 11:12:02 +0800 Subject: [PATCH 35/78] MLK-18245-1: ASoC: fsl_dsp: remove the explicit power enablement The driver don't need to explicit enable the power domain, which can be done by runtime power management, when the power domain tree defined in device tree. in this case, the MU initialization can be moved to runtime pm function. Signed-off-by: Shengjiu Wang --- sound/soc/fsl/fsl_dsp.c | 20 +++++--------------- 1 file changed, 5 insertions(+), 15 deletions(-) diff --git a/sound/soc/fsl/fsl_dsp.c b/sound/soc/fsl/fsl_dsp.c index 2719b1b2c376..ea95c87507c4 100644 --- a/sound/soc/fsl/fsl_dsp.c +++ b/sound/soc/fsl/fsl_dsp.c @@ -721,12 +721,6 @@ int dsp_mu_init(struct fsl_dsp *dsp_priv) return -EINVAL; } - if (!dsp_priv->dsp_mu_init) { - MU_Init(dsp_priv->mu_base_virtaddr); - MU_EnableRxFullInt(dsp_priv->mu_base_virtaddr, 0); - dsp_priv->dsp_mu_init = 1; - } - return ret; } @@ -904,10 +898,10 @@ static int fsl_dsp_runtime_resume(struct device *dev) struct xf_proxy *proxy = &dsp_priv->proxy; int ret; - if (sc_pm_set_resource_power_mode(dsp_priv->dsp_ipcHandle, - SC_R_DSP_RAM, SC_PM_PW_MODE_ON) != SC_ERR_NONE) { - dev_err(dev, "Error power on DSP RAM\n"); - return -EIO; + if (!dsp_priv->dsp_mu_init) { + MU_Init(dsp_priv->mu_base_virtaddr); + MU_EnableRxFullInt(dsp_priv->mu_base_virtaddr, 0); + dsp_priv->dsp_mu_init = 1; } if (!proxy->is_ready) { @@ -938,11 +932,7 @@ static int fsl_dsp_runtime_suspend(struct device *dev) struct fsl_dsp *dsp_priv = dev_get_drvdata(dev); struct xf_proxy *proxy = &dsp_priv->proxy; - if (sc_pm_set_resource_power_mode(dsp_priv->dsp_ipcHandle, - SC_R_DSP_RAM, SC_PM_PW_MODE_OFF) != SC_ERR_NONE) { - dev_err(dev, "Error power off DSP RAM\n"); - return -EIO; - } + dsp_priv->dsp_mu_init = 0; proxy->is_ready = 0; return 0; } From dc9756fa77434d5a3c85ce44a82565c2fe6b89ab Mon Sep 17 00:00:00 2001 From: Weiguang Kong Date: Fri, 11 May 2018 12:34:10 +0800 Subject: [PATCH 36/78] MLK-18279: ASoC: fsl_dsp: get the information of reserved memory from dts The reserved memory for dsp is defined in dts file, however, the dsp driver has also defined the address and size of this reserved memory, which is repeated and inflexible. So by cancelling the definition in dsp driver and use system API to get the information of reserved memory from dts dynamically to fix this problem. Signed-off-by: Weiguang Kong --- sound/soc/fsl/fsl_dsp.c | 38 ++++++++++++++++++++++++++++------- sound/soc/fsl/fsl_dsp.h | 22 +------------------- sound/soc/fsl/fsl_dsp_proxy.c | 6 +++--- 3 files changed, 35 insertions(+), 31 deletions(-) diff --git a/sound/soc/fsl/fsl_dsp.c b/sound/soc/fsl/fsl_dsp.c index ea95c87507c4..593fb80ba48b 100644 --- a/sound/soc/fsl/fsl_dsp.c +++ b/sound/soc/fsl/fsl_dsp.c @@ -739,6 +739,8 @@ static const struct file_operations dsp_fops = { static int fsl_dsp_probe(struct platform_device *pdev) { struct device_node *np = pdev->dev.of_node; + struct device_node *reserved_node; + struct resource reserved_res; struct fsl_dsp *dsp_priv; const char *fw_name; struct resource *res; @@ -820,14 +822,32 @@ static int fsl_dsp_probe(struct platform_device *pdev) return ret; } - dsp_priv->sdram_phys_addr = SDRAM_BASE_ADDR; + reserved_node = of_parse_phandle(np, "reserved-region", 0); + if (!reserved_node) { + dev_err(&pdev->dev, "failed to get reserved region node\n"); + return -ENODEV; + } + + if (of_address_to_resource(reserved_node, 0, &reserved_res)) { + dev_err(&pdev->dev, "failed to get reserved region address\n"); + return -EINVAL; + } + + dsp_priv->sdram_phys_addr = reserved_res.start; + dsp_priv->sdram_reserved_size = (reserved_res.end - reserved_res.start) + + 1; + if (dsp_priv->sdram_reserved_size <= 0) { + dev_err(&pdev->dev, "invalid value of reserved region size\n"); + return -EINVAL; + } + dsp_priv->sdram_vir_addr = ioremap_wc(dsp_priv->sdram_phys_addr, - SDRAM_BASE_SIZE); + dsp_priv->sdram_reserved_size); if (!dsp_priv->sdram_vir_addr) { dev_err(&pdev->dev, "failed to remap sdram space for dsp firmware\n"); return -ENXIO; } - memset_io(dsp_priv->sdram_vir_addr, 0, SDRAM_BASE_SIZE); + memset_io(dsp_priv->sdram_vir_addr, 0, dsp_priv->sdram_reserved_size); size = MSG_BUF_SIZE + DSP_CONFIG_SIZE; @@ -848,12 +868,16 @@ static int fsl_dsp_probe(struct platform_device *pdev) dsp_priv->dsp_config_phys = buf_phys + offset; dsp_priv->dsp_config_size = DSP_CONFIG_SIZE; - /* scratch memory for dsp framework */ + /* scratch memory for dsp framework. The sdram reserved memory + * is split into two equal parts currently. The front part is + * used to keep the dsp firmware, the other part is considered + * as scratch memory for dsp framework. + */ dsp_priv->scratch_buf_virt = dsp_priv->sdram_vir_addr + - SDRAM_CODEC_LIB_OFFSET; + dsp_priv->sdram_reserved_size / 2; dsp_priv->scratch_buf_phys = dsp_priv->sdram_phys_addr + - SDRAM_CODEC_LIB_OFFSET; - dsp_priv->scratch_buf_size = SDRAM_BASE_SIZE - SDRAM_CODEC_LIB_OFFSET; + dsp_priv->sdram_reserved_size / 2; + dsp_priv->scratch_buf_size = dsp_priv->sdram_reserved_size / 2; /* initialize the reference counter for dsp_priv * structure diff --git a/sound/soc/fsl/fsl_dsp.h b/sound/soc/fsl/fsl_dsp.h index 3824641c2f93..02eca8ef5c80 100644 --- a/sound/soc/fsl/fsl_dsp.h +++ b/sound/soc/fsl/fsl_dsp.h @@ -67,6 +67,7 @@ struct fsl_dsp { unsigned long sram; void *sdram_vir_addr; unsigned long sdram_phys_addr; + int sdram_reserved_size; void *msg_buf_virt; dma_addr_t msg_buf_phys; int msg_buf_size; @@ -107,27 +108,6 @@ struct fsl_dsp { #define OUTPUT_BUF_SIZE 16384 #define DSP_CONFIG_SIZE 4096 -/*external buffer - * ---------------------------------------------------------------------- - * | name | size | description | - * ----------------------------------------------------------------------- - * | scratch buffer for malloc | 0xffffff | For MEM_scratch_malloc() - * ------------------------------------------------------------------------ - * | global structure | 4096 | For store dsp config structure - * ------------------------------------------------------------------------ - */ - -#define MEMORY_REMAP_OFFSET 0x39000000 - -/* reserved memory for dsp firmware and core libs to - * save their instruction/data section in SDRAM, the physical - * address range is 0x8e000000 ~ 0x8fffffff (32M bytes). - */ -#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 diff --git a/sound/soc/fsl/fsl_dsp_proxy.c b/sound/soc/fsl/fsl_dsp_proxy.c index f9a226d1f577..0eb0605018c8 100644 --- a/sound/soc/fsl/fsl_dsp_proxy.c +++ b/sound/soc/fsl/fsl_dsp_proxy.c @@ -281,7 +281,7 @@ irqreturn_t fsl_dsp_mu_isr(int irq, void *dev_id) /* ...NULL-address specification */ #define XF_PROXY_NULL (~0U) -#define XF_PROXY_BADADDR SDRAM_SCRATCH_BUF_SIZE +#define XF_PROXY_BADADDR (dsp_priv->scratch_buf_size) /* ...shared memory translation - kernel virtual address to shared address */ u32 xf_proxy_b2a(struct xf_proxy *proxy, void *b) @@ -292,7 +292,7 @@ u32 xf_proxy_b2a(struct xf_proxy *proxy, void *b) if (b == NULL) return XF_PROXY_NULL; else if ((u32)(b - dsp_priv->scratch_buf_virt) < - SDRAM_SCRATCH_BUF_SIZE) + dsp_priv->scratch_buf_size) return (u32)(b - dsp_priv->scratch_buf_virt); else return XF_PROXY_BADADDR; @@ -304,7 +304,7 @@ void *xf_proxy_a2b(struct xf_proxy *proxy, u32 address) struct fsl_dsp *dsp_priv = container_of(proxy, struct fsl_dsp, proxy); - if (address < SDRAM_SCRATCH_BUF_SIZE) + if (address < dsp_priv->scratch_buf_size) return dsp_priv->scratch_buf_virt + address; else if (address == XF_PROXY_NULL) return NULL; From 49c0d24bec411f2f787d77703c91e9d47aa67dc7 Mon Sep 17 00:00:00 2001 From: Shengjiu Wang Date: Wed, 20 Jun 2018 17:08:15 +0800 Subject: [PATCH 37/78] MLK-18646: ASoC: fsl_dsp: fix the license issue correct the license issue Signed-off-by: Shengjiu Wang Reviewed-by: Daniel Baluta --- sound/soc/fsl/fsl_dsp.h | 7 ++----- sound/soc/fsl/fsl_dsp_proxy.c | 5 +---- sound/soc/fsl/fsl_dsp_proxy.h | 5 +---- 3 files changed, 4 insertions(+), 13 deletions(-) diff --git a/sound/soc/fsl/fsl_dsp.h b/sound/soc/fsl/fsl_dsp.h index 02eca8ef5c80..e87b531fcba5 100644 --- a/sound/soc/fsl/fsl_dsp.h +++ b/sound/soc/fsl/fsl_dsp.h @@ -1,11 +1,8 @@ +/* SPDX-License-Identifier: (GPL-2.0+ OR MIT)*/ /* - * Freescale DSP driver - * + * Copyright (C) 2017 Cadence Design Systems, Inc. * Copyright 2018 NXP * - * 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. */ #include diff --git a/sound/soc/fsl/fsl_dsp_proxy.c b/sound/soc/fsl/fsl_dsp_proxy.c index 0eb0605018c8..7b1a86d8576c 100644 --- a/sound/soc/fsl/fsl_dsp_proxy.c +++ b/sound/soc/fsl/fsl_dsp_proxy.c @@ -1,8 +1,5 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR MIT) /******************************************************************************* - * - * 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 diff --git a/sound/soc/fsl/fsl_dsp_proxy.h b/sound/soc/fsl/fsl_dsp_proxy.h index 4c3ec9b17e37..0942b8d85a6e 100644 --- a/sound/soc/fsl/fsl_dsp_proxy.h +++ b/sound/soc/fsl/fsl_dsp_proxy.h @@ -1,8 +1,5 @@ +/* SPDX-License-Identifier: (GPL-2.0+ OR MIT)*/ /******************************************************************************* - * - * 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 From 8184e47416f8e581ba3c97f84f81289d468d6840 Mon Sep 17 00:00:00 2001 From: Daniel Baluta Date: Wed, 23 May 2018 09:40:55 +0300 Subject: [PATCH 38/78] MLK-17481-3: ASoC: fsl: Fix DSP memory mappings We load DSP firmware from the ARM side at 0x556e8000 but because the compiler generated memory layout starts at 0x596e8000 we need to do some fixups. Thus, each address (in DSP local memory) generated by the compiler needs to be substracted an offset = 0x596e8000 - 0x556e8000 = 0x4000000. Because this only happens on QM we will use dts to specify the offset. Signed-off-by: Daniel Baluta Reviewed-by: Shengjiu Wang (cherry picked from commit 8d4518d2a5d956549e829470af15003d7adff841) --- sound/soc/fsl/fsl_dsp.c | 8 ++++++++ sound/soc/fsl/fsl_dsp.h | 2 ++ 2 files changed, 10 insertions(+) diff --git a/sound/soc/fsl/fsl_dsp.c b/sound/soc/fsl/fsl_dsp.c index 593fb80ba48b..7a1a067615c7 100644 --- a/sound/soc/fsl/fsl_dsp.c +++ b/sound/soc/fsl/fsl_dsp.c @@ -670,6 +670,12 @@ static void dsp_load_firmware(const struct firmware *fw, void *context) (const void *)image, shdr->sh_size); } else { + /* sh_addr is from DSP view, we need to + * fixup addr because we load the firmware from + * the ARM core side + */ + sh_addr -= dsp_priv->fixup_offset; + memcpy_dsp((void *)(dsp_priv->regs + (sh_addr - dsp_priv->paddr)), (const void *)image, @@ -811,6 +817,8 @@ static int fsl_dsp_probe(struct platform_device *pdev) ret = of_property_read_string(np, "fsl,dsp-firmware", &fw_name); dsp_priv->fw_name = fw_name; + ret = of_property_read_u32(np, "fixup-offset", &dsp_priv->fixup_offset); + platform_set_drvdata(pdev, dsp_priv); pm_runtime_enable(&pdev->dev); diff --git a/sound/soc/fsl/fsl_dsp.h b/sound/soc/fsl/fsl_dsp.h index e87b531fcba5..f39a11dbbf6b 100644 --- a/sound/soc/fsl/fsl_dsp.h +++ b/sound/soc/fsl/fsl_dsp.h @@ -75,6 +75,8 @@ struct fsl_dsp { dma_addr_t dsp_config_phys; int dsp_config_size; + unsigned int fixup_offset; + /* ...proxy data structures */ struct xf_proxy proxy; From 8f8581c48f25c7a103cf580ab4a79af9186f1b10 Mon Sep 17 00:00:00 2001 From: Daniel Baluta Date: Mon, 4 Jun 2018 17:37:20 +0300 Subject: [PATCH 39/78] MLK-17481-4: ASoC: fsl: Don't bail out on OFS_PERIPH error Signed-off-by: Daniel Baluta Reviewed-by: Shengjiu Wang (cherry picked from commit b6fa30e239da2f38cf31508e98a405ef697e233b) --- sound/soc/fsl/fsl_dsp.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/fsl/fsl_dsp.c b/sound/soc/fsl/fsl_dsp.c index 7a1a067615c7..33e19f80327a 100644 --- a/sound/soc/fsl/fsl_dsp.c +++ b/sound/soc/fsl/fsl_dsp.c @@ -799,8 +799,8 @@ static int fsl_dsp_probe(struct platform_device *pdev) ret = imx_sc_misc_set_control(dsp_priv->dsp_ipcHandle, IMX_SC_R_DSP, IMX_SC_C_OFS_PERIPH, 0x5A); if (ret) { - dev_err(&pdev->dev, "Error system address offset of PERIPH\n"); - return -EIO; + dev_err(&pdev->dev, "Error system address offset of PERIPH %d\n", + sciErr); } ret = imx_sc_misc_set_control(dsp_priv->dsp_ipcHandle, IMX_SC_R_DSP, From b6fdfbcf64e42eba8f70717d14b69cbe86e17b00 Mon Sep 17 00:00:00 2001 From: Daniel Baluta Date: Thu, 26 Jul 2018 17:58:10 +0300 Subject: [PATCH 40/78] MLK-19063: ASoC: fsl_dsp: Fix use after free Move client freeing later when no one needs it. This fixes Coverity Issue 3344686. Note that this also fixes a potential memory leak, if proxy happens to be NULL. Reported-by: Ioan-alexandru Palalau Signed-off-by: Daniel Baluta Reviewed-by: Shengjiu Wang (cherry picked from commit a0bb3e2d5a0517e46bdf1eb35eb94ff46fd5b709) --- sound/soc/fsl/fsl_dsp.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/sound/soc/fsl/fsl_dsp.c b/sound/soc/fsl/fsl_dsp.c index 33e19f80327a..7d5a686f4e8d 100644 --- a/sound/soc/fsl/fsl_dsp.c +++ b/sound/soc/fsl/fsl_dsp.c @@ -401,18 +401,18 @@ static int fsl_dsp_close(struct inode *inode, struct file *file) return PTR_ERR(client); 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); - } + /* release all pending messages */ + if (proxy) + xf_msg_free_all(proxy, &client->queue); dsp_priv = (struct fsl_dsp *)client->global; dev = dsp_priv->dev; pm_runtime_put_sync(dev); + /* ...recycle client id and release memory */ + xf_client_free(client); + mutex_lock(&dsp_priv->dsp_mutex); /* decrease reference counter when closing device */ atomic_long_dec(&dsp_priv->refcnt); From ea43dedbf9632fefbfc6d60f209ad7732da01ed5 Mon Sep 17 00:00:00 2001 From: Daniel Baluta Date: Thu, 4 Oct 2018 11:14:02 +0300 Subject: [PATCH 41/78] MLK-18497-1: ASoC: fsl: dsp_proxy: Fix license headers This is a cleanup patch to have all the headers style consistent across DSP driver. Reviewed-by: Cosmin-Gabriel Samoila Signed-off-by: Shengjiu Wang --- sound/soc/fsl/fsl_dsp_proxy.c | 20 +++++--------------- sound/soc/fsl/fsl_dsp_proxy.h | 15 +++++---------- 2 files changed, 10 insertions(+), 25 deletions(-) diff --git a/sound/soc/fsl/fsl_dsp_proxy.c b/sound/soc/fsl/fsl_dsp_proxy.c index 7b1a86d8576c..e78f1d835d53 100644 --- a/sound/soc/fsl/fsl_dsp_proxy.c +++ b/sound/soc/fsl/fsl_dsp_proxy.c @@ -1,23 +1,13 @@ // SPDX-License-Identifier: (GPL-2.0+ OR MIT) -/******************************************************************************* - * - * Copyright (C) 2017 Cadence Design Systems, Inc. - * Copyright 2018 NXP - * - ******************************************************************************/ -/******************************************************************************* - * fsl_dsp_proxy.c - * - * DSP proxy driver - * - * DSP proxy driver is used to transfer messages between dsp driver - * and dsp framework - ******************************************************************************/ +// +// DSP proxy driver transfers messages between DSP driver and DSP framework +// +// Copyright 2018 NXP +// Copyright (C) 2017 Cadence Design Systems, Inc. #include "fsl_dsp_proxy.h" #include "fsl_dsp.h" - /* ...initialize message queue */ void xf_msg_queue_init(struct xf_msg_queue *queue) { diff --git a/sound/soc/fsl/fsl_dsp_proxy.h b/sound/soc/fsl/fsl_dsp_proxy.h index 0942b8d85a6e..131acf3129a7 100644 --- a/sound/soc/fsl/fsl_dsp_proxy.h +++ b/sound/soc/fsl/fsl_dsp_proxy.h @@ -1,15 +1,10 @@ -/* SPDX-License-Identifier: (GPL-2.0+ OR MIT)*/ -/******************************************************************************* +/* SPDX-License-Identifier: (GPL-2.0+ OR MIT) */ +/* + * DSP proxy header - commands/responses from DSP driver to DSP ramework * - * Copyright (c) 2017 Cadence Design Systems, Inc. * Copyright 2018 NXP - * - ************************************************************/ -/************************************************************ - * fsl_dsp_proxy.h - * - * Proxy commmand/response messages - ************************************************************/ + * Copyright (c) 2017 Cadence Design Systems, Inc. + */ #ifndef __FSL_DSP_PROXY_H #define __FSL_DSP_PROXY_H From 9e49bf4e07ed80f9038c5a3e60dfa466a8270220 Mon Sep 17 00:00:00 2001 From: Daniel Baluta Date: Thu, 4 Oct 2018 11:31:28 +0300 Subject: [PATCH 42/78] MLK-18497-2: ASoC: fsl: dsp_proxy: Add missing xf_unlock xf_cmd_send_recv function returns with a lock taken in case of success. Fix this, now! This bug is present since the beginning of time and it didn't show up because no one used xd_cmd_alloc/xf_cmd_free. Reviewed-by: Cosmin-Gabriel Samoila Signed-off-by: Shengjiu Wang --- sound/soc/fsl/fsl_dsp_proxy.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sound/soc/fsl/fsl_dsp_proxy.c b/sound/soc/fsl/fsl_dsp_proxy.c index e78f1d835d53..e55aea78c4a3 100644 --- a/sound/soc/fsl/fsl_dsp_proxy.c +++ b/sound/soc/fsl/fsl_dsp_proxy.c @@ -614,6 +614,7 @@ int xf_cmd_alloc(struct xf_proxy *proxy, void **buffer, u32 length) /* ...free message and release proxy lock */ xf_msg_free(proxy, m); + xf_unlock(&proxy->lock); return ret; } @@ -640,6 +641,7 @@ int xf_cmd_free(struct xf_proxy *proxy, void *buffer, u32 length) /* ...free message and release proxy lock */ xf_msg_free(proxy, m); + xf_unlock(&proxy->lock); return ret; } From 1aeb3e481a292ae78906e5cb0f4f0d8b57f05ad3 Mon Sep 17 00:00:00 2001 From: Daniel Baluta Date: Thu, 4 Oct 2018 11:17:35 +0300 Subject: [PATCH 43/78] MLK-18497-3: ASoC: fsl: dsp_proxy: Add new send/recv helpers This commit adds 3 new function helpers for sending messages to DSP framework and waiting for response. While at it cleanup spaces around struct client fields. Reviewed-by: Cosmin-Gabriel Samoila Signed-off-by: Shengjiu Wang --- sound/soc/fsl/fsl_dsp.h | 15 ++++--- sound/soc/fsl/fsl_dsp_proxy.c | 77 +++++++++++++++++++++++++++++++++++ sound/soc/fsl/fsl_dsp_proxy.h | 25 +++++++++++- 3 files changed, 107 insertions(+), 10 deletions(-) diff --git a/sound/soc/fsl/fsl_dsp.h b/sound/soc/fsl/fsl_dsp.h index f39a11dbbf6b..b4ab6fc1a9d4 100644 --- a/sound/soc/fsl/fsl_dsp.h +++ b/sound/soc/fsl/fsl_dsp.h @@ -22,22 +22,21 @@ struct xf_client { struct xf_proxy *proxy; /* ...allocated proxy client id */ - u32 id; + u32 id; /* ...pending response queue */ - struct xf_msg_queue queue; - + struct xf_msg_queue queue; /* ...response waiting queue */ - wait_queue_head_t wait; + wait_queue_head_t wait; /* ...virtual memory mapping */ - unsigned long vm_start; - + unsigned long vm_start; /* ...counter of memory mappings (no real use of it yet - tbd) */ - atomic_t vm_use; + atomic_t vm_use; /* ...global structure pointer */ - void *global; + void *global; + struct xf_message m; }; union xf_client_link { diff --git a/sound/soc/fsl/fsl_dsp_proxy.c b/sound/soc/fsl/fsl_dsp_proxy.c index e55aea78c4a3..0bf1d233fcf5 100644 --- a/sound/soc/fsl/fsl_dsp_proxy.c +++ b/sound/soc/fsl/fsl_dsp_proxy.c @@ -570,6 +570,27 @@ struct xf_message *xf_cmd_recv(struct xf_proxy *proxy, return m; } +struct xf_message *xf_cmd_recv_timeout(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_timeout(*wq, + (m = xf_msg_received(proxy, queue)) != NULL || !wait, + msecs_to_jiffies(1000)); + if (ret < 0) + return ERR_PTR(-EINTR); + + if (ret == 0) + return ERR_PTR(-ETIMEDOUT); + + /* ...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, @@ -587,6 +608,62 @@ struct xf_message *xf_cmd_send_recv(struct xf_proxy *proxy, return xf_cmd_recv(proxy, &proxy->wait, &proxy->response, 1); } +struct xf_message *xf_cmd_send_recv_wq(struct xf_proxy *proxy, u32 id, + u32 opcode, void *buffer, u32 length, + wait_queue_head_t *wq, + struct xf_msg_queue *queue) +{ + 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, wq, queue, 1); +} + +struct xf_message *xf_cmd_send_recv_complete(struct xf_client *client, + struct xf_proxy *proxy, + u32 id, u32 opcode, void *buffer, + u32 length, + struct work_struct *work, + struct completion *completion) +{ + struct xf_message *m; + int ret; + + /* ...retrieve message handle (take the lock on success) */ + m = xf_msg_available(proxy); + if (!m) + return ERR_PTR(-EBUSY); + + /* ...fill-in message parameters (lock is taken) */ + m->id = id; + m->opcode = opcode; + m->length = length; + m->buffer = buffer; + m->ret = 0; + + init_completion(completion); + + /* ...submit command to the proxy */ + xf_proxy_command(proxy, m); + + schedule_work(work); + + /* ...wait for message reception (take lock on success) */ + ret = wait_for_completion_timeout(completion, + msecs_to_jiffies(1000)); + if (!ret) + return ERR_PTR(-ETIMEDOUT); + + m = &client->m; + + /* ...return message with a lock taken */ + return m; +} /* * Proxy allocate and free memory functions */ diff --git a/sound/soc/fsl/fsl_dsp_proxy.h b/sound/soc/fsl/fsl_dsp_proxy.h index 131acf3129a7..dc54dc2d00ef 100644 --- a/sound/soc/fsl/fsl_dsp_proxy.h +++ b/sound/soc/fsl/fsl_dsp_proxy.h @@ -21,6 +21,8 @@ #define XF_CFG_MESSAGE_POOL_SIZE 256 +struct xf_client; + /******************************************************************************* * Local proxy data ******************************************************************************/ @@ -284,8 +286,8 @@ struct xf_proxy { /* ...shared memory status change processing item */ struct work_struct work; - struct completion cmd_complete; - int is_ready; + struct completion cmd_complete; + int is_ready; /* ...internal lock */ spinlock_t lock; @@ -366,6 +368,25 @@ struct xf_message *xf_cmd_recv(struct xf_proxy *proxy, struct xf_msg_queue *queue, int wait); +struct xf_message* +xf_cmd_recv_timeout(struct xf_proxy *proxy, wait_queue_head_t *wq, + struct xf_msg_queue *queue, int wait); + +struct xf_message* +xf_cmd_send_recv(struct xf_proxy *proxy, u32 id, u32 opcode, + void *buffer, u32 length); + +struct xf_message* +xf_cmd_send_recv_wq(struct xf_proxy *proxy, u32 id, u32 opcode, void *buffer, + u32 length, wait_queue_head_t *wq, + struct xf_msg_queue *queue); + +struct xf_message* +xf_cmd_send_recv_complete(struct xf_client *client, struct xf_proxy *proxy, + u32 id, u32 opcode, void *buffer, u32 length, + struct work_struct *work, + struct completion *completion); + /* ...mu interrupt handle */ irqreturn_t fsl_dsp_mu_isr(int irq, void *dev_id); From 17aa1ae7609a2dbb1e705fb6b4766451662afc49 Mon Sep 17 00:00:00 2001 From: Daniel Baluta Date: Thu, 4 Oct 2018 16:34:29 +0300 Subject: [PATCH 44/78] MLK-18497-4: ASoC: fsl: dsp: Add message buffer pool API Memory is allocated to clients from memory pools. A memory pool allocation is requested to DSP framework via XF_ALLOC command and freed via XF_FREE. Memory pool allocation API offers two functions: * xf_pool_alloc, allocate a number of buffers of given length * xf_pool_free, free memory area allocated for a pool. Once a buffer pool is allocated users can handle buffers using the following API: * xf_buffer_get(pool), gets a buffer from a pool * xf_buffer_put(buf), puts back a buffer into its pool Reviewed-by: Cosmin-Gabriel Samoila Signed-off-by: Shengjiu Wang --- sound/soc/fsl/Makefile | 2 +- sound/soc/fsl/fsl_dsp.h | 3 + sound/soc/fsl/fsl_dsp_pool.c | 150 ++++++++++++++++++++++++++++++++++ sound/soc/fsl/fsl_dsp_pool.h | 113 +++++++++++++++++++++++++ sound/soc/fsl/fsl_dsp_proxy.h | 3 + 5 files changed, 270 insertions(+), 1 deletion(-) create mode 100644 sound/soc/fsl/fsl_dsp_pool.c create mode 100644 sound/soc/fsl/fsl_dsp_pool.h diff --git a/sound/soc/fsl/Makefile b/sound/soc/fsl/Makefile index cb3ea47d507c..ef4d5494265b 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-dsp-objs := fsl_dsp.o fsl_dsp_proxy.o +snd-soc-fsl-dsp-objs := fsl_dsp.o fsl_dsp_proxy.o fsl_dsp_pool.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_dsp.h b/sound/soc/fsl/fsl_dsp.h index b4ab6fc1a9d4..95815fa23c33 100644 --- a/sound/soc/fsl/fsl_dsp.h +++ b/sound/soc/fsl/fsl_dsp.h @@ -37,6 +37,9 @@ struct xf_client { /* ...global structure pointer */ void *global; struct xf_message m; + + struct work_struct work; + struct completion compr_complete; }; union xf_client_link { diff --git a/sound/soc/fsl/fsl_dsp_pool.c b/sound/soc/fsl/fsl_dsp_pool.c new file mode 100644 index 000000000000..637454d97231 --- /dev/null +++ b/sound/soc/fsl/fsl_dsp_pool.c @@ -0,0 +1,150 @@ +// SPDX-License-Identifier: GPL-2.0+ +// +// Xtensa buffer pool API +// +// Copyright 2018 NXP +// Copyright (c) 2012-2013 by Tensilica Inc. + +#include + +#include "fsl_dsp_pool.h" +#include "fsl_dsp.h" + +/* ...allocate buffer pool */ +int xf_pool_alloc(struct xf_client *client, struct xf_proxy *proxy, + u32 number, u32 length, xf_pool_type_t type, + struct xf_pool **pool) +{ + struct xf_pool *p; + struct xf_buffer *b; + void *data; + struct xf_message msg; + struct xf_message *rmsg; + + /* ...basic sanity checks; number of buffers is positive */ + if (number <=0) + return -EINVAL; + + /* ...get properly aligned buffer length */ + length = ALIGN(length, XF_PROXY_ALIGNMENT); + + p = kzalloc(offsetof(struct xf_pool, buffer) + + number * sizeof(struct xf_buffer), GFP_KERNEL); + if(!p) + return -ENOMEM; + + /* ...prepare command parameters */ + msg.id = __XF_MSG_ID(__XF_AP_PROXY(0), __XF_DSP_PROXY(0)); + msg.id = XF_MSG_AP_FROM_USER(msg.id, client->id); + msg.opcode = XF_ALLOC; + msg.length = length * number; + msg.buffer = NULL; + msg.ret = 0; + + /* ...execute command synchronously */ + rmsg = xf_cmd_send_recv_complete(client, proxy, msg.id, msg.opcode, + msg.buffer, msg.length, &client->work, + &client->compr_complete); + if (IS_ERR(rmsg)) { + kfree(p); + return PTR_ERR(rmsg); + } + + p->p = rmsg->buffer; + /* TODO: review cleanup */ + /* xf_msg_free(proxy, rmsg); + * xf_unlock(&proxy->lock); */ + + /* ...if operation is failed, do cleanup */ + /* ...set pool parameters */ + p->number = number, p->length = length; + p->proxy = proxy; + + /* ...create individual buffers and link them into free list */ + for (p->free = b = &p->buffer[0], data = p->p; number > 0; + number--, b++) { + /* ...set address of the buffer (no length there) */ + b->address = data; + + /* ...file buffer into the free list */ + b->link.next = b + 1; + + /* ...advance data pointer in contiguous buffer */ + data += length; + } + + /* ...terminate list of buffers (not too good - tbd) */ + b[-1].link.next = NULL; + + /* ...return buffer pointer */ + *pool = p; + + return 0; +} +/* ...buffer pool destruction */ +int xf_pool_free(struct xf_client *client, struct xf_pool *pool) +{ + struct xf_proxy *proxy; + struct xf_message msg; + struct xf_message *rmsg; + + /* ...basic sanity checks; pool is positive */ + if (pool == NULL) + return -EINVAL; + + /* ...get proxy pointer */ + if ((proxy = pool->proxy) == NULL) + return -EINVAL; + + /* ...prepare command parameters */ + msg.id = __XF_MSG_ID(__XF_AP_PROXY(0), __XF_DSP_PROXY(0)); + msg.id = XF_MSG_AP_FROM_USER(msg.id, client->id); + msg.opcode = XF_FREE; + msg.length = pool->length * pool->number; + msg.buffer = pool->p; + msg.ret = 0; + + /* ...execute command synchronously */ + rmsg = xf_cmd_send_recv_complete(client, proxy, msg.id, msg.opcode, + msg.buffer, msg.length, &client->work, + &client->compr_complete); + kfree(pool); + if (IS_ERR(rmsg)) + return PTR_ERR(rmsg); + + /* TODO: review cleanup */ + /* xf_msg_free(proxy, rmsg); + * xf_unlock(&proxy->lock); */ + + return 0; +} + +/* ...get new buffer from a pool */ +struct xf_buffer *xf_buffer_get(struct xf_pool *pool) +{ + struct xf_buffer *b; + + xf_lock(&pool->proxy->lock); + /* ...take buffer from a head of the free list */ + b = pool->free; + if (b) { + /* ...advance free list head */ + pool->free = b->link.next, b->link.pool = pool; + } + + xf_unlock(&pool->proxy->lock); + return b; +} + +/* ...return buffer back to pool */ +void xf_buffer_put(struct xf_buffer *buffer) +{ + struct xf_pool *pool = buffer->link.pool; + + xf_lock(&pool->proxy->lock); + /* ...use global proxy lock for pool operations protection */ + /* ...put buffer back to a pool */ + buffer->link.next = pool->free, pool->free = buffer; + + xf_unlock(&pool->proxy->lock); +} diff --git a/sound/soc/fsl/fsl_dsp_pool.h b/sound/soc/fsl/fsl_dsp_pool.h new file mode 100644 index 000000000000..4a56262faf7f --- /dev/null +++ b/sound/soc/fsl/fsl_dsp_pool.h @@ -0,0 +1,113 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * Xtensa buffer pool API header + * + * Copyright 2018 NXP + * Copyright (c) 2012-2013 by Tensilica Inc + */ +#ifndef FSL_DSP_POOL_H +#define FSL_DSP_POOL_H + +#include +#include "fsl_dsp_proxy.h" + +/* ...buffer pool type */ +typedef u32 xf_pool_type_t; + +/* ...previous declaration of struct */ +struct xf_buffer; +struct xf_pool; +struct xf_handle; +struct xf_message; +struct xf_client; + +/* ...response callback */ +typedef void (*xf_response_cb)(struct xf_handle *h, struct xf_message *msg); + +/* ...buffer pool type */ +enum xf_pool_type { + XF_POOL_AUX = 0, + XF_POOL_INPUT = 1, + XF_POOL_OUTPUT = 2 +}; + +/* ...buffer link pointer */ +union xf_buffer_link { + /* ...pointer to next free buffer in a pool (for free buffer) */ + struct xf_buffer *next; + /* ...reference to a buffer pool (for allocated buffer) */ + struct xf_pool *pool; +}; + +/* ...buffer descriptor */ +struct xf_buffer { + /* ...virtual address of contiguous buffer */ + void *address; + /* ...link pointer */ + union xf_buffer_link link; +}; + +/* ...buffer pool */ +struct xf_pool { + /* ...reference to proxy data */ + struct xf_proxy *proxy; + /* ...length of individual buffer in a pool */ + u32 length; + /* ...number of buffers in a pool */ + u32 number; + /* ...pointer to pool memory */ + void *p; + /* ...pointer to first free buffer in a pool */ + struct xf_buffer *free; + /* ...individual buffers */ + struct xf_buffer buffer[0]; +}; + +/* component handle */ +struct xf_handle { + /* ...reference to proxy data */ + struct xf_proxy *proxy; + /* ...auxiliary control buffer for control transactions */ + struct xf_buffer *aux; + /* ...global client-id of the component */ + u32 id; + /* ...local client number (think about merging into "id" field - tbd) */ + u32 client; + /* ...response processing hook */ + xf_response_cb response; +}; + +/* ...accessor to buffer data */ +static inline void *xf_buffer_data(struct xf_buffer *buffer) +{ + return buffer->address; +} + +/* ...length of buffer data */ +static inline size_t xf_buffer_length(struct xf_buffer *buffer) +{ + struct xf_pool *pool = buffer->link.pool; + + return (size_t)pool->length; +} + +/* ...component client-id (global scope) */ +static inline u32 xf_handle_id(struct xf_handle *handle) +{ + return handle->id; +} + +/* ...pointer to auxiliary buffer */ +static inline void *xf_handle_aux(struct xf_handle *handle) +{ + return xf_buffer_data(handle->aux); +} + +int xf_pool_alloc(struct xf_client *client, struct xf_proxy *proxy, u32 number, + u32 length, xf_pool_type_t type, struct xf_pool **pool); +int xf_pool_free(struct xf_client *client, struct xf_pool *pool); + +struct xf_buffer *xf_buffer_get(struct xf_pool *pool); +void xf_buffer_put(struct xf_buffer *buffer); + +#endif /* FSL_DSP_POOL_H */ diff --git a/sound/soc/fsl/fsl_dsp_proxy.h b/sound/soc/fsl/fsl_dsp_proxy.h index dc54dc2d00ef..78b033719eb8 100644 --- a/sound/soc/fsl/fsl_dsp_proxy.h +++ b/sound/soc/fsl/fsl_dsp_proxy.h @@ -309,6 +309,9 @@ struct xf_proxy { /* ...pointer to first free message in the pool */ struct xf_message *free; + + /* ...auxiliary buffer pool for clients */ + struct xf_pool *aux; }; union icm_header_t { From d2164cd4e6df01e34502d13785f5d38001062a53 Mon Sep 17 00:00:00 2001 From: Daniel Baluta Date: Thu, 4 Oct 2018 16:05:45 +0300 Subject: [PATCH 45/78] MLK-18497-5: ASoC: fsl: dsp_proxy: Introduce client API This will allow DSP driver to create/destroy a client on DSP audio-framework proxy. Registering a client on remote DSP proxy means creating a component. The implementation is similar with userspace application proxy implementation. Reviewed-by: Cosmin-Gabriel Samoila Signed-off-by: Shengjiu Wang --- sound/soc/fsl/fsl_dsp_proxy.c | 87 +++++++++++++++++++++++++++ sound/soc/fsl/fsl_dsp_proxy.h | 108 ++++++++++++++++++++++++++++++++-- 2 files changed, 190 insertions(+), 5 deletions(-) diff --git a/sound/soc/fsl/fsl_dsp_proxy.c b/sound/soc/fsl/fsl_dsp_proxy.c index 0bf1d233fcf5..1f4390487c78 100644 --- a/sound/soc/fsl/fsl_dsp_proxy.c +++ b/sound/soc/fsl/fsl_dsp_proxy.c @@ -765,3 +765,90 @@ int xf_cmd_send_resume(struct xf_proxy *proxy) return ret; } + +/* ...open component handle */ +int xf_open(struct xf_client *client, struct xf_proxy *proxy, + struct xf_handle *handle, const char *id, u32 core, + xf_response_cb response) +{ + void *b; + struct xf_message msg; + struct xf_message *rmsg; + + /* ...retrieve auxiliary control buffer from proxy - need I */ + handle->aux = xf_buffer_get(proxy->aux); + + b = xf_handle_aux(handle); + + msg.id = __XF_MSG_ID(__XF_AP_PROXY(0), __XF_DSP_PROXY(0)); + msg.id = XF_MSG_AP_FROM_USER(msg.id, client->id); + msg.opcode = XF_REGISTER; + msg.buffer = b; + msg.length = strlen(id) + 1; + msg.ret = 0; + + /* ...copy component identifier */ + memcpy(b, (void *)id, xf_buffer_length(handle->aux)); + + /* ...execute command synchronously */ + rmsg = xf_cmd_send_recv_complete(client, proxy, msg.id, msg.opcode, + msg.buffer, msg.length, &client->work, + &client->compr_complete); + + if (IS_ERR(rmsg)) { + xf_buffer_put(handle->aux), handle->aux = NULL; + return PTR_ERR(rmsg); + } + /* ...save received component global client-id */ + handle->id = XF_MSG_SRC(rmsg->id); + /* TODO: review cleanup */ + /* xf_msg_free(proxy, rmsg); + * xf_unlock(&proxy->lock); */ + + /* ...if failed, release buffer handle */ + /* ...operation completed successfully; assign handle data */ + handle->response = response; + handle->proxy = proxy; + + return 0; +} + +/* ...close component handle */ +int xf_close(struct xf_client *client, struct xf_handle *handle) +{ + struct xf_proxy *proxy = handle->proxy; + struct xf_message msg; + struct xf_message *rmsg; + + /* ...do I need to take component lock here? guess no - tbd */ + + /* ...buffers and stuff? - tbd */ + + /* ...acquire global proxy lock */ + /* ...unregister component from remote DSP proxy (ignore result code) */ + + msg.id = __XF_MSG_ID(__XF_AP_PROXY(0), handle->id); + msg.id = XF_MSG_AP_FROM_USER(msg.id, client->id); + msg.opcode = XF_UNREGISTER; + msg.buffer = NULL; + msg.length = 0; + msg.ret = 0; + + /* ...execute command synchronously */ + rmsg = xf_cmd_send_recv_complete(client, proxy, msg.id, msg.opcode, + msg.buffer, msg.length, &client->work, + &client->compr_complete); + + if (IS_ERR(rmsg)) { + xf_buffer_put(handle->aux), handle->aux = NULL; + return PTR_ERR(rmsg); + } + /* TODO: review cleanup */ + /* xf_msg_free(proxy, rmsg); + * xf_unlock(&proxy->lock); */ + + /* ...wipe out proxy pointer */ + handle->proxy = NULL; + + return 0; +} diff --git a/sound/soc/fsl/fsl_dsp_proxy.h b/sound/soc/fsl/fsl_dsp_proxy.h index 78b033719eb8..fabcf768fb88 100644 --- a/sound/soc/fsl/fsl_dsp_proxy.h +++ b/sound/soc/fsl/fsl_dsp_proxy.h @@ -19,6 +19,7 @@ #include #include +#include "fsl_dsp_pool.h" #define XF_CFG_MESSAGE_POOL_SIZE 256 struct xf_client; @@ -27,6 +28,10 @@ struct xf_client; * Local proxy data ******************************************************************************/ +struct xf_message; +struct xf_handle; +typedef void (*xf_response_cb)(struct xf_handle *h, struct xf_message *msg); + /* ...execution message */ struct xf_message { /* ...pointer to next message in a list */ @@ -84,8 +89,10 @@ enum icm_action_t { /* ...adjust IPC client of message going from user-space */ #define XF_MSG_AP_FROM_USER(id, client) (((id) & ~(0xF << 2)) | (client << 2)) -/* ...message id contains source and destination ports specification */ -#define __XF_MSG_ID(src, dst) (((src) & 0xFFFF) | (((dst) & 0xFFFF) << 16)) + +#define __XF_PORT_SPEC(core, id, port) ((core) | ((id) << 2) | ((port) << 8)) +#define __XF_PORT_SPEC2(id, port) ((id) | ((port) << 8)) + /* ...wipe out IPC client from message going to user-space */ #define XF_MSG_AP_TO_USER(id) ((id) & ~(0xF << 18)) @@ -94,13 +101,17 @@ enum icm_action_t { /* ...message id contains source and destination ports specification */ #define __XF_MSG_ID(src, dst) (((src) & 0xFFFF) | (((dst) & 0xFFFF) << 16)) +#define XF_MSG_SRC(id) (((id) >> 0) & 0xFFFF) +#define XF_MSG_SRC_CORE(id) (((id) >> 0) & 0x3) #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) +#define XF_AP_IPC_CLIENT(id) (((id) >> 18) & 0xF) +#define XF_AP_CLIENT(id) (((id) >> 22) & 0x1FF) +#define __XF_AP_PROXY(core) ((core) | 0x8000) +#define __XF_DSP_PROXY(core) ((core) | 0x8000) +#define __XF_AP_CLIENT(core, client) ((core) | ((client) << 6) | 0x8000) /* ...opcode composition with command/response data tags */ #define __XF_OPCODE(c, r, op) (((c) << 31) | ((r) << 30) | ((op) & 0x3F)) @@ -417,4 +428,91 @@ void *xf_proxy_a2b(struct xf_proxy *proxy, u32 address); int xf_cmd_send_suspend(struct xf_proxy *proxy); int xf_cmd_send_resume(struct xf_proxy *proxy); +int xf_cmd_alloc(struct xf_proxy *proxy, void **buffer, u32 length); +int xf_cmd_free(struct xf_proxy *proxy, void *buffer, u32 length); + +int xf_open(struct xf_client *client, struct xf_proxy *proxy, + struct xf_handle *handle, const char *id, u32 core, + xf_response_cb response); + +int xf_close(struct xf_client *client, struct xf_handle *handle); + + + +/******************************************************************************* + * Opcode composition + ******************************************************************************/ + +/* ...opcode composition with command/response data tags */ +#define __XF_OPCODE(c, r, op) (((c) << 31) | ((r) << 30) | ((op) & 0x3F)) + +/* ...accessors */ +#define XF_OPCODE_CDATA(opcode) ((opcode) & (1 << 31)) +#define XF_OPCODE_RDATA(opcode) ((opcode) & (1 << 30)) +#define XF_OPCODE_TYPE(opcode) ((opcode) & (0x3F)) + +/******************************************************************************* + * Opcode types + ******************************************************************************/ + +/* ...unregister client */ +#define XF_UNREGISTER __XF_OPCODE(0, 0, 0) + +/* ...register client at proxy */ +#define XF_REGISTER __XF_OPCODE(1, 0, 1) + +/* ...port routing command */ +#define XF_ROUTE __XF_OPCODE(1, 0, 2) + +/* ...port unrouting command */ +#define XF_UNROUTE __XF_OPCODE(1, 0, 3) + +/* ...shared buffer allocation */ +#define XF_ALLOC __XF_OPCODE(0, 0, 4) + +/* ...shared buffer freeing */ +#define XF_FREE __XF_OPCODE(0, 0, 5) + +/* ...set component parameters */ +#define XF_SET_PARAM __XF_OPCODE(1, 0, 6) + +/* ...get component parameters */ +#define XF_GET_PARAM __XF_OPCODE(1, 1, 7) + +/* ...input buffer reception */ +#define XF_EMPTY_THIS_BUFFER __XF_OPCODE(1, 0, 8) + +/* ...output buffer reception */ +#define XF_FILL_THIS_BUFFER __XF_OPCODE(0, 1, 9) + +/* ...flush specific port */ +#define XF_FLUSH __XF_OPCODE(0, 0, 10) + +/* ...start component operation */ +#define XF_START __XF_OPCODE(0, 0, 11) + +/* ...stop component operation */ +#define XF_STOP __XF_OPCODE(0, 0, 12) + +/* ...pause component operation */ +#define XF_PAUSE __XF_OPCODE(0, 0, 13) + +/* ...resume component operation */ +#define XF_RESUME __XF_OPCODE(0, 0, 14) + +/* ...resume component operation */ +#define XF_SUSPEND __XF_OPCODE(0, 0, 15) + +/* ...load lib for component operation */ +#define XF_LOAD_LIB __XF_OPCODE(0, 0, 16) + +/* ...unload lib for component operation */ +#define XF_UNLOAD_LIB __XF_OPCODE(0, 0, 17) + +/* ...component output eos operation */ +#define XF_OUTPUT_EOS __XF_OPCODE(0, 0, 18) + +/* ...total amount of supported decoder commands */ +#define __XF_OP_NUM 19 + #endif From 93bc6108aa6708b411d28302dea98029a6acb5e1 Mon Sep 17 00:00:00 2001 From: Daniel Baluta Date: Wed, 3 Oct 2018 19:27:58 +0300 Subject: [PATCH 46/78] MLK-18497-6: ASoC: fsl: dsp: Add Xtensa library handling API This is based on RF-2016.4-linux package received from Cadence and introduce the API for loading shared libraries into memory. Based on this we create xf_load_lib/xf_load_unlib functions which are used to tell DSP framework that codec libraries are mapped in memory and it can start using them. Reviewed-by: Cosmin-Gabriel Samoila Signed-off-by: Shengjiu Wang --- include/uapi/linux/mxc_dsp.h | 3 + sound/soc/fsl/Makefile | 3 +- sound/soc/fsl/fsl_dsp.h | 1 + sound/soc/fsl/fsl_dsp_library_load.c | 645 +++++++++++++++++++++++++++ sound/soc/fsl/fsl_dsp_library_load.h | 92 ++++ 5 files changed, 743 insertions(+), 1 deletion(-) create mode 100644 sound/soc/fsl/fsl_dsp_library_load.c create mode 100644 sound/soc/fsl/fsl_dsp_library_load.h diff --git a/include/uapi/linux/mxc_dsp.h b/include/uapi/linux/mxc_dsp.h index aa721f31d403..5820acc2e386 100644 --- a/include/uapi/linux/mxc_dsp.h +++ b/include/uapi/linux/mxc_dsp.h @@ -32,6 +32,9 @@ #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 DSP_LOAD_LIB _IOW(DSP_IOC_MAGIC, 5, unsigned int) +#define DSP_UNLOAD_LIB _IOW(DSP_IOC_MAGIC, 6, unsigned int) + #define CODEC_MP3_DEC 1 #define CODEC_AAC_DEC 2 diff --git a/sound/soc/fsl/Makefile b/sound/soc/fsl/Makefile index ef4d5494265b..68a2f9aae71c 100644 --- a/sound/soc/fsl/Makefile +++ b/sound/soc/fsl/Makefile @@ -15,7 +15,8 @@ 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-dsp-objs := fsl_dsp.o fsl_dsp_proxy.o fsl_dsp_pool.o +snd-soc-fsl-dsp-objs := fsl_dsp.o fsl_dsp_proxy.o fsl_dsp_pool.o \ + fsl_dsp_library_load.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_dsp.h b/sound/soc/fsl/fsl_dsp.h index 95815fa23c33..9ee7e025ed7f 100644 --- a/sound/soc/fsl/fsl_dsp.h +++ b/sound/soc/fsl/fsl_dsp.h @@ -5,6 +5,7 @@ * */ +#include #include #include "fsl_dsp_proxy.h" diff --git a/sound/soc/fsl/fsl_dsp_library_load.c b/sound/soc/fsl/fsl_dsp_library_load.c new file mode 100644 index 000000000000..37bce3a289b5 --- /dev/null +++ b/sound/soc/fsl/fsl_dsp_library_load.c @@ -0,0 +1,645 @@ +// SPDX-License-Identifier: GPL-2.0+ +// Copyright 2018 NXP +// Copyright (c) 2012-2013 by Tensilica Inc. + +#include +#include +#include + +#include "fsl_dsp.h" +#include "fsl_dsp_library_load.h" + +static Elf32_Half xtlib_host_half(Elf32_Half v, int byteswap) +{ + return (byteswap) ? (v >> 8) | (v << 8) : v; +} + +static 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; +} + +static int xtlib_verify_magic(Elf32_Ehdr *header, + struct lib_info *lib_info) +{ + struct xtlib_loader_globals *xtlib_globals = + &lib_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 0; +} + +static void xtlib_load_seg(Elf32_Phdr *pheader, void *src_addr, xt_ptr dst_addr, + struct lib_info *lib_info) +{ + struct xtlib_loader_globals *xtlib_globals = + &lib_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; + unsigned int i; + char *src_back, *dst_back; + + void *zero_addr = (void *)dst_addr + bytes_to_copy; + + if (bytes_to_copy > 0) { + // memcpy((void *)(dst_addr), src_addr, bytes_to_copy); + src_back = (char *)src_addr; + dst_back = (char *)dst_addr; + for (i = 0; i < bytes_to_copy; i++) + *dst_back++ = *src_back++; + } + + if (bytes_to_zero > 0) { + // memset(zero_addr, 0, bytes_to_zero); + dst_back = (char *)zero_addr; + for (i = 0; i < bytes_to_zero; i++) + *dst_back++ = 0; + } +} + +#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) +{ + return (xt_ptr)(((xt_uint)ptr + align - 1) & ~(align - 1)); +} + +static xt_ptr xt_ptr_offs(xt_ptr base, Elf32_Word offs, + struct lib_info *lib_info) +{ + struct xtlib_loader_globals *xtlib_globals = + &lib_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 lib_info *lib_info) +{ + char *base_addr = (char *)eheader; + struct xtlib_loader_globals *xtlib_globals = + &lib_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 lib_info *lib_info) +{ + struct xtlib_loader_globals *xtlib_globals = + &lib_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 lib_info *lib_info) +{ + struct xtlib_loader_globals *xtlib_globals = + &lib_info->xtlib_globals; + + if (xtlib_verify_magic(header, lib_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 lib_info *lib_info) +{ + struct xtlib_loader_globals *xtlib_globals = + &lib_info->xtlib_globals; + Elf32_Phdr *pheader; + int err = validate_dynamic(header, lib_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; +} + +static unsigned int +xtlib_split_pi_library_size(struct xtlib_packaged_library *library, + unsigned int *code_size, + unsigned int *data_size, + struct lib_info *lib_info) +{ + struct xtlib_loader_globals *xtlib_globals = + &lib_info->xtlib_globals; + Elf32_Phdr *pheader; + Elf32_Ehdr *header = (Elf32_Ehdr *)library; + int align; + int err = validate_dynamic_splitload(header, lib_info); + + if (err != XTLIB_NO_ERR) { + xtlib_globals->err = err; + return err; + } + + align = find_align(header, lib_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 lib_info *lib_info) +{ + unsigned int jmprel = 0; + unsigned int pltrelsz = 0; + struct xtlib_loader_globals *xtlib_globals = + &lib_info->xtlib_globals; + Elf32_Dyn *dyn_entry = find_dynamic_info(eheader, lib_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, lib_info); + + info->align = xtlib_xt_word(find_align(eheader, lib_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, lib_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, lib_info); + break; + case DT_FINI: + info->fini = xt_ptr_offs(dst_addr, + dyn_entry->d_un.d_ptr, lib_info); + break; + case DT_HASH: + info->hash = xt_ptr_offs(dst_data_addr, + dyn_entry->d_un.d_ptr, lib_info); + break; + case DT_SYMTAB: + info->symtab = xt_ptr_offs(dst_data_addr, + dyn_entry->d_un.d_ptr, lib_info); + break; + case DT_STRTAB: + info->strtab = xt_ptr_offs(dst_data_addr, + dyn_entry->d_un.d_ptr, lib_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, lib_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 *info, + struct lib_info *lib_info) +{ + struct xtlib_loader_globals *xtlib_globals = + &lib_info->xtlib_globals; + Elf32_Ehdr *header = (Elf32_Ehdr *)library; + Elf32_Phdr *pheader; + unsigned int align; + int err = validate_dynamic_splitload(header, lib_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, lib_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); + lib_info->code_buf_virt += (destination_code_address - + destination_code_address_back); + lib_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), + info, + lib_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)lib_info->code_buf_virt, + lib_info); + + if (info->text_addr == 0) + 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)lib_info->data_buf_virt + + xtlib_host_word(pheader[1].p_paddr, + xtlib_globals->byteswap), + lib_info); + + if (err != XTLIB_NO_ERR) { + xtlib_globals->err = err; + return 0; + } + + return (xt_ptr)xtlib_host_word((Elf32_Word)info->start_sym, + xtlib_globals->byteswap); +} + +static 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 *info, + struct lib_info *lib_info) +{ + return xtlib_load_split_pi_library_common(library, + destination_code_address, + destination_data_address, + info, + lib_info); +} + +static long +load_dpu_with_library(struct xf_client *client, struct xf_proxy *proxy, + struct lib_info *lib_info) +{ + struct fsl_dsp *dsp_priv = container_of(proxy, struct fsl_dsp, proxy); + unsigned char *srambuf; + struct lib_dnld_info_t dpulib; + struct file *file; + struct xf_buffer *buf; + Elf32_Phdr *pheader; + Elf32_Ehdr *header; + loff_t pos = 0; + unsigned int align; + int filesize = 0; + long ret_val = 0; + + file = filp_open(lib_info->filename, O_RDONLY, 0); + if (IS_ERR(file)) + return PTR_ERR(file); + + vfs_llseek(file, 0, SEEK_END); + filesize = (int)file->f_pos; + + srambuf = kmalloc(filesize, GFP_KERNEL); + if (!srambuf) + return -ENOMEM; + + vfs_llseek(file, 0, SEEK_SET); + kernel_read(file, srambuf, filesize, &pos); + filp_close(file, NULL); + + ret_val = xtlib_split_pi_library_size( + (struct xtlib_packaged_library *)(srambuf), + (unsigned int *)&dpulib.size_code, + (unsigned int *)&dpulib.size_data, + lib_info); + if (ret_val != XTLIB_NO_ERR) + return -EINVAL; + + lib_info->code_buf_size = dpulib.size_code; + lib_info->data_buf_size = dpulib.size_data; + + header = (Elf32_Ehdr *)srambuf; + pheader = (Elf32_Phdr *)((char *)srambuf + + xtlib_host_word(header->e_phoff, + lib_info->xtlib_globals.byteswap)); + + align = find_align(header, lib_info); + ret_val = xf_pool_alloc(client, proxy, 1, dpulib.size_code + align, + XF_POOL_AUX, &lib_info->code_section_pool); + if (ret_val) { + kfree(srambuf); + pr_err("Allocation failure for loading code section\n"); + return -ENOMEM; + } + + ret_val = xf_pool_alloc(client, proxy, 1, + dpulib.size_data + pheader[1].p_paddr + align, + XF_POOL_AUX, &lib_info->data_section_pool); + if (ret_val) { + kfree(srambuf); + pr_err("Allocation failure for loading data section\n"); + return -ENOMEM; + } + + buf = xf_buffer_get(lib_info->code_section_pool); + lib_info->code_buf_virt = xf_buffer_data(buf); + lib_info->code_buf_phys = ((u64)xf_buffer_data(buf) - + (u64)dsp_priv->scratch_buf_virt) + + dsp_priv->scratch_buf_phys; + lib_info->code_buf_size = dpulib.size_code + align; + xf_buffer_put(buf); + + buf = xf_buffer_get(lib_info->data_section_pool); + lib_info->data_buf_virt = xf_buffer_data(buf); + lib_info->data_buf_phys = ((u64)xf_buffer_data(buf) - + (u64)dsp_priv->scratch_buf_virt) + + dsp_priv->scratch_buf_phys; + lib_info->data_buf_size = dpulib.size_data + align + pheader[1].p_paddr; + xf_buffer_put(buf); + + dpulib.pbuf_code = (unsigned long)lib_info->code_buf_phys; + dpulib.pbuf_data = (unsigned long)lib_info->data_buf_phys; + + dpulib.ppil_inf = &lib_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, + (void *)lib_info); + kfree(srambuf); + + return ret_val; +} + +static long +unload_dpu_with_library(struct xf_client *client, struct xf_proxy *proxy, + struct lib_info *lib_info) +{ + xf_pool_free(client, lib_info->code_section_pool); + xf_pool_free(client, lib_info->data_section_pool); + + return 0; +} + +long xf_load_lib(struct xf_client *client, + struct xf_handle *handle, struct lib_info *lib_info) +{ + void *b = xf_handle_aux(handle); + struct icm_xtlib_pil_info icm_info; + struct xf_proxy *proxy = handle->proxy; + struct xf_message msg; + struct xf_message *rmsg; + long ret_val; + + ret_val = load_dpu_with_library(client, proxy, lib_info); + if (ret_val) + return ret_val; + + memcpy((void *)(&icm_info.pil_info), (void *)(&lib_info->pil_info), + sizeof(struct xtlib_pil_info)); + + icm_info.lib_type = lib_info->lib_type; + + /* ...set message parameters */ + msg.id = __XF_MSG_ID(__XF_AP_CLIENT(0, 0), __XF_PORT_SPEC2(handle->id, 0)); + msg.id = XF_MSG_AP_FROM_USER(msg.id, client->id); + msg.opcode = XF_LOAD_LIB; + msg.buffer = b; + msg.length = sizeof(struct icm_xtlib_pil_info); + msg.ret = 0; + + /* ...copy lib info */ + memcpy(b, (void *)&icm_info, xf_buffer_length(handle->aux)); + + /* ...execute command synchronously */ + rmsg = xf_cmd_send_recv_complete(client, proxy, msg.id, msg.opcode, + msg.buffer, msg.length, &client->work, + &client->compr_complete); + if (IS_ERR(rmsg)) + return PTR_ERR(rmsg); + +// xf_msg_free(proxy, rmsg); +// xf_unlock(&proxy->lock); + + return 0; +} + +long xf_unload_lib(struct xf_client *client, struct xf_handle *handle, struct lib_info *lib_info) +{ + void *b = xf_handle_aux(handle); + struct xf_proxy *proxy = handle->proxy; + struct xf_message msg; + struct xf_message *rmsg; + struct icm_xtlib_pil_info icm_info; + + memset((void *)&icm_info, 0, sizeof(struct icm_xtlib_pil_info)); + icm_info.lib_type = lib_info->lib_type; + + /* ...set message parameters */ + msg.id = __XF_MSG_ID(__XF_AP_CLIENT(0, 0),__XF_PORT_SPEC2(handle->id, 0)); + msg.id = XF_MSG_AP_FROM_USER(msg.id, client->id); + msg.opcode = XF_UNLOAD_LIB; + msg.buffer = b; + msg.length = sizeof(struct icm_xtlib_pil_info); + msg.ret = 0; + + /* ...copy lib info */ + memcpy(b, (void *)&icm_info, xf_buffer_length(handle->aux)); + + /* ...execute command synchronously */ + rmsg = xf_cmd_send_recv_complete(client, proxy, msg.id, msg.opcode, + msg.buffer, msg.length, &client->work, + &client->compr_complete); + if (IS_ERR(rmsg)) + return PTR_ERR(rmsg); + +// xf_msg_free(proxy, rmsg); +// xf_unlock(&proxy->lock); + + return unload_dpu_with_library(client, proxy, lib_info); +} diff --git a/sound/soc/fsl/fsl_dsp_library_load.h b/sound/soc/fsl/fsl_dsp_library_load.h new file mode 100644 index 000000000000..8c14dda20b27 --- /dev/null +++ b/sound/soc/fsl/fsl_dsp_library_load.h @@ -0,0 +1,92 @@ +// SPDX-License-Identifier: GPL-2.0+ +// Copyright 2018 NXP +// Copyright (c) 2012-2013 by Tensilica Inc. + +#ifndef FSL_DSP_LIBRARY_LOAD_H +#define FSL_DSP_LIBRARY_LOAD_H + +#include "fsl_dsp_pool.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 + +struct xtlib_packaged_library; + +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 +}; + +enum lib_type { + DSP_CODEC_LIB = 1, + DSP_CODEC_WRAP_LIB +}; + +struct xtlib_loader_globals { + int err; + int byteswap; +}; + +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; + unsigned int lib_type; +}; + +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. */ +}; + +struct lib_info { + struct xtlib_pil_info pil_info; + struct xtlib_loader_globals xtlib_globals; + + struct xf_pool *code_section_pool; + struct xf_pool *data_section_pool; + + void *code_buf_virt; + unsigned int code_buf_phys; + unsigned int code_buf_size; + void *data_buf_virt; + unsigned int data_buf_phys; + unsigned int data_buf_size; + + const char *filename; + unsigned int lib_type; +}; + +long xf_load_lib(struct xf_client *client, struct xf_handle *handle, struct lib_info *lib_info); +long xf_unload_lib(struct xf_client *client, struct xf_handle *handle, struct lib_info *lib_info); + +#endif From 67f631a2d6e93ae80dfdbe2a7cc83874ab5d9749 Mon Sep 17 00:00:00 2001 From: Daniel Baluta Date: Thu, 4 Oct 2018 12:16:42 +0300 Subject: [PATCH 47/78] MLK-18497-7: ASoC: fsl: xaf_afi: Introduce component API This is based on Xtensa Audio framework userspace implemention API. Reviewed-by: Cosmin-Gabriel Samoila Signed-off-by: Shengjiu Wang --- include/uapi/linux/mxc_dsp.h | 3 + sound/soc/fsl/Makefile | 2 +- sound/soc/fsl/fsl_dsp_xaf_api.c | 473 ++++++++++++++++++++++++++++++++ sound/soc/fsl/fsl_dsp_xaf_api.h | 134 +++++++++ 4 files changed, 611 insertions(+), 1 deletion(-) create mode 100644 sound/soc/fsl/fsl_dsp_xaf_api.c create mode 100644 sound/soc/fsl/fsl_dsp_xaf_api.h diff --git a/include/uapi/linux/mxc_dsp.h b/include/uapi/linux/mxc_dsp.h index 5820acc2e386..040681cc39c8 100644 --- a/include/uapi/linux/mxc_dsp.h +++ b/include/uapi/linux/mxc_dsp.h @@ -46,6 +46,9 @@ #define CODEC_SBC_ENC 8 #define CODEC_DEMO_DEC 9 +#define RENDER_ESAI 0x10 +#define RENDER_SAI 0x11 + enum DSP_ERROR_TYPE { XA_SUCCESS = 0, diff --git a/sound/soc/fsl/Makefile b/sound/soc/fsl/Makefile index 68a2f9aae71c..2c7f0dd75b8b 100644 --- a/sound/soc/fsl/Makefile +++ b/sound/soc/fsl/Makefile @@ -16,7 +16,7 @@ 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-dsp-objs := fsl_dsp.o fsl_dsp_proxy.o fsl_dsp_pool.o \ - fsl_dsp_library_load.o + fsl_dsp_library_load.o fsl_dsp_xaf_api.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_dsp_xaf_api.c b/sound/soc/fsl/fsl_dsp_xaf_api.c new file mode 100644 index 000000000000..503503a28922 --- /dev/null +++ b/sound/soc/fsl/fsl_dsp_xaf_api.c @@ -0,0 +1,473 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR MIT) +// +// Xtensa Audio Framework API for communication with DSP +// +// Copyright (C) 2017 Cadence Design Systems, Inc. +// Copyright 2018 NXP + +#include "fsl_dsp.h" +#include "fsl_dsp_xaf_api.h" + +/* ...send a command message to component */ +int xf_command(struct xf_client *client, struct xf_handle *handle, + u32 port, u32 opcode, void *buffer, u32 length) +{ + struct xf_proxy *proxy = handle->proxy; + struct xf_message msg; + + /* ...fill-in message parameters */ + msg.id = __XF_MSG_ID(__XF_AP_CLIENT(0, 0), + __XF_PORT_SPEC2(handle->id, port)); + msg.id = XF_MSG_AP_FROM_USER(msg.id, client->id); + msg.opcode = opcode; + msg.length = length; + msg.buffer = buffer; + msg.ret = 0; + + /* ...execute command synchronously */ + return xf_cmd_send(proxy, msg.id, msg.opcode, msg.buffer, msg.length); +} + +int xaf_comp_set_config(struct xf_client *client, struct xaf_comp *p_comp, + u32 num_param, void *p_param) +{ + struct xf_handle *p_handle; + struct xf_message msg; + struct xf_message *rmsg; + struct xf_set_param_msg *smsg; + struct xf_set_param_msg *param = (struct xf_set_param_msg *)p_param; + struct xf_proxy *proxy; + u32 i; + + p_handle = &p_comp->handle; + proxy = p_handle->proxy; + + /* ...set persistent stream characteristics */ + smsg = xf_buffer_data(p_handle->aux); + + for (i = 0; i < num_param; i++) { + smsg[i].id = param[i].id; + smsg[i].value = param[i].value; + } + + /* ...set command parameters */ + msg.id = __XF_MSG_ID(__XF_AP_CLIENT(0, 0), + __XF_PORT_SPEC2(p_handle->id, 0)); + msg.id = XF_MSG_AP_FROM_USER(msg.id, client->id); + msg.opcode = XF_SET_PARAM; + msg.length = sizeof(*smsg) * num_param; + msg.buffer = smsg; + msg.ret = 0; + + /* ...execute command synchronously */ + rmsg = xf_cmd_send_recv_complete(client, proxy, msg.id, msg.opcode, + msg.buffer, msg.length, &client->work, + &client->compr_complete); + + if(IS_ERR(rmsg)) + return PTR_ERR(rmsg); + /* ...save received component global client-id */ + /* TODO: review cleanup */ + /* xf_msg_free(proxy, rmsg); + * xf_unlock(&proxy->lock); + */ + + /* ...make sure response is expected */ + if ((rmsg->opcode != XF_SET_PARAM) || (rmsg->buffer != smsg)) { + return -EPIPE; + } + + return 0; +} + +int xaf_comp_get_config(struct xf_client *client, struct xaf_comp *p_comp, + u32 num_param, void *p_param) +{ + + struct xf_handle *p_handle; + struct xf_message msg; + struct xf_message *rmsg; + struct xf_get_param_msg *smsg; + struct xf_get_param_msg *param = (struct xf_get_param_msg *)p_param; + struct xf_proxy *proxy; + u32 i; + + p_handle = &p_comp->handle; + proxy = p_handle->proxy; + + /* ...set persistent stream characteristics */ + smsg = xf_buffer_data(p_handle->aux); + + for (i = 0; i < num_param; i++) + smsg[i].id = param[i].id; + + + msg.id = __XF_MSG_ID(__XF_AP_CLIENT(0, 0), + __XF_PORT_SPEC2(p_handle->id, 0)); + msg.id = XF_MSG_AP_FROM_USER(msg.id, client->id); + msg.opcode = XF_GET_PARAM; + msg.length = sizeof(*smsg) * num_param; + msg.buffer = smsg; + msg.ret = 0; + + /* ...execute command synchronously */ + rmsg = xf_cmd_send_recv_complete(client, proxy, msg.id, msg.opcode, + msg.buffer, msg.length, &client->work, + &client->compr_complete); + + /* ...save received component global client-id */ + if(IS_ERR(rmsg)) + return PTR_ERR(rmsg); + + /* TODO: review cleanup */ + /* xf_msg_free(proxy, rmsg); + * xf_unlock(&proxy->lock); */ + + /* ...make sure response is expected */ + if ((rmsg->opcode != (u32)XF_GET_PARAM) || (rmsg->buffer != smsg)) { + return -EPIPE; + } + + for (i = 0; i < num_param; i++) + param[i].value = smsg[i].value; + + return 0; +} + +int xaf_comp_flush(struct xf_client *client, struct xaf_comp *p_comp) +{ + + struct xf_handle *p_handle; + struct xf_proxy *proxy; + struct xf_message msg; + struct xf_message *rmsg; + + p_handle = &p_comp->handle; + proxy = p_handle->proxy; + + msg.id = __XF_MSG_ID(__XF_AP_CLIENT(0, 0), + __XF_PORT_SPEC2(p_handle->id, 0)); + msg.id = XF_MSG_AP_FROM_USER(msg.id, client->id); + msg.opcode = XF_FLUSH; + msg.length = 0; + msg.buffer = NULL; + msg.ret = 0; + + + /* ...execute command synchronously */ + rmsg = xf_cmd_send_recv_complete(client, proxy, msg.id, msg.opcode, + msg.buffer, msg.length, &client->work, + &client->compr_complete); + + if(IS_ERR(rmsg)) + return PTR_ERR(rmsg); + + /* ...make sure response is expected */ + if ((rmsg->opcode != (u32)XF_FLUSH) || rmsg->buffer) { + return -EPIPE; + } + + return 0; +} + +int xaf_comp_create(struct xf_client *client, struct xf_proxy *proxy, + struct xaf_comp *p_comp, int comp_type) +{ + struct fsl_dsp *dsp_priv = container_of(proxy, struct fsl_dsp, proxy); + char lib_path[200]; + char lib_wrap_path[200]; + struct xf_handle *p_handle; + struct xf_buffer *buf; + int ret = 0; + bool loadlib = true; + + memset((void *)p_comp, 0, sizeof(struct xaf_comp)); + + strcpy(lib_path, "/lib/firmware/imx/dsp/"); + strcpy(lib_wrap_path, "/lib/firmware/imx/dsp/"); + + p_handle = &p_comp->handle; + + p_comp->comp_type = comp_type; + + if (comp_type == RENDER_ESAI) + loadlib = false; + + if (loadlib) { + p_comp->codec_lib.filename = lib_path; + p_comp->codec_wrap_lib.filename = lib_wrap_path; + p_comp->codec_lib.lib_type = DSP_CODEC_LIB; + } + + switch (comp_type) { + case CODEC_MP3_DEC: + p_comp->dec_id = "audio-decoder/mp3"; + strcat(lib_path, "lib_dsp_mp3_dec.so"); + break; + case CODEC_AAC_DEC: + p_comp->dec_id = "audio-decoder/aac"; + strcat(lib_path, "lib_dsp_aac_dec.so"); + break; + case RENDER_ESAI: + p_comp->dec_id = "renderer/esai"; + break; + + default: + return -EINVAL; + break; + } + + /* ...create decoder component instance (select core-0) */ + ret = xf_open(client, proxy, p_handle, p_comp->dec_id, 0, NULL); + if (ret) { + dev_err(dsp_priv->dev, "create (%s) component error: %d\n", + p_comp->dec_id, ret); + return ret; + } + + if (loadlib) { + strcat(lib_wrap_path, "lib_dsp_codec_wrap.so"); + p_comp->codec_wrap_lib.lib_type = DSP_CODEC_WRAP_LIB; + + /* ...load codec wrapper lib */ + ret = xf_load_lib(client, p_handle, &p_comp->codec_wrap_lib); + if (ret) { + dev_err(dsp_priv->dev, "load codec wrap lib error\n"); + return ret; + } + + /* ...load codec lib */ + ret = xf_load_lib(client, p_handle, &p_comp->codec_lib); + if (ret) { + dev_err(dsp_priv->dev, "load codec lib error\n"); + return ret; + } + + /* ...allocate input buffer */ + ret = xf_pool_alloc(client, proxy, 1, INBUF_SIZE, + XF_POOL_INPUT, &p_comp->inpool); + if (ret) { + dev_err(dsp_priv->dev, "alloc input buf error\n"); + return ret; + } + + /* ...initialize input buffer pointer */ + buf = xf_buffer_get(p_comp->inpool); + p_comp->inptr = xf_buffer_data(buf); + } + + return ret; +} + +int xaf_comp_delete(struct xf_client *client, struct xaf_comp *p_comp) +{ + + struct xf_handle *p_handle; + bool loadlib = true; + u32 ret = 0; + + if (p_comp->comp_type == RENDER_ESAI) + loadlib = false; + + p_handle = &p_comp->handle; + + if (loadlib) { + /* ...unload codec wrapper library */ + xf_unload_lib(client, p_handle, &p_comp->codec_wrap_lib); + + /* ...unload codec library */ + xf_unload_lib(client, p_handle, &p_comp->codec_lib); + + xf_pool_free(client, p_comp->inpool); + } + + /* ...delete component */ + xf_close(client, p_handle); + + return ret; +} + +int xaf_comp_process(struct xf_client *client, struct xaf_comp *p_comp, void *p_buf, u32 length, u32 flag) +{ + struct xf_handle *p_handle; + u32 ret = 0; + + p_handle = &p_comp->handle; + + switch (flag) { + case XF_FILL_THIS_BUFFER: + /* ...send message to component output port (port-id=1) */ + ret = xf_command(client, p_handle, 1, XF_FILL_THIS_BUFFER, + p_buf, length); + break; + case XF_EMPTY_THIS_BUFFER: + /* ...send message to component input port (port-id=0) */ + ret = xf_command(client, p_handle, 0, XF_EMPTY_THIS_BUFFER, + p_buf, length); + break; + default: + break; + } + + return ret; +} + +/* ...port binding function */ +int xf_route(struct xf_client *client, struct xf_handle *src, u32 src_port, + struct xf_handle *dst, u32 dst_port, u32 num, u32 size, u32 align) +{ + struct xf_proxy *proxy = src->proxy; + struct xf_buffer *b; + struct xf_route_port_msg *m; + struct xf_message msg; + struct xf_message *rmsg; + + /* ...sanity checks - proxy pointers are same */ + if (proxy != dst->proxy) + return -EINVAL; + + /* ...buffer data is sane */ + if (!(num && size && xf_is_power_of_two(align))) + return -EINVAL; + + /* ...get control buffer */ + if ((b = xf_buffer_get(proxy->aux)) == NULL) + return -EBUSY; + + /* ...get message buffer */ + m = xf_buffer_data(b); + + /* ...fill-in message parameters */ + m->src = __XF_PORT_SPEC2(src->id, src_port); + m->dst = __XF_PORT_SPEC2(dst->id, dst_port); + m->alloc_number = num; + m->alloc_size = size; + m->alloc_align = align; + + /* ...set command parameters */ + msg.id = __XF_MSG_ID(__XF_AP_PROXY(0), + __XF_PORT_SPEC2(src->id, src_port)); + msg.id = XF_MSG_AP_FROM_USER(msg.id, client->id); + msg.opcode = XF_ROUTE; + msg.length = sizeof(*m); + msg.buffer = m; + msg.ret = 0; + + /* ...execute command synchronously */ + rmsg = xf_cmd_send_recv_complete(client, proxy, msg.id, msg.opcode, + msg.buffer, msg.length, &client->work, + &client->compr_complete); + if(IS_ERR(rmsg)) + return PTR_ERR(rmsg); + + /* ...save received component global client-id */ + /* TODO: review cleanup */ + /* xf_msg_free(proxy, rmsg); + * xf_unlock(&proxy->lock); */ + + + /* ...synchronously execute command on remote DSP */ + /* XF_CHK_API(xf_proxy_cmd_exec(proxy, &msg)); */ + + /* ...return buffer to proxy */ + xf_buffer_put(b); + + /* ...check result is successful */ + /* XF_CHK_ERR(msg.opcode == XF_ROUTE, -ENOMEM); */ + + return 0; +} + +/* ...port unbinding function */ +int xf_unroute(struct xf_client *client, struct xf_handle *src, u32 src_port) +{ + struct xf_proxy *proxy = src->proxy; + struct xf_buffer *b; + struct xf_unroute_port_msg *m; + struct xf_message msg; + struct xf_message *rmsg; + int r = 0; + + /* ...get control buffer */ + if((b = xf_buffer_get(proxy->aux)) == NULL) + return -EBUSY; + + /* ...get message buffer */ + m = xf_buffer_data(b); + + /* ...fill-in message parameters */ + m->src = __XF_PORT_SPEC2(src->id, src_port); + + /* ...set command parameters */ + msg.id = __XF_MSG_ID(__XF_AP_PROXY(0), + __XF_PORT_SPEC2(src->id, src_port)); + msg.id = XF_MSG_AP_FROM_USER(msg.id, client->id); + msg.opcode = XF_UNROUTE; + msg.length = sizeof(*m); + msg.buffer = m; + msg.ret = 0; + + /* ...execute command synchronously */ + rmsg = xf_cmd_send_recv_complete(client, proxy, msg.id, msg.opcode, + msg.buffer, msg.length, &client->work, + &client->compr_complete); + if (IS_ERR(rmsg)) + return PTR_ERR(rmsg); + /* ...save received component global client-id */ + + /*TODO: review cleanup */ + /* xf_msg_free(proxy, rmsg); */ + /* xf_unlock(&proxy->lock); */ + + /* ...return buffer to proxy */ + xf_buffer_put(b); + + return r; +} + +int xaf_connect(struct xf_client *client, + struct xaf_comp *p_src, + struct xaf_comp *p_dest, + u32 num_buf, + u32 buf_length) +{ + /* ...connect p_src output port with p_dest input port */ + return xf_route(client, &p_src->handle, 0, &p_dest->handle, 0, + num_buf, buf_length, 8); +} + +int xaf_disconnect(struct xf_client *client, struct xaf_comp *p_comp) +{ + /* ...disconnect p_src output port with p_dest input port */ + return xf_unroute(client, &p_comp->handle, 0); + +} + +int xaf_comp_add(struct xaf_pipeline *p_pipe, struct xaf_comp *p_comp) +{ + int ret = 0; + + p_comp->next = p_pipe->comp_chain; + p_comp->pipeline = p_pipe; + p_pipe->comp_chain = p_comp; + + return ret; +} + +int xaf_pipeline_create(struct xaf_pipeline *p_pipe) +{ + int ret = 0; + + memset(p_pipe, 0, sizeof(struct xaf_pipeline)); + + return ret; +} + +int xaf_pipeline_delete(struct xaf_pipeline *p_pipe) +{ + int ret = 0; + + memset(p_pipe, 0, sizeof(struct xaf_pipeline)); + + return ret; +} diff --git a/sound/soc/fsl/fsl_dsp_xaf_api.h b/sound/soc/fsl/fsl_dsp_xaf_api.h new file mode 100644 index 000000000000..5087b46520d5 --- /dev/null +++ b/sound/soc/fsl/fsl_dsp_xaf_api.h @@ -0,0 +1,134 @@ +/* SPDX-License-Identifier: (GPL-2.0+ OR MIT)*/ +/* + * Xtensa Audio Framework API for communication with DSP + * + * Copyright (C) 2017 Cadence Design Systems, Inc. + * Copyright 2018 NXP + */ +#ifndef FSL_DSP_XAF_API_H +#define FSL_DSP_XAF_API_H + +#include "fsl_dsp_library_load.h" + +/* ...size of auxiliary pool for communication with DSP */ +#define XA_AUX_POOL_SIZE 32 + +/* ...length of auxiliary pool messages */ +#define XA_AUX_POOL_MSG_LENGTH 128 + +/* ...number of max input buffers */ +#define INBUF_SIZE 4096 +#define OUTBUF_SIZE 16384 + +struct xaf_pipeline; + +struct xaf_info_s { + u32 opcode; + void *buf; + u32 length; + u32 ret; +}; + +struct xaf_comp { + struct xaf_comp *next; + + struct xaf_pipeline *pipeline; + struct xf_handle handle; + + const char *dec_id; + int comp_type; + + struct xf_pool *inpool; + struct xf_pool *outpool; + void *inptr; + void *outptr; + + struct lib_info codec_lib; + struct lib_info codec_wrap_lib; +}; + +struct xaf_pipeline { + struct xaf_comp *comp_chain; + + u32 input_eos; + u32 output_eos; +}; + +int xaf_comp_create(struct xf_client *client, struct xf_proxy *p_proxy, + struct xaf_comp *p_comp, int comp_type); +int xaf_comp_delete(struct xf_client *client, struct xaf_comp *p_comp); +int xaf_comp_flush(struct xf_client *client, struct xaf_comp *p_comp); + +int xaf_comp_set_config(struct xf_client *client,struct xaf_comp *p_comp, + u32 num_param, void *p_param); +int xaf_comp_get_config(struct xf_client *client,struct xaf_comp *p_comp, + u32 num_param, void *p_param); + +int xaf_comp_add(struct xaf_pipeline *p_pipe, struct xaf_comp *p_comp); +int xaf_comp_process(struct xf_client *client, struct xaf_comp *p_comp, + void *p_buf, u32 length, u32 flag); +int xaf_comp_get_status(struct xaf_comp *p_comp, struct xaf_info_s *p_info); +int xaf_comp_get_msg_count(struct xaf_comp *p_comp); + +int xaf_connect(struct xf_client *client,struct xaf_comp *p_src, + struct xaf_comp *p_dest, u32 num_buf, u32 buf_length); +int xaf_disconnect(struct xf_client *client,struct xaf_comp *p_comp); + +int xaf_pipeline_create(struct xaf_pipeline *p_pipe); +int xaf_pipeline_delete(struct xaf_pipeline *p_pipe); + +int xaf_pipeline_send_eos(struct xaf_pipeline *p_pipe); + +/* ...port routing command */ +struct __attribute__((__packed__)) xf_route_port_msg { + /* ...source port specification */ + u32 src; + /* ...destination port specification */ + u32 dst; + /* ...number of buffers to allocate */ + u32 alloc_number; + /* ...length of buffer to allocate */ + u32 alloc_size; + /* ...alignment restriction for a buffer */ + u32 alloc_align; +}; + +/* ...port unrouting command */ +struct __attribute__((__packed__)) xf_unroute_port_msg { + /* ...source port specification */ + u32 src; + /* ...destination port specification */ + u32 dst; +}; + +/* ...check if non-zero value is a power-of-two */ +#define xf_is_power_of_two(v) (((v) & ((v) - 1)) == 0) + +/* ...component initialization parameter */ +struct __attribute__((__packed__)) xf_set_param_msg { + /* ...index of parameter passed to SET_CONFIG_PARAM call */ + u32 id; + /* ...value of parameter */ + u32 value; +}; + +/* ...message body (command/response) */ +struct __attribute__((__packed__)) xf_get_param_msg { + /* ...array of parameters requested */ + u32 id; + /* ...array of parameters values */ + u32 value; +}; + +/* ...renderer-specific configuration parameters */ +enum xa_config_param_renderer { + XA_RENDERER_CONFIG_PARAM_CB = 0, + XA_RENDERER_CONFIG_PARAM_STATE = 1, + XA_RENDERER_CONFIG_PARAM_PCM_WIDTH = 2, + XA_RENDERER_CONFIG_PARAM_CHANNELS = 3, + XA_RENDERER_CONFIG_PARAM_SAMPLE_RATE = 4, + XA_RENDERER_CONFIG_PARAM_FRAME_SIZE = 5, + XA_RENDERER_CONFIG_PARAM_NUM = 6, +}; + +#endif /* FSL_DSP_XAF_API_H */ From 6bb3efa95e431a326f6f8f17bdb5ff70ab5fd3df Mon Sep 17 00:00:00 2001 From: Daniel Baluta Date: Thu, 4 Oct 2018 14:29:36 +0300 Subject: [PATCH 48/78] MLK-18497-8: ASoC: fsl: dsp: Add DSP audio platform driver Reviewed-by: Cosmin-Gabriel Samoila Signed-off-by: Shengjiu Wang --- sound/soc/fsl/Kconfig | 1 + sound/soc/fsl/Makefile | 2 +- sound/soc/fsl/fsl_dsp_cpu.c | 153 ++++++++++++++++++++++++++++++++++++ sound/soc/fsl/fsl_dsp_cpu.h | 18 +++++ 4 files changed, 173 insertions(+), 1 deletion(-) create mode 100644 sound/soc/fsl/fsl_dsp_cpu.c create mode 100644 sound/soc/fsl/fsl_dsp_cpu.h diff --git a/sound/soc/fsl/Kconfig b/sound/soc/fsl/Kconfig index 60aef56522ad..0af54d900a8e 100644 --- a/sound/soc/fsl/Kconfig +++ b/sound/soc/fsl/Kconfig @@ -76,6 +76,7 @@ config SND_SOC_FSL_MICFIL config SND_SOC_FSL_DSP tristate "dsp module support" + select SND_SOC_COMPRESS help Say Y if you want to add hifi 4 support for the Freescale CPUs. which is a DSP core for audio processing. diff --git a/sound/soc/fsl/Makefile b/sound/soc/fsl/Makefile index 2c7f0dd75b8b..58d4c7c78430 100644 --- a/sound/soc/fsl/Makefile +++ b/sound/soc/fsl/Makefile @@ -16,7 +16,7 @@ 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-dsp-objs := fsl_dsp.o fsl_dsp_proxy.o fsl_dsp_pool.o \ - fsl_dsp_library_load.o fsl_dsp_xaf_api.o + fsl_dsp_library_load.o fsl_dsp_xaf_api.o fsl_dsp_cpu.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_dsp_cpu.c b/sound/soc/fsl/fsl_dsp_cpu.c new file mode 100644 index 000000000000..c203b70160f4 --- /dev/null +++ b/sound/soc/fsl/fsl_dsp_cpu.c @@ -0,0 +1,153 @@ +// SPDX-License-Identifier: GPL-2.0+ +// +// DSP Audio platform driver +// +// Copyright 2018 NXP + +#include +#include +#include +#include +#include +#include + +#include "fsl_dsp_cpu.h" + +static int dsp_audio_startup(struct snd_pcm_substream *substream, + struct snd_soc_dai *cpu_dai) { + pm_runtime_get_sync(cpu_dai->dev); + return 0; +} + + +static void dsp_audio_shutdown(struct snd_pcm_substream *substream, + struct snd_soc_dai *cpu_dai) { + pm_runtime_put_sync(cpu_dai->dev); +} + +static const struct snd_soc_dai_ops dsp_audio_dai_ops = { + .startup = dsp_audio_startup, + .shutdown = dsp_audio_shutdown, +}; + +static struct snd_soc_dai_driver dsp_audio_dai = { + .name = "dsp-audio-cpu-dai", + .compress_new = snd_soc_new_compress, + .ops = &dsp_audio_dai_ops, + .playback = { + .stream_name = "Compress Playback", + .channels_min = 1, + }, +}; + +static const struct snd_soc_component_driver audio_dsp_component = { + .name = "audio-dsp", +}; + +static int dsp_audio_probe(struct platform_device *pdev) +{ + struct fsl_dsp_audio *dsp_audio; + int ret; + + dsp_audio = devm_kzalloc(&pdev->dev, sizeof(*dsp_audio), GFP_KERNEL); + if (dsp_audio == NULL) + return -ENOMEM; + + dev_dbg(&pdev->dev, "probing DSP device....\n"); + + /* intialise sof device */ + dev_set_drvdata(&pdev->dev, dsp_audio); + + /* No error out for old DTB cases but only mark the clock NULL */ + dsp_audio->bus_clk = devm_clk_get(&pdev->dev, "bus"); + if (IS_ERR(dsp_audio->bus_clk)) { + dev_err(&pdev->dev, "failed to get bus clock: %ld\n", + PTR_ERR(dsp_audio->bus_clk)); + dsp_audio->bus_clk = NULL; + } + + dsp_audio->m_clk = devm_clk_get(&pdev->dev, "mclk"); + if (IS_ERR(dsp_audio->m_clk)) { + dev_err(&pdev->dev, "failed to get m clock: %ld\n", + PTR_ERR(dsp_audio->m_clk)); + dsp_audio->m_clk = NULL; + } + + pm_runtime_enable(&pdev->dev); + + /* now register audio DSP platform driver */ + ret = snd_soc_register_component(&pdev->dev, &audio_dsp_component, + &dsp_audio_dai, 1); + if (ret < 0) { + dev_err(&pdev->dev, + "error: failed to register DSP DAI driver %d\n", ret); + goto err; + } + + return 0; + +err: + return ret; +} + +static int dsp_audio_remove(struct platform_device *pdev) +{ + snd_soc_unregister_component(&pdev->dev); + return 0; +} + +#ifdef CONFIG_PM +static int dsp_runtime_resume(struct device *dev) +{ + struct fsl_dsp_audio *dsp_audio = dev_get_drvdata(dev); + int ret; + + ret = clk_prepare_enable(dsp_audio->bus_clk); + if (ret) { + dev_err(dev, "failed to enable bus clock: %d\n", ret); + return ret; + } + + ret = clk_prepare_enable(dsp_audio->m_clk); + if (ret) { + dev_err(dev, "failed to enable m clock: %d\n", ret); + return ret; + } + + return ret; +} + +static int dsp_runtime_suspend(struct device *dev) +{ + struct fsl_dsp_audio *dsp_audio = dev_get_drvdata(dev); + + clk_disable_unprepare(dsp_audio->m_clk); + clk_disable_unprepare(dsp_audio->bus_clk); + + return 0; +} +#endif + +static const struct dev_pm_ops dsp_pm_ops = { + SET_RUNTIME_PM_OPS(dsp_runtime_suspend, + dsp_runtime_resume, + NULL) + SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, pm_runtime_force_resume) +}; + +static const struct of_device_id dsp_audio_ids[] = { + { .compatible = "fsl,dsp-audio"}, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, dsp_audio_ids); + +static struct platform_driver dsp_audio_driver = { + .driver = { + .name = "dsp-audio", + .of_match_table = dsp_audio_ids, + .pm = &dsp_pm_ops, + }, + .probe = dsp_audio_probe, + .remove = dsp_audio_remove, +}; +module_platform_driver(dsp_audio_driver); diff --git a/sound/soc/fsl/fsl_dsp_cpu.h b/sound/soc/fsl/fsl_dsp_cpu.h new file mode 100644 index 000000000000..ef2813868be8 --- /dev/null +++ b/sound/soc/fsl/fsl_dsp_cpu.h @@ -0,0 +1,18 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * DSP Audio DAI header + * + * Copyright 2018 NXP + */ + +#ifndef __FSL_DSP_CPU_H +#define __FSL_DSP_CPU_H + +struct fsl_dsp_audio { + struct platform_device *pdev; + struct clk *bus_clk; + struct clk *m_clk; +}; + +#endif /*__FSL_DSP_CPU_H*/ + From e5a35115db1a6c79fdf66f07bd65bbe7a741835e Mon Sep 17 00:00:00 2001 From: Daniel Baluta Date: Fri, 5 Oct 2018 19:07:56 +0300 Subject: [PATCH 49/78] MLK-18497-9: ASoC: fsl: dsp: Export xf_client_alloc While at it add include guard to dsp.h Reviewed-by: Cosmin-Gabriel Samoila Signed-off-by: Shengjiu Wang --- sound/soc/fsl/fsl_dsp.c | 9 +++++++-- sound/soc/fsl/fsl_dsp.h | 7 ++++++- 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/sound/soc/fsl/fsl_dsp.c b/sound/soc/fsl/fsl_dsp.c index 7d5a686f4e8d..7d2d6314d27f 100644 --- a/sound/soc/fsl/fsl_dsp.c +++ b/sound/soc/fsl/fsl_dsp.c @@ -62,11 +62,16 @@ #include #include #include -#include "fsl_dsp.h" +#include +#include + +#include "fsl_dsp.h" +#include "fsl_dsp_pool.h" +#include "fsl_dsp_xaf_api.h" /* ...allocate new client */ -static inline struct xf_client *xf_client_alloc(struct fsl_dsp *dsp_priv) +struct xf_client *xf_client_alloc(struct fsl_dsp *dsp_priv) { struct xf_client *client; u32 id; diff --git a/sound/soc/fsl/fsl_dsp.h b/sound/soc/fsl/fsl_dsp.h index 9ee7e025ed7f..04fefa75d992 100644 --- a/sound/soc/fsl/fsl_dsp.h +++ b/sound/soc/fsl/fsl_dsp.h @@ -5,8 +5,10 @@ * */ -#include +#ifndef FSL_DSP_H +#define FSL_DSP_H #include +#include #include "fsl_dsp_proxy.h" @@ -118,3 +120,6 @@ struct fsl_dsp { void *memcpy_dsp(void *dest, const void *src, size_t count); void *memset_dsp(void *dest, int c, size_t count); struct xf_client *xf_client_lookup(struct fsl_dsp *dsp_priv, u32 id); +struct xf_client *xf_client_alloc(struct fsl_dsp *dsp_priv); + +#endif From 78520df6826e552bbc2c23e76e0f11c32fa559f1 Mon Sep 17 00:00:00 2001 From: Daniel Baluta Date: Fri, 5 Oct 2018 19:05:25 +0300 Subject: [PATCH 50/78] MLK-18497-10: ASoC: fsl: dsp: Refactor fsl_dsp_{open|close} DSP driver now supports two interfaces. Old ioctl chardev based interface and ALSA compress inteface. Because some part of the open/close code is common introduce two new functions which encapsulate the common functionality. Reviewed-by: Cosmin-Gabriel Samoila Signed-off-by: Shengjiu Wang --- sound/soc/fsl/fsl_dsp.c | 58 +++++++++++++++++++++++++++-------------- sound/soc/fsl/fsl_dsp.h | 3 +++ 2 files changed, 41 insertions(+), 20 deletions(-) diff --git a/sound/soc/fsl/fsl_dsp.c b/sound/soc/fsl/fsl_dsp.c index 7d2d6314d27f..3dddaf9e6f53 100644 --- a/sound/soc/fsl/fsl_dsp.c +++ b/sound/soc/fsl/fsl_dsp.c @@ -351,22 +351,11 @@ void resource_release(struct fsl_dsp *dsp_priv) xf_proxy_init(&dsp_priv->proxy); } -static int fsl_dsp_open(struct inode *inode, struct file *file) +int fsl_dsp_open_func(struct fsl_dsp *dsp_priv, struct xf_client *client) { - struct fsl_dsp *dsp_priv = dev_get_drvdata(dsp_miscdev.parent); struct device *dev = dsp_priv->dev; - struct xf_client *client; int ret = 0; - /* ...basic sanity checks */ - if (!inode || !file) - return -EINVAL; - - /* ...allocate new proxy client object */ - client = xf_client_alloc(dsp_priv); - if (IS_ERR(client)) - return PTR_ERR(client); - /* ...initialize waiting queue */ init_waitqueue_head(&client->wait); @@ -381,8 +370,6 @@ static int fsl_dsp_open(struct inode *inode, struct file *file) client->global = (void *)dsp_priv; - file->private_data = (void *)client; - pm_runtime_get_sync(dev); mutex_lock(&dsp_priv->dsp_mutex); @@ -393,18 +380,35 @@ static int fsl_dsp_open(struct inode *inode, struct file *file) return ret; } -static int fsl_dsp_close(struct inode *inode, struct file *file) +static int fsl_dsp_open(struct inode *inode, struct file *file) +{ + struct fsl_dsp *dsp_priv = dev_get_drvdata(dsp_miscdev.parent); + struct xf_client *client; + int ret = 0; + + /* ...basic sanity checks */ + if (!inode || !file) + return -EINVAL; + + /* ...allocate new proxy client object */ + client = xf_client_alloc(dsp_priv); + if (IS_ERR(client)) + return PTR_ERR(client); + + fsl_dsp_open_func(dsp_priv, client); + + file->private_data = (void *)client; + + return ret; +} + +int fsl_dsp_close_func(struct xf_client *client) { struct fsl_dsp *dsp_priv; struct device *dev; struct xf_proxy *proxy; - struct xf_client *client; /* ...basic sanity checks */ - client = xf_get_client(file); - if (IS_ERR(client)) - return PTR_ERR(client); - proxy = client->proxy; /* release all pending messages */ @@ -432,6 +436,20 @@ static int fsl_dsp_close(struct inode *inode, struct file *file) return 0; } +static int fsl_dsp_close(struct inode *inode, struct file *file) +{ + struct xf_client *client; + + /* ...basic sanity checks */ + client = xf_get_client(file); + if (IS_ERR(client)) + return PTR_ERR(client); + + fsl_dsp_close_func(client); + + return 0; +} + /* ...wait until data is available in the response queue */ static unsigned int fsl_dsp_poll(struct file *file, poll_table *wait) { diff --git a/sound/soc/fsl/fsl_dsp.h b/sound/soc/fsl/fsl_dsp.h index 04fefa75d992..eaabe17e0f54 100644 --- a/sound/soc/fsl/fsl_dsp.h +++ b/sound/soc/fsl/fsl_dsp.h @@ -122,4 +122,7 @@ void *memset_dsp(void *dest, int c, size_t count); struct xf_client *xf_client_lookup(struct fsl_dsp *dsp_priv, u32 id); struct xf_client *xf_client_alloc(struct fsl_dsp *dsp_priv); +int fsl_dsp_open_func(struct fsl_dsp *dsp_priv, struct xf_client *client); +int fsl_dsp_close_func(struct xf_client *client); + #endif From 09194b889d50146c20eafa3a661c5911d4ee2cbf Mon Sep 17 00:00:00 2001 From: Daniel Baluta Date: Thu, 4 Oct 2018 14:46:32 +0300 Subject: [PATCH 51/78] MLK-18497-11: ASoC: fsl: compress: Introduce compress implemenation Reviewed-by: Cosmin-Gabriel Samoila Signed-off-by: Shengjiu Wang --- sound/soc/fsl/Makefile | 3 +- sound/soc/fsl/fsl_dsp.c | 13 + sound/soc/fsl/fsl_dsp.h | 10 + sound/soc/fsl/fsl_dsp_platform.h | 21 + sound/soc/fsl/fsl_dsp_platform_compress.c | 462 ++++++++++++++++++++++ 5 files changed, 508 insertions(+), 1 deletion(-) create mode 100644 sound/soc/fsl/fsl_dsp_platform.h create mode 100644 sound/soc/fsl/fsl_dsp_platform_compress.c diff --git a/sound/soc/fsl/Makefile b/sound/soc/fsl/Makefile index 58d4c7c78430..36ff6b3a534b 100644 --- a/sound/soc/fsl/Makefile +++ b/sound/soc/fsl/Makefile @@ -16,7 +16,8 @@ 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-dsp-objs := fsl_dsp.o fsl_dsp_proxy.o fsl_dsp_pool.o \ - fsl_dsp_library_load.o fsl_dsp_xaf_api.o fsl_dsp_cpu.o + fsl_dsp_library_load.o fsl_dsp_xaf_api.o fsl_dsp_cpu.o \ + fsl_dsp_platform_compress.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_dsp.c b/sound/soc/fsl/fsl_dsp.c index 3dddaf9e6f53..ef30b5a30bd2 100644 --- a/sound/soc/fsl/fsl_dsp.c +++ b/sound/soc/fsl/fsl_dsp.c @@ -765,6 +765,13 @@ static const struct file_operations dsp_fops = { .release = fsl_dsp_close, }; +extern struct snd_compr_ops dsp_platform_compr_ops; + +static const struct snd_soc_component_driver dsp_soc_platform_drv = { + .name = FSL_DSP_COMP_NAME, + .compr_ops = &dsp_platform_compr_ops, +}; + static int fsl_dsp_probe(struct platform_device *pdev) { struct device_node *np = pdev->dev.of_node; @@ -927,6 +934,12 @@ static int fsl_dsp_probe(struct platform_device *pdev) /* ...initialize mutex */ mutex_init(&dsp_priv->dsp_mutex); + ret = devm_snd_soc_register_component(&pdev->dev, &dsp_soc_platform_drv, NULL, 0); + if (ret) { + dev_err(&pdev->dev, "registering soc platform failed\n"); + return ret; + } + return 0; } diff --git a/sound/soc/fsl/fsl_dsp.h b/sound/soc/fsl/fsl_dsp.h index eaabe17e0f54..ad6f7a9e8be1 100644 --- a/sound/soc/fsl/fsl_dsp.h +++ b/sound/soc/fsl/fsl_dsp.h @@ -10,8 +10,11 @@ #include #include #include "fsl_dsp_proxy.h" +#include "fsl_dsp_platform.h" +#define FSL_DSP_COMP_NAME "fsl-dsp-component" + typedef void (*memcpy_func) (void *dest, const void *src, size_t n); typedef void (*memset_func) (void *s, int c, size_t n); @@ -41,8 +44,13 @@ struct xf_client { void *global; struct xf_message m; + struct snd_compr_stream *cstream; + struct work_struct work; struct completion compr_complete; + + int input_bytes; + int consume_bytes; }; union xf_client_link { @@ -88,6 +96,8 @@ struct fsl_dsp { /* ...mutex lock */ struct mutex dsp_mutex; + struct dsp_data dsp_data; + /* ...global clients pool (item[0] serves as list terminator) */ union xf_client_link xf_client_map[XF_CFG_MAX_IPC_CLIENTS]; }; diff --git a/sound/soc/fsl/fsl_dsp_platform.h b/sound/soc/fsl/fsl_dsp_platform.h new file mode 100644 index 000000000000..15d085c9f23d --- /dev/null +++ b/sound/soc/fsl/fsl_dsp_platform.h @@ -0,0 +1,21 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * Copyright (c) 2012-2013 by Tensilica Inc. ALL RIGHTS RESERVED. + * Copyright 2018 NXP + */ + +#ifndef _FSL_DSP_PLATFORM_H +#define _FSL_DSP_PLATFORM_H + +#include "fsl_dsp_xaf_api.h" + +struct dsp_data { + struct xf_client *client; + struct xaf_pipeline *p_pipe; + struct xaf_pipeline pipeline; + struct xaf_comp component[2]; + int codec_type; + int status; +}; + +#endif /*_FSL_DSP_PLATFORM_H*/ diff --git a/sound/soc/fsl/fsl_dsp_platform_compress.c b/sound/soc/fsl/fsl_dsp_platform_compress.c new file mode 100644 index 000000000000..004a539d2b8a --- /dev/null +++ b/sound/soc/fsl/fsl_dsp_platform_compress.c @@ -0,0 +1,462 @@ +// SPDX-License-Identifier: GPL-2.0+ +// +// DSP driver compress implementation +// +// Copyright (c) 2012-2013 by Tensilica Inc. ALL RIGHTS RESERVED. +// Copyright 2018 NXP + +#include +#include +#include +#include + +#include "fsl_dsp.h" +#include "fsl_dsp_platform.h" +#include "fsl_dsp_xaf_api.h" + +#define NUM_CODEC 2 +#define MIN_FRAGMENT 1 +#define MAX_FRAGMENT 1 +#define MIN_FRAGMENT_SIZE (4 * 1024) +#define MAX_FRAGMENT_SIZE (4 * 1024) + +void dsp_platform_process(struct work_struct *w) +{ + struct xf_client *client = container_of(w, struct xf_client, work); + struct xf_proxy *proxy = client->proxy; + struct xf_message *rmsg; + + while (1) { + rmsg = xf_cmd_recv(proxy, &client->wait, &client->queue, 1); + if (IS_ERR(rmsg)) { + return; + } + if (rmsg->opcode == XF_EMPTY_THIS_BUFFER) { + client->consume_bytes += rmsg->length; + snd_compr_fragment_elapsed(client->cstream); + + if (rmsg->buffer == NULL && rmsg->length == 0) + snd_compr_drain_notify(client->cstream); + + } else { + memcpy(&client->m, rmsg, sizeof(struct xf_message)); + complete(&client->compr_complete); + } + + xf_msg_free(proxy, rmsg); + xf_unlock(&proxy->lock); + } +} + +static int dsp_platform_compr_open(struct snd_compr_stream *cstream) +{ + struct snd_soc_pcm_runtime *rtd = cstream->private_data; + struct snd_soc_component *component = snd_soc_rtdcom_lookup(rtd, FSL_DSP_COMP_NAME); + struct snd_soc_dai *cpu_dai = rtd->cpu_dai; + struct fsl_dsp *dsp_priv = snd_soc_component_get_drvdata(component); + struct dsp_data *drv = &dsp_priv->dsp_data; + + drv->client = xf_client_alloc(dsp_priv); + if (IS_ERR(drv->client)) + return PTR_ERR(drv->client); + + fsl_dsp_open_func(dsp_priv, drv->client); + + drv->client->proxy = &dsp_priv->proxy; + + cpu_dai->driver->ops->startup(NULL, cpu_dai); + + drv->client->cstream = cstream; + + INIT_WORK(&drv->client->work, dsp_platform_process); + + return 0; +} + +static int dsp_platform_compr_free(struct snd_compr_stream *cstream) +{ + struct snd_soc_pcm_runtime *rtd = cstream->private_data; + struct snd_soc_component *component = snd_soc_rtdcom_lookup(rtd, FSL_DSP_COMP_NAME); + struct snd_soc_dai *cpu_dai = rtd->cpu_dai; + struct fsl_dsp *dsp_priv = snd_soc_component_get_drvdata(component); + struct dsp_data *drv = &dsp_priv->dsp_data; + int ret; + + if (cstream->runtime->state != SNDRV_PCM_STATE_PAUSED && + cstream->runtime->state != SNDRV_PCM_STATE_RUNNING && + cstream->runtime->state != SNDRV_PCM_STATE_DRAINING) { + + ret = xaf_comp_delete(drv->client, &drv->component[1]); + if (ret) { + dev_err(component->dev, "Fail to delete component, err = %d\n", ret); + return ret; + } + + ret = xaf_comp_delete(drv->client, &drv->component[0]); + if (ret) { + dev_err(component->dev, "Fail to delete component, err = %d\n", ret); + return ret; + } + } + + cpu_dai->driver->ops->shutdown(NULL, cpu_dai); + + ret = cancel_work(&drv->client->work); + + fsl_dsp_close_func(drv->client); + + return 0; +} + +static int dsp_platform_compr_set_params(struct snd_compr_stream *cstream, + struct snd_compr_params *params) +{ + /* accroding to the params, load the library and create component*/ + struct snd_soc_pcm_runtime *rtd = cstream->private_data; + struct snd_soc_component *component = snd_soc_rtdcom_lookup(rtd, FSL_DSP_COMP_NAME); + struct fsl_dsp *dsp_priv = snd_soc_component_get_drvdata(component); + struct dsp_data *drv = &dsp_priv->dsp_data; + struct xf_proxy *p_proxy = &dsp_priv->proxy; + struct xf_set_param_msg s_param; + int ret; + + switch (params->codec.id) { + case SND_AUDIOCODEC_MP3: + drv->codec_type = CODEC_MP3_DEC; + break; + case SND_AUDIOCODEC_AAC: + drv->codec_type = CODEC_AAC_DEC; + break; + default: + dev_err(component->dev, "codec not supported, id =%d\n", params->codec.id); + return -EINVAL; + } + + /* ...create auxiliary buffers pool for control commands */ + ret = xf_pool_alloc(drv->client, + p_proxy, + XA_AUX_POOL_SIZE, + XA_AUX_POOL_MSG_LENGTH, + XF_POOL_AUX, + &p_proxy->aux); + if (ret) { + dev_err(component->dev, "xf_pool_alloc failed"); + return ret; + } + + /* ...create pipeline */ + ret = xaf_pipeline_create(&drv->pipeline); + if (ret) { + dev_err(component->dev, "create pipeline error\n"); + goto failed; + } + + /* ...create component */ + ret = xaf_comp_create(drv->client, p_proxy, &drv->component[0], drv->codec_type); + if (ret) { + dev_err(component->dev, "create component failed, type = %d, err = %d\n", + drv->codec_type, ret); + goto failed; + } + + ret = xaf_comp_create(drv->client, p_proxy, &drv->component[1], RENDER_ESAI); + if (ret) { + dev_err(component->dev, "create component failed, type = %d, err = %d\n", + RENDER_ESAI, ret); + goto failed; + } + + /* ...add component into pipeline */ + ret = xaf_comp_add(&drv->pipeline, &drv->component[0]); + if (ret) { + dev_err(component->dev, "add component failed, type = %d, err = %d\n", + drv->codec_type, ret); + goto failed; + } + + ret = xaf_comp_add(&drv->pipeline, &drv->component[1]); + if (ret) { + dev_err(component->dev, "add component failed, type = %d, err = %d\n", + drv->codec_type, ret); + goto failed; + } + + drv->client->input_bytes = 0; + drv->client->consume_bytes = 0; + + s_param.id = XA_RENDERER_CONFIG_PARAM_SAMPLE_RATE; + s_param.value = params->codec.sample_rate; + ret = xaf_comp_set_config(drv->client, &drv->component[1], 1, &s_param); + if (ret) { + dev_err(component->dev, "set param[cmd:0x%x|val:0x%x] error, err = %d\n", + s_param.id, s_param.value, ret); + goto failed; + } + + s_param.id = XA_RENDERER_CONFIG_PARAM_CHANNELS; + s_param.value = params->codec.ch_out; + ret = xaf_comp_set_config(drv->client, &drv->component[1], 1, &s_param); + if (ret) { + dev_err(component->dev, "set param[cmd:0x%x|val:0x%x] error, err = %d\n", + s_param.id, s_param.value, ret); + goto failed; + } + + s_param.id = XA_RENDERER_CONFIG_PARAM_PCM_WIDTH; + s_param.value = 16; + ret = xaf_comp_set_config(drv->client, &drv->component[1], 1, &s_param); + if (ret) { + dev_err(component->dev, "set param[cmd:0x%x|val:0x%x] error, err = %d\n", + s_param.id, s_param.value, ret); + goto failed; + } + +failed: + return 0; +} + +static int dsp_platform_compr_trigger_start(struct snd_compr_stream *cstream) +{ + struct snd_soc_pcm_runtime *rtd = cstream->private_data; + struct snd_soc_component *component = snd_soc_rtdcom_lookup(rtd, FSL_DSP_COMP_NAME); + struct fsl_dsp *dsp_priv = snd_soc_component_get_drvdata(component); + struct dsp_data *drv = &dsp_priv->dsp_data; + struct xaf_comp *p_comp = &drv->component[0]; + int ret; + + ret = xaf_comp_process(drv->client, + p_comp, + p_comp->inptr, + drv->client->input_bytes, + XF_EMPTY_THIS_BUFFER); + + ret = xaf_connect(drv->client, + &drv->component[0], + &drv->component[1], + 1, + OUTBUF_SIZE); + if (ret) { + dev_err(component->dev, "Failed to connect component, err = %d\n", ret); + return ret; + } + + schedule_work(&drv->client->work); + + return 0; +} + +static int dsp_platform_compr_trigger_stop(struct snd_compr_stream *cstream) +{ + struct snd_soc_pcm_runtime *rtd = cstream->private_data; + struct snd_soc_component *component = snd_soc_rtdcom_lookup(rtd, FSL_DSP_COMP_NAME); + struct fsl_dsp *dsp_priv = snd_soc_component_get_drvdata(component); + struct dsp_data *drv = &dsp_priv->dsp_data; + int ret; + + ret = xaf_comp_flush(drv->client, &drv->component[0]); + if (ret) { + dev_err(component->dev, "Fail to flush component, err = %d\n", ret); + return ret; + } + + ret = xaf_comp_flush(drv->client, &drv->component[1]); + if (ret) { + dev_err(component->dev, "Fail to flush component, err = %d\n", ret); + return ret; + } + + ret = xaf_comp_delete(drv->client, &drv->component[0]); + if (ret) { + dev_err(component->dev, "Fail to delete component, err = %d\n", ret); + return ret; + } + + ret = xaf_comp_delete(drv->client, &drv->component[1]); + if (ret) { + dev_err(component->dev, "Fail to delete component, err = %d\n", ret); + return ret; + } + + return 0; +} + +static int dsp_platform_compr_trigger_drain(struct snd_compr_stream *cstream) +{ + struct snd_soc_pcm_runtime *rtd = cstream->private_data; + struct snd_soc_component *component = snd_soc_rtdcom_lookup(rtd, FSL_DSP_COMP_NAME); + struct fsl_dsp *dsp_priv = snd_soc_component_get_drvdata(component); + struct dsp_data *drv = &dsp_priv->dsp_data; + struct xaf_comp *p_comp = &drv->component[0]; + int ret; + + ret = xaf_comp_process(drv->client, p_comp, NULL, 0, + XF_EMPTY_THIS_BUFFER); + + schedule_work(&drv->client->work); + return 0; +} + +static int dsp_platform_compr_trigger(struct snd_compr_stream *cstream, int cmd) +{ + int ret = 0; + + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + ret = dsp_platform_compr_trigger_start(cstream); + break; + case SNDRV_PCM_TRIGGER_STOP: + ret = dsp_platform_compr_trigger_stop(cstream); + break; + case SND_COMPR_TRIGGER_DRAIN: + ret = dsp_platform_compr_trigger_drain(cstream); + break; + case SND_COMPR_TRIGGER_PARTIAL_DRAIN: + break; + case SNDRV_PCM_TRIGGER_PAUSE_PUSH: + break; + case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: + break; + } + + /*send command*/ + return ret; +} + +static int dsp_platform_compr_pointer(struct snd_compr_stream *cstream, + struct snd_compr_tstamp *tstamp) +{ + struct snd_soc_pcm_runtime *rtd = cstream->private_data; + struct snd_soc_component *component = snd_soc_rtdcom_lookup(rtd, FSL_DSP_COMP_NAME); + struct fsl_dsp *dsp_priv = snd_soc_component_get_drvdata(component); + struct dsp_data *drv = &dsp_priv->dsp_data; + + tstamp->copied_total = drv->client->input_bytes; + tstamp->byte_offset = drv->client->input_bytes; + tstamp->pcm_frames = 0x900; + tstamp->pcm_io_frames = 0, + tstamp->sampling_rate = 48000; + + return 0; +} + +static int dsp_platform_compr_copy(struct snd_compr_stream *cstream, + char __user *buf, + size_t count) +{ + struct snd_soc_pcm_runtime *rtd = cstream->private_data; + struct snd_soc_component *component = snd_soc_rtdcom_lookup(rtd, FSL_DSP_COMP_NAME); + struct fsl_dsp *dsp_priv = snd_soc_component_get_drvdata(component); + struct dsp_data *drv = &dsp_priv->dsp_data; + struct xaf_comp *p_comp = &drv->component[0]; + int copied = 0; + int ret; + + if (drv->client->input_bytes == drv->client->consume_bytes) { + if (count > INBUF_SIZE){ + ret = copy_from_user(p_comp->inptr, buf, INBUF_SIZE); + if (ret) { + dev_err(component->dev, "failed to get message from user space\n"); + return -EFAULT; + } + copied = INBUF_SIZE; + } else { + ret = copy_from_user(p_comp->inptr, buf, count); + if (ret) { + dev_err(component->dev, "failed to get message from user space\n"); + return -EFAULT; + } + copied = count; + } + drv->client->input_bytes += copied; + + if (cstream->runtime->state == SNDRV_PCM_STATE_RUNNING) { + ret = xaf_comp_process(drv->client, p_comp, + p_comp->inptr, copied, + XF_EMPTY_THIS_BUFFER); + schedule_work(&drv->client->work); + } + } + + return copied; +} + +static int dsp_platform_compr_get_caps(struct snd_compr_stream *cstream, + struct snd_compr_caps *caps) +{ + caps->num_codecs = NUM_CODEC; + caps->min_fragment_size = MIN_FRAGMENT_SIZE; /* 50KB */ + caps->max_fragment_size = MAX_FRAGMENT_SIZE; /* 1024KB */ + caps->min_fragments = MIN_FRAGMENT; + caps->max_fragments = MAX_FRAGMENT; + caps->codecs[0] = SND_AUDIOCODEC_MP3; + caps->codecs[1] = SND_AUDIOCODEC_AAC; + + return 0; +} + +static struct snd_compr_codec_caps caps_mp3 = { + .num_descriptors = 1, + .descriptor[0].max_ch = 2, + .descriptor[0].sample_rates[0] = 48000, + .descriptor[0].sample_rates[1] = 44100, + .descriptor[0].sample_rates[2] = 32000, + .descriptor[0].sample_rates[3] = 16000, + .descriptor[0].sample_rates[4] = 8000, + .descriptor[0].num_sample_rates = 5, + .descriptor[0].bit_rate[0] = 320, + .descriptor[0].bit_rate[1] = 192, + .descriptor[0].num_bitrates = 2, + .descriptor[0].profiles = 0, + .descriptor[0].modes = SND_AUDIOCHANMODE_MP3_STEREO, + .descriptor[0].formats = 0, +}; + +static struct snd_compr_codec_caps caps_aac = { + .num_descriptors = 2, + .descriptor[1].max_ch = 2, + .descriptor[0].sample_rates[0] = 48000, + .descriptor[0].sample_rates[1] = 44100, + .descriptor[0].sample_rates[2] = 32000, + .descriptor[0].sample_rates[3] = 16000, + .descriptor[0].sample_rates[4] = 8000, + .descriptor[0].num_sample_rates = 5, + .descriptor[1].bit_rate[0] = 320, + .descriptor[1].bit_rate[1] = 192, + .descriptor[1].num_bitrates = 2, + .descriptor[1].profiles = 0, + .descriptor[1].modes = 0, + .descriptor[1].formats = + (SND_AUDIOSTREAMFORMAT_MP4ADTS | + SND_AUDIOSTREAMFORMAT_RAW), +}; + +static int dsp_platform_compr_get_codec_caps(struct snd_compr_stream *cstream, + struct snd_compr_codec_caps *codec) +{ + if (codec->codec == SND_AUDIOCODEC_MP3) + *codec = caps_mp3; + else if (codec->codec == SND_AUDIOCODEC_AAC) + *codec = caps_aac; + else + return -EINVAL; + + return 0; +} + +static int dsp_platform_compr_set_metadata(struct snd_compr_stream *cstream, + struct snd_compr_metadata *metadata) +{ + return 0; +} + +const struct snd_compr_ops dsp_platform_compr_ops = { + .open = dsp_platform_compr_open, + .free = dsp_platform_compr_free, + .set_params = dsp_platform_compr_set_params, + .set_metadata = dsp_platform_compr_set_metadata, + .trigger = dsp_platform_compr_trigger, + .pointer = dsp_platform_compr_pointer, + .copy = dsp_platform_compr_copy, + .get_caps = dsp_platform_compr_get_caps, + .get_codec_caps = dsp_platform_compr_get_codec_caps, +}; From ee01b4da5e9a77ed540113bac8711b7de5e14bde Mon Sep 17 00:00:00 2001 From: Daniel Baluta Date: Thu, 4 Oct 2018 14:46:43 +0300 Subject: [PATCH 52/78] MLK-18497-12: ASoC: fsl: imx-dsp: Add DSP machine driver Finally! We register DSP as a sound card. Reviewed-by: Cosmin-Gabriel Samoila Signed-off-by: Shengjiu Wang [ Aisheng: Makefile clean for a new base ] Signed-off-by: Dong Aisheng --- sound/soc/fsl/Kconfig | 9 ++ sound/soc/fsl/Makefile | 2 + sound/soc/fsl/imx-dsp.c | 203 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 214 insertions(+) create mode 100644 sound/soc/fsl/imx-dsp.c diff --git a/sound/soc/fsl/Kconfig b/sound/soc/fsl/Kconfig index 0af54d900a8e..ac4cf2f34f7e 100644 --- a/sound/soc/fsl/Kconfig +++ b/sound/soc/fsl/Kconfig @@ -323,6 +323,15 @@ config SND_SOC_IMX_AUDMIX Say Y if you want to add support for SoC audio on an i.MX board with an Audio Mixer. +config SND_SOC_IMX_DSP + tristate "SoC Audio support for i.MX boards with DSP port" + select SND_SOC_FSL_DSP + select SND_SOC_COMPRESS + help + SoC Audio support for i.MX boards with DSP audio + Say Y if you want to add support for SoC audio on an i.MX board with + IMX DSP. + endif # SND_IMX_SOC endmenu diff --git a/sound/soc/fsl/Makefile b/sound/soc/fsl/Makefile index 36ff6b3a534b..d2d99dca5388 100644 --- a/sound/soc/fsl/Makefile +++ b/sound/soc/fsl/Makefile @@ -67,6 +67,7 @@ snd-soc-imx-sgtl5000-objs := imx-sgtl5000.o snd-soc-imx-spdif-objs := imx-spdif.o snd-soc-imx-mc13783-objs := imx-mc13783.o snd-soc-imx-audmix-objs := imx-audmix.o +snd-soc-imx-dsp-objs := imx-dsp.o obj-$(CONFIG_SND_SOC_EUKREA_TLV320) += snd-soc-eukrea-tlv320.o obj-$(CONFIG_SND_SOC_PHYCORE_AC97) += snd-soc-phycore-ac97.o @@ -77,3 +78,4 @@ obj-$(CONFIG_SND_SOC_IMX_SGTL5000) += snd-soc-imx-sgtl5000.o obj-$(CONFIG_SND_SOC_IMX_SPDIF) += snd-soc-imx-spdif.o obj-$(CONFIG_SND_SOC_IMX_MC13783) += snd-soc-imx-mc13783.o obj-$(CONFIG_SND_SOC_IMX_AUDMIX) += snd-soc-imx-audmix.o +obj-$(CONFIG_SND_SOC_IMX_DSP) += snd-soc-imx-dsp.o diff --git a/sound/soc/fsl/imx-dsp.c b/sound/soc/fsl/imx-dsp.c new file mode 100644 index 000000000000..a6f5a34f8605 --- /dev/null +++ b/sound/soc/fsl/imx-dsp.c @@ -0,0 +1,203 @@ +// SPDX-License-Identifier: (GPL-2.0+ +// +// DSP machine driver +// +// Copyright (c) 2012-2013 by Tensilica Inc. ALL RIGHTS RESERVED. +// Copyright 2018 NXP + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +struct imx_dsp_audio_data { + struct snd_soc_dai_link dai[2]; + struct snd_soc_card card; +}; + +static int imx_dsp_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_dai *codec_dai = rtd->codec_dai; + int ret; + u32 dai_format = SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_LEFT_J | + SND_SOC_DAIFMT_CBS_CFS; + + ret = snd_soc_dai_set_sysclk(codec_dai, 0, + 24576000, SND_SOC_CLOCK_IN); + if (ret) { + dev_err(rtd->dev, "failed to set codec sysclk: %d\n", ret); + return ret; + } + + ret = snd_soc_dai_set_fmt(codec_dai, dai_format); + if (ret) { + dev_err(rtd->dev, "failed to set codec dai fmt: %d\n", ret); + return ret; + } + + return 0; +} + +static struct snd_soc_ops imx_dsp_ops_be = { + .hw_params = imx_dsp_hw_params, +}; + +static int be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd, + struct snd_pcm_hw_params *params) { + + struct snd_interval *rate; + struct snd_interval *channels; + struct snd_mask *mask; + + rate = hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE); + rate->max = rate->min = 48000; + + channels = hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS); + channels->max = channels->min = 2; + + mask = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT); + snd_mask_none(mask); + snd_mask_set(mask, SNDRV_PCM_FORMAT_S16_LE); + + return 0; +} + +static const struct snd_soc_dapm_route imx_dsp_audio_map[] = { + {"Playback", NULL, "Compress Playback"},/* dai route for be and fe */ + {"Playback", NULL, "Playback"}, +}; + +static int imx_dsp_audio_probe(struct platform_device *pdev) +{ + struct device_node *cpu_np=NULL, *codec_np=NULL, *platform_np=NULL; + struct platform_device *cpu_pdev; + struct imx_dsp_audio_data *data; + int ret; + + data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL); + if (!data) { + ret = -ENOMEM; + goto fail; + } + + cpu_np = of_parse_phandle(pdev->dev.of_node, "cpu-dai", 0); + if (!cpu_np) { + dev_err(&pdev->dev, "cpu dai phandle missing or invalid\n"); + ret = -EINVAL; + goto fail; + } + + cpu_pdev = of_find_device_by_node(cpu_np); + if (!cpu_pdev) { + dev_err(&pdev->dev, "failed to find rpmsg platform device\n"); + ret = -EINVAL; + goto fail; + } + + codec_np = of_parse_phandle(pdev->dev.of_node, "audio-codec", 0); + if (!codec_np) { + dev_err(&pdev->dev, "phandle missing or invalid\n"); + ret = -EINVAL; + goto fail; + } + + platform_np = of_parse_phandle(pdev->dev.of_node, "audio-platform", 0); + if (!platform_np) { + dev_err(&pdev->dev, "platform missing or invalid\n"); + ret = -EINVAL; + goto fail; + } + + data->dai[0].name = "dsp hifi fe"; + data->dai[0].stream_name = "dsp hifi fe"; + data->dai[0].codec_dai_name = "snd-soc-dummy-dai"; + data->dai[0].codec_name = "snd-soc-dummy"; + data->dai[0].cpu_dai_name = dev_name(&cpu_pdev->dev); + data->dai[0].cpu_of_node = cpu_np; + data->dai[0].platform_of_node = platform_np; + data->dai[0].playback_only = true; + data->dai[0].capture_only = false; + data->dai[0].dpcm_playback = 1; + data->dai[0].dpcm_capture = 0; + data->dai[0].dynamic = 1, + data->dai[0].ignore_pmdown_time = 1, + data->dai[0].dai_fmt = SND_SOC_DAIFMT_LEFT_J | + SND_SOC_DAIFMT_NB_NF | + SND_SOC_DAIFMT_CBS_CFS; + + data->dai[1].name = "dsp hifi be"; + data->dai[1].stream_name = "dsp hifi be"; + data->dai[1].codec_dai_name = "cs42888"; + data->dai[1].codec_of_node = codec_np; + data->dai[1].cpu_dai_name = "snd-soc-dummy-dai"; + data->dai[1].cpu_name = "snd-soc-dummy"; + data->dai[1].platform_name = "snd-soc-dummy"; + data->dai[1].playback_only = true; + data->dai[1].capture_only = false; + data->dai[1].dpcm_playback = 1; + data->dai[1].dpcm_capture = 0; + data->dai[1].no_pcm = 1, + data->dai[1].ignore_pmdown_time = 1, + data->dai[1].dai_fmt = SND_SOC_DAIFMT_LEFT_J | + SND_SOC_DAIFMT_NB_NF | + SND_SOC_DAIFMT_CBS_CFS; + data->dai[1].ops = &imx_dsp_ops_be; + data->dai[1].be_hw_params_fixup = be_hw_params_fixup; + + data->card.dapm_routes = imx_dsp_audio_map; + data->card.num_dapm_routes = ARRAY_SIZE(imx_dsp_audio_map); + data->card.num_links = 2; + data->card.dai_link = data->dai; + + data->card.dev = &pdev->dev; + data->card.owner = THIS_MODULE; + ret = snd_soc_of_parse_card_name(&data->card, "model"); + if (ret) + goto fail; + + platform_set_drvdata(pdev, &data->card); + snd_soc_card_set_drvdata(&data->card, data); + ret = devm_snd_soc_register_card(&pdev->dev, &data->card); + if (ret) { + dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n", ret); + goto fail; + } + +fail: + if (cpu_np) + of_node_put(cpu_np); + if (codec_np) + of_node_put(codec_np); + if (platform_np) + of_node_put(platform_np); + return ret; +} + +static const struct of_device_id imx_dsp_audio_dt_ids[] = { + { .compatible = "fsl,imx-dsp-audio", }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, imx_dsp_audio_dt_ids); + +static struct platform_driver imx_dsp_audio_driver = { + .driver = { + .name = "imx-dsp-audio", + .owner = THIS_MODULE, + .pm = &snd_soc_pm_ops, + .of_match_table = imx_dsp_audio_dt_ids, + }, + .probe = imx_dsp_audio_probe, +}; +module_platform_driver(imx_dsp_audio_driver); + +MODULE_LICENSE("GPL v2"); From eae3b2f34cd1a7a0301a8fe087a5a02b8a226859 Mon Sep 17 00:00:00 2001 From: Daniel Baluta Date: Wed, 3 Oct 2018 16:45:57 +0300 Subject: [PATCH 53/78] MLK-18497-13: ASoC: fsl: dsp: Skip SDRAM section update if fw is already loaded If the DSP firmware binary is already loaded it is wrong to update SDRAM located sections because we will overwrite and data stored there. This makes suspend/resume work. Reviewed-by: Cosmin-Gabriel Samoila Signed-off-by: Shengjiu Wang --- sound/soc/fsl/fsl_dsp.c | 12 ++++++++---- sound/soc/fsl/fsl_dsp_proxy.h | 1 + 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/sound/soc/fsl/fsl_dsp.c b/sound/soc/fsl/fsl_dsp.c index ef30b5a30bd2..c849f0832b3d 100644 --- a/sound/soc/fsl/fsl_dsp.c +++ b/sound/soc/fsl/fsl_dsp.c @@ -369,6 +369,7 @@ int fsl_dsp_open_func(struct fsl_dsp *dsp_priv, struct xf_client *client) atomic_set(&client->vm_use, 0); client->global = (void *)dsp_priv; + dsp_priv->proxy.is_loaded = 0; pm_runtime_get_sync(dev); @@ -688,10 +689,12 @@ static void dsp_load_firmware(const struct firmware *fw, void *context) (!strcmp(&strtab[shdr->sh_name], ".data")) || (!strcmp(&strtab[shdr->sh_name], ".bss")) ) { - memcpy_dsp((void *)(dsp_priv->sdram_vir_addr - + (sh_addr - dsp_priv->sdram_phys_addr)), - (const void *)image, - shdr->sh_size); + if (!dsp_priv->proxy.is_loaded) { + memcpy_dsp((void *)(dsp_priv->sdram_vir_addr + + (sh_addr - dsp_priv->sdram_phys_addr)), + (const void *)image, + shdr->sh_size); + } } else { /* sh_addr is from DSP view, we need to * fixup addr because we load the firmware from @@ -710,6 +713,7 @@ static void dsp_load_firmware(const struct firmware *fw, void *context) /* start the core */ imx_sc_pm_cpu_start(dsp_priv->dsp_ipcHandle, IMX_SC_R_DSP, true, dsp_priv->iram); + dsp_priv->proxy.is_loaded = 1; } /* Initialization of the MU code. */ diff --git a/sound/soc/fsl/fsl_dsp_proxy.h b/sound/soc/fsl/fsl_dsp_proxy.h index fabcf768fb88..8df703efea63 100644 --- a/sound/soc/fsl/fsl_dsp_proxy.h +++ b/sound/soc/fsl/fsl_dsp_proxy.h @@ -299,6 +299,7 @@ struct xf_proxy { struct completion cmd_complete; int is_ready; + int is_loaded; /* ...internal lock */ spinlock_t lock; From ef0c584816f4ee3549f259cc8c48b8b42339a19d Mon Sep 17 00:00:00 2001 From: Daniel Baluta Date: Mon, 15 Oct 2018 20:09:00 +0300 Subject: [PATCH 54/78] MLK-19949: ASoC: dsp: Fix codec libraries search path Old implementation uses /usr/lib/imx-mm/audio-codec to look for codec libraries. Also this is the patch where Yocto rootfs stores the codec libraries. So until we align Yocto with the kernel lets change the driver to use the old path. Signed-off-by: Daniel Baluta --- sound/soc/fsl/fsl_dsp_xaf_api.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/fsl/fsl_dsp_xaf_api.c b/sound/soc/fsl/fsl_dsp_xaf_api.c index 503503a28922..f40560b099ad 100644 --- a/sound/soc/fsl/fsl_dsp_xaf_api.c +++ b/sound/soc/fsl/fsl_dsp_xaf_api.c @@ -183,8 +183,8 @@ int xaf_comp_create(struct xf_client *client, struct xf_proxy *proxy, memset((void *)p_comp, 0, sizeof(struct xaf_comp)); - strcpy(lib_path, "/lib/firmware/imx/dsp/"); - strcpy(lib_wrap_path, "/lib/firmware/imx/dsp/"); + strcpy(lib_path, "/usr/lib/imx-mm/audio-codec/dsp/"); + strcpy(lib_wrap_path, "/usr/lib/imx-mm/audio-codec/dsp/"); p_handle = &p_comp->handle; From 2cdddf2f2e89c73d7126355fdea7b22a3c12f74e Mon Sep 17 00:00:00 2001 From: Daniel Baluta Date: Wed, 17 Oct 2018 16:04:28 +0300 Subject: [PATCH 55/78] MLK-19972-1: ASoC: fsl: dsp: Fix compr_set_param cleanup path In case of error no cleanup was done leaving thus reasources in an undefined state. This can cause crashes like this: [ 34.259281] fsl-dsp 596e8000.dsp: load codec wrap lib error [ 34.266333] fsl-dsp 596e8000.dsp: create component failed, type = 1, err = -2 [ 34.273493] err pool alloc ret = -2 [ 34.298363] Unable to handle kernel NULL pointer dereference at virtual address 00000000 ... which happens when lib_dsp_codec_wrap.so is not present. While at it, we also realign some lines of code in order to avoid going over the 80 characters limit that Linux kernel coding style preaches on. Reviewed-by: Shengjiu Wang Signed-off-by: Daniel Baluta --- sound/soc/fsl/fsl_dsp_platform_compress.c | 62 ++++++++++++++--------- 1 file changed, 39 insertions(+), 23 deletions(-) diff --git a/sound/soc/fsl/fsl_dsp_platform_compress.c b/sound/soc/fsl/fsl_dsp_platform_compress.c index 004a539d2b8a..6f0d5515c740 100644 --- a/sound/soc/fsl/fsl_dsp_platform_compress.c +++ b/sound/soc/fsl/fsl_dsp_platform_compress.c @@ -148,37 +148,43 @@ static int dsp_platform_compr_set_params(struct snd_compr_stream *cstream, ret = xaf_pipeline_create(&drv->pipeline); if (ret) { dev_err(component->dev, "create pipeline error\n"); - goto failed; + goto err_pool_alloc; } /* ...create component */ - ret = xaf_comp_create(drv->client, p_proxy, &drv->component[0], drv->codec_type); + ret = xaf_comp_create(drv->client, p_proxy, &drv->component[0], + drv->codec_type); if (ret) { - dev_err(component->dev, "create component failed, type = %d, err = %d\n", - drv->codec_type, ret); - goto failed; + dev_err(component->dev, + "create component failed type = %d, err = %d\n", + drv->codec_type, ret); + goto err_pool_alloc; } - ret = xaf_comp_create(drv->client, p_proxy, &drv->component[1], RENDER_ESAI); + ret = xaf_comp_create(drv->client, p_proxy, &drv->component[1], + RENDER_ESAI); if (ret) { - dev_err(component->dev, "create component failed, type = %d, err = %d\n", - RENDER_ESAI, ret); - goto failed; + dev_err(component->dev, + "create component failed, type = %d, err = %d\n", + RENDER_ESAI, ret); + goto err_comp0_create; } /* ...add component into pipeline */ ret = xaf_comp_add(&drv->pipeline, &drv->component[0]); if (ret) { - dev_err(component->dev, "add component failed, type = %d, err = %d\n", - drv->codec_type, ret); - goto failed; + dev_err(component->dev, + "add component failed, type = %d, err = %d\n", + drv->codec_type, ret); + goto err_comp1_create; } ret = xaf_comp_add(&drv->pipeline, &drv->component[1]); if (ret) { - dev_err(component->dev, "add component failed, type = %d, err = %d\n", - drv->codec_type, ret); - goto failed; + dev_err(component->dev, + "add component failed, type = %d, err = %d\n", + drv->codec_type, ret); + goto err_comp1_create; } drv->client->input_bytes = 0; @@ -188,31 +194,41 @@ static int dsp_platform_compr_set_params(struct snd_compr_stream *cstream, s_param.value = params->codec.sample_rate; ret = xaf_comp_set_config(drv->client, &drv->component[1], 1, &s_param); if (ret) { - dev_err(component->dev, "set param[cmd:0x%x|val:0x%x] error, err = %d\n", + dev_err(component->dev, + "set param[cmd:0x%x|val:0x%x] error, err = %d\n", s_param.id, s_param.value, ret); - goto failed; + goto err_comp1_create; } s_param.id = XA_RENDERER_CONFIG_PARAM_CHANNELS; s_param.value = params->codec.ch_out; ret = xaf_comp_set_config(drv->client, &drv->component[1], 1, &s_param); if (ret) { - dev_err(component->dev, "set param[cmd:0x%x|val:0x%x] error, err = %d\n", + dev_err(component->dev, + "set param[cmd:0x%x|val:0x%x] error, err = %d\n", s_param.id, s_param.value, ret); - goto failed; + goto err_comp1_create; } s_param.id = XA_RENDERER_CONFIG_PARAM_PCM_WIDTH; s_param.value = 16; ret = xaf_comp_set_config(drv->client, &drv->component[1], 1, &s_param); if (ret) { - dev_err(component->dev, "set param[cmd:0x%x|val:0x%x] error, err = %d\n", + dev_err(component->dev, + "set param[cmd:0x%x|val:0x%x] error, err = %d\n", s_param.id, s_param.value, ret); - goto failed; + goto err_comp1_create; } - -failed: return 0; + +err_comp1_create: + xaf_comp_delete(drv->client, &drv->component[1]); +err_comp0_create: + xaf_comp_delete(drv->client, &drv->component[0]); +err_pool_alloc: + xf_pool_free(drv->client, p_proxy->aux); + + return ret; } static int dsp_platform_compr_trigger_start(struct snd_compr_stream *cstream) From d50e2b69e8026a22c164c5009aa556652ade723d Mon Sep 17 00:00:00 2001 From: Daniel Baluta Date: Fri, 19 Oct 2018 14:09:17 +0300 Subject: [PATCH 56/78] MLK-19972-2: ASoC: fsl: dsp: Fix component creation cleanup path Because we don't correctly free resources when an error occurs on component creation path we can end up with partially initialized components. Freeing such partially initialized components most of the time leads to kernel crashing in pain. Avoid this by making sure we either: * return a fully initialized component, comp->active = true * don't "create" the component at all, comp->active = false Reviewed-by: Shengjiu Wang Signed-off-by: Daniel Baluta --- sound/soc/fsl/fsl_dsp_xaf_api.c | 23 ++++++++++++++++++++--- sound/soc/fsl/fsl_dsp_xaf_api.h | 2 ++ 2 files changed, 22 insertions(+), 3 deletions(-) diff --git a/sound/soc/fsl/fsl_dsp_xaf_api.c b/sound/soc/fsl/fsl_dsp_xaf_api.c index f40560b099ad..05d1a1685989 100644 --- a/sound/soc/fsl/fsl_dsp_xaf_api.c +++ b/sound/soc/fsl/fsl_dsp_xaf_api.c @@ -233,14 +233,14 @@ int xaf_comp_create(struct xf_client *client, struct xf_proxy *proxy, ret = xf_load_lib(client, p_handle, &p_comp->codec_wrap_lib); if (ret) { dev_err(dsp_priv->dev, "load codec wrap lib error\n"); - return ret; + goto err_wrap_load; } /* ...load codec lib */ ret = xf_load_lib(client, p_handle, &p_comp->codec_lib); if (ret) { dev_err(dsp_priv->dev, "load codec lib error\n"); - return ret; + goto err_codec_load; } /* ...allocate input buffer */ @@ -248,7 +248,7 @@ int xaf_comp_create(struct xf_client *client, struct xf_proxy *proxy, XF_POOL_INPUT, &p_comp->inpool); if (ret) { dev_err(dsp_priv->dev, "alloc input buf error\n"); - return ret; + goto err_pool_alloc; } /* ...initialize input buffer pointer */ @@ -256,6 +256,17 @@ int xaf_comp_create(struct xf_client *client, struct xf_proxy *proxy, p_comp->inptr = xf_buffer_data(buf); } + p_comp->active = true; + + return ret; + +err_pool_alloc: + xf_unload_lib(client, p_handle, &p_comp->codec_lib); +err_codec_load: + xf_unload_lib(client, p_handle, &p_comp->codec_wrap_lib); +err_wrap_load: + xf_close(client, p_handle); + return ret; } @@ -266,6 +277,12 @@ int xaf_comp_delete(struct xf_client *client, struct xaf_comp *p_comp) bool loadlib = true; u32 ret = 0; + if (!p_comp->active) + return ret; + + /* mark component as unusable from this point */ + p_comp->active = false; + if (p_comp->comp_type == RENDER_ESAI) loadlib = false; diff --git a/sound/soc/fsl/fsl_dsp_xaf_api.h b/sound/soc/fsl/fsl_dsp_xaf_api.h index 5087b46520d5..d6dc734000aa 100644 --- a/sound/soc/fsl/fsl_dsp_xaf_api.h +++ b/sound/soc/fsl/fsl_dsp_xaf_api.h @@ -45,6 +45,8 @@ struct xaf_comp { struct lib_info codec_lib; struct lib_info codec_wrap_lib; + + int active; /* component fully initialized */ }; struct xaf_pipeline { From 3aa009e2c04696fd233f5d442cd8835c2b6b06ef Mon Sep 17 00:00:00 2001 From: Daniel Baluta Date: Fri, 2 Nov 2018 17:20:53 +0200 Subject: [PATCH 57/78] MLK-20094: ASoC: fsl: dsp: Fix crash in compress cleanup path We must find a way to no longer touch resources after they are cleand up. Now, after a stress test we get the following crash: [ 2156.863772] fsl-dsp 596e8000.dsp: xf_pool_alloc failed [ 2156.869337] Unable to handle kernel NULL pointer dereference at virtual address 00000060 [ 2157.148594] [] _raw_spin_lock+0x14/0x48 [ 2157.153995] [] xf_cmd_send_recv_complete+0x40/0xf0 [ 2157.160354] [] xf_close+0x40/0x88 [ 2157.165239] [] xaf_comp_delete+0x5c/0x70 [ 2157.170730] [] dsp_platform_compr_free+0xa0/0xe8 [ 2157.176917] [] soc_compr_free_fe+0x144/0x1a0 [ 2157.182754] [] snd_compr_free+0x64/0x98 This happens because: 1) dsp_platform_process work handler waits in a loop for messages to arrive. 2) when cplay process finishes it cleans up most of the resources. 3) when another cplay process starts it reinitializes the resources including queues for example. 4) a message will be generated and kernel will crash because dsp_platform_process uses the older queues. A solution for this is to make sure dsp_platform_process work loop is stopped at cleanup time. We use is_active state and signal dsp_platform_process handler to finish because we are on the cleanup path. While at it replace cancel_work with cancel_work sync to be sure that work handler ends before going on with the rest of the cleanup. Reviewed-by: Cosmin-Gabriel Samoila Signed-off-by: Daniel Baluta --- sound/soc/fsl/fsl_dsp.c | 1 + sound/soc/fsl/fsl_dsp_platform_compress.c | 8 +++++--- sound/soc/fsl/fsl_dsp_proxy.c | 5 +++-- sound/soc/fsl/fsl_dsp_proxy.h | 2 +- 4 files changed, 10 insertions(+), 6 deletions(-) diff --git a/sound/soc/fsl/fsl_dsp.c b/sound/soc/fsl/fsl_dsp.c index c849f0832b3d..629947f65ca8 100644 --- a/sound/soc/fsl/fsl_dsp.c +++ b/sound/soc/fsl/fsl_dsp.c @@ -370,6 +370,7 @@ int fsl_dsp_open_func(struct fsl_dsp *dsp_priv, struct xf_client *client) client->global = (void *)dsp_priv; dsp_priv->proxy.is_loaded = 0; + dsp_priv->proxy.is_active = 1; pm_runtime_get_sync(dev); diff --git a/sound/soc/fsl/fsl_dsp_platform_compress.c b/sound/soc/fsl/fsl_dsp_platform_compress.c index 6f0d5515c740..42c80ee8ccb8 100644 --- a/sound/soc/fsl/fsl_dsp_platform_compress.c +++ b/sound/soc/fsl/fsl_dsp_platform_compress.c @@ -28,9 +28,9 @@ void dsp_platform_process(struct work_struct *w) while (1) { rmsg = xf_cmd_recv(proxy, &client->wait, &client->queue, 1); - if (IS_ERR(rmsg)) { + + if (!proxy->is_active || IS_ERR(rmsg)) return; - } if (rmsg->opcode == XF_EMPTY_THIS_BUFFER) { client->consume_bytes += rmsg->length; snd_compr_fragment_elapsed(client->cstream); @@ -101,7 +101,9 @@ static int dsp_platform_compr_free(struct snd_compr_stream *cstream) cpu_dai->driver->ops->shutdown(NULL, cpu_dai); - ret = cancel_work(&drv->client->work); + drv->client->proxy->is_active = 0; + wake_up(&drv->client->wait); + cancel_work_sync(&drv->client->work); fsl_dsp_close_func(drv->client); diff --git a/sound/soc/fsl/fsl_dsp_proxy.c b/sound/soc/fsl/fsl_dsp_proxy.c index 1f4390487c78..94bffc06c608 100644 --- a/sound/soc/fsl/fsl_dsp_proxy.c +++ b/sound/soc/fsl/fsl_dsp_proxy.c @@ -557,12 +557,13 @@ struct xf_message *xf_cmd_recv(struct xf_proxy *proxy, struct xf_msg_queue *queue, int wait) { - struct xf_message *m; + struct xf_message *m = NULL; int ret; /* ...wait for message reception (take lock on success) */ ret = wait_event_interruptible(*wq, - (m = xf_msg_received(proxy, queue)) != NULL || !wait); + (m = xf_msg_received(proxy, queue)) != NULL || !wait + || !proxy->is_active); if (ret) return ERR_PTR(-EINTR); diff --git a/sound/soc/fsl/fsl_dsp_proxy.h b/sound/soc/fsl/fsl_dsp_proxy.h index 8df703efea63..c80412a632ff 100644 --- a/sound/soc/fsl/fsl_dsp_proxy.h +++ b/sound/soc/fsl/fsl_dsp_proxy.h @@ -300,7 +300,7 @@ struct xf_proxy { struct completion cmd_complete; int is_ready; int is_loaded; - + int is_active; /* ...internal lock */ spinlock_t lock; From fc803f2425607fc71ae513df55e0e185d45c4e8b Mon Sep 17 00:00:00 2001 From: Ranjani Vaidyanathan Date: Fri, 2 Nov 2018 16:05:51 -0500 Subject: [PATCH 58/78] MLK-20222-4 sound: Update SCFW API Update SCFW API to the following commit: " ("430d1e3646fbe75e339e18abf2330565eac906e0") Author: Chuck Cannon Date: Fri Nov 2 15:25:45 2018 -0500 SCF-105: RN updates. " Signed-off-by: Ranjani Vaidyanathan --- sound/soc/fsl/fsl_dsp.h | 5 ----- 1 file changed, 5 deletions(-) diff --git a/sound/soc/fsl/fsl_dsp.h b/sound/soc/fsl/fsl_dsp.h index ad6f7a9e8be1..6f983f7fae5f 100644 --- a/sound/soc/fsl/fsl_dsp.h +++ b/sound/soc/fsl/fsl_dsp.h @@ -122,11 +122,6 @@ struct fsl_dsp { #define OUTPUT_BUF_SIZE 16384 #define DSP_CONFIG_SIZE 4096 -#define SC_C_OFS_SEL 39 -#define SC_C_OFS_AUDIO 40 -#define SC_C_OFS_PERIPH 41 -#define SC_C_OFS_IRQ 42 - void *memcpy_dsp(void *dest, const void *src, size_t count); void *memset_dsp(void *dest, int c, size_t count); struct xf_client *xf_client_lookup(struct fsl_dsp *dsp_priv, u32 id); From 20a12565f1e2e8899ed046025a2da1dd6e6f4ed3 Mon Sep 17 00:00:00 2001 From: Daniel Baluta Date: Thu, 8 Nov 2018 14:40:50 +0200 Subject: [PATCH 59/78] MLK-20189-1: ASoC: fsl: dsp: Unlock proxy->lock on error path xf_cmd_recv will return with lock taken in two cases: * msg was received * waiting for msg was interrupted by a signal Make sure we unlock proxy->lock in both cases. This fixes Coverity issue: CID3335482. Reviewed-by: S.j. Wang Reviewed-by: Cosmin-Gabriel Samoila Signed-off-by: Daniel Baluta --- sound/soc/fsl/fsl_dsp.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/soc/fsl/fsl_dsp.c b/sound/soc/fsl/fsl_dsp.c index 629947f65ca8..f303a73df282 100644 --- a/sound/soc/fsl/fsl_dsp.c +++ b/sound/soc/fsl/fsl_dsp.c @@ -231,6 +231,7 @@ static int fsl_dsp_ipc_msg_from_dsp(struct xf_client *client, m = xf_cmd_recv(&dsp_priv->proxy, &client->wait, &client->queue, 0); if (IS_ERR(m)) { + xf_unlock(&dsp_priv->proxy.lock); dev_err(dev, "receiving failed: %d", (int)PTR_ERR(m)); return PTR_ERR(m); } From 4130b46451fdf6b9920cf8edea7069c5a86586cd Mon Sep 17 00:00:00 2001 From: Daniel Baluta Date: Thu, 8 Nov 2018 15:07:56 +0200 Subject: [PATCH 60/78] MLK-20189-2: ASoC: dsp: Replace atomic_dec_return with atomic_dec Return value is not used so better use atomic_dec. This also silences coverity warning CID3344689. Reviewed-by: S.j. Wang Reviewed-by: Cosmin-Gabriel Samoila Signed-off-by: Daniel Baluta --- sound/soc/fsl/fsl_dsp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/fsl/fsl_dsp.c b/sound/soc/fsl/fsl_dsp.c index f303a73df282..bd180d9356e6 100644 --- a/sound/soc/fsl/fsl_dsp.c +++ b/sound/soc/fsl/fsl_dsp.c @@ -502,7 +502,7 @@ static void dsp_mmap_close(struct vm_area_struct *vma) pr_debug("xf_mmap_close: vma = %p, b = %p", vma, client); /* ...decrement number of mapping */ - atomic_dec_return(&client->vm_use); + atomic_dec(&client->vm_use); } /* ...memory map operations */ From a314e4fe32a16ca94484c596b1370e40453ec1ae Mon Sep 17 00:00:00 2001 From: Daniel Baluta Date: Thu, 8 Nov 2018 15:52:08 +0200 Subject: [PATCH 61/78] MLK-20189-3: ASoC: fsl: library_load: Remove dead code At this point err is always 0. So, just remove the check. Fixes: CID1477380 Reviewed-by: S.j. Wang Reviewed-by: Cosmin-Gabriel Samoila Signed-off-by: Daniel Baluta --- sound/soc/fsl/fsl_dsp_library_load.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/sound/soc/fsl/fsl_dsp_library_load.c b/sound/soc/fsl/fsl_dsp_library_load.c index 37bce3a289b5..11bb9396ab4d 100644 --- a/sound/soc/fsl/fsl_dsp_library_load.c +++ b/sound/soc/fsl/fsl_dsp_library_load.c @@ -438,11 +438,6 @@ xtlib_load_split_pi_library_common(struct xtlib_packaged_library *library, xtlib_globals->byteswap), lib_info); - if (err != XTLIB_NO_ERR) { - xtlib_globals->err = err; - return 0; - } - return (xt_ptr)xtlib_host_word((Elf32_Word)info->start_sym, xtlib_globals->byteswap); } From 13bc9cfb13def83d394bb6ca7a8fbcdbf0f00f44 Mon Sep 17 00:00:00 2001 From: Daniel Baluta Date: Thu, 8 Nov 2018 16:02:40 +0200 Subject: [PATCH 62/78] MLK-20189-4: ASoC: fsl: library_load: Check return value for kernel_read Bail out if kernel_read returns an error. Fixes: CID1477415 Reviewed-by: S.j. Wang Reviewed-by: Cosmin-Gabriel Samoila Signed-off-by: Daniel Baluta --- sound/soc/fsl/fsl_dsp_library_load.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/sound/soc/fsl/fsl_dsp_library_load.c b/sound/soc/fsl/fsl_dsp_library_load.c index 11bb9396ab4d..d273f7296e29 100644 --- a/sound/soc/fsl/fsl_dsp_library_load.c +++ b/sound/soc/fsl/fsl_dsp_library_load.c @@ -484,7 +484,9 @@ load_dpu_with_library(struct xf_client *client, struct xf_proxy *proxy, return -ENOMEM; vfs_llseek(file, 0, SEEK_SET); - kernel_read(file, srambuf, filesize, &pos); + ret_val = kernel_read(file, srambuf, filesize, &pos); + if (ret_val < 0) + return ret_val; filp_close(file, NULL); ret_val = xtlib_split_pi_library_size( From f5f13e4c2c78efb8dda749aeedbc4b51ee9694ee Mon Sep 17 00:00:00 2001 From: Daniel Baluta Date: Thu, 8 Nov 2018 16:13:12 +0200 Subject: [PATCH 63/78] MLK-20189-5: ASoC: fsl: dsp_proxy: Unlock proxy->lock on error path xf_cmd_send_recv returns with lock taken if waiting was interrupted by a signal. This fixes Coverity issues: CID5233120 / CID5233060 Reviewed-by: S.j. Wang Reviewed-by: Cosmin-Gabriel Samoila Signed-off-by: Daniel Baluta --- sound/soc/fsl/fsl_dsp_proxy.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sound/soc/fsl/fsl_dsp_proxy.c b/sound/soc/fsl/fsl_dsp_proxy.c index 94bffc06c608..f29b6ecaacbb 100644 --- a/sound/soc/fsl/fsl_dsp_proxy.c +++ b/sound/soc/fsl/fsl_dsp_proxy.c @@ -678,6 +678,7 @@ int xf_cmd_alloc(struct xf_proxy *proxy, void **buffer, u32 length) /* ...send command to remote proxy */ m = xf_cmd_send_recv(proxy, id, XF_ALLOC, NULL, length); if (IS_ERR(m)) { + xf_unlock(&proxy->lock); ret = PTR_ERR(m); return ret; } @@ -707,6 +708,7 @@ int xf_cmd_free(struct xf_proxy *proxy, void *buffer, u32 length) /* ...synchronously execute freeing command */ m = xf_cmd_send_recv(proxy, id, XF_FREE, buffer, length); if (IS_ERR(m)) { + xf_unlock(&proxy->lock); ret = PTR_ERR(m); return ret; } From 4bff2e7204131a99510cfbaa4397c633ac7ab47a Mon Sep 17 00:00:00 2001 From: Daniel Baluta Date: Fri, 9 Nov 2018 11:35:46 +0200 Subject: [PATCH 64/78] MLK-20189-6: ASoC: fsl: Skip checking for string section type e_shstrndx already contains the section header index, so shdr->sh_type will always be SHT_STRTAB. Remove this redundant check and make Coverity happy. Fixes: CID3901026 Reviewed-by: Cosmin-Gabriel Samoila Signed-off-by: Daniel Baluta --- sound/soc/fsl/fsl_dsp.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/sound/soc/fsl/fsl_dsp.c b/sound/soc/fsl/fsl_dsp.c index bd180d9356e6..3825fe5e2e59 100644 --- a/sound/soc/fsl/fsl_dsp.c +++ b/sound/soc/fsl/fsl_dsp.c @@ -657,8 +657,7 @@ static void dsp_load_firmware(const struct firmware *fw, void *context) shdr = (Elf32_Shdr *)(addr + ehdr->e_shoff + (ehdr->e_shstrndx * sizeof(Elf32_Shdr))); - if (shdr->sh_type == SHT_STRTAB) - strtab = (unsigned char *)(addr + shdr->sh_offset); + strtab = (unsigned char *)(addr + shdr->sh_offset); /* Load each appropriate section */ for (i = 0; i < ehdr->e_shnum; ++i) { From 1ac4dce34cf9962638a8f7378a0ca8db50517325 Mon Sep 17 00:00:00 2001 From: Daniel Baluta Date: Tue, 13 Nov 2018 15:21:36 +0200 Subject: [PATCH 65/78] MLK-20189-10: ASoC: fsl: dsp: Avoid unnecessary check strtab is always non-null so remove unnecessary check. This is a follow up of patch 167a6d79f ("ASoC: fsl: Skip checking for string section type") and finally fixes CID3901026 Reviewed-by: Shengjiu Wang Signed-off-by: Daniel Baluta --- sound/soc/fsl/fsl_dsp.c | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/sound/soc/fsl/fsl_dsp.c b/sound/soc/fsl/fsl_dsp.c index 3825fe5e2e59..fa238834385b 100644 --- a/sound/soc/fsl/fsl_dsp.c +++ b/sound/soc/fsl/fsl_dsp.c @@ -668,13 +668,10 @@ static void dsp_load_firmware(const struct firmware *fw, void *context) shdr->sh_addr == 0 || shdr->sh_size == 0) continue; - if (strtab) { - dev_dbg(dev, "%sing %s @ 0x%08lx (%ld bytes)\n", - (shdr->sh_type == SHT_NOBITS) ? "Clear" : "Load", - &strtab[shdr->sh_name], - (unsigned long)shdr->sh_addr, - (long)shdr->sh_size); - } + dev_dbg(dev, "%sing %s @ 0x%08lx (%ld bytes)\n", + (shdr->sh_type == SHT_NOBITS) ? "Clear" : "Load", + &strtab[shdr->sh_name], (unsigned long)shdr->sh_addr, + (long)shdr->sh_size); sh_addr = shdr->sh_addr; From b9668d7af2016b052dd5ac7c8ccb64303935bb86 Mon Sep 17 00:00:00 2001 From: Daniel Baluta Date: Tue, 27 Nov 2018 10:44:13 +0200 Subject: [PATCH 66/78] MLK-20095-3: ASoC: fsl: dsp: Add ASRC clocks We enable the ASRC clocks from CPU side. We only need the following clocks: "mem", "ipg" and "asrc0..3". Signed-off-by: Daniel Baluta Reviewed-by: Shengjiu Wang --- sound/soc/fsl/fsl_dsp_cpu.c | 47 +++++++++++++++++++++++++++++++++++-- sound/soc/fsl/fsl_dsp_cpu.h | 5 ++++ 2 files changed, 50 insertions(+), 2 deletions(-) diff --git a/sound/soc/fsl/fsl_dsp_cpu.c b/sound/soc/fsl/fsl_dsp_cpu.c index c203b70160f4..4903deb3efd7 100644 --- a/sound/soc/fsl/fsl_dsp_cpu.c +++ b/sound/soc/fsl/fsl_dsp_cpu.c @@ -47,7 +47,8 @@ static const struct snd_soc_component_driver audio_dsp_component = { static int dsp_audio_probe(struct platform_device *pdev) { struct fsl_dsp_audio *dsp_audio; - int ret; + int i, ret; + char tmp[16]; dsp_audio = devm_kzalloc(&pdev->dev, sizeof(*dsp_audio), GFP_KERNEL); if (dsp_audio == NULL) @@ -73,6 +74,27 @@ static int dsp_audio_probe(struct platform_device *pdev) dsp_audio->m_clk = NULL; } + dsp_audio->asrc_mem_clk = devm_clk_get(&pdev->dev, "mem"); + if (IS_ERR(dsp_audio->asrc_mem_clk)) { + dev_err(&pdev->dev, "failed to get mem clock\n"); + dsp_audio->asrc_mem_clk = NULL; + } + + dsp_audio->asrc_ipg_clk = devm_clk_get(&pdev->dev, "ipg"); + if (IS_ERR(dsp_audio->asrc_ipg_clk)) { + dev_err(&pdev->dev, "failed to get ipg clock\n"); + dsp_audio->asrc_ipg_clk = NULL; + } + + for (i = 0; i < ASRC_CLK_MAX_NUM; i++) { + sprintf(tmp, "asrck_%x", i); + dsp_audio->asrck_clk[i] = devm_clk_get(&pdev->dev, tmp); + if (IS_ERR(dsp_audio->asrck_clk[i])) { + dev_err(&pdev->dev, "failed to get %s clock\n", tmp); + dsp_audio->asrck_clk[i] = NULL; + } + } + pm_runtime_enable(&pdev->dev); /* now register audio DSP platform driver */ @@ -100,7 +122,7 @@ static int dsp_audio_remove(struct platform_device *pdev) static int dsp_runtime_resume(struct device *dev) { struct fsl_dsp_audio *dsp_audio = dev_get_drvdata(dev); - int ret; + int i, ret; ret = clk_prepare_enable(dsp_audio->bus_clk); if (ret) { @@ -114,13 +136,34 @@ static int dsp_runtime_resume(struct device *dev) return ret; } + ret = clk_prepare_enable(dsp_audio->asrc_mem_clk); + if (ret < 0) + dev_err(dev, "Failed to enable asrc_mem_clk ret = %d\n", ret); + + ret = clk_prepare_enable(dsp_audio->asrc_ipg_clk); + if (ret < 0) + dev_err(dev, "Failed to enable asrc_ipg_clk ret = %d\n", ret); + + for (i = 0; i < ASRC_CLK_MAX_NUM; i++) { + ret = clk_prepare_enable(dsp_audio->asrck_clk[i]); + if (ret < 0) + dev_err(dev, "failed to prepare arc clk %d\n", i); + } + return ret; } static int dsp_runtime_suspend(struct device *dev) { + int i; struct fsl_dsp_audio *dsp_audio = dev_get_drvdata(dev); + for (i = 0; i < ASRC_CLK_MAX_NUM; i++) + clk_disable_unprepare(dsp_audio->asrck_clk[i]); + + clk_disable_unprepare(dsp_audio->asrc_ipg_clk); + clk_disable_unprepare(dsp_audio->asrc_mem_clk); + clk_disable_unprepare(dsp_audio->m_clk); clk_disable_unprepare(dsp_audio->bus_clk); diff --git a/sound/soc/fsl/fsl_dsp_cpu.h b/sound/soc/fsl/fsl_dsp_cpu.h index ef2813868be8..a6c1043a5908 100644 --- a/sound/soc/fsl/fsl_dsp_cpu.h +++ b/sound/soc/fsl/fsl_dsp_cpu.h @@ -8,10 +8,15 @@ #ifndef __FSL_DSP_CPU_H #define __FSL_DSP_CPU_H +#define ASRC_CLK_MAX_NUM 4 + struct fsl_dsp_audio { struct platform_device *pdev; struct clk *bus_clk; struct clk *m_clk; + struct clk *asrc_mem_clk; + struct clk *asrc_ipg_clk; + struct clk *asrck_clk[ASRC_CLK_MAX_NUM]; }; #endif /*__FSL_DSP_CPU_H*/ From b35ac86e876b69efc85ebb97f7dca3a695762ef6 Mon Sep 17 00:00:00 2001 From: Daniel Baluta Date: Fri, 14 Dec 2018 19:15:07 +0200 Subject: [PATCH 67/78] MLK-20095-3: ASoC: fsl: Differentiate between QXP and QM On QM the DSP is inside the VPU subsystem while in QXP it is inside the Audio DMA subsystem. For this reason there are "subtle" differences. Introduce new compatible string for QM to help us correctly configure the DSP depending on the board they run. dsp_mem_msg structure is shared with the DSP, so by introducing new member dsp_board_type we can let DSP know on which target it runs. Reviewed-by: Shengjiu Wang Signed-off-by: Daniel Baluta --- sound/soc/fsl/fsl_dsp.c | 6 ++++++ sound/soc/fsl/fsl_dsp.h | 6 +++++- sound/soc/fsl/fsl_dsp_proxy.c | 1 + sound/soc/fsl/fsl_dsp_proxy.h | 1 + 4 files changed, 13 insertions(+), 1 deletion(-) diff --git a/sound/soc/fsl/fsl_dsp.c b/sound/soc/fsl/fsl_dsp.c index fa238834385b..63c11db54f04 100644 --- a/sound/soc/fsl/fsl_dsp.c +++ b/sound/soc/fsl/fsl_dsp.c @@ -792,6 +792,11 @@ static int fsl_dsp_probe(struct platform_device *pdev) if (!dsp_priv) return -ENOMEM; + if (of_device_is_compatible(np, "fsl,imx8qxp-dsp")) + dsp_priv->dsp_board_type = DSP_IMX8QXP_TYPE; + else + dsp_priv->dsp_board_type = DSP_IMX8QM_TYPE; + dsp_priv->dev = &pdev->dev; /* Get the addresses and IRQ */ @@ -1059,6 +1064,7 @@ static const struct dev_pm_ops fsl_dsp_pm = { static const struct of_device_id fsl_dsp_ids[] = { { .compatible = "fsl,imx8qxp-dsp", }, + { .compatible = "fsl,imx8qm-dsp", }, {} }; MODULE_DEVICE_TABLE(of, fsl_dsp_ids); diff --git a/sound/soc/fsl/fsl_dsp.h b/sound/soc/fsl/fsl_dsp.h index 6f983f7fae5f..99199e4d5c22 100644 --- a/sound/soc/fsl/fsl_dsp.h +++ b/sound/soc/fsl/fsl_dsp.h @@ -21,6 +21,10 @@ typedef void (*memset_func) (void *s, int c, size_t n); /* ...maximal number of IPC clients per proxy */ #define XF_CFG_MAX_IPC_CLIENTS (1 << 4) +enum { + DSP_IMX8QXP_TYPE = 0, + DSP_IMX8QM_TYPE, +}; /* ...proxy client data */ struct xf_client { @@ -87,7 +91,7 @@ struct fsl_dsp { void *dsp_config_virt; dma_addr_t dsp_config_phys; int dsp_config_size; - + int dsp_board_type; unsigned int fixup_offset; /* ...proxy data structures */ diff --git a/sound/soc/fsl/fsl_dsp_proxy.c b/sound/soc/fsl/fsl_dsp_proxy.c index f29b6ecaacbb..266a50deab91 100644 --- a/sound/soc/fsl/fsl_dsp_proxy.c +++ b/sound/soc/fsl/fsl_dsp_proxy.c @@ -192,6 +192,7 @@ int send_dpu_ext_msg_addr(struct xf_proxy *proxy) dpu_ext_msg->scratch_size = dsp_priv->scratch_buf_size; dpu_ext_msg->dsp_config_phys = dsp_priv->dsp_config_phys; dpu_ext_msg->dsp_config_size = dsp_priv->dsp_config_size; + dpu_ext_msg->dsp_board_type = dsp_priv->dsp_board_type; icm_intr_extended_send(proxy, msghdr.allbits, &ext_msg); diff --git a/sound/soc/fsl/fsl_dsp_proxy.h b/sound/soc/fsl/fsl_dsp_proxy.h index c80412a632ff..9b5c78f8b993 100644 --- a/sound/soc/fsl/fsl_dsp_proxy.h +++ b/sound/soc/fsl/fsl_dsp_proxy.h @@ -350,6 +350,7 @@ struct dsp_mem_msg { u32 scratch_size; u32 dsp_config_phys; u32 dsp_config_size; + u32 dsp_board_type; }; static inline void xf_lock_init(spinlock_t *lock) From 4ef357502632565256d61200d499c102a8377e2b Mon Sep 17 00:00:00 2001 From: Daniel Baluta Date: Fri, 14 Dec 2018 19:19:15 +0200 Subject: [PATCH 68/78] MLK-20095-4: ASoC: fsl: Use hardwired system address offset source select for QM We set system address offset select to 0 on QM because of the following reasons: * SC_C_OFS_PERIPH, it is not available for QM * SC_C_OFS_AUDIO, it is not used * SC_C_OFS_IRQ, needs to get outside of the VPU. A simplified version of the code is: if (dsp_priv->dsp_board_type == DSP_IMX8QXP_TYPE) { sc_misc_set_control(ipcHndl, SC_R_DSP, SC_C_OFS_SEL, 1); sc_misc_set_control(ipcHndl, SC_R_DSP, SC_C_OFS_PERIPH, 0x5A); sc_misc_set_control(ipcHndl, SC_R_DSP, SC_C_OFS_IRQ, 0x51); sc_misc_set_control(ipcHndl, SC_R_DSP, SC_C_OFS_AUDIO, 0x80); } } else { sc_misc_set_control(ipcHndl, SC_R_DSP, SC_C_OFS_SEL, 0); } Reviewed-by: Shengjiu Wang Signed-off-by: Daniel Baluta --- sound/soc/fsl/fsl_dsp.c | 56 ++++++++++++++++++++++++----------------- 1 file changed, 33 insertions(+), 23 deletions(-) diff --git a/sound/soc/fsl/fsl_dsp.c b/sound/soc/fsl/fsl_dsp.c index 63c11db54f04..1d5b28fc05ac 100644 --- a/sound/soc/fsl/fsl_dsp.c +++ b/sound/soc/fsl/fsl_dsp.c @@ -819,32 +819,42 @@ static int fsl_dsp_probe(struct platform_device *pdev) return ret; }; - ret = imx_sc_misc_set_control(dsp_priv->dsp_ipcHandle, IMX_SC_R_DSP, - IMX_SC_C_OFS_SEL, 1); - if (ret) { - dev_err(&pdev->dev, "Error system address offset source select\n"); - return -EIO; - } + if (dsp_priv->dsp_board_type == DSP_IMX8QXP_TYPE) { + ret = imx_sc_misc_set_control(dsp_priv->dsp_ipcHandle, IMX_SC_R_DSP, + IMX_SC_C_OFS_SEL, 1); + if (ret) { + dev_err(&pdev->dev, "Error system address offset source select\n"); + return -EIO; + } - ret = imx_sc_misc_set_control(dsp_priv->dsp_ipcHandle, IMX_SC_R_DSP, - IMX_SC_C_OFS_AUDIO, 0x80); - if (ret) { - dev_err(&pdev->dev, "Error system address offset of AUDIO\n"); - return -EIO; - } + ret = imx_sc_misc_set_control(dsp_priv->dsp_ipcHandle, IMX_SC_R_DSP, + IMX_SC_C_OFS_PERIPH, 0x5A); + if (ret) { + dev_err(&pdev->dev, "Error system address offset of PERIPH %d\n", + ret); + return -EIO; + } - ret = imx_sc_misc_set_control(dsp_priv->dsp_ipcHandle, IMX_SC_R_DSP, - IMX_SC_C_OFS_PERIPH, 0x5A); - if (ret) { - dev_err(&pdev->dev, "Error system address offset of PERIPH %d\n", - sciErr); - } + ret = imx_sc_misc_set_control(dsp_priv->dsp_ipcHandle, IMX_SC_R_DSP, + IMX_SC_C_OFS_IRQ, 0x51); + if (ret) { + dev_err(&pdev->dev, "Error system address offset of IRQ\n"); + return -EIO; + } - ret = imx_sc_misc_set_control(dsp_priv->dsp_ipcHandle, IMX_SC_R_DSP, - IMX_SC_C_OFS_IRQ, 0x51); - if (ret) { - dev_err(&pdev->dev, "Error system address offset of IRQ\n"); - return -EIO; + ret = imx_sc_misc_set_control(dsp_priv->dsp_ipcHandle, IMX_SC_R_DSP, + IMX_SC_C_OFS_AUDIO, 0x80); + if (ret) { + dev_err(&pdev->dev, "Error system address offset of AUDIO\n"); + return -EIO; + } + } else { + ret = imx_sc_misc_set_control(dsp_priv->dsp_ipcHandle, IMX_SC_R_DSP, + IMX_SC_C_OFS_SEL, 0); + if (ret) { + dev_err(&pdev->dev, "Error system address offset source select\n"); + return -EIO; + } } ret = dsp_mu_init(dsp_priv); From e8d93a7218db71fe798d797f3713b0f37b43bedc Mon Sep 17 00:00:00 2001 From: Shengjiu Wang Date: Thu, 27 Dec 2018 16:23:59 +0800 Subject: [PATCH 69/78] MLK-20693-1: ASoC: fsl_dsp: remove this workaround of skip sections Revert "MLK-18497-13: ASoC: fsl: dsp: Skip SDRAM section update if fw is already loaded" This reverts commit a0cffd9a9299362f2b3a4d24b78a8574b736fdfa. This is just to avoid reconfigure the edma isr handler in dsp framework, which should be handled by dsp framework. Signed-off-by: Shengjiu Wang --- sound/soc/fsl/fsl_dsp.c | 12 ++++-------- sound/soc/fsl/fsl_dsp_proxy.h | 2 +- 2 files changed, 5 insertions(+), 9 deletions(-) diff --git a/sound/soc/fsl/fsl_dsp.c b/sound/soc/fsl/fsl_dsp.c index 1d5b28fc05ac..fa5efb267f62 100644 --- a/sound/soc/fsl/fsl_dsp.c +++ b/sound/soc/fsl/fsl_dsp.c @@ -370,7 +370,6 @@ int fsl_dsp_open_func(struct fsl_dsp *dsp_priv, struct xf_client *client) atomic_set(&client->vm_use, 0); client->global = (void *)dsp_priv; - dsp_priv->proxy.is_loaded = 0; dsp_priv->proxy.is_active = 1; pm_runtime_get_sync(dev); @@ -687,12 +686,10 @@ static void dsp_load_firmware(const struct firmware *fw, void *context) (!strcmp(&strtab[shdr->sh_name], ".data")) || (!strcmp(&strtab[shdr->sh_name], ".bss")) ) { - if (!dsp_priv->proxy.is_loaded) { - memcpy_dsp((void *)(dsp_priv->sdram_vir_addr - + (sh_addr - dsp_priv->sdram_phys_addr)), - (const void *)image, - shdr->sh_size); - } + memcpy_dsp((void *)(dsp_priv->sdram_vir_addr + + (sh_addr - dsp_priv->sdram_phys_addr)), + (const void *)image, + shdr->sh_size); } else { /* sh_addr is from DSP view, we need to * fixup addr because we load the firmware from @@ -711,7 +708,6 @@ static void dsp_load_firmware(const struct firmware *fw, void *context) /* start the core */ imx_sc_pm_cpu_start(dsp_priv->dsp_ipcHandle, IMX_SC_R_DSP, true, dsp_priv->iram); - dsp_priv->proxy.is_loaded = 1; } /* Initialization of the MU code. */ diff --git a/sound/soc/fsl/fsl_dsp_proxy.h b/sound/soc/fsl/fsl_dsp_proxy.h index 9b5c78f8b993..bc9ccf37bc8f 100644 --- a/sound/soc/fsl/fsl_dsp_proxy.h +++ b/sound/soc/fsl/fsl_dsp_proxy.h @@ -299,8 +299,8 @@ struct xf_proxy { struct completion cmd_complete; int is_ready; - int is_loaded; int is_active; + /* ...internal lock */ spinlock_t lock; From 248f112adbc078c51209bb1838c081450c442908 Mon Sep 17 00:00:00 2001 From: Shengjiu Wang Date: Wed, 9 Jan 2019 10:12:16 +0800 Subject: [PATCH 70/78] MLK-20693-2: ASoC: fsl_dsp_cpu: remove the clock operation Remove the clock operation in cpu dai, all clock will be moved to platform driver. The reason is that the suspend and resume of dsp is handled in platform driver, if the clock is disabled before the suspend, the dsp framework can't access the registers of device in suspend. Signed-off-by: Shengjiu Wang --- sound/soc/fsl/fsl_dsp_cpu.c | 101 +----------------------------------- sound/soc/fsl/fsl_dsp_cpu.h | 7 --- 2 files changed, 1 insertion(+), 107 deletions(-) diff --git a/sound/soc/fsl/fsl_dsp_cpu.c b/sound/soc/fsl/fsl_dsp_cpu.c index 4903deb3efd7..e97d09ae0c45 100644 --- a/sound/soc/fsl/fsl_dsp_cpu.c +++ b/sound/soc/fsl/fsl_dsp_cpu.c @@ -15,14 +15,12 @@ static int dsp_audio_startup(struct snd_pcm_substream *substream, struct snd_soc_dai *cpu_dai) { - pm_runtime_get_sync(cpu_dai->dev); return 0; } static void dsp_audio_shutdown(struct snd_pcm_substream *substream, struct snd_soc_dai *cpu_dai) { - pm_runtime_put_sync(cpu_dai->dev); } static const struct snd_soc_dai_ops dsp_audio_dai_ops = { @@ -47,8 +45,7 @@ static const struct snd_soc_component_driver audio_dsp_component = { static int dsp_audio_probe(struct platform_device *pdev) { struct fsl_dsp_audio *dsp_audio; - int i, ret; - char tmp[16]; + int ret; dsp_audio = devm_kzalloc(&pdev->dev, sizeof(*dsp_audio), GFP_KERNEL); if (dsp_audio == NULL) @@ -59,42 +56,6 @@ static int dsp_audio_probe(struct platform_device *pdev) /* intialise sof device */ dev_set_drvdata(&pdev->dev, dsp_audio); - /* No error out for old DTB cases but only mark the clock NULL */ - dsp_audio->bus_clk = devm_clk_get(&pdev->dev, "bus"); - if (IS_ERR(dsp_audio->bus_clk)) { - dev_err(&pdev->dev, "failed to get bus clock: %ld\n", - PTR_ERR(dsp_audio->bus_clk)); - dsp_audio->bus_clk = NULL; - } - - dsp_audio->m_clk = devm_clk_get(&pdev->dev, "mclk"); - if (IS_ERR(dsp_audio->m_clk)) { - dev_err(&pdev->dev, "failed to get m clock: %ld\n", - PTR_ERR(dsp_audio->m_clk)); - dsp_audio->m_clk = NULL; - } - - dsp_audio->asrc_mem_clk = devm_clk_get(&pdev->dev, "mem"); - if (IS_ERR(dsp_audio->asrc_mem_clk)) { - dev_err(&pdev->dev, "failed to get mem clock\n"); - dsp_audio->asrc_mem_clk = NULL; - } - - dsp_audio->asrc_ipg_clk = devm_clk_get(&pdev->dev, "ipg"); - if (IS_ERR(dsp_audio->asrc_ipg_clk)) { - dev_err(&pdev->dev, "failed to get ipg clock\n"); - dsp_audio->asrc_ipg_clk = NULL; - } - - for (i = 0; i < ASRC_CLK_MAX_NUM; i++) { - sprintf(tmp, "asrck_%x", i); - dsp_audio->asrck_clk[i] = devm_clk_get(&pdev->dev, tmp); - if (IS_ERR(dsp_audio->asrck_clk[i])) { - dev_err(&pdev->dev, "failed to get %s clock\n", tmp); - dsp_audio->asrck_clk[i] = NULL; - } - } - pm_runtime_enable(&pdev->dev); /* now register audio DSP platform driver */ @@ -118,65 +79,6 @@ static int dsp_audio_remove(struct platform_device *pdev) return 0; } -#ifdef CONFIG_PM -static int dsp_runtime_resume(struct device *dev) -{ - struct fsl_dsp_audio *dsp_audio = dev_get_drvdata(dev); - int i, ret; - - ret = clk_prepare_enable(dsp_audio->bus_clk); - if (ret) { - dev_err(dev, "failed to enable bus clock: %d\n", ret); - return ret; - } - - ret = clk_prepare_enable(dsp_audio->m_clk); - if (ret) { - dev_err(dev, "failed to enable m clock: %d\n", ret); - return ret; - } - - ret = clk_prepare_enable(dsp_audio->asrc_mem_clk); - if (ret < 0) - dev_err(dev, "Failed to enable asrc_mem_clk ret = %d\n", ret); - - ret = clk_prepare_enable(dsp_audio->asrc_ipg_clk); - if (ret < 0) - dev_err(dev, "Failed to enable asrc_ipg_clk ret = %d\n", ret); - - for (i = 0; i < ASRC_CLK_MAX_NUM; i++) { - ret = clk_prepare_enable(dsp_audio->asrck_clk[i]); - if (ret < 0) - dev_err(dev, "failed to prepare arc clk %d\n", i); - } - - return ret; -} - -static int dsp_runtime_suspend(struct device *dev) -{ - int i; - struct fsl_dsp_audio *dsp_audio = dev_get_drvdata(dev); - - for (i = 0; i < ASRC_CLK_MAX_NUM; i++) - clk_disable_unprepare(dsp_audio->asrck_clk[i]); - - clk_disable_unprepare(dsp_audio->asrc_ipg_clk); - clk_disable_unprepare(dsp_audio->asrc_mem_clk); - - clk_disable_unprepare(dsp_audio->m_clk); - clk_disable_unprepare(dsp_audio->bus_clk); - - return 0; -} -#endif - -static const struct dev_pm_ops dsp_pm_ops = { - SET_RUNTIME_PM_OPS(dsp_runtime_suspend, - dsp_runtime_resume, - NULL) - SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, pm_runtime_force_resume) -}; static const struct of_device_id dsp_audio_ids[] = { { .compatible = "fsl,dsp-audio"}, @@ -188,7 +90,6 @@ static struct platform_driver dsp_audio_driver = { .driver = { .name = "dsp-audio", .of_match_table = dsp_audio_ids, - .pm = &dsp_pm_ops, }, .probe = dsp_audio_probe, .remove = dsp_audio_remove, diff --git a/sound/soc/fsl/fsl_dsp_cpu.h b/sound/soc/fsl/fsl_dsp_cpu.h index a6c1043a5908..dac10b4ab9d0 100644 --- a/sound/soc/fsl/fsl_dsp_cpu.h +++ b/sound/soc/fsl/fsl_dsp_cpu.h @@ -8,15 +8,8 @@ #ifndef __FSL_DSP_CPU_H #define __FSL_DSP_CPU_H -#define ASRC_CLK_MAX_NUM 4 - struct fsl_dsp_audio { struct platform_device *pdev; - struct clk *bus_clk; - struct clk *m_clk; - struct clk *asrc_mem_clk; - struct clk *asrc_ipg_clk; - struct clk *asrck_clk[ASRC_CLK_MAX_NUM]; }; #endif /*__FSL_DSP_CPU_H*/ From badc4f7be2f879be7abf28f093c18e987d42151f Mon Sep 17 00:00:00 2001 From: Shengjiu Wang Date: Wed, 9 Jan 2019 10:21:18 +0800 Subject: [PATCH 71/78] MLK-20693-3: ASoC: fsl_dsp: Add clocks for peripheral devices Add clocks for peripheral devices Signed-off-by: Shengjiu Wang --- sound/soc/fsl/fsl_dsp.c | 74 +++++++++++++++++++++++++++++++++++++++++ sound/soc/fsl/fsl_dsp.h | 6 ++++ 2 files changed, 80 insertions(+) diff --git a/sound/soc/fsl/fsl_dsp.c b/sound/soc/fsl/fsl_dsp.c index fa5efb267f62..aa49eb694d71 100644 --- a/sound/soc/fsl/fsl_dsp.c +++ b/sound/soc/fsl/fsl_dsp.c @@ -783,6 +783,7 @@ static int fsl_dsp_probe(struct platform_device *pdev) dma_addr_t buf_phys; int size, offset, i; int ret; + char tmp[16]; dsp_priv = devm_kzalloc(&pdev->dev, sizeof(*dsp_priv), GFP_KERNEL); if (!dsp_priv) @@ -953,6 +954,41 @@ static int fsl_dsp_probe(struct platform_device *pdev) return ret; } + dsp_priv->esai_ipg_clk = devm_clk_get(&pdev->dev, "esai_ipg"); + if (IS_ERR(dsp_priv->esai_ipg_clk)) { + dev_err(&pdev->dev, "failed to get esai ipg clock: %ld\n", + PTR_ERR(dsp_priv->esai_ipg_clk)); + dsp_priv->esai_ipg_clk = NULL; + } + + dsp_priv->esai_mclk = devm_clk_get(&pdev->dev, "esai_mclk"); + if (IS_ERR(dsp_priv->esai_mclk)) { + dev_err(&pdev->dev, "failed to get esai mclk: %ld\n", + PTR_ERR(dsp_priv->esai_mclk)); + dsp_priv->esai_mclk = NULL; + } + + dsp_priv->asrc_mem_clk = devm_clk_get(&pdev->dev, "asrc_mem"); + if (IS_ERR(dsp_priv->asrc_mem_clk)) { + dev_err(&pdev->dev, "failed to get mem clock\n"); + dsp_priv->asrc_mem_clk = NULL; + } + + dsp_priv->asrc_ipg_clk = devm_clk_get(&pdev->dev, "asrc_ipg"); + if (IS_ERR(dsp_priv->asrc_ipg_clk)) { + dev_err(&pdev->dev, "failed to get ipg clock\n"); + dsp_priv->asrc_ipg_clk = NULL; + } + + for (i = 0; i < 4; i++) { + sprintf(tmp, "asrck_%x", i); + dsp_priv->asrck_clk[i] = devm_clk_get(&pdev->dev, tmp); + if (IS_ERR(dsp_priv->asrck_clk[i])) { + dev_err(&pdev->dev, "failed to get %s clock\n", tmp); + dsp_priv->asrck_clk[i] = NULL; + } + } + return 0; } @@ -978,6 +1014,33 @@ static int fsl_dsp_runtime_resume(struct device *dev) struct fsl_dsp *dsp_priv = dev_get_drvdata(dev); struct xf_proxy *proxy = &dsp_priv->proxy; int ret; + int i; + + ret = clk_prepare_enable(dsp_priv->esai_ipg_clk); + if (ret) { + dev_err(dev, "failed to enable esai ipg clock: %d\n", ret); + return ret; + } + + ret = clk_prepare_enable(dsp_priv->esai_mclk); + if (ret) { + dev_err(dev, "failed to enable esai mclk: %d\n", ret); + return ret; + } + + ret = clk_prepare_enable(dsp_priv->asrc_mem_clk); + if (ret < 0) + dev_err(dev, "Failed to enable asrc_mem_clk ret = %d\n", ret); + + ret = clk_prepare_enable(dsp_priv->asrc_ipg_clk); + if (ret < 0) + dev_err(dev, "Failed to enable asrc_ipg_clk ret = %d\n", ret); + + for (i = 0; i < 4; i++) { + ret = clk_prepare_enable(dsp_priv->asrck_clk[i]); + if (ret < 0) + dev_err(dev, "failed to prepare arc clk %d\n", i); + } if (!dsp_priv->dsp_mu_init) { MU_Init(dsp_priv->mu_base_virtaddr); @@ -1012,9 +1075,20 @@ static int fsl_dsp_runtime_suspend(struct device *dev) { struct fsl_dsp *dsp_priv = dev_get_drvdata(dev); struct xf_proxy *proxy = &dsp_priv->proxy; + int i; dsp_priv->dsp_mu_init = 0; proxy->is_ready = 0; + + for (i = 0; i < 4; i++) + clk_disable_unprepare(dsp_priv->asrck_clk[i]); + + clk_disable_unprepare(dsp_priv->asrc_ipg_clk); + clk_disable_unprepare(dsp_priv->asrc_mem_clk); + + clk_disable_unprepare(dsp_priv->esai_mclk); + clk_disable_unprepare(dsp_priv->esai_ipg_clk); + return 0; } #endif /* CONFIG_PM */ diff --git a/sound/soc/fsl/fsl_dsp.h b/sound/soc/fsl/fsl_dsp.h index 99199e4d5c22..a66b083124ae 100644 --- a/sound/soc/fsl/fsl_dsp.h +++ b/sound/soc/fsl/fsl_dsp.h @@ -104,6 +104,12 @@ struct fsl_dsp { /* ...global clients pool (item[0] serves as list terminator) */ union xf_client_link xf_client_map[XF_CFG_MAX_IPC_CLIENTS]; + + struct clk *esai_ipg_clk; + struct clk *esai_mclk; + struct clk *asrc_mem_clk; + struct clk *asrc_ipg_clk; + struct clk *asrck_clk[4]; }; #define IRAM_OFFSET 0x10000 From 87850fce9591db72709ec8acee100a79b843d083 Mon Sep 17 00:00:00 2001 From: Shengjiu Wang Date: Wed, 30 Jan 2019 14:58:57 +0800 Subject: [PATCH 72/78] ASoC: fsl_dsp: support multi power domain support multi power domain Signed-off-by: Shengjiu Wang --- sound/soc/fsl/fsl_dsp.c | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/sound/soc/fsl/fsl_dsp.c b/sound/soc/fsl/fsl_dsp.c index aa49eb694d71..fa6e2478714a 100644 --- a/sound/soc/fsl/fsl_dsp.c +++ b/sound/soc/fsl/fsl_dsp.c @@ -52,6 +52,7 @@ #include #include #include +#include #include #include #include @@ -783,6 +784,7 @@ static int fsl_dsp_probe(struct platform_device *pdev) dma_addr_t buf_phys; int size, offset, i; int ret; + int num_domains = 0; char tmp[16]; dsp_priv = devm_kzalloc(&pdev->dev, sizeof(*dsp_priv), GFP_KERNEL); @@ -816,6 +818,24 @@ static int fsl_dsp_probe(struct platform_device *pdev) return ret; }; + num_domains = of_count_phandle_with_args(np, "power-domains", + "#power-domain-cells"); + for (i = 0; i < num_domains; i++) { + struct device *pd_dev; + struct device_link *link; + + pd_dev = dev_pm_domain_attach_by_id(&pdev->dev, i); + if (IS_ERR(pd_dev)) + return PTR_ERR(pd_dev); + + link = device_link_add(&pdev->dev, pd_dev, + DL_FLAG_STATELESS | + DL_FLAG_PM_RUNTIME | + DL_FLAG_RPM_ACTIVE); + if (IS_ERR(link)) + return PTR_ERR(link); + } + if (dsp_priv->dsp_board_type == DSP_IMX8QXP_TYPE) { ret = imx_sc_misc_set_control(dsp_priv->dsp_ipcHandle, IMX_SC_R_DSP, IMX_SC_C_OFS_SEL, 1); From 4de686476afe60e176cce63fbc274b5d723826dd Mon Sep 17 00:00:00 2001 From: Shengjiu Wang Date: Thu, 24 Jan 2019 15:20:52 +0800 Subject: [PATCH 73/78] MLK-20793: ASoC: fsl_dsp: remove error message With non fsl-imx8qxp-mek-dsp.dts, the clock is not assigned to dsp node, which cause error message when kernel boot up. Signed-off-by: Shengjiu Wang Reviewed-by: Daniel Baluta --- sound/soc/fsl/fsl_dsp.c | 22 +++++----------------- 1 file changed, 5 insertions(+), 17 deletions(-) diff --git a/sound/soc/fsl/fsl_dsp.c b/sound/soc/fsl/fsl_dsp.c index fa6e2478714a..a6247f915163 100644 --- a/sound/soc/fsl/fsl_dsp.c +++ b/sound/soc/fsl/fsl_dsp.c @@ -975,38 +975,26 @@ static int fsl_dsp_probe(struct platform_device *pdev) } dsp_priv->esai_ipg_clk = devm_clk_get(&pdev->dev, "esai_ipg"); - if (IS_ERR(dsp_priv->esai_ipg_clk)) { - dev_err(&pdev->dev, "failed to get esai ipg clock: %ld\n", - PTR_ERR(dsp_priv->esai_ipg_clk)); + if (IS_ERR(dsp_priv->esai_ipg_clk)) dsp_priv->esai_ipg_clk = NULL; - } dsp_priv->esai_mclk = devm_clk_get(&pdev->dev, "esai_mclk"); - if (IS_ERR(dsp_priv->esai_mclk)) { - dev_err(&pdev->dev, "failed to get esai mclk: %ld\n", - PTR_ERR(dsp_priv->esai_mclk)); + if (IS_ERR(dsp_priv->esai_mclk)) dsp_priv->esai_mclk = NULL; - } dsp_priv->asrc_mem_clk = devm_clk_get(&pdev->dev, "asrc_mem"); - if (IS_ERR(dsp_priv->asrc_mem_clk)) { - dev_err(&pdev->dev, "failed to get mem clock\n"); + if (IS_ERR(dsp_priv->asrc_mem_clk)) dsp_priv->asrc_mem_clk = NULL; - } dsp_priv->asrc_ipg_clk = devm_clk_get(&pdev->dev, "asrc_ipg"); - if (IS_ERR(dsp_priv->asrc_ipg_clk)) { - dev_err(&pdev->dev, "failed to get ipg clock\n"); + if (IS_ERR(dsp_priv->asrc_ipg_clk)) dsp_priv->asrc_ipg_clk = NULL; - } for (i = 0; i < 4; i++) { sprintf(tmp, "asrck_%x", i); dsp_priv->asrck_clk[i] = devm_clk_get(&pdev->dev, tmp); - if (IS_ERR(dsp_priv->asrck_clk[i])) { - dev_err(&pdev->dev, "failed to get %s clock\n", tmp); + if (IS_ERR(dsp_priv->asrck_clk[i])) dsp_priv->asrck_clk[i] = NULL; - } } return 0; From 3a3aba569a48b5bdb071c688ff98b769bbc1119f Mon Sep 17 00:00:00 2001 From: Dong Aisheng Date: Tue, 11 Jun 2019 12:27:19 +0800 Subject: [PATCH 74/78] MLK-21985-6 ASoC: imx-dsp: fix build for next 20190607 upgrade MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit API change due to: adb76b5b9c47 ("ASoC: soc-core: remove legacy style dai_link") ../sound/soc/fsl/imx-dsp.c: In function ‘imx_dsp_audio_probe’: ../sound/soc/fsl/imx-dsp.c:123:14: error: ‘struct snd_soc_dai_link’ has no member named ‘codec_dai_name’ data->dai[0].codec_dai_name = "snd-soc-dummy-dai"; ^ ../sound/soc/fsl/imx-dsp.c:124:14: error: ‘struct snd_soc_dai_link’ has no member named ‘codec_name’ data->dai[0].codec_name = "snd-soc-dummy"; ^ ../sound/soc/fsl/imx-dsp.c:125:14: error: ‘struct snd_soc_dai_link’ has no member named ‘cpu_dai_name’ data->dai[0].cpu_dai_name = dev_name(&cpu_pdev->dev); ^ ../sound/soc/fsl/imx-dsp.c:126:14: error: ‘struct snd_soc_dai_link’ has no member named ‘cpu_of_node’ data->dai[0].cpu_of_node = cpu_np; ^ ../sound/soc/fsl/imx-dsp.c:127:14: error: ‘struct snd_soc_dai_link’ has no member named ‘platform_of_node’ data->dai[0].platform_of_node = platform_np; ^ ../sound/soc/fsl/imx-dsp.c:140:14: error: ‘struct snd_soc_dai_link’ has no member named ‘codec_dai_name’ data->dai[1].codec_dai_name = "cs42888"; ^ ../sound/soc/fsl/imx-dsp.c:141:14: error: ‘struct snd_soc_dai_link’ has no member named ‘codec_of_node’ data->dai[1].codec_of_node = codec_np; ^ ../sound/soc/fsl/imx-dsp.c:142:14: error: ‘struct snd_soc_dai_link’ has no member named ‘cpu_dai_name’ data->dai[1].cpu_dai_name = "snd-soc-dummy-dai"; ^ ../sound/soc/fsl/imx-dsp.c:143:14: error: ‘struct snd_soc_dai_link’ has no member named ‘cpu_name’ data->dai[1].cpu_name = "snd-soc-dummy"; ^ ../sound/soc/fsl/imx-dsp.c:144:14: error: ‘struct snd_soc_dai_link’ has no member named ‘platform_name’ data->dai[1].platform_name = "snd-soc-dummy"; Signed-off-by: Dong Aisheng --- sound/soc/fsl/imx-dsp.c | 44 +++++++++++++++++++++++++++++++---------- 1 file changed, 34 insertions(+), 10 deletions(-) diff --git a/sound/soc/fsl/imx-dsp.c b/sound/soc/fsl/imx-dsp.c index a6f5a34f8605..f60d55073d8e 100644 --- a/sound/soc/fsl/imx-dsp.c +++ b/sound/soc/fsl/imx-dsp.c @@ -80,6 +80,7 @@ static const struct snd_soc_dapm_route imx_dsp_audio_map[] = { static int imx_dsp_audio_probe(struct platform_device *pdev) { struct device_node *cpu_np=NULL, *codec_np=NULL, *platform_np=NULL; + struct snd_soc_dai_link_component *comp; struct platform_device *cpu_pdev; struct imx_dsp_audio_data *data; int ret; @@ -90,6 +91,12 @@ static int imx_dsp_audio_probe(struct platform_device *pdev) goto fail; } + comp = devm_kzalloc(&pdev->dev, 6 * sizeof(*comp), GFP_KERNEL); + if (!comp) { + ret = -ENOMEM; + goto fail; + } + cpu_np = of_parse_phandle(pdev->dev.of_node, "cpu-dai", 0); if (!cpu_np) { dev_err(&pdev->dev, "cpu dai phandle missing or invalid\n"); @@ -118,13 +125,22 @@ static int imx_dsp_audio_probe(struct platform_device *pdev) goto fail; } + + data->dai[0].cpus = &comp[0]; + data->dai[0].codecs = &comp[1]; + data->dai[0].platforms = &comp[2]; + + data->dai[0].num_cpus = 1; + data->dai[0].num_codecs = 1; + data->dai[0].num_platforms = 1; + data->dai[0].name = "dsp hifi fe"; data->dai[0].stream_name = "dsp hifi fe"; - data->dai[0].codec_dai_name = "snd-soc-dummy-dai"; - data->dai[0].codec_name = "snd-soc-dummy"; - data->dai[0].cpu_dai_name = dev_name(&cpu_pdev->dev); - data->dai[0].cpu_of_node = cpu_np; - data->dai[0].platform_of_node = platform_np; + data->dai[0].codecs->dai_name = "snd-soc-dummy-dai"; + data->dai[0].codecs->name = "snd-soc-dummy"; + data->dai[0].cpus->dai_name = dev_name(&cpu_pdev->dev); + data->dai[0].cpus->of_node = cpu_np; + data->dai[0].platforms->of_node = platform_np; data->dai[0].playback_only = true; data->dai[0].capture_only = false; data->dai[0].dpcm_playback = 1; @@ -135,13 +151,21 @@ static int imx_dsp_audio_probe(struct platform_device *pdev) SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS; + data->dai[1].cpus = &comp[3]; + data->dai[1].codecs = &comp[4]; + data->dai[1].platforms = &comp[5]; + + data->dai[1].num_cpus = 1; + data->dai[1].num_codecs = 1; + data->dai[1].num_platforms = 1; + data->dai[1].name = "dsp hifi be"; data->dai[1].stream_name = "dsp hifi be"; - data->dai[1].codec_dai_name = "cs42888"; - data->dai[1].codec_of_node = codec_np; - data->dai[1].cpu_dai_name = "snd-soc-dummy-dai"; - data->dai[1].cpu_name = "snd-soc-dummy"; - data->dai[1].platform_name = "snd-soc-dummy"; + data->dai[1].codecs->dai_name = "cs42888"; + data->dai[1].codecs->of_node = codec_np; + data->dai[1].cpus->dai_name = "snd-soc-dummy-dai"; + data->dai[1].cpus->name = "snd-soc-dummy"; + data->dai[1].platforms->name = "snd-soc-dummy"; data->dai[1].playback_only = true; data->dai[1].capture_only = false; data->dai[1].dpcm_playback = 1; From 129c45f83791363d7cbef10a15d3d3fb020588f7 Mon Sep 17 00:00:00 2001 From: Dong Aisheng Date: Fri, 19 Jul 2019 16:02:24 +0800 Subject: [PATCH 75/78] ASoC: fsl: dsp: remove unused types.h types.h has been moved into rsrc.h Signed-off-by: Dong Aisheng --- sound/soc/fsl/fsl_dsp.c | 1 - 1 file changed, 1 deletion(-) diff --git a/sound/soc/fsl/fsl_dsp.c b/sound/soc/fsl/fsl_dsp.c index a6247f915163..c99e9bba07cf 100644 --- a/sound/soc/fsl/fsl_dsp.c +++ b/sound/soc/fsl/fsl_dsp.c @@ -60,7 +60,6 @@ #include #endif #include -#include #include #include From 940d9baeca0f6d7782f8dc59e0b6f0db85fa2325 Mon Sep 17 00:00:00 2001 From: Daniel Baluta Date: Tue, 20 Aug 2019 14:10:35 +0300 Subject: [PATCH 76/78] ASoC: fsl_dsp: Use new compatible string for FSL DSP In order to support in parallel FSL DSP and SOF Linux drivers we will need to use different compatible strings for DSP nodes. Use fsl,imx8qxp-dsp-v1 for FSL DSP driver. Note that our goal is to only support SOF Linux driver, so FSL DSP driver will be deprecated. Signed-off-by: Daniel Baluta --- sound/soc/fsl/fsl_dsp.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/sound/soc/fsl/fsl_dsp.c b/sound/soc/fsl/fsl_dsp.c index c99e9bba07cf..2c7976ffdb09 100644 --- a/sound/soc/fsl/fsl_dsp.c +++ b/sound/soc/fsl/fsl_dsp.c @@ -790,7 +790,7 @@ static int fsl_dsp_probe(struct platform_device *pdev) if (!dsp_priv) return -ENOMEM; - if (of_device_is_compatible(np, "fsl,imx8qxp-dsp")) + if (of_device_is_compatible(np, "fsl,imx8qxp-dsp-v1")) dsp_priv->dsp_board_type = DSP_IMX8QXP_TYPE; else dsp_priv->dsp_board_type = DSP_IMX8QM_TYPE; @@ -1150,8 +1150,8 @@ static const struct dev_pm_ops fsl_dsp_pm = { }; static const struct of_device_id fsl_dsp_ids[] = { - { .compatible = "fsl,imx8qxp-dsp", }, - { .compatible = "fsl,imx8qm-dsp", }, + { .compatible = "fsl,imx8qxp-dsp-v1", }, + { .compatible = "fsl,imx8qm-dsp-v1", }, {} }; MODULE_DEVICE_TABLE(of, fsl_dsp_ids); From 6bfa0c442b69c07b45e74f00704f74fd1ad99fa5 Mon Sep 17 00:00:00 2001 From: Daniel Baluta Date: Wed, 27 Mar 2019 10:25:22 +0200 Subject: [PATCH 77/78] MLK-21144 ASoC: fsl: Fix crash with multiple open/close Because we are re-initializing the proxy at close it might happen that work is still pending which causes the following crash: [ 94.699835] Unable to handle kernel NULL pointer dereference at virtual address 00000008 [ 94.707923] Mem abort info: [ 94.710722] Exception class = DABT (current EL), IL = 32 bits [ 94.716637] SET = 0, FnV = 0 [ 94.719686] EA = 0, S1PTW = 0 [ 94.722822] Data abort info: [ 94.725698] ISV = 0, ISS = 0x00000005 [ 94.729530] CM = 0, WnR = 0 [ 94.732504] user pgtable: 4k pages, 48-bit VAs, pgd = ffff8008d9ba3000 [ 94.739035] [0000000000000008] *pgd=0000000938419003, *pud=0000000000000000 [ 94.746015] Internal error: Oops: 96000005 [#1] PREEMPT SMP [ 94.751589] Modules linked in: [ 94.754652] CPU: 0 PID: 2068 Comm: kworker/0:2 Not tainted 4.14.98-dirty #75 [ 94.761700] Hardware name: Freescale i.MX8QM MEK (DT) [ 94.766768] task: ffff8008f23ae200 task.stack: ffff000014378000 [ 94.772705] PC is at process_one_work+0x34/0x414 [ 94.777325] LR is at process_one_work+0x1e0/0x414 In order to fix this, we make sure that no work is pending before starting the re-initialization. Signed-off-by: Daniel Baluta Reviewed-by: Shengjiu Wang (cherry picked from commit 2c00c24be5f8b63636e3f9005e15a3de42058438) --- sound/soc/fsl/fsl_dsp.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/sound/soc/fsl/fsl_dsp.c b/sound/soc/fsl/fsl_dsp.c index 2c7976ffdb09..b3bcf21730d2 100644 --- a/sound/soc/fsl/fsl_dsp.c +++ b/sound/soc/fsl/fsl_dsp.c @@ -430,8 +430,12 @@ int fsl_dsp_close_func(struct xf_client *client) /* If device is free, reinitialize the resource of * dsp driver and framework */ - if (atomic_long_read(&dsp_priv->refcnt) <= 0) + if (atomic_long_read(&dsp_priv->refcnt) <= 0) { + /* we are closing up, wait for proxy processing + * function to finish */ + cancel_work_sync(&dsp_priv->proxy.work); resource_release(dsp_priv); + } mutex_unlock(&dsp_priv->dsp_mutex); From 21f3df8506d95fbb6a0db7d58205b0180c200a52 Mon Sep 17 00:00:00 2001 From: Zhang Peng Date: Wed, 23 Oct 2019 10:02:00 +0800 Subject: [PATCH 78/78] MLK-22815-1: ASoC: fsl: dsp: Expand parameter msg size Modified parameter msg in dsp, make sure still can transfer right msg between DSP and user, modified parameter msg in kernel. Signed-off-by: Zhang Peng --- sound/soc/fsl/fsl_dsp_platform_compress.c | 12 +++++----- sound/soc/fsl/fsl_dsp_xaf_api.c | 4 ++-- sound/soc/fsl/fsl_dsp_xaf_api.h | 28 +++++++++++++++++++++-- 3 files changed, 34 insertions(+), 10 deletions(-) diff --git a/sound/soc/fsl/fsl_dsp_platform_compress.c b/sound/soc/fsl/fsl_dsp_platform_compress.c index 42c80ee8ccb8..43b07af3cbfe 100644 --- a/sound/soc/fsl/fsl_dsp_platform_compress.c +++ b/sound/soc/fsl/fsl_dsp_platform_compress.c @@ -193,32 +193,32 @@ static int dsp_platform_compr_set_params(struct snd_compr_stream *cstream, drv->client->consume_bytes = 0; s_param.id = XA_RENDERER_CONFIG_PARAM_SAMPLE_RATE; - s_param.value = params->codec.sample_rate; + s_param.mixData.value = params->codec.sample_rate; ret = xaf_comp_set_config(drv->client, &drv->component[1], 1, &s_param); if (ret) { dev_err(component->dev, "set param[cmd:0x%x|val:0x%x] error, err = %d\n", - s_param.id, s_param.value, ret); + s_param.id, s_param.mixData.value, ret); goto err_comp1_create; } s_param.id = XA_RENDERER_CONFIG_PARAM_CHANNELS; - s_param.value = params->codec.ch_out; + s_param.mixData.value = params->codec.ch_out; ret = xaf_comp_set_config(drv->client, &drv->component[1], 1, &s_param); if (ret) { dev_err(component->dev, "set param[cmd:0x%x|val:0x%x] error, err = %d\n", - s_param.id, s_param.value, ret); + s_param.id, s_param.mixData.value, ret); goto err_comp1_create; } s_param.id = XA_RENDERER_CONFIG_PARAM_PCM_WIDTH; - s_param.value = 16; + s_param.mixData.value = 16; ret = xaf_comp_set_config(drv->client, &drv->component[1], 1, &s_param); if (ret) { dev_err(component->dev, "set param[cmd:0x%x|val:0x%x] error, err = %d\n", - s_param.id, s_param.value, ret); + s_param.id, s_param.mixData.value, ret); goto err_comp1_create; } return 0; diff --git a/sound/soc/fsl/fsl_dsp_xaf_api.c b/sound/soc/fsl/fsl_dsp_xaf_api.c index 05d1a1685989..4312a6b29ef1 100644 --- a/sound/soc/fsl/fsl_dsp_xaf_api.c +++ b/sound/soc/fsl/fsl_dsp_xaf_api.c @@ -47,7 +47,7 @@ int xaf_comp_set_config(struct xf_client *client, struct xaf_comp *p_comp, for (i = 0; i < num_param; i++) { smsg[i].id = param[i].id; - smsg[i].value = param[i].value; + smsg[i].mixData.value = param[i].mixData.value; } /* ...set command parameters */ @@ -129,7 +129,7 @@ int xaf_comp_get_config(struct xf_client *client, struct xaf_comp *p_comp, } for (i = 0; i < num_param; i++) - param[i].value = smsg[i].value; + param[i].mixData.value = smsg[i].mixData.value; return 0; } diff --git a/sound/soc/fsl/fsl_dsp_xaf_api.h b/sound/soc/fsl/fsl_dsp_xaf_api.h index d6dc734000aa..2367b6c9c34d 100644 --- a/sound/soc/fsl/fsl_dsp_xaf_api.h +++ b/sound/soc/fsl/fsl_dsp_xaf_api.h @@ -106,12 +106,36 @@ struct __attribute__((__packed__)) xf_unroute_port_msg { /* ...check if non-zero value is a power-of-two */ #define xf_is_power_of_two(v) (((v) & ((v) - 1)) == 0) + +/******************************************************************************* + * bascial message + ******************************************************************************/ +typedef union DATA { + u32 value; + + struct { + u32 size; + u32 channel_table[10]; + } chan_map_tab; + + struct { + u32 samplerate; + u32 width; + u32 depth; + u32 channels; + u32 endian; + u32 interleave; + u32 layout[12]; + u32 chan_pos_set; // indicate if channel position is set outside or use codec default + } outputFormat; +} data_t; + /* ...component initialization parameter */ struct __attribute__((__packed__)) xf_set_param_msg { /* ...index of parameter passed to SET_CONFIG_PARAM call */ u32 id; /* ...value of parameter */ - u32 value; + data_t mixData; }; /* ...message body (command/response) */ @@ -119,7 +143,7 @@ struct __attribute__((__packed__)) xf_get_param_msg { /* ...array of parameters requested */ u32 id; /* ...array of parameters values */ - u32 value; + data_t mixData; }; /* ...renderer-specific configuration parameters */