From 51951b3e431d43279da15c33daebf35c6fd94f7b Mon Sep 17 00:00:00 2001 From: Daniel Baluta <daniel.baluta@nxp.com> Date: Thu, 4 Oct 2018 12:16:42 +0300 Subject: [PATCH] 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 <cosmin.samoila@nxp.com> Signed-off-by: Shengjiu Wang <shengjiu.wang@nxp.com Signed-off-by: Daniel Baluta <daniel.baluta@nxp.com> (cherry picked from commit 83b6f7340c4bb5fd9380cce5d856b18b9dc34457) TODO: checkpatch warnings Signed-off-by: Vipul Kumar <vipul_kumar@mentor.com> Signed-off-by: Srikanth Krishnakar <Srikanth_Krishnakar@mentor.com> Signed-off-by: Vipul Kumar <vipul_kumar@mentor.com> --- 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 e328c7fe2447a6..35c6bdfd57692e 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 144a4931ae6ed8..dfe7ebe33092b6 100644 --- a/sound/soc/fsl/Makefile +++ b/sound/soc/fsl/Makefile @@ -17,7 +17,7 @@ snd-soc-fsl-amix-objs := fsl_amix.o snd-soc-fsl-asrc-objs := fsl_asrc.o fsl_asrc_dma.o snd-soc-fsl-dma-workaround-objs := fsl_dma_workaround.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 00000000000000..503503a28922d4 --- /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 00000000000000..5087b46520d589 --- /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 */ -- GitLab