From 6e55ad86b2dec8febca1e3966e1f1f05131c5980 Mon Sep 17 00:00:00 2001 From: Vikram Panduranga Date: Wed, 14 Mar 2018 13:56:18 -0700 Subject: [PATCH] dsp: preload voice and copp topologies Set topology info to q6core service in ADSP so that the modules in a topology can be loaded before the usecase starts, thus reducing usecase setup latency. The same topology is unloaded before vocproc or copp is destroyed or replaced. Change-Id: I5f8872130fb09f049e080c61edb8bb0b05e5e2de Signed-off-by: Vikram Panduranga --- asoc/msm-pcm-routing-v2.c | 65 ++++++++++++++++++++++++++++++++++++ dsp/q6core.c | 69 +++++++++++++++++++++++++++++++++++++++ dsp/q6voice.c | 42 ++++++++++++++++++++++++ include/dsp/q6core.h | 18 +++++++++- 4 files changed, 193 insertions(+), 1 deletion(-) diff --git a/asoc/msm-pcm-routing-v2.c b/asoc/msm-pcm-routing-v2.c index 5e825506e74c..bd023929b17e 100644 --- a/asoc/msm-pcm-routing-v2.c +++ b/asoc/msm-pcm-routing-v2.c @@ -147,6 +147,9 @@ static struct msm_pcm_route_bdai_name be_dai_name_table[MSM_BACKEND_DAI_MAX]; static int msm_routing_send_device_pp_params(int port_id, int copp_idx, int fe_id); +static void msm_routing_load_topology(size_t data_size, void *data); +static void msm_routing_unload_topology(uint32_t topology_id); + static int msm_routing_get_bit_width(unsigned int format) { int bit_width; @@ -1547,6 +1550,7 @@ void msm_pcm_routing_dereg_phy_stream(int fedai_id, int stream_type) } topology = adm_get_topology_for_port_copp_idx( msm_bedais[i].port_id, idx); + msm_routing_unload_topology(topology); adm_close(msm_bedais[i].port_id, fdai->perf_mode, idx); pr_debug("%s:copp:%ld,idx bit fe:%d,type:%d,be:%d\n", __func__, copp, fedai_id, session_type, i); @@ -1745,6 +1749,7 @@ static void msm_pcm_routing_process_audio(u16 reg, u16 val, int set) port_id = msm_bedais[reg].port_id; topology = adm_get_topology_for_port_copp_idx(port_id, idx); + msm_routing_unload_topology(topology); adm_close(msm_bedais[reg].port_id, fdai->perf_mode, idx); pr_debug("%s: copp: %ld, reset idx bit fe:%d, type: %d, be:%d topology=0x%x\n", @@ -16308,6 +16313,7 @@ static int msm_pcm_routing_close(struct snd_pcm_substream *substream) port_id = bedai->port_id; topology = adm_get_topology_for_port_copp_idx(port_id, idx); + msm_routing_unload_topology(topology); adm_close(bedai->port_id, fdai->perf_mode, idx); pr_debug("%s: copp:%ld,idx bit fe:%d, type:%d,be:%d topology=0x%x\n", __func__, copp, i, session_type, be_id, @@ -16600,6 +16606,60 @@ static int msm_routing_send_device_pp_params(int port_id, int copp_idx, return 0; } +static uint32_t msm_routing_get_topology(size_t data_size, void *data) +{ + uint32_t topology = NULL_COPP_TOPOLOGY; + void *cal_info = NULL; + uint32_t size = 0; + + /* Retrieve cal_info size from cal data*/ + size = data_size - sizeof(struct audio_cal_type_basic); + cal_info = kzalloc(size, GFP_KERNEL); + + if (!cal_info) + goto done; + + memcpy(cal_info, + ((uint8_t *)data + sizeof(struct audio_cal_type_basic)), size); + + topology = ((struct audio_cal_info_adm_top *)cal_info)->topology; + kfree(cal_info); + cal_info = NULL; + +done: + pr_debug("%s: Using topology %d\n", __func__, topology); + + return topology; +} + +static void msm_routing_load_topology(size_t data_size, void *data) +{ + uint32_t topology_id; + int ret; + + topology_id = msm_routing_get_topology(data_size, data); + if (topology_id != NULL_COPP_TOPOLOGY) + ret = q6core_load_unload_topo_modules(topology_id, + CORE_LOAD_TOPOLOGY); + if (ret < 0) + pr_debug("%s %d load topology failed\n", + __func__, topology_id); + +} + +static void msm_routing_unload_topology(uint32_t topology_id) +{ + int ret; + + if (topology_id != NULL_COPP_TOPOLOGY) + ret = q6core_load_unload_topo_modules(topology_id, + CORE_UNLOAD_TOPOLOGY); + if (ret < 0) + pr_debug("%s %d unload topology failed\n", + __func__, topology_id); + +} + static int msm_routing_put_device_pp_params_mixer(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { @@ -17065,6 +17125,11 @@ static int msm_routing_set_cal(int32_t cal_type, ret = -EINVAL; goto done; } + /* Pre-load if it is ADM topology */ + if ((cal_index == ADM_TOPOLOGY_CAL_TYPE_IDX) || + (cal_index == ADM_LSM_TOPOLOGY_CAL_TYPE_IDX)) { + msm_routing_load_topology(data_size, data); + } done: return ret; } diff --git a/dsp/q6core.c b/dsp/q6core.c index c5b64096a234..cc163ff67fa9 100644 --- a/dsp/q6core.c +++ b/dsp/q6core.c @@ -184,6 +184,17 @@ static int32_t aprv2_core_fn_q(struct apr_client_data *data, void *priv) q6core_lcl.avcs_fwk_ver_resp_received = 1; wake_up(&q6core_lcl.avcs_fwk_ver_req_wait); break; + case AVCS_CMD_LOAD_TOPO_MODULES: + case AVCS_CMD_UNLOAD_TOPO_MODULES: + pr_debug("%s: Cmd = %s status[%s]\n", + __func__, + (payload1[0] == AVCS_CMD_LOAD_TOPO_MODULES) ? + "AVCS_CMD_LOAD_TOPO_MODULES" : + "AVCS_CMD_UNLOAD_TOPO_MODULES", + adsp_err_get_err_str(payload1[1])); + q6core_lcl.bus_bw_resp_received = 1; + wake_up(&q6core_lcl.bus_bw_req_wait); + break; default: pr_err("%s: Invalid cmd rsp[0x%x][0x%x] opcode %d\n", __func__, @@ -655,6 +666,64 @@ uint32_t core_set_dolby_manufacturer_id(int manufacturer_id) } EXPORT_SYMBOL(core_set_dolby_manufacturer_id); +int32_t q6core_load_unload_topo_modules(uint32_t topo_id, + bool preload_type) +{ + struct avcs_cmd_load_unload_topo_modules load_unload_topo_modules; + int ret = 0; + + mutex_lock(&(q6core_lcl.cmd_lock)); + ocm_core_open(); + if (q6core_lcl.core_handle_q == NULL) { + pr_err("%s: apr registration for CORE failed\n", __func__); + ret = -ENODEV; + goto done; + } + + memset(&load_unload_topo_modules, 0, sizeof(load_unload_topo_modules)); + load_unload_topo_modules.hdr.hdr_field = + APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD, + APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER); + load_unload_topo_modules.hdr.pkt_size = + sizeof(struct avcs_cmd_load_unload_topo_modules); + load_unload_topo_modules.hdr.src_port = 0; + load_unload_topo_modules.hdr.dest_port = 0; + load_unload_topo_modules.hdr.token = 0; + + if (preload_type == CORE_LOAD_TOPOLOGY) + load_unload_topo_modules.hdr.opcode = + AVCS_CMD_LOAD_TOPO_MODULES; + else + load_unload_topo_modules.hdr.opcode = + AVCS_CMD_UNLOAD_TOPO_MODULES; + + load_unload_topo_modules.topology_id = topo_id; + q6core_lcl.bus_bw_resp_received = 0; + ret = apr_send_pkt(q6core_lcl.core_handle_q, + (uint32_t *) &load_unload_topo_modules); + if (ret < 0) { + pr_err("%s: Load/unload topo modules failed for topology = %d ret = %d\n", + __func__, topo_id, ret); + ret = -EINVAL; + goto done; + } + + ret = wait_event_timeout(q6core_lcl.bus_bw_req_wait, + (q6core_lcl.bus_bw_resp_received == 1), + msecs_to_jiffies(TIMEOUT_MS)); + if (!ret) { + pr_err("%s: wait_event timeout for load/unload topo modules\n", + __func__); + ret = -ETIME; + goto done; + } +done: + mutex_unlock(&(q6core_lcl.cmd_lock)); + + return ret; +} +EXPORT_SYMBOL(q6core_load_unload_topo_modules); + /** * q6core_is_adsp_ready - check adsp ready status * diff --git a/dsp/q6voice.c b/dsp/q6voice.c index 788805e0bdf5..af933a804e0b 100644 --- a/dsp/q6voice.c +++ b/dsp/q6voice.c @@ -96,6 +96,8 @@ static int voice_send_cvp_channel_info_v2(struct voice_data *v, uint32_t param_type); static int voice_get_avcs_version_per_service(uint32_t service_id); +static void voice_load_topo_modules(int cal_index); +static void voice_unload_topo_modules(void); static int voice_cvs_stop_playback(struct voice_data *v); static int voice_cvs_start_playback(struct voice_data *v); @@ -2698,6 +2700,35 @@ done: } +static void voice_load_topo_modules(int cal_index) +{ + uint32_t topology_id; + int ret; + + topology_id = voice_get_topology(cal_index); + ret = q6core_load_unload_topo_modules(topology_id, CORE_LOAD_TOPOLOGY); + if (ret < 0) + pr_debug("%s ret:%d load topo modules %d failed\n", + __func__, ret, topology_id); + +} + +static void voice_unload_topo_modules(void) +{ + uint32_t topology_id; + int i, ret; + + for (i = CVP_VOC_RX_TOPOLOGY_CAL; i <= CVP_VOC_TX_TOPOLOGY_CAL; i++) { + topology_id = voice_get_topology(i); + ret = q6core_load_unload_topo_modules(topology_id, + CORE_UNLOAD_TOPOLOGY); + if (ret < 0) { + pr_debug("%s ret:%d unload topo modules %d failed\n", + __func__, ret, topology_id); + } + } +} + static int voice_send_cvp_create_cmd(struct voice_data *v) { struct cvp_create_full_ctl_session_cmd cvp_session_cmd; @@ -5000,6 +5031,9 @@ static int voice_destroy_vocproc(struct voice_data *v) voice_send_cvp_deregister_dev_cfg_cmd(v); voice_send_cvs_deregister_cal_cmd(v); + /* Unload topology modules */ + voice_unload_topo_modules(); + /* destrop cvp session */ cvp_destroy_session_cmd.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD, APR_HDR_LEN(APR_HDR_SIZE), @@ -6728,6 +6762,9 @@ int voc_disable_device(uint32_t session_id) voice_send_cvp_deregister_cal_cmd(v); voice_send_cvp_deregister_dev_cfg_cmd(v); + /* Unload topology modules */ + voice_unload_topo_modules(); + v->voc_state = VOC_CHANGE; } else { pr_debug("%s: called in voc state=%d, No_OP\n", @@ -8721,6 +8758,11 @@ static int voice_set_cal(int32_t cal_type, ret = -EINVAL; goto done; } + /* Pre-load if it is voice Rx or Tx topology */ + if ((cal_index == CVP_VOC_RX_TOPOLOGY_CAL) || + (cal_index == CVP_VOC_TX_TOPOLOGY_CAL)) { + voice_load_topo_modules(cal_index); + } done: return ret; } diff --git a/include/dsp/q6core.h b/include/dsp/q6core.h index f6240a33e6fd..e7f135a0bcdf 100644 --- a/include/dsp/q6core.h +++ b/include/dsp/q6core.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2012-2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2012-2018, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -158,8 +158,24 @@ struct avcs_cmd_deregister_topologies { #define AVCS_MODE_DEREGISTER_ALL_CUSTOM_TOPOLOGIES 2 +#define AVCS_CMD_LOAD_TOPO_MODULES 0x0001296C + +#define AVCS_CMD_UNLOAD_TOPO_MODULES 0x0001296D + +#define CORE_LOAD_TOPOLOGY 0 + +#define CORE_UNLOAD_TOPOLOGY 1 + +struct avcs_cmd_load_unload_topo_modules { + struct apr_hdr hdr; + uint32_t topology_id; +} __packed; + int32_t core_set_license(uint32_t key, uint32_t module_id); int32_t core_get_license_status(uint32_t module_id); +int32_t q6core_load_unload_topo_modules(uint32_t topology_id, + bool preload_type); + #endif /* __Q6CORE_H__ */