mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-09-04 09:59:32 +00:00
ASoC: qdsp6: audioreach: Simplify handing FE and BE graph connections
Current AudioReach design of connecting FE and BE graph is very complicated and not reliable. Instead used the virtual damp widgets private data to help identify the modules that needs connection at runtime. Also maintain a inter-graph connection info in the graph info, which can be used to both determine if the graphs are connected and at graph build time. Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org> Link: https://lore.kernel.org/r/20221027102710.21407-5-srinivas.kandagatla@linaro.org Signed-off-by: Mark Brown <broonie@kernel.org>
This commit is contained in:
parent
1c87d3817b
commit
e4977b91cf
5 changed files with 126 additions and 173 deletions
|
@ -332,63 +332,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 +343,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 +372,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,7 +393,7 @@ 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) {
|
||||
list_for_each_entry(module, &container->modules_list, node) {
|
||||
uint32_t src_mod_inst_id;
|
||||
|
||||
src_mod_inst_id = module->src_mod_inst_id;
|
||||
|
@ -462,7 +416,7 @@ static void audioreach_populate_graph(struct apm_graph_open_params *open,
|
|||
}
|
||||
}
|
||||
|
||||
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,6 +429,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;
|
||||
struct list_head *sg_list;
|
||||
int num_modules_per_list;
|
||||
int num_connections = 0;
|
||||
int num_containers = 0;
|
||||
|
@ -484,12 +439,19 @@ 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) {
|
||||
list_for_each_entry(module, &container->modules_list, node) {
|
||||
if (module->src_mod_inst_id)
|
||||
num_connections++;
|
||||
}
|
||||
|
@ -557,7 +519,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(¶ms, sg_list, num_sub_graphs);
|
||||
audioreach_populate_graph(apm, info, ¶ms, sg_list, num_sub_graphs);
|
||||
|
||||
return pkt;
|
||||
}
|
||||
|
|
|
@ -595,6 +595,11 @@ struct audioreach_graph_info {
|
|||
int id;
|
||||
uint32_t num_sub_graphs;
|
||||
struct list_head sg_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 {
|
||||
|
@ -693,9 +698,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);
|
||||
|
||||
|
@ -716,14 +720,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__ */
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -142,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_ */
|
||||
|
|
|
@ -872,7 +872,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);
|
||||
|
@ -890,14 +904,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;
|
||||
struct audioreach_module *src_module, *sink_module;
|
||||
struct snd_ar_control *control;
|
||||
struct snd_soc_dapm_widget *w;
|
||||
int i;
|
||||
|
||||
src = audioreach_find_widget(scomp, route->source);
|
||||
sink = audioreach_find_widget(scomp, route->sink);
|
||||
/* 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;
|
||||
|
@ -928,6 +969,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)
|
||||
{
|
||||
|
@ -940,7 +1023,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
|
||||
|
@ -961,10 +1044,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;
|
||||
|
|
Loading…
Reference in a new issue