]> git.proxmox.com Git - mirror_ubuntu-eoan-kernel.git/blame - sound/soc/intel/skylake/skl-topology.c
ASoC: Intel: Skylake: Add module configuration helpers
[mirror_ubuntu-eoan-kernel.git] / sound / soc / intel / skylake / skl-topology.c
CommitLineData
e4e2d2f4
JK
1/*
2 * skl-topology.c - Implements Platform component ALSA controls/widget
3 * handlers.
4 *
5 * Copyright (C) 2014-2015 Intel Corp
6 * Author: Jeeja KP <jeeja.kp@intel.com>
7 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as version 2, as
11 * published by the Free Software Foundation.
12 *
13 * This program is distributed in the hope that it will be useful, but
14 * WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * General Public License for more details.
17 */
18
19#include <linux/slab.h>
20#include <linux/types.h>
21#include <linux/firmware.h>
22#include <sound/soc.h>
23#include <sound/soc-topology.h>
24#include "skl-sst-dsp.h"
25#include "skl-sst-ipc.h"
26#include "skl-topology.h"
27#include "skl.h"
28#include "skl-tplg-interface.h"
29
f7590d4f
JK
30#define SKL_CH_FIXUP_MASK (1 << 0)
31#define SKL_RATE_FIXUP_MASK (1 << 1)
32#define SKL_FMT_FIXUP_MASK (1 << 2)
33
e4e2d2f4
JK
34/*
35 * SKL DSP driver modelling uses only few DAPM widgets so for rest we will
36 * ignore. This helpers checks if the SKL driver handles this widget type
37 */
38static int is_skl_dsp_widget_type(struct snd_soc_dapm_widget *w)
39{
40 switch (w->id) {
41 case snd_soc_dapm_dai_link:
42 case snd_soc_dapm_dai_in:
43 case snd_soc_dapm_aif_in:
44 case snd_soc_dapm_aif_out:
45 case snd_soc_dapm_dai_out:
46 case snd_soc_dapm_switch:
47 return false;
48 default:
49 return true;
50 }
51}
52
53/*
54 * Each pipelines needs memory to be allocated. Check if we have free memory
55 * from available pool. Then only add this to pool
56 * This is freed when pipe is deleted
57 * Note: DSP does actual memory management we only keep track for complete
58 * pool
59 */
60static bool skl_tplg_alloc_pipe_mem(struct skl *skl,
61 struct skl_module_cfg *mconfig)
62{
63 struct skl_sst *ctx = skl->skl_sst;
64
65 if (skl->resource.mem + mconfig->pipe->memory_pages >
66 skl->resource.max_mem) {
67 dev_err(ctx->dev,
68 "%s: module_id %d instance %d\n", __func__,
69 mconfig->id.module_id,
70 mconfig->id.instance_id);
71 dev_err(ctx->dev,
72 "exceeds ppl memory available %d mem %d\n",
73 skl->resource.max_mem, skl->resource.mem);
74 return false;
75 }
76
77 skl->resource.mem += mconfig->pipe->memory_pages;
78 return true;
79}
80
81/*
82 * Pipeline needs needs DSP CPU resources for computation, this is
83 * quantified in MCPS (Million Clocks Per Second) required for module/pipe
84 *
85 * Each pipelines needs mcps to be allocated. Check if we have mcps for this
86 * pipe. This adds the mcps to driver counter
87 * This is removed on pipeline delete
88 */
89static bool skl_tplg_alloc_pipe_mcps(struct skl *skl,
90 struct skl_module_cfg *mconfig)
91{
92 struct skl_sst *ctx = skl->skl_sst;
93
94 if (skl->resource.mcps + mconfig->mcps > skl->resource.max_mcps) {
95 dev_err(ctx->dev,
96 "%s: module_id %d instance %d\n", __func__,
97 mconfig->id.module_id, mconfig->id.instance_id);
98 dev_err(ctx->dev,
99 "exceeds ppl memory available %d > mem %d\n",
100 skl->resource.max_mcps, skl->resource.mcps);
101 return false;
102 }
103
104 skl->resource.mcps += mconfig->mcps;
105 return true;
106}
107
108/*
109 * Free the mcps when tearing down
110 */
111static void
112skl_tplg_free_pipe_mcps(struct skl *skl, struct skl_module_cfg *mconfig)
113{
114 skl->resource.mcps -= mconfig->mcps;
115}
116
117/*
118 * Free the memory when tearing down
119 */
120static void
121skl_tplg_free_pipe_mem(struct skl *skl, struct skl_module_cfg *mconfig)
122{
123 skl->resource.mem -= mconfig->pipe->memory_pages;
124}
125
f7590d4f
JK
126
127static void skl_dump_mconfig(struct skl_sst *ctx,
128 struct skl_module_cfg *mcfg)
129{
130 dev_dbg(ctx->dev, "Dumping config\n");
131 dev_dbg(ctx->dev, "Input Format:\n");
132 dev_dbg(ctx->dev, "channels = %d\n", mcfg->in_fmt.channels);
133 dev_dbg(ctx->dev, "s_freq = %d\n", mcfg->in_fmt.s_freq);
134 dev_dbg(ctx->dev, "ch_cfg = %d\n", mcfg->in_fmt.ch_cfg);
135 dev_dbg(ctx->dev, "valid bit depth = %d\n",
136 mcfg->in_fmt.valid_bit_depth);
137 dev_dbg(ctx->dev, "Output Format:\n");
138 dev_dbg(ctx->dev, "channels = %d\n", mcfg->out_fmt.channels);
139 dev_dbg(ctx->dev, "s_freq = %d\n", mcfg->out_fmt.s_freq);
140 dev_dbg(ctx->dev, "valid bit depth = %d\n",
141 mcfg->out_fmt.valid_bit_depth);
142 dev_dbg(ctx->dev, "ch_cfg = %d\n", mcfg->out_fmt.ch_cfg);
143}
144
145static void skl_tplg_update_params(struct skl_module_fmt *fmt,
146 struct skl_pipe_params *params, int fixup)
147{
148 if (fixup & SKL_RATE_FIXUP_MASK)
149 fmt->s_freq = params->s_freq;
150 if (fixup & SKL_CH_FIXUP_MASK)
151 fmt->channels = params->ch;
152 if (fixup & SKL_FMT_FIXUP_MASK)
153 fmt->valid_bit_depth = params->s_fmt;
154}
155
156/*
157 * A pipeline may have modules which impact the pcm parameters, like SRC,
158 * channel converter, format converter.
159 * We need to calculate the output params by applying the 'fixup'
160 * Topology will tell driver which type of fixup is to be applied by
161 * supplying the fixup mask, so based on that we calculate the output
162 *
163 * Now In FE the pcm hw_params is source/target format. Same is applicable
164 * for BE with its hw_params invoked.
165 * here based on FE, BE pipeline and direction we calculate the input and
166 * outfix and then apply that for a module
167 */
168static void skl_tplg_update_params_fixup(struct skl_module_cfg *m_cfg,
169 struct skl_pipe_params *params, bool is_fe)
170{
171 int in_fixup, out_fixup;
172 struct skl_module_fmt *in_fmt, *out_fmt;
173
174 in_fmt = &m_cfg->in_fmt;
175 out_fmt = &m_cfg->out_fmt;
176
177 if (params->stream == SNDRV_PCM_STREAM_PLAYBACK) {
178 if (is_fe) {
179 in_fixup = m_cfg->params_fixup;
180 out_fixup = (~m_cfg->converter) &
181 m_cfg->params_fixup;
182 } else {
183 out_fixup = m_cfg->params_fixup;
184 in_fixup = (~m_cfg->converter) &
185 m_cfg->params_fixup;
186 }
187 } else {
188 if (is_fe) {
189 out_fixup = m_cfg->params_fixup;
190 in_fixup = (~m_cfg->converter) &
191 m_cfg->params_fixup;
192 } else {
193 in_fixup = m_cfg->params_fixup;
194 out_fixup = (~m_cfg->converter) &
195 m_cfg->params_fixup;
196 }
197 }
198
199 skl_tplg_update_params(in_fmt, params, in_fixup);
200 skl_tplg_update_params(out_fmt, params, out_fixup);
201}
202
203/*
204 * A module needs input and output buffers, which are dependent upon pcm
205 * params, so once we have calculate params, we need buffer calculation as
206 * well.
207 */
208static void skl_tplg_update_buffer_size(struct skl_sst *ctx,
209 struct skl_module_cfg *mcfg)
210{
211 int multiplier = 1;
212
213 if (mcfg->m_type == SKL_MODULE_TYPE_SRCINT)
214 multiplier = 5;
215
216 mcfg->ibs = (mcfg->in_fmt.s_freq / 1000) *
217 (mcfg->in_fmt.channels) *
218 (mcfg->in_fmt.bit_depth >> 3) *
219 multiplier;
220
221 mcfg->obs = (mcfg->out_fmt.s_freq / 1000) *
222 (mcfg->out_fmt.channels) *
223 (mcfg->out_fmt.bit_depth >> 3) *
224 multiplier;
225}
226
227static void skl_tplg_update_module_params(struct snd_soc_dapm_widget *w,
228 struct skl_sst *ctx)
229{
230 struct skl_module_cfg *m_cfg = w->priv;
231 struct skl_pipe_params *params = m_cfg->pipe->p_params;
232 int p_conn_type = m_cfg->pipe->conn_type;
233 bool is_fe;
234
235 if (!m_cfg->params_fixup)
236 return;
237
238 dev_dbg(ctx->dev, "Mconfig for widget=%s BEFORE updation\n",
239 w->name);
240
241 skl_dump_mconfig(ctx, m_cfg);
242
243 if (p_conn_type == SKL_PIPE_CONN_TYPE_FE)
244 is_fe = true;
245 else
246 is_fe = false;
247
248 skl_tplg_update_params_fixup(m_cfg, params, is_fe);
249 skl_tplg_update_buffer_size(ctx, m_cfg);
250
251 dev_dbg(ctx->dev, "Mconfig for widget=%s AFTER updation\n",
252 w->name);
253
254 skl_dump_mconfig(ctx, m_cfg);
255}
256
e4e2d2f4
JK
257/*
258 * A pipe can have multiple modules, each of them will be a DAPM widget as
259 * well. While managing a pipeline we need to get the list of all the
260 * widgets in a pipelines, so this helper - skl_tplg_get_pipe_widget() helps
261 * to get the SKL type widgets in that pipeline
262 */
263static int skl_tplg_alloc_pipe_widget(struct device *dev,
264 struct snd_soc_dapm_widget *w, struct skl_pipe *pipe)
265{
266 struct skl_module_cfg *src_module = NULL;
267 struct snd_soc_dapm_path *p = NULL;
268 struct skl_pipe_module *p_module = NULL;
269
270 p_module = devm_kzalloc(dev, sizeof(*p_module), GFP_KERNEL);
271 if (!p_module)
272 return -ENOMEM;
273
274 p_module->w = w;
275 list_add_tail(&p_module->node, &pipe->w_list);
276
277 snd_soc_dapm_widget_for_each_sink_path(w, p) {
278 if ((p->sink->priv == NULL)
279 && (!is_skl_dsp_widget_type(w)))
280 continue;
281
282 if ((p->sink->priv != NULL) && p->connect
283 && is_skl_dsp_widget_type(p->sink)) {
284
285 src_module = p->sink->priv;
286 if (pipe->ppl_id == src_module->pipe->ppl_id)
287 skl_tplg_alloc_pipe_widget(dev,
288 p->sink, pipe);
289 }
290 }
291 return 0;
292}
293
294/*
295 * Inside a pipe instance, we can have various modules. These modules need
296 * to instantiated in DSP by invoking INIT_MODULE IPC, which is achieved by
297 * skl_init_module() routine, so invoke that for all modules in a pipeline
298 */
299static int
300skl_tplg_init_pipe_modules(struct skl *skl, struct skl_pipe *pipe)
301{
302 struct skl_pipe_module *w_module;
303 struct snd_soc_dapm_widget *w;
304 struct skl_module_cfg *mconfig;
305 struct skl_sst *ctx = skl->skl_sst;
306 int ret = 0;
307
308 list_for_each_entry(w_module, &pipe->w_list, node) {
309 w = w_module->w;
310 mconfig = w->priv;
311
312 /* check resource available */
313 if (!skl_tplg_alloc_pipe_mcps(skl, mconfig))
314 return -ENOMEM;
315
f7590d4f
JK
316 /*
317 * apply fix/conversion to module params based on
318 * FE/BE params
319 */
320 skl_tplg_update_module_params(w, ctx);
e4e2d2f4
JK
321 ret = skl_init_module(ctx, mconfig, NULL);
322 if (ret < 0)
323 return ret;
324 }
325
326 return 0;
327}