147d7195dSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
2e4e2d2f4SJeeja KP /*
3e4e2d2f4SJeeja KP * skl-topology.c - Implements Platform component ALSA controls/widget
4e4e2d2f4SJeeja KP * handlers.
5e4e2d2f4SJeeja KP *
6e4e2d2f4SJeeja KP * Copyright (C) 2014-2015 Intel Corp
7e4e2d2f4SJeeja KP * Author: Jeeja KP <jeeja.kp@intel.com>
8e4e2d2f4SJeeja KP * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
9e4e2d2f4SJeeja KP */
10e4e2d2f4SJeeja KP
11e4e2d2f4SJeeja KP #include <linux/slab.h>
12e4e2d2f4SJeeja KP #include <linux/types.h>
13e4e2d2f4SJeeja KP #include <linux/firmware.h>
14ac9391daSGuenter Roeck #include <linux/uuid.h>
1563643b59SPierre-Louis Bossart #include <sound/intel-nhlt.h>
16e4e2d2f4SJeeja KP #include <sound/soc.h>
171b290ef0SMateusz Gorski #include <sound/soc-acpi.h>
18e4e2d2f4SJeeja KP #include <sound/soc-topology.h>
196277e832SShreyas NC #include <uapi/sound/snd_sst_tokens.h>
200c24fdc0SGuenter Roeck #include <uapi/sound/skl-tplg-interface.h>
21e4e2d2f4SJeeja KP #include "skl-sst-dsp.h"
22e4e2d2f4SJeeja KP #include "skl-sst-ipc.h"
23e4e2d2f4SJeeja KP #include "skl-topology.h"
24e4e2d2f4SJeeja KP #include "skl.h"
256c5768b3SDharageswari R #include "../common/sst-dsp.h"
266c5768b3SDharageswari R #include "../common/sst-dsp-priv.h"
27e4e2d2f4SJeeja KP
28f7590d4fSJeeja KP #define SKL_CH_FIXUP_MASK (1 << 0)
29f7590d4fSJeeja KP #define SKL_RATE_FIXUP_MASK (1 << 1)
30f7590d4fSJeeja KP #define SKL_FMT_FIXUP_MASK (1 << 2)
316277e832SShreyas NC #define SKL_IN_DIR_BIT_MASK BIT(0)
326277e832SShreyas NC #define SKL_PIN_COUNT_MASK GENMASK(7, 4)
33f7590d4fSJeeja KP
347a1b749bSDharageswari R static const int mic_mono_list[] = {
357a1b749bSDharageswari R 0, 1, 2, 3,
367a1b749bSDharageswari R };
377a1b749bSDharageswari R static const int mic_stereo_list[][SKL_CH_STEREO] = {
387a1b749bSDharageswari R {0, 1}, {0, 2}, {0, 3}, {1, 2}, {1, 3}, {2, 3},
397a1b749bSDharageswari R };
407a1b749bSDharageswari R static const int mic_trio_list[][SKL_CH_TRIO] = {
417a1b749bSDharageswari R {0, 1, 2}, {0, 1, 3}, {0, 2, 3}, {1, 2, 3},
427a1b749bSDharageswari R };
437a1b749bSDharageswari R static const int mic_quatro_list[][SKL_CH_QUATRO] = {
447a1b749bSDharageswari R {0, 1, 2, 3},
457a1b749bSDharageswari R };
467a1b749bSDharageswari R
47f6fa56e2SRamesh Babu #define CHECK_HW_PARAMS(ch, freq, bps, prm_ch, prm_freq, prm_bps) \
48f6fa56e2SRamesh Babu ((ch == prm_ch) && (bps == prm_bps) && (freq == prm_freq))
49f6fa56e2SRamesh Babu
skl_tplg_d0i3_get(struct skl_dev * skl,enum d0i3_capability caps)50bcc2a2dcSCezary Rojewski void skl_tplg_d0i3_get(struct skl_dev *skl, enum d0i3_capability caps)
51a83e3b4cSVinod Koul {
52bcc2a2dcSCezary Rojewski struct skl_d0i3_data *d0i3 = &skl->d0i3;
53a83e3b4cSVinod Koul
54a83e3b4cSVinod Koul switch (caps) {
55a83e3b4cSVinod Koul case SKL_D0I3_NONE:
56a83e3b4cSVinod Koul d0i3->non_d0i3++;
57a83e3b4cSVinod Koul break;
58a83e3b4cSVinod Koul
59a83e3b4cSVinod Koul case SKL_D0I3_STREAMING:
60a83e3b4cSVinod Koul d0i3->streaming++;
61a83e3b4cSVinod Koul break;
62a83e3b4cSVinod Koul
63a83e3b4cSVinod Koul case SKL_D0I3_NON_STREAMING:
64a83e3b4cSVinod Koul d0i3->non_streaming++;
65a83e3b4cSVinod Koul break;
66a83e3b4cSVinod Koul }
67a83e3b4cSVinod Koul }
68a83e3b4cSVinod Koul
skl_tplg_d0i3_put(struct skl_dev * skl,enum d0i3_capability caps)69bcc2a2dcSCezary Rojewski void skl_tplg_d0i3_put(struct skl_dev *skl, enum d0i3_capability caps)
70a83e3b4cSVinod Koul {
71bcc2a2dcSCezary Rojewski struct skl_d0i3_data *d0i3 = &skl->d0i3;
72a83e3b4cSVinod Koul
73a83e3b4cSVinod Koul switch (caps) {
74a83e3b4cSVinod Koul case SKL_D0I3_NONE:
75a83e3b4cSVinod Koul d0i3->non_d0i3--;
76a83e3b4cSVinod Koul break;
77a83e3b4cSVinod Koul
78a83e3b4cSVinod Koul case SKL_D0I3_STREAMING:
79a83e3b4cSVinod Koul d0i3->streaming--;
80a83e3b4cSVinod Koul break;
81a83e3b4cSVinod Koul
82a83e3b4cSVinod Koul case SKL_D0I3_NON_STREAMING:
83a83e3b4cSVinod Koul d0i3->non_streaming--;
84a83e3b4cSVinod Koul break;
85a83e3b4cSVinod Koul }
86a83e3b4cSVinod Koul }
87a83e3b4cSVinod Koul
88e4e2d2f4SJeeja KP /*
89e4e2d2f4SJeeja KP * SKL DSP driver modelling uses only few DAPM widgets so for rest we will
90e4e2d2f4SJeeja KP * ignore. This helpers checks if the SKL driver handles this widget type
91e4e2d2f4SJeeja KP */
is_skl_dsp_widget_type(struct snd_soc_dapm_widget * w,struct device * dev)92cb1f904dSGuneshwor Singh static int is_skl_dsp_widget_type(struct snd_soc_dapm_widget *w,
93cb1f904dSGuneshwor Singh struct device *dev)
94e4e2d2f4SJeeja KP {
95cb1f904dSGuneshwor Singh if (w->dapm->dev != dev)
96cb1f904dSGuneshwor Singh return false;
97cb1f904dSGuneshwor Singh
98e4e2d2f4SJeeja KP switch (w->id) {
99e4e2d2f4SJeeja KP case snd_soc_dapm_dai_link:
100e4e2d2f4SJeeja KP case snd_soc_dapm_dai_in:
101e4e2d2f4SJeeja KP case snd_soc_dapm_aif_in:
102e4e2d2f4SJeeja KP case snd_soc_dapm_aif_out:
103e4e2d2f4SJeeja KP case snd_soc_dapm_dai_out:
104e4e2d2f4SJeeja KP case snd_soc_dapm_switch:
105fe65324eSRakesh Ughreja case snd_soc_dapm_output:
106fe65324eSRakesh Ughreja case snd_soc_dapm_mux:
107fe65324eSRakesh Ughreja
108e4e2d2f4SJeeja KP return false;
109e4e2d2f4SJeeja KP default:
110e4e2d2f4SJeeja KP return true;
111e4e2d2f4SJeeja KP }
112e4e2d2f4SJeeja KP }
113e4e2d2f4SJeeja KP
skl_dump_mconfig(struct skl_dev * skl,struct skl_module_cfg * mcfg)114bcc2a2dcSCezary Rojewski static void skl_dump_mconfig(struct skl_dev *skl, struct skl_module_cfg *mcfg)
115f7590d4fSJeeja KP {
116e8b374b6SCezary Rojewski struct skl_module_iface *iface = &mcfg->module->formats[mcfg->fmt_idx];
117f6fa56e2SRamesh Babu
118bcc2a2dcSCezary Rojewski dev_dbg(skl->dev, "Dumping config\n");
119bcc2a2dcSCezary Rojewski dev_dbg(skl->dev, "Input Format:\n");
120bcc2a2dcSCezary Rojewski dev_dbg(skl->dev, "channels = %d\n", iface->inputs[0].fmt.channels);
121bcc2a2dcSCezary Rojewski dev_dbg(skl->dev, "s_freq = %d\n", iface->inputs[0].fmt.s_freq);
122bcc2a2dcSCezary Rojewski dev_dbg(skl->dev, "ch_cfg = %d\n", iface->inputs[0].fmt.ch_cfg);
123bcc2a2dcSCezary Rojewski dev_dbg(skl->dev, "valid bit depth = %d\n",
124f6fa56e2SRamesh Babu iface->inputs[0].fmt.valid_bit_depth);
125bcc2a2dcSCezary Rojewski dev_dbg(skl->dev, "Output Format:\n");
126bcc2a2dcSCezary Rojewski dev_dbg(skl->dev, "channels = %d\n", iface->outputs[0].fmt.channels);
127bcc2a2dcSCezary Rojewski dev_dbg(skl->dev, "s_freq = %d\n", iface->outputs[0].fmt.s_freq);
128bcc2a2dcSCezary Rojewski dev_dbg(skl->dev, "valid bit depth = %d\n",
129f6fa56e2SRamesh Babu iface->outputs[0].fmt.valid_bit_depth);
130bcc2a2dcSCezary Rojewski dev_dbg(skl->dev, "ch_cfg = %d\n", iface->outputs[0].fmt.ch_cfg);
131f7590d4fSJeeja KP }
132f7590d4fSJeeja KP
skl_tplg_update_chmap(struct skl_module_fmt * fmt,int chs)133ea5a137dSSubhransu S. Prusty static void skl_tplg_update_chmap(struct skl_module_fmt *fmt, int chs)
134ea5a137dSSubhransu S. Prusty {
135ea5a137dSSubhransu S. Prusty int slot_map = 0xFFFFFFFF;
136ea5a137dSSubhransu S. Prusty int start_slot = 0;
137ea5a137dSSubhransu S. Prusty int i;
138ea5a137dSSubhransu S. Prusty
139ea5a137dSSubhransu S. Prusty for (i = 0; i < chs; i++) {
140ea5a137dSSubhransu S. Prusty /*
141ea5a137dSSubhransu S. Prusty * For 2 channels with starting slot as 0, slot map will
142ea5a137dSSubhransu S. Prusty * look like 0xFFFFFF10.
143ea5a137dSSubhransu S. Prusty */
144ea5a137dSSubhransu S. Prusty slot_map &= (~(0xF << (4 * i)) | (start_slot << (4 * i)));
145ea5a137dSSubhransu S. Prusty start_slot++;
146ea5a137dSSubhransu S. Prusty }
147ea5a137dSSubhransu S. Prusty fmt->ch_map = slot_map;
148ea5a137dSSubhransu S. Prusty }
149ea5a137dSSubhransu S. Prusty
skl_tplg_update_params(struct skl_module_fmt * fmt,struct skl_pipe_params * params,int fixup)150f7590d4fSJeeja KP static void skl_tplg_update_params(struct skl_module_fmt *fmt,
151f7590d4fSJeeja KP struct skl_pipe_params *params, int fixup)
152f7590d4fSJeeja KP {
153f7590d4fSJeeja KP if (fixup & SKL_RATE_FIXUP_MASK)
154f7590d4fSJeeja KP fmt->s_freq = params->s_freq;
155ea5a137dSSubhransu S. Prusty if (fixup & SKL_CH_FIXUP_MASK) {
156f7590d4fSJeeja KP fmt->channels = params->ch;
157ea5a137dSSubhransu S. Prusty skl_tplg_update_chmap(fmt, fmt->channels);
158ea5a137dSSubhransu S. Prusty }
15998256f83SJeeja KP if (fixup & SKL_FMT_FIXUP_MASK) {
16098256f83SJeeja KP fmt->valid_bit_depth = skl_get_bit_depth(params->s_fmt);
16198256f83SJeeja KP
16298256f83SJeeja KP /*
16398256f83SJeeja KP * 16 bit is 16 bit container whereas 24 bit is in 32 bit
16498256f83SJeeja KP * container so update bit depth accordingly
16598256f83SJeeja KP */
16698256f83SJeeja KP switch (fmt->valid_bit_depth) {
16798256f83SJeeja KP case SKL_DEPTH_16BIT:
16898256f83SJeeja KP fmt->bit_depth = fmt->valid_bit_depth;
16998256f83SJeeja KP break;
17098256f83SJeeja KP
17198256f83SJeeja KP default:
17298256f83SJeeja KP fmt->bit_depth = SKL_DEPTH_32BIT;
17398256f83SJeeja KP break;
17498256f83SJeeja KP }
17598256f83SJeeja KP }
17698256f83SJeeja KP
177f7590d4fSJeeja KP }
178f7590d4fSJeeja KP
179f7590d4fSJeeja KP /*
180f7590d4fSJeeja KP * A pipeline may have modules which impact the pcm parameters, like SRC,
181f7590d4fSJeeja KP * channel converter, format converter.
182f7590d4fSJeeja KP * We need to calculate the output params by applying the 'fixup'
183f7590d4fSJeeja KP * Topology will tell driver which type of fixup is to be applied by
184f7590d4fSJeeja KP * supplying the fixup mask, so based on that we calculate the output
185f7590d4fSJeeja KP *
186f7590d4fSJeeja KP * Now In FE the pcm hw_params is source/target format. Same is applicable
187f7590d4fSJeeja KP * for BE with its hw_params invoked.
188f7590d4fSJeeja KP * here based on FE, BE pipeline and direction we calculate the input and
189f7590d4fSJeeja KP * outfix and then apply that for a module
190f7590d4fSJeeja KP */
skl_tplg_update_params_fixup(struct skl_module_cfg * m_cfg,struct skl_pipe_params * params,bool is_fe)191f7590d4fSJeeja KP static void skl_tplg_update_params_fixup(struct skl_module_cfg *m_cfg,
192f7590d4fSJeeja KP struct skl_pipe_params *params, bool is_fe)
193f7590d4fSJeeja KP {
194f7590d4fSJeeja KP int in_fixup, out_fixup;
195f7590d4fSJeeja KP struct skl_module_fmt *in_fmt, *out_fmt;
196f7590d4fSJeeja KP
1974cd9899fSHardik T Shah /* Fixups will be applied to pin 0 only */
198e8b374b6SCezary Rojewski in_fmt = &m_cfg->module->formats[m_cfg->fmt_idx].inputs[0].fmt;
199e8b374b6SCezary Rojewski out_fmt = &m_cfg->module->formats[m_cfg->fmt_idx].outputs[0].fmt;
200f7590d4fSJeeja KP
201f7590d4fSJeeja KP if (params->stream == SNDRV_PCM_STREAM_PLAYBACK) {
202f7590d4fSJeeja KP if (is_fe) {
203f7590d4fSJeeja KP in_fixup = m_cfg->params_fixup;
204f7590d4fSJeeja KP out_fixup = (~m_cfg->converter) &
205f7590d4fSJeeja KP m_cfg->params_fixup;
206f7590d4fSJeeja KP } else {
207f7590d4fSJeeja KP out_fixup = m_cfg->params_fixup;
208f7590d4fSJeeja KP in_fixup = (~m_cfg->converter) &
209f7590d4fSJeeja KP m_cfg->params_fixup;
210f7590d4fSJeeja KP }
211f7590d4fSJeeja KP } else {
212f7590d4fSJeeja KP if (is_fe) {
213f7590d4fSJeeja KP out_fixup = m_cfg->params_fixup;
214f7590d4fSJeeja KP in_fixup = (~m_cfg->converter) &
215f7590d4fSJeeja KP m_cfg->params_fixup;
216f7590d4fSJeeja KP } else {
217f7590d4fSJeeja KP in_fixup = m_cfg->params_fixup;
218f7590d4fSJeeja KP out_fixup = (~m_cfg->converter) &
219f7590d4fSJeeja KP m_cfg->params_fixup;
220f7590d4fSJeeja KP }
221f7590d4fSJeeja KP }
222f7590d4fSJeeja KP
223f7590d4fSJeeja KP skl_tplg_update_params(in_fmt, params, in_fixup);
224f7590d4fSJeeja KP skl_tplg_update_params(out_fmt, params, out_fixup);
225f7590d4fSJeeja KP }
226f7590d4fSJeeja KP
227f7590d4fSJeeja KP /*
228f7590d4fSJeeja KP * A module needs input and output buffers, which are dependent upon pcm
229f7590d4fSJeeja KP * params, so once we have calculate params, we need buffer calculation as
230f7590d4fSJeeja KP * well.
231f7590d4fSJeeja KP */
skl_tplg_update_buffer_size(struct skl_dev * skl,struct skl_module_cfg * mcfg)232bcc2a2dcSCezary Rojewski static void skl_tplg_update_buffer_size(struct skl_dev *skl,
233f7590d4fSJeeja KP struct skl_module_cfg *mcfg)
234f7590d4fSJeeja KP {
235f7590d4fSJeeja KP int multiplier = 1;
2364cd9899fSHardik T Shah struct skl_module_fmt *in_fmt, *out_fmt;
237f6fa56e2SRamesh Babu struct skl_module_res *res;
2384cd9899fSHardik T Shah
2394cd9899fSHardik T Shah /* Since fixups is applied to pin 0 only, ibs, obs needs
2404cd9899fSHardik T Shah * change for pin 0 only
2414cd9899fSHardik T Shah */
242e8b374b6SCezary Rojewski res = &mcfg->module->resources[mcfg->res_idx];
243e8b374b6SCezary Rojewski in_fmt = &mcfg->module->formats[mcfg->fmt_idx].inputs[0].fmt;
244e8b374b6SCezary Rojewski out_fmt = &mcfg->module->formats[mcfg->fmt_idx].outputs[0].fmt;
245f7590d4fSJeeja KP
246f7590d4fSJeeja KP if (mcfg->m_type == SKL_MODULE_TYPE_SRCINT)
247f7590d4fSJeeja KP multiplier = 5;
248f0c8e1d9SSubhransu S. Prusty
249f6fa56e2SRamesh Babu res->ibs = DIV_ROUND_UP(in_fmt->s_freq, 1000) *
250998d6fb5STakashi Sakamoto in_fmt->channels * (in_fmt->bit_depth >> 3) *
251f7590d4fSJeeja KP multiplier;
252f7590d4fSJeeja KP
253f6fa56e2SRamesh Babu res->obs = DIV_ROUND_UP(out_fmt->s_freq, 1000) *
254998d6fb5STakashi Sakamoto out_fmt->channels * (out_fmt->bit_depth >> 3) *
255f7590d4fSJeeja KP multiplier;
256f7590d4fSJeeja KP }
257f7590d4fSJeeja KP
skl_tplg_be_dev_type(int dev_type)258db2f586bSSenthilnathan Veppur static u8 skl_tplg_be_dev_type(int dev_type)
259db2f586bSSenthilnathan Veppur {
260db2f586bSSenthilnathan Veppur int ret;
261db2f586bSSenthilnathan Veppur
262db2f586bSSenthilnathan Veppur switch (dev_type) {
263db2f586bSSenthilnathan Veppur case SKL_DEVICE_BT:
264db2f586bSSenthilnathan Veppur ret = NHLT_DEVICE_BT;
265db2f586bSSenthilnathan Veppur break;
266db2f586bSSenthilnathan Veppur
267db2f586bSSenthilnathan Veppur case SKL_DEVICE_DMIC:
268db2f586bSSenthilnathan Veppur ret = NHLT_DEVICE_DMIC;
269db2f586bSSenthilnathan Veppur break;
270db2f586bSSenthilnathan Veppur
271db2f586bSSenthilnathan Veppur case SKL_DEVICE_I2S:
272db2f586bSSenthilnathan Veppur ret = NHLT_DEVICE_I2S;
273db2f586bSSenthilnathan Veppur break;
274db2f586bSSenthilnathan Veppur
275db2f586bSSenthilnathan Veppur default:
276db2f586bSSenthilnathan Veppur ret = NHLT_DEVICE_INVALID;
277db2f586bSSenthilnathan Veppur break;
278db2f586bSSenthilnathan Veppur }
279db2f586bSSenthilnathan Veppur
280db2f586bSSenthilnathan Veppur return ret;
281db2f586bSSenthilnathan Veppur }
282db2f586bSSenthilnathan Veppur
skl_tplg_update_be_blob(struct snd_soc_dapm_widget * w,struct skl_dev * skl)2832d1419a3SJeeja KP static int skl_tplg_update_be_blob(struct snd_soc_dapm_widget *w,
284bcc2a2dcSCezary Rojewski struct skl_dev *skl)
2852d1419a3SJeeja KP {
2862d1419a3SJeeja KP struct skl_module_cfg *m_cfg = w->priv;
2872d1419a3SJeeja KP int link_type, dir;
288322fa431SAmadeusz Sławiński u32 ch, s_freq, s_fmt, s_cont;
2892d1419a3SJeeja KP struct nhlt_specific_cfg *cfg;
290db2f586bSSenthilnathan Veppur u8 dev_type = skl_tplg_be_dev_type(m_cfg->dev_type);
291f6fa56e2SRamesh Babu int fmt_idx = m_cfg->fmt_idx;
292f6fa56e2SRamesh Babu struct skl_module_iface *m_iface = &m_cfg->module->formats[fmt_idx];
2932d1419a3SJeeja KP
2942d1419a3SJeeja KP /* check if we already have blob */
295a4ad42d2SKareem Shaik if (m_cfg->formats_config[SKL_PARAM_INIT].caps_size > 0)
2962d1419a3SJeeja KP return 0;
2972d1419a3SJeeja KP
298bcc2a2dcSCezary Rojewski dev_dbg(skl->dev, "Applying default cfg blob\n");
2992d1419a3SJeeja KP switch (m_cfg->dev_type) {
3002d1419a3SJeeja KP case SKL_DEVICE_DMIC:
3012d1419a3SJeeja KP link_type = NHLT_LINK_DMIC;
302c7c6c736SJeeja KP dir = SNDRV_PCM_STREAM_CAPTURE;
303f6fa56e2SRamesh Babu s_freq = m_iface->inputs[0].fmt.s_freq;
304322fa431SAmadeusz Sławiński s_fmt = m_iface->inputs[0].fmt.valid_bit_depth;
305322fa431SAmadeusz Sławiński s_cont = m_iface->inputs[0].fmt.bit_depth;
306f6fa56e2SRamesh Babu ch = m_iface->inputs[0].fmt.channels;
3072d1419a3SJeeja KP break;
3082d1419a3SJeeja KP
3092d1419a3SJeeja KP case SKL_DEVICE_I2S:
3102d1419a3SJeeja KP link_type = NHLT_LINK_SSP;
3112d1419a3SJeeja KP if (m_cfg->hw_conn_type == SKL_CONN_SOURCE) {
312c7c6c736SJeeja KP dir = SNDRV_PCM_STREAM_PLAYBACK;
313f6fa56e2SRamesh Babu s_freq = m_iface->outputs[0].fmt.s_freq;
314322fa431SAmadeusz Sławiński s_fmt = m_iface->outputs[0].fmt.valid_bit_depth;
315322fa431SAmadeusz Sławiński s_cont = m_iface->outputs[0].fmt.bit_depth;
316f6fa56e2SRamesh Babu ch = m_iface->outputs[0].fmt.channels;
317c7c6c736SJeeja KP } else {
318c7c6c736SJeeja KP dir = SNDRV_PCM_STREAM_CAPTURE;
319f6fa56e2SRamesh Babu s_freq = m_iface->inputs[0].fmt.s_freq;
320322fa431SAmadeusz Sławiński s_fmt = m_iface->inputs[0].fmt.valid_bit_depth;
321322fa431SAmadeusz Sławiński s_cont = m_iface->inputs[0].fmt.bit_depth;
322f6fa56e2SRamesh Babu ch = m_iface->inputs[0].fmt.channels;
3232d1419a3SJeeja KP }
3242d1419a3SJeeja KP break;
3252d1419a3SJeeja KP
3262d1419a3SJeeja KP default:
3272d1419a3SJeeja KP return -EINVAL;
3282d1419a3SJeeja KP }
3292d1419a3SJeeja KP
3302d1419a3SJeeja KP /* update the blob based on virtual bus_id and default params */
331322fa431SAmadeusz Sławiński cfg = intel_nhlt_get_endpoint_blob(skl->dev, skl->nhlt, m_cfg->vbus_id,
332322fa431SAmadeusz Sławiński link_type, s_fmt, s_cont, ch,
333322fa431SAmadeusz Sławiński s_freq, dir, dev_type);
3342d1419a3SJeeja KP if (cfg) {
335a4ad42d2SKareem Shaik m_cfg->formats_config[SKL_PARAM_INIT].caps_size = cfg->size;
336a4ad42d2SKareem Shaik m_cfg->formats_config[SKL_PARAM_INIT].caps = (u32 *)&cfg->caps;
3372d1419a3SJeeja KP } else {
338bcc2a2dcSCezary Rojewski dev_err(skl->dev, "Blob NULL for id %x type %d dirn %d\n",
3392d1419a3SJeeja KP m_cfg->vbus_id, link_type, dir);
340322fa431SAmadeusz Sławiński dev_err(skl->dev, "PCM: ch %d, freq %d, fmt %d/%d\n",
341322fa431SAmadeusz Sławiński ch, s_freq, s_fmt, s_cont);
3422d1419a3SJeeja KP return -EIO;
3432d1419a3SJeeja KP }
3442d1419a3SJeeja KP
3452d1419a3SJeeja KP return 0;
3462d1419a3SJeeja KP }
3472d1419a3SJeeja KP
skl_tplg_update_module_params(struct snd_soc_dapm_widget * w,struct skl_dev * skl)348f7590d4fSJeeja KP static void skl_tplg_update_module_params(struct snd_soc_dapm_widget *w,
349bcc2a2dcSCezary Rojewski struct skl_dev *skl)
350f7590d4fSJeeja KP {
351f7590d4fSJeeja KP struct skl_module_cfg *m_cfg = w->priv;
352f7590d4fSJeeja KP struct skl_pipe_params *params = m_cfg->pipe->p_params;
353f7590d4fSJeeja KP int p_conn_type = m_cfg->pipe->conn_type;
354f7590d4fSJeeja KP bool is_fe;
355f7590d4fSJeeja KP
356f7590d4fSJeeja KP if (!m_cfg->params_fixup)
357f7590d4fSJeeja KP return;
358f7590d4fSJeeja KP
359bcc2a2dcSCezary Rojewski dev_dbg(skl->dev, "Mconfig for widget=%s BEFORE updation\n",
360f7590d4fSJeeja KP w->name);
361f7590d4fSJeeja KP
362bcc2a2dcSCezary Rojewski skl_dump_mconfig(skl, m_cfg);
363f7590d4fSJeeja KP
364f7590d4fSJeeja KP if (p_conn_type == SKL_PIPE_CONN_TYPE_FE)
365f7590d4fSJeeja KP is_fe = true;
366f7590d4fSJeeja KP else
367f7590d4fSJeeja KP is_fe = false;
368f7590d4fSJeeja KP
369f7590d4fSJeeja KP skl_tplg_update_params_fixup(m_cfg, params, is_fe);
370bcc2a2dcSCezary Rojewski skl_tplg_update_buffer_size(skl, m_cfg);
371f7590d4fSJeeja KP
372bcc2a2dcSCezary Rojewski dev_dbg(skl->dev, "Mconfig for widget=%s AFTER updation\n",
373f7590d4fSJeeja KP w->name);
374f7590d4fSJeeja KP
375bcc2a2dcSCezary Rojewski skl_dump_mconfig(skl, m_cfg);
376f7590d4fSJeeja KP }
377f7590d4fSJeeja KP
378e4e2d2f4SJeeja KP /*
379abb74003SJeeja KP * some modules can have multiple params set from user control and
380abb74003SJeeja KP * need to be set after module is initialized. If set_param flag is
381abb74003SJeeja KP * set module params will be done after module is initialised.
382abb74003SJeeja KP */
skl_tplg_set_module_params(struct snd_soc_dapm_widget * w,struct skl_dev * skl)383abb74003SJeeja KP static int skl_tplg_set_module_params(struct snd_soc_dapm_widget *w,
384bcc2a2dcSCezary Rojewski struct skl_dev *skl)
385abb74003SJeeja KP {
386abb74003SJeeja KP int i, ret;
387abb74003SJeeja KP struct skl_module_cfg *mconfig = w->priv;
388abb74003SJeeja KP const struct snd_kcontrol_new *k;
389abb74003SJeeja KP struct soc_bytes_ext *sb;
390abb74003SJeeja KP struct skl_algo_data *bc;
391abb74003SJeeja KP struct skl_specific_cfg *sp_cfg;
392abb74003SJeeja KP
393a4ad42d2SKareem Shaik if (mconfig->formats_config[SKL_PARAM_SET].caps_size > 0 &&
394a4ad42d2SKareem Shaik mconfig->formats_config[SKL_PARAM_SET].set_params == SKL_PARAM_SET) {
395a4ad42d2SKareem Shaik sp_cfg = &mconfig->formats_config[SKL_PARAM_SET];
396bcc2a2dcSCezary Rojewski ret = skl_set_module_params(skl, sp_cfg->caps,
397abb74003SJeeja KP sp_cfg->caps_size,
398abb74003SJeeja KP sp_cfg->param_id, mconfig);
399abb74003SJeeja KP if (ret < 0)
400abb74003SJeeja KP return ret;
401abb74003SJeeja KP }
402abb74003SJeeja KP
403abb74003SJeeja KP for (i = 0; i < w->num_kcontrols; i++) {
404abb74003SJeeja KP k = &w->kcontrol_news[i];
405abb74003SJeeja KP if (k->access & SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK) {
406abb74003SJeeja KP sb = (void *) k->private_value;
407abb74003SJeeja KP bc = (struct skl_algo_data *)sb->dobj.private;
408abb74003SJeeja KP
4094ced1827SJeeja KP if (bc->set_params == SKL_PARAM_SET) {
410bcc2a2dcSCezary Rojewski ret = skl_set_module_params(skl,
4110d682104SDharageswari R (u32 *)bc->params, bc->size,
412abb74003SJeeja KP bc->param_id, mconfig);
413abb74003SJeeja KP if (ret < 0)
414abb74003SJeeja KP return ret;
415abb74003SJeeja KP }
416abb74003SJeeja KP }
417abb74003SJeeja KP }
418abb74003SJeeja KP
419abb74003SJeeja KP return 0;
420abb74003SJeeja KP }
421abb74003SJeeja KP
422abb74003SJeeja KP /*
423abb74003SJeeja KP * some module param can set from user control and this is required as
424abb74003SJeeja KP * when module is initailzed. if module param is required in init it is
425abb74003SJeeja KP * identifed by set_param flag. if set_param flag is not set, then this
426abb74003SJeeja KP * parameter needs to set as part of module init.
427abb74003SJeeja KP */
skl_tplg_set_module_init_data(struct snd_soc_dapm_widget * w)428abb74003SJeeja KP static int skl_tplg_set_module_init_data(struct snd_soc_dapm_widget *w)
429abb74003SJeeja KP {
430abb74003SJeeja KP const struct snd_kcontrol_new *k;
431abb74003SJeeja KP struct soc_bytes_ext *sb;
432abb74003SJeeja KP struct skl_algo_data *bc;
433abb74003SJeeja KP struct skl_module_cfg *mconfig = w->priv;
434abb74003SJeeja KP int i;
435abb74003SJeeja KP
436abb74003SJeeja KP for (i = 0; i < w->num_kcontrols; i++) {
437abb74003SJeeja KP k = &w->kcontrol_news[i];
438abb74003SJeeja KP if (k->access & SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK) {
439abb74003SJeeja KP sb = (struct soc_bytes_ext *)k->private_value;
440abb74003SJeeja KP bc = (struct skl_algo_data *)sb->dobj.private;
441abb74003SJeeja KP
4424ced1827SJeeja KP if (bc->set_params != SKL_PARAM_INIT)
443abb74003SJeeja KP continue;
444abb74003SJeeja KP
445a4ad42d2SKareem Shaik mconfig->formats_config[SKL_PARAM_INIT].caps =
446a4ad42d2SKareem Shaik (u32 *)bc->params;
447a4ad42d2SKareem Shaik mconfig->formats_config[SKL_PARAM_INIT].caps_size =
448a4ad42d2SKareem Shaik bc->size;
449abb74003SJeeja KP
450abb74003SJeeja KP break;
451abb74003SJeeja KP }
452abb74003SJeeja KP }
453abb74003SJeeja KP
454abb74003SJeeja KP return 0;
455abb74003SJeeja KP }
456abb74003SJeeja KP
skl_tplg_module_prepare(struct skl_dev * skl,struct skl_pipe * pipe,struct snd_soc_dapm_widget * w,struct skl_module_cfg * mcfg)457bcc2a2dcSCezary Rojewski static int skl_tplg_module_prepare(struct skl_dev *skl, struct skl_pipe *pipe,
458bb704a73SJeeja KP struct snd_soc_dapm_widget *w, struct skl_module_cfg *mcfg)
459bb704a73SJeeja KP {
460bb704a73SJeeja KP switch (mcfg->dev_type) {
461bb704a73SJeeja KP case SKL_DEVICE_HDAHOST:
462bcc2a2dcSCezary Rojewski return skl_pcm_host_dma_prepare(skl->dev, pipe->p_params);
463bb704a73SJeeja KP
464bb704a73SJeeja KP case SKL_DEVICE_HDALINK:
465bcc2a2dcSCezary Rojewski return skl_pcm_link_dma_prepare(skl->dev, pipe->p_params);
466bb704a73SJeeja KP }
467bb704a73SJeeja KP
468bb704a73SJeeja KP return 0;
469bb704a73SJeeja KP }
470bb704a73SJeeja KP
471abb74003SJeeja KP /*
472e4e2d2f4SJeeja KP * Inside a pipe instance, we can have various modules. These modules need
473e4e2d2f4SJeeja KP * to instantiated in DSP by invoking INIT_MODULE IPC, which is achieved by
474e4e2d2f4SJeeja KP * skl_init_module() routine, so invoke that for all modules in a pipeline
475e4e2d2f4SJeeja KP */
476e4e2d2f4SJeeja KP static int
skl_tplg_init_pipe_modules(struct skl_dev * skl,struct skl_pipe * pipe)477bcc2a2dcSCezary Rojewski skl_tplg_init_pipe_modules(struct skl_dev *skl, struct skl_pipe *pipe)
478e4e2d2f4SJeeja KP {
479e4e2d2f4SJeeja KP struct skl_pipe_module *w_module;
480e4e2d2f4SJeeja KP struct snd_soc_dapm_widget *w;
481e4e2d2f4SJeeja KP struct skl_module_cfg *mconfig;
482f6fa56e2SRamesh Babu u8 cfg_idx;
483e4e2d2f4SJeeja KP int ret = 0;
484e4e2d2f4SJeeja KP
485e4e2d2f4SJeeja KP list_for_each_entry(w_module, &pipe->w_list, node) {
4869e0784d0SAndy Shevchenko guid_t *uuid_mod;
487e4e2d2f4SJeeja KP w = w_module->w;
488e4e2d2f4SJeeja KP mconfig = w->priv;
489e4e2d2f4SJeeja KP
490b7c50555SVinod Koul /* check if module ids are populated */
491b7c50555SVinod Koul if (mconfig->id.module_id < 0) {
492bcc2a2dcSCezary Rojewski dev_err(skl->dev,
493a657ae7eSVinod Koul "module %pUL id not populated\n",
4949e0784d0SAndy Shevchenko (guid_t *)mconfig->guid);
495a657ae7eSVinod Koul return -EIO;
496b7c50555SVinod Koul }
497b7c50555SVinod Koul
498f6fa56e2SRamesh Babu cfg_idx = mconfig->pipe->cur_config_idx;
499f6fa56e2SRamesh Babu mconfig->fmt_idx = mconfig->mod_cfg[cfg_idx].fmt_idx;
500f6fa56e2SRamesh Babu mconfig->res_idx = mconfig->mod_cfg[cfg_idx].res_idx;
501f6fa56e2SRamesh Babu
502bcc2a2dcSCezary Rojewski if (mconfig->module->loadable && skl->dsp->fw_ops.load_mod) {
503bcc2a2dcSCezary Rojewski ret = skl->dsp->fw_ops.load_mod(skl->dsp,
5046c5768b3SDharageswari R mconfig->id.module_id, mconfig->guid);
5056c5768b3SDharageswari R if (ret < 0)
5066c5768b3SDharageswari R return ret;
5076c5768b3SDharageswari R }
5086c5768b3SDharageswari R
509bb704a73SJeeja KP /* prepare the DMA if the module is gateway cpr */
510bcc2a2dcSCezary Rojewski ret = skl_tplg_module_prepare(skl, pipe, w, mconfig);
511bb704a73SJeeja KP if (ret < 0)
512bb704a73SJeeja KP return ret;
513bb704a73SJeeja KP
5142d1419a3SJeeja KP /* update blob if blob is null for be with default value */
515bcc2a2dcSCezary Rojewski skl_tplg_update_be_blob(w, skl);
5162d1419a3SJeeja KP
517f7590d4fSJeeja KP /*
518f7590d4fSJeeja KP * apply fix/conversion to module params based on
519f7590d4fSJeeja KP * FE/BE params
520f7590d4fSJeeja KP */
521bcc2a2dcSCezary Rojewski skl_tplg_update_module_params(w, skl);
5229e0784d0SAndy Shevchenko uuid_mod = (guid_t *)mconfig->guid;
523bcc2a2dcSCezary Rojewski mconfig->id.pvt_id = skl_get_pvt_id(skl, uuid_mod,
524b26199eaSJeeja KP mconfig->id.instance_id);
525ef2a352cSDharageswari R if (mconfig->id.pvt_id < 0)
526ef2a352cSDharageswari R return ret;
527abb74003SJeeja KP skl_tplg_set_module_init_data(w);
5284147a6e5SPardha Saradhi K
529bcc2a2dcSCezary Rojewski ret = skl_dsp_get_core(skl->dsp, mconfig->core_id);
5304147a6e5SPardha Saradhi K if (ret < 0) {
531bcc2a2dcSCezary Rojewski dev_err(skl->dev, "Failed to wake up core %d ret=%d\n",
5324147a6e5SPardha Saradhi K mconfig->core_id, ret);
5334147a6e5SPardha Saradhi K return ret;
5344147a6e5SPardha Saradhi K }
5354147a6e5SPardha Saradhi K
536bcc2a2dcSCezary Rojewski ret = skl_init_module(skl, mconfig);
537ef2a352cSDharageswari R if (ret < 0) {
538bcc2a2dcSCezary Rojewski skl_put_pvt_id(skl, uuid_mod, &mconfig->id.pvt_id);
5394147a6e5SPardha Saradhi K goto err;
540ef2a352cSDharageswari R }
541f2a167caSCezary Rojewski
542bcc2a2dcSCezary Rojewski ret = skl_tplg_set_module_params(w, skl);
543e4e2d2f4SJeeja KP if (ret < 0)
5444147a6e5SPardha Saradhi K goto err;
545e4e2d2f4SJeeja KP }
546e4e2d2f4SJeeja KP
547e4e2d2f4SJeeja KP return 0;
5484147a6e5SPardha Saradhi K err:
549bcc2a2dcSCezary Rojewski skl_dsp_put_core(skl->dsp, mconfig->core_id);
5504147a6e5SPardha Saradhi K return ret;
551e4e2d2f4SJeeja KP }
552d93f8e55SVinod Koul
skl_tplg_unload_pipe_modules(struct skl_dev * skl,struct skl_pipe * pipe)553bcc2a2dcSCezary Rojewski static int skl_tplg_unload_pipe_modules(struct skl_dev *skl,
5546c5768b3SDharageswari R struct skl_pipe *pipe)
5556c5768b3SDharageswari R {
5564147a6e5SPardha Saradhi K int ret = 0;
55725722cf6SPierre-Louis Bossart struct skl_pipe_module *w_module;
55825722cf6SPierre-Louis Bossart struct skl_module_cfg *mconfig;
5596c5768b3SDharageswari R
5606c5768b3SDharageswari R list_for_each_entry(w_module, &pipe->w_list, node) {
5619e0784d0SAndy Shevchenko guid_t *uuid_mod;
5626c5768b3SDharageswari R mconfig = w_module->w->priv;
5639e0784d0SAndy Shevchenko uuid_mod = (guid_t *)mconfig->guid;
5646c5768b3SDharageswari R
565e4e95d82SGustaw Lewandowski if (mconfig->module->loadable && skl->dsp->fw_ops.unload_mod) {
566bcc2a2dcSCezary Rojewski ret = skl->dsp->fw_ops.unload_mod(skl->dsp,
5676c5768b3SDharageswari R mconfig->id.module_id);
568b0fab9c6SDharageswari R if (ret < 0)
569b0fab9c6SDharageswari R return -EIO;
570b0fab9c6SDharageswari R }
571bcc2a2dcSCezary Rojewski skl_put_pvt_id(skl, uuid_mod, &mconfig->id.pvt_id);
5724147a6e5SPardha Saradhi K
573bcc2a2dcSCezary Rojewski ret = skl_dsp_put_core(skl->dsp, mconfig->core_id);
5744147a6e5SPardha Saradhi K if (ret < 0) {
5754147a6e5SPardha Saradhi K /* don't return; continue with other modules */
576bcc2a2dcSCezary Rojewski dev_err(skl->dev, "Failed to sleep core %d ret=%d\n",
5774147a6e5SPardha Saradhi K mconfig->core_id, ret);
5784147a6e5SPardha Saradhi K }
5796c5768b3SDharageswari R }
5806c5768b3SDharageswari R
5816c5768b3SDharageswari R /* no modules to unload in this path, so return */
5824147a6e5SPardha Saradhi K return ret;
5836c5768b3SDharageswari R }
5846c5768b3SDharageswari R
skl_tplg_set_pipe_config_idx(struct skl_pipe * pipe,int idx)5854ac587f3SCezary Rojewski static void skl_tplg_set_pipe_config_idx(struct skl_pipe *pipe, int idx)
5864ac587f3SCezary Rojewski {
5874ac587f3SCezary Rojewski pipe->cur_config_idx = idx;
5884ac587f3SCezary Rojewski pipe->memory_pages = pipe->configs[idx].mem_pages;
5894ac587f3SCezary Rojewski }
5904ac587f3SCezary Rojewski
591d93f8e55SVinod Koul /*
592f6fa56e2SRamesh Babu * Here, we select pipe format based on the pipe type and pipe
593f6fa56e2SRamesh Babu * direction to determine the current config index for the pipeline.
594f6fa56e2SRamesh Babu * The config index is then used to select proper module resources.
595f6fa56e2SRamesh Babu * Intermediate pipes currently have a fixed format hence we select the
596f6fa56e2SRamesh Babu * 0th configuratation by default for such pipes.
597f6fa56e2SRamesh Babu */
598f6fa56e2SRamesh Babu static int
skl_tplg_get_pipe_config(struct skl_dev * skl,struct skl_module_cfg * mconfig)599bcc2a2dcSCezary Rojewski skl_tplg_get_pipe_config(struct skl_dev *skl, struct skl_module_cfg *mconfig)
600f6fa56e2SRamesh Babu {
601f6fa56e2SRamesh Babu struct skl_pipe *pipe = mconfig->pipe;
602f6fa56e2SRamesh Babu struct skl_pipe_params *params = pipe->p_params;
603f6fa56e2SRamesh Babu struct skl_path_config *pconfig = &pipe->configs[0];
604f6fa56e2SRamesh Babu struct skl_pipe_fmt *fmt = NULL;
605f6fa56e2SRamesh Babu bool in_fmt = false;
606f6fa56e2SRamesh Babu int i;
607f6fa56e2SRamesh Babu
608f6fa56e2SRamesh Babu if (pipe->nr_cfgs == 0) {
6094ac587f3SCezary Rojewski skl_tplg_set_pipe_config_idx(pipe, 0);
610f6fa56e2SRamesh Babu return 0;
611f6fa56e2SRamesh Babu }
612f6fa56e2SRamesh Babu
613b947d2b4SCezary Rojewski if (pipe->conn_type == SKL_PIPE_CONN_TYPE_NONE || pipe->nr_cfgs == 1) {
614b947d2b4SCezary Rojewski dev_dbg(skl->dev, "No conn_type or just 1 pathcfg, taking 0th for %d\n",
615b947d2b4SCezary Rojewski pipe->ppl_id);
6164ac587f3SCezary Rojewski skl_tplg_set_pipe_config_idx(pipe, 0);
617f6fa56e2SRamesh Babu return 0;
618f6fa56e2SRamesh Babu }
619f6fa56e2SRamesh Babu
620f6fa56e2SRamesh Babu if ((pipe->conn_type == SKL_PIPE_CONN_TYPE_FE &&
621f6fa56e2SRamesh Babu pipe->direction == SNDRV_PCM_STREAM_PLAYBACK) ||
622f6fa56e2SRamesh Babu (pipe->conn_type == SKL_PIPE_CONN_TYPE_BE &&
623f6fa56e2SRamesh Babu pipe->direction == SNDRV_PCM_STREAM_CAPTURE))
624f6fa56e2SRamesh Babu in_fmt = true;
625f6fa56e2SRamesh Babu
626f6fa56e2SRamesh Babu for (i = 0; i < pipe->nr_cfgs; i++) {
627f6fa56e2SRamesh Babu pconfig = &pipe->configs[i];
628f6fa56e2SRamesh Babu if (in_fmt)
629f6fa56e2SRamesh Babu fmt = &pconfig->in_fmt;
630f6fa56e2SRamesh Babu else
631f6fa56e2SRamesh Babu fmt = &pconfig->out_fmt;
632f6fa56e2SRamesh Babu
633f6fa56e2SRamesh Babu if (CHECK_HW_PARAMS(params->ch, params->s_freq, params->s_fmt,
634f6fa56e2SRamesh Babu fmt->channels, fmt->freq, fmt->bps)) {
6354ac587f3SCezary Rojewski skl_tplg_set_pipe_config_idx(pipe, i);
636bcc2a2dcSCezary Rojewski dev_dbg(skl->dev, "Using pipe config: %d\n", i);
637f6fa56e2SRamesh Babu return 0;
638f6fa56e2SRamesh Babu }
639f6fa56e2SRamesh Babu }
640f6fa56e2SRamesh Babu
641bcc2a2dcSCezary Rojewski dev_err(skl->dev, "Invalid pipe config: %d %d %d for pipe: %d\n",
642f6fa56e2SRamesh Babu params->ch, params->s_freq, params->s_fmt, pipe->ppl_id);
643f6fa56e2SRamesh Babu return -EINVAL;
644f6fa56e2SRamesh Babu }
645f6fa56e2SRamesh Babu
646f6fa56e2SRamesh Babu /*
647d93f8e55SVinod Koul * Mixer module represents a pipeline. So in the Pre-PMU event of mixer we
648d93f8e55SVinod Koul * need create the pipeline. So we do following:
649d93f8e55SVinod Koul * - Create the pipeline
650d93f8e55SVinod Koul * - Initialize the modules in pipeline
651d93f8e55SVinod Koul * - finally bind all modules together
652d93f8e55SVinod Koul */
skl_tplg_mixer_dapm_pre_pmu_event(struct snd_soc_dapm_widget * w,struct skl_dev * skl)653d93f8e55SVinod Koul static int skl_tplg_mixer_dapm_pre_pmu_event(struct snd_soc_dapm_widget *w,
654bcc2a2dcSCezary Rojewski struct skl_dev *skl)
655d93f8e55SVinod Koul {
656d93f8e55SVinod Koul int ret;
657d93f8e55SVinod Koul struct skl_module_cfg *mconfig = w->priv;
658d93f8e55SVinod Koul struct skl_pipe_module *w_module;
659d93f8e55SVinod Koul struct skl_pipe *s_pipe = mconfig->pipe;
660b8c722ddSJeeja KP struct skl_module_cfg *src_module = NULL, *dst_module, *module;
661b8c722ddSJeeja KP struct skl_module_deferred_bind *modules;
662d93f8e55SVinod Koul
663f6fa56e2SRamesh Babu ret = skl_tplg_get_pipe_config(skl, mconfig);
664f6fa56e2SRamesh Babu if (ret < 0)
665f6fa56e2SRamesh Babu return ret;
666f6fa56e2SRamesh Babu
667d93f8e55SVinod Koul /*
668d93f8e55SVinod Koul * Create a list of modules for pipe.
669d93f8e55SVinod Koul * This list contains modules from source to sink
670d93f8e55SVinod Koul */
671bcc2a2dcSCezary Rojewski ret = skl_create_pipeline(skl, mconfig->pipe);
672d93f8e55SVinod Koul if (ret < 0)
673d93f8e55SVinod Koul return ret;
674d93f8e55SVinod Koul
675d93f8e55SVinod Koul /* Init all pipe modules from source to sink */
676d93f8e55SVinod Koul ret = skl_tplg_init_pipe_modules(skl, s_pipe);
677d93f8e55SVinod Koul if (ret < 0)
678d93f8e55SVinod Koul return ret;
679d93f8e55SVinod Koul
680d93f8e55SVinod Koul /* Bind modules from source to sink */
681d93f8e55SVinod Koul list_for_each_entry(w_module, &s_pipe->w_list, node) {
682d93f8e55SVinod Koul dst_module = w_module->w->priv;
683d93f8e55SVinod Koul
684d93f8e55SVinod Koul if (src_module == NULL) {
685d93f8e55SVinod Koul src_module = dst_module;
686d93f8e55SVinod Koul continue;
687d93f8e55SVinod Koul }
688d93f8e55SVinod Koul
689bcc2a2dcSCezary Rojewski ret = skl_bind_modules(skl, src_module, dst_module);
690d93f8e55SVinod Koul if (ret < 0)
691d93f8e55SVinod Koul return ret;
692d93f8e55SVinod Koul
693d93f8e55SVinod Koul src_module = dst_module;
694d93f8e55SVinod Koul }
695d93f8e55SVinod Koul
696b8c722ddSJeeja KP /*
697b8c722ddSJeeja KP * When the destination module is initialized, check for these modules
698b8c722ddSJeeja KP * in deferred bind list. If found, bind them.
699b8c722ddSJeeja KP */
700b8c722ddSJeeja KP list_for_each_entry(w_module, &s_pipe->w_list, node) {
701b8c722ddSJeeja KP if (list_empty(&skl->bind_list))
702b8c722ddSJeeja KP break;
703b8c722ddSJeeja KP
704b8c722ddSJeeja KP list_for_each_entry(modules, &skl->bind_list, node) {
705b8c722ddSJeeja KP module = w_module->w->priv;
706b8c722ddSJeeja KP if (modules->dst == module)
707bcc2a2dcSCezary Rojewski skl_bind_modules(skl, modules->src,
708b8c722ddSJeeja KP modules->dst);
709b8c722ddSJeeja KP }
710b8c722ddSJeeja KP }
711b8c722ddSJeeja KP
712d93f8e55SVinod Koul return 0;
713d93f8e55SVinod Koul }
714d93f8e55SVinod Koul
skl_fill_sink_instance_id(struct skl_dev * skl,u32 * params,int size,struct skl_module_cfg * mcfg)715bcc2a2dcSCezary Rojewski static int skl_fill_sink_instance_id(struct skl_dev *skl, u32 *params,
716bf3e5ef5SDharageswari R int size, struct skl_module_cfg *mcfg)
7175e8f0ee4SDharageswari R {
7185e8f0ee4SDharageswari R int i, pvt_id;
7195e8f0ee4SDharageswari R
720bf3e5ef5SDharageswari R if (mcfg->m_type == SKL_MODULE_TYPE_KPB) {
721bf3e5ef5SDharageswari R struct skl_kpb_params *kpb_params =
722bf3e5ef5SDharageswari R (struct skl_kpb_params *)params;
723f7a9f772SSriram Periyasamy struct skl_mod_inst_map *inst = kpb_params->u.map;
7245e8f0ee4SDharageswari R
725bf3e5ef5SDharageswari R for (i = 0; i < kpb_params->num_modules; i++) {
726bcc2a2dcSCezary Rojewski pvt_id = skl_get_pvt_instance_id_map(skl, inst->mod_id,
727bf3e5ef5SDharageswari R inst->inst_id);
7285e8f0ee4SDharageswari R if (pvt_id < 0)
7295e8f0ee4SDharageswari R return -EINVAL;
730bf3e5ef5SDharageswari R
7315e8f0ee4SDharageswari R inst->inst_id = pvt_id;
7325e8f0ee4SDharageswari R inst++;
7335e8f0ee4SDharageswari R }
7345e8f0ee4SDharageswari R }
7355e8f0ee4SDharageswari R
736bf3e5ef5SDharageswari R return 0;
737bf3e5ef5SDharageswari R }
738cc6a4044SJeeja KP /*
739cc6a4044SJeeja KP * Some modules require params to be set after the module is bound to
740cc6a4044SJeeja KP * all pins connected.
741cc6a4044SJeeja KP *
742cc6a4044SJeeja KP * The module provider initializes set_param flag for such modules and we
743cc6a4044SJeeja KP * send params after binding
744cc6a4044SJeeja KP */
skl_tplg_set_module_bind_params(struct snd_soc_dapm_widget * w,struct skl_module_cfg * mcfg,struct skl_dev * skl)745cc6a4044SJeeja KP static int skl_tplg_set_module_bind_params(struct snd_soc_dapm_widget *w,
746bcc2a2dcSCezary Rojewski struct skl_module_cfg *mcfg, struct skl_dev *skl)
747cc6a4044SJeeja KP {
748cc6a4044SJeeja KP int i, ret;
749cc6a4044SJeeja KP struct skl_module_cfg *mconfig = w->priv;
750cc6a4044SJeeja KP const struct snd_kcontrol_new *k;
751cc6a4044SJeeja KP struct soc_bytes_ext *sb;
752cc6a4044SJeeja KP struct skl_algo_data *bc;
753cc6a4044SJeeja KP struct skl_specific_cfg *sp_cfg;
754bf3e5ef5SDharageswari R u32 *params;
755cc6a4044SJeeja KP
756cc6a4044SJeeja KP /*
757cc6a4044SJeeja KP * check all out/in pins are in bind state.
758cc6a4044SJeeja KP * if so set the module param
759cc6a4044SJeeja KP */
760f6fa56e2SRamesh Babu for (i = 0; i < mcfg->module->max_output_pins; i++) {
761cc6a4044SJeeja KP if (mcfg->m_out_pin[i].pin_state != SKL_PIN_BIND_DONE)
762cc6a4044SJeeja KP return 0;
763cc6a4044SJeeja KP }
764cc6a4044SJeeja KP
765f6fa56e2SRamesh Babu for (i = 0; i < mcfg->module->max_input_pins; i++) {
766cc6a4044SJeeja KP if (mcfg->m_in_pin[i].pin_state != SKL_PIN_BIND_DONE)
767cc6a4044SJeeja KP return 0;
768cc6a4044SJeeja KP }
769cc6a4044SJeeja KP
770a4ad42d2SKareem Shaik if (mconfig->formats_config[SKL_PARAM_BIND].caps_size > 0 &&
771a4ad42d2SKareem Shaik mconfig->formats_config[SKL_PARAM_BIND].set_params ==
772a4ad42d2SKareem Shaik SKL_PARAM_BIND) {
773a4ad42d2SKareem Shaik sp_cfg = &mconfig->formats_config[SKL_PARAM_BIND];
774bcc2a2dcSCezary Rojewski ret = skl_set_module_params(skl, sp_cfg->caps,
775cc6a4044SJeeja KP sp_cfg->caps_size,
776cc6a4044SJeeja KP sp_cfg->param_id, mconfig);
777cc6a4044SJeeja KP if (ret < 0)
778cc6a4044SJeeja KP return ret;
779cc6a4044SJeeja KP }
780cc6a4044SJeeja KP
781cc6a4044SJeeja KP for (i = 0; i < w->num_kcontrols; i++) {
782cc6a4044SJeeja KP k = &w->kcontrol_news[i];
783cc6a4044SJeeja KP if (k->access & SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK) {
784cc6a4044SJeeja KP sb = (void *) k->private_value;
785cc6a4044SJeeja KP bc = (struct skl_algo_data *)sb->dobj.private;
786cc6a4044SJeeja KP
787cc6a4044SJeeja KP if (bc->set_params == SKL_PARAM_BIND) {
788ca92cc46Szhong jiang params = kmemdup(bc->params, bc->max, GFP_KERNEL);
789bf3e5ef5SDharageswari R if (!params)
790bf3e5ef5SDharageswari R return -ENOMEM;
791bf3e5ef5SDharageswari R
792bcc2a2dcSCezary Rojewski skl_fill_sink_instance_id(skl, params, bc->max,
793bf3e5ef5SDharageswari R mconfig);
794bf3e5ef5SDharageswari R
795bcc2a2dcSCezary Rojewski ret = skl_set_module_params(skl, params,
796bf3e5ef5SDharageswari R bc->max, bc->param_id, mconfig);
797bf3e5ef5SDharageswari R kfree(params);
798bf3e5ef5SDharageswari R
799cc6a4044SJeeja KP if (ret < 0)
800cc6a4044SJeeja KP return ret;
801cc6a4044SJeeja KP }
802cc6a4044SJeeja KP }
803cc6a4044SJeeja KP }
804cc6a4044SJeeja KP
805cc6a4044SJeeja KP return 0;
806cc6a4044SJeeja KP }
807cc6a4044SJeeja KP
skl_get_module_id(struct skl_dev * skl,guid_t * uuid)808bcc2a2dcSCezary Rojewski static int skl_get_module_id(struct skl_dev *skl, guid_t *uuid)
809f7a9f772SSriram Periyasamy {
810f7a9f772SSriram Periyasamy struct uuid_module *module;
811f7a9f772SSriram Periyasamy
812bcc2a2dcSCezary Rojewski list_for_each_entry(module, &skl->uuid_list, list) {
8139e0784d0SAndy Shevchenko if (guid_equal(uuid, &module->uuid))
814f7a9f772SSriram Periyasamy return module->id;
815f7a9f772SSriram Periyasamy }
816f7a9f772SSriram Periyasamy
817f7a9f772SSriram Periyasamy return -EINVAL;
818f7a9f772SSriram Periyasamy }
819f7a9f772SSriram Periyasamy
skl_tplg_find_moduleid_from_uuid(struct skl_dev * skl,const struct snd_kcontrol_new * k)820bcc2a2dcSCezary Rojewski static int skl_tplg_find_moduleid_from_uuid(struct skl_dev *skl,
821f7a9f772SSriram Periyasamy const struct snd_kcontrol_new *k)
822f7a9f772SSriram Periyasamy {
823f7a9f772SSriram Periyasamy struct soc_bytes_ext *sb = (void *) k->private_value;
824f7a9f772SSriram Periyasamy struct skl_algo_data *bc = (struct skl_algo_data *)sb->dobj.private;
825f7a9f772SSriram Periyasamy struct skl_kpb_params *uuid_params, *params;
82676f56faeSRakesh Ughreja struct hdac_bus *bus = skl_to_bus(skl);
827f7a9f772SSriram Periyasamy int i, size, module_id;
828f7a9f772SSriram Periyasamy
829f7a9f772SSriram Periyasamy if (bc->set_params == SKL_PARAM_BIND && bc->max) {
830f7a9f772SSriram Periyasamy uuid_params = (struct skl_kpb_params *)bc->params;
831d00cc2f1SGustavo A. R. Silva size = struct_size(params, u.map, uuid_params->num_modules);
832f7a9f772SSriram Periyasamy
833f7a9f772SSriram Periyasamy params = devm_kzalloc(bus->dev, size, GFP_KERNEL);
834f7a9f772SSriram Periyasamy if (!params)
835f7a9f772SSriram Periyasamy return -ENOMEM;
836f7a9f772SSriram Periyasamy
837f7a9f772SSriram Periyasamy params->num_modules = uuid_params->num_modules;
838f7a9f772SSriram Periyasamy
839f7a9f772SSriram Periyasamy for (i = 0; i < uuid_params->num_modules; i++) {
840bcc2a2dcSCezary Rojewski module_id = skl_get_module_id(skl,
841f7a9f772SSriram Periyasamy &uuid_params->u.map_uuid[i].mod_uuid);
842f7a9f772SSriram Periyasamy if (module_id < 0) {
843f7a9f772SSriram Periyasamy devm_kfree(bus->dev, params);
844f7a9f772SSriram Periyasamy return -EINVAL;
845f7a9f772SSriram Periyasamy }
846f7a9f772SSriram Periyasamy
847f7a9f772SSriram Periyasamy params->u.map[i].mod_id = module_id;
848f7a9f772SSriram Periyasamy params->u.map[i].inst_id =
849f7a9f772SSriram Periyasamy uuid_params->u.map_uuid[i].inst_id;
850f7a9f772SSriram Periyasamy }
851f7a9f772SSriram Periyasamy
852f7a9f772SSriram Periyasamy devm_kfree(bus->dev, bc->params);
853f7a9f772SSriram Periyasamy bc->params = (char *)params;
854f7a9f772SSriram Periyasamy bc->max = size;
855f7a9f772SSriram Periyasamy }
856f7a9f772SSriram Periyasamy
857f7a9f772SSriram Periyasamy return 0;
858f7a9f772SSriram Periyasamy }
859f7a9f772SSriram Periyasamy
860f7a9f772SSriram Periyasamy /*
861f7a9f772SSriram Periyasamy * Retrieve the module id from UUID mentioned in the
862f7a9f772SSriram Periyasamy * post bind params
863f7a9f772SSriram Periyasamy */
skl_tplg_add_moduleid_in_bind_params(struct skl_dev * skl,struct snd_soc_dapm_widget * w)864bcc2a2dcSCezary Rojewski void skl_tplg_add_moduleid_in_bind_params(struct skl_dev *skl,
865f7a9f772SSriram Periyasamy struct snd_soc_dapm_widget *w)
866f7a9f772SSriram Periyasamy {
867f7a9f772SSriram Periyasamy struct skl_module_cfg *mconfig = w->priv;
868f7a9f772SSriram Periyasamy int i;
869f7a9f772SSriram Periyasamy
870f7a9f772SSriram Periyasamy /*
871f7a9f772SSriram Periyasamy * Post bind params are used for only for KPB
872f7a9f772SSriram Periyasamy * to set copier instances to drain the data
873f7a9f772SSriram Periyasamy * in fast mode
874f7a9f772SSriram Periyasamy */
875f7a9f772SSriram Periyasamy if (mconfig->m_type != SKL_MODULE_TYPE_KPB)
876f7a9f772SSriram Periyasamy return;
877f7a9f772SSriram Periyasamy
878f7a9f772SSriram Periyasamy for (i = 0; i < w->num_kcontrols; i++)
879f7a9f772SSriram Periyasamy if ((w->kcontrol_news[i].access &
880f7a9f772SSriram Periyasamy SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK) &&
881f7a9f772SSriram Periyasamy (skl_tplg_find_moduleid_from_uuid(skl,
882f7a9f772SSriram Periyasamy &w->kcontrol_news[i]) < 0))
883bcc2a2dcSCezary Rojewski dev_err(skl->dev,
884f7a9f772SSriram Periyasamy "%s: invalid kpb post bind params\n",
885f7a9f772SSriram Periyasamy __func__);
886f7a9f772SSriram Periyasamy }
887b8c722ddSJeeja KP
skl_tplg_module_add_deferred_bind(struct skl_dev * skl,struct skl_module_cfg * src,struct skl_module_cfg * dst)888bcc2a2dcSCezary Rojewski static int skl_tplg_module_add_deferred_bind(struct skl_dev *skl,
889b8c722ddSJeeja KP struct skl_module_cfg *src, struct skl_module_cfg *dst)
890b8c722ddSJeeja KP {
891b8c722ddSJeeja KP struct skl_module_deferred_bind *m_list, *modules;
892b8c722ddSJeeja KP int i;
893b8c722ddSJeeja KP
894b8c722ddSJeeja KP /* only supported for module with static pin connection */
895f6fa56e2SRamesh Babu for (i = 0; i < dst->module->max_input_pins; i++) {
896b8c722ddSJeeja KP struct skl_module_pin *pin = &dst->m_in_pin[i];
897b8c722ddSJeeja KP
898b8c722ddSJeeja KP if (pin->is_dynamic)
899b8c722ddSJeeja KP continue;
900b8c722ddSJeeja KP
901b8c722ddSJeeja KP if ((pin->id.module_id == src->id.module_id) &&
902b8c722ddSJeeja KP (pin->id.instance_id == src->id.instance_id)) {
903b8c722ddSJeeja KP
904b8c722ddSJeeja KP if (!list_empty(&skl->bind_list)) {
905b8c722ddSJeeja KP list_for_each_entry(modules, &skl->bind_list, node) {
906b8c722ddSJeeja KP if (modules->src == src && modules->dst == dst)
907b8c722ddSJeeja KP return 0;
908b8c722ddSJeeja KP }
909b8c722ddSJeeja KP }
910b8c722ddSJeeja KP
911b8c722ddSJeeja KP m_list = kzalloc(sizeof(*m_list), GFP_KERNEL);
912b8c722ddSJeeja KP if (!m_list)
913b8c722ddSJeeja KP return -ENOMEM;
914b8c722ddSJeeja KP
915b8c722ddSJeeja KP m_list->src = src;
916b8c722ddSJeeja KP m_list->dst = dst;
917b8c722ddSJeeja KP
918b8c722ddSJeeja KP list_add(&m_list->node, &skl->bind_list);
919b8c722ddSJeeja KP }
920b8c722ddSJeeja KP }
921b8c722ddSJeeja KP
922b8c722ddSJeeja KP return 0;
923b8c722ddSJeeja KP }
924b8c722ddSJeeja KP
skl_tplg_bind_sinks(struct snd_soc_dapm_widget * w,struct skl_dev * skl,struct snd_soc_dapm_widget * src_w,struct skl_module_cfg * src_mconfig)9258724ff17SJeeja KP static int skl_tplg_bind_sinks(struct snd_soc_dapm_widget *w,
926bcc2a2dcSCezary Rojewski struct skl_dev *skl,
9276bd4cf85SJeeja KP struct snd_soc_dapm_widget *src_w,
9288724ff17SJeeja KP struct skl_module_cfg *src_mconfig)
929d93f8e55SVinod Koul {
930d93f8e55SVinod Koul struct snd_soc_dapm_path *p;
9310ed95d76SJeeja KP struct snd_soc_dapm_widget *sink = NULL, *next_sink = NULL;
9328724ff17SJeeja KP struct skl_module_cfg *sink_mconfig;
9338724ff17SJeeja KP int ret;
934d93f8e55SVinod Koul
9358724ff17SJeeja KP snd_soc_dapm_widget_for_each_sink_path(w, p) {
936d93f8e55SVinod Koul if (!p->connect)
937d93f8e55SVinod Koul continue;
938d93f8e55SVinod Koul
939bcc2a2dcSCezary Rojewski dev_dbg(skl->dev,
940bcc2a2dcSCezary Rojewski "%s: src widget=%s\n", __func__, w->name);
941bcc2a2dcSCezary Rojewski dev_dbg(skl->dev,
942bcc2a2dcSCezary Rojewski "%s: sink widget=%s\n", __func__, p->sink->name);
943d93f8e55SVinod Koul
9440ed95d76SJeeja KP next_sink = p->sink;
9456bd4cf85SJeeja KP
946bcc2a2dcSCezary Rojewski if (!is_skl_dsp_widget_type(p->sink, skl->dev))
9476bd4cf85SJeeja KP return skl_tplg_bind_sinks(p->sink, skl, src_w, src_mconfig);
9486bd4cf85SJeeja KP
949d93f8e55SVinod Koul /*
950d93f8e55SVinod Koul * here we will check widgets in sink pipelines, so that
951d93f8e55SVinod Koul * can be any widgets type and we are only interested if
952d93f8e55SVinod Koul * they are ones used for SKL so check that first
953d93f8e55SVinod Koul */
954d93f8e55SVinod Koul if ((p->sink->priv != NULL) &&
955bcc2a2dcSCezary Rojewski is_skl_dsp_widget_type(p->sink, skl->dev)) {
956d93f8e55SVinod Koul
957d93f8e55SVinod Koul sink = p->sink;
958d93f8e55SVinod Koul sink_mconfig = sink->priv;
959d93f8e55SVinod Koul
960b8c722ddSJeeja KP /*
961b8c722ddSJeeja KP * Modules other than PGA leaf can be connected
962b8c722ddSJeeja KP * directly or via switch to a module in another
963b8c722ddSJeeja KP * pipeline. EX: reference path
964b8c722ddSJeeja KP * when the path is enabled, the dst module that needs
965b8c722ddSJeeja KP * to be bound may not be initialized. if the module is
966b8c722ddSJeeja KP * not initialized, add these modules in the deferred
967b8c722ddSJeeja KP * bind list and when the dst module is initialised,
968b8c722ddSJeeja KP * bind this module to the dst_module in deferred list.
969b8c722ddSJeeja KP */
970b8c722ddSJeeja KP if (((src_mconfig->m_state == SKL_MODULE_INIT_DONE)
971b8c722ddSJeeja KP && (sink_mconfig->m_state == SKL_MODULE_UNINIT))) {
972b8c722ddSJeeja KP
973b8c722ddSJeeja KP ret = skl_tplg_module_add_deferred_bind(skl,
974b8c722ddSJeeja KP src_mconfig, sink_mconfig);
975b8c722ddSJeeja KP
976b8c722ddSJeeja KP if (ret < 0)
977b8c722ddSJeeja KP return ret;
978b8c722ddSJeeja KP
979b8c722ddSJeeja KP }
980b8c722ddSJeeja KP
981b8c722ddSJeeja KP
982cc6a4044SJeeja KP if (src_mconfig->m_state == SKL_MODULE_UNINIT ||
983cc6a4044SJeeja KP sink_mconfig->m_state == SKL_MODULE_UNINIT)
984cc6a4044SJeeja KP continue;
985cc6a4044SJeeja KP
986d93f8e55SVinod Koul /* Bind source to sink, mixin is always source */
987bcc2a2dcSCezary Rojewski ret = skl_bind_modules(skl, src_mconfig, sink_mconfig);
988d93f8e55SVinod Koul if (ret)
989d93f8e55SVinod Koul return ret;
990d93f8e55SVinod Koul
991cc6a4044SJeeja KP /* set module params after bind */
992bcc2a2dcSCezary Rojewski skl_tplg_set_module_bind_params(src_w,
993bcc2a2dcSCezary Rojewski src_mconfig, skl);
994bcc2a2dcSCezary Rojewski skl_tplg_set_module_bind_params(sink,
995bcc2a2dcSCezary Rojewski sink_mconfig, skl);
996cc6a4044SJeeja KP
997d93f8e55SVinod Koul /* Start sinks pipe first */
998d93f8e55SVinod Koul if (sink_mconfig->pipe->state != SKL_PIPE_STARTED) {
999d1730c3dSJeeja KP if (sink_mconfig->pipe->conn_type !=
1000d1730c3dSJeeja KP SKL_PIPE_CONN_TYPE_FE)
1001bcc2a2dcSCezary Rojewski ret = skl_run_pipe(skl,
1002d1730c3dSJeeja KP sink_mconfig->pipe);
1003d93f8e55SVinod Koul if (ret)
1004d93f8e55SVinod Koul return ret;
1005d93f8e55SVinod Koul }
1006d93f8e55SVinod Koul }
1007d93f8e55SVinod Koul }
1008d93f8e55SVinod Koul
100910a5439fSguneshwor.o.singh@intel.com if (!sink && next_sink)
10106bd4cf85SJeeja KP return skl_tplg_bind_sinks(next_sink, skl, src_w, src_mconfig);
10118724ff17SJeeja KP
10128724ff17SJeeja KP return 0;
10138724ff17SJeeja KP }
10148724ff17SJeeja KP
1015d93f8e55SVinod Koul /*
1016d93f8e55SVinod Koul * A PGA represents a module in a pipeline. So in the Pre-PMU event of PGA
1017d93f8e55SVinod Koul * we need to do following:
1018d93f8e55SVinod Koul * - Bind to sink pipeline
1019d93f8e55SVinod Koul * Since the sink pipes can be running and we don't get mixer event on
1020d93f8e55SVinod Koul * connect for already running mixer, we need to find the sink pipes
1021d93f8e55SVinod Koul * here and bind to them. This way dynamic connect works.
1022d93f8e55SVinod Koul * - Start sink pipeline, if not running
1023d93f8e55SVinod Koul * - Then run current pipe
1024d93f8e55SVinod Koul */
skl_tplg_pga_dapm_pre_pmu_event(struct snd_soc_dapm_widget * w,struct skl_dev * skl)1025d93f8e55SVinod Koul static int skl_tplg_pga_dapm_pre_pmu_event(struct snd_soc_dapm_widget *w,
1026bcc2a2dcSCezary Rojewski struct skl_dev *skl)
1027d93f8e55SVinod Koul {
10288724ff17SJeeja KP struct skl_module_cfg *src_mconfig;
1029d93f8e55SVinod Koul int ret = 0;
1030d93f8e55SVinod Koul
10318724ff17SJeeja KP src_mconfig = w->priv;
1032d93f8e55SVinod Koul
1033d93f8e55SVinod Koul /*
1034d93f8e55SVinod Koul * find which sink it is connected to, bind with the sink,
1035d93f8e55SVinod Koul * if sink is not started, start sink pipe first, then start
1036d93f8e55SVinod Koul * this pipe
1037d93f8e55SVinod Koul */
10386bd4cf85SJeeja KP ret = skl_tplg_bind_sinks(w, skl, w, src_mconfig);
10398724ff17SJeeja KP if (ret)
10408724ff17SJeeja KP return ret;
10418724ff17SJeeja KP
1042d93f8e55SVinod Koul /* Start source pipe last after starting all sinks */
1043d1730c3dSJeeja KP if (src_mconfig->pipe->conn_type != SKL_PIPE_CONN_TYPE_FE)
1044bcc2a2dcSCezary Rojewski return skl_run_pipe(skl, src_mconfig->pipe);
1045d93f8e55SVinod Koul
1046d93f8e55SVinod Koul return 0;
1047d93f8e55SVinod Koul }
1048d93f8e55SVinod Koul
skl_get_src_dsp_widget(struct snd_soc_dapm_widget * w,struct skl_dev * skl)10498724ff17SJeeja KP static struct snd_soc_dapm_widget *skl_get_src_dsp_widget(
1050bcc2a2dcSCezary Rojewski struct snd_soc_dapm_widget *w, struct skl_dev *skl)
10518724ff17SJeeja KP {
10528724ff17SJeeja KP struct snd_soc_dapm_path *p;
10538724ff17SJeeja KP struct snd_soc_dapm_widget *src_w = NULL;
10548724ff17SJeeja KP
1055d93f8e55SVinod Koul snd_soc_dapm_widget_for_each_source_path(w, p) {
10568724ff17SJeeja KP src_w = p->source;
1057d93f8e55SVinod Koul if (!p->connect)
1058d93f8e55SVinod Koul continue;
1059d93f8e55SVinod Koul
1060bcc2a2dcSCezary Rojewski dev_dbg(skl->dev, "sink widget=%s\n", w->name);
1061bcc2a2dcSCezary Rojewski dev_dbg(skl->dev, "src widget=%s\n", p->source->name);
1062d93f8e55SVinod Koul
1063d93f8e55SVinod Koul /*
10648724ff17SJeeja KP * here we will check widgets in sink pipelines, so that can
10658724ff17SJeeja KP * be any widgets type and we are only interested if they are
10668724ff17SJeeja KP * ones used for SKL so check that first
1067d93f8e55SVinod Koul */
10688724ff17SJeeja KP if ((p->source->priv != NULL) &&
1069bcc2a2dcSCezary Rojewski is_skl_dsp_widget_type(p->source, skl->dev)) {
10708724ff17SJeeja KP return p->source;
1071d93f8e55SVinod Koul }
1072d93f8e55SVinod Koul }
1073d93f8e55SVinod Koul
10748724ff17SJeeja KP if (src_w != NULL)
10758724ff17SJeeja KP return skl_get_src_dsp_widget(src_w, skl);
1076d93f8e55SVinod Koul
10778724ff17SJeeja KP return NULL;
1078d93f8e55SVinod Koul }
1079d93f8e55SVinod Koul
1080d93f8e55SVinod Koul /*
1081d93f8e55SVinod Koul * in the Post-PMU event of mixer we need to do following:
1082d93f8e55SVinod Koul * - Check if this pipe is running
1083d93f8e55SVinod Koul * - if not, then
1084d93f8e55SVinod Koul * - bind this pipeline to its source pipeline
1085d93f8e55SVinod Koul * if source pipe is already running, this means it is a dynamic
1086d93f8e55SVinod Koul * connection and we need to bind only to that pipe
1087d93f8e55SVinod Koul * - start this pipeline
1088d93f8e55SVinod Koul */
skl_tplg_mixer_dapm_post_pmu_event(struct snd_soc_dapm_widget * w,struct skl_dev * skl)1089d93f8e55SVinod Koul static int skl_tplg_mixer_dapm_post_pmu_event(struct snd_soc_dapm_widget *w,
1090bcc2a2dcSCezary Rojewski struct skl_dev *skl)
1091d93f8e55SVinod Koul {
1092d93f8e55SVinod Koul int ret = 0;
1093d93f8e55SVinod Koul struct snd_soc_dapm_widget *source, *sink;
1094d93f8e55SVinod Koul struct skl_module_cfg *src_mconfig, *sink_mconfig;
1095d93f8e55SVinod Koul int src_pipe_started = 0;
1096d93f8e55SVinod Koul
1097d93f8e55SVinod Koul sink = w;
1098d93f8e55SVinod Koul sink_mconfig = sink->priv;
1099d93f8e55SVinod Koul
1100d93f8e55SVinod Koul /*
1101d93f8e55SVinod Koul * If source pipe is already started, that means source is driving
1102d93f8e55SVinod Koul * one more sink before this sink got connected, Since source is
1103d93f8e55SVinod Koul * started, bind this sink to source and start this pipe.
1104d93f8e55SVinod Koul */
11058724ff17SJeeja KP source = skl_get_src_dsp_widget(w, skl);
11068724ff17SJeeja KP if (source != NULL) {
1107d93f8e55SVinod Koul src_mconfig = source->priv;
1108d93f8e55SVinod Koul sink_mconfig = sink->priv;
1109d93f8e55SVinod Koul src_pipe_started = 1;
1110d93f8e55SVinod Koul
1111d93f8e55SVinod Koul /*
11128724ff17SJeeja KP * check pipe state, then no need to bind or start the
11138724ff17SJeeja KP * pipe
1114d93f8e55SVinod Koul */
1115d93f8e55SVinod Koul if (src_mconfig->pipe->state != SKL_PIPE_STARTED)
1116d93f8e55SVinod Koul src_pipe_started = 0;
1117d93f8e55SVinod Koul }
1118d93f8e55SVinod Koul
1119d93f8e55SVinod Koul if (src_pipe_started) {
1120bcc2a2dcSCezary Rojewski ret = skl_bind_modules(skl, src_mconfig, sink_mconfig);
1121d93f8e55SVinod Koul if (ret)
1122d93f8e55SVinod Koul return ret;
1123d93f8e55SVinod Koul
1124cc6a4044SJeeja KP /* set module params after bind */
1125bcc2a2dcSCezary Rojewski skl_tplg_set_module_bind_params(source, src_mconfig, skl);
1126bcc2a2dcSCezary Rojewski skl_tplg_set_module_bind_params(sink, sink_mconfig, skl);
1127cc6a4044SJeeja KP
1128d1730c3dSJeeja KP if (sink_mconfig->pipe->conn_type != SKL_PIPE_CONN_TYPE_FE)
1129bcc2a2dcSCezary Rojewski ret = skl_run_pipe(skl, sink_mconfig->pipe);
1130d93f8e55SVinod Koul }
1131d93f8e55SVinod Koul
1132d93f8e55SVinod Koul return ret;
1133d93f8e55SVinod Koul }
1134d93f8e55SVinod Koul
1135d93f8e55SVinod Koul /*
1136d93f8e55SVinod Koul * in the Pre-PMD event of mixer we need to do following:
1137d93f8e55SVinod Koul * - Stop the pipe
1138d93f8e55SVinod Koul * - find the source connections and remove that from dapm_path_list
1139d93f8e55SVinod Koul * - unbind with source pipelines if still connected
1140d93f8e55SVinod Koul */
skl_tplg_mixer_dapm_pre_pmd_event(struct snd_soc_dapm_widget * w,struct skl_dev * skl)1141d93f8e55SVinod Koul static int skl_tplg_mixer_dapm_pre_pmd_event(struct snd_soc_dapm_widget *w,
1142bcc2a2dcSCezary Rojewski struct skl_dev *skl)
1143d93f8e55SVinod Koul {
1144d93f8e55SVinod Koul struct skl_module_cfg *src_mconfig, *sink_mconfig;
1145ce1b5551SJeeja KP int ret = 0, i;
1146d93f8e55SVinod Koul
1147ce1b5551SJeeja KP sink_mconfig = w->priv;
1148d93f8e55SVinod Koul
1149d93f8e55SVinod Koul /* Stop the pipe */
1150bcc2a2dcSCezary Rojewski ret = skl_stop_pipe(skl, sink_mconfig->pipe);
1151d93f8e55SVinod Koul if (ret)
1152d93f8e55SVinod Koul return ret;
1153d93f8e55SVinod Koul
1154f6fa56e2SRamesh Babu for (i = 0; i < sink_mconfig->module->max_input_pins; i++) {
1155ce1b5551SJeeja KP if (sink_mconfig->m_in_pin[i].pin_state == SKL_PIN_BIND_DONE) {
1156ce1b5551SJeeja KP src_mconfig = sink_mconfig->m_in_pin[i].tgt_mcfg;
1157ce1b5551SJeeja KP if (!src_mconfig)
1158ce1b5551SJeeja KP continue;
1159d93f8e55SVinod Koul
1160bcc2a2dcSCezary Rojewski ret = skl_unbind_modules(skl,
1161ce1b5551SJeeja KP src_mconfig, sink_mconfig);
1162ce1b5551SJeeja KP }
1163d93f8e55SVinod Koul }
1164d93f8e55SVinod Koul
1165d93f8e55SVinod Koul return ret;
1166d93f8e55SVinod Koul }
1167d93f8e55SVinod Koul
1168d93f8e55SVinod Koul /*
1169d93f8e55SVinod Koul * in the Post-PMD event of mixer we need to do following:
1170d93f8e55SVinod Koul * - Unbind the modules within the pipeline
1171d93f8e55SVinod Koul * - Delete the pipeline (modules are not required to be explicitly
1172d93f8e55SVinod Koul * deleted, pipeline delete is enough here
1173d93f8e55SVinod Koul */
skl_tplg_mixer_dapm_post_pmd_event(struct snd_soc_dapm_widget * w,struct skl_dev * skl)1174d93f8e55SVinod Koul static int skl_tplg_mixer_dapm_post_pmd_event(struct snd_soc_dapm_widget *w,
1175bcc2a2dcSCezary Rojewski struct skl_dev *skl)
1176d93f8e55SVinod Koul {
1177d93f8e55SVinod Koul struct skl_module_cfg *mconfig = w->priv;
1178d93f8e55SVinod Koul struct skl_pipe_module *w_module;
1179d93f8e55SVinod Koul struct skl_module_cfg *src_module = NULL, *dst_module;
1180d93f8e55SVinod Koul struct skl_pipe *s_pipe = mconfig->pipe;
1181550b349aSDan Carpenter struct skl_module_deferred_bind *modules, *tmp;
1182d93f8e55SVinod Koul
1183260eb73aSDharageswari R if (s_pipe->state == SKL_PIPE_INVALID)
1184260eb73aSDharageswari R return -EINVAL;
1185260eb73aSDharageswari R
1186d93f8e55SVinod Koul list_for_each_entry(w_module, &s_pipe->w_list, node) {
1187b8c722ddSJeeja KP if (list_empty(&skl->bind_list))
1188b8c722ddSJeeja KP break;
1189b8c722ddSJeeja KP
1190b8c722ddSJeeja KP src_module = w_module->w->priv;
1191b8c722ddSJeeja KP
1192550b349aSDan Carpenter list_for_each_entry_safe(modules, tmp, &skl->bind_list, node) {
1193b8c722ddSJeeja KP /*
1194b8c722ddSJeeja KP * When the destination module is deleted, Unbind the
1195b8c722ddSJeeja KP * modules from deferred bind list.
1196b8c722ddSJeeja KP */
1197b8c722ddSJeeja KP if (modules->dst == src_module) {
1198bcc2a2dcSCezary Rojewski skl_unbind_modules(skl, modules->src,
1199b8c722ddSJeeja KP modules->dst);
1200b8c722ddSJeeja KP }
1201b8c722ddSJeeja KP
1202b8c722ddSJeeja KP /*
1203b8c722ddSJeeja KP * When the source module is deleted, remove this entry
1204b8c722ddSJeeja KP * from the deferred bind list.
1205b8c722ddSJeeja KP */
1206b8c722ddSJeeja KP if (modules->src == src_module) {
1207b8c722ddSJeeja KP list_del(&modules->node);
1208b8c722ddSJeeja KP modules->src = NULL;
1209b8c722ddSJeeja KP modules->dst = NULL;
1210b8c722ddSJeeja KP kfree(modules);
1211b8c722ddSJeeja KP }
1212b8c722ddSJeeja KP }
1213b8c722ddSJeeja KP }
1214b8c722ddSJeeja KP
1215b8c722ddSJeeja KP list_for_each_entry(w_module, &s_pipe->w_list, node) {
1216d93f8e55SVinod Koul dst_module = w_module->w->priv;
1217d93f8e55SVinod Koul
1218d93f8e55SVinod Koul if (src_module == NULL) {
1219d93f8e55SVinod Koul src_module = dst_module;
1220d93f8e55SVinod Koul continue;
1221d93f8e55SVinod Koul }
1222d93f8e55SVinod Koul
1223bcc2a2dcSCezary Rojewski skl_unbind_modules(skl, src_module, dst_module);
1224d93f8e55SVinod Koul src_module = dst_module;
1225d93f8e55SVinod Koul }
1226d93f8e55SVinod Koul
1227bcc2a2dcSCezary Rojewski skl_delete_pipe(skl, mconfig->pipe);
1228d93f8e55SVinod Koul
1229473a4d51SJeeja KP list_for_each_entry(w_module, &s_pipe->w_list, node) {
1230473a4d51SJeeja KP src_module = w_module->w->priv;
1231473a4d51SJeeja KP src_module->m_state = SKL_MODULE_UNINIT;
1232473a4d51SJeeja KP }
1233473a4d51SJeeja KP
1234bcc2a2dcSCezary Rojewski return skl_tplg_unload_pipe_modules(skl, s_pipe);
1235d93f8e55SVinod Koul }
1236d93f8e55SVinod Koul
1237d93f8e55SVinod Koul /*
1238d93f8e55SVinod Koul * in the Post-PMD event of PGA we need to do following:
1239d93f8e55SVinod Koul * - Stop the pipeline
1240d93f8e55SVinod Koul * - In source pipe is connected, unbind with source pipelines
1241d93f8e55SVinod Koul */
skl_tplg_pga_dapm_post_pmd_event(struct snd_soc_dapm_widget * w,struct skl_dev * skl)1242d93f8e55SVinod Koul static int skl_tplg_pga_dapm_post_pmd_event(struct snd_soc_dapm_widget *w,
1243bcc2a2dcSCezary Rojewski struct skl_dev *skl)
1244d93f8e55SVinod Koul {
1245d93f8e55SVinod Koul struct skl_module_cfg *src_mconfig, *sink_mconfig;
1246ce1b5551SJeeja KP int ret = 0, i;
1247d93f8e55SVinod Koul
1248ce1b5551SJeeja KP src_mconfig = w->priv;
1249d93f8e55SVinod Koul
1250d93f8e55SVinod Koul /* Stop the pipe since this is a mixin module */
1251bcc2a2dcSCezary Rojewski ret = skl_stop_pipe(skl, src_mconfig->pipe);
1252d93f8e55SVinod Koul if (ret)
1253d93f8e55SVinod Koul return ret;
1254d93f8e55SVinod Koul
1255f6fa56e2SRamesh Babu for (i = 0; i < src_mconfig->module->max_output_pins; i++) {
1256ce1b5551SJeeja KP if (src_mconfig->m_out_pin[i].pin_state == SKL_PIN_BIND_DONE) {
1257ce1b5551SJeeja KP sink_mconfig = src_mconfig->m_out_pin[i].tgt_mcfg;
1258ce1b5551SJeeja KP if (!sink_mconfig)
1259ce1b5551SJeeja KP continue;
1260d93f8e55SVinod Koul /*
1261ce1b5551SJeeja KP * This is a connecter and if path is found that means
1262d93f8e55SVinod Koul * unbind between source and sink has not happened yet
1263d93f8e55SVinod Koul */
1264bcc2a2dcSCezary Rojewski ret = skl_unbind_modules(skl, src_mconfig,
1265ce1b5551SJeeja KP sink_mconfig);
1266ce1b5551SJeeja KP }
1267d93f8e55SVinod Koul }
1268d93f8e55SVinod Koul
1269d93f8e55SVinod Koul return ret;
1270d93f8e55SVinod Koul }
1271d93f8e55SVinod Koul
1272d93f8e55SVinod Koul /*
1273d93f8e55SVinod Koul * In modelling, we assume there will be ONLY one mixer in a pipeline. If a
1274d93f8e55SVinod Koul * second one is required that is created as another pipe entity.
1275d93f8e55SVinod Koul * The mixer is responsible for pipe management and represent a pipeline
1276d93f8e55SVinod Koul * instance
1277d93f8e55SVinod Koul */
skl_tplg_mixer_event(struct snd_soc_dapm_widget * w,struct snd_kcontrol * k,int event)1278d93f8e55SVinod Koul static int skl_tplg_mixer_event(struct snd_soc_dapm_widget *w,
1279d93f8e55SVinod Koul struct snd_kcontrol *k, int event)
1280d93f8e55SVinod Koul {
1281d93f8e55SVinod Koul struct snd_soc_dapm_context *dapm = w->dapm;
1282bcc2a2dcSCezary Rojewski struct skl_dev *skl = get_skl_ctx(dapm->dev);
1283d93f8e55SVinod Koul
1284d93f8e55SVinod Koul switch (event) {
1285d93f8e55SVinod Koul case SND_SOC_DAPM_PRE_PMU:
1286d93f8e55SVinod Koul return skl_tplg_mixer_dapm_pre_pmu_event(w, skl);
1287d93f8e55SVinod Koul
1288d93f8e55SVinod Koul case SND_SOC_DAPM_POST_PMU:
1289d93f8e55SVinod Koul return skl_tplg_mixer_dapm_post_pmu_event(w, skl);
1290d93f8e55SVinod Koul
1291d93f8e55SVinod Koul case SND_SOC_DAPM_PRE_PMD:
1292d93f8e55SVinod Koul return skl_tplg_mixer_dapm_pre_pmd_event(w, skl);
1293d93f8e55SVinod Koul
1294d93f8e55SVinod Koul case SND_SOC_DAPM_POST_PMD:
1295d93f8e55SVinod Koul return skl_tplg_mixer_dapm_post_pmd_event(w, skl);
1296d93f8e55SVinod Koul }
1297d93f8e55SVinod Koul
1298d93f8e55SVinod Koul return 0;
1299d93f8e55SVinod Koul }
1300d93f8e55SVinod Koul
1301d93f8e55SVinod Koul /*
1302d93f8e55SVinod Koul * In modelling, we assumed rest of the modules in pipeline are PGA. But we
1303d93f8e55SVinod Koul * are interested in last PGA (leaf PGA) in a pipeline to disconnect with
1304d93f8e55SVinod Koul * the sink when it is running (two FE to one BE or one FE to two BE)
1305d93f8e55SVinod Koul * scenarios
1306d93f8e55SVinod Koul */
skl_tplg_pga_event(struct snd_soc_dapm_widget * w,struct snd_kcontrol * k,int event)1307d93f8e55SVinod Koul static int skl_tplg_pga_event(struct snd_soc_dapm_widget *w,
1308d93f8e55SVinod Koul struct snd_kcontrol *k, int event)
1309d93f8e55SVinod Koul
1310d93f8e55SVinod Koul {
1311d93f8e55SVinod Koul struct snd_soc_dapm_context *dapm = w->dapm;
1312bcc2a2dcSCezary Rojewski struct skl_dev *skl = get_skl_ctx(dapm->dev);
1313d93f8e55SVinod Koul
1314d93f8e55SVinod Koul switch (event) {
1315d93f8e55SVinod Koul case SND_SOC_DAPM_PRE_PMU:
1316d93f8e55SVinod Koul return skl_tplg_pga_dapm_pre_pmu_event(w, skl);
1317d93f8e55SVinod Koul
1318d93f8e55SVinod Koul case SND_SOC_DAPM_POST_PMD:
1319d93f8e55SVinod Koul return skl_tplg_pga_dapm_post_pmd_event(w, skl);
1320d93f8e55SVinod Koul }
1321d93f8e55SVinod Koul
1322d93f8e55SVinod Koul return 0;
1323d93f8e55SVinod Koul }
1324cfb0a873SVinod Koul
skl_tplg_multi_config_set_get(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol,bool is_set)13251b450791SMateusz Gorski static int skl_tplg_multi_config_set_get(struct snd_kcontrol *kcontrol,
13261b450791SMateusz Gorski struct snd_ctl_elem_value *ucontrol,
13271b450791SMateusz Gorski bool is_set)
13281b450791SMateusz Gorski {
13291b450791SMateusz Gorski struct snd_soc_component *component =
13301b450791SMateusz Gorski snd_soc_kcontrol_component(kcontrol);
13311b450791SMateusz Gorski struct hdac_bus *bus = snd_soc_component_get_drvdata(component);
13321b450791SMateusz Gorski struct skl_dev *skl = bus_to_skl(bus);
13331b450791SMateusz Gorski struct skl_pipeline *ppl;
13341b450791SMateusz Gorski struct skl_pipe *pipe = NULL;
13351b450791SMateusz Gorski struct soc_enum *ec = (struct soc_enum *)kcontrol->private_value;
13361b450791SMateusz Gorski u32 *pipe_id;
13371b450791SMateusz Gorski
13381b450791SMateusz Gorski if (!ec)
13391b450791SMateusz Gorski return -EINVAL;
13401b450791SMateusz Gorski
13411b450791SMateusz Gorski if (is_set && ucontrol->value.enumerated.item[0] > ec->items)
13421b450791SMateusz Gorski return -EINVAL;
13431b450791SMateusz Gorski
13441b450791SMateusz Gorski pipe_id = ec->dobj.private;
13451b450791SMateusz Gorski
13461b450791SMateusz Gorski list_for_each_entry(ppl, &skl->ppl_list, node) {
13471b450791SMateusz Gorski if (ppl->pipe->ppl_id == *pipe_id) {
13481b450791SMateusz Gorski pipe = ppl->pipe;
13491b450791SMateusz Gorski break;
13501b450791SMateusz Gorski }
13511b450791SMateusz Gorski }
13521b450791SMateusz Gorski if (!pipe)
13531b450791SMateusz Gorski return -EIO;
13541b450791SMateusz Gorski
13551b450791SMateusz Gorski if (is_set)
13564ac587f3SCezary Rojewski skl_tplg_set_pipe_config_idx(pipe, ucontrol->value.enumerated.item[0]);
13571b450791SMateusz Gorski else
135875ab3c00SCezary Rojewski ucontrol->value.enumerated.item[0] = pipe->cur_config_idx;
13591b450791SMateusz Gorski
13601b450791SMateusz Gorski return 0;
13611b450791SMateusz Gorski }
13621b450791SMateusz Gorski
skl_tplg_multi_config_get(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)13631b450791SMateusz Gorski static int skl_tplg_multi_config_get(struct snd_kcontrol *kcontrol,
13641b450791SMateusz Gorski struct snd_ctl_elem_value *ucontrol)
13651b450791SMateusz Gorski {
13661b450791SMateusz Gorski return skl_tplg_multi_config_set_get(kcontrol, ucontrol, false);
13671b450791SMateusz Gorski }
13681b450791SMateusz Gorski
skl_tplg_multi_config_set(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)13691b450791SMateusz Gorski static int skl_tplg_multi_config_set(struct snd_kcontrol *kcontrol,
13701b450791SMateusz Gorski struct snd_ctl_elem_value *ucontrol)
13711b450791SMateusz Gorski {
13721b450791SMateusz Gorski return skl_tplg_multi_config_set_get(kcontrol, ucontrol, true);
13731b450791SMateusz Gorski }
13741b450791SMateusz Gorski
skl_tplg_multi_config_get_dmic(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)13752d744ecfSMateusz Gorski static int skl_tplg_multi_config_get_dmic(struct snd_kcontrol *kcontrol,
13762d744ecfSMateusz Gorski struct snd_ctl_elem_value *ucontrol)
13772d744ecfSMateusz Gorski {
13782d744ecfSMateusz Gorski return skl_tplg_multi_config_set_get(kcontrol, ucontrol, false);
13792d744ecfSMateusz Gorski }
13802d744ecfSMateusz Gorski
skl_tplg_multi_config_set_dmic(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)13812d744ecfSMateusz Gorski static int skl_tplg_multi_config_set_dmic(struct snd_kcontrol *kcontrol,
13822d744ecfSMateusz Gorski struct snd_ctl_elem_value *ucontrol)
13832d744ecfSMateusz Gorski {
13842d744ecfSMateusz Gorski return skl_tplg_multi_config_set_get(kcontrol, ucontrol, true);
13852d744ecfSMateusz Gorski }
13862d744ecfSMateusz Gorski
skl_tplg_tlv_control_get(struct snd_kcontrol * kcontrol,unsigned int __user * data,unsigned int size)1387140adfbaSJeeja KP static int skl_tplg_tlv_control_get(struct snd_kcontrol *kcontrol,
1388140adfbaSJeeja KP unsigned int __user *data, unsigned int size)
1389140adfbaSJeeja KP {
1390140adfbaSJeeja KP struct soc_bytes_ext *sb =
1391140adfbaSJeeja KP (struct soc_bytes_ext *)kcontrol->private_value;
1392140adfbaSJeeja KP struct skl_algo_data *bc = (struct skl_algo_data *)sb->dobj.private;
13937d9f2911SOmair M Abdullah struct snd_soc_dapm_widget *w = snd_soc_dapm_kcontrol_widget(kcontrol);
13947d9f2911SOmair M Abdullah struct skl_module_cfg *mconfig = w->priv;
1395bcc2a2dcSCezary Rojewski struct skl_dev *skl = get_skl_ctx(w->dapm->dev);
13967d9f2911SOmair M Abdullah
13977d9f2911SOmair M Abdullah if (w->power)
1398bcc2a2dcSCezary Rojewski skl_get_module_params(skl, (u32 *)bc->params,
13990d682104SDharageswari R bc->size, bc->param_id, mconfig);
1400140adfbaSJeeja KP
140141556f68SVinod Koul /* decrement size for TLV header */
140241556f68SVinod Koul size -= 2 * sizeof(u32);
140341556f68SVinod Koul
140441556f68SVinod Koul /* check size as we don't want to send kernel data */
140541556f68SVinod Koul if (size > bc->max)
140641556f68SVinod Koul size = bc->max;
140741556f68SVinod Koul
1408140adfbaSJeeja KP if (bc->params) {
1409140adfbaSJeeja KP if (copy_to_user(data, &bc->param_id, sizeof(u32)))
1410140adfbaSJeeja KP return -EFAULT;
1411e8bc3c99SDan Carpenter if (copy_to_user(data + 1, &size, sizeof(u32)))
1412140adfbaSJeeja KP return -EFAULT;
1413e8bc3c99SDan Carpenter if (copy_to_user(data + 2, bc->params, size))
1414140adfbaSJeeja KP return -EFAULT;
1415140adfbaSJeeja KP }
1416140adfbaSJeeja KP
1417140adfbaSJeeja KP return 0;
1418140adfbaSJeeja KP }
1419140adfbaSJeeja KP
1420140adfbaSJeeja KP #define SKL_PARAM_VENDOR_ID 0xff
1421140adfbaSJeeja KP
skl_tplg_tlv_control_set(struct snd_kcontrol * kcontrol,const unsigned int __user * data,unsigned int size)1422140adfbaSJeeja KP static int skl_tplg_tlv_control_set(struct snd_kcontrol *kcontrol,
1423140adfbaSJeeja KP const unsigned int __user *data, unsigned int size)
1424140adfbaSJeeja KP {
1425140adfbaSJeeja KP struct snd_soc_dapm_widget *w = snd_soc_dapm_kcontrol_widget(kcontrol);
1426140adfbaSJeeja KP struct skl_module_cfg *mconfig = w->priv;
1427140adfbaSJeeja KP struct soc_bytes_ext *sb =
1428140adfbaSJeeja KP (struct soc_bytes_ext *)kcontrol->private_value;
1429140adfbaSJeeja KP struct skl_algo_data *ac = (struct skl_algo_data *)sb->dobj.private;
1430bcc2a2dcSCezary Rojewski struct skl_dev *skl = get_skl_ctx(w->dapm->dev);
1431140adfbaSJeeja KP
1432140adfbaSJeeja KP if (ac->params) {
14330d682104SDharageswari R if (size > ac->max)
14340d682104SDharageswari R return -EINVAL;
14350d682104SDharageswari R ac->size = size;
1436a8cd7066SKamil Lulko
1437140adfbaSJeeja KP if (copy_from_user(ac->params, data, size))
1438140adfbaSJeeja KP return -EFAULT;
1439140adfbaSJeeja KP
1440140adfbaSJeeja KP if (w->power)
1441bcc2a2dcSCezary Rojewski return skl_set_module_params(skl,
14420d682104SDharageswari R (u32 *)ac->params, ac->size,
1443140adfbaSJeeja KP ac->param_id, mconfig);
1444140adfbaSJeeja KP }
1445140adfbaSJeeja KP
1446140adfbaSJeeja KP return 0;
1447140adfbaSJeeja KP }
1448140adfbaSJeeja KP
skl_tplg_mic_control_get(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)14497a1b749bSDharageswari R static int skl_tplg_mic_control_get(struct snd_kcontrol *kcontrol,
14507a1b749bSDharageswari R struct snd_ctl_elem_value *ucontrol)
14517a1b749bSDharageswari R {
14527a1b749bSDharageswari R struct snd_soc_dapm_widget *w = snd_soc_dapm_kcontrol_widget(kcontrol);
14537a1b749bSDharageswari R struct skl_module_cfg *mconfig = w->priv;
14547a1b749bSDharageswari R struct soc_enum *ec = (struct soc_enum *)kcontrol->private_value;
14557a1b749bSDharageswari R u32 ch_type = *((u32 *)ec->dobj.private);
14567a1b749bSDharageswari R
14577a1b749bSDharageswari R if (mconfig->dmic_ch_type == ch_type)
14587a1b749bSDharageswari R ucontrol->value.enumerated.item[0] =
14597a1b749bSDharageswari R mconfig->dmic_ch_combo_index;
14607a1b749bSDharageswari R else
14617a1b749bSDharageswari R ucontrol->value.enumerated.item[0] = 0;
14627a1b749bSDharageswari R
14637a1b749bSDharageswari R return 0;
14647a1b749bSDharageswari R }
14657a1b749bSDharageswari R
skl_fill_mic_sel_params(struct skl_module_cfg * mconfig,struct skl_mic_sel_config * mic_cfg,struct device * dev)14667a1b749bSDharageswari R static int skl_fill_mic_sel_params(struct skl_module_cfg *mconfig,
14677a1b749bSDharageswari R struct skl_mic_sel_config *mic_cfg, struct device *dev)
14687a1b749bSDharageswari R {
1469a4ad42d2SKareem Shaik struct skl_specific_cfg *sp_cfg =
1470a4ad42d2SKareem Shaik &mconfig->formats_config[SKL_PARAM_INIT];
14717a1b749bSDharageswari R
14727a1b749bSDharageswari R sp_cfg->caps_size = sizeof(struct skl_mic_sel_config);
14737a1b749bSDharageswari R sp_cfg->set_params = SKL_PARAM_SET;
14747a1b749bSDharageswari R sp_cfg->param_id = 0x00;
14757a1b749bSDharageswari R if (!sp_cfg->caps) {
14767a1b749bSDharageswari R sp_cfg->caps = devm_kzalloc(dev, sp_cfg->caps_size, GFP_KERNEL);
14777a1b749bSDharageswari R if (!sp_cfg->caps)
14787a1b749bSDharageswari R return -ENOMEM;
14797a1b749bSDharageswari R }
14807a1b749bSDharageswari R
14817a1b749bSDharageswari R mic_cfg->mic_switch = SKL_MIC_SEL_SWITCH;
14827a1b749bSDharageswari R mic_cfg->flags = 0;
14837a1b749bSDharageswari R memcpy(sp_cfg->caps, mic_cfg, sp_cfg->caps_size);
14847a1b749bSDharageswari R
14857a1b749bSDharageswari R return 0;
14867a1b749bSDharageswari R }
14877a1b749bSDharageswari R
skl_tplg_mic_control_set(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)14887a1b749bSDharageswari R static int skl_tplg_mic_control_set(struct snd_kcontrol *kcontrol,
14897a1b749bSDharageswari R struct snd_ctl_elem_value *ucontrol)
14907a1b749bSDharageswari R {
14917a1b749bSDharageswari R struct snd_soc_dapm_widget *w = snd_soc_dapm_kcontrol_widget(kcontrol);
14927a1b749bSDharageswari R struct skl_module_cfg *mconfig = w->priv;
14937a1b749bSDharageswari R struct skl_mic_sel_config mic_cfg = {0};
14947a1b749bSDharageswari R struct soc_enum *ec = (struct soc_enum *)kcontrol->private_value;
14957a1b749bSDharageswari R u32 ch_type = *((u32 *)ec->dobj.private);
14967a1b749bSDharageswari R const int *list;
14977a1b749bSDharageswari R u8 in_ch, out_ch, index;
14987a1b749bSDharageswari R
14997a1b749bSDharageswari R mconfig->dmic_ch_type = ch_type;
15007a1b749bSDharageswari R mconfig->dmic_ch_combo_index = ucontrol->value.enumerated.item[0];
15017a1b749bSDharageswari R
15027a1b749bSDharageswari R /* enum control index 0 is INVALID, so no channels to be set */
15037a1b749bSDharageswari R if (mconfig->dmic_ch_combo_index == 0)
15047a1b749bSDharageswari R return 0;
15057a1b749bSDharageswari R
15067a1b749bSDharageswari R /* No valid channel selection map for index 0, so offset by 1 */
15077a1b749bSDharageswari R index = mconfig->dmic_ch_combo_index - 1;
15087a1b749bSDharageswari R
15097a1b749bSDharageswari R switch (ch_type) {
15107a1b749bSDharageswari R case SKL_CH_MONO:
15117a1b749bSDharageswari R if (mconfig->dmic_ch_combo_index > ARRAY_SIZE(mic_mono_list))
15127a1b749bSDharageswari R return -EINVAL;
15137a1b749bSDharageswari R
15147a1b749bSDharageswari R list = &mic_mono_list[index];
15157a1b749bSDharageswari R break;
15167a1b749bSDharageswari R
15177a1b749bSDharageswari R case SKL_CH_STEREO:
15187a1b749bSDharageswari R if (mconfig->dmic_ch_combo_index > ARRAY_SIZE(mic_stereo_list))
15197a1b749bSDharageswari R return -EINVAL;
15207a1b749bSDharageswari R
15217a1b749bSDharageswari R list = mic_stereo_list[index];
15227a1b749bSDharageswari R break;
15237a1b749bSDharageswari R
15247a1b749bSDharageswari R case SKL_CH_TRIO:
15257a1b749bSDharageswari R if (mconfig->dmic_ch_combo_index > ARRAY_SIZE(mic_trio_list))
15267a1b749bSDharageswari R return -EINVAL;
15277a1b749bSDharageswari R
15287a1b749bSDharageswari R list = mic_trio_list[index];
15297a1b749bSDharageswari R break;
15307a1b749bSDharageswari R
15317a1b749bSDharageswari R case SKL_CH_QUATRO:
15327a1b749bSDharageswari R if (mconfig->dmic_ch_combo_index > ARRAY_SIZE(mic_quatro_list))
15337a1b749bSDharageswari R return -EINVAL;
15347a1b749bSDharageswari R
15357a1b749bSDharageswari R list = mic_quatro_list[index];
15367a1b749bSDharageswari R break;
15377a1b749bSDharageswari R
15387a1b749bSDharageswari R default:
15397a1b749bSDharageswari R dev_err(w->dapm->dev,
15407a1b749bSDharageswari R "Invalid channel %d for mic_select module\n",
15417a1b749bSDharageswari R ch_type);
15427a1b749bSDharageswari R return -EINVAL;
15437a1b749bSDharageswari R
15447a1b749bSDharageswari R }
15457a1b749bSDharageswari R
15467a1b749bSDharageswari R /* channel type enum map to number of chanels for that type */
15477a1b749bSDharageswari R for (out_ch = 0; out_ch < ch_type; out_ch++) {
15487a1b749bSDharageswari R in_ch = list[out_ch];
15497a1b749bSDharageswari R mic_cfg.blob[out_ch][in_ch] = SKL_DEFAULT_MIC_SEL_GAIN;
15507a1b749bSDharageswari R }
15517a1b749bSDharageswari R
15527a1b749bSDharageswari R return skl_fill_mic_sel_params(mconfig, &mic_cfg, w->dapm->dev);
15537a1b749bSDharageswari R }
15547a1b749bSDharageswari R
1555cfb0a873SVinod Koul /*
15568871dcb9SJeeja KP * Fill the dma id for host and link. In case of passthrough
15578871dcb9SJeeja KP * pipeline, this will both host and link in the same
15588871dcb9SJeeja KP * pipeline, so need to copy the link and host based on dev_type
15598871dcb9SJeeja KP */
skl_tplg_fill_dma_id(struct skl_module_cfg * mcfg,struct skl_pipe_params * params)15608871dcb9SJeeja KP static void skl_tplg_fill_dma_id(struct skl_module_cfg *mcfg,
15618871dcb9SJeeja KP struct skl_pipe_params *params)
15628871dcb9SJeeja KP {
15638871dcb9SJeeja KP struct skl_pipe *pipe = mcfg->pipe;
15648871dcb9SJeeja KP
15658871dcb9SJeeja KP if (pipe->passthru) {
15668871dcb9SJeeja KP switch (mcfg->dev_type) {
15678871dcb9SJeeja KP case SKL_DEVICE_HDALINK:
15688871dcb9SJeeja KP pipe->p_params->link_dma_id = params->link_dma_id;
156912c3be0eSJeeja KP pipe->p_params->link_index = params->link_index;
15707f975a38SJeeja KP pipe->p_params->link_bps = params->link_bps;
15718871dcb9SJeeja KP break;
15728871dcb9SJeeja KP
15738871dcb9SJeeja KP case SKL_DEVICE_HDAHOST:
15748871dcb9SJeeja KP pipe->p_params->host_dma_id = params->host_dma_id;
15757f975a38SJeeja KP pipe->p_params->host_bps = params->host_bps;
15768871dcb9SJeeja KP break;
15778871dcb9SJeeja KP
15788871dcb9SJeeja KP default:
15798871dcb9SJeeja KP break;
15808871dcb9SJeeja KP }
15818871dcb9SJeeja KP pipe->p_params->s_fmt = params->s_fmt;
15828871dcb9SJeeja KP pipe->p_params->ch = params->ch;
15838871dcb9SJeeja KP pipe->p_params->s_freq = params->s_freq;
15848871dcb9SJeeja KP pipe->p_params->stream = params->stream;
158512c3be0eSJeeja KP pipe->p_params->format = params->format;
15868871dcb9SJeeja KP
15878871dcb9SJeeja KP } else {
15888871dcb9SJeeja KP memcpy(pipe->p_params, params, sizeof(*params));
15898871dcb9SJeeja KP }
15908871dcb9SJeeja KP }
15918871dcb9SJeeja KP
15928871dcb9SJeeja KP /*
1593cfb0a873SVinod Koul * The FE params are passed by hw_params of the DAI.
1594cfb0a873SVinod Koul * On hw_params, the params are stored in Gateway module of the FE and we
1595cfb0a873SVinod Koul * need to calculate the format in DSP module configuration, that
1596cfb0a873SVinod Koul * conversion is done here
1597cfb0a873SVinod Koul */
skl_tplg_update_pipe_params(struct device * dev,struct skl_module_cfg * mconfig,struct skl_pipe_params * params)1598cfb0a873SVinod Koul int skl_tplg_update_pipe_params(struct device *dev,
1599cfb0a873SVinod Koul struct skl_module_cfg *mconfig,
1600cfb0a873SVinod Koul struct skl_pipe_params *params)
1601cfb0a873SVinod Koul {
1602e8b374b6SCezary Rojewski struct skl_module_res *res;
1603bcc2a2dcSCezary Rojewski struct skl_dev *skl = get_skl_ctx(dev);
1604cfb0a873SVinod Koul struct skl_module_fmt *format = NULL;
1605f6fa56e2SRamesh Babu u8 cfg_idx = mconfig->pipe->cur_config_idx;
1606cfb0a873SVinod Koul
1607e8b374b6SCezary Rojewski res = &mconfig->module->resources[mconfig->res_idx];
16088871dcb9SJeeja KP skl_tplg_fill_dma_id(mconfig, params);
1609f6fa56e2SRamesh Babu mconfig->fmt_idx = mconfig->mod_cfg[cfg_idx].fmt_idx;
1610f6fa56e2SRamesh Babu mconfig->res_idx = mconfig->mod_cfg[cfg_idx].res_idx;
1611f6fa56e2SRamesh Babu
1612f6fa56e2SRamesh Babu if (skl->nr_modules)
1613f6fa56e2SRamesh Babu return 0;
1614cfb0a873SVinod Koul
1615cfb0a873SVinod Koul if (params->stream == SNDRV_PCM_STREAM_PLAYBACK)
1616e8b374b6SCezary Rojewski format = &mconfig->module->formats[mconfig->fmt_idx].inputs[0].fmt;
1617cfb0a873SVinod Koul else
1618e8b374b6SCezary Rojewski format = &mconfig->module->formats[mconfig->fmt_idx].outputs[0].fmt;
1619cfb0a873SVinod Koul
1620cfb0a873SVinod Koul /* set the hw_params */
1621cfb0a873SVinod Koul format->s_freq = params->s_freq;
1622cfb0a873SVinod Koul format->channels = params->ch;
1623cfb0a873SVinod Koul format->valid_bit_depth = skl_get_bit_depth(params->s_fmt);
1624cfb0a873SVinod Koul
1625cfb0a873SVinod Koul /*
1626cfb0a873SVinod Koul * 16 bit is 16 bit container whereas 24 bit is in 32 bit
1627cfb0a873SVinod Koul * container so update bit depth accordingly
1628cfb0a873SVinod Koul */
1629cfb0a873SVinod Koul switch (format->valid_bit_depth) {
1630cfb0a873SVinod Koul case SKL_DEPTH_16BIT:
1631cfb0a873SVinod Koul format->bit_depth = format->valid_bit_depth;
1632cfb0a873SVinod Koul break;
1633cfb0a873SVinod Koul
1634cfb0a873SVinod Koul case SKL_DEPTH_24BIT:
16356654f39eSJeeja KP case SKL_DEPTH_32BIT:
1636cfb0a873SVinod Koul format->bit_depth = SKL_DEPTH_32BIT;
1637cfb0a873SVinod Koul break;
1638cfb0a873SVinod Koul
1639cfb0a873SVinod Koul default:
1640cfb0a873SVinod Koul dev_err(dev, "Invalid bit depth %x for pipe\n",
1641cfb0a873SVinod Koul format->valid_bit_depth);
1642cfb0a873SVinod Koul return -EINVAL;
1643cfb0a873SVinod Koul }
1644cfb0a873SVinod Koul
1645cfb0a873SVinod Koul if (params->stream == SNDRV_PCM_STREAM_PLAYBACK) {
1646f6fa56e2SRamesh Babu res->ibs = (format->s_freq / 1000) *
1647cfb0a873SVinod Koul (format->channels) *
1648cfb0a873SVinod Koul (format->bit_depth >> 3);
1649cfb0a873SVinod Koul } else {
1650f6fa56e2SRamesh Babu res->obs = (format->s_freq / 1000) *
1651cfb0a873SVinod Koul (format->channels) *
1652cfb0a873SVinod Koul (format->bit_depth >> 3);
1653cfb0a873SVinod Koul }
1654cfb0a873SVinod Koul
1655cfb0a873SVinod Koul return 0;
1656cfb0a873SVinod Koul }
1657cfb0a873SVinod Koul
1658cfb0a873SVinod Koul /*
1659cfb0a873SVinod Koul * Query the module config for the FE DAI
1660cfb0a873SVinod Koul * This is used to find the hw_params set for that DAI and apply to FE
1661cfb0a873SVinod Koul * pipeline
1662cfb0a873SVinod Koul */
1663cfb0a873SVinod Koul struct skl_module_cfg *
skl_tplg_fe_get_cpr_module(struct snd_soc_dai * dai,int stream)1664cfb0a873SVinod Koul skl_tplg_fe_get_cpr_module(struct snd_soc_dai *dai, int stream)
1665cfb0a873SVinod Koul {
1666*ec4b2099SKuninori Morimoto struct snd_soc_dapm_widget *w = snd_soc_dai_get_widget(dai, stream);
1667cfb0a873SVinod Koul struct snd_soc_dapm_path *p = NULL;
1668cfb0a873SVinod Koul
1669cfb0a873SVinod Koul if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
1670f0900eb2SSubhransu S. Prusty snd_soc_dapm_widget_for_each_sink_path(w, p) {
1671cfb0a873SVinod Koul if (p->connect && p->sink->power &&
1672cb1f904dSGuneshwor Singh !is_skl_dsp_widget_type(p->sink, dai->dev))
1673cfb0a873SVinod Koul continue;
1674cfb0a873SVinod Koul
1675cfb0a873SVinod Koul if (p->sink->priv) {
1676cfb0a873SVinod Koul dev_dbg(dai->dev, "set params for %s\n",
1677cfb0a873SVinod Koul p->sink->name);
1678cfb0a873SVinod Koul return p->sink->priv;
1679cfb0a873SVinod Koul }
1680cfb0a873SVinod Koul }
1681cfb0a873SVinod Koul } else {
1682f0900eb2SSubhransu S. Prusty snd_soc_dapm_widget_for_each_source_path(w, p) {
1683cfb0a873SVinod Koul if (p->connect && p->source->power &&
1684cb1f904dSGuneshwor Singh !is_skl_dsp_widget_type(p->source, dai->dev))
1685cfb0a873SVinod Koul continue;
1686cfb0a873SVinod Koul
1687cfb0a873SVinod Koul if (p->source->priv) {
1688cfb0a873SVinod Koul dev_dbg(dai->dev, "set params for %s\n",
1689cfb0a873SVinod Koul p->source->name);
1690cfb0a873SVinod Koul return p->source->priv;
1691cfb0a873SVinod Koul }
1692cfb0a873SVinod Koul }
1693cfb0a873SVinod Koul }
1694cfb0a873SVinod Koul
1695cfb0a873SVinod Koul return NULL;
1696cfb0a873SVinod Koul }
1697cfb0a873SVinod Koul
skl_get_mconfig_pb_cpr(struct snd_soc_dai * dai,struct snd_soc_dapm_widget * w)1698718a42b5SDharageswari.R static struct skl_module_cfg *skl_get_mconfig_pb_cpr(
1699718a42b5SDharageswari.R struct snd_soc_dai *dai, struct snd_soc_dapm_widget *w)
1700718a42b5SDharageswari.R {
1701718a42b5SDharageswari.R struct snd_soc_dapm_path *p;
1702718a42b5SDharageswari.R struct skl_module_cfg *mconfig = NULL;
1703718a42b5SDharageswari.R
1704718a42b5SDharageswari.R snd_soc_dapm_widget_for_each_source_path(w, p) {
1705718a42b5SDharageswari.R if (w->endpoints[SND_SOC_DAPM_DIR_OUT] > 0) {
1706718a42b5SDharageswari.R if (p->connect &&
1707718a42b5SDharageswari.R (p->sink->id == snd_soc_dapm_aif_out) &&
1708718a42b5SDharageswari.R p->source->priv) {
1709718a42b5SDharageswari.R mconfig = p->source->priv;
1710718a42b5SDharageswari.R return mconfig;
1711718a42b5SDharageswari.R }
1712718a42b5SDharageswari.R mconfig = skl_get_mconfig_pb_cpr(dai, p->source);
1713718a42b5SDharageswari.R if (mconfig)
1714718a42b5SDharageswari.R return mconfig;
1715718a42b5SDharageswari.R }
1716718a42b5SDharageswari.R }
1717718a42b5SDharageswari.R return mconfig;
1718718a42b5SDharageswari.R }
1719718a42b5SDharageswari.R
skl_get_mconfig_cap_cpr(struct snd_soc_dai * dai,struct snd_soc_dapm_widget * w)1720718a42b5SDharageswari.R static struct skl_module_cfg *skl_get_mconfig_cap_cpr(
1721718a42b5SDharageswari.R struct snd_soc_dai *dai, struct snd_soc_dapm_widget *w)
1722718a42b5SDharageswari.R {
1723718a42b5SDharageswari.R struct snd_soc_dapm_path *p;
1724718a42b5SDharageswari.R struct skl_module_cfg *mconfig = NULL;
1725718a42b5SDharageswari.R
1726718a42b5SDharageswari.R snd_soc_dapm_widget_for_each_sink_path(w, p) {
1727718a42b5SDharageswari.R if (w->endpoints[SND_SOC_DAPM_DIR_IN] > 0) {
1728718a42b5SDharageswari.R if (p->connect &&
1729718a42b5SDharageswari.R (p->source->id == snd_soc_dapm_aif_in) &&
1730718a42b5SDharageswari.R p->sink->priv) {
1731718a42b5SDharageswari.R mconfig = p->sink->priv;
1732718a42b5SDharageswari.R return mconfig;
1733718a42b5SDharageswari.R }
1734718a42b5SDharageswari.R mconfig = skl_get_mconfig_cap_cpr(dai, p->sink);
1735718a42b5SDharageswari.R if (mconfig)
1736718a42b5SDharageswari.R return mconfig;
1737718a42b5SDharageswari.R }
1738718a42b5SDharageswari.R }
1739718a42b5SDharageswari.R return mconfig;
1740718a42b5SDharageswari.R }
1741718a42b5SDharageswari.R
1742718a42b5SDharageswari.R struct skl_module_cfg *
skl_tplg_be_get_cpr_module(struct snd_soc_dai * dai,int stream)1743718a42b5SDharageswari.R skl_tplg_be_get_cpr_module(struct snd_soc_dai *dai, int stream)
1744718a42b5SDharageswari.R {
1745*ec4b2099SKuninori Morimoto struct snd_soc_dapm_widget *w = snd_soc_dai_get_widget(dai, stream);
1746718a42b5SDharageswari.R struct skl_module_cfg *mconfig;
1747718a42b5SDharageswari.R
1748718a42b5SDharageswari.R if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
1749718a42b5SDharageswari.R mconfig = skl_get_mconfig_pb_cpr(dai, w);
1750718a42b5SDharageswari.R } else {
1751718a42b5SDharageswari.R mconfig = skl_get_mconfig_cap_cpr(dai, w);
1752718a42b5SDharageswari.R }
1753718a42b5SDharageswari.R return mconfig;
1754718a42b5SDharageswari.R }
1755718a42b5SDharageswari.R
skl_tplg_be_link_type(int dev_type)1756cfb0a873SVinod Koul static u8 skl_tplg_be_link_type(int dev_type)
1757cfb0a873SVinod Koul {
1758cfb0a873SVinod Koul int ret;
1759cfb0a873SVinod Koul
1760cfb0a873SVinod Koul switch (dev_type) {
1761cfb0a873SVinod Koul case SKL_DEVICE_BT:
1762cfb0a873SVinod Koul ret = NHLT_LINK_SSP;
1763cfb0a873SVinod Koul break;
1764cfb0a873SVinod Koul
1765cfb0a873SVinod Koul case SKL_DEVICE_DMIC:
1766cfb0a873SVinod Koul ret = NHLT_LINK_DMIC;
1767cfb0a873SVinod Koul break;
1768cfb0a873SVinod Koul
1769cfb0a873SVinod Koul case SKL_DEVICE_I2S:
1770cfb0a873SVinod Koul ret = NHLT_LINK_SSP;
1771cfb0a873SVinod Koul break;
1772cfb0a873SVinod Koul
1773cfb0a873SVinod Koul case SKL_DEVICE_HDALINK:
1774cfb0a873SVinod Koul ret = NHLT_LINK_HDA;
1775cfb0a873SVinod Koul break;
1776cfb0a873SVinod Koul
1777cfb0a873SVinod Koul default:
1778cfb0a873SVinod Koul ret = NHLT_LINK_INVALID;
1779cfb0a873SVinod Koul break;
1780cfb0a873SVinod Koul }
1781cfb0a873SVinod Koul
1782cfb0a873SVinod Koul return ret;
1783cfb0a873SVinod Koul }
1784cfb0a873SVinod Koul
1785cfb0a873SVinod Koul /*
1786cfb0a873SVinod Koul * Fill the BE gateway parameters
1787cfb0a873SVinod Koul * The BE gateway expects a blob of parameters which are kept in the ACPI
1788cfb0a873SVinod Koul * NHLT blob, so query the blob for interface type (i2s/pdm) and instance.
178987b26526SPiotr Maziarz * The port can have multiple settings so pick based on the pipeline
1790cfb0a873SVinod Koul * parameters
1791cfb0a873SVinod Koul */
skl_tplg_be_fill_pipe_params(struct snd_soc_dai * dai,struct skl_module_cfg * mconfig,struct skl_pipe_params * params)1792cfb0a873SVinod Koul static int skl_tplg_be_fill_pipe_params(struct snd_soc_dai *dai,
1793cfb0a873SVinod Koul struct skl_module_cfg *mconfig,
1794cfb0a873SVinod Koul struct skl_pipe_params *params)
1795cfb0a873SVinod Koul {
1796cfb0a873SVinod Koul struct nhlt_specific_cfg *cfg;
179787b26526SPiotr Maziarz struct skl_pipe *pipe = mconfig->pipe;
179872d9a541SCezary Rojewski struct skl_pipe_params save = *pipe->p_params;
179987b26526SPiotr Maziarz struct skl_pipe_fmt *pipe_fmt;
1800bcc2a2dcSCezary Rojewski struct skl_dev *skl = get_skl_ctx(dai->dev);
1801cfb0a873SVinod Koul int link_type = skl_tplg_be_link_type(mconfig->dev_type);
1802db2f586bSSenthilnathan Veppur u8 dev_type = skl_tplg_be_dev_type(mconfig->dev_type);
180372d9a541SCezary Rojewski int ret;
1804cfb0a873SVinod Koul
18058871dcb9SJeeja KP skl_tplg_fill_dma_id(mconfig, params);
1806cfb0a873SVinod Koul
1807b30c275eSJeeja KP if (link_type == NHLT_LINK_HDA)
1808b30c275eSJeeja KP return 0;
1809b30c275eSJeeja KP
181072d9a541SCezary Rojewski *pipe->p_params = *params;
181172d9a541SCezary Rojewski ret = skl_tplg_get_pipe_config(skl, mconfig);
181272d9a541SCezary Rojewski if (ret)
181372d9a541SCezary Rojewski goto err;
181472d9a541SCezary Rojewski
181575ab3c00SCezary Rojewski dev_dbg(skl->dev, "%s using pipe config: %d\n", __func__, pipe->cur_config_idx);
181687b26526SPiotr Maziarz if (pipe->direction == SNDRV_PCM_STREAM_PLAYBACK)
181775ab3c00SCezary Rojewski pipe_fmt = &pipe->configs[pipe->cur_config_idx].out_fmt;
181887b26526SPiotr Maziarz else
181975ab3c00SCezary Rojewski pipe_fmt = &pipe->configs[pipe->cur_config_idx].in_fmt;
182087b26526SPiotr Maziarz
1821cfb0a873SVinod Koul /* update the blob based on virtual bus_id*/
1822322fa431SAmadeusz Sławiński cfg = intel_nhlt_get_endpoint_blob(dai->dev, skl->nhlt,
1823322fa431SAmadeusz Sławiński mconfig->vbus_id, link_type,
1824322fa431SAmadeusz Sławiński pipe_fmt->bps, params->s_cont,
1825322fa431SAmadeusz Sławiński pipe_fmt->channels, pipe_fmt->freq,
1826322fa431SAmadeusz Sławiński pipe->direction, dev_type);
1827cfb0a873SVinod Koul if (cfg) {
1828a4ad42d2SKareem Shaik mconfig->formats_config[SKL_PARAM_INIT].caps_size = cfg->size;
1829a4ad42d2SKareem Shaik mconfig->formats_config[SKL_PARAM_INIT].caps = (u32 *)&cfg->caps;
1830cfb0a873SVinod Koul } else {
183187b26526SPiotr Maziarz dev_err(dai->dev, "Blob NULL for id:%d type:%d dirn:%d ch:%d, freq:%d, fmt:%d\n",
183287b26526SPiotr Maziarz mconfig->vbus_id, link_type, params->stream,
1833cfb0a873SVinod Koul params->ch, params->s_freq, params->s_fmt);
183472d9a541SCezary Rojewski ret = -EINVAL;
183572d9a541SCezary Rojewski goto err;
1836cfb0a873SVinod Koul }
1837cfb0a873SVinod Koul
1838cfb0a873SVinod Koul return 0;
183972d9a541SCezary Rojewski
184072d9a541SCezary Rojewski err:
184172d9a541SCezary Rojewski *pipe->p_params = save;
184272d9a541SCezary Rojewski return ret;
1843cfb0a873SVinod Koul }
1844cfb0a873SVinod Koul
skl_tplg_be_set_src_pipe_params(struct snd_soc_dai * dai,struct snd_soc_dapm_widget * w,struct skl_pipe_params * params)1845cfb0a873SVinod Koul static int skl_tplg_be_set_src_pipe_params(struct snd_soc_dai *dai,
1846cfb0a873SVinod Koul struct snd_soc_dapm_widget *w,
1847cfb0a873SVinod Koul struct skl_pipe_params *params)
1848cfb0a873SVinod Koul {
1849cfb0a873SVinod Koul struct snd_soc_dapm_path *p;
18504d8adccbSSubhransu S. Prusty int ret = -EIO;
1851cfb0a873SVinod Koul
1852f0900eb2SSubhransu S. Prusty snd_soc_dapm_widget_for_each_source_path(w, p) {
1853cb1f904dSGuneshwor Singh if (p->connect && is_skl_dsp_widget_type(p->source, dai->dev) &&
1854cfb0a873SVinod Koul p->source->priv) {
1855cfb0a873SVinod Koul
18569a03cb49SJeeja KP ret = skl_tplg_be_fill_pipe_params(dai,
18579a03cb49SJeeja KP p->source->priv, params);
18584d8adccbSSubhransu S. Prusty if (ret < 0)
18594d8adccbSSubhransu S. Prusty return ret;
1860cfb0a873SVinod Koul } else {
18619a03cb49SJeeja KP ret = skl_tplg_be_set_src_pipe_params(dai,
18629a03cb49SJeeja KP p->source, params);
18634d8adccbSSubhransu S. Prusty if (ret < 0)
18644d8adccbSSubhransu S. Prusty return ret;
1865cfb0a873SVinod Koul }
1866cfb0a873SVinod Koul }
1867cfb0a873SVinod Koul
18684d8adccbSSubhransu S. Prusty return ret;
1869cfb0a873SVinod Koul }
1870cfb0a873SVinod Koul
skl_tplg_be_set_sink_pipe_params(struct snd_soc_dai * dai,struct snd_soc_dapm_widget * w,struct skl_pipe_params * params)1871cfb0a873SVinod Koul static int skl_tplg_be_set_sink_pipe_params(struct snd_soc_dai *dai,
1872cfb0a873SVinod Koul struct snd_soc_dapm_widget *w, struct skl_pipe_params *params)
1873cfb0a873SVinod Koul {
187425722cf6SPierre-Louis Bossart struct snd_soc_dapm_path *p;
18754d8adccbSSubhransu S. Prusty int ret = -EIO;
1876cfb0a873SVinod Koul
1877f0900eb2SSubhransu S. Prusty snd_soc_dapm_widget_for_each_sink_path(w, p) {
1878cb1f904dSGuneshwor Singh if (p->connect && is_skl_dsp_widget_type(p->sink, dai->dev) &&
1879cfb0a873SVinod Koul p->sink->priv) {
1880cfb0a873SVinod Koul
18819a03cb49SJeeja KP ret = skl_tplg_be_fill_pipe_params(dai,
18829a03cb49SJeeja KP p->sink->priv, params);
18834d8adccbSSubhransu S. Prusty if (ret < 0)
18844d8adccbSSubhransu S. Prusty return ret;
18854d8adccbSSubhransu S. Prusty } else {
18864d8adccbSSubhransu S. Prusty ret = skl_tplg_be_set_sink_pipe_params(
1887cfb0a873SVinod Koul dai, p->sink, params);
18884d8adccbSSubhransu S. Prusty if (ret < 0)
18894d8adccbSSubhransu S. Prusty return ret;
1890cfb0a873SVinod Koul }
1891cfb0a873SVinod Koul }
1892cfb0a873SVinod Koul
18934d8adccbSSubhransu S. Prusty return ret;
1894cfb0a873SVinod Koul }
1895cfb0a873SVinod Koul
1896cfb0a873SVinod Koul /*
1897cfb0a873SVinod Koul * BE hw_params can be a source parameters (capture) or sink parameters
1898cfb0a873SVinod Koul * (playback). Based on sink and source we need to either find the source
1899cfb0a873SVinod Koul * list or the sink list and set the pipeline parameters
1900cfb0a873SVinod Koul */
skl_tplg_be_update_params(struct snd_soc_dai * dai,struct skl_pipe_params * params)1901cfb0a873SVinod Koul int skl_tplg_be_update_params(struct snd_soc_dai *dai,
1902cfb0a873SVinod Koul struct skl_pipe_params *params)
1903cfb0a873SVinod Koul {
1904*ec4b2099SKuninori Morimoto struct snd_soc_dapm_widget *w = snd_soc_dai_get_widget(dai, params->stream);
1905cfb0a873SVinod Koul
1906cfb0a873SVinod Koul if (params->stream == SNDRV_PCM_STREAM_PLAYBACK) {
1907cfb0a873SVinod Koul return skl_tplg_be_set_src_pipe_params(dai, w, params);
1908cfb0a873SVinod Koul } else {
1909cfb0a873SVinod Koul return skl_tplg_be_set_sink_pipe_params(dai, w, params);
1910cfb0a873SVinod Koul }
1911cfb0a873SVinod Koul }
19123af36706SVinod Koul
19133af36706SVinod Koul static const struct snd_soc_tplg_widget_events skl_tplg_widget_ops[] = {
19143af36706SVinod Koul {SKL_MIXER_EVENT, skl_tplg_mixer_event},
19159a1e3507SVinod Koul {SKL_VMIXER_EVENT, skl_tplg_mixer_event},
19163af36706SVinod Koul {SKL_PGA_EVENT, skl_tplg_pga_event},
19173af36706SVinod Koul };
19183af36706SVinod Koul
1919140adfbaSJeeja KP static const struct snd_soc_tplg_bytes_ext_ops skl_tlv_ops[] = {
1920140adfbaSJeeja KP {SKL_CONTROL_TYPE_BYTE_TLV, skl_tplg_tlv_control_get,
1921140adfbaSJeeja KP skl_tplg_tlv_control_set},
1922140adfbaSJeeja KP };
1923140adfbaSJeeja KP
19247a1b749bSDharageswari R static const struct snd_soc_tplg_kcontrol_ops skl_tplg_kcontrol_ops[] = {
19257a1b749bSDharageswari R {
19267a1b749bSDharageswari R .id = SKL_CONTROL_TYPE_MIC_SELECT,
19277a1b749bSDharageswari R .get = skl_tplg_mic_control_get,
19287a1b749bSDharageswari R .put = skl_tplg_mic_control_set,
19297a1b749bSDharageswari R },
19301b450791SMateusz Gorski {
19311b450791SMateusz Gorski .id = SKL_CONTROL_TYPE_MULTI_IO_SELECT,
19321b450791SMateusz Gorski .get = skl_tplg_multi_config_get,
19331b450791SMateusz Gorski .put = skl_tplg_multi_config_set,
19341b450791SMateusz Gorski },
19352d744ecfSMateusz Gorski {
19362d744ecfSMateusz Gorski .id = SKL_CONTROL_TYPE_MULTI_IO_SELECT_DMIC,
19372d744ecfSMateusz Gorski .get = skl_tplg_multi_config_get_dmic,
19382d744ecfSMateusz Gorski .put = skl_tplg_multi_config_set_dmic,
19392d744ecfSMateusz Gorski }
19407a1b749bSDharageswari R };
19417a1b749bSDharageswari R
skl_tplg_fill_pipe_cfg(struct device * dev,struct skl_pipe * pipe,u32 tkn,u32 tkn_val,int conf_idx,int dir)1942f6fa56e2SRamesh Babu static int skl_tplg_fill_pipe_cfg(struct device *dev,
1943f6fa56e2SRamesh Babu struct skl_pipe *pipe, u32 tkn,
1944f6fa56e2SRamesh Babu u32 tkn_val, int conf_idx, int dir)
1945f6fa56e2SRamesh Babu {
1946f6fa56e2SRamesh Babu struct skl_pipe_fmt *fmt;
1947f6fa56e2SRamesh Babu struct skl_path_config *config;
1948f6fa56e2SRamesh Babu
1949f6fa56e2SRamesh Babu switch (dir) {
1950f6fa56e2SRamesh Babu case SKL_DIR_IN:
1951f6fa56e2SRamesh Babu fmt = &pipe->configs[conf_idx].in_fmt;
1952f6fa56e2SRamesh Babu break;
1953f6fa56e2SRamesh Babu
1954f6fa56e2SRamesh Babu case SKL_DIR_OUT:
1955f6fa56e2SRamesh Babu fmt = &pipe->configs[conf_idx].out_fmt;
1956f6fa56e2SRamesh Babu break;
1957f6fa56e2SRamesh Babu
1958f6fa56e2SRamesh Babu default:
1959f6fa56e2SRamesh Babu dev_err(dev, "Invalid direction: %d\n", dir);
1960f6fa56e2SRamesh Babu return -EINVAL;
1961f6fa56e2SRamesh Babu }
1962f6fa56e2SRamesh Babu
1963f6fa56e2SRamesh Babu config = &pipe->configs[conf_idx];
1964f6fa56e2SRamesh Babu
1965f6fa56e2SRamesh Babu switch (tkn) {
1966f6fa56e2SRamesh Babu case SKL_TKN_U32_CFG_FREQ:
1967f6fa56e2SRamesh Babu fmt->freq = tkn_val;
1968f6fa56e2SRamesh Babu break;
1969f6fa56e2SRamesh Babu
1970f6fa56e2SRamesh Babu case SKL_TKN_U8_CFG_CHAN:
1971f6fa56e2SRamesh Babu fmt->channels = tkn_val;
1972f6fa56e2SRamesh Babu break;
1973f6fa56e2SRamesh Babu
1974f6fa56e2SRamesh Babu case SKL_TKN_U8_CFG_BPS:
1975f6fa56e2SRamesh Babu fmt->bps = tkn_val;
1976f6fa56e2SRamesh Babu break;
1977f6fa56e2SRamesh Babu
1978f6fa56e2SRamesh Babu case SKL_TKN_U32_PATH_MEM_PGS:
1979f6fa56e2SRamesh Babu config->mem_pages = tkn_val;
1980f6fa56e2SRamesh Babu break;
1981f6fa56e2SRamesh Babu
1982f6fa56e2SRamesh Babu default:
1983f6fa56e2SRamesh Babu dev_err(dev, "Invalid token config: %d\n", tkn);
1984f6fa56e2SRamesh Babu return -EINVAL;
1985f6fa56e2SRamesh Babu }
1986f6fa56e2SRamesh Babu
1987f6fa56e2SRamesh Babu return 0;
1988f6fa56e2SRamesh Babu }
1989f6fa56e2SRamesh Babu
skl_tplg_fill_pipe_tkn(struct device * dev,struct skl_pipe * pipe,u32 tkn,u32 tkn_val)19906277e832SShreyas NC static int skl_tplg_fill_pipe_tkn(struct device *dev,
19916277e832SShreyas NC struct skl_pipe *pipe, u32 tkn,
19926277e832SShreyas NC u32 tkn_val)
19933af36706SVinod Koul {
19943af36706SVinod Koul
19956277e832SShreyas NC switch (tkn) {
19966277e832SShreyas NC case SKL_TKN_U32_PIPE_CONN_TYPE:
19976277e832SShreyas NC pipe->conn_type = tkn_val;
19986277e832SShreyas NC break;
19996277e832SShreyas NC
20006277e832SShreyas NC case SKL_TKN_U32_PIPE_PRIORITY:
20016277e832SShreyas NC pipe->pipe_priority = tkn_val;
20026277e832SShreyas NC break;
20036277e832SShreyas NC
20046277e832SShreyas NC case SKL_TKN_U32_PIPE_MEM_PGS:
20056277e832SShreyas NC pipe->memory_pages = tkn_val;
20066277e832SShreyas NC break;
20076277e832SShreyas NC
20088a0cb236SVinod Koul case SKL_TKN_U32_PMODE:
20098a0cb236SVinod Koul pipe->lp_mode = tkn_val;
20108a0cb236SVinod Koul break;
20118a0cb236SVinod Koul
2012f6fa56e2SRamesh Babu case SKL_TKN_U32_PIPE_DIRECTION:
2013f6fa56e2SRamesh Babu pipe->direction = tkn_val;
2014f6fa56e2SRamesh Babu break;
2015f6fa56e2SRamesh Babu
2016f6fa56e2SRamesh Babu case SKL_TKN_U32_NUM_CONFIGS:
2017f6fa56e2SRamesh Babu pipe->nr_cfgs = tkn_val;
2018f6fa56e2SRamesh Babu break;
2019f6fa56e2SRamesh Babu
20206277e832SShreyas NC default:
20216277e832SShreyas NC dev_err(dev, "Token not handled %d\n", tkn);
20226277e832SShreyas NC return -EINVAL;
20233af36706SVinod Koul }
20246277e832SShreyas NC
20256277e832SShreyas NC return 0;
20263af36706SVinod Koul }
20273af36706SVinod Koul
20283af36706SVinod Koul /*
20296277e832SShreyas NC * Add pipeline by parsing the relevant tokens
20306277e832SShreyas NC * Return an existing pipe if the pipe already exists.
20313af36706SVinod Koul */
skl_tplg_add_pipe(struct device * dev,struct skl_module_cfg * mconfig,struct skl_dev * skl,struct snd_soc_tplg_vendor_value_elem * tkn_elem)20326277e832SShreyas NC static int skl_tplg_add_pipe(struct device *dev,
2033bcc2a2dcSCezary Rojewski struct skl_module_cfg *mconfig, struct skl_dev *skl,
20346277e832SShreyas NC struct snd_soc_tplg_vendor_value_elem *tkn_elem)
20353af36706SVinod Koul {
20363af36706SVinod Koul struct skl_pipeline *ppl;
20373af36706SVinod Koul struct skl_pipe *pipe;
20383af36706SVinod Koul struct skl_pipe_params *params;
20393af36706SVinod Koul
20403af36706SVinod Koul list_for_each_entry(ppl, &skl->ppl_list, node) {
20416277e832SShreyas NC if (ppl->pipe->ppl_id == tkn_elem->value) {
20426277e832SShreyas NC mconfig->pipe = ppl->pipe;
2043081dc8abSGuneshwor Singh return -EEXIST;
20446277e832SShreyas NC }
20453af36706SVinod Koul }
20463af36706SVinod Koul
20473af36706SVinod Koul ppl = devm_kzalloc(dev, sizeof(*ppl), GFP_KERNEL);
20483af36706SVinod Koul if (!ppl)
20496277e832SShreyas NC return -ENOMEM;
20503af36706SVinod Koul
20513af36706SVinod Koul pipe = devm_kzalloc(dev, sizeof(*pipe), GFP_KERNEL);
20523af36706SVinod Koul if (!pipe)
20536277e832SShreyas NC return -ENOMEM;
20543af36706SVinod Koul
20553af36706SVinod Koul params = devm_kzalloc(dev, sizeof(*params), GFP_KERNEL);
20563af36706SVinod Koul if (!params)
20576277e832SShreyas NC return -ENOMEM;
20583af36706SVinod Koul
20593af36706SVinod Koul pipe->p_params = params;
20606277e832SShreyas NC pipe->ppl_id = tkn_elem->value;
20613af36706SVinod Koul INIT_LIST_HEAD(&pipe->w_list);
20623af36706SVinod Koul
20633af36706SVinod Koul ppl->pipe = pipe;
20643af36706SVinod Koul list_add(&ppl->node, &skl->ppl_list);
20653af36706SVinod Koul
20666277e832SShreyas NC mconfig->pipe = pipe;
20676277e832SShreyas NC mconfig->pipe->state = SKL_PIPE_INVALID;
20686277e832SShreyas NC
20696277e832SShreyas NC return 0;
20703af36706SVinod Koul }
20713af36706SVinod Koul
skl_tplg_get_uuid(struct device * dev,guid_t * guid,struct snd_soc_tplg_vendor_uuid_elem * uuid_tkn)20729e0784d0SAndy Shevchenko static int skl_tplg_get_uuid(struct device *dev, guid_t *guid,
207322ebd666SSriram Periyasamy struct snd_soc_tplg_vendor_uuid_elem *uuid_tkn)
20746277e832SShreyas NC {
207522ebd666SSriram Periyasamy if (uuid_tkn->token == SKL_TKN_UUID) {
2076cade2f59SAndy Shevchenko import_guid(guid, uuid_tkn->uuid);
207722ebd666SSriram Periyasamy return 0;
207822ebd666SSriram Periyasamy }
207922ebd666SSriram Periyasamy
208022ebd666SSriram Periyasamy dev_err(dev, "Not an UUID token %d\n", uuid_tkn->token);
208122ebd666SSriram Periyasamy
208222ebd666SSriram Periyasamy return -EINVAL;
208322ebd666SSriram Periyasamy }
208422ebd666SSriram Periyasamy
skl_tplg_fill_pin(struct device * dev,struct snd_soc_tplg_vendor_value_elem * tkn_elem,struct skl_module_pin * m_pin,int pin_index)208522ebd666SSriram Periyasamy static int skl_tplg_fill_pin(struct device *dev,
208622ebd666SSriram Periyasamy struct snd_soc_tplg_vendor_value_elem *tkn_elem,
208722ebd666SSriram Periyasamy struct skl_module_pin *m_pin,
208822ebd666SSriram Periyasamy int pin_index)
208922ebd666SSriram Periyasamy {
2090d9561474SSriram Periyasamy int ret;
2091d9561474SSriram Periyasamy
209222ebd666SSriram Periyasamy switch (tkn_elem->token) {
20936277e832SShreyas NC case SKL_TKN_U32_PIN_MOD_ID:
209422ebd666SSriram Periyasamy m_pin[pin_index].id.module_id = tkn_elem->value;
20956277e832SShreyas NC break;
20966277e832SShreyas NC
20976277e832SShreyas NC case SKL_TKN_U32_PIN_INST_ID:
209822ebd666SSriram Periyasamy m_pin[pin_index].id.instance_id = tkn_elem->value;
20996277e832SShreyas NC break;
21006277e832SShreyas NC
2101d9561474SSriram Periyasamy case SKL_TKN_UUID:
21029e0784d0SAndy Shevchenko ret = skl_tplg_get_uuid(dev, &m_pin[pin_index].id.mod_uuid,
2103d9561474SSriram Periyasamy (struct snd_soc_tplg_vendor_uuid_elem *)tkn_elem);
2104d9561474SSriram Periyasamy if (ret < 0)
2105d9561474SSriram Periyasamy return ret;
2106d9561474SSriram Periyasamy
21076277e832SShreyas NC break;
21086277e832SShreyas NC
21096277e832SShreyas NC default:
211022ebd666SSriram Periyasamy dev_err(dev, "%d Not a pin token\n", tkn_elem->token);
21116277e832SShreyas NC return -EINVAL;
21126277e832SShreyas NC }
21136277e832SShreyas NC
21146277e832SShreyas NC return 0;
21156277e832SShreyas NC }
21166277e832SShreyas NC
21176277e832SShreyas NC /*
21186277e832SShreyas NC * Parse for pin config specific tokens to fill up the
21196277e832SShreyas NC * module private data
21206277e832SShreyas NC */
skl_tplg_fill_pins_info(struct device * dev,struct skl_module_cfg * mconfig,struct snd_soc_tplg_vendor_value_elem * tkn_elem,int dir,int pin_count)21216277e832SShreyas NC static int skl_tplg_fill_pins_info(struct device *dev,
21226277e832SShreyas NC struct skl_module_cfg *mconfig,
21236277e832SShreyas NC struct snd_soc_tplg_vendor_value_elem *tkn_elem,
21246277e832SShreyas NC int dir, int pin_count)
21256277e832SShreyas NC {
21266277e832SShreyas NC int ret;
21276277e832SShreyas NC struct skl_module_pin *m_pin;
21286277e832SShreyas NC
21296277e832SShreyas NC switch (dir) {
21306277e832SShreyas NC case SKL_DIR_IN:
21316277e832SShreyas NC m_pin = mconfig->m_in_pin;
21326277e832SShreyas NC break;
21336277e832SShreyas NC
21346277e832SShreyas NC case SKL_DIR_OUT:
21356277e832SShreyas NC m_pin = mconfig->m_out_pin;
21366277e832SShreyas NC break;
21376277e832SShreyas NC
21386277e832SShreyas NC default:
2139ecd286a9SColin Ian King dev_err(dev, "Invalid direction value\n");
21406277e832SShreyas NC return -EINVAL;
21416277e832SShreyas NC }
21426277e832SShreyas NC
214322ebd666SSriram Periyasamy ret = skl_tplg_fill_pin(dev, tkn_elem, m_pin, pin_count);
21446277e832SShreyas NC if (ret < 0)
21456277e832SShreyas NC return ret;
21466277e832SShreyas NC
21476277e832SShreyas NC m_pin[pin_count].in_use = false;
21486277e832SShreyas NC m_pin[pin_count].pin_state = SKL_PIN_UNBIND;
21496277e832SShreyas NC
21506277e832SShreyas NC return 0;
21516277e832SShreyas NC }
21526277e832SShreyas NC
21536277e832SShreyas NC /*
21546277e832SShreyas NC * Fill up input/output module config format based
21556277e832SShreyas NC * on the direction
21566277e832SShreyas NC */
skl_tplg_fill_fmt(struct device * dev,struct skl_module_fmt * dst_fmt,u32 tkn,u32 value)21576277e832SShreyas NC static int skl_tplg_fill_fmt(struct device *dev,
2158ca312fdaSShreyas NC struct skl_module_fmt *dst_fmt,
2159ca312fdaSShreyas NC u32 tkn, u32 value)
21606277e832SShreyas NC {
21616277e832SShreyas NC switch (tkn) {
21626277e832SShreyas NC case SKL_TKN_U32_FMT_CH:
21636277e832SShreyas NC dst_fmt->channels = value;
21646277e832SShreyas NC break;
21656277e832SShreyas NC
21666277e832SShreyas NC case SKL_TKN_U32_FMT_FREQ:
21676277e832SShreyas NC dst_fmt->s_freq = value;
21686277e832SShreyas NC break;
21696277e832SShreyas NC
21706277e832SShreyas NC case SKL_TKN_U32_FMT_BIT_DEPTH:
21716277e832SShreyas NC dst_fmt->bit_depth = value;
21726277e832SShreyas NC break;
21736277e832SShreyas NC
21746277e832SShreyas NC case SKL_TKN_U32_FMT_SAMPLE_SIZE:
21756277e832SShreyas NC dst_fmt->valid_bit_depth = value;
21766277e832SShreyas NC break;
21776277e832SShreyas NC
21786277e832SShreyas NC case SKL_TKN_U32_FMT_CH_CONFIG:
21796277e832SShreyas NC dst_fmt->ch_cfg = value;
21806277e832SShreyas NC break;
21816277e832SShreyas NC
21826277e832SShreyas NC case SKL_TKN_U32_FMT_INTERLEAVE:
21836277e832SShreyas NC dst_fmt->interleaving_style = value;
21846277e832SShreyas NC break;
21856277e832SShreyas NC
21866277e832SShreyas NC case SKL_TKN_U32_FMT_SAMPLE_TYPE:
21876277e832SShreyas NC dst_fmt->sample_type = value;
21886277e832SShreyas NC break;
21896277e832SShreyas NC
21906277e832SShreyas NC case SKL_TKN_U32_FMT_CH_MAP:
21916277e832SShreyas NC dst_fmt->ch_map = value;
21926277e832SShreyas NC break;
21936277e832SShreyas NC
21946277e832SShreyas NC default:
2195ecd286a9SColin Ian King dev_err(dev, "Invalid token %d\n", tkn);
21966277e832SShreyas NC return -EINVAL;
21976277e832SShreyas NC }
21986277e832SShreyas NC
21996277e832SShreyas NC return 0;
22006277e832SShreyas NC }
22016277e832SShreyas NC
skl_tplg_widget_fill_fmt(struct device * dev,struct skl_module_iface * fmt,u32 tkn,u32 val,u32 dir,int fmt_idx)2202ca312fdaSShreyas NC static int skl_tplg_widget_fill_fmt(struct device *dev,
2203f6fa56e2SRamesh Babu struct skl_module_iface *fmt,
2204ca312fdaSShreyas NC u32 tkn, u32 val, u32 dir, int fmt_idx)
2205ca312fdaSShreyas NC {
2206ca312fdaSShreyas NC struct skl_module_fmt *dst_fmt;
2207ca312fdaSShreyas NC
2208f6fa56e2SRamesh Babu if (!fmt)
2209f6fa56e2SRamesh Babu return -EINVAL;
2210f6fa56e2SRamesh Babu
2211ca312fdaSShreyas NC switch (dir) {
2212ca312fdaSShreyas NC case SKL_DIR_IN:
2213f6fa56e2SRamesh Babu dst_fmt = &fmt->inputs[fmt_idx].fmt;
2214ca312fdaSShreyas NC break;
2215ca312fdaSShreyas NC
2216ca312fdaSShreyas NC case SKL_DIR_OUT:
2217f6fa56e2SRamesh Babu dst_fmt = &fmt->outputs[fmt_idx].fmt;
2218ca312fdaSShreyas NC break;
2219ca312fdaSShreyas NC
2220ca312fdaSShreyas NC default:
2221ca312fdaSShreyas NC dev_err(dev, "Invalid direction: %d\n", dir);
2222ca312fdaSShreyas NC return -EINVAL;
2223ca312fdaSShreyas NC }
2224ca312fdaSShreyas NC
2225ca312fdaSShreyas NC return skl_tplg_fill_fmt(dev, dst_fmt, tkn, val);
2226ca312fdaSShreyas NC }
2227ca312fdaSShreyas NC
skl_tplg_fill_pin_dynamic_val(struct skl_module_pin * mpin,u32 pin_count,u32 value)22286277e832SShreyas NC static void skl_tplg_fill_pin_dynamic_val(
22296277e832SShreyas NC struct skl_module_pin *mpin, u32 pin_count, u32 value)
22304cd9899fSHardik T Shah {
22314cd9899fSHardik T Shah int i;
22324cd9899fSHardik T Shah
22336277e832SShreyas NC for (i = 0; i < pin_count; i++)
22346277e832SShreyas NC mpin[i].is_dynamic = value;
22354cd9899fSHardik T Shah }
22366277e832SShreyas NC
22376277e832SShreyas NC /*
2238db6ed55dSShreyas NC * Resource table in the manifest has pin specific resources
2239db6ed55dSShreyas NC * like pin and pin buffer size
2240db6ed55dSShreyas NC */
skl_tplg_manifest_pin_res_tkn(struct device * dev,struct snd_soc_tplg_vendor_value_elem * tkn_elem,struct skl_module_res * res,int pin_idx,int dir)2241db6ed55dSShreyas NC static int skl_tplg_manifest_pin_res_tkn(struct device *dev,
2242db6ed55dSShreyas NC struct snd_soc_tplg_vendor_value_elem *tkn_elem,
2243db6ed55dSShreyas NC struct skl_module_res *res, int pin_idx, int dir)
2244db6ed55dSShreyas NC {
2245db6ed55dSShreyas NC struct skl_module_pin_resources *m_pin;
2246db6ed55dSShreyas NC
2247db6ed55dSShreyas NC switch (dir) {
2248db6ed55dSShreyas NC case SKL_DIR_IN:
2249db6ed55dSShreyas NC m_pin = &res->input[pin_idx];
2250db6ed55dSShreyas NC break;
2251db6ed55dSShreyas NC
2252db6ed55dSShreyas NC case SKL_DIR_OUT:
2253db6ed55dSShreyas NC m_pin = &res->output[pin_idx];
2254db6ed55dSShreyas NC break;
2255db6ed55dSShreyas NC
2256db6ed55dSShreyas NC default:
2257db6ed55dSShreyas NC dev_err(dev, "Invalid pin direction: %d\n", dir);
2258db6ed55dSShreyas NC return -EINVAL;
2259db6ed55dSShreyas NC }
2260db6ed55dSShreyas NC
2261db6ed55dSShreyas NC switch (tkn_elem->token) {
2262db6ed55dSShreyas NC case SKL_TKN_MM_U32_RES_PIN_ID:
2263db6ed55dSShreyas NC m_pin->pin_index = tkn_elem->value;
2264db6ed55dSShreyas NC break;
2265db6ed55dSShreyas NC
2266db6ed55dSShreyas NC case SKL_TKN_MM_U32_PIN_BUF:
2267db6ed55dSShreyas NC m_pin->buf_size = tkn_elem->value;
2268db6ed55dSShreyas NC break;
2269db6ed55dSShreyas NC
2270db6ed55dSShreyas NC default:
2271db6ed55dSShreyas NC dev_err(dev, "Invalid token: %d\n", tkn_elem->token);
2272db6ed55dSShreyas NC return -EINVAL;
2273db6ed55dSShreyas NC }
2274db6ed55dSShreyas NC
2275db6ed55dSShreyas NC return 0;
2276db6ed55dSShreyas NC }
2277db6ed55dSShreyas NC
2278db6ed55dSShreyas NC /*
2279db6ed55dSShreyas NC * Fill module specific resources from the manifest's resource
2280db6ed55dSShreyas NC * table like CPS, DMA size, mem_pages.
2281db6ed55dSShreyas NC */
skl_tplg_fill_res_tkn(struct device * dev,struct snd_soc_tplg_vendor_value_elem * tkn_elem,struct skl_module_res * res,int pin_idx,int dir)2282db6ed55dSShreyas NC static int skl_tplg_fill_res_tkn(struct device *dev,
2283db6ed55dSShreyas NC struct snd_soc_tplg_vendor_value_elem *tkn_elem,
2284db6ed55dSShreyas NC struct skl_module_res *res,
2285db6ed55dSShreyas NC int pin_idx, int dir)
2286db6ed55dSShreyas NC {
2287db6ed55dSShreyas NC int ret, tkn_count = 0;
2288db6ed55dSShreyas NC
2289db6ed55dSShreyas NC if (!res)
2290db6ed55dSShreyas NC return -EINVAL;
2291db6ed55dSShreyas NC
2292db6ed55dSShreyas NC switch (tkn_elem->token) {
2293db6ed55dSShreyas NC case SKL_TKN_MM_U32_DMA_SIZE:
2294db6ed55dSShreyas NC res->dma_buffer_size = tkn_elem->value;
2295db6ed55dSShreyas NC break;
2296db6ed55dSShreyas NC
2297db6ed55dSShreyas NC case SKL_TKN_MM_U32_CPC:
2298db6ed55dSShreyas NC res->cpc = tkn_elem->value;
2299db6ed55dSShreyas NC break;
2300db6ed55dSShreyas NC
2301db6ed55dSShreyas NC case SKL_TKN_U32_MEM_PAGES:
2302db6ed55dSShreyas NC res->is_pages = tkn_elem->value;
2303db6ed55dSShreyas NC break;
2304db6ed55dSShreyas NC
2305db6ed55dSShreyas NC case SKL_TKN_U32_OBS:
2306db6ed55dSShreyas NC res->obs = tkn_elem->value;
2307db6ed55dSShreyas NC break;
2308db6ed55dSShreyas NC
2309db6ed55dSShreyas NC case SKL_TKN_U32_IBS:
2310db6ed55dSShreyas NC res->ibs = tkn_elem->value;
2311db6ed55dSShreyas NC break;
2312db6ed55dSShreyas NC
2313db6ed55dSShreyas NC case SKL_TKN_MM_U32_RES_PIN_ID:
2314db6ed55dSShreyas NC case SKL_TKN_MM_U32_PIN_BUF:
2315db6ed55dSShreyas NC ret = skl_tplg_manifest_pin_res_tkn(dev, tkn_elem, res,
2316db6ed55dSShreyas NC pin_idx, dir);
2317db6ed55dSShreyas NC if (ret < 0)
2318db6ed55dSShreyas NC return ret;
2319db6ed55dSShreyas NC break;
2320db6ed55dSShreyas NC
232184b71067SCezary Rojewski case SKL_TKN_MM_U32_CPS:
232284b71067SCezary Rojewski case SKL_TKN_U32_MAX_MCPS:
232384b71067SCezary Rojewski /* ignore unused tokens */
232484b71067SCezary Rojewski break;
232584b71067SCezary Rojewski
2326db6ed55dSShreyas NC default:
2327db6ed55dSShreyas NC dev_err(dev, "Not a res type token: %d", tkn_elem->token);
2328db6ed55dSShreyas NC return -EINVAL;
2329db6ed55dSShreyas NC
2330db6ed55dSShreyas NC }
2331db6ed55dSShreyas NC tkn_count++;
2332db6ed55dSShreyas NC
2333db6ed55dSShreyas NC return tkn_count;
2334db6ed55dSShreyas NC }
2335db6ed55dSShreyas NC
2336db6ed55dSShreyas NC /*
23376277e832SShreyas NC * Parse tokens to fill up the module private data
23386277e832SShreyas NC */
skl_tplg_get_token(struct device * dev,struct snd_soc_tplg_vendor_value_elem * tkn_elem,struct skl_dev * skl,struct skl_module_cfg * mconfig)23396277e832SShreyas NC static int skl_tplg_get_token(struct device *dev,
23406277e832SShreyas NC struct snd_soc_tplg_vendor_value_elem *tkn_elem,
2341bcc2a2dcSCezary Rojewski struct skl_dev *skl, struct skl_module_cfg *mconfig)
23426277e832SShreyas NC {
23436277e832SShreyas NC int tkn_count = 0;
23446277e832SShreyas NC int ret;
23456277e832SShreyas NC static int is_pipe_exists;
2346f6fa56e2SRamesh Babu static int pin_index, dir, conf_idx;
2347f6fa56e2SRamesh Babu struct skl_module_iface *iface = NULL;
2348f6fa56e2SRamesh Babu struct skl_module_res *res = NULL;
2349f6fa56e2SRamesh Babu int res_idx = mconfig->res_idx;
2350f6fa56e2SRamesh Babu int fmt_idx = mconfig->fmt_idx;
2351f6fa56e2SRamesh Babu
2352f6fa56e2SRamesh Babu /*
2353f6fa56e2SRamesh Babu * If the manifest structure contains no modules, fill all
2354f6fa56e2SRamesh Babu * the module data to 0th index.
2355f6fa56e2SRamesh Babu * res_idx and fmt_idx are default set to 0.
2356f6fa56e2SRamesh Babu */
2357f6fa56e2SRamesh Babu if (skl->nr_modules == 0) {
2358f6fa56e2SRamesh Babu res = &mconfig->module->resources[res_idx];
2359f6fa56e2SRamesh Babu iface = &mconfig->module->formats[fmt_idx];
2360f6fa56e2SRamesh Babu }
23616277e832SShreyas NC
23626277e832SShreyas NC if (tkn_elem->token > SKL_TKN_MAX)
23636277e832SShreyas NC return -EINVAL;
23646277e832SShreyas NC
23656277e832SShreyas NC switch (tkn_elem->token) {
23666277e832SShreyas NC case SKL_TKN_U8_IN_QUEUE_COUNT:
2367f6fa56e2SRamesh Babu mconfig->module->max_input_pins = tkn_elem->value;
23686277e832SShreyas NC break;
23696277e832SShreyas NC
23706277e832SShreyas NC case SKL_TKN_U8_OUT_QUEUE_COUNT:
2371f6fa56e2SRamesh Babu mconfig->module->max_output_pins = tkn_elem->value;
23726277e832SShreyas NC break;
23736277e832SShreyas NC
23746277e832SShreyas NC case SKL_TKN_U8_DYN_IN_PIN:
23756277e832SShreyas NC if (!mconfig->m_in_pin)
2376a86854d0SKees Cook mconfig->m_in_pin =
2377a86854d0SKees Cook devm_kcalloc(dev, MAX_IN_QUEUE,
2378a86854d0SKees Cook sizeof(*mconfig->m_in_pin),
2379a86854d0SKees Cook GFP_KERNEL);
2380f6fa56e2SRamesh Babu if (!mconfig->m_in_pin)
23816277e832SShreyas NC return -ENOMEM;
23826277e832SShreyas NC
2383f6fa56e2SRamesh Babu skl_tplg_fill_pin_dynamic_val(mconfig->m_in_pin, MAX_IN_QUEUE,
2384f6fa56e2SRamesh Babu tkn_elem->value);
23856277e832SShreyas NC break;
23866277e832SShreyas NC
23876277e832SShreyas NC case SKL_TKN_U8_DYN_OUT_PIN:
23886277e832SShreyas NC if (!mconfig->m_out_pin)
2389a86854d0SKees Cook mconfig->m_out_pin =
2390a86854d0SKees Cook devm_kcalloc(dev, MAX_IN_QUEUE,
2391a86854d0SKees Cook sizeof(*mconfig->m_in_pin),
2392a86854d0SKees Cook GFP_KERNEL);
2393f6fa56e2SRamesh Babu if (!mconfig->m_out_pin)
23946277e832SShreyas NC return -ENOMEM;
23956277e832SShreyas NC
2396f6fa56e2SRamesh Babu skl_tplg_fill_pin_dynamic_val(mconfig->m_out_pin, MAX_OUT_QUEUE,
2397f6fa56e2SRamesh Babu tkn_elem->value);
23986277e832SShreyas NC break;
23996277e832SShreyas NC
24006277e832SShreyas NC case SKL_TKN_U8_TIME_SLOT:
24016277e832SShreyas NC mconfig->time_slot = tkn_elem->value;
24026277e832SShreyas NC break;
24036277e832SShreyas NC
24046277e832SShreyas NC case SKL_TKN_U8_CORE_ID:
24056277e832SShreyas NC mconfig->core_id = tkn_elem->value;
24069c80c5a8STakashi Iwai break;
24076277e832SShreyas NC
24086277e832SShreyas NC case SKL_TKN_U8_MOD_TYPE:
24096277e832SShreyas NC mconfig->m_type = tkn_elem->value;
24106277e832SShreyas NC break;
24116277e832SShreyas NC
24126277e832SShreyas NC case SKL_TKN_U8_DEV_TYPE:
24136277e832SShreyas NC mconfig->dev_type = tkn_elem->value;
24146277e832SShreyas NC break;
24156277e832SShreyas NC
24166277e832SShreyas NC case SKL_TKN_U8_HW_CONN_TYPE:
24176277e832SShreyas NC mconfig->hw_conn_type = tkn_elem->value;
24186277e832SShreyas NC break;
24196277e832SShreyas NC
24206277e832SShreyas NC case SKL_TKN_U16_MOD_INST_ID:
24216277e832SShreyas NC mconfig->id.instance_id =
24226277e832SShreyas NC tkn_elem->value;
24236277e832SShreyas NC break;
24246277e832SShreyas NC
24256277e832SShreyas NC case SKL_TKN_U32_MEM_PAGES:
24266277e832SShreyas NC case SKL_TKN_U32_MAX_MCPS:
24276277e832SShreyas NC case SKL_TKN_U32_OBS:
24286277e832SShreyas NC case SKL_TKN_U32_IBS:
24292b79b15cSColin Ian King ret = skl_tplg_fill_res_tkn(dev, tkn_elem, res, pin_index, dir);
2430f6fa56e2SRamesh Babu if (ret < 0)
2431f6fa56e2SRamesh Babu return ret;
2432f6fa56e2SRamesh Babu
24336277e832SShreyas NC break;
24346277e832SShreyas NC
24356277e832SShreyas NC case SKL_TKN_U32_VBUS_ID:
24366277e832SShreyas NC mconfig->vbus_id = tkn_elem->value;
24376277e832SShreyas NC break;
24386277e832SShreyas NC
24396277e832SShreyas NC case SKL_TKN_U32_PARAMS_FIXUP:
24406277e832SShreyas NC mconfig->params_fixup = tkn_elem->value;
24416277e832SShreyas NC break;
24426277e832SShreyas NC
24436277e832SShreyas NC case SKL_TKN_U32_CONVERTER:
24446277e832SShreyas NC mconfig->converter = tkn_elem->value;
24456277e832SShreyas NC break;
24466277e832SShreyas NC
2447c0116be3SSubhransu S. Prusty case SKL_TKN_U32_D0I3_CAPS:
24486bd9dcf3SVinod Koul mconfig->d0i3_caps = tkn_elem->value;
24496bd9dcf3SVinod Koul break;
24506bd9dcf3SVinod Koul
24516277e832SShreyas NC case SKL_TKN_U32_PIPE_ID:
24526277e832SShreyas NC ret = skl_tplg_add_pipe(dev,
24536277e832SShreyas NC mconfig, skl, tkn_elem);
24546277e832SShreyas NC
2455081dc8abSGuneshwor Singh if (ret < 0) {
2456081dc8abSGuneshwor Singh if (ret == -EEXIST) {
24576277e832SShreyas NC is_pipe_exists = 1;
2458081dc8abSGuneshwor Singh break;
2459081dc8abSGuneshwor Singh }
2460081dc8abSGuneshwor Singh return is_pipe_exists;
2461081dc8abSGuneshwor Singh }
24626277e832SShreyas NC
24636277e832SShreyas NC break;
24646277e832SShreyas NC
2465f6fa56e2SRamesh Babu case SKL_TKN_U32_PIPE_CONFIG_ID:
2466f6fa56e2SRamesh Babu conf_idx = tkn_elem->value;
2467f6fa56e2SRamesh Babu break;
2468f6fa56e2SRamesh Babu
24696277e832SShreyas NC case SKL_TKN_U32_PIPE_CONN_TYPE:
24706277e832SShreyas NC case SKL_TKN_U32_PIPE_PRIORITY:
24716277e832SShreyas NC case SKL_TKN_U32_PIPE_MEM_PGS:
24728a0cb236SVinod Koul case SKL_TKN_U32_PMODE:
2473f6fa56e2SRamesh Babu case SKL_TKN_U32_PIPE_DIRECTION:
2474f6fa56e2SRamesh Babu case SKL_TKN_U32_NUM_CONFIGS:
24756277e832SShreyas NC if (is_pipe_exists) {
24766277e832SShreyas NC ret = skl_tplg_fill_pipe_tkn(dev, mconfig->pipe,
24776277e832SShreyas NC tkn_elem->token, tkn_elem->value);
24786277e832SShreyas NC if (ret < 0)
24796277e832SShreyas NC return ret;
24806277e832SShreyas NC }
24816277e832SShreyas NC
24826277e832SShreyas NC break;
24836277e832SShreyas NC
2484f6fa56e2SRamesh Babu case SKL_TKN_U32_PATH_MEM_PGS:
2485f6fa56e2SRamesh Babu case SKL_TKN_U32_CFG_FREQ:
2486f6fa56e2SRamesh Babu case SKL_TKN_U8_CFG_CHAN:
2487f6fa56e2SRamesh Babu case SKL_TKN_U8_CFG_BPS:
2488f6fa56e2SRamesh Babu if (mconfig->pipe->nr_cfgs) {
2489f6fa56e2SRamesh Babu ret = skl_tplg_fill_pipe_cfg(dev, mconfig->pipe,
2490f6fa56e2SRamesh Babu tkn_elem->token, tkn_elem->value,
2491f6fa56e2SRamesh Babu conf_idx, dir);
2492f6fa56e2SRamesh Babu if (ret < 0)
2493f6fa56e2SRamesh Babu return ret;
2494f6fa56e2SRamesh Babu }
2495f6fa56e2SRamesh Babu break;
2496f6fa56e2SRamesh Babu
2497f6fa56e2SRamesh Babu case SKL_TKN_CFG_MOD_RES_ID:
2498f6fa56e2SRamesh Babu mconfig->mod_cfg[conf_idx].res_idx = tkn_elem->value;
2499f6fa56e2SRamesh Babu break;
2500f6fa56e2SRamesh Babu
2501f6fa56e2SRamesh Babu case SKL_TKN_CFG_MOD_FMT_ID:
2502f6fa56e2SRamesh Babu mconfig->mod_cfg[conf_idx].fmt_idx = tkn_elem->value;
2503f6fa56e2SRamesh Babu break;
2504f6fa56e2SRamesh Babu
25056277e832SShreyas NC /*
25066277e832SShreyas NC * SKL_TKN_U32_DIR_PIN_COUNT token has the value for both
25076277e832SShreyas NC * direction and the pin count. The first four bits represent
25086277e832SShreyas NC * direction and next four the pin count.
25096277e832SShreyas NC */
25106277e832SShreyas NC case SKL_TKN_U32_DIR_PIN_COUNT:
25116277e832SShreyas NC dir = tkn_elem->value & SKL_IN_DIR_BIT_MASK;
25126277e832SShreyas NC pin_index = (tkn_elem->value &
25136277e832SShreyas NC SKL_PIN_COUNT_MASK) >> 4;
25146277e832SShreyas NC
25156277e832SShreyas NC break;
25166277e832SShreyas NC
25176277e832SShreyas NC case SKL_TKN_U32_FMT_CH:
25186277e832SShreyas NC case SKL_TKN_U32_FMT_FREQ:
25196277e832SShreyas NC case SKL_TKN_U32_FMT_BIT_DEPTH:
25206277e832SShreyas NC case SKL_TKN_U32_FMT_SAMPLE_SIZE:
25216277e832SShreyas NC case SKL_TKN_U32_FMT_CH_CONFIG:
25226277e832SShreyas NC case SKL_TKN_U32_FMT_INTERLEAVE:
25236277e832SShreyas NC case SKL_TKN_U32_FMT_SAMPLE_TYPE:
25246277e832SShreyas NC case SKL_TKN_U32_FMT_CH_MAP:
2525f6fa56e2SRamesh Babu ret = skl_tplg_widget_fill_fmt(dev, iface, tkn_elem->token,
25266277e832SShreyas NC tkn_elem->value, dir, pin_index);
25276277e832SShreyas NC
25286277e832SShreyas NC if (ret < 0)
25296277e832SShreyas NC return ret;
25306277e832SShreyas NC
25316277e832SShreyas NC break;
25326277e832SShreyas NC
25336277e832SShreyas NC case SKL_TKN_U32_PIN_MOD_ID:
25346277e832SShreyas NC case SKL_TKN_U32_PIN_INST_ID:
2535d9561474SSriram Periyasamy case SKL_TKN_UUID:
25366277e832SShreyas NC ret = skl_tplg_fill_pins_info(dev,
25376277e832SShreyas NC mconfig, tkn_elem, dir,
25386277e832SShreyas NC pin_index);
25396277e832SShreyas NC if (ret < 0)
25406277e832SShreyas NC return ret;
25416277e832SShreyas NC
25426277e832SShreyas NC break;
25436277e832SShreyas NC
2544a4ad42d2SKareem Shaik case SKL_TKN_U32_FMT_CFG_IDX:
2545a4ad42d2SKareem Shaik if (tkn_elem->value > SKL_MAX_PARAMS_TYPES)
2546a4ad42d2SKareem Shaik return -EINVAL;
2547a4ad42d2SKareem Shaik
2548a4ad42d2SKareem Shaik mconfig->fmt_cfg_idx = tkn_elem->value;
2549a4ad42d2SKareem Shaik break;
2550a4ad42d2SKareem Shaik
25516277e832SShreyas NC case SKL_TKN_U32_CAPS_SIZE:
2552a4ad42d2SKareem Shaik mconfig->formats_config[mconfig->fmt_cfg_idx].caps_size =
25536277e832SShreyas NC tkn_elem->value;
25546277e832SShreyas NC
25556277e832SShreyas NC break;
25566277e832SShreyas NC
2557133e6e5cSShreyas NC case SKL_TKN_U32_CAPS_SET_PARAMS:
2558a4ad42d2SKareem Shaik mconfig->formats_config[mconfig->fmt_cfg_idx].set_params =
2559133e6e5cSShreyas NC tkn_elem->value;
2560133e6e5cSShreyas NC break;
2561133e6e5cSShreyas NC
2562133e6e5cSShreyas NC case SKL_TKN_U32_CAPS_PARAMS_ID:
2563a4ad42d2SKareem Shaik mconfig->formats_config[mconfig->fmt_cfg_idx].param_id =
2564133e6e5cSShreyas NC tkn_elem->value;
2565133e6e5cSShreyas NC break;
2566133e6e5cSShreyas NC
25676277e832SShreyas NC case SKL_TKN_U32_PROC_DOMAIN:
25686277e832SShreyas NC mconfig->domain =
25696277e832SShreyas NC tkn_elem->value;
25706277e832SShreyas NC
25716277e832SShreyas NC break;
25726277e832SShreyas NC
2573939df3adSRamesh Babu case SKL_TKN_U32_DMA_BUF_SIZE:
2574939df3adSRamesh Babu mconfig->dma_buffer_size = tkn_elem->value;
2575939df3adSRamesh Babu break;
2576939df3adSRamesh Babu
25776277e832SShreyas NC case SKL_TKN_U8_IN_PIN_TYPE:
25786277e832SShreyas NC case SKL_TKN_U8_OUT_PIN_TYPE:
25796277e832SShreyas NC case SKL_TKN_U8_CONN_TYPE:
25806277e832SShreyas NC break;
25816277e832SShreyas NC
25826277e832SShreyas NC default:
25836277e832SShreyas NC dev_err(dev, "Token %d not handled\n",
25846277e832SShreyas NC tkn_elem->token);
25856277e832SShreyas NC return -EINVAL;
25866277e832SShreyas NC }
25876277e832SShreyas NC
25886277e832SShreyas NC tkn_count++;
25896277e832SShreyas NC
25906277e832SShreyas NC return tkn_count;
25916277e832SShreyas NC }
25926277e832SShreyas NC
25936277e832SShreyas NC /*
25946277e832SShreyas NC * Parse the vendor array for specific tokens to construct
25956277e832SShreyas NC * module private data
25966277e832SShreyas NC */
skl_tplg_get_tokens(struct device * dev,char * pvt_data,struct skl_dev * skl,struct skl_module_cfg * mconfig,int block_size)25976277e832SShreyas NC static int skl_tplg_get_tokens(struct device *dev,
2598bcc2a2dcSCezary Rojewski char *pvt_data, struct skl_dev *skl,
25996277e832SShreyas NC struct skl_module_cfg *mconfig, int block_size)
26006277e832SShreyas NC {
26016277e832SShreyas NC struct snd_soc_tplg_vendor_array *array;
26026277e832SShreyas NC struct snd_soc_tplg_vendor_value_elem *tkn_elem;
26036277e832SShreyas NC int tkn_count = 0, ret;
26046277e832SShreyas NC int off = 0, tuple_size = 0;
2605d9561474SSriram Periyasamy bool is_module_guid = true;
26066277e832SShreyas NC
26076277e832SShreyas NC if (block_size <= 0)
26086277e832SShreyas NC return -EINVAL;
26096277e832SShreyas NC
26106277e832SShreyas NC while (tuple_size < block_size) {
26116277e832SShreyas NC array = (struct snd_soc_tplg_vendor_array *)(pvt_data + off);
26126277e832SShreyas NC
26136277e832SShreyas NC off += array->size;
26146277e832SShreyas NC
26156277e832SShreyas NC switch (array->type) {
26166277e832SShreyas NC case SND_SOC_TPLG_TUPLE_TYPE_STRING:
2617ecd286a9SColin Ian King dev_warn(dev, "no string tokens expected for skl tplg\n");
26186277e832SShreyas NC continue;
26196277e832SShreyas NC
26206277e832SShreyas NC case SND_SOC_TPLG_TUPLE_TYPE_UUID:
2621d9561474SSriram Periyasamy if (is_module_guid) {
26229e0784d0SAndy Shevchenko ret = skl_tplg_get_uuid(dev, (guid_t *)mconfig->guid,
262322ebd666SSriram Periyasamy array->uuid);
2624d9561474SSriram Periyasamy is_module_guid = false;
2625d9561474SSriram Periyasamy } else {
2626d9561474SSriram Periyasamy ret = skl_tplg_get_token(dev, array->value, skl,
2627d9561474SSriram Periyasamy mconfig);
2628d9561474SSriram Periyasamy }
2629d9561474SSriram Periyasamy
26306277e832SShreyas NC if (ret < 0)
26316277e832SShreyas NC return ret;
26326277e832SShreyas NC
26336277e832SShreyas NC tuple_size += sizeof(*array->uuid);
26346277e832SShreyas NC
26356277e832SShreyas NC continue;
26366277e832SShreyas NC
26376277e832SShreyas NC default:
26386277e832SShreyas NC tkn_elem = array->value;
26396277e832SShreyas NC tkn_count = 0;
26406277e832SShreyas NC break;
26416277e832SShreyas NC }
26426277e832SShreyas NC
26436277e832SShreyas NC while (tkn_count <= (array->num_elems - 1)) {
26446277e832SShreyas NC ret = skl_tplg_get_token(dev, tkn_elem,
26456277e832SShreyas NC skl, mconfig);
26466277e832SShreyas NC
26476277e832SShreyas NC if (ret < 0)
26486277e832SShreyas NC return ret;
26496277e832SShreyas NC
26506277e832SShreyas NC tkn_count = tkn_count + ret;
26516277e832SShreyas NC tkn_elem++;
26526277e832SShreyas NC }
26536277e832SShreyas NC
26546277e832SShreyas NC tuple_size += tkn_count * sizeof(*tkn_elem);
26556277e832SShreyas NC }
26566277e832SShreyas NC
2657133e6e5cSShreyas NC return off;
26586277e832SShreyas NC }
26596277e832SShreyas NC
26606277e832SShreyas NC /*
26616277e832SShreyas NC * Every data block is preceded by a descriptor to read the number
26626277e832SShreyas NC * of data blocks, they type of the block and it's size
26636277e832SShreyas NC */
skl_tplg_get_desc_blocks(struct device * dev,struct snd_soc_tplg_vendor_array * array)26646277e832SShreyas NC static int skl_tplg_get_desc_blocks(struct device *dev,
26656277e832SShreyas NC struct snd_soc_tplg_vendor_array *array)
26666277e832SShreyas NC {
26676277e832SShreyas NC struct snd_soc_tplg_vendor_value_elem *tkn_elem;
26686277e832SShreyas NC
26696277e832SShreyas NC tkn_elem = array->value;
26706277e832SShreyas NC
26716277e832SShreyas NC switch (tkn_elem->token) {
26726277e832SShreyas NC case SKL_TKN_U8_NUM_BLOCKS:
26736277e832SShreyas NC case SKL_TKN_U8_BLOCK_TYPE:
26746277e832SShreyas NC case SKL_TKN_U16_BLOCK_SIZE:
26756277e832SShreyas NC return tkn_elem->value;
26766277e832SShreyas NC
26776277e832SShreyas NC default:
2678ecd286a9SColin Ian King dev_err(dev, "Invalid descriptor token %d\n", tkn_elem->token);
26796277e832SShreyas NC break;
26806277e832SShreyas NC }
26816277e832SShreyas NC
26826277e832SShreyas NC return -EINVAL;
26836277e832SShreyas NC }
26846277e832SShreyas NC
2685ac9391daSGuenter Roeck /* Functions to parse private data from configuration file format v4 */
2686ac9391daSGuenter Roeck
2687ac9391daSGuenter Roeck /*
2688ac9391daSGuenter Roeck * Add pipeline from topology binary into driver pipeline list
2689ac9391daSGuenter Roeck *
2690ac9391daSGuenter Roeck * If already added we return that instance
2691ac9391daSGuenter Roeck * Otherwise we create a new instance and add into driver list
2692ac9391daSGuenter Roeck */
skl_tplg_add_pipe_v4(struct device * dev,struct skl_module_cfg * mconfig,struct skl_dev * skl,struct skl_dfw_v4_pipe * dfw_pipe)2693ac9391daSGuenter Roeck static int skl_tplg_add_pipe_v4(struct device *dev,
2694bcc2a2dcSCezary Rojewski struct skl_module_cfg *mconfig, struct skl_dev *skl,
2695ac9391daSGuenter Roeck struct skl_dfw_v4_pipe *dfw_pipe)
2696ac9391daSGuenter Roeck {
2697ac9391daSGuenter Roeck struct skl_pipeline *ppl;
2698ac9391daSGuenter Roeck struct skl_pipe *pipe;
2699ac9391daSGuenter Roeck struct skl_pipe_params *params;
2700ac9391daSGuenter Roeck
2701ac9391daSGuenter Roeck list_for_each_entry(ppl, &skl->ppl_list, node) {
2702ac9391daSGuenter Roeck if (ppl->pipe->ppl_id == dfw_pipe->pipe_id) {
2703ac9391daSGuenter Roeck mconfig->pipe = ppl->pipe;
2704ac9391daSGuenter Roeck return 0;
2705ac9391daSGuenter Roeck }
2706ac9391daSGuenter Roeck }
2707ac9391daSGuenter Roeck
2708ac9391daSGuenter Roeck ppl = devm_kzalloc(dev, sizeof(*ppl), GFP_KERNEL);
2709ac9391daSGuenter Roeck if (!ppl)
2710ac9391daSGuenter Roeck return -ENOMEM;
2711ac9391daSGuenter Roeck
2712ac9391daSGuenter Roeck pipe = devm_kzalloc(dev, sizeof(*pipe), GFP_KERNEL);
2713ac9391daSGuenter Roeck if (!pipe)
2714ac9391daSGuenter Roeck return -ENOMEM;
2715ac9391daSGuenter Roeck
2716ac9391daSGuenter Roeck params = devm_kzalloc(dev, sizeof(*params), GFP_KERNEL);
2717ac9391daSGuenter Roeck if (!params)
2718ac9391daSGuenter Roeck return -ENOMEM;
2719ac9391daSGuenter Roeck
2720ac9391daSGuenter Roeck pipe->ppl_id = dfw_pipe->pipe_id;
2721ac9391daSGuenter Roeck pipe->memory_pages = dfw_pipe->memory_pages;
2722ac9391daSGuenter Roeck pipe->pipe_priority = dfw_pipe->pipe_priority;
2723ac9391daSGuenter Roeck pipe->conn_type = dfw_pipe->conn_type;
2724ac9391daSGuenter Roeck pipe->state = SKL_PIPE_INVALID;
2725ac9391daSGuenter Roeck pipe->p_params = params;
2726ac9391daSGuenter Roeck INIT_LIST_HEAD(&pipe->w_list);
2727ac9391daSGuenter Roeck
2728ac9391daSGuenter Roeck ppl->pipe = pipe;
2729ac9391daSGuenter Roeck list_add(&ppl->node, &skl->ppl_list);
2730ac9391daSGuenter Roeck
2731ac9391daSGuenter Roeck mconfig->pipe = pipe;
2732ac9391daSGuenter Roeck
2733ac9391daSGuenter Roeck return 0;
2734ac9391daSGuenter Roeck }
2735ac9391daSGuenter Roeck
skl_fill_module_pin_info_v4(struct skl_dfw_v4_module_pin * dfw_pin,struct skl_module_pin * m_pin,bool is_dynamic,int max_pin)2736ac9391daSGuenter Roeck static void skl_fill_module_pin_info_v4(struct skl_dfw_v4_module_pin *dfw_pin,
2737ac9391daSGuenter Roeck struct skl_module_pin *m_pin,
2738ac9391daSGuenter Roeck bool is_dynamic, int max_pin)
2739ac9391daSGuenter Roeck {
2740ac9391daSGuenter Roeck int i;
2741ac9391daSGuenter Roeck
2742ac9391daSGuenter Roeck for (i = 0; i < max_pin; i++) {
2743ac9391daSGuenter Roeck m_pin[i].id.module_id = dfw_pin[i].module_id;
2744ac9391daSGuenter Roeck m_pin[i].id.instance_id = dfw_pin[i].instance_id;
2745ac9391daSGuenter Roeck m_pin[i].in_use = false;
2746ac9391daSGuenter Roeck m_pin[i].is_dynamic = is_dynamic;
2747ac9391daSGuenter Roeck m_pin[i].pin_state = SKL_PIN_UNBIND;
2748ac9391daSGuenter Roeck }
2749ac9391daSGuenter Roeck }
2750ac9391daSGuenter Roeck
skl_tplg_fill_fmt_v4(struct skl_module_pin_fmt * dst_fmt,struct skl_dfw_v4_module_fmt * src_fmt,int pins)2751ac9391daSGuenter Roeck static void skl_tplg_fill_fmt_v4(struct skl_module_pin_fmt *dst_fmt,
2752ac9391daSGuenter Roeck struct skl_dfw_v4_module_fmt *src_fmt,
2753ac9391daSGuenter Roeck int pins)
2754ac9391daSGuenter Roeck {
2755ac9391daSGuenter Roeck int i;
2756ac9391daSGuenter Roeck
2757ac9391daSGuenter Roeck for (i = 0; i < pins; i++) {
2758ac9391daSGuenter Roeck dst_fmt[i].fmt.channels = src_fmt[i].channels;
2759ac9391daSGuenter Roeck dst_fmt[i].fmt.s_freq = src_fmt[i].freq;
2760ac9391daSGuenter Roeck dst_fmt[i].fmt.bit_depth = src_fmt[i].bit_depth;
2761ac9391daSGuenter Roeck dst_fmt[i].fmt.valid_bit_depth = src_fmt[i].valid_bit_depth;
2762ac9391daSGuenter Roeck dst_fmt[i].fmt.ch_cfg = src_fmt[i].ch_cfg;
2763ac9391daSGuenter Roeck dst_fmt[i].fmt.ch_map = src_fmt[i].ch_map;
2764ac9391daSGuenter Roeck dst_fmt[i].fmt.interleaving_style =
2765ac9391daSGuenter Roeck src_fmt[i].interleaving_style;
2766ac9391daSGuenter Roeck dst_fmt[i].fmt.sample_type = src_fmt[i].sample_type;
2767ac9391daSGuenter Roeck }
2768ac9391daSGuenter Roeck }
2769ac9391daSGuenter Roeck
skl_tplg_get_pvt_data_v4(struct snd_soc_tplg_dapm_widget * tplg_w,struct skl_dev * skl,struct device * dev,struct skl_module_cfg * mconfig)2770ac9391daSGuenter Roeck static int skl_tplg_get_pvt_data_v4(struct snd_soc_tplg_dapm_widget *tplg_w,
2771bcc2a2dcSCezary Rojewski struct skl_dev *skl, struct device *dev,
2772ac9391daSGuenter Roeck struct skl_module_cfg *mconfig)
2773ac9391daSGuenter Roeck {
2774ac9391daSGuenter Roeck struct skl_dfw_v4_module *dfw =
2775ac9391daSGuenter Roeck (struct skl_dfw_v4_module *)tplg_w->priv.data;
2776ac9391daSGuenter Roeck int ret;
2777a4ad42d2SKareem Shaik int idx = mconfig->fmt_cfg_idx;
2778ac9391daSGuenter Roeck
2779ac9391daSGuenter Roeck dev_dbg(dev, "Parsing Skylake v4 widget topology data\n");
2780ac9391daSGuenter Roeck
2781ac9391daSGuenter Roeck ret = guid_parse(dfw->uuid, (guid_t *)mconfig->guid);
2782ac9391daSGuenter Roeck if (ret)
2783ac9391daSGuenter Roeck return ret;
2784ac9391daSGuenter Roeck mconfig->id.module_id = -1;
2785ac9391daSGuenter Roeck mconfig->id.instance_id = dfw->instance_id;
278684b71067SCezary Rojewski mconfig->module->resources[0].cpc = dfw->max_mcps / 1000;
2787ac9391daSGuenter Roeck mconfig->module->resources[0].ibs = dfw->ibs;
2788ac9391daSGuenter Roeck mconfig->module->resources[0].obs = dfw->obs;
2789ac9391daSGuenter Roeck mconfig->core_id = dfw->core_id;
2790ac9391daSGuenter Roeck mconfig->module->max_input_pins = dfw->max_in_queue;
2791ac9391daSGuenter Roeck mconfig->module->max_output_pins = dfw->max_out_queue;
2792ac9391daSGuenter Roeck mconfig->module->loadable = dfw->is_loadable;
2793ac9391daSGuenter Roeck skl_tplg_fill_fmt_v4(mconfig->module->formats[0].inputs, dfw->in_fmt,
2794ac9391daSGuenter Roeck MAX_IN_QUEUE);
2795ac9391daSGuenter Roeck skl_tplg_fill_fmt_v4(mconfig->module->formats[0].outputs, dfw->out_fmt,
2796ac9391daSGuenter Roeck MAX_OUT_QUEUE);
2797ac9391daSGuenter Roeck
2798ac9391daSGuenter Roeck mconfig->params_fixup = dfw->params_fixup;
2799ac9391daSGuenter Roeck mconfig->converter = dfw->converter;
2800ac9391daSGuenter Roeck mconfig->m_type = dfw->module_type;
2801ac9391daSGuenter Roeck mconfig->vbus_id = dfw->vbus_id;
2802ac9391daSGuenter Roeck mconfig->module->resources[0].is_pages = dfw->mem_pages;
2803ac9391daSGuenter Roeck
2804ac9391daSGuenter Roeck ret = skl_tplg_add_pipe_v4(dev, mconfig, skl, &dfw->pipe);
2805ac9391daSGuenter Roeck if (ret)
2806ac9391daSGuenter Roeck return ret;
2807ac9391daSGuenter Roeck
2808ac9391daSGuenter Roeck mconfig->dev_type = dfw->dev_type;
2809ac9391daSGuenter Roeck mconfig->hw_conn_type = dfw->hw_conn_type;
2810ac9391daSGuenter Roeck mconfig->time_slot = dfw->time_slot;
2811a4ad42d2SKareem Shaik mconfig->formats_config[idx].caps_size = dfw->caps.caps_size;
2812ac9391daSGuenter Roeck
2813a86854d0SKees Cook mconfig->m_in_pin = devm_kcalloc(dev,
2814a86854d0SKees Cook MAX_IN_QUEUE, sizeof(*mconfig->m_in_pin),
2815ac9391daSGuenter Roeck GFP_KERNEL);
2816ac9391daSGuenter Roeck if (!mconfig->m_in_pin)
2817ac9391daSGuenter Roeck return -ENOMEM;
2818ac9391daSGuenter Roeck
2819a86854d0SKees Cook mconfig->m_out_pin = devm_kcalloc(dev,
2820a86854d0SKees Cook MAX_OUT_QUEUE, sizeof(*mconfig->m_out_pin),
2821ac9391daSGuenter Roeck GFP_KERNEL);
2822ac9391daSGuenter Roeck if (!mconfig->m_out_pin)
2823ac9391daSGuenter Roeck return -ENOMEM;
2824ac9391daSGuenter Roeck
2825ac9391daSGuenter Roeck skl_fill_module_pin_info_v4(dfw->in_pin, mconfig->m_in_pin,
2826ac9391daSGuenter Roeck dfw->is_dynamic_in_pin,
2827ac9391daSGuenter Roeck mconfig->module->max_input_pins);
2828ac9391daSGuenter Roeck skl_fill_module_pin_info_v4(dfw->out_pin, mconfig->m_out_pin,
2829ac9391daSGuenter Roeck dfw->is_dynamic_out_pin,
2830ac9391daSGuenter Roeck mconfig->module->max_output_pins);
2831ac9391daSGuenter Roeck
2832a4ad42d2SKareem Shaik if (mconfig->formats_config[idx].caps_size) {
2833a4ad42d2SKareem Shaik mconfig->formats_config[idx].set_params = dfw->caps.set_params;
2834a4ad42d2SKareem Shaik mconfig->formats_config[idx].param_id = dfw->caps.param_id;
2835a4ad42d2SKareem Shaik mconfig->formats_config[idx].caps =
2836a4ad42d2SKareem Shaik devm_kzalloc(dev, mconfig->formats_config[idx].caps_size,
2837ac9391daSGuenter Roeck GFP_KERNEL);
2838a4ad42d2SKareem Shaik if (!mconfig->formats_config[idx].caps)
2839ac9391daSGuenter Roeck return -ENOMEM;
2840a4ad42d2SKareem Shaik memcpy(mconfig->formats_config[idx].caps, dfw->caps.caps,
2841ac9391daSGuenter Roeck dfw->caps.caps_size);
2842ac9391daSGuenter Roeck }
2843ac9391daSGuenter Roeck
2844ac9391daSGuenter Roeck return 0;
2845ac9391daSGuenter Roeck }
2846ac9391daSGuenter Roeck
skl_tplg_get_caps_data(struct device * dev,char * data,struct skl_module_cfg * mconfig)2847a4ad42d2SKareem Shaik static int skl_tplg_get_caps_data(struct device *dev, char *data,
2848a4ad42d2SKareem Shaik struct skl_module_cfg *mconfig)
2849a4ad42d2SKareem Shaik {
2850a4ad42d2SKareem Shaik int idx = mconfig->fmt_cfg_idx;
2851a4ad42d2SKareem Shaik
2852a4ad42d2SKareem Shaik if (mconfig->formats_config[idx].caps_size > 0) {
2853a4ad42d2SKareem Shaik mconfig->formats_config[idx].caps =
2854a4ad42d2SKareem Shaik devm_kzalloc(dev, mconfig->formats_config[idx].caps_size,
2855a4ad42d2SKareem Shaik GFP_KERNEL);
2856a4ad42d2SKareem Shaik if (!mconfig->formats_config[idx].caps)
2857a4ad42d2SKareem Shaik return -ENOMEM;
2858a4ad42d2SKareem Shaik memcpy(mconfig->formats_config[idx].caps, data,
2859a4ad42d2SKareem Shaik mconfig->formats_config[idx].caps_size);
2860a4ad42d2SKareem Shaik }
2861a4ad42d2SKareem Shaik
2862a4ad42d2SKareem Shaik return mconfig->formats_config[idx].caps_size;
2863a4ad42d2SKareem Shaik }
2864a4ad42d2SKareem Shaik
28656277e832SShreyas NC /*
28666277e832SShreyas NC * Parse the private data for the token and corresponding value.
28676277e832SShreyas NC * The private data can have multiple data blocks. So, a data block
28686277e832SShreyas NC * is preceded by a descriptor for number of blocks and a descriptor
28696277e832SShreyas NC * for the type and size of the suceeding data block.
28706277e832SShreyas NC */
skl_tplg_get_pvt_data(struct snd_soc_tplg_dapm_widget * tplg_w,struct skl_dev * skl,struct device * dev,struct skl_module_cfg * mconfig)28716277e832SShreyas NC static int skl_tplg_get_pvt_data(struct snd_soc_tplg_dapm_widget *tplg_w,
2872bcc2a2dcSCezary Rojewski struct skl_dev *skl, struct device *dev,
28736277e832SShreyas NC struct skl_module_cfg *mconfig)
28746277e832SShreyas NC {
28756277e832SShreyas NC struct snd_soc_tplg_vendor_array *array;
287611a790f9SPierre-Louis Bossart int num_blocks, block_size, block_type, off = 0;
28776277e832SShreyas NC char *data;
28786277e832SShreyas NC int ret;
28796277e832SShreyas NC
2880ac9391daSGuenter Roeck /*
2881ac9391daSGuenter Roeck * v4 configuration files have a valid UUID at the start of
2882ac9391daSGuenter Roeck * the widget's private data.
2883ac9391daSGuenter Roeck */
2884ac9391daSGuenter Roeck if (uuid_is_valid((char *)tplg_w->priv.data))
2885ac9391daSGuenter Roeck return skl_tplg_get_pvt_data_v4(tplg_w, skl, dev, mconfig);
2886ac9391daSGuenter Roeck
28876277e832SShreyas NC /* Read the NUM_DATA_BLOCKS descriptor */
28886277e832SShreyas NC array = (struct snd_soc_tplg_vendor_array *)tplg_w->priv.data;
28896277e832SShreyas NC ret = skl_tplg_get_desc_blocks(dev, array);
28906277e832SShreyas NC if (ret < 0)
28916277e832SShreyas NC return ret;
28926277e832SShreyas NC num_blocks = ret;
28936277e832SShreyas NC
28946277e832SShreyas NC off += array->size;
28956277e832SShreyas NC /* Read the BLOCK_TYPE and BLOCK_SIZE descriptor */
28966277e832SShreyas NC while (num_blocks > 0) {
2897133e6e5cSShreyas NC array = (struct snd_soc_tplg_vendor_array *)
2898133e6e5cSShreyas NC (tplg_w->priv.data + off);
2899133e6e5cSShreyas NC
29006277e832SShreyas NC ret = skl_tplg_get_desc_blocks(dev, array);
29016277e832SShreyas NC
29026277e832SShreyas NC if (ret < 0)
29036277e832SShreyas NC return ret;
29046277e832SShreyas NC block_type = ret;
29056277e832SShreyas NC off += array->size;
29066277e832SShreyas NC
29076277e832SShreyas NC array = (struct snd_soc_tplg_vendor_array *)
29086277e832SShreyas NC (tplg_w->priv.data + off);
29096277e832SShreyas NC
29106277e832SShreyas NC ret = skl_tplg_get_desc_blocks(dev, array);
29116277e832SShreyas NC
29126277e832SShreyas NC if (ret < 0)
29136277e832SShreyas NC return ret;
29146277e832SShreyas NC block_size = ret;
29156277e832SShreyas NC off += array->size;
29166277e832SShreyas NC
29176277e832SShreyas NC data = (tplg_w->priv.data + off);
29186277e832SShreyas NC
29196277e832SShreyas NC if (block_type == SKL_TYPE_TUPLE) {
29206277e832SShreyas NC ret = skl_tplg_get_tokens(dev, data,
29216277e832SShreyas NC skl, mconfig, block_size);
2922a4ad42d2SKareem Shaik } else {
2923a4ad42d2SKareem Shaik ret = skl_tplg_get_caps_data(dev, data, mconfig);
2924a4ad42d2SKareem Shaik }
29256277e832SShreyas NC
29266277e832SShreyas NC if (ret < 0)
29276277e832SShreyas NC return ret;
29286277e832SShreyas NC
29296277e832SShreyas NC --num_blocks;
2930133e6e5cSShreyas NC off += ret;
29316277e832SShreyas NC }
29326277e832SShreyas NC
29336277e832SShreyas NC return 0;
29344cd9899fSHardik T Shah }
29354cd9899fSHardik T Shah
skl_clear_pin_config(struct snd_soc_component * component,struct snd_soc_dapm_widget * w)293656b03b4cSKuninori Morimoto static void skl_clear_pin_config(struct snd_soc_component *component,
2937fe3f4442SDharageswari R struct snd_soc_dapm_widget *w)
2938fe3f4442SDharageswari R {
2939fe3f4442SDharageswari R int i;
2940fe3f4442SDharageswari R struct skl_module_cfg *mconfig;
2941fe3f4442SDharageswari R struct skl_pipe *pipe;
2942fe3f4442SDharageswari R
294356b03b4cSKuninori Morimoto if (!strncmp(w->dapm->component->name, component->name,
294456b03b4cSKuninori Morimoto strlen(component->name))) {
2945fe3f4442SDharageswari R mconfig = w->priv;
2946fe3f4442SDharageswari R pipe = mconfig->pipe;
2947f6fa56e2SRamesh Babu for (i = 0; i < mconfig->module->max_input_pins; i++) {
2948fe3f4442SDharageswari R mconfig->m_in_pin[i].in_use = false;
2949fe3f4442SDharageswari R mconfig->m_in_pin[i].pin_state = SKL_PIN_UNBIND;
2950fe3f4442SDharageswari R }
2951f6fa56e2SRamesh Babu for (i = 0; i < mconfig->module->max_output_pins; i++) {
2952fe3f4442SDharageswari R mconfig->m_out_pin[i].in_use = false;
2953fe3f4442SDharageswari R mconfig->m_out_pin[i].pin_state = SKL_PIN_UNBIND;
2954fe3f4442SDharageswari R }
2955fe3f4442SDharageswari R pipe->state = SKL_PIPE_INVALID;
2956fe3f4442SDharageswari R mconfig->m_state = SKL_MODULE_UNINIT;
2957fe3f4442SDharageswari R }
2958fe3f4442SDharageswari R }
2959fe3f4442SDharageswari R
skl_cleanup_resources(struct skl_dev * skl)2960bcc2a2dcSCezary Rojewski void skl_cleanup_resources(struct skl_dev *skl)
2961fe3f4442SDharageswari R {
296256b03b4cSKuninori Morimoto struct snd_soc_component *soc_component = skl->component;
2963fe3f4442SDharageswari R struct snd_soc_dapm_widget *w;
2964fe3f4442SDharageswari R struct snd_soc_card *card;
2965fe3f4442SDharageswari R
296656b03b4cSKuninori Morimoto if (soc_component == NULL)
2967fe3f4442SDharageswari R return;
2968fe3f4442SDharageswari R
296956b03b4cSKuninori Morimoto card = soc_component->card;
2970*ec4b2099SKuninori Morimoto if (!snd_soc_card_is_instantiated(card))
2971fe3f4442SDharageswari R return;
2972fe3f4442SDharageswari R
2973fe3f4442SDharageswari R list_for_each_entry(w, &card->widgets, list) {
2974bcc2a2dcSCezary Rojewski if (is_skl_dsp_widget_type(w, skl->dev) && w->priv != NULL)
297556b03b4cSKuninori Morimoto skl_clear_pin_config(soc_component, w);
2976fe3f4442SDharageswari R }
2977fe3f4442SDharageswari R
2978bcc2a2dcSCezary Rojewski skl_clear_module_cnt(skl->dsp);
2979fe3f4442SDharageswari R }
2980fe3f4442SDharageswari R
29813af36706SVinod Koul /*
29823af36706SVinod Koul * Topology core widget load callback
29833af36706SVinod Koul *
29843af36706SVinod Koul * This is used to save the private data for each widget which gives
29853af36706SVinod Koul * information to the driver about module and pipeline parameters which DSP
29863af36706SVinod Koul * FW expects like ids, resource values, formats etc
29873af36706SVinod Koul */
skl_tplg_widget_load(struct snd_soc_component * cmpnt,int index,struct snd_soc_dapm_widget * w,struct snd_soc_tplg_dapm_widget * tplg_w)2988c60b613aSLiam Girdwood static int skl_tplg_widget_load(struct snd_soc_component *cmpnt, int index,
29893af36706SVinod Koul struct snd_soc_dapm_widget *w,
29903af36706SVinod Koul struct snd_soc_tplg_dapm_widget *tplg_w)
29913af36706SVinod Koul {
29923af36706SVinod Koul int ret;
299376f56faeSRakesh Ughreja struct hdac_bus *bus = snd_soc_component_get_drvdata(cmpnt);
2994bcc2a2dcSCezary Rojewski struct skl_dev *skl = bus_to_skl(bus);
29953af36706SVinod Koul struct skl_module_cfg *mconfig;
29963af36706SVinod Koul
29973af36706SVinod Koul if (!tplg_w->priv.size)
29983af36706SVinod Koul goto bind_event;
29993af36706SVinod Koul
30003af36706SVinod Koul mconfig = devm_kzalloc(bus->dev, sizeof(*mconfig), GFP_KERNEL);
30013af36706SVinod Koul
30023af36706SVinod Koul if (!mconfig)
30033af36706SVinod Koul return -ENOMEM;
30043af36706SVinod Koul
3005f6fa56e2SRamesh Babu if (skl->nr_modules == 0) {
3006f6fa56e2SRamesh Babu mconfig->module = devm_kzalloc(bus->dev,
3007f6fa56e2SRamesh Babu sizeof(*mconfig->module), GFP_KERNEL);
3008f6fa56e2SRamesh Babu if (!mconfig->module)
3009f6fa56e2SRamesh Babu return -ENOMEM;
3010f6fa56e2SRamesh Babu }
3011f6fa56e2SRamesh Babu
30123af36706SVinod Koul w->priv = mconfig;
301309305da9SShreyas NC
3014b7c50555SVinod Koul /*
3015b7c50555SVinod Koul * module binary can be loaded later, so set it to query when
3016b7c50555SVinod Koul * module is load for a use case
3017b7c50555SVinod Koul */
3018b7c50555SVinod Koul mconfig->id.module_id = -1;
30194cd9899fSHardik T Shah
3020a4ad42d2SKareem Shaik /* To provide backward compatibility, set default as SKL_PARAM_INIT */
3021a4ad42d2SKareem Shaik mconfig->fmt_cfg_idx = SKL_PARAM_INIT;
3022a4ad42d2SKareem Shaik
30236277e832SShreyas NC /* Parse private data for tuples */
30246277e832SShreyas NC ret = skl_tplg_get_pvt_data(tplg_w, skl, bus->dev, mconfig);
30256277e832SShreyas NC if (ret < 0)
30266277e832SShreyas NC return ret;
3027d14700a0SVinod Koul
3028d14700a0SVinod Koul skl_debug_init_module(skl->debugfs, w, mconfig);
3029d14700a0SVinod Koul
30303af36706SVinod Koul bind_event:
30313af36706SVinod Koul if (tplg_w->event_type == 0) {
30323373f716SVinod Koul dev_dbg(bus->dev, "ASoC: No event handler required\n");
30333af36706SVinod Koul return 0;
30343af36706SVinod Koul }
30353af36706SVinod Koul
30363af36706SVinod Koul ret = snd_soc_tplg_widget_bind_event(w, skl_tplg_widget_ops,
3037b663a8c5SJeeja KP ARRAY_SIZE(skl_tplg_widget_ops),
3038b663a8c5SJeeja KP tplg_w->event_type);
30393af36706SVinod Koul
30403af36706SVinod Koul if (ret) {
30413af36706SVinod Koul dev_err(bus->dev, "%s: No matching event handlers found for %d\n",
30423af36706SVinod Koul __func__, tplg_w->event_type);
30433af36706SVinod Koul return -EINVAL;
30443af36706SVinod Koul }
30453af36706SVinod Koul
30463af36706SVinod Koul return 0;
30473af36706SVinod Koul }
30483af36706SVinod Koul
skl_init_algo_data(struct device * dev,struct soc_bytes_ext * be,struct snd_soc_tplg_bytes_control * bc)3049140adfbaSJeeja KP static int skl_init_algo_data(struct device *dev, struct soc_bytes_ext *be,
3050140adfbaSJeeja KP struct snd_soc_tplg_bytes_control *bc)
3051140adfbaSJeeja KP {
3052140adfbaSJeeja KP struct skl_algo_data *ac;
3053140adfbaSJeeja KP struct skl_dfw_algo_data *dfw_ac =
3054140adfbaSJeeja KP (struct skl_dfw_algo_data *)bc->priv.data;
3055140adfbaSJeeja KP
3056140adfbaSJeeja KP ac = devm_kzalloc(dev, sizeof(*ac), GFP_KERNEL);
3057140adfbaSJeeja KP if (!ac)
3058140adfbaSJeeja KP return -ENOMEM;
3059140adfbaSJeeja KP
3060140adfbaSJeeja KP /* Fill private data */
3061140adfbaSJeeja KP ac->max = dfw_ac->max;
3062140adfbaSJeeja KP ac->param_id = dfw_ac->param_id;
3063140adfbaSJeeja KP ac->set_params = dfw_ac->set_params;
30640d682104SDharageswari R ac->size = dfw_ac->max;
3065140adfbaSJeeja KP
3066140adfbaSJeeja KP if (ac->max) {
3067431b67c2SPierre-Louis Bossart ac->params = devm_kzalloc(dev, ac->max, GFP_KERNEL);
3068140adfbaSJeeja KP if (!ac->params)
3069140adfbaSJeeja KP return -ENOMEM;
3070140adfbaSJeeja KP
3071140adfbaSJeeja KP memcpy(ac->params, dfw_ac->params, ac->max);
3072140adfbaSJeeja KP }
3073140adfbaSJeeja KP
3074140adfbaSJeeja KP be->dobj.private = ac;
3075140adfbaSJeeja KP return 0;
3076140adfbaSJeeja KP }
3077140adfbaSJeeja KP
skl_init_enum_data(struct device * dev,struct soc_enum * se,struct snd_soc_tplg_enum_control * ec)30787a1b749bSDharageswari R static int skl_init_enum_data(struct device *dev, struct soc_enum *se,
30797a1b749bSDharageswari R struct snd_soc_tplg_enum_control *ec)
30807a1b749bSDharageswari R {
30817a1b749bSDharageswari R
30827a1b749bSDharageswari R void *data;
30837a1b749bSDharageswari R
30847a1b749bSDharageswari R if (ec->priv.size) {
30857a1b749bSDharageswari R data = devm_kzalloc(dev, sizeof(ec->priv.size), GFP_KERNEL);
30867a1b749bSDharageswari R if (!data)
30877a1b749bSDharageswari R return -ENOMEM;
30887a1b749bSDharageswari R memcpy(data, ec->priv.data, ec->priv.size);
30897a1b749bSDharageswari R se->dobj.private = data;
30907a1b749bSDharageswari R }
30917a1b749bSDharageswari R
30927a1b749bSDharageswari R return 0;
30937a1b749bSDharageswari R
30947a1b749bSDharageswari R }
30957a1b749bSDharageswari R
skl_tplg_control_load(struct snd_soc_component * cmpnt,int index,struct snd_kcontrol_new * kctl,struct snd_soc_tplg_ctl_hdr * hdr)3096140adfbaSJeeja KP static int skl_tplg_control_load(struct snd_soc_component *cmpnt,
3097c60b613aSLiam Girdwood int index,
3098140adfbaSJeeja KP struct snd_kcontrol_new *kctl,
3099140adfbaSJeeja KP struct snd_soc_tplg_ctl_hdr *hdr)
3100140adfbaSJeeja KP {
3101140adfbaSJeeja KP struct soc_bytes_ext *sb;
3102140adfbaSJeeja KP struct snd_soc_tplg_bytes_control *tplg_bc;
31037a1b749bSDharageswari R struct snd_soc_tplg_enum_control *tplg_ec;
310476f56faeSRakesh Ughreja struct hdac_bus *bus = snd_soc_component_get_drvdata(cmpnt);
31057a1b749bSDharageswari R struct soc_enum *se;
3106140adfbaSJeeja KP
3107140adfbaSJeeja KP switch (hdr->ops.info) {
3108140adfbaSJeeja KP case SND_SOC_TPLG_CTL_BYTES:
3109140adfbaSJeeja KP tplg_bc = container_of(hdr,
3110140adfbaSJeeja KP struct snd_soc_tplg_bytes_control, hdr);
3111140adfbaSJeeja KP if (kctl->access & SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK) {
3112140adfbaSJeeja KP sb = (struct soc_bytes_ext *)kctl->private_value;
3113140adfbaSJeeja KP if (tplg_bc->priv.size)
3114140adfbaSJeeja KP return skl_init_algo_data(
3115140adfbaSJeeja KP bus->dev, sb, tplg_bc);
3116140adfbaSJeeja KP }
3117140adfbaSJeeja KP break;
3118140adfbaSJeeja KP
31197a1b749bSDharageswari R case SND_SOC_TPLG_CTL_ENUM:
31207a1b749bSDharageswari R tplg_ec = container_of(hdr,
31217a1b749bSDharageswari R struct snd_soc_tplg_enum_control, hdr);
31222d744ecfSMateusz Gorski if (kctl->access & SNDRV_CTL_ELEM_ACCESS_READ) {
31237a1b749bSDharageswari R se = (struct soc_enum *)kctl->private_value;
31247a1b749bSDharageswari R if (tplg_ec->priv.size)
31252d744ecfSMateusz Gorski skl_init_enum_data(bus->dev, se, tplg_ec);
31267a1b749bSDharageswari R }
31272d744ecfSMateusz Gorski
31282d744ecfSMateusz Gorski /*
31292d744ecfSMateusz Gorski * now that the control initializations are done, remove
31302d744ecfSMateusz Gorski * write permission for the DMIC configuration enums to
31312d744ecfSMateusz Gorski * avoid conflicts between NHLT settings and user interaction
31322d744ecfSMateusz Gorski */
31332d744ecfSMateusz Gorski
31342d744ecfSMateusz Gorski if (hdr->ops.get == SKL_CONTROL_TYPE_MULTI_IO_SELECT_DMIC)
31352d744ecfSMateusz Gorski kctl->access = SNDRV_CTL_ELEM_ACCESS_READ;
31362d744ecfSMateusz Gorski
31377a1b749bSDharageswari R break;
31387a1b749bSDharageswari R
3139140adfbaSJeeja KP default:
31404362934aSNaveen Manohar dev_dbg(bus->dev, "Control load not supported %d:%d:%d\n",
3141140adfbaSJeeja KP hdr->ops.get, hdr->ops.put, hdr->ops.info);
3142140adfbaSJeeja KP break;
3143140adfbaSJeeja KP }
3144140adfbaSJeeja KP
3145140adfbaSJeeja KP return 0;
3146140adfbaSJeeja KP }
3147140adfbaSJeeja KP
skl_tplg_fill_str_mfest_tkn(struct device * dev,struct snd_soc_tplg_vendor_string_elem * str_elem,struct skl_dev * skl)3148541070ceSShreyas NC static int skl_tplg_fill_str_mfest_tkn(struct device *dev,
3149541070ceSShreyas NC struct snd_soc_tplg_vendor_string_elem *str_elem,
3150bcc2a2dcSCezary Rojewski struct skl_dev *skl)
3151541070ceSShreyas NC {
3152541070ceSShreyas NC int tkn_count = 0;
3153541070ceSShreyas NC static int ref_count;
3154541070ceSShreyas NC
3155541070ceSShreyas NC switch (str_elem->token) {
3156541070ceSShreyas NC case SKL_TKN_STR_LIB_NAME:
3157bcc2a2dcSCezary Rojewski if (ref_count > skl->lib_count - 1) {
3158541070ceSShreyas NC ref_count = 0;
3159541070ceSShreyas NC return -EINVAL;
3160541070ceSShreyas NC }
3161541070ceSShreyas NC
3162bcc2a2dcSCezary Rojewski strncpy(skl->lib_info[ref_count].name,
3163eee0e16fSJeeja KP str_elem->string,
3164bcc2a2dcSCezary Rojewski ARRAY_SIZE(skl->lib_info[ref_count].name));
3165541070ceSShreyas NC ref_count++;
3166541070ceSShreyas NC break;
3167541070ceSShreyas NC
3168541070ceSShreyas NC default:
3169ecd286a9SColin Ian King dev_err(dev, "Not a string token %d\n", str_elem->token);
3170541070ceSShreyas NC break;
3171541070ceSShreyas NC }
3172db6ed55dSShreyas NC tkn_count++;
3173541070ceSShreyas NC
3174541070ceSShreyas NC return tkn_count;
3175541070ceSShreyas NC }
3176541070ceSShreyas NC
skl_tplg_get_str_tkn(struct device * dev,struct snd_soc_tplg_vendor_array * array,struct skl_dev * skl)3177541070ceSShreyas NC static int skl_tplg_get_str_tkn(struct device *dev,
3178541070ceSShreyas NC struct snd_soc_tplg_vendor_array *array,
3179bcc2a2dcSCezary Rojewski struct skl_dev *skl)
3180541070ceSShreyas NC {
3181541070ceSShreyas NC int tkn_count = 0, ret;
3182541070ceSShreyas NC struct snd_soc_tplg_vendor_string_elem *str_elem;
3183541070ceSShreyas NC
3184541070ceSShreyas NC str_elem = (struct snd_soc_tplg_vendor_string_elem *)array->value;
3185541070ceSShreyas NC while (tkn_count < array->num_elems) {
3186eee0e16fSJeeja KP ret = skl_tplg_fill_str_mfest_tkn(dev, str_elem, skl);
3187541070ceSShreyas NC str_elem++;
3188541070ceSShreyas NC
3189541070ceSShreyas NC if (ret < 0)
3190541070ceSShreyas NC return ret;
3191541070ceSShreyas NC
3192541070ceSShreyas NC tkn_count = tkn_count + ret;
3193541070ceSShreyas NC }
3194541070ceSShreyas NC
3195541070ceSShreyas NC return tkn_count;
3196541070ceSShreyas NC }
3197541070ceSShreyas NC
skl_tplg_manifest_fill_fmt(struct device * dev,struct skl_module_iface * fmt,struct snd_soc_tplg_vendor_value_elem * tkn_elem,u32 dir,int fmt_idx)3198db6ed55dSShreyas NC static int skl_tplg_manifest_fill_fmt(struct device *dev,
3199db6ed55dSShreyas NC struct skl_module_iface *fmt,
3200db6ed55dSShreyas NC struct snd_soc_tplg_vendor_value_elem *tkn_elem,
3201db6ed55dSShreyas NC u32 dir, int fmt_idx)
3202db6ed55dSShreyas NC {
3203db6ed55dSShreyas NC struct skl_module_pin_fmt *dst_fmt;
3204db6ed55dSShreyas NC struct skl_module_fmt *mod_fmt;
3205db6ed55dSShreyas NC int ret;
3206db6ed55dSShreyas NC
3207db6ed55dSShreyas NC if (!fmt)
3208db6ed55dSShreyas NC return -EINVAL;
3209db6ed55dSShreyas NC
3210db6ed55dSShreyas NC switch (dir) {
3211db6ed55dSShreyas NC case SKL_DIR_IN:
3212db6ed55dSShreyas NC dst_fmt = &fmt->inputs[fmt_idx];
3213db6ed55dSShreyas NC break;
3214db6ed55dSShreyas NC
3215db6ed55dSShreyas NC case SKL_DIR_OUT:
3216db6ed55dSShreyas NC dst_fmt = &fmt->outputs[fmt_idx];
3217db6ed55dSShreyas NC break;
3218db6ed55dSShreyas NC
3219db6ed55dSShreyas NC default:
3220db6ed55dSShreyas NC dev_err(dev, "Invalid direction: %d\n", dir);
3221db6ed55dSShreyas NC return -EINVAL;
3222db6ed55dSShreyas NC }
3223db6ed55dSShreyas NC
3224db6ed55dSShreyas NC mod_fmt = &dst_fmt->fmt;
3225db6ed55dSShreyas NC
3226db6ed55dSShreyas NC switch (tkn_elem->token) {
3227db6ed55dSShreyas NC case SKL_TKN_MM_U32_INTF_PIN_ID:
3228db6ed55dSShreyas NC dst_fmt->id = tkn_elem->value;
3229db6ed55dSShreyas NC break;
3230db6ed55dSShreyas NC
3231db6ed55dSShreyas NC default:
3232db6ed55dSShreyas NC ret = skl_tplg_fill_fmt(dev, mod_fmt, tkn_elem->token,
3233db6ed55dSShreyas NC tkn_elem->value);
3234db6ed55dSShreyas NC if (ret < 0)
3235db6ed55dSShreyas NC return ret;
3236db6ed55dSShreyas NC break;
3237db6ed55dSShreyas NC }
3238db6ed55dSShreyas NC
3239db6ed55dSShreyas NC return 0;
3240db6ed55dSShreyas NC }
3241db6ed55dSShreyas NC
skl_tplg_fill_mod_info(struct device * dev,struct snd_soc_tplg_vendor_value_elem * tkn_elem,struct skl_module * mod)3242db6ed55dSShreyas NC static int skl_tplg_fill_mod_info(struct device *dev,
3243db6ed55dSShreyas NC struct snd_soc_tplg_vendor_value_elem *tkn_elem,
3244db6ed55dSShreyas NC struct skl_module *mod)
3245db6ed55dSShreyas NC {
3246db6ed55dSShreyas NC
3247db6ed55dSShreyas NC if (!mod)
3248db6ed55dSShreyas NC return -EINVAL;
3249db6ed55dSShreyas NC
3250db6ed55dSShreyas NC switch (tkn_elem->token) {
3251db6ed55dSShreyas NC case SKL_TKN_U8_IN_PIN_TYPE:
3252db6ed55dSShreyas NC mod->input_pin_type = tkn_elem->value;
3253db6ed55dSShreyas NC break;
3254db6ed55dSShreyas NC
3255db6ed55dSShreyas NC case SKL_TKN_U8_OUT_PIN_TYPE:
3256db6ed55dSShreyas NC mod->output_pin_type = tkn_elem->value;
3257db6ed55dSShreyas NC break;
3258db6ed55dSShreyas NC
3259db6ed55dSShreyas NC case SKL_TKN_U8_IN_QUEUE_COUNT:
3260db6ed55dSShreyas NC mod->max_input_pins = tkn_elem->value;
3261db6ed55dSShreyas NC break;
3262db6ed55dSShreyas NC
3263db6ed55dSShreyas NC case SKL_TKN_U8_OUT_QUEUE_COUNT:
3264db6ed55dSShreyas NC mod->max_output_pins = tkn_elem->value;
3265db6ed55dSShreyas NC break;
3266db6ed55dSShreyas NC
3267db6ed55dSShreyas NC case SKL_TKN_MM_U8_NUM_RES:
3268db6ed55dSShreyas NC mod->nr_resources = tkn_elem->value;
3269db6ed55dSShreyas NC break;
3270db6ed55dSShreyas NC
3271db6ed55dSShreyas NC case SKL_TKN_MM_U8_NUM_INTF:
3272db6ed55dSShreyas NC mod->nr_interfaces = tkn_elem->value;
3273db6ed55dSShreyas NC break;
3274db6ed55dSShreyas NC
3275db6ed55dSShreyas NC default:
3276db6ed55dSShreyas NC dev_err(dev, "Invalid mod info token %d", tkn_elem->token);
3277db6ed55dSShreyas NC return -EINVAL;
3278db6ed55dSShreyas NC }
3279db6ed55dSShreyas NC
3280db6ed55dSShreyas NC return 0;
3281db6ed55dSShreyas NC }
3282db6ed55dSShreyas NC
3283db6ed55dSShreyas NC
skl_tplg_get_int_tkn(struct device * dev,struct snd_soc_tplg_vendor_value_elem * tkn_elem,struct skl_dev * skl)3284541070ceSShreyas NC static int skl_tplg_get_int_tkn(struct device *dev,
3285541070ceSShreyas NC struct snd_soc_tplg_vendor_value_elem *tkn_elem,
3286bcc2a2dcSCezary Rojewski struct skl_dev *skl)
3287541070ceSShreyas NC {
3288d00cc2f1SGustavo A. R. Silva int tkn_count = 0, ret;
3289db6ed55dSShreyas NC static int mod_idx, res_val_idx, intf_val_idx, dir, pin_idx;
3290db6ed55dSShreyas NC struct skl_module_res *res = NULL;
3291db6ed55dSShreyas NC struct skl_module_iface *fmt = NULL;
3292db6ed55dSShreyas NC struct skl_module *mod = NULL;
329343762355SPradeep Tewani static struct skl_astate_param *astate_table;
329443762355SPradeep Tewani static int astate_cfg_idx, count;
3295db6ed55dSShreyas NC int i;
3296d00cc2f1SGustavo A. R. Silva size_t size;
3297db6ed55dSShreyas NC
3298db6ed55dSShreyas NC if (skl->modules) {
3299db6ed55dSShreyas NC mod = skl->modules[mod_idx];
3300db6ed55dSShreyas NC res = &mod->resources[res_val_idx];
3301db6ed55dSShreyas NC fmt = &mod->formats[intf_val_idx];
3302db6ed55dSShreyas NC }
3303541070ceSShreyas NC
3304541070ceSShreyas NC switch (tkn_elem->token) {
3305541070ceSShreyas NC case SKL_TKN_U32_LIB_COUNT:
3306bcc2a2dcSCezary Rojewski skl->lib_count = tkn_elem->value;
3307db6ed55dSShreyas NC break;
3308db6ed55dSShreyas NC
3309db6ed55dSShreyas NC case SKL_TKN_U8_NUM_MOD:
3310db6ed55dSShreyas NC skl->nr_modules = tkn_elem->value;
3311db6ed55dSShreyas NC skl->modules = devm_kcalloc(dev, skl->nr_modules,
3312db6ed55dSShreyas NC sizeof(*skl->modules), GFP_KERNEL);
3313db6ed55dSShreyas NC if (!skl->modules)
3314db6ed55dSShreyas NC return -ENOMEM;
3315db6ed55dSShreyas NC
3316db6ed55dSShreyas NC for (i = 0; i < skl->nr_modules; i++) {
3317db6ed55dSShreyas NC skl->modules[i] = devm_kzalloc(dev,
3318db6ed55dSShreyas NC sizeof(struct skl_module), GFP_KERNEL);
3319db6ed55dSShreyas NC if (!skl->modules[i])
3320db6ed55dSShreyas NC return -ENOMEM;
3321db6ed55dSShreyas NC }
3322db6ed55dSShreyas NC break;
3323db6ed55dSShreyas NC
3324db6ed55dSShreyas NC case SKL_TKN_MM_U8_MOD_IDX:
3325db6ed55dSShreyas NC mod_idx = tkn_elem->value;
3326db6ed55dSShreyas NC break;
3327db6ed55dSShreyas NC
332843762355SPradeep Tewani case SKL_TKN_U32_ASTATE_COUNT:
332943762355SPradeep Tewani if (astate_table != NULL) {
333043762355SPradeep Tewani dev_err(dev, "More than one entry for A-State count");
333143762355SPradeep Tewani return -EINVAL;
333243762355SPradeep Tewani }
333343762355SPradeep Tewani
333443762355SPradeep Tewani if (tkn_elem->value > SKL_MAX_ASTATE_CFG) {
333543762355SPradeep Tewani dev_err(dev, "Invalid A-State count %d\n",
333643762355SPradeep Tewani tkn_elem->value);
333743762355SPradeep Tewani return -EINVAL;
333843762355SPradeep Tewani }
333943762355SPradeep Tewani
3340d00cc2f1SGustavo A. R. Silva size = struct_size(skl->cfg.astate_cfg, astate_table,
3341d00cc2f1SGustavo A. R. Silva tkn_elem->value);
334243762355SPradeep Tewani skl->cfg.astate_cfg = devm_kzalloc(dev, size, GFP_KERNEL);
334343762355SPradeep Tewani if (!skl->cfg.astate_cfg)
334443762355SPradeep Tewani return -ENOMEM;
334543762355SPradeep Tewani
334643762355SPradeep Tewani astate_table = skl->cfg.astate_cfg->astate_table;
334743762355SPradeep Tewani count = skl->cfg.astate_cfg->count = tkn_elem->value;
334843762355SPradeep Tewani break;
334943762355SPradeep Tewani
335043762355SPradeep Tewani case SKL_TKN_U32_ASTATE_IDX:
335143762355SPradeep Tewani if (tkn_elem->value >= count) {
335243762355SPradeep Tewani dev_err(dev, "Invalid A-State index %d\n",
335343762355SPradeep Tewani tkn_elem->value);
335443762355SPradeep Tewani return -EINVAL;
335543762355SPradeep Tewani }
335643762355SPradeep Tewani
335743762355SPradeep Tewani astate_cfg_idx = tkn_elem->value;
335843762355SPradeep Tewani break;
335943762355SPradeep Tewani
336043762355SPradeep Tewani case SKL_TKN_U32_ASTATE_KCPS:
336143762355SPradeep Tewani astate_table[astate_cfg_idx].kcps = tkn_elem->value;
336243762355SPradeep Tewani break;
336343762355SPradeep Tewani
336443762355SPradeep Tewani case SKL_TKN_U32_ASTATE_CLK_SRC:
336543762355SPradeep Tewani astate_table[astate_cfg_idx].clk_src = tkn_elem->value;
336643762355SPradeep Tewani break;
336743762355SPradeep Tewani
3368db6ed55dSShreyas NC case SKL_TKN_U8_IN_PIN_TYPE:
3369db6ed55dSShreyas NC case SKL_TKN_U8_OUT_PIN_TYPE:
3370db6ed55dSShreyas NC case SKL_TKN_U8_IN_QUEUE_COUNT:
3371db6ed55dSShreyas NC case SKL_TKN_U8_OUT_QUEUE_COUNT:
3372db6ed55dSShreyas NC case SKL_TKN_MM_U8_NUM_RES:
3373db6ed55dSShreyas NC case SKL_TKN_MM_U8_NUM_INTF:
3374db6ed55dSShreyas NC ret = skl_tplg_fill_mod_info(dev, tkn_elem, mod);
3375db6ed55dSShreyas NC if (ret < 0)
3376db6ed55dSShreyas NC return ret;
3377db6ed55dSShreyas NC break;
3378db6ed55dSShreyas NC
3379db6ed55dSShreyas NC case SKL_TKN_U32_DIR_PIN_COUNT:
3380db6ed55dSShreyas NC dir = tkn_elem->value & SKL_IN_DIR_BIT_MASK;
3381db6ed55dSShreyas NC pin_idx = (tkn_elem->value & SKL_PIN_COUNT_MASK) >> 4;
3382db6ed55dSShreyas NC break;
3383db6ed55dSShreyas NC
3384db6ed55dSShreyas NC case SKL_TKN_MM_U32_RES_ID:
3385db6ed55dSShreyas NC if (!res)
3386db6ed55dSShreyas NC return -EINVAL;
3387db6ed55dSShreyas NC
3388db6ed55dSShreyas NC res->id = tkn_elem->value;
3389db6ed55dSShreyas NC res_val_idx = tkn_elem->value;
3390db6ed55dSShreyas NC break;
3391db6ed55dSShreyas NC
3392db6ed55dSShreyas NC case SKL_TKN_MM_U32_FMT_ID:
3393db6ed55dSShreyas NC if (!fmt)
3394db6ed55dSShreyas NC return -EINVAL;
3395db6ed55dSShreyas NC
3396db6ed55dSShreyas NC fmt->fmt_idx = tkn_elem->value;
3397db6ed55dSShreyas NC intf_val_idx = tkn_elem->value;
3398db6ed55dSShreyas NC break;
3399db6ed55dSShreyas NC
3400db6ed55dSShreyas NC case SKL_TKN_MM_U32_CPS:
3401db6ed55dSShreyas NC case SKL_TKN_MM_U32_DMA_SIZE:
3402db6ed55dSShreyas NC case SKL_TKN_MM_U32_CPC:
3403db6ed55dSShreyas NC case SKL_TKN_U32_MEM_PAGES:
3404db6ed55dSShreyas NC case SKL_TKN_U32_OBS:
3405db6ed55dSShreyas NC case SKL_TKN_U32_IBS:
3406db6ed55dSShreyas NC case SKL_TKN_MM_U32_RES_PIN_ID:
3407db6ed55dSShreyas NC case SKL_TKN_MM_U32_PIN_BUF:
3408db6ed55dSShreyas NC ret = skl_tplg_fill_res_tkn(dev, tkn_elem, res, pin_idx, dir);
3409db6ed55dSShreyas NC if (ret < 0)
3410db6ed55dSShreyas NC return ret;
3411db6ed55dSShreyas NC
3412db6ed55dSShreyas NC break;
3413db6ed55dSShreyas NC
3414db6ed55dSShreyas NC case SKL_TKN_MM_U32_NUM_IN_FMT:
3415db6ed55dSShreyas NC if (!fmt)
3416db6ed55dSShreyas NC return -EINVAL;
3417db6ed55dSShreyas NC
3418db6ed55dSShreyas NC res->nr_input_pins = tkn_elem->value;
3419db6ed55dSShreyas NC break;
3420db6ed55dSShreyas NC
3421db6ed55dSShreyas NC case SKL_TKN_MM_U32_NUM_OUT_FMT:
3422db6ed55dSShreyas NC if (!fmt)
3423db6ed55dSShreyas NC return -EINVAL;
3424db6ed55dSShreyas NC
3425db6ed55dSShreyas NC res->nr_output_pins = tkn_elem->value;
3426db6ed55dSShreyas NC break;
3427db6ed55dSShreyas NC
3428db6ed55dSShreyas NC case SKL_TKN_U32_FMT_CH:
3429db6ed55dSShreyas NC case SKL_TKN_U32_FMT_FREQ:
3430db6ed55dSShreyas NC case SKL_TKN_U32_FMT_BIT_DEPTH:
3431db6ed55dSShreyas NC case SKL_TKN_U32_FMT_SAMPLE_SIZE:
3432db6ed55dSShreyas NC case SKL_TKN_U32_FMT_CH_CONFIG:
3433db6ed55dSShreyas NC case SKL_TKN_U32_FMT_INTERLEAVE:
3434db6ed55dSShreyas NC case SKL_TKN_U32_FMT_SAMPLE_TYPE:
3435db6ed55dSShreyas NC case SKL_TKN_U32_FMT_CH_MAP:
3436db6ed55dSShreyas NC case SKL_TKN_MM_U32_INTF_PIN_ID:
3437db6ed55dSShreyas NC ret = skl_tplg_manifest_fill_fmt(dev, fmt, tkn_elem,
3438db6ed55dSShreyas NC dir, pin_idx);
3439db6ed55dSShreyas NC if (ret < 0)
3440db6ed55dSShreyas NC return ret;
3441541070ceSShreyas NC break;
3442541070ceSShreyas NC
3443541070ceSShreyas NC default:
3444ecd286a9SColin Ian King dev_err(dev, "Not a manifest token %d\n", tkn_elem->token);
3445541070ceSShreyas NC return -EINVAL;
3446541070ceSShreyas NC }
3447db6ed55dSShreyas NC tkn_count++;
3448541070ceSShreyas NC
3449541070ceSShreyas NC return tkn_count;
3450541070ceSShreyas NC }
3451541070ceSShreyas NC
3452541070ceSShreyas NC /*
3453541070ceSShreyas NC * Fill the manifest structure by parsing the tokens based on the
3454541070ceSShreyas NC * type.
3455541070ceSShreyas NC */
skl_tplg_get_manifest_tkn(struct device * dev,char * pvt_data,struct skl_dev * skl,int block_size)3456541070ceSShreyas NC static int skl_tplg_get_manifest_tkn(struct device *dev,
3457bcc2a2dcSCezary Rojewski char *pvt_data, struct skl_dev *skl,
3458541070ceSShreyas NC int block_size)
3459541070ceSShreyas NC {
3460541070ceSShreyas NC int tkn_count = 0, ret;
3461541070ceSShreyas NC int off = 0, tuple_size = 0;
3462096769eaSAmadeusz Sławiński u8 uuid_index = 0;
3463541070ceSShreyas NC struct snd_soc_tplg_vendor_array *array;
3464541070ceSShreyas NC struct snd_soc_tplg_vendor_value_elem *tkn_elem;
3465541070ceSShreyas NC
3466541070ceSShreyas NC if (block_size <= 0)
3467541070ceSShreyas NC return -EINVAL;
3468541070ceSShreyas NC
3469541070ceSShreyas NC while (tuple_size < block_size) {
3470541070ceSShreyas NC array = (struct snd_soc_tplg_vendor_array *)(pvt_data + off);
3471541070ceSShreyas NC off += array->size;
3472541070ceSShreyas NC switch (array->type) {
3473541070ceSShreyas NC case SND_SOC_TPLG_TUPLE_TYPE_STRING:
3474eee0e16fSJeeja KP ret = skl_tplg_get_str_tkn(dev, array, skl);
3475541070ceSShreyas NC
3476541070ceSShreyas NC if (ret < 0)
3477541070ceSShreyas NC return ret;
34780a716776SShreyas NC tkn_count = ret;
3479541070ceSShreyas NC
3480541070ceSShreyas NC tuple_size += tkn_count *
3481541070ceSShreyas NC sizeof(struct snd_soc_tplg_vendor_string_elem);
3482541070ceSShreyas NC continue;
3483541070ceSShreyas NC
3484541070ceSShreyas NC case SND_SOC_TPLG_TUPLE_TYPE_UUID:
3485096769eaSAmadeusz Sławiński if (array->uuid->token != SKL_TKN_UUID) {
3486096769eaSAmadeusz Sławiński dev_err(dev, "Not an UUID token: %d\n",
3487096769eaSAmadeusz Sławiński array->uuid->token);
3488096769eaSAmadeusz Sławiński return -EINVAL;
3489096769eaSAmadeusz Sławiński }
3490096769eaSAmadeusz Sławiński if (uuid_index >= skl->nr_modules) {
3491096769eaSAmadeusz Sławiński dev_err(dev, "Too many UUID tokens\n");
3492096769eaSAmadeusz Sławiński return -EINVAL;
3493096769eaSAmadeusz Sławiński }
3494cade2f59SAndy Shevchenko import_guid(&skl->modules[uuid_index++]->uuid,
3495cade2f59SAndy Shevchenko array->uuid->uuid);
3496db6ed55dSShreyas NC
3497db6ed55dSShreyas NC tuple_size += sizeof(*array->uuid);
3498541070ceSShreyas NC continue;
3499541070ceSShreyas NC
3500541070ceSShreyas NC default:
3501541070ceSShreyas NC tkn_elem = array->value;
3502541070ceSShreyas NC tkn_count = 0;
3503541070ceSShreyas NC break;
3504541070ceSShreyas NC }
3505541070ceSShreyas NC
3506541070ceSShreyas NC while (tkn_count <= array->num_elems - 1) {
3507541070ceSShreyas NC ret = skl_tplg_get_int_tkn(dev,
3508eee0e16fSJeeja KP tkn_elem, skl);
3509541070ceSShreyas NC if (ret < 0)
3510541070ceSShreyas NC return ret;
3511541070ceSShreyas NC
3512541070ceSShreyas NC tkn_count = tkn_count + ret;
3513541070ceSShreyas NC tkn_elem++;
3514541070ceSShreyas NC }
35159fc129f6SShreyas NC tuple_size += (tkn_count * sizeof(*tkn_elem));
3516541070ceSShreyas NC tkn_count = 0;
3517541070ceSShreyas NC }
3518541070ceSShreyas NC
35199fc129f6SShreyas NC return off;
3520541070ceSShreyas NC }
3521541070ceSShreyas NC
3522541070ceSShreyas NC /*
3523541070ceSShreyas NC * Parse manifest private data for tokens. The private data block is
3524541070ceSShreyas NC * preceded by descriptors for type and size of data block.
3525541070ceSShreyas NC */
skl_tplg_get_manifest_data(struct snd_soc_tplg_manifest * manifest,struct device * dev,struct skl_dev * skl)3526541070ceSShreyas NC static int skl_tplg_get_manifest_data(struct snd_soc_tplg_manifest *manifest,
3527bcc2a2dcSCezary Rojewski struct device *dev, struct skl_dev *skl)
3528541070ceSShreyas NC {
3529541070ceSShreyas NC struct snd_soc_tplg_vendor_array *array;
3530541070ceSShreyas NC int num_blocks, block_size = 0, block_type, off = 0;
3531541070ceSShreyas NC char *data;
3532541070ceSShreyas NC int ret;
3533541070ceSShreyas NC
3534541070ceSShreyas NC /* Read the NUM_DATA_BLOCKS descriptor */
3535541070ceSShreyas NC array = (struct snd_soc_tplg_vendor_array *)manifest->priv.data;
3536541070ceSShreyas NC ret = skl_tplg_get_desc_blocks(dev, array);
3537541070ceSShreyas NC if (ret < 0)
3538541070ceSShreyas NC return ret;
3539541070ceSShreyas NC num_blocks = ret;
3540541070ceSShreyas NC
3541541070ceSShreyas NC off += array->size;
3542541070ceSShreyas NC /* Read the BLOCK_TYPE and BLOCK_SIZE descriptor */
3543541070ceSShreyas NC while (num_blocks > 0) {
35449fc129f6SShreyas NC array = (struct snd_soc_tplg_vendor_array *)
35459fc129f6SShreyas NC (manifest->priv.data + off);
3546541070ceSShreyas NC ret = skl_tplg_get_desc_blocks(dev, array);
3547541070ceSShreyas NC
3548541070ceSShreyas NC if (ret < 0)
3549541070ceSShreyas NC return ret;
3550541070ceSShreyas NC block_type = ret;
3551541070ceSShreyas NC off += array->size;
3552541070ceSShreyas NC
3553541070ceSShreyas NC array = (struct snd_soc_tplg_vendor_array *)
3554541070ceSShreyas NC (manifest->priv.data + off);
3555541070ceSShreyas NC
3556541070ceSShreyas NC ret = skl_tplg_get_desc_blocks(dev, array);
3557541070ceSShreyas NC
3558541070ceSShreyas NC if (ret < 0)
3559541070ceSShreyas NC return ret;
3560541070ceSShreyas NC block_size = ret;
3561541070ceSShreyas NC off += array->size;
3562541070ceSShreyas NC
3563541070ceSShreyas NC data = (manifest->priv.data + off);
3564541070ceSShreyas NC
3565541070ceSShreyas NC if (block_type == SKL_TYPE_TUPLE) {
3566eee0e16fSJeeja KP ret = skl_tplg_get_manifest_tkn(dev, data, skl,
3567541070ceSShreyas NC block_size);
3568541070ceSShreyas NC
3569541070ceSShreyas NC if (ret < 0)
3570541070ceSShreyas NC return ret;
3571541070ceSShreyas NC
3572541070ceSShreyas NC --num_blocks;
3573541070ceSShreyas NC } else {
3574541070ceSShreyas NC return -EINVAL;
3575541070ceSShreyas NC }
35769fc129f6SShreyas NC off += ret;
3577541070ceSShreyas NC }
3578541070ceSShreyas NC
3579541070ceSShreyas NC return 0;
3580541070ceSShreyas NC }
3581541070ceSShreyas NC
skl_manifest_load(struct snd_soc_component * cmpnt,int index,struct snd_soc_tplg_manifest * manifest)3582c60b613aSLiam Girdwood static int skl_manifest_load(struct snd_soc_component *cmpnt, int index,
358315ecaba9SKranthi G struct snd_soc_tplg_manifest *manifest)
358415ecaba9SKranthi G {
358576f56faeSRakesh Ughreja struct hdac_bus *bus = snd_soc_component_get_drvdata(cmpnt);
3586bcc2a2dcSCezary Rojewski struct skl_dev *skl = bus_to_skl(bus);
358715ecaba9SKranthi G
3588c15ad605SVinod Koul /* proceed only if we have private data defined */
3589c15ad605SVinod Koul if (manifest->priv.size == 0)
3590c15ad605SVinod Koul return 0;
3591c15ad605SVinod Koul
3592eee0e16fSJeeja KP skl_tplg_get_manifest_data(manifest, bus->dev, skl);
3593541070ceSShreyas NC
3594bcc2a2dcSCezary Rojewski if (skl->lib_count > SKL_MAX_LIB) {
359515ecaba9SKranthi G dev_err(bus->dev, "Exceeding max Library count. Got:%d\n",
3596bcc2a2dcSCezary Rojewski skl->lib_count);
3597eee0e16fSJeeja KP return -EINVAL;
359815ecaba9SKranthi G }
359915ecaba9SKranthi G
3600eee0e16fSJeeja KP return 0;
360115ecaba9SKranthi G }
360215ecaba9SKranthi G
skl_tplg_complete(struct snd_soc_component * component)3603415717e1SRanjani Sridharan static int skl_tplg_complete(struct snd_soc_component *component)
36042d744ecfSMateusz Gorski {
36052d744ecfSMateusz Gorski struct snd_soc_dobj *dobj;
3606bef2897dSNick Desaulniers struct snd_soc_acpi_mach *mach;
3607bef2897dSNick Desaulniers struct snd_ctl_elem_value *val;
36082d744ecfSMateusz Gorski int i;
36092d744ecfSMateusz Gorski
3610bef2897dSNick Desaulniers val = kmalloc(sizeof(*val), GFP_KERNEL);
3611bef2897dSNick Desaulniers if (!val)
3612415717e1SRanjani Sridharan return -ENOMEM;
3613bef2897dSNick Desaulniers
3614bef2897dSNick Desaulniers mach = dev_get_platdata(component->card->dev);
36152d744ecfSMateusz Gorski list_for_each_entry(dobj, &component->dobj_list, list) {
36162d744ecfSMateusz Gorski struct snd_kcontrol *kcontrol = dobj->control.kcontrol;
3617c1c3ba1fSRicardo Ribalda struct soc_enum *se;
3618c1c3ba1fSRicardo Ribalda char **texts;
36192d744ecfSMateusz Gorski char chan_text[4];
36202d744ecfSMateusz Gorski
3621c1c3ba1fSRicardo Ribalda if (dobj->type != SND_SOC_DOBJ_ENUM || !kcontrol ||
3622c1c3ba1fSRicardo Ribalda kcontrol->put != skl_tplg_multi_config_set_dmic)
36232d744ecfSMateusz Gorski continue;
3624c1c3ba1fSRicardo Ribalda
3625c1c3ba1fSRicardo Ribalda se = (struct soc_enum *)kcontrol->private_value;
3626c1c3ba1fSRicardo Ribalda texts = dobj->control.dtexts;
36272d744ecfSMateusz Gorski sprintf(chan_text, "c%d", mach->mach_params.dmic_num);
36282d744ecfSMateusz Gorski
36292d744ecfSMateusz Gorski for (i = 0; i < se->items; i++) {
36302d744ecfSMateusz Gorski if (strstr(texts[i], chan_text)) {
3631bef2897dSNick Desaulniers memset(val, 0, sizeof(*val));
3632bef2897dSNick Desaulniers val->value.enumerated.item[0] = i;
3633bef2897dSNick Desaulniers kcontrol->put(kcontrol, val);
36342d744ecfSMateusz Gorski }
36352d744ecfSMateusz Gorski }
36362d744ecfSMateusz Gorski }
3637415717e1SRanjani Sridharan
3638bef2897dSNick Desaulniers kfree(val);
3639415717e1SRanjani Sridharan return 0;
36402d744ecfSMateusz Gorski }
36412d744ecfSMateusz Gorski
36423af36706SVinod Koul static struct snd_soc_tplg_ops skl_tplg_ops = {
36433af36706SVinod Koul .widget_load = skl_tplg_widget_load,
3644140adfbaSJeeja KP .control_load = skl_tplg_control_load,
3645140adfbaSJeeja KP .bytes_ext_ops = skl_tlv_ops,
3646140adfbaSJeeja KP .bytes_ext_ops_count = ARRAY_SIZE(skl_tlv_ops),
36477a1b749bSDharageswari R .io_ops = skl_tplg_kcontrol_ops,
36487a1b749bSDharageswari R .io_ops_count = ARRAY_SIZE(skl_tplg_kcontrol_ops),
364915ecaba9SKranthi G .manifest = skl_manifest_load,
3650606e21fdSGuneshwor Singh .dai_load = skl_dai_load,
36512d744ecfSMateusz Gorski .complete = skl_tplg_complete,
36523af36706SVinod Koul };
36533af36706SVinod Koul
3654287af4f9SJeeja KP /*
3655287af4f9SJeeja KP * A pipe can have multiple modules, each of them will be a DAPM widget as
3656287af4f9SJeeja KP * well. While managing a pipeline we need to get the list of all the
3657287af4f9SJeeja KP * widgets in a pipelines, so this helper - skl_tplg_create_pipe_widget_list()
3658287af4f9SJeeja KP * helps to get the SKL type widgets in that pipeline
3659287af4f9SJeeja KP */
skl_tplg_create_pipe_widget_list(struct snd_soc_component * component)366056b03b4cSKuninori Morimoto static int skl_tplg_create_pipe_widget_list(struct snd_soc_component *component)
3661287af4f9SJeeja KP {
3662287af4f9SJeeja KP struct snd_soc_dapm_widget *w;
3663287af4f9SJeeja KP struct skl_module_cfg *mcfg = NULL;
3664287af4f9SJeeja KP struct skl_pipe_module *p_module = NULL;
3665287af4f9SJeeja KP struct skl_pipe *pipe;
3666287af4f9SJeeja KP
366756b03b4cSKuninori Morimoto list_for_each_entry(w, &component->card->widgets, list) {
3668a1f362d8SMark Brown if (is_skl_dsp_widget_type(w, component->dev) && w->priv) {
3669287af4f9SJeeja KP mcfg = w->priv;
3670287af4f9SJeeja KP pipe = mcfg->pipe;
3671287af4f9SJeeja KP
367256b03b4cSKuninori Morimoto p_module = devm_kzalloc(component->dev,
3673287af4f9SJeeja KP sizeof(*p_module), GFP_KERNEL);
3674287af4f9SJeeja KP if (!p_module)
3675287af4f9SJeeja KP return -ENOMEM;
3676287af4f9SJeeja KP
3677287af4f9SJeeja KP p_module->w = w;
3678287af4f9SJeeja KP list_add_tail(&p_module->node, &pipe->w_list);
3679287af4f9SJeeja KP }
3680287af4f9SJeeja KP }
3681287af4f9SJeeja KP
3682287af4f9SJeeja KP return 0;
3683287af4f9SJeeja KP }
3684287af4f9SJeeja KP
skl_tplg_set_pipe_type(struct skl_dev * skl,struct skl_pipe * pipe)3685bcc2a2dcSCezary Rojewski static void skl_tplg_set_pipe_type(struct skl_dev *skl, struct skl_pipe *pipe)
3686f0aa94faSJeeja KP {
3687f0aa94faSJeeja KP struct skl_pipe_module *w_module;
3688f0aa94faSJeeja KP struct snd_soc_dapm_widget *w;
3689f0aa94faSJeeja KP struct skl_module_cfg *mconfig;
3690f0aa94faSJeeja KP bool host_found = false, link_found = false;
3691f0aa94faSJeeja KP
3692f0aa94faSJeeja KP list_for_each_entry(w_module, &pipe->w_list, node) {
3693f0aa94faSJeeja KP w = w_module->w;
3694f0aa94faSJeeja KP mconfig = w->priv;
3695f0aa94faSJeeja KP
3696f0aa94faSJeeja KP if (mconfig->dev_type == SKL_DEVICE_HDAHOST)
3697f0aa94faSJeeja KP host_found = true;
3698f0aa94faSJeeja KP else if (mconfig->dev_type != SKL_DEVICE_NONE)
3699f0aa94faSJeeja KP link_found = true;
3700f0aa94faSJeeja KP }
3701f0aa94faSJeeja KP
3702f0aa94faSJeeja KP if (host_found && link_found)
3703f0aa94faSJeeja KP pipe->passthru = true;
3704f0aa94faSJeeja KP else
3705f0aa94faSJeeja KP pipe->passthru = false;
3706f0aa94faSJeeja KP }
3707f0aa94faSJeeja KP
37083af36706SVinod Koul /*
37093af36706SVinod Koul * SKL topology init routine
37103af36706SVinod Koul */
skl_tplg_init(struct snd_soc_component * component,struct hdac_bus * bus)371176f56faeSRakesh Ughreja int skl_tplg_init(struct snd_soc_component *component, struct hdac_bus *bus)
37123af36706SVinod Koul {
37133af36706SVinod Koul int ret;
37143af36706SVinod Koul const struct firmware *fw;
3715bcc2a2dcSCezary Rojewski struct skl_dev *skl = bus_to_skl(bus);
3716f0aa94faSJeeja KP struct skl_pipeline *ppl;
37173af36706SVinod Koul
37184b235c43SVinod Koul ret = request_firmware(&fw, skl->tplg_name, bus->dev);
37193af36706SVinod Koul if (ret < 0) {
37201b290ef0SMateusz Gorski char alt_tplg_name[64];
37211b290ef0SMateusz Gorski
37221b290ef0SMateusz Gorski snprintf(alt_tplg_name, sizeof(alt_tplg_name), "%s-tplg.bin",
37231b290ef0SMateusz Gorski skl->mach->drv_name);
37241b290ef0SMateusz Gorski dev_info(bus->dev, "tplg fw %s load failed with %d, trying alternative tplg name %s",
37251b290ef0SMateusz Gorski skl->tplg_name, ret, alt_tplg_name);
37261b290ef0SMateusz Gorski
37271b290ef0SMateusz Gorski ret = request_firmware(&fw, alt_tplg_name, bus->dev);
37281b290ef0SMateusz Gorski if (!ret)
37291b290ef0SMateusz Gorski goto component_load;
37301b290ef0SMateusz Gorski
37311b290ef0SMateusz Gorski dev_info(bus->dev, "tplg %s failed with %d, falling back to dfw_sst.bin",
37321b290ef0SMateusz Gorski alt_tplg_name, ret);
37331b290ef0SMateusz Gorski
37344b235c43SVinod Koul ret = request_firmware(&fw, "dfw_sst.bin", bus->dev);
37354b235c43SVinod Koul if (ret < 0) {
37364b235c43SVinod Koul dev_err(bus->dev, "Fallback tplg fw %s load failed with %d\n",
37373af36706SVinod Koul "dfw_sst.bin", ret);
37383af36706SVinod Koul return ret;
37393af36706SVinod Koul }
37404b235c43SVinod Koul }
37413af36706SVinod Koul
37421b290ef0SMateusz Gorski component_load:
3743a5b8f71cSAmadeusz Sławiński ret = snd_soc_tplg_component_load(component, &skl_tplg_ops, fw);
37443af36706SVinod Koul if (ret < 0) {
37453af36706SVinod Koul dev_err(bus->dev, "tplg component load failed%d\n", ret);
37466f437917SAmadeusz Sławiński goto err;
37473af36706SVinod Koul }
37483af36706SVinod Koul
374956b03b4cSKuninori Morimoto ret = skl_tplg_create_pipe_widget_list(component);
37506f437917SAmadeusz Sławiński if (ret < 0) {
37516f437917SAmadeusz Sławiński dev_err(bus->dev, "tplg create pipe widget list failed%d\n",
37526f437917SAmadeusz Sławiński ret);
37536f437917SAmadeusz Sławiński goto err;
37546f437917SAmadeusz Sławiński }
3755d8018361SVinod Koul
3756f0aa94faSJeeja KP list_for_each_entry(ppl, &skl->ppl_list, node)
3757f0aa94faSJeeja KP skl_tplg_set_pipe_type(skl, ppl->pipe);
37583af36706SVinod Koul
37596f437917SAmadeusz Sławiński err:
37606f437917SAmadeusz Sławiński release_firmware(fw);
37616f437917SAmadeusz Sławiński return ret;
37623af36706SVinod Koul }
3763e79986ceSAmadeusz Sławiński
skl_tplg_exit(struct snd_soc_component * component,struct hdac_bus * bus)3764e79986ceSAmadeusz Sławiński void skl_tplg_exit(struct snd_soc_component *component, struct hdac_bus *bus)
3765e79986ceSAmadeusz Sławiński {
3766bcc2a2dcSCezary Rojewski struct skl_dev *skl = bus_to_skl(bus);
3767e79986ceSAmadeusz Sławiński struct skl_pipeline *ppl, *tmp;
3768e79986ceSAmadeusz Sławiński
3769e79986ceSAmadeusz Sławiński list_for_each_entry_safe(ppl, tmp, &skl->ppl_list, node)
3770e79986ceSAmadeusz Sławiński list_del(&ppl->node);
3771e79986ceSAmadeusz Sławiński
3772e79986ceSAmadeusz Sławiński /* clean up topology */
3773a5b8f71cSAmadeusz Sławiński snd_soc_tplg_component_remove(component);
3774e79986ceSAmadeusz Sławiński }
3775