Skip to content

Commit

Permalink
ASoC: Intel: Skylake: Add support for deferred DSP module bind
Browse files Browse the repository at this point in the history
Module at the end of DSP pipeline that needs to be connected to a module
in another pipeline are represented as a PGA(leaf node) and in PGA event
handler these modules are bound/unbounded. Modules other than PGA leaf
can be connected directly or via switch to a module in another pipeline.
Example: reference path.

To support the deferred DSP module bind, following changes are done:
o When the path is enabled, the destination module that needs to be
bound may not be initialized. If the module is not initialized, add
these modules in a deferred bind list.
o When the destination module is initialized, check for these modules
in deferred bind list. If found, bind them.
o When the destination module is deleted, Unbind the modules.
o When the source module is deleted, remove the entry from the deferred
bind list.

Signed-off-by: Jeeja KP <jeeja.kp@intel.com>
Acked-by: Vinod Koul <vinod.koul@intel.com>
Signed-off-by: Mark Brown <broonie@kernel.org>
  • Loading branch information
Jeeja KP authored and Mark Brown committed Apr 12, 2017
1 parent 5f75b19 commit b8c722d
Show file tree
Hide file tree
Showing 4 changed files with 127 additions and 1 deletion.
12 changes: 12 additions & 0 deletions sound/soc/intel/skylake/skl-pcm.c
Original file line number Diff line number Diff line change
Expand Up @@ -1300,6 +1300,7 @@ int skl_platform_register(struct device *dev)
struct skl *skl = ebus_to_skl(ebus);

INIT_LIST_HEAD(&skl->ppl_list);
INIT_LIST_HEAD(&skl->bind_list);

ret = snd_soc_register_platform(dev, &skl_platform_drv);
if (ret) {
Expand All @@ -1320,6 +1321,17 @@ int skl_platform_register(struct device *dev)

int skl_platform_unregister(struct device *dev)
{
struct hdac_ext_bus *ebus = dev_get_drvdata(dev);
struct skl *skl = ebus_to_skl(ebus);
struct skl_module_deferred_bind *modules;

if (!list_empty(&skl->bind_list)) {
list_for_each_entry(modules, &skl->bind_list, node) {
list_del(&modules->node);
kfree(modules);
}
}

snd_soc_unregister_component(dev);
snd_soc_unregister_platform(dev);
return 0;
Expand Down
109 changes: 108 additions & 1 deletion sound/soc/intel/skylake/skl-topology.c
Original file line number Diff line number Diff line change
Expand Up @@ -638,8 +638,9 @@ static int skl_tplg_mixer_dapm_pre_pmu_event(struct snd_soc_dapm_widget *w,
struct skl_module_cfg *mconfig = w->priv;
struct skl_pipe_module *w_module;
struct skl_pipe *s_pipe = mconfig->pipe;
struct skl_module_cfg *src_module = NULL, *dst_module;
struct skl_module_cfg *src_module = NULL, *dst_module, *module;
struct skl_sst *ctx = skl->skl_sst;
struct skl_module_deferred_bind *modules;

/* check resource available */
if (!skl_is_pipe_mcps_avail(skl, mconfig))
Expand Down Expand Up @@ -680,6 +681,22 @@ static int skl_tplg_mixer_dapm_pre_pmu_event(struct snd_soc_dapm_widget *w,
src_module = dst_module;
}

/*
* When the destination module is initialized, check for these modules
* in deferred bind list. If found, bind them.
*/
list_for_each_entry(w_module, &s_pipe->w_list, node) {
if (list_empty(&skl->bind_list))
break;

list_for_each_entry(modules, &skl->bind_list, node) {
module = w_module->w->priv;
if (modules->dst == module)
skl_bind_modules(ctx, modules->src,
modules->dst);
}
}

return 0;
}

Expand Down Expand Up @@ -776,6 +793,44 @@ static int skl_tplg_set_module_bind_params(struct snd_soc_dapm_widget *w,
return 0;
}


static int skl_tplg_module_add_deferred_bind(struct skl *skl,
struct skl_module_cfg *src, struct skl_module_cfg *dst)
{
struct skl_module_deferred_bind *m_list, *modules;
int i;

/* only supported for module with static pin connection */
for (i = 0; i < dst->max_in_queue; i++) {
struct skl_module_pin *pin = &dst->m_in_pin[i];

if (pin->is_dynamic)
continue;

if ((pin->id.module_id == src->id.module_id) &&
(pin->id.instance_id == src->id.instance_id)) {

if (!list_empty(&skl->bind_list)) {
list_for_each_entry(modules, &skl->bind_list, node) {
if (modules->src == src && modules->dst == dst)
return 0;
}
}

m_list = kzalloc(sizeof(*m_list), GFP_KERNEL);
if (!m_list)
return -ENOMEM;

m_list->src = src;
m_list->dst = dst;

list_add(&m_list->node, &skl->bind_list);
}
}

return 0;
}

static int skl_tplg_bind_sinks(struct snd_soc_dapm_widget *w,
struct skl *skl,
struct snd_soc_dapm_widget *src_w,
Expand Down Expand Up @@ -810,6 +865,28 @@ static int skl_tplg_bind_sinks(struct snd_soc_dapm_widget *w,
sink = p->sink;
sink_mconfig = sink->priv;

/*
* Modules other than PGA leaf can be connected
* directly or via switch to a module in another
* pipeline. EX: reference path
* when the path is enabled, the dst module that needs
* to be bound may not be initialized. if the module is
* not initialized, add these modules in the deferred
* bind list and when the dst module is initialised,
* bind this module to the dst_module in deferred list.
*/
if (((src_mconfig->m_state == SKL_MODULE_INIT_DONE)
&& (sink_mconfig->m_state == SKL_MODULE_UNINIT))) {

ret = skl_tplg_module_add_deferred_bind(skl,
src_mconfig, sink_mconfig);

if (ret < 0)
return ret;

}


if (src_mconfig->m_state == SKL_MODULE_UNINIT ||
sink_mconfig->m_state == SKL_MODULE_UNINIT)
continue;
Expand Down Expand Up @@ -1014,13 +1091,43 @@ static int skl_tplg_mixer_dapm_post_pmd_event(struct snd_soc_dapm_widget *w,
struct skl_module_cfg *src_module = NULL, *dst_module;
struct skl_sst *ctx = skl->skl_sst;
struct skl_pipe *s_pipe = mconfig->pipe;
struct skl_module_deferred_bind *modules;

if (s_pipe->state == SKL_PIPE_INVALID)
return -EINVAL;

skl_tplg_free_pipe_mcps(skl, mconfig);
skl_tplg_free_pipe_mem(skl, mconfig);

list_for_each_entry(w_module, &s_pipe->w_list, node) {
if (list_empty(&skl->bind_list))
break;

src_module = w_module->w->priv;

list_for_each_entry(modules, &skl->bind_list, node) {
/*
* When the destination module is deleted, Unbind the
* modules from deferred bind list.
*/
if (modules->dst == src_module) {
skl_unbind_modules(ctx, modules->src,
modules->dst);
}

/*
* When the source module is deleted, remove this entry
* from the deferred bind list.
*/
if (modules->src == src_module) {
list_del(&modules->node);
modules->src = NULL;
modules->dst = NULL;
kfree(modules);
}
}
}

list_for_each_entry(w_module, &s_pipe->w_list, node) {
dst_module = w_module->w->priv;

Expand Down
6 changes: 6 additions & 0 deletions sound/soc/intel/skylake/skl-topology.h
Original file line number Diff line number Diff line change
Expand Up @@ -336,6 +336,12 @@ struct skl_pipeline {
struct list_head node;
};

struct skl_module_deferred_bind {
struct skl_module_cfg *src;
struct skl_module_cfg *dst;
struct list_head node;
};

static inline struct skl *get_skl_ctx(struct device *dev)
{
struct hdac_ext_bus *ebus = dev_get_drvdata(dev);
Expand Down
1 change: 1 addition & 0 deletions sound/soc/intel/skylake/skl.h
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ struct skl {

struct skl_dsp_resource resource;
struct list_head ppl_list;
struct list_head bind_list;

const char *fw_name;
char tplg_name[64];
Expand Down

0 comments on commit b8c722d

Please sign in to comment.