Skip to content
Snippets Groups Projects
Commit f609df9b authored by Weiguang Kong's avatar Weiguang Kong Committed by Leonard Crestez
Browse files

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: default avatarWeiguang Kong <weiguang.kong@nxp.com>
Reviewed-by: default avatarMihai Serban <mihai.serban@nxp.com>
Signed-off-by: default avatarVipul Kumar <vipul_kumar@mentor.com>
Signed-off-by: default avatarSrikanth Krishnakar <Srikanth_Krishnakar@mentor.com>
parent 973cd65a
No related branches found
No related tags found
No related merge requests found
......@@ -60,11 +60,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,
......@@ -75,7 +77,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;
}
......@@ -86,6 +89,19 @@ 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)
{
......@@ -102,7 +118,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;
}
......@@ -133,6 +150,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)
{
......@@ -140,8 +217,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))
......@@ -164,8 +244,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(
......@@ -537,13 +621,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);
......@@ -585,7 +670,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);
......@@ -618,36 +703,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;
......@@ -687,7 +764,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 ||
......@@ -709,6 +794,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;
......@@ -749,7 +835,7 @@ static long fsl_hifi4_decode_frame(struct fsl_hifi4 *hifi4_priv,
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;
......@@ -774,6 +860,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");
......@@ -793,6 +887,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;
......@@ -831,7 +926,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) {
......@@ -856,7 +950,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);
......@@ -883,7 +985,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;
......@@ -901,7 +1003,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);
......@@ -922,6 +1032,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;
......@@ -932,13 +1043,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);
......@@ -948,13 +1063,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;
......@@ -970,8 +1147,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) {
......@@ -986,15 +1167,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");
......@@ -1003,17 +1247,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;
......@@ -1037,15 +1296,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;
......@@ -1058,6 +1338,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;
}
......@@ -1070,26 +1362,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;
......@@ -1103,6 +1401,8 @@ static long fsl_hifi4_ioctl(struct file *file, unsigned int cmd,
break;
}
mutex_unlock(&hifi4_priv->hifi4_mutex);
return ret;
}
......@@ -1110,26 +1410,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;
......@@ -1143,17 +1449,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)
......@@ -1181,19 +1494,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;
}
......@@ -1298,8 +1618,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:
......@@ -1307,10 +1629,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 *)pext_msg->dtstamp;
hifi4_priv->ret_status = pext_msg->ret;
hifi4_priv->is_done = 1;
complete(&hifi4_priv->cmd_complete);
}
break;
......@@ -1326,9 +1648,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;
......@@ -1343,10 +1665,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;
hifi4_priv->ret_status = ext_msg->ret;
complete(&hifi4_priv->cmd_complete);
hifi4_priv->is_done = 1;
hifi4_priv->ret_status = ext_msg->ret;
complete(&hifi4_priv->cmd_complete);
}
break;
......@@ -1354,20 +1676,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:
......@@ -1391,7 +1723,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;
......@@ -1400,6 +1733,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);
......@@ -1592,7 +1927,7 @@ static int fsl_hifi4_probe(struct platform_device *pdev)
sc_err_t sciErr;
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);
......@@ -1730,6 +2065,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;
}
......
......@@ -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,
......@@ -61,8 +62,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 {
......@@ -134,6 +133,8 @@ enum icm_action_t {
ICM_CORE_EXIT,
ICM_EXT_MSG_ADDR,
ICM_SWITCH_CODEC,
};
enum aud_status_t {
......@@ -150,6 +151,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;
......@@ -166,6 +172,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
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment