summaryrefslogtreecommitdiffstats
path: root/sound/soc/qcom/qdsp6
diff options
context:
space:
mode:
Diffstat (limited to 'sound/soc/qcom/qdsp6')
-rw-r--r--sound/soc/qcom/qdsp6/audioreach.c310
-rw-r--r--sound/soc/qcom/qdsp6/audioreach.h47
-rw-r--r--sound/soc/qcom/qdsp6/q6apm.c84
-rw-r--r--sound/soc/qcom/qdsp6/q6apm.h6
-rw-r--r--sound/soc/qcom/qdsp6/q6prm.c2
-rw-r--r--sound/soc/qcom/qdsp6/topology.c243
6 files changed, 463 insertions, 229 deletions
diff --git a/sound/soc/qcom/qdsp6/audioreach.c b/sound/soc/qcom/qdsp6/audioreach.c
index 01dac32c50fd..1e0c918eb576 100644
--- a/sound/soc/qcom/qdsp6/audioreach.c
+++ b/sound/soc/qcom/qdsp6/audioreach.c
@@ -159,6 +159,8 @@ struct apm_module_hw_ep_mf_cfg {
#define APM_HW_EP_CFG_PSIZE ALIGN(sizeof(struct apm_module_hw_ep_mf_cfg), 8)
+#define APM_MFC_CFG_PSIZE(p, n) ALIGN(struct_size(p, channel_mapping, n), 4)
+
struct apm_module_frame_size_factor_cfg {
struct apm_module_param_data param_data;
uint32_t frame_size_factor;
@@ -311,15 +313,6 @@ static void apm_populate_sub_graph_config(struct apm_sub_graph_data *cfg,
cfg->sid.scenario_id = sg->scenario_id;
}
-static void apm_populate_connection_obj(struct apm_module_conn_obj *obj,
- struct audioreach_module *module)
-{
- obj->src_mod_inst_id = module->src_mod_inst_id;
- obj->src_mod_op_port_id = module->src_mod_op_port_id;
- obj->dst_mod_inst_id = module->instance_id;
- obj->dst_mod_ip_port_id = module->in_port;
-}
-
static void apm_populate_module_prop_obj(struct apm_mod_prop_obj *obj,
struct audioreach_module *module)
{
@@ -332,63 +325,6 @@ static void apm_populate_module_prop_obj(struct apm_mod_prop_obj *obj,
obj->prop_id_port.max_op_port = module->max_op_port;
}
-struct audioreach_module *audioreach_get_container_last_module(
- struct audioreach_container *container)
-{
- struct audioreach_module *module;
-
- list_for_each_entry(module, &container->modules_list, node) {
- if (module->dst_mod_inst_id == 0)
- return module;
- }
-
- return NULL;
-}
-EXPORT_SYMBOL_GPL(audioreach_get_container_last_module);
-
-static bool is_module_in_container(struct audioreach_container *container, int module_iid)
-{
- struct audioreach_module *module;
-
- list_for_each_entry(module, &container->modules_list, node) {
- if (module->instance_id == module_iid)
- return true;
- }
-
- return false;
-}
-
-struct audioreach_module *audioreach_get_container_first_module(
- struct audioreach_container *container)
-{
- struct audioreach_module *module;
-
- /* get the first module from both connected or un-connected containers */
- list_for_each_entry(module, &container->modules_list, node) {
- if (module->src_mod_inst_id == 0 ||
- !is_module_in_container(container, module->src_mod_inst_id))
- return module;
- }
- return NULL;
-}
-EXPORT_SYMBOL_GPL(audioreach_get_container_first_module);
-
-struct audioreach_module *audioreach_get_container_next_module(
- struct audioreach_container *container,
- struct audioreach_module *module)
-{
- int nmodule_iid = module->dst_mod_inst_id;
- struct audioreach_module *nmodule;
-
- list_for_each_entry(nmodule, &container->modules_list, node) {
- if (nmodule->instance_id == nmodule_iid)
- return nmodule;
- }
-
- return NULL;
-}
-EXPORT_SYMBOL_GPL(audioreach_get_container_next_module);
-
static void apm_populate_module_list_obj(struct apm_mod_list_obj *obj,
struct audioreach_container *container,
int sub_graph_id)
@@ -400,14 +336,15 @@ static void apm_populate_module_list_obj(struct apm_mod_list_obj *obj,
obj->container_id = container->container_id;
obj->num_modules = container->num_modules;
i = 0;
- list_for_each_container_module(module, container) {
+ list_for_each_entry(module, &container->modules_list, node) {
obj->mod_cfg[i].module_id = module->module_id;
obj->mod_cfg[i].instance_id = module->instance_id;
i++;
}
}
-static void audioreach_populate_graph(struct apm_graph_open_params *open,
+static void audioreach_populate_graph(struct q6apm *apm, struct audioreach_graph_info *info,
+ struct apm_graph_open_params *open,
struct list_head *sg_list,
int num_sub_graphs)
{
@@ -428,6 +365,16 @@ static void audioreach_populate_graph(struct apm_graph_open_params *open,
mlobj = &ml_data->mod_list_obj[0];
+
+ if (info->dst_mod_inst_id && info->src_mod_inst_id) {
+ conn_obj = &mc_data->conn_obj[nconn];
+ conn_obj->src_mod_inst_id = info->src_mod_inst_id;
+ conn_obj->src_mod_op_port_id = info->src_mod_op_port_id;
+ conn_obj->dst_mod_inst_id = info->dst_mod_inst_id;
+ conn_obj->dst_mod_ip_port_id = info->dst_mod_ip_port_id;
+ nconn++;
+ }
+
list_for_each_entry(sg, sg_list, node) {
struct apm_sub_graph_data *sg_cfg = &sg_data->sg_cfg[i++];
@@ -439,30 +386,38 @@ static void audioreach_populate_graph(struct apm_graph_open_params *open,
apm_populate_container_config(cobj, container);
apm_populate_module_list_obj(mlobj, container, sg->sub_graph_id);
- list_for_each_container_module(module, container) {
- uint32_t src_mod_inst_id;
-
- src_mod_inst_id = module->src_mod_inst_id;
+ list_for_each_entry(module, &container->modules_list, node) {
+ int pn;
- module_prop_obj = &mp_data->mod_prop_obj[nmodule];
+ module_prop_obj = &mp_data->mod_prop_obj[nmodule++];
apm_populate_module_prop_obj(module_prop_obj, module);
- if (src_mod_inst_id) {
- conn_obj = &mc_data->conn_obj[nconn];
- apm_populate_connection_obj(conn_obj, module);
- nconn++;
+ if (!module->max_op_port)
+ continue;
+
+ for (pn = 0; pn < module->max_op_port; pn++) {
+ if (module->dst_mod_inst_id[pn]) {
+ conn_obj = &mc_data->conn_obj[nconn];
+ conn_obj->src_mod_inst_id = module->instance_id;
+ conn_obj->src_mod_op_port_id =
+ module->src_mod_op_port_id[pn];
+ conn_obj->dst_mod_inst_id =
+ module->dst_mod_inst_id[pn];
+ conn_obj->dst_mod_ip_port_id =
+ module->dst_mod_ip_port_id[pn];
+ nconn++;
+ }
}
-
- nmodule++;
}
- mlobj = (void *) mlobj + APM_MOD_LIST_OBJ_PSIZE(mlobj, container->num_modules);
+ mlobj = (void *) mlobj + APM_MOD_LIST_OBJ_PSIZE(mlobj,
+ container->num_modules);
ncontainer++;
}
}
}
-void *audioreach_alloc_graph_pkt(struct q6apm *apm, struct list_head *sg_list, int graph_id)
+void *audioreach_alloc_graph_pkt(struct q6apm *apm, struct audioreach_graph_info *info)
{
int payload_size, sg_sz, cont_sz, ml_sz, mp_sz, mc_sz;
struct apm_module_param_data *param_data;
@@ -475,7 +430,7 @@ void *audioreach_alloc_graph_pkt(struct q6apm *apm, struct list_head *sg_list, i
struct audioreach_module *module;
struct audioreach_sub_graph *sgs;
struct apm_mod_list_obj *mlobj;
- int num_modules_per_list;
+ struct list_head *sg_list;
int num_connections = 0;
int num_containers = 0;
int num_sub_graphs = 0;
@@ -484,24 +439,33 @@ void *audioreach_alloc_graph_pkt(struct q6apm *apm, struct list_head *sg_list, i
struct gpr_pkt *pkt;
void *p;
+ sg_list = &info->sg_list;
+ ml_sz = 0;
+
+ /* add FE-BE connections */
+ if (info->dst_mod_inst_id && info->src_mod_inst_id)
+ num_connections++;
+
list_for_each_entry(sgs, sg_list, node) {
num_sub_graphs++;
list_for_each_entry(container, &sgs->container_list, node) {
num_containers++;
num_modules += container->num_modules;
- list_for_each_container_module(module, container) {
- if (module->src_mod_inst_id)
- num_connections++;
+ ml_sz = ml_sz + sizeof(struct apm_module_list_params) +
+ APM_MOD_LIST_OBJ_PSIZE(mlobj, container->num_modules);
+
+ list_for_each_entry(module, &container->modules_list, node) {
+ num_connections += module->num_connections;
}
}
}
num_modules_list = num_containers;
- num_modules_per_list = num_modules/num_containers;
sg_sz = APM_SUB_GRAPH_PSIZE(sg_params, num_sub_graphs);
cont_sz = APM_CONTAINER_PSIZE(cont_params, num_containers);
- ml_sz = ALIGN(sizeof(struct apm_module_list_params) +
- num_modules_list * APM_MOD_LIST_OBJ_PSIZE(mlobj, num_modules_per_list), 8);
+
+ ml_sz = ALIGN(ml_sz, 8);
+
mp_sz = APM_MOD_PROP_PSIZE(mprop, num_modules);
mc_sz = APM_MOD_CONN_PSIZE(mcon, num_connections);
@@ -536,7 +500,7 @@ void *audioreach_alloc_graph_pkt(struct q6apm *apm, struct list_head *sg_list, i
param_data->module_instance_id = APM_MODULE_INSTANCE_ID;
param_data->param_id = APM_PARAM_ID_MODULE_LIST;
param_data->param_size = ml_sz - APM_MODULE_PARAM_DATA_SIZE;
- params.mod_list_data->num_modules_list = num_sub_graphs;
+ params.mod_list_data->num_modules_list = num_modules_list;
p += ml_sz;
/* Module Properties */
@@ -557,7 +521,7 @@ void *audioreach_alloc_graph_pkt(struct q6apm *apm, struct list_head *sg_list, i
params.mod_conn_list_data->num_connections = num_connections;
p += mc_sz;
- audioreach_populate_graph(&params, sg_list, num_sub_graphs);
+ audioreach_populate_graph(apm, info, &params, sg_list, num_sub_graphs);
return pkt;
}
@@ -696,6 +660,160 @@ static int audioreach_codec_dma_set_media_format(struct q6apm_graph *graph,
return rc;
}
+static int audioreach_sal_limiter_enable(struct q6apm_graph *graph,
+ struct audioreach_module *module, bool enable)
+{
+ struct apm_module_param_data *param_data;
+ struct param_id_sal_limiter_enable *limiter_enable;
+ int payload_size;
+ struct gpr_pkt *pkt;
+ int rc;
+ void *p;
+
+ payload_size = sizeof(*limiter_enable) + APM_MODULE_PARAM_DATA_SIZE;
+
+ pkt = audioreach_alloc_apm_cmd_pkt(payload_size, APM_CMD_SET_CFG, 0);
+ if (IS_ERR(pkt))
+ return PTR_ERR(pkt);
+
+ p = (void *)pkt + GPR_HDR_SIZE + APM_CMD_HDR_SIZE;
+
+ param_data = p;
+ param_data->module_instance_id = module->instance_id;
+ param_data->error_code = 0;
+ param_data->param_id = PARAM_ID_SAL_LIMITER_ENABLE;
+ param_data->param_size = sizeof(*limiter_enable);
+ p = p + APM_MODULE_PARAM_DATA_SIZE;
+ limiter_enable = p;
+
+ limiter_enable->enable_lim = enable;
+
+ rc = q6apm_send_cmd_sync(graph->apm, pkt, 0);
+
+ kfree(pkt);
+
+ return rc;
+}
+
+static int audioreach_sal_set_media_format(struct q6apm_graph *graph,
+ struct audioreach_module *module,
+ struct audioreach_module_config *cfg)
+{
+ struct apm_module_param_data *param_data;
+ struct param_id_sal_output_config *media_format;
+ int payload_size;
+ struct gpr_pkt *pkt;
+ int rc;
+ void *p;
+
+ payload_size = sizeof(*media_format) + APM_MODULE_PARAM_DATA_SIZE;
+
+ pkt = audioreach_alloc_apm_cmd_pkt(payload_size, APM_CMD_SET_CFG, 0);
+ if (IS_ERR(pkt))
+ return PTR_ERR(pkt);
+
+ p = (void *)pkt + GPR_HDR_SIZE + APM_CMD_HDR_SIZE;
+
+ param_data = p;
+ param_data->module_instance_id = module->instance_id;
+ param_data->error_code = 0;
+ param_data->param_id = PARAM_ID_SAL_OUTPUT_CFG;
+ param_data->param_size = sizeof(*media_format);
+ p = p + APM_MODULE_PARAM_DATA_SIZE;
+ media_format = p;
+
+ media_format->bits_per_sample = cfg->bit_width;
+
+ rc = q6apm_send_cmd_sync(graph->apm, pkt, 0);
+
+ kfree(pkt);
+
+ return rc;
+}
+
+static int audioreach_module_enable(struct q6apm_graph *graph,
+ struct audioreach_module *module,
+ bool enable)
+{
+ struct apm_module_param_data *param_data;
+ struct param_id_module_enable *param;
+ int payload_size;
+ struct gpr_pkt *pkt;
+ int rc;
+ void *p;
+
+ payload_size = sizeof(*param) + APM_MODULE_PARAM_DATA_SIZE;
+
+ pkt = audioreach_alloc_apm_cmd_pkt(payload_size, APM_CMD_SET_CFG, 0);
+ if (IS_ERR(pkt))
+ return PTR_ERR(pkt);
+
+ p = (void *)pkt + GPR_HDR_SIZE + APM_CMD_HDR_SIZE;
+
+ param_data = p;
+ param_data->module_instance_id = module->instance_id;
+ param_data->error_code = 0;
+ param_data->param_id = PARAM_ID_MODULE_ENABLE;
+ param_data->param_size = sizeof(*param);
+ p = p + APM_MODULE_PARAM_DATA_SIZE;
+ param = p;
+
+ param->enable = enable;
+
+ rc = q6apm_send_cmd_sync(graph->apm, pkt, 0);
+
+ kfree(pkt);
+
+ return rc;
+}
+
+static int audioreach_mfc_set_media_format(struct q6apm_graph *graph,
+ struct audioreach_module *module,
+ struct audioreach_module_config *cfg)
+{
+ struct apm_module_param_data *param_data;
+ struct param_id_mfc_media_format *media_format;
+ uint32_t num_channels = cfg->num_channels;
+ int payload_size;
+ struct gpr_pkt *pkt;
+ int rc;
+ void *p;
+
+ payload_size = APM_MFC_CFG_PSIZE(media_format, num_channels) +
+ APM_MODULE_PARAM_DATA_SIZE;
+
+ pkt = audioreach_alloc_apm_cmd_pkt(payload_size, APM_CMD_SET_CFG, 0);
+ if (IS_ERR(pkt))
+ return PTR_ERR(pkt);
+
+ p = (void *)pkt + GPR_HDR_SIZE + APM_CMD_HDR_SIZE;
+
+ param_data = p;
+ param_data->module_instance_id = module->instance_id;
+ param_data->error_code = 0;
+ param_data->param_id = PARAM_ID_MFC_OUTPUT_MEDIA_FORMAT;
+ param_data->param_size = APM_MFC_CFG_PSIZE(media_format, num_channels);
+ p = p + APM_MODULE_PARAM_DATA_SIZE;
+ media_format = p;
+
+ media_format->sample_rate = cfg->sample_rate;
+ media_format->bit_width = cfg->bit_width;
+ media_format->num_channels = cfg->num_channels;
+
+ if (num_channels == 1) {
+ media_format->channel_mapping[0] = PCM_CHANNEL_L;
+ } else if (num_channels == 2) {
+ media_format->channel_mapping[0] = PCM_CHANNEL_L;
+ media_format->channel_mapping[1] = PCM_CHANNEL_R;
+ }
+
+ rc = q6apm_send_cmd_sync(graph->apm, pkt, 0);
+
+ kfree(pkt);
+
+ return rc;
+}
+
static int audioreach_i2s_set_media_format(struct q6apm_graph *graph,
struct audioreach_module *module,
struct audioreach_module_config *cfg)
@@ -995,7 +1113,9 @@ int audioreach_set_media_format(struct q6apm_graph *graph, struct audioreach_mod
switch (module->module_id) {
case MODULE_ID_DATA_LOGGING:
- rc = audioreach_logging_set_media_format(graph, module);
+ rc = audioreach_module_enable(graph, module, true);
+ if (!rc)
+ rc = audioreach_logging_set_media_format(graph, module);
break;
case MODULE_ID_PCM_DEC:
case MODULE_ID_PCM_ENC:
@@ -1016,6 +1136,14 @@ int audioreach_set_media_format(struct q6apm_graph *graph, struct audioreach_mod
case MODULE_ID_CODEC_DMA_SOURCE:
rc = audioreach_codec_dma_set_media_format(graph, module, cfg);
break;
+ case MODULE_ID_SAL:
+ rc = audioreach_sal_set_media_format(graph, module, cfg);
+ if (!rc)
+ rc = audioreach_sal_limiter_enable(graph, module, true);
+ break;
+ case MODULE_ID_MFC:
+ rc = audioreach_mfc_set_media_format(graph, module, cfg);
+ break;
default:
rc = 0;
}
diff --git a/sound/soc/qcom/qdsp6/audioreach.h b/sound/soc/qcom/qdsp6/audioreach.h
index 3ee8bfcd0121..1d1d47d47d40 100644
--- a/sound/soc/qcom/qdsp6/audioreach.h
+++ b/sound/soc/qcom/qdsp6/audioreach.h
@@ -15,6 +15,8 @@ struct q6apm_graph;
#define MODULE_ID_PCM_CNV 0x07001003
#define MODULE_ID_PCM_ENC 0x07001004
#define MODULE_ID_PCM_DEC 0x07001005
+#define MODULE_ID_SAL 0x07001010
+#define MODULE_ID_MFC 0x07001015
#define MODULE_ID_CODEC_DMA_SINK 0x07001023
#define MODULE_ID_CODEC_DMA_SOURCE 0x07001024
#define MODULE_ID_I2S_SINK 0x0700100A
@@ -499,6 +501,16 @@ struct data_logging_config {
uint32_t mode;
} __packed;
+#define PARAM_ID_SAL_OUTPUT_CFG 0x08001016
+struct param_id_sal_output_config {
+ uint32_t bits_per_sample;
+} __packed;
+
+#define PARAM_ID_SAL_LIMITER_ENABLE 0x0800101E
+struct param_id_sal_limiter_enable {
+ uint32_t enable_lim;
+} __packed;
+
#define PARAM_ID_MFC_OUTPUT_MEDIA_FORMAT 0x08001024
struct param_id_mfc_media_format {
@@ -525,6 +537,11 @@ struct payload_media_fmt_pcm {
uint8_t channel_mapping[];
} __packed;
+#define PARAM_ID_MODULE_ENABLE 0x08001026
+struct param_id_module_enable {
+ uint32_t enable;
+} __packed;
+
#define PARAM_ID_CODEC_DMA_INTF_CFG 0x08001063
struct param_id_codec_dma_intf_cfg {
@@ -595,7 +612,11 @@ struct audioreach_graph_info {
int id;
uint32_t num_sub_graphs;
struct list_head sg_list;
- struct list_head connection_list;
+ /* DPCM connection from FE Graph to BE graph */
+ uint32_t src_mod_inst_id;
+ uint32_t src_mod_op_port_id;
+ uint32_t dst_mod_inst_id;
+ uint32_t dst_mod_ip_port_id;
};
struct audioreach_sub_graph {
@@ -623,6 +644,8 @@ struct audioreach_container {
struct audioreach_sub_graph *sub_graph;
};
+#define AR_MAX_MOD_LINKS 8
+
struct audioreach_module {
uint32_t module_id;
uint32_t instance_id;
@@ -633,11 +656,12 @@ struct audioreach_module {
uint32_t in_port;
uint32_t out_port;
+ uint32_t num_connections;
/* Connections */
uint32_t src_mod_inst_id;
- uint32_t src_mod_op_port_id;
- uint32_t dst_mod_inst_id;
- uint32_t dst_mod_ip_port_id;
+ uint32_t src_mod_op_port_id[AR_MAX_MOD_LINKS];
+ uint32_t dst_mod_inst_id[AR_MAX_MOD_LINKS];
+ uint32_t dst_mod_ip_port_id[AR_MAX_MOD_LINKS];
/* Format specifics */
uint32_t ch_fmt;
@@ -694,9 +718,8 @@ void *audioreach_alloc_apm_pkt(int pkt_size, uint32_t opcode, uint32_t token,
void *audioreach_alloc_pkt(int payload_size, uint32_t opcode,
uint32_t token, uint32_t src_port,
uint32_t dest_port);
-void *audioreach_alloc_graph_pkt(struct q6apm *apm,
- struct list_head *sg_list,
- int graph_id);
+void *audioreach_alloc_graph_pkt(struct q6apm *apm, struct audioreach_graph_info
+ *info);
/* Topology specific */
int audioreach_tplg_init(struct snd_soc_component *component);
@@ -717,14 +740,4 @@ int audioreach_set_media_format(struct q6apm_graph *graph,
int audioreach_shared_memory_send_eos(struct q6apm_graph *graph);
int audioreach_gain_set_vol_ctrl(struct q6apm *apm,
struct audioreach_module *module, int vol);
-struct audioreach_module *audioreach_get_container_last_module(
- struct audioreach_container *container);
-struct audioreach_module *audioreach_get_container_first_module(
- struct audioreach_container *container);
-struct audioreach_module *audioreach_get_container_next_module(
- struct audioreach_container *container,
- struct audioreach_module *module);
-#define list_for_each_container_module(mod, cont) \
- for (mod = audioreach_get_container_first_module(cont); mod != NULL; \
- mod = audioreach_get_container_next_module(cont, mod))
#endif /* __AUDIOREACH_H__ */
diff --git a/sound/soc/qcom/qdsp6/q6apm.c b/sound/soc/qcom/qdsp6/q6apm.c
index 794019286c70..5beb898f28f5 100644
--- a/sound/soc/qcom/qdsp6/q6apm.c
+++ b/sound/soc/qcom/qdsp6/q6apm.c
@@ -63,7 +63,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;
@@ -178,87 +178,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)
{
@@ -731,6 +650,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);
diff --git a/sound/soc/qcom/qdsp6/q6apm.h b/sound/soc/qcom/qdsp6/q6apm.h
index 54eadadf712c..273f97812741 100644
--- a/sound/soc/qcom/qdsp6/q6apm.h
+++ b/sound/soc/qcom/qdsp6/q6apm.h
@@ -58,6 +58,7 @@ struct q6apm {
struct mutex lock;
uint32_t state;
+ struct list_head widget_list;
struct idr graph_idr;
struct idr graph_info_idr;
struct idr sub_graphs_idr;
@@ -141,12 +142,7 @@ int q6apm_send_cmd_sync(struct q6apm *apm, struct gpr_pkt *pkt,
/* Callback for graph specific */
struct audioreach_module *q6apm_find_module_by_mid(struct q6apm_graph *graph,
uint32_t mid);
-
void q6apm_set_fe_dai_ops(struct snd_soc_dai_driver *dai_drv);
-int q6apm_connect_sub_graphs(struct q6apm *apm, u32 src_sgid, u32 dst_sgid,
- bool connect);
-bool q6apm_is_sub_graphs_connected(struct q6apm *apm, u32 src_sgid,
- u32 dst_sgid);
int q6apm_graph_get_rx_shmem_module_iid(struct q6apm_graph *graph);
#endif /* __APM_GRAPH_ */
diff --git a/sound/soc/qcom/qdsp6/q6prm.c b/sound/soc/qcom/qdsp6/q6prm.c
index cda33ded29be..8aa1a213bfb7 100644
--- a/sound/soc/qcom/qdsp6/q6prm.c
+++ b/sound/soc/qcom/qdsp6/q6prm.c
@@ -247,5 +247,5 @@ static gpr_driver_t prm_driver = {
};
module_gpr_driver(prm_driver);
-MODULE_DESCRIPTION("Audio Process Manager");
+MODULE_DESCRIPTION("Q6 Proxy Resource Manager");
MODULE_LICENSE("GPL");
diff --git a/sound/soc/qcom/qdsp6/topology.c b/sound/soc/qcom/qdsp6/topology.c
index bd649c232a06..cccc59b570b9 100644
--- a/sound/soc/qcom/qdsp6/topology.c
+++ b/sound/soc/qcom/qdsp6/topology.c
@@ -16,7 +16,11 @@
#include "audioreach.h"
struct snd_ar_control {
+ u32 graph_id; /* Graph ID */
u32 sgid; /* Sub Graph ID */
+ u32 module_instance_id; /* Connected Module Instance ID */
+ struct snd_soc_dapm_widget *w;
+ struct list_head node;
struct snd_soc_component *scomp;
};
@@ -44,7 +48,7 @@ static struct audioreach_graph_info *audioreach_tplg_alloc_graph_info(struct q6a
INIT_LIST_HEAD(&info->sg_list);
mutex_lock(&apm->lock);
- ret = idr_alloc(&apm->graph_info_idr, info, graph_id, graph_id + 1, GFP_KERNEL);
+ ret = idr_alloc_u32(&apm->graph_info_idr, info, &graph_id, graph_id, GFP_KERNEL);
mutex_unlock(&apm->lock);
if (ret < 0) {
@@ -53,7 +57,7 @@ static struct audioreach_graph_info *audioreach_tplg_alloc_graph_info(struct q6a
return ERR_PTR(ret);
}
- info->id = ret;
+ info->id = graph_id;
return info;
}
@@ -94,7 +98,7 @@ static struct audioreach_sub_graph *audioreach_tplg_alloc_sub_graph(struct q6apm
INIT_LIST_HEAD(&sg->container_list);
mutex_lock(&apm->lock);
- ret = idr_alloc(&apm->sub_graphs_idr, sg, sub_graph_id, sub_graph_id + 1, GFP_KERNEL);
+ ret = idr_alloc_u32(&apm->sub_graphs_idr, sg, &sub_graph_id, sub_graph_id, GFP_KERNEL);
mutex_unlock(&apm->lock);
if (ret < 0) {
@@ -103,7 +107,7 @@ static struct audioreach_sub_graph *audioreach_tplg_alloc_sub_graph(struct q6apm
return ERR_PTR(ret);
}
- sg->sub_graph_id = ret;
+ sg->sub_graph_id = sub_graph_id;
return sg;
}
@@ -136,7 +140,7 @@ static struct audioreach_container *audioreach_tplg_alloc_container(struct q6apm
INIT_LIST_HEAD(&cont->modules_list);
mutex_lock(&apm->lock);
- ret = idr_alloc(&apm->containers_idr, cont, container_id, container_id + 1, GFP_KERNEL);
+ ret = idr_alloc_u32(&apm->containers_idr, cont, &container_id, container_id, GFP_KERNEL);
mutex_unlock(&apm->lock);
if (ret < 0) {
@@ -145,7 +149,7 @@ static struct audioreach_container *audioreach_tplg_alloc_container(struct q6apm
return ERR_PTR(ret);
}
- cont->container_id = ret;
+ cont->container_id = container_id;
cont->sub_graph = sg;
/* add to container list */
list_add_tail(&cont->node, &sg->container_list);
@@ -181,7 +185,7 @@ static struct audioreach_module *audioreach_tplg_alloc_module(struct q6apm *apm,
AR_MODULE_DYNAMIC_INSTANCE_ID_START,
AR_MODULE_DYNAMIC_INSTANCE_ID_END, GFP_KERNEL);
} else {
- ret = idr_alloc(&apm->modules_idr, mod, module_id, module_id + 1, GFP_KERNEL);
+ ret = idr_alloc_u32(&apm->modules_idr, mod, &module_id, module_id, GFP_KERNEL);
}
mutex_unlock(&apm->lock);
@@ -191,7 +195,7 @@ static struct audioreach_module *audioreach_tplg_alloc_module(struct q6apm *apm,
return ERR_PTR(ret);
}
- mod->instance_id = ret;
+ mod->instance_id = module_id;
/* add to module list */
list_add_tail(&mod->node, &cont->modules_list);
mod->container = cont;
@@ -408,19 +412,25 @@ static struct audioreach_module *audioreach_parse_common_tokens(struct q6apm *ap
struct snd_soc_dapm_widget *w)
{
uint32_t max_ip_port = 0, max_op_port = 0, in_port = 0, out_port = 0;
- uint32_t src_mod_inst_id = 0, src_mod_op_port_id = 0;
- uint32_t dst_mod_inst_id = 0, dst_mod_ip_port_id = 0;
+ uint32_t src_mod_op_port_id[AR_MAX_MOD_LINKS] = { 0, };
+ uint32_t dst_mod_inst_id[AR_MAX_MOD_LINKS] = { 0, };
+ uint32_t dst_mod_ip_port_id[AR_MAX_MOD_LINKS] = { 0, };
+ uint32_t src_mod_inst_id = 0;
+
int module_id = 0, instance_id = 0, tkn_count = 0;
struct snd_soc_tplg_vendor_value_elem *mod_elem;
struct snd_soc_tplg_vendor_array *mod_array;
struct audioreach_module *mod = NULL;
+ uint32_t token;
bool found;
+ int max_tokens;
mod_array = audioreach_get_module_array(private);
mod_elem = mod_array->value;
-
- while (tkn_count <= (le32_to_cpu(mod_array->num_elems) - 1)) {
- switch (le32_to_cpu(mod_elem->token)) {
+ max_tokens = le32_to_cpu(mod_array->num_elems);
+ while (tkn_count <= (max_tokens - 1)) {
+ token = le32_to_cpu(mod_elem->token);
+ switch (token) {
/* common module info */
case AR_TKN_U32_MODULE_ID:
module_id = le32_to_cpu(mod_elem->value);
@@ -450,17 +460,80 @@ static struct audioreach_module *audioreach_parse_common_tokens(struct q6apm *ap
case AR_TKN_U32_MODULE_OUT_PORTS:
out_port = le32_to_cpu(mod_elem->value);
break;
- case AR_TKN_U32_MODULE_SRC_OP_PORT_ID:
- src_mod_op_port_id = le32_to_cpu(mod_elem->value);
- break;
case AR_TKN_U32_MODULE_SRC_INSTANCE_ID:
src_mod_inst_id = le32_to_cpu(mod_elem->value);
break;
+ case AR_TKN_U32_MODULE_SRC_OP_PORT_ID:
+ src_mod_op_port_id[0] = le32_to_cpu(mod_elem->value);
+ break;
+ case AR_TKN_U32_MODULE_SRC_OP_PORT_ID1:
+ src_mod_op_port_id[1] = le32_to_cpu(mod_elem->value);
+ break;
+ case AR_TKN_U32_MODULE_SRC_OP_PORT_ID2:
+ src_mod_op_port_id[2] = le32_to_cpu(mod_elem->value);
+ break;
+ case AR_TKN_U32_MODULE_SRC_OP_PORT_ID3:
+ src_mod_op_port_id[3] = le32_to_cpu(mod_elem->value);
+ break;
+ case AR_TKN_U32_MODULE_SRC_OP_PORT_ID4:
+ src_mod_op_port_id[4] = le32_to_cpu(mod_elem->value);
+ break;
+ case AR_TKN_U32_MODULE_SRC_OP_PORT_ID5:
+ src_mod_op_port_id[5] = le32_to_cpu(mod_elem->value);
+ break;
+ case AR_TKN_U32_MODULE_SRC_OP_PORT_ID6:
+ src_mod_op_port_id[6] = le32_to_cpu(mod_elem->value);
+ break;
+ case AR_TKN_U32_MODULE_SRC_OP_PORT_ID7:
+ src_mod_op_port_id[7] = le32_to_cpu(mod_elem->value);
+ break;
case AR_TKN_U32_MODULE_DST_INSTANCE_ID:
- dst_mod_inst_id = le32_to_cpu(mod_elem->value);
+ dst_mod_inst_id[0] = le32_to_cpu(mod_elem->value);
+ break;
+ case AR_TKN_U32_MODULE_DST_INSTANCE_ID1:
+ dst_mod_inst_id[1] = le32_to_cpu(mod_elem->value);
+ break;
+ case AR_TKN_U32_MODULE_DST_INSTANCE_ID2:
+ dst_mod_inst_id[2] = le32_to_cpu(mod_elem->value);
+ break;
+ case AR_TKN_U32_MODULE_DST_INSTANCE_ID3:
+ dst_mod_inst_id[3] = le32_to_cpu(mod_elem->value);
+ break;
+ case AR_TKN_U32_MODULE_DST_INSTANCE_ID4:
+ dst_mod_inst_id[4] = le32_to_cpu(mod_elem->value);
+ break;
+ case AR_TKN_U32_MODULE_DST_INSTANCE_ID5:
+ dst_mod_inst_id[5] = le32_to_cpu(mod_elem->value);
+ break;
+ case AR_TKN_U32_MODULE_DST_INSTANCE_ID6:
+ dst_mod_inst_id[6] = le32_to_cpu(mod_elem->value);
+ break;
+ case AR_TKN_U32_MODULE_DST_INSTANCE_ID7:
+ dst_mod_inst_id[7] = le32_to_cpu(mod_elem->value);
break;
case AR_TKN_U32_MODULE_DST_IN_PORT_ID:
- dst_mod_ip_port_id = le32_to_cpu(mod_elem->value);
+ dst_mod_ip_port_id[0] = le32_to_cpu(mod_elem->value);
+ break;
+ case AR_TKN_U32_MODULE_DST_IN_PORT_ID1:
+ dst_mod_ip_port_id[1] = le32_to_cpu(mod_elem->value);
+ break;
+ case AR_TKN_U32_MODULE_DST_IN_PORT_ID2:
+ dst_mod_ip_port_id[2] = le32_to_cpu(mod_elem->value);
+ break;
+ case AR_TKN_U32_MODULE_DST_IN_PORT_ID3:
+ dst_mod_ip_port_id[3] = le32_to_cpu(mod_elem->value);
+ break;
+ case AR_TKN_U32_MODULE_DST_IN_PORT_ID4:
+ dst_mod_ip_port_id[4] = le32_to_cpu(mod_elem->value);
+ break;
+ case AR_TKN_U32_MODULE_DST_IN_PORT_ID5:
+ dst_mod_ip_port_id[5] = le32_to_cpu(mod_elem->value);
+ break;
+ case AR_TKN_U32_MODULE_DST_IN_PORT_ID6:
+ dst_mod_ip_port_id[6] = le32_to_cpu(mod_elem->value);
+ break;
+ case AR_TKN_U32_MODULE_DST_IN_PORT_ID7:
+ dst_mod_ip_port_id[7] = le32_to_cpu(mod_elem->value);
break;
default:
break;
@@ -471,15 +544,23 @@ static struct audioreach_module *audioreach_parse_common_tokens(struct q6apm *ap
}
if (mod) {
+ int pn, id = 0;
mod->module_id = module_id;
mod->max_ip_port = max_ip_port;
mod->max_op_port = max_op_port;
mod->in_port = in_port;
mod->out_port = out_port;
mod->src_mod_inst_id = src_mod_inst_id;
- mod->src_mod_op_port_id = src_mod_op_port_id;
- mod->dst_mod_inst_id = dst_mod_inst_id;
- mod->dst_mod_ip_port_id = dst_mod_ip_port_id;
+ for (pn = 0; pn < mod->max_op_port; pn++) {
+ if (src_mod_op_port_id[pn] && dst_mod_inst_id[pn] &&
+ dst_mod_ip_port_id[pn]) {
+ mod->src_mod_op_port_id[id] = src_mod_op_port_id[pn];
+ mod->dst_mod_inst_id[id] = dst_mod_inst_id[pn];
+ mod->dst_mod_ip_port_id[id] = dst_mod_ip_port_id[pn];
+ id++;
+ mod->num_connections = id;
+ }
+ }
}
return mod;
@@ -692,6 +773,7 @@ static int audioreach_widget_load_mixer(struct snd_soc_component *component,
struct snd_soc_tplg_vendor_value_elem *w_elem;
struct snd_soc_tplg_vendor_array *w_array;
struct snd_ar_control *scontrol;
+ struct q6apm *data = dev_get_drvdata(component->dev);
struct snd_soc_dobj *dobj;
int tkn_count = 0;
@@ -711,6 +793,9 @@ static int audioreach_widget_load_mixer(struct snd_soc_component *component,
case AR_TKN_U32_SUB_GRAPH_INSTANCE_ID:
scontrol->sgid = le32_to_cpu(w_elem->value);
break;
+ case AR_TKN_DAI_INDEX:
+ scontrol->graph_id = le32_to_cpu(w_elem->value);
+ break;
default: /* ignore other tokens */
break;
}
@@ -718,6 +803,9 @@ static int audioreach_widget_load_mixer(struct snd_soc_component *component,
w_elem++;
}
+ scontrol->w = w;
+ list_add_tail(&scontrol->node, &data->widget_list);
+
return 0;
}
@@ -819,7 +907,10 @@ static int audioreach_widget_unload(struct snd_soc_component *scomp,
if (w->id == snd_soc_dapm_mixer) {
/* virtual widget */
- kfree(dobj->private);
+ struct snd_ar_control *scontrol = dobj->private;
+
+ list_del(&scontrol->node);
+ kfree(scontrol);
return 0;
}
@@ -858,7 +949,21 @@ static int audioreach_widget_unload(struct snd_soc_component *scomp,
return 0;
}
-static struct audioreach_module *audioreach_find_widget(struct snd_soc_component *comp,
+static struct snd_ar_control *audioreach_find_widget(struct snd_soc_component *comp,
+ const char *name)
+{
+ struct q6apm *apm = dev_get_drvdata(comp->dev);
+ struct snd_ar_control *control;
+
+ list_for_each_entry(control, &apm->widget_list, node) {
+ if (control->w && !strcmp(name, control->w->name))
+ return control;
+ }
+
+ return NULL;
+}
+
+static struct audioreach_module *audioreach_find_module(struct snd_soc_component *comp,
const char *name)
{
struct q6apm *apm = dev_get_drvdata(comp->dev);
@@ -876,14 +981,41 @@ static struct audioreach_module *audioreach_find_widget(struct snd_soc_component
static int audioreach_route_load(struct snd_soc_component *scomp, int index,
struct snd_soc_dapm_route *route)
{
- struct audioreach_module *src, *sink;
-
- src = audioreach_find_widget(scomp, route->source);
- sink = audioreach_find_widget(scomp, route->sink);
+ struct audioreach_module *src_module, *sink_module;
+ struct snd_ar_control *control;
+ struct snd_soc_dapm_widget *w;
+ int i;
+
+ /* check if these are actual modules */
+ src_module = audioreach_find_module(scomp, route->source);
+ sink_module = audioreach_find_module(scomp, route->sink);
+
+ if (sink_module && !src_module) {
+ control = audioreach_find_widget(scomp, route->source);
+ if (control)
+ control->module_instance_id = sink_module->instance_id;
+
+ } else if (!sink_module && src_module && route->control) {
+ /* check if this is a virtual mixer */
+ control = audioreach_find_widget(scomp, route->sink);
+ if (!control || !control->w)
+ return 0;
+
+ w = control->w;
+
+ for (i = 0; i < w->num_kcontrols; i++) {
+ if (!strcmp(route->control, w->kcontrol_news[i].name)) {
+ struct soc_mixer_control *sm;
+ struct snd_soc_dobj *dobj;
+ struct snd_ar_control *scontrol;
+
+ sm = (struct soc_mixer_control *)w->kcontrol_news[i].private_value;
+ dobj = &sm->dobj;
+ scontrol = dobj->private;
+ scontrol->module_instance_id = src_module->instance_id;
+ }
+ }
- if (src && sink) {
- src->dst_mod_inst_id = sink->instance_id;
- sink->src_mod_inst_id = src->instance_id;
}
return 0;
@@ -914,6 +1046,48 @@ static int audioreach_link_load(struct snd_soc_component *component, int index,
return 0;
}
+static void audioreach_connect_sub_graphs(struct q6apm *apm,
+ struct snd_ar_control *m1,
+ struct snd_ar_control *m2,
+ bool connect)
+{
+ struct audioreach_graph_info *info;
+
+ mutex_lock(&apm->lock);
+ info = idr_find(&apm->graph_info_idr, m2->graph_id);
+ mutex_unlock(&apm->lock);
+
+ if (connect) {
+ info->src_mod_inst_id = m1->module_instance_id;
+ info->src_mod_op_port_id = 1;
+ info->dst_mod_inst_id = m2->module_instance_id;
+ info->dst_mod_ip_port_id = 2;
+
+ } else {
+ info->src_mod_inst_id = 0;
+ info->src_mod_op_port_id = 0;
+ info->dst_mod_inst_id = 0;
+ info->dst_mod_ip_port_id = 0;
+ }
+}
+
+static bool audioreach_is_vmixer_connected(struct q6apm *apm,
+ struct snd_ar_control *m1,
+ struct snd_ar_control *m2)
+{
+ struct audioreach_graph_info *info;
+
+ mutex_lock(&apm->lock);
+ info = idr_find(&apm->graph_info_idr, m2->graph_id);
+ mutex_unlock(&apm->lock);
+
+ if (info->dst_mod_inst_id == m2->module_instance_id &&
+ info->src_mod_inst_id == m1->module_instance_id)
+ return true;
+
+ return false;
+}
+
static int audioreach_get_audio_mixer(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
@@ -926,7 +1100,7 @@ static int audioreach_get_audio_mixer(struct snd_kcontrol *kcontrol,
struct q6apm *data = dev_get_drvdata(c->dev);
bool connected;
- connected = q6apm_is_sub_graphs_connected(data, scontrol->sgid, dapm_scontrol->sgid);
+ connected = audioreach_is_vmixer_connected(data, scontrol, dapm_scontrol);
if (connected)
ucontrol->value.integer.value[0] = 1;
else
@@ -947,10 +1121,10 @@ static int audioreach_put_audio_mixer(struct snd_kcontrol *kcontrol,
struct q6apm *data = dev_get_drvdata(c->dev);
if (ucontrol->value.integer.value[0]) {
- q6apm_connect_sub_graphs(data, scontrol->sgid, dapm_scontrol->sgid, true);
+ audioreach_connect_sub_graphs(data, scontrol, dapm_scontrol, true);
snd_soc_dapm_mixer_update_power(dapm, kcontrol, 1, NULL);
} else {
- q6apm_connect_sub_graphs(data, scontrol->sgid, dapm_scontrol->sgid, false);
+ audioreach_connect_sub_graphs(data, scontrol, dapm_scontrol, false);
snd_soc_dapm_mixer_update_power(dapm, kcontrol, 0, NULL);
}
return 0;
@@ -998,6 +1172,9 @@ static int audioreach_control_load_mix(struct snd_soc_component *scomp,
case AR_TKN_U32_SUB_GRAPH_INSTANCE_ID:
scontrol->sgid = le32_to_cpu(c_elem->value);
break;
+ case AR_TKN_DAI_INDEX:
+ scontrol->graph_id = le32_to_cpu(c_elem->value);
+ break;
default:
/* Ignore other tokens */
break;