-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
ASoC: Intel: Skylake: Add pipe and modules handlers
SKL driver needs to instantiate pipelines and modules in the DSP. The topology in the DSP is modelled as DAPM graph with a PGA representing a module instance and mixer representing a pipeline for a group of modules along with the mixer itself. Here we start adding building block for handling these. We add resource checks (memory/compute) for pipelines, find the modules in a pipeline, init modules in a pipe and lastly bind/unbind modules in a pipe These will be used by pipe event handlers in subsequent patches Signed-off-by: Jeeja KP <jeeja.kp@intel.com> Signed-off-by: Subhransu S. Prusty <subhransu.s.prusty@intel.com> Signed-off-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
Oct 7, 2015
1 parent
b5e5a45
commit e4e2d2f
Showing
4 changed files
with
210 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,187 @@ | ||
/* | ||
* skl-topology.c - Implements Platform component ALSA controls/widget | ||
* handlers. | ||
* | ||
* Copyright (C) 2014-2015 Intel Corp | ||
* Author: Jeeja KP <jeeja.kp@intel.com> | ||
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||
* | ||
* This program is free software; you can redistribute it and/or modify | ||
* it under the terms of the GNU General Public License as version 2, as | ||
* published by the Free Software Foundation. | ||
* | ||
* This program is distributed in the hope that it will be useful, but | ||
* WITHOUT ANY WARRANTY; without even the implied warranty of | ||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
* General Public License for more details. | ||
*/ | ||
|
||
#include <linux/slab.h> | ||
#include <linux/types.h> | ||
#include <linux/firmware.h> | ||
#include <sound/soc.h> | ||
#include <sound/soc-topology.h> | ||
#include "skl-sst-dsp.h" | ||
#include "skl-sst-ipc.h" | ||
#include "skl-topology.h" | ||
#include "skl.h" | ||
#include "skl-tplg-interface.h" | ||
|
||
/* | ||
* SKL DSP driver modelling uses only few DAPM widgets so for rest we will | ||
* ignore. This helpers checks if the SKL driver handles this widget type | ||
*/ | ||
static int is_skl_dsp_widget_type(struct snd_soc_dapm_widget *w) | ||
{ | ||
switch (w->id) { | ||
case snd_soc_dapm_dai_link: | ||
case snd_soc_dapm_dai_in: | ||
case snd_soc_dapm_aif_in: | ||
case snd_soc_dapm_aif_out: | ||
case snd_soc_dapm_dai_out: | ||
case snd_soc_dapm_switch: | ||
return false; | ||
default: | ||
return true; | ||
} | ||
} | ||
|
||
/* | ||
* Each pipelines needs memory to be allocated. Check if we have free memory | ||
* from available pool. Then only add this to pool | ||
* This is freed when pipe is deleted | ||
* Note: DSP does actual memory management we only keep track for complete | ||
* pool | ||
*/ | ||
static bool skl_tplg_alloc_pipe_mem(struct skl *skl, | ||
struct skl_module_cfg *mconfig) | ||
{ | ||
struct skl_sst *ctx = skl->skl_sst; | ||
|
||
if (skl->resource.mem + mconfig->pipe->memory_pages > | ||
skl->resource.max_mem) { | ||
dev_err(ctx->dev, | ||
"%s: module_id %d instance %d\n", __func__, | ||
mconfig->id.module_id, | ||
mconfig->id.instance_id); | ||
dev_err(ctx->dev, | ||
"exceeds ppl memory available %d mem %d\n", | ||
skl->resource.max_mem, skl->resource.mem); | ||
return false; | ||
} | ||
|
||
skl->resource.mem += mconfig->pipe->memory_pages; | ||
return true; | ||
} | ||
|
||
/* | ||
* Pipeline needs needs DSP CPU resources for computation, this is | ||
* quantified in MCPS (Million Clocks Per Second) required for module/pipe | ||
* | ||
* Each pipelines needs mcps to be allocated. Check if we have mcps for this | ||
* pipe. This adds the mcps to driver counter | ||
* This is removed on pipeline delete | ||
*/ | ||
static bool skl_tplg_alloc_pipe_mcps(struct skl *skl, | ||
struct skl_module_cfg *mconfig) | ||
{ | ||
struct skl_sst *ctx = skl->skl_sst; | ||
|
||
if (skl->resource.mcps + mconfig->mcps > skl->resource.max_mcps) { | ||
dev_err(ctx->dev, | ||
"%s: module_id %d instance %d\n", __func__, | ||
mconfig->id.module_id, mconfig->id.instance_id); | ||
dev_err(ctx->dev, | ||
"exceeds ppl memory available %d > mem %d\n", | ||
skl->resource.max_mcps, skl->resource.mcps); | ||
return false; | ||
} | ||
|
||
skl->resource.mcps += mconfig->mcps; | ||
return true; | ||
} | ||
|
||
/* | ||
* Free the mcps when tearing down | ||
*/ | ||
static void | ||
skl_tplg_free_pipe_mcps(struct skl *skl, struct skl_module_cfg *mconfig) | ||
{ | ||
skl->resource.mcps -= mconfig->mcps; | ||
} | ||
|
||
/* | ||
* Free the memory when tearing down | ||
*/ | ||
static void | ||
skl_tplg_free_pipe_mem(struct skl *skl, struct skl_module_cfg *mconfig) | ||
{ | ||
skl->resource.mem -= mconfig->pipe->memory_pages; | ||
} | ||
|
||
/* | ||
* A pipe can have multiple modules, each of them will be a DAPM widget as | ||
* well. While managing a pipeline we need to get the list of all the | ||
* widgets in a pipelines, so this helper - skl_tplg_get_pipe_widget() helps | ||
* to get the SKL type widgets in that pipeline | ||
*/ | ||
static int skl_tplg_alloc_pipe_widget(struct device *dev, | ||
struct snd_soc_dapm_widget *w, struct skl_pipe *pipe) | ||
{ | ||
struct skl_module_cfg *src_module = NULL; | ||
struct snd_soc_dapm_path *p = NULL; | ||
struct skl_pipe_module *p_module = NULL; | ||
|
||
p_module = devm_kzalloc(dev, sizeof(*p_module), GFP_KERNEL); | ||
if (!p_module) | ||
return -ENOMEM; | ||
|
||
p_module->w = w; | ||
list_add_tail(&p_module->node, &pipe->w_list); | ||
|
||
snd_soc_dapm_widget_for_each_sink_path(w, p) { | ||
if ((p->sink->priv == NULL) | ||
&& (!is_skl_dsp_widget_type(w))) | ||
continue; | ||
|
||
if ((p->sink->priv != NULL) && p->connect | ||
&& is_skl_dsp_widget_type(p->sink)) { | ||
|
||
src_module = p->sink->priv; | ||
if (pipe->ppl_id == src_module->pipe->ppl_id) | ||
skl_tplg_alloc_pipe_widget(dev, | ||
p->sink, pipe); | ||
} | ||
} | ||
return 0; | ||
} | ||
|
||
/* | ||
* Inside a pipe instance, we can have various modules. These modules need | ||
* to instantiated in DSP by invoking INIT_MODULE IPC, which is achieved by | ||
* skl_init_module() routine, so invoke that for all modules in a pipeline | ||
*/ | ||
static int | ||
skl_tplg_init_pipe_modules(struct skl *skl, struct skl_pipe *pipe) | ||
{ | ||
struct skl_pipe_module *w_module; | ||
struct snd_soc_dapm_widget *w; | ||
struct skl_module_cfg *mconfig; | ||
struct skl_sst *ctx = skl->skl_sst; | ||
int ret = 0; | ||
|
||
list_for_each_entry(w_module, &pipe->w_list, node) { | ||
w = w_module->w; | ||
mconfig = w->priv; | ||
|
||
/* check resource available */ | ||
if (!skl_tplg_alloc_pipe_mcps(skl, mconfig)) | ||
return -ENOMEM; | ||
|
||
ret = skl_init_module(ctx, mconfig, NULL); | ||
if (ret < 0) | ||
return ret; | ||
} | ||
|
||
return 0; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters