summaryrefslogtreecommitdiff
path: root/sound/soc/qcom/qdsp6/q6apm.c
diff options
context:
space:
mode:
Diffstat (limited to 'sound/soc/qcom/qdsp6/q6apm.c')
-rw-r--r--sound/soc/qcom/qdsp6/q6apm.c256
1 files changed, 130 insertions, 126 deletions
diff --git a/sound/soc/qcom/qdsp6/q6apm.c b/sound/soc/qcom/qdsp6/q6apm.c
index f424d7aa389a..94cc6376a367 100644
--- a/sound/soc/qcom/qdsp6/q6apm.c
+++ b/sound/soc/qcom/qdsp6/q6apm.c
@@ -27,6 +27,8 @@ struct apm_graph_mgmt_cmd {
#define APM_GRAPH_MGMT_PSIZE(p, n) ALIGN(struct_size(p, sub_graph_id_list, n), 8)
+static struct q6apm *g_apm;
+
int q6apm_send_cmd_sync(struct q6apm *apm, struct gpr_pkt *pkt, uint32_t rsp_opcode)
{
gpr_device_t *gdev = apm->gdev;
@@ -63,7 +65,7 @@ static struct audioreach_graph *q6apm_get_audioreach_graph(struct q6apm *apm, ui
graph->info = info;
graph->id = graph_id;
- graph->graph = audioreach_alloc_graph_pkt(apm, &info->sg_list, graph_id);
+ graph->graph = audioreach_alloc_graph_pkt(apm, info);
if (IS_ERR(graph->graph)) {
void *err = graph->graph;
@@ -75,6 +77,7 @@ static struct audioreach_graph *q6apm_get_audioreach_graph(struct q6apm *apm, ui
id = idr_alloc(&apm->graph_idr, graph, graph_id, graph_id + 1, GFP_KERNEL);
if (id < 0) {
dev_err(apm->dev, "Unable to allocate graph id (%d)\n", graph_id);
+ kfree(graph->graph);
kfree(graph);
mutex_unlock(&apm->lock);
return ERR_PTR(id);
@@ -96,12 +99,8 @@ static int audioreach_graph_mgmt_cmd(struct audioreach_graph *graph, uint32_t op
struct apm_graph_mgmt_cmd *mgmt_cmd;
struct audioreach_sub_graph *sg;
struct q6apm *apm = graph->apm;
- int i = 0, rc, payload_size;
- struct gpr_pkt *pkt;
-
- payload_size = APM_GRAPH_MGMT_PSIZE(mgmt_cmd, num_sub_graphs);
-
- pkt = audioreach_alloc_apm_cmd_pkt(payload_size, opcode, 0);
+ int i = 0, payload_size = APM_GRAPH_MGMT_PSIZE(mgmt_cmd, num_sub_graphs);
+ struct gpr_pkt *pkt __free(kfree) = audioreach_alloc_apm_cmd_pkt(payload_size, opcode, 0);
if (IS_ERR(pkt))
return PTR_ERR(pkt);
@@ -117,11 +116,7 @@ static int audioreach_graph_mgmt_cmd(struct audioreach_graph *graph, uint32_t op
list_for_each_entry(sg, &info->sg_list, node)
mgmt_cmd->sub_graph_id_list[i++] = sg->sub_graph_id;
- rc = q6apm_send_cmd_sync(apm, pkt, 0);
-
- kfree(pkt);
-
- return rc;
+ return q6apm_send_cmd_sync(apm, pkt, 0);
}
static void q6apm_put_audioreach_graph(struct kref *ref)
@@ -142,21 +137,28 @@ static void q6apm_put_audioreach_graph(struct kref *ref)
kfree(graph);
}
+
static int q6apm_get_apm_state(struct q6apm *apm)
{
- struct gpr_pkt *pkt;
-
- pkt = audioreach_alloc_apm_cmd_pkt(0, APM_CMD_GET_SPF_STATE, 0);
+ struct gpr_pkt *pkt __free(kfree) = audioreach_alloc_apm_cmd_pkt(0,
+ APM_CMD_GET_SPF_STATE, 0);
if (IS_ERR(pkt))
return PTR_ERR(pkt);
q6apm_send_cmd_sync(apm, pkt, APM_CMD_RSP_GET_SPF_STATE);
- kfree(pkt);
-
return apm->state;
}
+bool q6apm_is_adsp_ready(void)
+{
+ if (g_apm)
+ return q6apm_get_apm_state(g_apm);
+
+ return false;
+}
+EXPORT_SYMBOL_GPL(q6apm_is_adsp_ready);
+
static struct audioreach_module *__q6apm_find_module_by_mid(struct q6apm *apm,
struct audioreach_graph_info *info,
uint32_t mid)
@@ -177,87 +179,6 @@ static struct audioreach_module *__q6apm_find_module_by_mid(struct q6apm *apm,
return NULL;
}
-static struct audioreach_module *q6apm_graph_get_last_module(struct q6apm *apm, u32 sgid)
-{
- struct audioreach_container *container;
- struct audioreach_module *module;
- struct audioreach_sub_graph *sg;
-
- mutex_lock(&apm->lock);
- sg = idr_find(&apm->sub_graphs_idr, sgid);
- mutex_unlock(&apm->lock);
- if (!sg)
- return NULL;
-
- container = list_last_entry(&sg->container_list, struct audioreach_container, node);
- module = audioreach_get_container_last_module(container);
-
- return module;
-}
-
-static struct audioreach_module *q6apm_graph_get_first_module(struct q6apm *apm, u32 sgid)
-{
- struct audioreach_container *container;
- struct audioreach_module *module;
- struct audioreach_sub_graph *sg;
-
- mutex_lock(&apm->lock);
- sg = idr_find(&apm->sub_graphs_idr, sgid);
- mutex_unlock(&apm->lock);
- if (!sg)
- return NULL;
-
- container = list_first_entry(&sg->container_list, struct audioreach_container, node);
- module = audioreach_get_container_first_module(container);
-
- return module;
-}
-
-bool q6apm_is_sub_graphs_connected(struct q6apm *apm, u32 src_sgid, u32 dst_sgid)
-{
- struct audioreach_module *module;
- u32 iid;
-
- module = q6apm_graph_get_last_module(apm, src_sgid);
- if (!module)
- return false;
-
- iid = module->instance_id;
- module = q6apm_graph_get_first_module(apm, dst_sgid);
- if (!module)
- return false;
-
- if (module->src_mod_inst_id == iid)
- return true;
-
- return false;
-}
-
-int q6apm_connect_sub_graphs(struct q6apm *apm, u32 src_sgid, u32 dst_sgid, bool connect)
-{
- struct audioreach_module *module;
- u32 iid;
-
- if (connect) {
- module = q6apm_graph_get_last_module(apm, src_sgid);
- if (!module)
- return -ENODEV;
-
- iid = module->instance_id;
- } else {
- iid = 0;
- }
-
- module = q6apm_graph_get_first_module(apm, dst_sgid);
- if (!module)
- return -ENODEV;
-
- /* set src module in dst subgraph first module */
- module->src_mod_inst_id = iid;
-
- return 0;
-}
-
int q6apm_graph_media_format_shmem(struct q6apm_graph *graph,
struct audioreach_module_config *cfg)
{
@@ -298,7 +219,7 @@ int q6apm_map_memory_regions(struct q6apm_graph *graph, unsigned int dir, phys_a
return 0;
}
- buf = kzalloc(((sizeof(struct audio_buffer)) * periods), GFP_KERNEL);
+ buf = kcalloc(periods, sizeof(struct audio_buffer), GFP_KERNEL);
if (!buf) {
mutex_unlock(&graph->lock);
return -ENOMEM;
@@ -338,7 +259,7 @@ int q6apm_unmap_memory_regions(struct q6apm_graph *graph, unsigned int dir)
{
struct apm_cmd_shared_mem_unmap_regions *cmd;
struct audioreach_graph_data *data;
- struct gpr_pkt *pkt;
+ struct gpr_pkt *pkt __free(kfree) = NULL;
int rc;
if (dir == SNDRV_PCM_STREAM_PLAYBACK)
@@ -358,7 +279,6 @@ int q6apm_unmap_memory_regions(struct q6apm_graph *graph, unsigned int dir)
cmd->mem_map_handle = data->mem_map_handle;
rc = audioreach_graph_send_cmd_sync(graph, pkt, APM_CMD_SHARED_MEM_UNMAP_REGIONS);
- kfree(pkt);
audioreach_graph_free_buf(graph);
@@ -366,6 +286,74 @@ int q6apm_unmap_memory_regions(struct q6apm_graph *graph, unsigned int dir)
}
EXPORT_SYMBOL_GPL(q6apm_unmap_memory_regions);
+int q6apm_remove_initial_silence(struct device *dev, struct q6apm_graph *graph, uint32_t samples)
+{
+ struct audioreach_module *module;
+
+ module = q6apm_find_module_by_mid(graph, MODULE_ID_PLACEHOLDER_DECODER);
+ if (!module)
+ return -ENODEV;
+
+ return audioreach_send_u32_param(graph, module, PARAM_ID_REMOVE_INITIAL_SILENCE, samples);
+}
+EXPORT_SYMBOL_GPL(q6apm_remove_initial_silence);
+
+int q6apm_remove_trailing_silence(struct device *dev, struct q6apm_graph *graph, uint32_t samples)
+{
+ struct audioreach_module *module;
+
+ module = q6apm_find_module_by_mid(graph, MODULE_ID_PLACEHOLDER_DECODER);
+ if (!module)
+ return -ENODEV;
+
+ return audioreach_send_u32_param(graph, module, PARAM_ID_REMOVE_TRAILING_SILENCE, samples);
+}
+EXPORT_SYMBOL_GPL(q6apm_remove_trailing_silence);
+
+int q6apm_enable_compress_module(struct device *dev, struct q6apm_graph *graph, bool en)
+{
+ struct audioreach_module *module;
+
+ module = q6apm_find_module_by_mid(graph, MODULE_ID_PLACEHOLDER_DECODER);
+ if (!module)
+ return -ENODEV;
+
+ return audioreach_send_u32_param(graph, module, PARAM_ID_MODULE_ENABLE, en);
+}
+EXPORT_SYMBOL_GPL(q6apm_enable_compress_module);
+
+int q6apm_set_real_module_id(struct device *dev, struct q6apm_graph *graph,
+ uint32_t codec_id)
+{
+ struct audioreach_module *module;
+ uint32_t module_id;
+
+ module = q6apm_find_module_by_mid(graph, MODULE_ID_PLACEHOLDER_DECODER);
+ if (!module)
+ return -ENODEV;
+
+ switch (codec_id) {
+ case SND_AUDIOCODEC_MP3:
+ module_id = MODULE_ID_MP3_DECODE;
+ break;
+ case SND_AUDIOCODEC_AAC:
+ module_id = MODULE_ID_AAC_DEC;
+ break;
+ case SND_AUDIOCODEC_FLAC:
+ module_id = MODULE_ID_FLAC_DEC;
+ break;
+ case SND_AUDIOCODEC_OPUS_RAW:
+ module_id = MODULE_ID_OPUS_DEC;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return audioreach_send_u32_param(graph, module, PARAM_ID_REAL_MODULE_ID,
+ module_id);
+}
+EXPORT_SYMBOL_GPL(q6apm_set_real_module_id);
+
int q6apm_graph_media_format_pcm(struct q6apm_graph *graph, struct audioreach_module_config *cfg)
{
struct audioreach_graph_info *info = graph->info;
@@ -420,13 +408,11 @@ int q6apm_write_async(struct q6apm_graph *graph, uint32_t len, uint32_t msw_ts,
{
struct apm_data_cmd_wr_sh_mem_ep_data_buffer_v2 *write_buffer;
struct audio_buffer *ab;
- struct gpr_pkt *pkt;
- int rc, iid;
-
- iid = q6apm_graph_get_rx_shmem_module_iid(graph);
- pkt = audioreach_alloc_pkt(sizeof(*write_buffer), DATA_CMD_WR_SH_MEM_EP_DATA_BUFFER_V2,
- graph->rx_data.dsp_buf | (len << APM_WRITE_TOKEN_LEN_SHIFT),
- graph->port->id, iid);
+ int iid = q6apm_graph_get_rx_shmem_module_iid(graph);
+ struct gpr_pkt *pkt __free(kfree) = audioreach_alloc_pkt(sizeof(*write_buffer),
+ DATA_CMD_WR_SH_MEM_EP_DATA_BUFFER_V2,
+ graph->rx_data.dsp_buf | (len << APM_WRITE_TOKEN_LEN_SHIFT),
+ graph->port->id, iid);
if (IS_ERR(pkt))
return PTR_ERR(pkt);
@@ -450,11 +436,7 @@ int q6apm_write_async(struct q6apm_graph *graph, uint32_t len, uint32_t msw_ts,
mutex_unlock(&graph->lock);
- rc = gpr_send_port_pkt(graph->port, pkt);
-
- kfree(pkt);
-
- return rc;
+ return gpr_send_port_pkt(graph->port, pkt);
}
EXPORT_SYMBOL_GPL(q6apm_write_async);
@@ -463,12 +445,10 @@ int q6apm_read(struct q6apm_graph *graph)
struct data_cmd_rd_sh_mem_ep_data_buffer_v2 *read_buffer;
struct audioreach_graph_data *port;
struct audio_buffer *ab;
- struct gpr_pkt *pkt;
- int rc, iid;
-
- iid = q6apm_graph_get_tx_shmem_module_iid(graph);
- pkt = audioreach_alloc_pkt(sizeof(*read_buffer), DATA_CMD_RD_SH_MEM_EP_DATA_BUFFER_V2,
- graph->tx_data.dsp_buf, graph->port->id, iid);
+ int iid = q6apm_graph_get_tx_shmem_module_iid(graph);
+ struct gpr_pkt *pkt __free(kfree) = audioreach_alloc_pkt(sizeof(*read_buffer),
+ DATA_CMD_RD_SH_MEM_EP_DATA_BUFFER_V2,
+ graph->tx_data.dsp_buf, graph->port->id, iid);
if (IS_ERR(pkt))
return PTR_ERR(pkt);
@@ -490,13 +470,23 @@ int q6apm_read(struct q6apm_graph *graph)
mutex_unlock(&graph->lock);
- rc = gpr_send_port_pkt(graph->port, pkt);
- kfree(pkt);
-
- return rc;
+ return gpr_send_port_pkt(graph->port, pkt);
}
EXPORT_SYMBOL_GPL(q6apm_read);
+int q6apm_get_hw_pointer(struct q6apm_graph *graph, int dir)
+{
+ struct audioreach_graph_data *data;
+
+ if (dir == SNDRV_PCM_STREAM_PLAYBACK)
+ data = &graph->rx_data;
+ else
+ data = &graph->tx_data;
+
+ return (int)atomic_read(&data->hw_ptr);
+}
+EXPORT_SYMBOL_GPL(q6apm_get_hw_pointer);
+
static int graph_callback(struct gpr_resp_pkt *data, void *priv, int op)
{
struct data_cmd_rsp_rd_sh_mem_ep_data_buffer_done_v2 *rd_done;
@@ -514,6 +504,8 @@ static int graph_callback(struct gpr_resp_pkt *data, void *priv, int op)
switch (hdr->opcode) {
case DATA_CMD_RSP_WR_SH_MEM_EP_DATA_BUFFER_DONE_V2:
+ if (!graph->ar_graph)
+ break;
client_event = APM_CLIENT_EVENT_DATA_WRITE_DONE;
mutex_lock(&graph->lock);
token = hdr->token & APM_WRITE_TOKEN_MASK;
@@ -521,7 +513,8 @@ static int graph_callback(struct gpr_resp_pkt *data, void *priv, int op)
done = data->payload;
phys = graph->rx_data.buf[token].phys;
mutex_unlock(&graph->lock);
-
+ /* token numbering starts at 0 */
+ atomic_set(&graph->rx_data.hw_ptr, token + 1);
if (lower_32_bits(phys) == done->buf_addr_lsw &&
upper_32_bits(phys) == done->buf_addr_msw) {
graph->result.opcode = hdr->opcode;
@@ -547,11 +540,15 @@ static int graph_callback(struct gpr_resp_pkt *data, void *priv, int op)
wake_up(&graph->cmd_wait);
break;
case DATA_CMD_RSP_RD_SH_MEM_EP_DATA_BUFFER_V2:
+ if (!graph->ar_graph)
+ break;
client_event = APM_CLIENT_EVENT_DATA_READ_DONE;
mutex_lock(&graph->lock);
rd_done = data->payload;
phys = graph->tx_data.buf[hdr->token].phys;
mutex_unlock(&graph->lock);
+ /* token numbering starts at 0 */
+ atomic_set(&graph->tx_data.hw_ptr, hdr->token + 1);
if (upper_32_bits(phys) == rd_done->buf_addr_msw &&
lower_32_bits(phys) == rd_done->buf_addr_lsw) {
@@ -565,6 +562,9 @@ static int graph_callback(struct gpr_resp_pkt *data, void *priv, int op)
}
break;
case DATA_CMD_WR_SH_MEM_EP_EOS_RENDERED:
+ client_event = APM_CLIENT_EVENT_CMD_EOS_DONE;
+ if (graph->cb)
+ graph->cb(client_event, hdr->token, data->payload, graph->priv);
break;
case GPR_BASIC_RSP_RESULT:
switch (result->opcode) {
@@ -649,8 +649,9 @@ int q6apm_graph_close(struct q6apm_graph *graph)
{
struct audioreach_graph *ar_graph = graph->ar_graph;
- gpr_free_port(graph->port);
+ graph->ar_graph = NULL;
kref_put(&ar_graph->refcount, q6apm_put_audioreach_graph);
+ gpr_free_port(graph->port);
kfree(graph);
return 0;
@@ -730,6 +731,7 @@ static int apm_probe(gpr_device_t *gdev)
apm->gdev = gdev;
init_waitqueue_head(&apm->wait);
+ INIT_LIST_HEAD(&apm->widget_list);
idr_init(&apm->graph_idr);
idr_init(&apm->graph_info_idr);
idr_init(&apm->sub_graphs_idr);
@@ -737,11 +739,13 @@ static int apm_probe(gpr_device_t *gdev)
idr_init(&apm->modules_idr);
+ g_apm = apm;
+
q6apm_get_apm_state(apm);
ret = devm_snd_soc_register_component(dev, &q6apm_audio_component, NULL, 0);
if (ret < 0) {
- dev_err(dev, "failed to get register q6apm: %d\n", ret);
+ dev_err(dev, "failed to register q6apm: %d\n", ret);
return ret;
}