1 // SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause)
3 // This file is provided under a dual BSD/GPLv2 license. When using or
4 // redistributing this file, you may do so under either license.
6 // Copyright(c) 2018 Intel Corporation. All rights reserved.
8 // Author: Liam Girdwood <liam.r.girdwood@linux.intel.com>
11 #include <linux/bits.h>
12 #include <linux/device.h>
13 #include <linux/errno.h>
14 #include <linux/firmware.h>
15 #include <linux/workqueue.h>
16 #include <sound/tlv.h>
17 #include <sound/pcm_params.h>
18 #include <uapi/sound/sof/tokens.h>
20 #include "sof-audio.h"
23 #define COMP_ID_UNASSIGNED 0xffffffff
25 * Constants used in the computation of linear volume gain
26 * from dB gain 20th root of 10 in Q1.16 fixed-point notation
28 #define VOL_TWENTIETH_ROOT_OF_TEN 73533
29 /* 40th root of 10 in Q1.16 fixed-point notation*/
30 #define VOL_FORTIETH_ROOT_OF_TEN 69419
32 * Volume fractional word length define to 16 sets
33 * the volume linear gain value to use Qx.16 format
36 /* 0.5 dB step value in topology TLV */
37 #define VOL_HALF_DB_STEP 50
38 /* Full volume for default values */
39 #define VOL_ZERO_DB BIT(VOLUME_FWL)
47 /* size of tplg abi in byte */
48 #define SOF_TPLG_ABI_SIZE 3
50 struct sof_widget_data
{
53 struct sof_abi_hdr
*pdata
;
54 struct snd_sof_control
*control
;
57 /* send pcm params ipc */
58 static int ipc_pcm_params(struct snd_sof_widget
*swidget
, int dir
)
60 struct sof_ipc_pcm_params_reply ipc_params_reply
;
61 struct snd_soc_component
*scomp
= swidget
->scomp
;
62 struct snd_sof_dev
*sdev
= snd_soc_component_get_drvdata(scomp
);
63 struct sof_ipc_pcm_params pcm
;
64 struct snd_pcm_hw_params
*params
;
65 struct snd_sof_pcm
*spcm
;
68 memset(&pcm
, 0, sizeof(pcm
));
70 /* get runtime PCM params using widget's stream name */
71 spcm
= snd_sof_find_spcm_name(scomp
, swidget
->widget
->sname
);
73 dev_err(scomp
->dev
, "error: cannot find PCM for %s\n",
74 swidget
->widget
->name
);
78 params
= &spcm
->params
[dir
];
80 /* set IPC PCM params */
81 pcm
.hdr
.size
= sizeof(pcm
);
82 pcm
.hdr
.cmd
= SOF_IPC_GLB_STREAM_MSG
| SOF_IPC_STREAM_PCM_PARAMS
;
83 pcm
.comp_id
= swidget
->comp_id
;
84 pcm
.params
.hdr
.size
= sizeof(pcm
.params
);
85 pcm
.params
.direction
= dir
;
86 pcm
.params
.sample_valid_bytes
= params_width(params
) >> 3;
87 pcm
.params
.buffer_fmt
= SOF_IPC_BUFFER_INTERLEAVED
;
88 pcm
.params
.rate
= params_rate(params
);
89 pcm
.params
.channels
= params_channels(params
);
90 pcm
.params
.host_period_bytes
= params_period_bytes(params
);
93 switch (params_format(params
)) {
94 case SNDRV_PCM_FORMAT_S16
:
95 pcm
.params
.frame_fmt
= SOF_IPC_FRAME_S16_LE
;
97 case SNDRV_PCM_FORMAT_S24
:
98 pcm
.params
.frame_fmt
= SOF_IPC_FRAME_S24_4LE
;
100 case SNDRV_PCM_FORMAT_S32
:
101 pcm
.params
.frame_fmt
= SOF_IPC_FRAME_S32_LE
;
107 /* send IPC to the DSP */
108 ret
= sof_ipc_tx_message(sdev
->ipc
, pcm
.hdr
.cmd
, &pcm
, sizeof(pcm
),
109 &ipc_params_reply
, sizeof(ipc_params_reply
));
111 dev_err(scomp
->dev
, "error: pcm params failed for %s\n",
112 swidget
->widget
->name
);
117 /* send stream trigger ipc */
118 static int ipc_trigger(struct snd_sof_widget
*swidget
, int cmd
)
120 struct snd_soc_component
*scomp
= swidget
->scomp
;
121 struct snd_sof_dev
*sdev
= snd_soc_component_get_drvdata(scomp
);
122 struct sof_ipc_stream stream
;
123 struct sof_ipc_reply reply
;
126 /* set IPC stream params */
127 stream
.hdr
.size
= sizeof(stream
);
128 stream
.hdr
.cmd
= SOF_IPC_GLB_STREAM_MSG
| cmd
;
129 stream
.comp_id
= swidget
->comp_id
;
131 /* send IPC to the DSP */
132 ret
= sof_ipc_tx_message(sdev
->ipc
, stream
.hdr
.cmd
, &stream
,
133 sizeof(stream
), &reply
, sizeof(reply
));
135 dev_err(scomp
->dev
, "error: failed to trigger %s\n",
136 swidget
->widget
->name
);
141 static int sof_keyword_dapm_event(struct snd_soc_dapm_widget
*w
,
142 struct snd_kcontrol
*k
, int event
)
144 struct snd_sof_widget
*swidget
= w
->dobj
.private;
145 struct snd_soc_component
*scomp
;
146 int stream
= SNDRV_PCM_STREAM_CAPTURE
;
147 struct snd_sof_pcm
*spcm
;
153 scomp
= swidget
->scomp
;
155 dev_dbg(scomp
->dev
, "received event %d for widget %s\n",
158 /* get runtime PCM params using widget's stream name */
159 spcm
= snd_sof_find_spcm_name(scomp
, swidget
->widget
->sname
);
161 dev_err(scomp
->dev
, "error: cannot find PCM for %s\n",
162 swidget
->widget
->name
);
168 case SND_SOC_DAPM_PRE_PMU
:
169 if (spcm
->stream
[stream
].suspend_ignored
) {
170 dev_dbg(scomp
->dev
, "PRE_PMU event ignored, KWD pipeline is already RUNNING\n");
175 ret
= ipc_pcm_params(swidget
, stream
);
178 "error: failed to set pcm params for widget %s\n",
179 swidget
->widget
->name
);
184 ret
= ipc_trigger(swidget
, SOF_IPC_STREAM_TRIG_START
);
187 "error: failed to trigger widget %s\n",
188 swidget
->widget
->name
);
190 case SND_SOC_DAPM_POST_PMD
:
191 if (spcm
->stream
[stream
].suspend_ignored
) {
192 dev_dbg(scomp
->dev
, "POST_PMD even ignored, KWD pipeline will remain RUNNING\n");
197 ret
= ipc_trigger(swidget
, SOF_IPC_STREAM_TRIG_STOP
);
200 "error: failed to trigger widget %s\n",
201 swidget
->widget
->name
);
204 ret
= ipc_trigger(swidget
, SOF_IPC_STREAM_PCM_FREE
);
207 "error: failed to trigger widget %s\n",
208 swidget
->widget
->name
);
217 /* event handlers for keyword detect component */
218 static const struct snd_soc_tplg_widget_events sof_kwd_events
[] = {
219 {SOF_KEYWORD_DETECT_DAPM_EVENT
, sof_keyword_dapm_event
},
222 static inline int get_tlv_data(const int *p
, int tlv
[TLV_ITEMS
])
224 /* we only support dB scale TLV type at the moment */
225 if ((int)p
[SNDRV_CTL_TLVO_TYPE
] != SNDRV_CTL_TLVT_DB_SCALE
)
228 /* min value in topology tlv data is multiplied by 100 */
229 tlv
[TLV_MIN
] = (int)p
[SNDRV_CTL_TLVO_DB_SCALE_MIN
] / 100;
232 tlv
[TLV_STEP
] = (int)(p
[SNDRV_CTL_TLVO_DB_SCALE_MUTE_AND_STEP
] &
236 if ((p
[SNDRV_CTL_TLVO_DB_SCALE_MUTE_AND_STEP
] &
237 TLV_DB_SCALE_MUTE
) == 0)
246 * Function to truncate an unsigned 64-bit number
247 * by x bits and return 32-bit unsigned number. This
248 * function also takes care of rounding while truncating
250 static inline u32
vol_shift_64(u64 i
, u32 x
)
252 /* do not truncate more than 32 bits */
259 return (u32
)(((i
>> (x
- 1)) + 1) >> 1);
263 * Function to compute a ^ exp where,
264 * a is a fractional number represented by a fixed-point
265 * integer with a fractional world length of "fwl"
267 * fwl is the fractional word length
268 * Return value is a fractional number represented by a
269 * fixed-point integer with a fractional word length of "fwl"
271 static u32
vol_pow32(u32 a
, int exp
, u32 fwl
)
274 u32 power
= 1 << fwl
;
277 /* if exponent is 0, return 1 */
281 /* determine the number of iterations based on the exponent */
287 /* mutiply a "iter" times to compute power */
288 for (i
= 0; i
< iter
; i
++) {
290 * Product of 2 Qx.fwl fixed-point numbers yields a Q2*x.2*fwl
291 * Truncate product back to fwl fractional bits with rounding
293 power
= vol_shift_64((u64
)power
* a
, fwl
);
297 /* if exp is positive, return the result */
301 /* if exp is negative, return the multiplicative inverse */
302 numerator
= (u64
)1 << (fwl
<< 1);
303 do_div(numerator
, power
);
305 return (u32
)numerator
;
309 * Function to calculate volume gain from TLV data.
310 * This function can only handle gain steps that are multiples of 0.5 dB
312 static u32
vol_compute_gain(u32 value
, int *tlv
)
319 if (value
== 0 && tlv
[TLV_MUTE
])
323 * compute dB gain from tlv. tlv_step
324 * in topology is multiplied by 100
326 dB_gain
= tlv
[TLV_MIN
] + (value
* tlv
[TLV_STEP
]) / 100;
329 * compute linear gain represented by fixed-point
330 * int with VOLUME_FWL fractional bits
332 linear_gain
= vol_pow32(VOL_TWENTIETH_ROOT_OF_TEN
, dB_gain
, VOLUME_FWL
);
334 /* extract the fractional part of volume step */
335 f_step
= tlv
[TLV_STEP
] - (tlv
[TLV_STEP
] / 100);
337 /* if volume step is an odd multiple of 0.5 dB */
338 if (f_step
== VOL_HALF_DB_STEP
&& (value
& 1))
339 linear_gain
= vol_shift_64((u64
)linear_gain
*
340 VOL_FORTIETH_ROOT_OF_TEN
,
347 * Set up volume table for kcontrols from tlv data
348 * "size" specifies the number of entries in the table
350 static int set_up_volume_table(struct snd_sof_control
*scontrol
,
351 int tlv
[TLV_ITEMS
], int size
)
355 /* init the volume table */
356 scontrol
->volume_table
= kcalloc(size
, sizeof(u32
), GFP_KERNEL
);
357 if (!scontrol
->volume_table
)
360 /* populate the volume table */
361 for (j
= 0; j
< size
; j
++)
362 scontrol
->volume_table
[j
] = vol_compute_gain(j
, tlv
);
367 struct sof_dai_types
{
369 enum sof_ipc_dai_type type
;
372 static const struct sof_dai_types sof_dais
[] = {
373 {"SSP", SOF_DAI_INTEL_SSP
},
374 {"HDA", SOF_DAI_INTEL_HDA
},
375 {"DMIC", SOF_DAI_INTEL_DMIC
},
376 {"ALH", SOF_DAI_INTEL_ALH
},
377 {"SAI", SOF_DAI_IMX_SAI
},
378 {"ESAI", SOF_DAI_IMX_ESAI
},
381 static enum sof_ipc_dai_type
find_dai(const char *name
)
385 for (i
= 0; i
< ARRAY_SIZE(sof_dais
); i
++) {
386 if (strcmp(name
, sof_dais
[i
].name
) == 0)
387 return sof_dais
[i
].type
;
390 return SOF_DAI_INTEL_NONE
;
394 * Supported Frame format types and lookup, add new ones to end of list.
397 struct sof_frame_types
{
399 enum sof_ipc_frame frame
;
402 static const struct sof_frame_types sof_frames
[] = {
403 {"s16le", SOF_IPC_FRAME_S16_LE
},
404 {"s24le", SOF_IPC_FRAME_S24_4LE
},
405 {"s32le", SOF_IPC_FRAME_S32_LE
},
406 {"float", SOF_IPC_FRAME_FLOAT
},
409 static enum sof_ipc_frame
find_format(const char *name
)
413 for (i
= 0; i
< ARRAY_SIZE(sof_frames
); i
++) {
414 if (strcmp(name
, sof_frames
[i
].name
) == 0)
415 return sof_frames
[i
].frame
;
418 /* use s32le if nothing is specified */
419 return SOF_IPC_FRAME_S32_LE
;
422 struct sof_process_types
{
424 enum sof_ipc_process_type type
;
425 enum sof_comp_type comp_type
;
428 static const struct sof_process_types sof_process
[] = {
429 {"EQFIR", SOF_PROCESS_EQFIR
, SOF_COMP_EQ_FIR
},
430 {"EQIIR", SOF_PROCESS_EQIIR
, SOF_COMP_EQ_IIR
},
431 {"KEYWORD_DETECT", SOF_PROCESS_KEYWORD_DETECT
, SOF_COMP_KEYWORD_DETECT
},
432 {"KPB", SOF_PROCESS_KPB
, SOF_COMP_KPB
},
433 {"CHAN_SELECTOR", SOF_PROCESS_CHAN_SELECTOR
, SOF_COMP_SELECTOR
},
434 {"MUX", SOF_PROCESS_MUX
, SOF_COMP_MUX
},
435 {"DEMUX", SOF_PROCESS_DEMUX
, SOF_COMP_DEMUX
},
436 {"DCBLOCK", SOF_PROCESS_DCBLOCK
, SOF_COMP_DCBLOCK
},
437 {"SMART_AMP", SOF_PROCESS_SMART_AMP
, SOF_COMP_SMART_AMP
},
440 static enum sof_ipc_process_type
find_process(const char *name
)
444 for (i
= 0; i
< ARRAY_SIZE(sof_process
); i
++) {
445 if (strcmp(name
, sof_process
[i
].name
) == 0)
446 return sof_process
[i
].type
;
449 return SOF_PROCESS_NONE
;
452 static enum sof_comp_type
find_process_comp_type(enum sof_ipc_process_type type
)
456 for (i
= 0; i
< ARRAY_SIZE(sof_process
); i
++) {
457 if (sof_process
[i
].type
== type
)
458 return sof_process
[i
].comp_type
;
461 return SOF_COMP_NONE
;
465 * Topology Token Parsing.
466 * New tokens should be added to headers and parsing tables below.
469 struct sof_topology_token
{
472 int (*get_token
)(void *elem
, void *object
, u32 offset
, u32 size
);
477 static int get_token_u32(void *elem
, void *object
, u32 offset
, u32 size
)
479 struct snd_soc_tplg_vendor_value_elem
*velem
= elem
;
480 u32
*val
= (u32
*)((u8
*)object
+ offset
);
482 *val
= le32_to_cpu(velem
->value
);
486 static int get_token_u16(void *elem
, void *object
, u32 offset
, u32 size
)
488 struct snd_soc_tplg_vendor_value_elem
*velem
= elem
;
489 u16
*val
= (u16
*)((u8
*)object
+ offset
);
491 *val
= (u16
)le32_to_cpu(velem
->value
);
495 static int get_token_uuid(void *elem
, void *object
, u32 offset
, u32 size
)
497 struct snd_soc_tplg_vendor_uuid_elem
*velem
= elem
;
498 u8
*dst
= (u8
*)object
+ offset
;
500 memcpy(dst
, velem
->uuid
, UUID_SIZE
);
505 static int get_token_comp_format(void *elem
, void *object
, u32 offset
, u32 size
)
507 struct snd_soc_tplg_vendor_string_elem
*velem
= elem
;
508 u32
*val
= (u32
*)((u8
*)object
+ offset
);
510 *val
= find_format(velem
->string
);
514 static int get_token_dai_type(void *elem
, void *object
, u32 offset
, u32 size
)
516 struct snd_soc_tplg_vendor_string_elem
*velem
= elem
;
517 u32
*val
= (u32
*)((u8
*)object
+ offset
);
519 *val
= find_dai(velem
->string
);
523 static int get_token_process_type(void *elem
, void *object
, u32 offset
,
526 struct snd_soc_tplg_vendor_string_elem
*velem
= elem
;
527 u32
*val
= (u32
*)((u8
*)object
+ offset
);
529 *val
= find_process(velem
->string
);
534 static const struct sof_topology_token buffer_tokens
[] = {
535 {SOF_TKN_BUF_SIZE
, SND_SOC_TPLG_TUPLE_TYPE_WORD
, get_token_u32
,
536 offsetof(struct sof_ipc_buffer
, size
), 0},
537 {SOF_TKN_BUF_CAPS
, SND_SOC_TPLG_TUPLE_TYPE_WORD
, get_token_u32
,
538 offsetof(struct sof_ipc_buffer
, caps
), 0},
542 static const struct sof_topology_token dai_tokens
[] = {
543 {SOF_TKN_DAI_TYPE
, SND_SOC_TPLG_TUPLE_TYPE_STRING
, get_token_dai_type
,
544 offsetof(struct sof_ipc_comp_dai
, type
), 0},
545 {SOF_TKN_DAI_INDEX
, SND_SOC_TPLG_TUPLE_TYPE_WORD
, get_token_u32
,
546 offsetof(struct sof_ipc_comp_dai
, dai_index
), 0},
547 {SOF_TKN_DAI_DIRECTION
, SND_SOC_TPLG_TUPLE_TYPE_WORD
, get_token_u32
,
548 offsetof(struct sof_ipc_comp_dai
, direction
), 0},
552 static const struct sof_topology_token dai_link_tokens
[] = {
553 {SOF_TKN_DAI_TYPE
, SND_SOC_TPLG_TUPLE_TYPE_STRING
, get_token_dai_type
,
554 offsetof(struct sof_ipc_dai_config
, type
), 0},
555 {SOF_TKN_DAI_INDEX
, SND_SOC_TPLG_TUPLE_TYPE_WORD
, get_token_u32
,
556 offsetof(struct sof_ipc_dai_config
, dai_index
), 0},
560 static const struct sof_topology_token sched_tokens
[] = {
561 {SOF_TKN_SCHED_PERIOD
, SND_SOC_TPLG_TUPLE_TYPE_WORD
, get_token_u32
,
562 offsetof(struct sof_ipc_pipe_new
, period
), 0},
563 {SOF_TKN_SCHED_PRIORITY
, SND_SOC_TPLG_TUPLE_TYPE_WORD
, get_token_u32
,
564 offsetof(struct sof_ipc_pipe_new
, priority
), 0},
565 {SOF_TKN_SCHED_MIPS
, SND_SOC_TPLG_TUPLE_TYPE_WORD
, get_token_u32
,
566 offsetof(struct sof_ipc_pipe_new
, period_mips
), 0},
567 {SOF_TKN_SCHED_CORE
, SND_SOC_TPLG_TUPLE_TYPE_WORD
, get_token_u32
,
568 offsetof(struct sof_ipc_pipe_new
, core
), 0},
569 {SOF_TKN_SCHED_FRAMES
, SND_SOC_TPLG_TUPLE_TYPE_WORD
, get_token_u32
,
570 offsetof(struct sof_ipc_pipe_new
, frames_per_sched
), 0},
571 {SOF_TKN_SCHED_TIME_DOMAIN
, SND_SOC_TPLG_TUPLE_TYPE_WORD
, get_token_u32
,
572 offsetof(struct sof_ipc_pipe_new
, time_domain
), 0},
576 static const struct sof_topology_token volume_tokens
[] = {
577 {SOF_TKN_VOLUME_RAMP_STEP_TYPE
, SND_SOC_TPLG_TUPLE_TYPE_WORD
,
578 get_token_u32
, offsetof(struct sof_ipc_comp_volume
, ramp
), 0},
579 {SOF_TKN_VOLUME_RAMP_STEP_MS
,
580 SND_SOC_TPLG_TUPLE_TYPE_WORD
, get_token_u32
,
581 offsetof(struct sof_ipc_comp_volume
, initial_ramp
), 0},
585 static const struct sof_topology_token src_tokens
[] = {
586 {SOF_TKN_SRC_RATE_IN
, SND_SOC_TPLG_TUPLE_TYPE_WORD
, get_token_u32
,
587 offsetof(struct sof_ipc_comp_src
, source_rate
), 0},
588 {SOF_TKN_SRC_RATE_OUT
, SND_SOC_TPLG_TUPLE_TYPE_WORD
, get_token_u32
,
589 offsetof(struct sof_ipc_comp_src
, sink_rate
), 0},
593 static const struct sof_topology_token asrc_tokens
[] = {
594 {SOF_TKN_ASRC_RATE_IN
, SND_SOC_TPLG_TUPLE_TYPE_WORD
, get_token_u32
,
595 offsetof(struct sof_ipc_comp_asrc
, source_rate
), 0},
596 {SOF_TKN_ASRC_RATE_OUT
, SND_SOC_TPLG_TUPLE_TYPE_WORD
, get_token_u32
,
597 offsetof(struct sof_ipc_comp_asrc
, sink_rate
), 0},
598 {SOF_TKN_ASRC_ASYNCHRONOUS_MODE
, SND_SOC_TPLG_TUPLE_TYPE_WORD
,
600 offsetof(struct sof_ipc_comp_asrc
, asynchronous_mode
), 0},
601 {SOF_TKN_ASRC_OPERATION_MODE
, SND_SOC_TPLG_TUPLE_TYPE_WORD
,
603 offsetof(struct sof_ipc_comp_asrc
, operation_mode
), 0},
607 static const struct sof_topology_token tone_tokens
[] = {
611 static const struct sof_topology_token process_tokens
[] = {
612 {SOF_TKN_PROCESS_TYPE
, SND_SOC_TPLG_TUPLE_TYPE_STRING
,
613 get_token_process_type
,
614 offsetof(struct sof_ipc_comp_process
, type
), 0},
618 static const struct sof_topology_token pcm_tokens
[] = {
619 {SOF_TKN_PCM_DMAC_CONFIG
, SND_SOC_TPLG_TUPLE_TYPE_WORD
, get_token_u32
,
620 offsetof(struct sof_ipc_comp_host
, dmac_config
), 0},
624 static const struct sof_topology_token stream_tokens
[] = {
625 {SOF_TKN_STREAM_PLAYBACK_COMPATIBLE_D0I3
,
626 SND_SOC_TPLG_TUPLE_TYPE_BOOL
, get_token_u16
,
627 offsetof(struct snd_sof_pcm
, stream
[0].d0i3_compatible
), 0},
628 {SOF_TKN_STREAM_CAPTURE_COMPATIBLE_D0I3
,
629 SND_SOC_TPLG_TUPLE_TYPE_BOOL
, get_token_u16
,
630 offsetof(struct snd_sof_pcm
, stream
[1].d0i3_compatible
), 0},
633 /* Generic components */
634 static const struct sof_topology_token comp_tokens
[] = {
635 {SOF_TKN_COMP_PERIOD_SINK_COUNT
,
636 SND_SOC_TPLG_TUPLE_TYPE_WORD
, get_token_u32
,
637 offsetof(struct sof_ipc_comp_config
, periods_sink
), 0},
638 {SOF_TKN_COMP_PERIOD_SOURCE_COUNT
,
639 SND_SOC_TPLG_TUPLE_TYPE_WORD
, get_token_u32
,
640 offsetof(struct sof_ipc_comp_config
, periods_source
), 0},
641 {SOF_TKN_COMP_FORMAT
,
642 SND_SOC_TPLG_TUPLE_TYPE_STRING
, get_token_comp_format
,
643 offsetof(struct sof_ipc_comp_config
, frame_fmt
), 0},
647 static const struct sof_topology_token ssp_tokens
[] = {
648 {SOF_TKN_INTEL_SSP_CLKS_CONTROL
,
649 SND_SOC_TPLG_TUPLE_TYPE_WORD
, get_token_u32
,
650 offsetof(struct sof_ipc_dai_ssp_params
, clks_control
), 0},
651 {SOF_TKN_INTEL_SSP_MCLK_ID
,
652 SND_SOC_TPLG_TUPLE_TYPE_SHORT
, get_token_u16
,
653 offsetof(struct sof_ipc_dai_ssp_params
, mclk_id
), 0},
654 {SOF_TKN_INTEL_SSP_SAMPLE_BITS
, SND_SOC_TPLG_TUPLE_TYPE_WORD
,
656 offsetof(struct sof_ipc_dai_ssp_params
, sample_valid_bits
), 0},
657 {SOF_TKN_INTEL_SSP_FRAME_PULSE_WIDTH
, SND_SOC_TPLG_TUPLE_TYPE_SHORT
,
659 offsetof(struct sof_ipc_dai_ssp_params
, frame_pulse_width
), 0},
660 {SOF_TKN_INTEL_SSP_QUIRKS
, SND_SOC_TPLG_TUPLE_TYPE_WORD
,
662 offsetof(struct sof_ipc_dai_ssp_params
, quirks
), 0},
663 {SOF_TKN_INTEL_SSP_TDM_PADDING_PER_SLOT
, SND_SOC_TPLG_TUPLE_TYPE_BOOL
,
665 offsetof(struct sof_ipc_dai_ssp_params
,
666 tdm_per_slot_padding_flag
), 0},
667 {SOF_TKN_INTEL_SSP_BCLK_DELAY
, SND_SOC_TPLG_TUPLE_TYPE_WORD
,
669 offsetof(struct sof_ipc_dai_ssp_params
, bclk_delay
), 0},
674 static const struct sof_topology_token alh_tokens
[] = {
675 {SOF_TKN_INTEL_ALH_RATE
,
676 SND_SOC_TPLG_TUPLE_TYPE_WORD
, get_token_u32
,
677 offsetof(struct sof_ipc_dai_alh_params
, rate
), 0},
678 {SOF_TKN_INTEL_ALH_CH
,
679 SND_SOC_TPLG_TUPLE_TYPE_WORD
, get_token_u32
,
680 offsetof(struct sof_ipc_dai_alh_params
, channels
), 0},
684 static const struct sof_topology_token dmic_tokens
[] = {
685 {SOF_TKN_INTEL_DMIC_DRIVER_VERSION
,
686 SND_SOC_TPLG_TUPLE_TYPE_WORD
, get_token_u32
,
687 offsetof(struct sof_ipc_dai_dmic_params
, driver_ipc_version
),
689 {SOF_TKN_INTEL_DMIC_CLK_MIN
,
690 SND_SOC_TPLG_TUPLE_TYPE_WORD
, get_token_u32
,
691 offsetof(struct sof_ipc_dai_dmic_params
, pdmclk_min
), 0},
692 {SOF_TKN_INTEL_DMIC_CLK_MAX
,
693 SND_SOC_TPLG_TUPLE_TYPE_WORD
, get_token_u32
,
694 offsetof(struct sof_ipc_dai_dmic_params
, pdmclk_max
), 0},
695 {SOF_TKN_INTEL_DMIC_SAMPLE_RATE
,
696 SND_SOC_TPLG_TUPLE_TYPE_WORD
, get_token_u32
,
697 offsetof(struct sof_ipc_dai_dmic_params
, fifo_fs
), 0},
698 {SOF_TKN_INTEL_DMIC_DUTY_MIN
,
699 SND_SOC_TPLG_TUPLE_TYPE_SHORT
, get_token_u16
,
700 offsetof(struct sof_ipc_dai_dmic_params
, duty_min
), 0},
701 {SOF_TKN_INTEL_DMIC_DUTY_MAX
,
702 SND_SOC_TPLG_TUPLE_TYPE_SHORT
, get_token_u16
,
703 offsetof(struct sof_ipc_dai_dmic_params
, duty_max
), 0},
704 {SOF_TKN_INTEL_DMIC_NUM_PDM_ACTIVE
,
705 SND_SOC_TPLG_TUPLE_TYPE_WORD
, get_token_u32
,
706 offsetof(struct sof_ipc_dai_dmic_params
,
708 {SOF_TKN_INTEL_DMIC_FIFO_WORD_LENGTH
,
709 SND_SOC_TPLG_TUPLE_TYPE_SHORT
, get_token_u16
,
710 offsetof(struct sof_ipc_dai_dmic_params
, fifo_bits
), 0},
711 {SOF_TKN_INTEL_DMIC_UNMUTE_RAMP_TIME_MS
,
712 SND_SOC_TPLG_TUPLE_TYPE_WORD
, get_token_u32
,
713 offsetof(struct sof_ipc_dai_dmic_params
, unmute_ramp_time
), 0},
718 static const struct sof_topology_token esai_tokens
[] = {
719 {SOF_TKN_IMX_ESAI_MCLK_ID
,
720 SND_SOC_TPLG_TUPLE_TYPE_SHORT
, get_token_u16
,
721 offsetof(struct sof_ipc_dai_esai_params
, mclk_id
), 0},
725 static const struct sof_topology_token sai_tokens
[] = {
726 {SOF_TKN_IMX_SAI_MCLK_ID
,
727 SND_SOC_TPLG_TUPLE_TYPE_SHORT
, get_token_u16
,
728 offsetof(struct sof_ipc_dai_sai_params
, mclk_id
), 0},
732 static const struct sof_topology_token core_tokens
[] = {
733 {SOF_TKN_COMP_CORE_ID
,
734 SND_SOC_TPLG_TUPLE_TYPE_WORD
, get_token_u32
,
735 offsetof(struct sof_ipc_comp
, core
), 0},
738 /* Component extended tokens */
739 static const struct sof_topology_token comp_ext_tokens
[] = {
741 SND_SOC_TPLG_TUPLE_TYPE_UUID
, get_token_uuid
,
742 offsetof(struct sof_ipc_comp_ext
, uuid
), 0},
747 * SOF_TKN_INTEL_DMIC_PDM_CTRL_ID should be the first token
748 * as it increments the index while parsing the array of pdm tokens
749 * and determines the correct offset
751 static const struct sof_topology_token dmic_pdm_tokens
[] = {
752 {SOF_TKN_INTEL_DMIC_PDM_CTRL_ID
,
753 SND_SOC_TPLG_TUPLE_TYPE_SHORT
, get_token_u16
,
754 offsetof(struct sof_ipc_dai_dmic_pdm_ctrl
, id
),
756 {SOF_TKN_INTEL_DMIC_PDM_MIC_A_Enable
,
757 SND_SOC_TPLG_TUPLE_TYPE_SHORT
, get_token_u16
,
758 offsetof(struct sof_ipc_dai_dmic_pdm_ctrl
, enable_mic_a
),
760 {SOF_TKN_INTEL_DMIC_PDM_MIC_B_Enable
,
761 SND_SOC_TPLG_TUPLE_TYPE_SHORT
, get_token_u16
,
762 offsetof(struct sof_ipc_dai_dmic_pdm_ctrl
, enable_mic_b
),
764 {SOF_TKN_INTEL_DMIC_PDM_POLARITY_A
,
765 SND_SOC_TPLG_TUPLE_TYPE_SHORT
, get_token_u16
,
766 offsetof(struct sof_ipc_dai_dmic_pdm_ctrl
, polarity_mic_a
),
768 {SOF_TKN_INTEL_DMIC_PDM_POLARITY_B
,
769 SND_SOC_TPLG_TUPLE_TYPE_SHORT
, get_token_u16
,
770 offsetof(struct sof_ipc_dai_dmic_pdm_ctrl
, polarity_mic_b
),
772 {SOF_TKN_INTEL_DMIC_PDM_CLK_EDGE
,
773 SND_SOC_TPLG_TUPLE_TYPE_SHORT
, get_token_u16
,
774 offsetof(struct sof_ipc_dai_dmic_pdm_ctrl
, clk_edge
),
776 {SOF_TKN_INTEL_DMIC_PDM_SKEW
,
777 SND_SOC_TPLG_TUPLE_TYPE_SHORT
, get_token_u16
,
778 offsetof(struct sof_ipc_dai_dmic_pdm_ctrl
, skew
),
783 static const struct sof_topology_token hda_tokens
[] = {
784 {SOF_TKN_INTEL_HDA_RATE
,
785 SND_SOC_TPLG_TUPLE_TYPE_WORD
, get_token_u32
,
786 offsetof(struct sof_ipc_dai_hda_params
, rate
), 0},
787 {SOF_TKN_INTEL_HDA_CH
,
788 SND_SOC_TPLG_TUPLE_TYPE_WORD
, get_token_u32
,
789 offsetof(struct sof_ipc_dai_hda_params
, channels
), 0},
793 static const struct sof_topology_token led_tokens
[] = {
794 {SOF_TKN_MUTE_LED_USE
, SND_SOC_TPLG_TUPLE_TYPE_WORD
, get_token_u32
,
795 offsetof(struct snd_sof_led_control
, use_led
), 0},
796 {SOF_TKN_MUTE_LED_DIRECTION
, SND_SOC_TPLG_TUPLE_TYPE_WORD
,
797 get_token_u32
, offsetof(struct snd_sof_led_control
, direction
), 0},
800 static int sof_parse_uuid_tokens(struct snd_soc_component
*scomp
,
802 const struct sof_topology_token
*tokens
,
804 struct snd_soc_tplg_vendor_array
*array
,
807 struct snd_soc_tplg_vendor_uuid_elem
*elem
;
811 /* parse element by element */
812 for (i
= 0; i
< le32_to_cpu(array
->num_elems
); i
++) {
813 elem
= &array
->uuid
[i
];
815 /* search for token */
816 for (j
= 0; j
< count
; j
++) {
817 /* match token type */
818 if (tokens
[j
].type
!= SND_SOC_TPLG_TUPLE_TYPE_UUID
)
822 if (tokens
[j
].token
!= le32_to_cpu(elem
->token
))
825 /* matched - now load token */
826 tokens
[j
].get_token(elem
, object
,
827 offset
+ tokens
[j
].offset
,
837 static int sof_parse_string_tokens(struct snd_soc_component
*scomp
,
839 const struct sof_topology_token
*tokens
,
841 struct snd_soc_tplg_vendor_array
*array
,
844 struct snd_soc_tplg_vendor_string_elem
*elem
;
848 /* parse element by element */
849 for (i
= 0; i
< le32_to_cpu(array
->num_elems
); i
++) {
850 elem
= &array
->string
[i
];
852 /* search for token */
853 for (j
= 0; j
< count
; j
++) {
854 /* match token type */
855 if (tokens
[j
].type
!= SND_SOC_TPLG_TUPLE_TYPE_STRING
)
859 if (tokens
[j
].token
!= le32_to_cpu(elem
->token
))
862 /* matched - now load token */
863 tokens
[j
].get_token(elem
, object
,
864 offset
+ tokens
[j
].offset
,
874 static int sof_parse_word_tokens(struct snd_soc_component
*scomp
,
876 const struct sof_topology_token
*tokens
,
878 struct snd_soc_tplg_vendor_array
*array
,
881 struct snd_soc_tplg_vendor_value_elem
*elem
;
885 /* parse element by element */
886 for (i
= 0; i
< le32_to_cpu(array
->num_elems
); i
++) {
887 elem
= &array
->value
[i
];
889 /* search for token */
890 for (j
= 0; j
< count
; j
++) {
891 /* match token type */
892 if (!(tokens
[j
].type
== SND_SOC_TPLG_TUPLE_TYPE_WORD
||
893 tokens
[j
].type
== SND_SOC_TPLG_TUPLE_TYPE_SHORT
||
894 tokens
[j
].type
== SND_SOC_TPLG_TUPLE_TYPE_BYTE
||
895 tokens
[j
].type
== SND_SOC_TPLG_TUPLE_TYPE_BOOL
))
899 if (tokens
[j
].token
!= le32_to_cpu(elem
->token
))
903 tokens
[j
].get_token(elem
, object
,
904 offset
+ tokens
[j
].offset
,
915 * sof_parse_token_sets - Parse multiple sets of tokens
916 * @scomp: pointer to soc component
917 * @object: target ipc struct for parsed values
918 * @tokens: token definition array describing what tokens to parse
919 * @count: number of tokens in definition array
920 * @array: source pointer to consecutive vendor arrays to be parsed
921 * @priv_size: total size of the consecutive source arrays
922 * @sets: number of similar token sets to be parsed, 1 set has count elements
923 * @object_size: offset to next target ipc struct with multiple sets
925 * This function parses multiple sets of tokens in vendor arrays into
926 * consecutive ipc structs.
928 static int sof_parse_token_sets(struct snd_soc_component
*scomp
,
930 const struct sof_topology_token
*tokens
,
932 struct snd_soc_tplg_vendor_array
*array
,
933 int priv_size
, int sets
, size_t object_size
)
940 while (priv_size
> 0 && total
< count
* sets
) {
941 asize
= le32_to_cpu(array
->size
);
944 if (asize
< 0) { /* FIXME: A zero-size array makes no sense */
945 dev_err(scomp
->dev
, "error: invalid array size 0x%x\n",
950 /* make sure there is enough data before parsing */
953 dev_err(scomp
->dev
, "error: invalid array size 0x%x\n",
958 /* call correct parser depending on type */
959 switch (le32_to_cpu(array
->type
)) {
960 case SND_SOC_TPLG_TUPLE_TYPE_UUID
:
961 found
+= sof_parse_uuid_tokens(scomp
, object
, tokens
,
962 count
, array
, offset
);
964 case SND_SOC_TPLG_TUPLE_TYPE_STRING
:
965 found
+= sof_parse_string_tokens(scomp
, object
, tokens
,
966 count
, array
, offset
);
968 case SND_SOC_TPLG_TUPLE_TYPE_BOOL
:
969 case SND_SOC_TPLG_TUPLE_TYPE_BYTE
:
970 case SND_SOC_TPLG_TUPLE_TYPE_WORD
:
971 case SND_SOC_TPLG_TUPLE_TYPE_SHORT
:
972 found
+= sof_parse_word_tokens(scomp
, object
, tokens
,
973 count
, array
, offset
);
976 dev_err(scomp
->dev
, "error: unknown token type %d\n",
982 array
= (struct snd_soc_tplg_vendor_array
*)((u8
*)array
985 /* move to next target struct */
986 if (found
>= count
) {
987 offset
+= object_size
;
996 static int sof_parse_tokens(struct snd_soc_component
*scomp
,
998 const struct sof_topology_token
*tokens
,
1000 struct snd_soc_tplg_vendor_array
*array
,
1004 * sof_parse_tokens is used when topology contains only a single set of
1005 * identical tuples arrays. So additional parameters to
1006 * sof_parse_token_sets are sets = 1 (only 1 set) and
1007 * object_size = 0 (irrelevant).
1009 return sof_parse_token_sets(scomp
, object
, tokens
, count
, array
,
1013 static void sof_dbg_comp_config(struct snd_soc_component
*scomp
,
1014 struct sof_ipc_comp_config
*config
)
1016 dev_dbg(scomp
->dev
, " config: periods snk %d src %d fmt %d\n",
1017 config
->periods_sink
, config
->periods_source
,
1022 * Standard Kcontrols.
1025 static int sof_control_load_volume(struct snd_soc_component
*scomp
,
1026 struct snd_sof_control
*scontrol
,
1027 struct snd_kcontrol_new
*kc
,
1028 struct snd_soc_tplg_ctl_hdr
*hdr
)
1030 struct snd_sof_dev
*sdev
= snd_soc_component_get_drvdata(scomp
);
1031 struct snd_soc_tplg_mixer_control
*mc
=
1032 container_of(hdr
, struct snd_soc_tplg_mixer_control
, hdr
);
1033 struct sof_ipc_ctrl_data
*cdata
;
1038 /* validate topology data */
1039 if (le32_to_cpu(mc
->num_channels
) > SND_SOC_TPLG_MAX_CHAN
) {
1045 * If control has more than 2 channels we need to override the info. This is because even if
1046 * ASoC layer has defined topology's max channel count to SND_SOC_TPLG_MAX_CHAN = 8, the
1047 * pre-defined dapm control types (and related functions) creating the actual control
1048 * restrict the channels only to mono or stereo.
1050 if (le32_to_cpu(mc
->num_channels
) > 2)
1051 kc
->info
= snd_sof_volume_info
;
1053 /* init the volume get/put data */
1054 scontrol
->size
= struct_size(scontrol
->control_data
, chanv
,
1055 le32_to_cpu(mc
->num_channels
));
1056 scontrol
->control_data
= kzalloc(scontrol
->size
, GFP_KERNEL
);
1057 if (!scontrol
->control_data
) {
1062 scontrol
->comp_id
= sdev
->next_comp_id
;
1063 scontrol
->min_volume_step
= le32_to_cpu(mc
->min
);
1064 scontrol
->max_volume_step
= le32_to_cpu(mc
->max
);
1065 scontrol
->num_channels
= le32_to_cpu(mc
->num_channels
);
1067 /* set cmd for mixer control */
1068 if (le32_to_cpu(mc
->max
) == 1) {
1069 scontrol
->cmd
= SOF_CTRL_CMD_SWITCH
;
1073 scontrol
->cmd
= SOF_CTRL_CMD_VOLUME
;
1075 /* extract tlv data */
1076 if (get_tlv_data(kc
->tlv
.p
, tlv
) < 0) {
1077 dev_err(scomp
->dev
, "error: invalid TLV data\n");
1082 /* set up volume table */
1083 ret
= set_up_volume_table(scontrol
, tlv
, le32_to_cpu(mc
->max
) + 1);
1085 dev_err(scomp
->dev
, "error: setting up volume table\n");
1089 /* set default volume values to 0dB in control */
1090 cdata
= scontrol
->control_data
;
1091 for (i
= 0; i
< scontrol
->num_channels
; i
++) {
1092 cdata
->chanv
[i
].channel
= i
;
1093 cdata
->chanv
[i
].value
= VOL_ZERO_DB
;
1097 /* set up possible led control from mixer private data */
1098 ret
= sof_parse_tokens(scomp
, &scontrol
->led_ctl
, led_tokens
,
1099 ARRAY_SIZE(led_tokens
), mc
->priv
.array
,
1100 le32_to_cpu(mc
->priv
.size
));
1102 dev_err(scomp
->dev
, "error: parse led tokens failed %d\n",
1103 le32_to_cpu(mc
->priv
.size
));
1104 goto out_free_table
;
1107 dev_dbg(scomp
->dev
, "tplg: load kcontrol index %d chans %d\n",
1108 scontrol
->comp_id
, scontrol
->num_channels
);
1113 if (le32_to_cpu(mc
->max
) > 1)
1114 kfree(scontrol
->volume_table
);
1116 kfree(scontrol
->control_data
);
1121 static int sof_control_load_enum(struct snd_soc_component
*scomp
,
1122 struct snd_sof_control
*scontrol
,
1123 struct snd_kcontrol_new
*kc
,
1124 struct snd_soc_tplg_ctl_hdr
*hdr
)
1126 struct snd_sof_dev
*sdev
= snd_soc_component_get_drvdata(scomp
);
1127 struct snd_soc_tplg_enum_control
*ec
=
1128 container_of(hdr
, struct snd_soc_tplg_enum_control
, hdr
);
1130 /* validate topology data */
1131 if (le32_to_cpu(ec
->num_channels
) > SND_SOC_TPLG_MAX_CHAN
)
1134 /* init the enum get/put data */
1135 scontrol
->size
= struct_size(scontrol
->control_data
, chanv
,
1136 le32_to_cpu(ec
->num_channels
));
1137 scontrol
->control_data
= kzalloc(scontrol
->size
, GFP_KERNEL
);
1138 if (!scontrol
->control_data
)
1141 scontrol
->comp_id
= sdev
->next_comp_id
;
1142 scontrol
->num_channels
= le32_to_cpu(ec
->num_channels
);
1144 scontrol
->cmd
= SOF_CTRL_CMD_ENUM
;
1146 dev_dbg(scomp
->dev
, "tplg: load kcontrol index %d chans %d comp_id %d\n",
1147 scontrol
->comp_id
, scontrol
->num_channels
, scontrol
->comp_id
);
1152 static int sof_control_load_bytes(struct snd_soc_component
*scomp
,
1153 struct snd_sof_control
*scontrol
,
1154 struct snd_kcontrol_new
*kc
,
1155 struct snd_soc_tplg_ctl_hdr
*hdr
)
1157 struct snd_sof_dev
*sdev
= snd_soc_component_get_drvdata(scomp
);
1158 struct sof_ipc_ctrl_data
*cdata
;
1159 struct snd_soc_tplg_bytes_control
*control
=
1160 container_of(hdr
, struct snd_soc_tplg_bytes_control
, hdr
);
1161 struct soc_bytes_ext
*sbe
= (struct soc_bytes_ext
*)kc
->private_value
;
1162 size_t max_size
= sbe
->max
;
1163 size_t priv_size
= le32_to_cpu(control
->priv
.size
);
1166 if (max_size
< sizeof(struct sof_ipc_ctrl_data
) ||
1167 max_size
< sizeof(struct sof_abi_hdr
)) {
1172 /* init the get/put bytes data */
1173 if (priv_size
> max_size
- sizeof(struct sof_ipc_ctrl_data
)) {
1174 dev_err(scomp
->dev
, "err: bytes data size %zu exceeds max %zu.\n",
1175 priv_size
, max_size
- sizeof(struct sof_ipc_ctrl_data
));
1180 scontrol
->size
= sizeof(struct sof_ipc_ctrl_data
) + priv_size
;
1182 scontrol
->control_data
= kzalloc(max_size
, GFP_KERNEL
);
1183 cdata
= scontrol
->control_data
;
1184 if (!scontrol
->control_data
) {
1189 scontrol
->comp_id
= sdev
->next_comp_id
;
1190 scontrol
->cmd
= SOF_CTRL_CMD_BINARY
;
1192 dev_dbg(scomp
->dev
, "tplg: load kcontrol index %d chans %d\n",
1193 scontrol
->comp_id
, scontrol
->num_channels
);
1195 if (le32_to_cpu(control
->priv
.size
) > 0) {
1196 memcpy(cdata
->data
, control
->priv
.data
,
1197 le32_to_cpu(control
->priv
.size
));
1199 if (cdata
->data
->magic
!= SOF_ABI_MAGIC
) {
1200 dev_err(scomp
->dev
, "error: Wrong ABI magic 0x%08x.\n",
1201 cdata
->data
->magic
);
1205 if (SOF_ABI_VERSION_INCOMPATIBLE(SOF_ABI_VERSION
,
1206 cdata
->data
->abi
)) {
1208 "error: Incompatible ABI version 0x%08x.\n",
1213 if (cdata
->data
->size
+ sizeof(struct sof_abi_hdr
) !=
1214 le32_to_cpu(control
->priv
.size
)) {
1216 "error: Conflict in bytes vs. priv size.\n");
1225 kfree(scontrol
->control_data
);
1230 /* external kcontrol init - used for any driver specific init */
1231 static int sof_control_load(struct snd_soc_component
*scomp
, int index
,
1232 struct snd_kcontrol_new
*kc
,
1233 struct snd_soc_tplg_ctl_hdr
*hdr
)
1235 struct soc_mixer_control
*sm
;
1236 struct soc_bytes_ext
*sbe
;
1237 struct soc_enum
*se
;
1238 struct snd_sof_dev
*sdev
= snd_soc_component_get_drvdata(scomp
);
1239 struct snd_soc_dobj
*dobj
;
1240 struct snd_sof_control
*scontrol
;
1243 dev_dbg(scomp
->dev
, "tplg: load control type %d name : %s\n",
1244 hdr
->type
, hdr
->name
);
1246 scontrol
= kzalloc(sizeof(*scontrol
), GFP_KERNEL
);
1250 scontrol
->scomp
= scomp
;
1252 switch (le32_to_cpu(hdr
->ops
.info
)) {
1253 case SND_SOC_TPLG_CTL_VOLSW
:
1254 case SND_SOC_TPLG_CTL_VOLSW_SX
:
1255 case SND_SOC_TPLG_CTL_VOLSW_XR_SX
:
1256 sm
= (struct soc_mixer_control
*)kc
->private_value
;
1258 ret
= sof_control_load_volume(scomp
, scontrol
, kc
, hdr
);
1260 case SND_SOC_TPLG_CTL_BYTES
:
1261 sbe
= (struct soc_bytes_ext
*)kc
->private_value
;
1263 ret
= sof_control_load_bytes(scomp
, scontrol
, kc
, hdr
);
1265 case SND_SOC_TPLG_CTL_ENUM
:
1266 case SND_SOC_TPLG_CTL_ENUM_VALUE
:
1267 se
= (struct soc_enum
*)kc
->private_value
;
1269 ret
= sof_control_load_enum(scomp
, scontrol
, kc
, hdr
);
1271 case SND_SOC_TPLG_CTL_RANGE
:
1272 case SND_SOC_TPLG_CTL_STROBE
:
1273 case SND_SOC_TPLG_DAPM_CTL_VOLSW
:
1274 case SND_SOC_TPLG_DAPM_CTL_ENUM_DOUBLE
:
1275 case SND_SOC_TPLG_DAPM_CTL_ENUM_VIRT
:
1276 case SND_SOC_TPLG_DAPM_CTL_ENUM_VALUE
:
1277 case SND_SOC_TPLG_DAPM_CTL_PIN
:
1279 dev_warn(scomp
->dev
, "control type not supported %d:%d:%d\n",
1280 hdr
->ops
.get
, hdr
->ops
.put
, hdr
->ops
.info
);
1290 scontrol
->led_ctl
.led_value
= -1;
1292 dobj
->private = scontrol
;
1293 list_add(&scontrol
->list
, &sdev
->kcontrol_list
);
1297 static int sof_control_unload(struct snd_soc_component
*scomp
,
1298 struct snd_soc_dobj
*dobj
)
1300 struct snd_sof_dev
*sdev
= snd_soc_component_get_drvdata(scomp
);
1301 struct sof_ipc_free fcomp
;
1302 struct snd_sof_control
*scontrol
= dobj
->private;
1304 dev_dbg(scomp
->dev
, "tplg: unload control name : %s\n", scomp
->name
);
1306 fcomp
.hdr
.cmd
= SOF_IPC_GLB_TPLG_MSG
| SOF_IPC_TPLG_COMP_FREE
;
1307 fcomp
.hdr
.size
= sizeof(fcomp
);
1308 fcomp
.id
= scontrol
->comp_id
;
1310 kfree(scontrol
->control_data
);
1311 list_del(&scontrol
->list
);
1313 /* send IPC to the DSP */
1314 return sof_ipc_tx_message(sdev
->ipc
,
1315 fcomp
.hdr
.cmd
, &fcomp
, sizeof(fcomp
),
1323 /* Static DSP core power management so far, should be extended in the future */
1324 static int sof_core_enable(struct snd_sof_dev
*sdev
, int core
)
1326 struct sof_ipc_pm_core_config pm_core_config
= {
1328 .cmd
= SOF_IPC_GLB_PM_MSG
| SOF_IPC_PM_CORE_ENABLE
,
1329 .size
= sizeof(pm_core_config
),
1331 .enable_mask
= sdev
->enabled_cores_mask
| BIT(core
),
1335 if (sdev
->enabled_cores_mask
& BIT(core
))
1338 /* power up the core if it is host managed */
1339 ret
= snd_sof_dsp_core_power_up(sdev
, BIT(core
));
1341 dev_err(sdev
->dev
, "error: %d powering up core %d\n",
1346 /* Now notify DSP */
1347 ret
= sof_ipc_tx_message(sdev
->ipc
, pm_core_config
.hdr
.cmd
,
1348 &pm_core_config
, sizeof(pm_core_config
),
1349 &pm_core_config
, sizeof(pm_core_config
));
1351 dev_err(sdev
->dev
, "error: core %d enable ipc failure %d\n",
1356 /* update enabled cores mask */
1357 sdev
->enabled_cores_mask
|= BIT(core
);
1361 /* power down core if it is host managed and return the original error if this fails too */
1362 if (snd_sof_dsp_core_power_down(sdev
, BIT(core
)) < 0)
1363 dev_err(sdev
->dev
, "error: powering down core %d\n", core
);
1368 int sof_pipeline_core_enable(struct snd_sof_dev
*sdev
,
1369 const struct snd_sof_widget
*swidget
)
1371 const struct sof_ipc_pipe_new
*pipeline
;
1374 if (swidget
->id
== snd_soc_dapm_scheduler
) {
1375 pipeline
= swidget
->private;
1377 pipeline
= snd_sof_pipeline_find(sdev
, swidget
->pipeline_id
);
1382 /* First enable the pipeline core */
1383 ret
= sof_core_enable(sdev
, pipeline
->core
);
1387 return sof_core_enable(sdev
, swidget
->core
);
1390 static int sof_connect_dai_widget(struct snd_soc_component
*scomp
,
1391 struct snd_soc_dapm_widget
*w
,
1392 struct snd_soc_tplg_dapm_widget
*tw
,
1393 struct snd_sof_dai
*dai
)
1395 struct snd_soc_card
*card
= scomp
->card
;
1396 struct snd_soc_pcm_runtime
*rtd
;
1397 struct snd_soc_dai
*cpu_dai
;
1400 list_for_each_entry(rtd
, &card
->rtd_list
, list
) {
1401 dev_vdbg(scomp
->dev
, "tplg: check widget: %s stream: %s dai stream: %s\n",
1402 w
->name
, w
->sname
, rtd
->dai_link
->stream_name
);
1404 if (!w
->sname
|| !rtd
->dai_link
->stream_name
)
1407 /* does stream match DAI link ? */
1408 if (strcmp(w
->sname
, rtd
->dai_link
->stream_name
))
1412 case snd_soc_dapm_dai_out
:
1413 for_each_rtd_cpu_dais(rtd
, i
, cpu_dai
) {
1415 * Please create DAI widget in the right order
1416 * to ensure BE will connect to the right DAI
1419 if (!cpu_dai
->capture_widget
) {
1420 cpu_dai
->capture_widget
= w
;
1424 if (i
== rtd
->num_cpus
) {
1425 dev_err(scomp
->dev
, "error: can't find BE for DAI %s\n",
1430 dai
->name
= rtd
->dai_link
->name
;
1431 dev_dbg(scomp
->dev
, "tplg: connected widget %s -> DAI link %s\n",
1432 w
->name
, rtd
->dai_link
->name
);
1434 case snd_soc_dapm_dai_in
:
1435 for_each_rtd_cpu_dais(rtd
, i
, cpu_dai
) {
1437 * Please create DAI widget in the right order
1438 * to ensure BE will connect to the right DAI
1441 if (!cpu_dai
->playback_widget
) {
1442 cpu_dai
->playback_widget
= w
;
1446 if (i
== rtd
->num_cpus
) {
1447 dev_err(scomp
->dev
, "error: can't find BE for DAI %s\n",
1452 dai
->name
= rtd
->dai_link
->name
;
1453 dev_dbg(scomp
->dev
, "tplg: connected widget %s -> DAI link %s\n",
1454 w
->name
, rtd
->dai_link
->name
);
1461 /* check we have a connection */
1463 dev_err(scomp
->dev
, "error: can't connect DAI %s stream %s\n",
1472 * sof_comp_alloc - allocate and initialize buffer for a new component
1473 * @swidget: pointer to struct snd_sof_widget containing extended data
1474 * @ipc_size: IPC payload size that will be updated depending on valid
1476 * @index: ID of the pipeline the component belongs to
1478 * Return: The pointer to the new allocated component, NULL if failed.
1480 static struct sof_ipc_comp
*sof_comp_alloc(struct snd_sof_widget
*swidget
,
1481 size_t *ipc_size
, int index
)
1483 u8 nil_uuid
[SOF_UUID_SIZE
] = {0};
1484 struct sof_ipc_comp
*comp
;
1485 size_t total_size
= *ipc_size
;
1487 /* only non-zero UUID is valid */
1488 if (memcmp(&swidget
->comp_ext
, nil_uuid
, SOF_UUID_SIZE
))
1489 total_size
+= sizeof(swidget
->comp_ext
);
1491 comp
= kzalloc(total_size
, GFP_KERNEL
);
1495 /* configure comp new IPC message */
1496 comp
->hdr
.size
= total_size
;
1497 comp
->hdr
.cmd
= SOF_IPC_GLB_TPLG_MSG
| SOF_IPC_TPLG_COMP_NEW
;
1498 comp
->id
= swidget
->comp_id
;
1499 comp
->pipeline_id
= index
;
1500 comp
->core
= swidget
->core
;
1502 /* handle the extended data if needed */
1503 if (total_size
> *ipc_size
) {
1504 /* append extended data to the end of the component */
1505 memcpy((u8
*)comp
+ *ipc_size
, &swidget
->comp_ext
, sizeof(swidget
->comp_ext
));
1506 comp
->ext_data_length
= sizeof(swidget
->comp_ext
);
1509 /* update ipc_size and return */
1510 *ipc_size
= total_size
;
1514 static int sof_widget_load_dai(struct snd_soc_component
*scomp
, int index
,
1515 struct snd_sof_widget
*swidget
,
1516 struct snd_soc_tplg_dapm_widget
*tw
,
1517 struct sof_ipc_comp_reply
*r
,
1518 struct snd_sof_dai
*dai
)
1520 struct snd_sof_dev
*sdev
= snd_soc_component_get_drvdata(scomp
);
1521 struct snd_soc_tplg_private
*private = &tw
->priv
;
1522 struct sof_ipc_comp_dai
*comp_dai
;
1523 size_t ipc_size
= sizeof(*comp_dai
);
1526 comp_dai
= (struct sof_ipc_comp_dai
*)
1527 sof_comp_alloc(swidget
, &ipc_size
, index
);
1531 /* configure dai IPC message */
1532 comp_dai
->comp
.type
= SOF_COMP_DAI
;
1533 comp_dai
->config
.hdr
.size
= sizeof(comp_dai
->config
);
1535 ret
= sof_parse_tokens(scomp
, comp_dai
, dai_tokens
,
1536 ARRAY_SIZE(dai_tokens
), private->array
,
1537 le32_to_cpu(private->size
));
1539 dev_err(scomp
->dev
, "error: parse dai tokens failed %d\n",
1540 le32_to_cpu(private->size
));
1544 ret
= sof_parse_tokens(scomp
, &comp_dai
->config
, comp_tokens
,
1545 ARRAY_SIZE(comp_tokens
), private->array
,
1546 le32_to_cpu(private->size
));
1548 dev_err(scomp
->dev
, "error: parse dai.cfg tokens failed %d\n",
1553 dev_dbg(scomp
->dev
, "dai %s: type %d index %d\n",
1554 swidget
->widget
->name
, comp_dai
->type
, comp_dai
->dai_index
);
1555 sof_dbg_comp_config(scomp
, &comp_dai
->config
);
1557 ret
= sof_ipc_tx_message(sdev
->ipc
, comp_dai
->comp
.hdr
.cmd
,
1558 comp_dai
, ipc_size
, r
, sizeof(*r
));
1560 if (ret
== 0 && dai
) {
1564 * copy only the sof_ipc_comp_dai to avoid collapsing
1565 * the snd_sof_dai, the extended data is kept in the
1568 memcpy(&dai
->comp_dai
, comp_dai
, sizeof(*comp_dai
));
1580 static int sof_widget_load_buffer(struct snd_soc_component
*scomp
, int index
,
1581 struct snd_sof_widget
*swidget
,
1582 struct snd_soc_tplg_dapm_widget
*tw
,
1583 struct sof_ipc_comp_reply
*r
)
1585 struct snd_sof_dev
*sdev
= snd_soc_component_get_drvdata(scomp
);
1586 struct snd_soc_tplg_private
*private = &tw
->priv
;
1587 struct sof_ipc_buffer
*buffer
;
1590 buffer
= kzalloc(sizeof(*buffer
), GFP_KERNEL
);
1594 /* configure dai IPC message */
1595 buffer
->comp
.hdr
.size
= sizeof(*buffer
);
1596 buffer
->comp
.hdr
.cmd
= SOF_IPC_GLB_TPLG_MSG
| SOF_IPC_TPLG_BUFFER_NEW
;
1597 buffer
->comp
.id
= swidget
->comp_id
;
1598 buffer
->comp
.type
= SOF_COMP_BUFFER
;
1599 buffer
->comp
.pipeline_id
= index
;
1600 buffer
->comp
.core
= swidget
->core
;
1602 ret
= sof_parse_tokens(scomp
, buffer
, buffer_tokens
,
1603 ARRAY_SIZE(buffer_tokens
), private->array
,
1604 le32_to_cpu(private->size
));
1606 dev_err(scomp
->dev
, "error: parse buffer tokens failed %d\n",
1612 dev_dbg(scomp
->dev
, "buffer %s: size %d caps 0x%x\n",
1613 swidget
->widget
->name
, buffer
->size
, buffer
->caps
);
1615 swidget
->private = buffer
;
1617 ret
= sof_ipc_tx_message(sdev
->ipc
, buffer
->comp
.hdr
.cmd
, buffer
,
1618 sizeof(*buffer
), r
, sizeof(*r
));
1620 dev_err(scomp
->dev
, "error: buffer %s load failed\n",
1621 swidget
->widget
->name
);
1628 /* bind PCM ID to host component ID */
1629 static int spcm_bind(struct snd_soc_component
*scomp
, struct snd_sof_pcm
*spcm
,
1632 struct snd_sof_widget
*host_widget
;
1634 host_widget
= snd_sof_find_swidget_sname(scomp
,
1635 spcm
->pcm
.caps
[dir
].name
,
1638 dev_err(scomp
->dev
, "can't find host comp to bind pcm\n");
1642 spcm
->stream
[dir
].comp_id
= host_widget
->comp_id
;
1651 static int sof_widget_load_pcm(struct snd_soc_component
*scomp
, int index
,
1652 struct snd_sof_widget
*swidget
,
1653 enum sof_ipc_stream_direction dir
,
1654 struct snd_soc_tplg_dapm_widget
*tw
,
1655 struct sof_ipc_comp_reply
*r
)
1657 struct snd_sof_dev
*sdev
= snd_soc_component_get_drvdata(scomp
);
1658 struct snd_soc_tplg_private
*private = &tw
->priv
;
1659 struct sof_ipc_comp_host
*host
;
1660 size_t ipc_size
= sizeof(*host
);
1663 host
= (struct sof_ipc_comp_host
*)
1664 sof_comp_alloc(swidget
, &ipc_size
, index
);
1668 /* configure host comp IPC message */
1669 host
->comp
.type
= SOF_COMP_HOST
;
1670 host
->direction
= dir
;
1671 host
->config
.hdr
.size
= sizeof(host
->config
);
1673 ret
= sof_parse_tokens(scomp
, host
, pcm_tokens
,
1674 ARRAY_SIZE(pcm_tokens
), private->array
,
1675 le32_to_cpu(private->size
));
1677 dev_err(scomp
->dev
, "error: parse host tokens failed %d\n",
1682 ret
= sof_parse_tokens(scomp
, &host
->config
, comp_tokens
,
1683 ARRAY_SIZE(comp_tokens
), private->array
,
1684 le32_to_cpu(private->size
));
1686 dev_err(scomp
->dev
, "error: parse host.cfg tokens failed %d\n",
1687 le32_to_cpu(private->size
));
1691 dev_dbg(scomp
->dev
, "loaded host %s\n", swidget
->widget
->name
);
1692 sof_dbg_comp_config(scomp
, &host
->config
);
1694 swidget
->private = host
;
1696 ret
= sof_ipc_tx_message(sdev
->ipc
, host
->comp
.hdr
.cmd
, host
,
1697 ipc_size
, r
, sizeof(*r
));
1708 int sof_load_pipeline_ipc(struct device
*dev
,
1709 struct sof_ipc_pipe_new
*pipeline
,
1710 struct sof_ipc_comp_reply
*r
)
1712 struct snd_sof_dev
*sdev
= dev_get_drvdata(dev
);
1713 int ret
= sof_core_enable(sdev
, pipeline
->core
);
1718 ret
= sof_ipc_tx_message(sdev
->ipc
, pipeline
->hdr
.cmd
, pipeline
,
1719 sizeof(*pipeline
), r
, sizeof(*r
));
1721 dev_err(dev
, "error: load pipeline ipc failure\n");
1726 static int sof_widget_load_pipeline(struct snd_soc_component
*scomp
, int index
,
1727 struct snd_sof_widget
*swidget
,
1728 struct snd_soc_tplg_dapm_widget
*tw
,
1729 struct sof_ipc_comp_reply
*r
)
1731 struct snd_soc_tplg_private
*private = &tw
->priv
;
1732 struct sof_ipc_pipe_new
*pipeline
;
1733 struct snd_sof_widget
*comp_swidget
;
1736 pipeline
= kzalloc(sizeof(*pipeline
), GFP_KERNEL
);
1740 /* configure dai IPC message */
1741 pipeline
->hdr
.size
= sizeof(*pipeline
);
1742 pipeline
->hdr
.cmd
= SOF_IPC_GLB_TPLG_MSG
| SOF_IPC_TPLG_PIPE_NEW
;
1743 pipeline
->pipeline_id
= index
;
1744 pipeline
->comp_id
= swidget
->comp_id
;
1746 /* component at start of pipeline is our stream id */
1747 comp_swidget
= snd_sof_find_swidget(scomp
, tw
->sname
);
1748 if (!comp_swidget
) {
1749 dev_err(scomp
->dev
, "error: widget %s refers to non existent widget %s\n",
1750 tw
->name
, tw
->sname
);
1755 pipeline
->sched_id
= comp_swidget
->comp_id
;
1757 dev_dbg(scomp
->dev
, "tplg: pipeline id %d comp %d scheduling comp id %d\n",
1758 pipeline
->pipeline_id
, pipeline
->comp_id
, pipeline
->sched_id
);
1760 ret
= sof_parse_tokens(scomp
, pipeline
, sched_tokens
,
1761 ARRAY_SIZE(sched_tokens
), private->array
,
1762 le32_to_cpu(private->size
));
1764 dev_err(scomp
->dev
, "error: parse pipeline tokens failed %d\n",
1769 dev_dbg(scomp
->dev
, "pipeline %s: period %d pri %d mips %d core %d frames %d\n",
1770 swidget
->widget
->name
, pipeline
->period
, pipeline
->priority
,
1771 pipeline
->period_mips
, pipeline
->core
, pipeline
->frames_per_sched
);
1773 swidget
->private = pipeline
;
1775 /* send ipc's to create pipeline comp and power up schedule core */
1776 ret
= sof_load_pipeline_ipc(scomp
->dev
, pipeline
, r
);
1788 static int sof_widget_load_mixer(struct snd_soc_component
*scomp
, int index
,
1789 struct snd_sof_widget
*swidget
,
1790 struct snd_soc_tplg_dapm_widget
*tw
,
1791 struct sof_ipc_comp_reply
*r
)
1793 struct snd_sof_dev
*sdev
= snd_soc_component_get_drvdata(scomp
);
1794 struct snd_soc_tplg_private
*private = &tw
->priv
;
1795 struct sof_ipc_comp_mixer
*mixer
;
1796 size_t ipc_size
= sizeof(*mixer
);
1799 mixer
= (struct sof_ipc_comp_mixer
*)
1800 sof_comp_alloc(swidget
, &ipc_size
, index
);
1804 /* configure mixer IPC message */
1805 mixer
->comp
.type
= SOF_COMP_MIXER
;
1806 mixer
->config
.hdr
.size
= sizeof(mixer
->config
);
1808 ret
= sof_parse_tokens(scomp
, &mixer
->config
, comp_tokens
,
1809 ARRAY_SIZE(comp_tokens
), private->array
,
1810 le32_to_cpu(private->size
));
1812 dev_err(scomp
->dev
, "error: parse mixer.cfg tokens failed %d\n",
1818 sof_dbg_comp_config(scomp
, &mixer
->config
);
1820 swidget
->private = mixer
;
1822 ret
= sof_ipc_tx_message(sdev
->ipc
, mixer
->comp
.hdr
.cmd
, mixer
,
1823 ipc_size
, r
, sizeof(*r
));
1833 static int sof_widget_load_mux(struct snd_soc_component
*scomp
, int index
,
1834 struct snd_sof_widget
*swidget
,
1835 struct snd_soc_tplg_dapm_widget
*tw
,
1836 struct sof_ipc_comp_reply
*r
)
1838 struct snd_sof_dev
*sdev
= snd_soc_component_get_drvdata(scomp
);
1839 struct snd_soc_tplg_private
*private = &tw
->priv
;
1840 struct sof_ipc_comp_mux
*mux
;
1841 size_t ipc_size
= sizeof(*mux
);
1844 mux
= (struct sof_ipc_comp_mux
*)
1845 sof_comp_alloc(swidget
, &ipc_size
, index
);
1849 /* configure mux IPC message */
1850 mux
->comp
.type
= SOF_COMP_MUX
;
1851 mux
->config
.hdr
.size
= sizeof(mux
->config
);
1853 ret
= sof_parse_tokens(scomp
, &mux
->config
, comp_tokens
,
1854 ARRAY_SIZE(comp_tokens
), private->array
,
1855 le32_to_cpu(private->size
));
1857 dev_err(scomp
->dev
, "error: parse mux.cfg tokens failed %d\n",
1863 sof_dbg_comp_config(scomp
, &mux
->config
);
1865 swidget
->private = mux
;
1867 ret
= sof_ipc_tx_message(sdev
->ipc
, mux
->comp
.hdr
.cmd
, mux
,
1868 ipc_size
, r
, sizeof(*r
));
1879 static int sof_widget_load_pga(struct snd_soc_component
*scomp
, int index
,
1880 struct snd_sof_widget
*swidget
,
1881 struct snd_soc_tplg_dapm_widget
*tw
,
1882 struct sof_ipc_comp_reply
*r
)
1884 struct snd_sof_dev
*sdev
= snd_soc_component_get_drvdata(scomp
);
1885 struct snd_soc_tplg_private
*private = &tw
->priv
;
1886 struct sof_ipc_comp_volume
*volume
;
1887 struct snd_sof_control
*scontrol
;
1888 size_t ipc_size
= sizeof(*volume
);
1893 volume
= (struct sof_ipc_comp_volume
*)
1894 sof_comp_alloc(swidget
, &ipc_size
, index
);
1898 if (!le32_to_cpu(tw
->num_kcontrols
)) {
1899 dev_err(scomp
->dev
, "error: invalid kcontrol count %d for volume\n",
1905 /* configure volume IPC message */
1906 volume
->comp
.type
= SOF_COMP_VOLUME
;
1907 volume
->config
.hdr
.size
= sizeof(volume
->config
);
1909 ret
= sof_parse_tokens(scomp
, volume
, volume_tokens
,
1910 ARRAY_SIZE(volume_tokens
), private->array
,
1911 le32_to_cpu(private->size
));
1913 dev_err(scomp
->dev
, "error: parse volume tokens failed %d\n",
1917 ret
= sof_parse_tokens(scomp
, &volume
->config
, comp_tokens
,
1918 ARRAY_SIZE(comp_tokens
), private->array
,
1919 le32_to_cpu(private->size
));
1921 dev_err(scomp
->dev
, "error: parse volume.cfg tokens failed %d\n",
1922 le32_to_cpu(private->size
));
1926 sof_dbg_comp_config(scomp
, &volume
->config
);
1928 swidget
->private = volume
;
1930 list_for_each_entry(scontrol
, &sdev
->kcontrol_list
, list
) {
1931 if (scontrol
->comp_id
== swidget
->comp_id
&&
1932 scontrol
->volume_table
) {
1933 min_step
= scontrol
->min_volume_step
;
1934 max_step
= scontrol
->max_volume_step
;
1935 volume
->min_value
= scontrol
->volume_table
[min_step
];
1936 volume
->max_value
= scontrol
->volume_table
[max_step
];
1937 volume
->channels
= scontrol
->num_channels
;
1942 ret
= sof_ipc_tx_message(sdev
->ipc
, volume
->comp
.hdr
.cmd
, volume
,
1943 ipc_size
, r
, sizeof(*r
));
1955 static int sof_widget_load_src(struct snd_soc_component
*scomp
, int index
,
1956 struct snd_sof_widget
*swidget
,
1957 struct snd_soc_tplg_dapm_widget
*tw
,
1958 struct sof_ipc_comp_reply
*r
)
1960 struct snd_sof_dev
*sdev
= snd_soc_component_get_drvdata(scomp
);
1961 struct snd_soc_tplg_private
*private = &tw
->priv
;
1962 struct sof_ipc_comp_src
*src
;
1963 size_t ipc_size
= sizeof(*src
);
1966 src
= (struct sof_ipc_comp_src
*)
1967 sof_comp_alloc(swidget
, &ipc_size
, index
);
1971 /* configure src IPC message */
1972 src
->comp
.type
= SOF_COMP_SRC
;
1973 src
->config
.hdr
.size
= sizeof(src
->config
);
1975 ret
= sof_parse_tokens(scomp
, src
, src_tokens
,
1976 ARRAY_SIZE(src_tokens
), private->array
,
1977 le32_to_cpu(private->size
));
1979 dev_err(scomp
->dev
, "error: parse src tokens failed %d\n",
1984 ret
= sof_parse_tokens(scomp
, &src
->config
, comp_tokens
,
1985 ARRAY_SIZE(comp_tokens
), private->array
,
1986 le32_to_cpu(private->size
));
1988 dev_err(scomp
->dev
, "error: parse src.cfg tokens failed %d\n",
1989 le32_to_cpu(private->size
));
1993 dev_dbg(scomp
->dev
, "src %s: source rate %d sink rate %d\n",
1994 swidget
->widget
->name
, src
->source_rate
, src
->sink_rate
);
1995 sof_dbg_comp_config(scomp
, &src
->config
);
1997 swidget
->private = src
;
1999 ret
= sof_ipc_tx_message(sdev
->ipc
, src
->comp
.hdr
.cmd
, src
,
2000 ipc_size
, r
, sizeof(*r
));
2012 static int sof_widget_load_asrc(struct snd_soc_component
*scomp
, int index
,
2013 struct snd_sof_widget
*swidget
,
2014 struct snd_soc_tplg_dapm_widget
*tw
,
2015 struct sof_ipc_comp_reply
*r
)
2017 struct snd_sof_dev
*sdev
= snd_soc_component_get_drvdata(scomp
);
2018 struct snd_soc_tplg_private
*private = &tw
->priv
;
2019 struct sof_ipc_comp_asrc
*asrc
;
2020 size_t ipc_size
= sizeof(*asrc
);
2023 asrc
= (struct sof_ipc_comp_asrc
*)
2024 sof_comp_alloc(swidget
, &ipc_size
, index
);
2028 /* configure ASRC IPC message */
2029 asrc
->comp
.type
= SOF_COMP_ASRC
;
2030 asrc
->config
.hdr
.size
= sizeof(asrc
->config
);
2032 ret
= sof_parse_tokens(scomp
, asrc
, asrc_tokens
,
2033 ARRAY_SIZE(asrc_tokens
), private->array
,
2034 le32_to_cpu(private->size
));
2036 dev_err(scomp
->dev
, "error: parse asrc tokens failed %d\n",
2041 ret
= sof_parse_tokens(scomp
, &asrc
->config
, comp_tokens
,
2042 ARRAY_SIZE(comp_tokens
), private->array
,
2043 le32_to_cpu(private->size
));
2045 dev_err(scomp
->dev
, "error: parse asrc.cfg tokens failed %d\n",
2046 le32_to_cpu(private->size
));
2050 dev_dbg(scomp
->dev
, "asrc %s: source rate %d sink rate %d "
2051 "asynch %d operation %d\n",
2052 swidget
->widget
->name
, asrc
->source_rate
, asrc
->sink_rate
,
2053 asrc
->asynchronous_mode
, asrc
->operation_mode
);
2054 sof_dbg_comp_config(scomp
, &asrc
->config
);
2056 swidget
->private = asrc
;
2058 ret
= sof_ipc_tx_message(sdev
->ipc
, asrc
->comp
.hdr
.cmd
, asrc
,
2059 ipc_size
, r
, sizeof(*r
));
2068 * Signal Generator Topology
2071 static int sof_widget_load_siggen(struct snd_soc_component
*scomp
, int index
,
2072 struct snd_sof_widget
*swidget
,
2073 struct snd_soc_tplg_dapm_widget
*tw
,
2074 struct sof_ipc_comp_reply
*r
)
2076 struct snd_sof_dev
*sdev
= snd_soc_component_get_drvdata(scomp
);
2077 struct snd_soc_tplg_private
*private = &tw
->priv
;
2078 struct sof_ipc_comp_tone
*tone
;
2079 size_t ipc_size
= sizeof(*tone
);
2082 tone
= (struct sof_ipc_comp_tone
*)
2083 sof_comp_alloc(swidget
, &ipc_size
, index
);
2087 /* configure siggen IPC message */
2088 tone
->comp
.type
= SOF_COMP_TONE
;
2089 tone
->config
.hdr
.size
= sizeof(tone
->config
);
2091 ret
= sof_parse_tokens(scomp
, tone
, tone_tokens
,
2092 ARRAY_SIZE(tone_tokens
), private->array
,
2093 le32_to_cpu(private->size
));
2095 dev_err(scomp
->dev
, "error: parse tone tokens failed %d\n",
2096 le32_to_cpu(private->size
));
2100 ret
= sof_parse_tokens(scomp
, &tone
->config
, comp_tokens
,
2101 ARRAY_SIZE(comp_tokens
), private->array
,
2102 le32_to_cpu(private->size
));
2104 dev_err(scomp
->dev
, "error: parse tone.cfg tokens failed %d\n",
2105 le32_to_cpu(private->size
));
2109 dev_dbg(scomp
->dev
, "tone %s: frequency %d amplitude %d\n",
2110 swidget
->widget
->name
, tone
->frequency
, tone
->amplitude
);
2111 sof_dbg_comp_config(scomp
, &tone
->config
);
2113 swidget
->private = tone
;
2115 ret
= sof_ipc_tx_message(sdev
->ipc
, tone
->comp
.hdr
.cmd
, tone
,
2116 ipc_size
, r
, sizeof(*r
));
2124 static int sof_get_control_data(struct snd_soc_component
*scomp
,
2125 struct snd_soc_dapm_widget
*widget
,
2126 struct sof_widget_data
*wdata
,
2129 const struct snd_kcontrol_new
*kc
;
2130 struct soc_mixer_control
*sm
;
2131 struct soc_bytes_ext
*sbe
;
2132 struct soc_enum
*se
;
2137 for (i
= 0; i
< widget
->num_kcontrols
; i
++) {
2138 kc
= &widget
->kcontrol_news
[i
];
2140 switch (widget
->dobj
.widget
.kcontrol_type
) {
2141 case SND_SOC_TPLG_TYPE_MIXER
:
2142 sm
= (struct soc_mixer_control
*)kc
->private_value
;
2143 wdata
[i
].control
= sm
->dobj
.private;
2145 case SND_SOC_TPLG_TYPE_BYTES
:
2146 sbe
= (struct soc_bytes_ext
*)kc
->private_value
;
2147 wdata
[i
].control
= sbe
->dobj
.private;
2149 case SND_SOC_TPLG_TYPE_ENUM
:
2150 se
= (struct soc_enum
*)kc
->private_value
;
2151 wdata
[i
].control
= se
->dobj
.private;
2154 dev_err(scomp
->dev
, "error: unknown kcontrol type %d in widget %s\n",
2155 widget
->dobj
.widget
.kcontrol_type
,
2160 if (!wdata
[i
].control
) {
2161 dev_err(scomp
->dev
, "error: no scontrol for widget %s\n",
2166 wdata
[i
].pdata
= wdata
[i
].control
->control_data
->data
;
2167 if (!wdata
[i
].pdata
)
2170 /* make sure data is valid - data can be updated at runtime */
2171 if (wdata
[i
].pdata
->magic
!= SOF_ABI_MAGIC
)
2174 *size
+= wdata
[i
].pdata
->size
;
2177 switch (wdata
[i
].control
->cmd
) {
2178 case SOF_CTRL_CMD_VOLUME
:
2179 case SOF_CTRL_CMD_ENUM
:
2180 case SOF_CTRL_CMD_SWITCH
:
2181 wdata
[i
].ipc_cmd
= SOF_IPC_COMP_SET_VALUE
;
2182 wdata
[i
].ctrl_type
= SOF_CTRL_TYPE_VALUE_CHAN_SET
;
2184 case SOF_CTRL_CMD_BINARY
:
2185 wdata
[i
].ipc_cmd
= SOF_IPC_COMP_SET_DATA
;
2186 wdata
[i
].ctrl_type
= SOF_CTRL_TYPE_DATA_SET
;
2196 static int sof_process_load(struct snd_soc_component
*scomp
, int index
,
2197 struct snd_sof_widget
*swidget
,
2198 struct snd_soc_tplg_dapm_widget
*tw
,
2199 struct sof_ipc_comp_reply
*r
,
2202 struct snd_sof_dev
*sdev
= snd_soc_component_get_drvdata(scomp
);
2203 struct snd_soc_dapm_widget
*widget
= swidget
->widget
;
2204 struct snd_soc_tplg_private
*private = &tw
->priv
;
2205 struct sof_ipc_comp_process
*process
;
2206 struct sof_widget_data
*wdata
= NULL
;
2207 size_t ipc_data_size
= 0;
2213 /* allocate struct for widget control data sizes and types */
2214 if (widget
->num_kcontrols
) {
2215 wdata
= kcalloc(widget
->num_kcontrols
,
2222 /* get possible component controls and get size of all pdata */
2223 ret
= sof_get_control_data(scomp
, widget
, wdata
,
2230 ipc_size
= sizeof(struct sof_ipc_comp_process
) + ipc_data_size
;
2232 /* we are exceeding max ipc size, config needs to be sent separately */
2233 if (ipc_size
> SOF_IPC_MSG_MAX_SIZE
) {
2234 ipc_size
-= ipc_data_size
;
2238 process
= (struct sof_ipc_comp_process
*)
2239 sof_comp_alloc(swidget
, &ipc_size
, index
);
2245 /* configure iir IPC message */
2246 process
->comp
.type
= type
;
2247 process
->config
.hdr
.size
= sizeof(process
->config
);
2249 ret
= sof_parse_tokens(scomp
, &process
->config
, comp_tokens
,
2250 ARRAY_SIZE(comp_tokens
), private->array
,
2251 le32_to_cpu(private->size
));
2253 dev_err(scomp
->dev
, "error: parse process.cfg tokens failed %d\n",
2254 le32_to_cpu(private->size
));
2258 sof_dbg_comp_config(scomp
, &process
->config
);
2261 * found private data in control, so copy it.
2262 * get possible component controls - get size of all pdata,
2263 * then memcpy with headers
2265 if (ipc_data_size
) {
2266 for (i
= 0; i
< widget
->num_kcontrols
; i
++) {
2267 memcpy(&process
->data
+ offset
,
2268 wdata
[i
].pdata
->data
,
2269 wdata
[i
].pdata
->size
);
2270 offset
+= wdata
[i
].pdata
->size
;
2274 process
->size
= ipc_data_size
;
2275 swidget
->private = process
;
2277 ret
= sof_ipc_tx_message(sdev
->ipc
, process
->comp
.hdr
.cmd
, process
,
2278 ipc_size
, r
, sizeof(*r
));
2281 dev_err(scomp
->dev
, "error: create process failed\n");
2285 /* we sent the data in single message so return */
2289 /* send control data with large message supported method */
2290 for (i
= 0; i
< widget
->num_kcontrols
; i
++) {
2291 wdata
[i
].control
->readback_offset
= 0;
2292 ret
= snd_sof_ipc_set_get_comp_data(wdata
[i
].control
,
2295 wdata
[i
].control
->cmd
,
2298 dev_err(scomp
->dev
, "error: send control failed\n");
2312 * Processing Component Topology - can be "effect", "codec", or general
2316 static int sof_widget_load_process(struct snd_soc_component
*scomp
, int index
,
2317 struct snd_sof_widget
*swidget
,
2318 struct snd_soc_tplg_dapm_widget
*tw
,
2319 struct sof_ipc_comp_reply
*r
)
2321 struct snd_soc_tplg_private
*private = &tw
->priv
;
2322 struct sof_ipc_comp_process config
;
2325 /* check we have some tokens - we need at least process type */
2326 if (le32_to_cpu(private->size
) == 0) {
2327 dev_err(scomp
->dev
, "error: process tokens not found\n");
2331 memset(&config
, 0, sizeof(config
));
2332 config
.comp
.core
= swidget
->core
;
2334 /* get the process token */
2335 ret
= sof_parse_tokens(scomp
, &config
, process_tokens
,
2336 ARRAY_SIZE(process_tokens
), private->array
,
2337 le32_to_cpu(private->size
));
2339 dev_err(scomp
->dev
, "error: parse process tokens failed %d\n",
2340 le32_to_cpu(private->size
));
2344 /* now load process specific data and send IPC */
2345 ret
= sof_process_load(scomp
, index
, swidget
, tw
, r
,
2346 find_process_comp_type(config
.type
));
2348 dev_err(scomp
->dev
, "error: process loading failed\n");
2355 static int sof_widget_bind_event(struct snd_soc_component
*scomp
,
2356 struct snd_sof_widget
*swidget
,
2359 struct sof_ipc_comp
*ipc_comp
;
2361 /* validate widget event type */
2362 switch (event_type
) {
2363 case SOF_KEYWORD_DETECT_DAPM_EVENT
:
2364 /* only KEYWORD_DETECT comps should handle this */
2365 if (swidget
->id
!= snd_soc_dapm_effect
)
2368 ipc_comp
= swidget
->private;
2369 if (ipc_comp
&& ipc_comp
->type
!= SOF_COMP_KEYWORD_DETECT
)
2372 /* bind event to keyword detect comp */
2373 return snd_soc_tplg_widget_bind_event(swidget
->widget
,
2375 ARRAY_SIZE(sof_kwd_events
),
2382 "error: invalid event type %d for widget %s\n",
2383 event_type
, swidget
->widget
->name
);
2387 /* external widget init - used for any driver specific init */
2388 static int sof_widget_ready(struct snd_soc_component
*scomp
, int index
,
2389 struct snd_soc_dapm_widget
*w
,
2390 struct snd_soc_tplg_dapm_widget
*tw
)
2392 struct snd_sof_dev
*sdev
= snd_soc_component_get_drvdata(scomp
);
2393 struct snd_sof_widget
*swidget
;
2394 struct snd_sof_dai
*dai
;
2395 struct sof_ipc_comp_reply reply
;
2396 struct snd_sof_control
*scontrol
;
2397 struct sof_ipc_comp comp
= {
2398 .core
= SOF_DSP_PRIMARY_CORE
,
2402 swidget
= kzalloc(sizeof(*swidget
), GFP_KERNEL
);
2406 swidget
->scomp
= scomp
;
2407 swidget
->widget
= w
;
2408 swidget
->comp_id
= sdev
->next_comp_id
++;
2409 swidget
->complete
= 0;
2410 swidget
->id
= w
->id
;
2411 swidget
->pipeline_id
= index
;
2412 swidget
->private = NULL
;
2413 memset(&reply
, 0, sizeof(reply
));
2415 dev_dbg(scomp
->dev
, "tplg: ready widget id %d pipe %d type %d name : %s stream %s\n",
2416 swidget
->comp_id
, index
, swidget
->id
, tw
->name
,
2417 strnlen(tw
->sname
, SNDRV_CTL_ELEM_ID_NAME_MAXLEN
) > 0
2418 ? tw
->sname
: "none");
2420 ret
= sof_parse_tokens(scomp
, &comp
, core_tokens
,
2421 ARRAY_SIZE(core_tokens
), tw
->priv
.array
,
2422 le32_to_cpu(tw
->priv
.size
));
2424 dev_err(scomp
->dev
, "error: parsing core tokens failed %d\n",
2430 swidget
->core
= comp
.core
;
2432 /* default is primary core, safe to call for already enabled cores */
2433 ret
= sof_core_enable(sdev
, comp
.core
);
2435 dev_err(scomp
->dev
, "error: enable core: %d\n", ret
);
2440 ret
= sof_parse_tokens(scomp
, &swidget
->comp_ext
, comp_ext_tokens
,
2441 ARRAY_SIZE(comp_ext_tokens
), tw
->priv
.array
,
2442 le32_to_cpu(tw
->priv
.size
));
2444 dev_err(scomp
->dev
, "error: parsing comp_ext_tokens failed %d\n",
2450 /* handle any special case widgets */
2452 case snd_soc_dapm_dai_in
:
2453 case snd_soc_dapm_dai_out
:
2454 dai
= kzalloc(sizeof(*dai
), GFP_KERNEL
);
2460 ret
= sof_widget_load_dai(scomp
, index
, swidget
, tw
, &reply
, dai
);
2462 sof_connect_dai_widget(scomp
, w
, tw
, dai
);
2463 list_add(&dai
->list
, &sdev
->dai_list
);
2464 swidget
->private = dai
;
2469 case snd_soc_dapm_mixer
:
2470 ret
= sof_widget_load_mixer(scomp
, index
, swidget
, tw
, &reply
);
2472 case snd_soc_dapm_pga
:
2473 ret
= sof_widget_load_pga(scomp
, index
, swidget
, tw
, &reply
);
2474 /* Find scontrol for this pga and set readback offset*/
2475 list_for_each_entry(scontrol
, &sdev
->kcontrol_list
, list
) {
2476 if (scontrol
->comp_id
== swidget
->comp_id
) {
2477 scontrol
->readback_offset
= reply
.offset
;
2482 case snd_soc_dapm_buffer
:
2483 ret
= sof_widget_load_buffer(scomp
, index
, swidget
, tw
, &reply
);
2485 case snd_soc_dapm_scheduler
:
2486 ret
= sof_widget_load_pipeline(scomp
, index
, swidget
, tw
, &reply
);
2488 case snd_soc_dapm_aif_out
:
2489 ret
= sof_widget_load_pcm(scomp
, index
, swidget
,
2490 SOF_IPC_STREAM_CAPTURE
, tw
, &reply
);
2492 case snd_soc_dapm_aif_in
:
2493 ret
= sof_widget_load_pcm(scomp
, index
, swidget
,
2494 SOF_IPC_STREAM_PLAYBACK
, tw
, &reply
);
2496 case snd_soc_dapm_src
:
2497 ret
= sof_widget_load_src(scomp
, index
, swidget
, tw
, &reply
);
2499 case snd_soc_dapm_asrc
:
2500 ret
= sof_widget_load_asrc(scomp
, index
, swidget
, tw
, &reply
);
2502 case snd_soc_dapm_siggen
:
2503 ret
= sof_widget_load_siggen(scomp
, index
, swidget
, tw
, &reply
);
2505 case snd_soc_dapm_effect
:
2506 ret
= sof_widget_load_process(scomp
, index
, swidget
, tw
, &reply
);
2508 case snd_soc_dapm_mux
:
2509 case snd_soc_dapm_demux
:
2510 ret
= sof_widget_load_mux(scomp
, index
, swidget
, tw
, &reply
);
2512 case snd_soc_dapm_switch
:
2513 case snd_soc_dapm_dai_link
:
2514 case snd_soc_dapm_kcontrol
:
2516 dev_dbg(scomp
->dev
, "widget type %d name %s not handled\n", swidget
->id
, tw
->name
);
2520 /* check IPC reply */
2521 if (ret
< 0 || reply
.rhdr
.error
< 0) {
2523 "error: DSP failed to add widget id %d type %d name : %s stream %s reply %d\n",
2524 tw
->shift
, swidget
->id
, tw
->name
,
2525 strnlen(tw
->sname
, SNDRV_CTL_ELEM_ID_NAME_MAXLEN
) > 0
2526 ? tw
->sname
: "none", reply
.rhdr
.error
);
2531 /* bind widget to external event */
2532 if (tw
->event_type
) {
2533 ret
= sof_widget_bind_event(scomp
, swidget
,
2534 le16_to_cpu(tw
->event_type
));
2536 dev_err(scomp
->dev
, "error: widget event binding failed\n");
2537 kfree(swidget
->private);
2543 w
->dobj
.private = swidget
;
2544 list_add(&swidget
->list
, &sdev
->widget_list
);
2548 static int sof_route_unload(struct snd_soc_component
*scomp
,
2549 struct snd_soc_dobj
*dobj
)
2551 struct snd_sof_route
*sroute
;
2553 sroute
= dobj
->private;
2557 /* free sroute and its private data */
2558 kfree(sroute
->private);
2559 list_del(&sroute
->list
);
2565 static int sof_widget_unload(struct snd_soc_component
*scomp
,
2566 struct snd_soc_dobj
*dobj
)
2568 struct snd_sof_dev
*sdev
= snd_soc_component_get_drvdata(scomp
);
2569 const struct snd_kcontrol_new
*kc
;
2570 struct snd_soc_dapm_widget
*widget
;
2571 struct sof_ipc_pipe_new
*pipeline
;
2572 struct snd_sof_control
*scontrol
;
2573 struct snd_sof_widget
*swidget
;
2574 struct soc_mixer_control
*sm
;
2575 struct soc_bytes_ext
*sbe
;
2576 struct snd_sof_dai
*dai
;
2577 struct soc_enum
*se
;
2581 swidget
= dobj
->private;
2585 widget
= swidget
->widget
;
2587 switch (swidget
->id
) {
2588 case snd_soc_dapm_dai_in
:
2589 case snd_soc_dapm_dai_out
:
2590 dai
= swidget
->private;
2593 /* free dai config */
2594 kfree(dai
->dai_config
);
2595 list_del(&dai
->list
);
2598 case snd_soc_dapm_scheduler
:
2600 /* power down the pipeline schedule core */
2601 pipeline
= swidget
->private;
2602 ret
= snd_sof_dsp_core_power_down(sdev
, 1 << pipeline
->core
);
2604 dev_err(scomp
->dev
, "error: powering down pipeline schedule core %d\n",
2607 /* update enabled cores mask */
2608 sdev
->enabled_cores_mask
&= ~(1 << pipeline
->core
);
2614 for (i
= 0; i
< widget
->num_kcontrols
; i
++) {
2615 kc
= &widget
->kcontrol_news
[i
];
2616 switch (dobj
->widget
.kcontrol_type
) {
2617 case SND_SOC_TPLG_TYPE_MIXER
:
2618 sm
= (struct soc_mixer_control
*)kc
->private_value
;
2619 scontrol
= sm
->dobj
.private;
2621 kfree(scontrol
->volume_table
);
2623 case SND_SOC_TPLG_TYPE_ENUM
:
2624 se
= (struct soc_enum
*)kc
->private_value
;
2625 scontrol
= se
->dobj
.private;
2627 case SND_SOC_TPLG_TYPE_BYTES
:
2628 sbe
= (struct soc_bytes_ext
*)kc
->private_value
;
2629 scontrol
= sbe
->dobj
.private;
2632 dev_warn(scomp
->dev
, "unsupported kcontrol_type\n");
2635 kfree(scontrol
->control_data
);
2636 list_del(&scontrol
->list
);
2641 /* free private value */
2642 kfree(swidget
->private);
2644 /* remove and free swidget object */
2645 list_del(&swidget
->list
);
2652 * DAI HW configuration.
2655 /* FE DAI - used for any driver specific init */
2656 static int sof_dai_load(struct snd_soc_component
*scomp
, int index
,
2657 struct snd_soc_dai_driver
*dai_drv
,
2658 struct snd_soc_tplg_pcm
*pcm
, struct snd_soc_dai
*dai
)
2660 struct snd_sof_dev
*sdev
= snd_soc_component_get_drvdata(scomp
);
2661 struct snd_soc_tplg_stream_caps
*caps
;
2662 struct snd_soc_tplg_private
*private = &pcm
->priv
;
2663 struct snd_sof_pcm
*spcm
;
2667 /* nothing to do for BEs atm */
2671 spcm
= kzalloc(sizeof(*spcm
), GFP_KERNEL
);
2675 spcm
->scomp
= scomp
;
2677 for_each_pcm_streams(stream
) {
2678 spcm
->stream
[stream
].comp_id
= COMP_ID_UNASSIGNED
;
2679 INIT_WORK(&spcm
->stream
[stream
].period_elapsed_work
,
2680 snd_sof_pcm_period_elapsed_work
);
2684 dev_dbg(scomp
->dev
, "tplg: load pcm %s\n", pcm
->dai_name
);
2686 dai_drv
->dobj
.private = spcm
;
2687 list_add(&spcm
->list
, &sdev
->pcm_list
);
2689 ret
= sof_parse_tokens(scomp
, spcm
, stream_tokens
,
2690 ARRAY_SIZE(stream_tokens
), private->array
,
2691 le32_to_cpu(private->size
));
2693 dev_err(scomp
->dev
, "error: parse stream tokens failed %d\n",
2694 le32_to_cpu(private->size
));
2698 /* do we need to allocate playback PCM DMA pages */
2699 if (!spcm
->pcm
.playback
)
2702 stream
= SNDRV_PCM_STREAM_PLAYBACK
;
2704 dev_vdbg(scomp
->dev
, "tplg: pcm %s stream tokens: playback d0i3:%d\n",
2705 spcm
->pcm
.pcm_name
, spcm
->stream
[stream
].d0i3_compatible
);
2707 caps
= &spcm
->pcm
.caps
[stream
];
2709 /* allocate playback page table buffer */
2710 ret
= snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV
, sdev
->dev
,
2711 PAGE_SIZE
, &spcm
->stream
[stream
].page_table
);
2713 dev_err(scomp
->dev
, "error: can't alloc page table for %s %d\n",
2719 /* bind pcm to host comp */
2720 ret
= spcm_bind(scomp
, spcm
, stream
);
2723 "error: can't bind pcm to host\n");
2724 goto free_playback_tables
;
2728 stream
= SNDRV_PCM_STREAM_CAPTURE
;
2730 /* do we need to allocate capture PCM DMA pages */
2731 if (!spcm
->pcm
.capture
)
2734 dev_vdbg(scomp
->dev
, "tplg: pcm %s stream tokens: capture d0i3:%d\n",
2735 spcm
->pcm
.pcm_name
, spcm
->stream
[stream
].d0i3_compatible
);
2737 caps
= &spcm
->pcm
.caps
[stream
];
2739 /* allocate capture page table buffer */
2740 ret
= snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV
, sdev
->dev
,
2741 PAGE_SIZE
, &spcm
->stream
[stream
].page_table
);
2743 dev_err(scomp
->dev
, "error: can't alloc page table for %s %d\n",
2745 goto free_playback_tables
;
2748 /* bind pcm to host comp */
2749 ret
= spcm_bind(scomp
, spcm
, stream
);
2752 "error: can't bind pcm to host\n");
2753 snd_dma_free_pages(&spcm
->stream
[stream
].page_table
);
2754 goto free_playback_tables
;
2759 free_playback_tables
:
2760 if (spcm
->pcm
.playback
)
2761 snd_dma_free_pages(&spcm
->stream
[SNDRV_PCM_STREAM_PLAYBACK
].page_table
);
2766 static int sof_dai_unload(struct snd_soc_component
*scomp
,
2767 struct snd_soc_dobj
*dobj
)
2769 struct snd_sof_pcm
*spcm
= dobj
->private;
2771 /* free PCM DMA pages */
2772 if (spcm
->pcm
.playback
)
2773 snd_dma_free_pages(&spcm
->stream
[SNDRV_PCM_STREAM_PLAYBACK
].page_table
);
2775 if (spcm
->pcm
.capture
)
2776 snd_dma_free_pages(&spcm
->stream
[SNDRV_PCM_STREAM_CAPTURE
].page_table
);
2778 /* remove from list and free spcm */
2779 list_del(&spcm
->list
);
2785 static void sof_dai_set_format(struct snd_soc_tplg_hw_config
*hw_config
,
2786 struct sof_ipc_dai_config
*config
)
2788 /* clock directions wrt codec */
2789 if (hw_config
->bclk_provider
== SND_SOC_TPLG_BCLK_CP
) {
2790 /* codec is bclk provider */
2791 if (hw_config
->fsync_provider
== SND_SOC_TPLG_FSYNC_CP
)
2792 config
->format
|= SOF_DAI_FMT_CBP_CFP
;
2794 config
->format
|= SOF_DAI_FMT_CBP_CFC
;
2796 /* codec is bclk consumer */
2797 if (hw_config
->fsync_provider
== SND_SOC_TPLG_FSYNC_CP
)
2798 config
->format
|= SOF_DAI_FMT_CBC_CFP
;
2800 config
->format
|= SOF_DAI_FMT_CBC_CFC
;
2803 /* inverted clocks ? */
2804 if (hw_config
->invert_bclk
) {
2805 if (hw_config
->invert_fsync
)
2806 config
->format
|= SOF_DAI_FMT_IB_IF
;
2808 config
->format
|= SOF_DAI_FMT_IB_NF
;
2810 if (hw_config
->invert_fsync
)
2811 config
->format
|= SOF_DAI_FMT_NB_IF
;
2813 config
->format
|= SOF_DAI_FMT_NB_NF
;
2818 * Send IPC and set the same config for all DAIs with name matching the link
2819 * name. Note that the function can only be used for the case that all DAIs
2820 * have a common DAI config for now.
2822 static int sof_set_dai_config(struct snd_sof_dev
*sdev
, u32 size
,
2823 struct snd_soc_dai_link
*link
,
2824 struct sof_ipc_dai_config
*config
)
2826 struct snd_sof_dai
*dai
;
2829 list_for_each_entry(dai
, &sdev
->dai_list
, list
) {
2833 if (strcmp(link
->name
, dai
->name
) == 0) {
2834 struct sof_ipc_reply reply
;
2838 * the same dai config will be applied to all DAIs in
2839 * the same dai link. We have to ensure that the ipc
2840 * dai config's dai_index match to the component's
2843 config
->dai_index
= dai
->comp_dai
.dai_index
;
2845 /* send message to DSP */
2846 ret
= sof_ipc_tx_message(sdev
->ipc
,
2847 config
->hdr
.cmd
, config
, size
,
2848 &reply
, sizeof(reply
));
2851 dev_err(sdev
->dev
, "error: failed to set DAI config for %s index %d\n",
2852 dai
->name
, config
->dai_index
);
2855 dai
->dai_config
= kmemdup(config
, size
, GFP_KERNEL
);
2856 if (!dai
->dai_config
)
2859 /* set cpu_dai_name */
2860 dai
->cpu_dai_name
= link
->cpus
->dai_name
;
2867 * machine driver may define a dai link with playback and capture
2868 * dai enabled, but the dai link in topology would support both, one
2869 * or none of them. Here print a warning message to notify user
2872 dev_warn(sdev
->dev
, "warning: failed to find dai for dai link %s",
2879 static int sof_link_ssp_load(struct snd_soc_component
*scomp
, int index
,
2880 struct snd_soc_dai_link
*link
,
2881 struct snd_soc_tplg_link_config
*cfg
,
2882 struct snd_soc_tplg_hw_config
*hw_config
,
2883 struct sof_ipc_dai_config
*config
)
2885 struct snd_sof_dev
*sdev
= snd_soc_component_get_drvdata(scomp
);
2886 struct snd_soc_tplg_private
*private = &cfg
->priv
;
2887 u32 size
= sizeof(*config
);
2890 /* handle master/slave and inverted clocks */
2891 sof_dai_set_format(hw_config
, config
);
2894 memset(&config
->ssp
, 0, sizeof(struct sof_ipc_dai_ssp_params
));
2895 config
->hdr
.size
= size
;
2897 ret
= sof_parse_tokens(scomp
, &config
->ssp
, ssp_tokens
,
2898 ARRAY_SIZE(ssp_tokens
), private->array
,
2899 le32_to_cpu(private->size
));
2901 dev_err(scomp
->dev
, "error: parse ssp tokens failed %d\n",
2902 le32_to_cpu(private->size
));
2906 config
->ssp
.mclk_rate
= le32_to_cpu(hw_config
->mclk_rate
);
2907 config
->ssp
.bclk_rate
= le32_to_cpu(hw_config
->bclk_rate
);
2908 config
->ssp
.fsync_rate
= le32_to_cpu(hw_config
->fsync_rate
);
2909 config
->ssp
.tdm_slots
= le32_to_cpu(hw_config
->tdm_slots
);
2910 config
->ssp
.tdm_slot_width
= le32_to_cpu(hw_config
->tdm_slot_width
);
2911 config
->ssp
.mclk_direction
= hw_config
->mclk_direction
;
2912 config
->ssp
.rx_slots
= le32_to_cpu(hw_config
->rx_slots
);
2913 config
->ssp
.tx_slots
= le32_to_cpu(hw_config
->tx_slots
);
2915 dev_dbg(scomp
->dev
, "tplg: config SSP%d fmt 0x%x mclk %d bclk %d fclk %d width (%d)%d slots %d mclk id %d quirks %d\n",
2916 config
->dai_index
, config
->format
,
2917 config
->ssp
.mclk_rate
, config
->ssp
.bclk_rate
,
2918 config
->ssp
.fsync_rate
, config
->ssp
.sample_valid_bits
,
2919 config
->ssp
.tdm_slot_width
, config
->ssp
.tdm_slots
,
2920 config
->ssp
.mclk_id
, config
->ssp
.quirks
);
2922 /* validate SSP fsync rate and channel count */
2923 if (config
->ssp
.fsync_rate
< 8000 || config
->ssp
.fsync_rate
> 192000) {
2924 dev_err(scomp
->dev
, "error: invalid fsync rate for SSP%d\n",
2929 if (config
->ssp
.tdm_slots
< 1 || config
->ssp
.tdm_slots
> 8) {
2930 dev_err(scomp
->dev
, "error: invalid channel count for SSP%d\n",
2935 /* set config for all DAI's with name matching the link name */
2936 ret
= sof_set_dai_config(sdev
, size
, link
, config
);
2938 dev_err(scomp
->dev
, "error: failed to save DAI config for SSP%d\n",
2944 static int sof_link_sai_load(struct snd_soc_component
*scomp
, int index
,
2945 struct snd_soc_dai_link
*link
,
2946 struct snd_soc_tplg_link_config
*cfg
,
2947 struct snd_soc_tplg_hw_config
*hw_config
,
2948 struct sof_ipc_dai_config
*config
)
2950 struct snd_sof_dev
*sdev
= snd_soc_component_get_drvdata(scomp
);
2951 struct snd_soc_tplg_private
*private = &cfg
->priv
;
2952 u32 size
= sizeof(*config
);
2955 /* handle master/slave and inverted clocks */
2956 sof_dai_set_format(hw_config
, config
);
2959 memset(&config
->sai
, 0, sizeof(struct sof_ipc_dai_sai_params
));
2960 config
->hdr
.size
= size
;
2962 ret
= sof_parse_tokens(scomp
, &config
->sai
, sai_tokens
,
2963 ARRAY_SIZE(sai_tokens
), private->array
,
2964 le32_to_cpu(private->size
));
2966 dev_err(scomp
->dev
, "error: parse sai tokens failed %d\n",
2967 le32_to_cpu(private->size
));
2971 config
->sai
.mclk_rate
= le32_to_cpu(hw_config
->mclk_rate
);
2972 config
->sai
.bclk_rate
= le32_to_cpu(hw_config
->bclk_rate
);
2973 config
->sai
.fsync_rate
= le32_to_cpu(hw_config
->fsync_rate
);
2974 config
->sai
.mclk_direction
= hw_config
->mclk_direction
;
2976 config
->sai
.tdm_slots
= le32_to_cpu(hw_config
->tdm_slots
);
2977 config
->sai
.tdm_slot_width
= le32_to_cpu(hw_config
->tdm_slot_width
);
2978 config
->sai
.rx_slots
= le32_to_cpu(hw_config
->rx_slots
);
2979 config
->sai
.tx_slots
= le32_to_cpu(hw_config
->tx_slots
);
2981 dev_info(scomp
->dev
,
2982 "tplg: config SAI%d fmt 0x%x mclk %d width %d slots %d mclk id %d\n",
2983 config
->dai_index
, config
->format
,
2984 config
->sai
.mclk_rate
, config
->sai
.tdm_slot_width
,
2985 config
->sai
.tdm_slots
, config
->sai
.mclk_id
);
2987 if (config
->sai
.tdm_slots
< 1 || config
->sai
.tdm_slots
> 8) {
2988 dev_err(scomp
->dev
, "error: invalid channel count for SAI%d\n",
2993 /* set config for all DAI's with name matching the link name */
2994 ret
= sof_set_dai_config(sdev
, size
, link
, config
);
2996 dev_err(scomp
->dev
, "error: failed to save DAI config for SAI%d\n",
3002 static int sof_link_esai_load(struct snd_soc_component
*scomp
, int index
,
3003 struct snd_soc_dai_link
*link
,
3004 struct snd_soc_tplg_link_config
*cfg
,
3005 struct snd_soc_tplg_hw_config
*hw_config
,
3006 struct sof_ipc_dai_config
*config
)
3008 struct snd_sof_dev
*sdev
= snd_soc_component_get_drvdata(scomp
);
3009 struct snd_soc_tplg_private
*private = &cfg
->priv
;
3010 u32 size
= sizeof(*config
);
3013 /* handle master/slave and inverted clocks */
3014 sof_dai_set_format(hw_config
, config
);
3017 memset(&config
->esai
, 0, sizeof(struct sof_ipc_dai_esai_params
));
3018 config
->hdr
.size
= size
;
3020 ret
= sof_parse_tokens(scomp
, &config
->esai
, esai_tokens
,
3021 ARRAY_SIZE(esai_tokens
), private->array
,
3022 le32_to_cpu(private->size
));
3024 dev_err(scomp
->dev
, "error: parse esai tokens failed %d\n",
3025 le32_to_cpu(private->size
));
3029 config
->esai
.mclk_rate
= le32_to_cpu(hw_config
->mclk_rate
);
3030 config
->esai
.bclk_rate
= le32_to_cpu(hw_config
->bclk_rate
);
3031 config
->esai
.fsync_rate
= le32_to_cpu(hw_config
->fsync_rate
);
3032 config
->esai
.mclk_direction
= hw_config
->mclk_direction
;
3033 config
->esai
.tdm_slots
= le32_to_cpu(hw_config
->tdm_slots
);
3034 config
->esai
.tdm_slot_width
= le32_to_cpu(hw_config
->tdm_slot_width
);
3035 config
->esai
.rx_slots
= le32_to_cpu(hw_config
->rx_slots
);
3036 config
->esai
.tx_slots
= le32_to_cpu(hw_config
->tx_slots
);
3038 dev_info(scomp
->dev
,
3039 "tplg: config ESAI%d fmt 0x%x mclk %d width %d slots %d mclk id %d\n",
3040 config
->dai_index
, config
->format
,
3041 config
->esai
.mclk_rate
, config
->esai
.tdm_slot_width
,
3042 config
->esai
.tdm_slots
, config
->esai
.mclk_id
);
3044 if (config
->esai
.tdm_slots
< 1 || config
->esai
.tdm_slots
> 8) {
3045 dev_err(scomp
->dev
, "error: invalid channel count for ESAI%d\n",
3050 /* set config for all DAI's with name matching the link name */
3051 ret
= sof_set_dai_config(sdev
, size
, link
, config
);
3053 dev_err(scomp
->dev
, "error: failed to save DAI config for ESAI%d\n",
3059 static int sof_link_dmic_load(struct snd_soc_component
*scomp
, int index
,
3060 struct snd_soc_dai_link
*link
,
3061 struct snd_soc_tplg_link_config
*cfg
,
3062 struct snd_soc_tplg_hw_config
*hw_config
,
3063 struct sof_ipc_dai_config
*config
)
3065 struct snd_sof_dev
*sdev
= snd_soc_component_get_drvdata(scomp
);
3066 struct snd_soc_tplg_private
*private = &cfg
->priv
;
3067 struct sof_ipc_fw_ready
*ready
= &sdev
->fw_ready
;
3068 struct sof_ipc_fw_version
*v
= &ready
->version
;
3069 size_t size
= sizeof(*config
);
3072 /* Ensure the entire DMIC config struct is zeros */
3073 memset(&config
->dmic
, 0, sizeof(struct sof_ipc_dai_dmic_params
));
3075 /* get DMIC tokens */
3076 ret
= sof_parse_tokens(scomp
, &config
->dmic
, dmic_tokens
,
3077 ARRAY_SIZE(dmic_tokens
), private->array
,
3078 le32_to_cpu(private->size
));
3080 dev_err(scomp
->dev
, "error: parse dmic tokens failed %d\n",
3081 le32_to_cpu(private->size
));
3085 /* get DMIC PDM tokens */
3086 ret
= sof_parse_token_sets(scomp
, &config
->dmic
.pdm
[0], dmic_pdm_tokens
,
3087 ARRAY_SIZE(dmic_pdm_tokens
), private->array
,
3088 le32_to_cpu(private->size
),
3089 config
->dmic
.num_pdm_active
,
3090 sizeof(struct sof_ipc_dai_dmic_pdm_ctrl
));
3093 dev_err(scomp
->dev
, "error: parse dmic pdm tokens failed %d\n",
3094 le32_to_cpu(private->size
));
3098 /* set IPC header size */
3099 config
->hdr
.size
= size
;
3101 /* debug messages */
3102 dev_dbg(scomp
->dev
, "tplg: config DMIC%d driver version %d\n",
3103 config
->dai_index
, config
->dmic
.driver_ipc_version
);
3104 dev_dbg(scomp
->dev
, "pdmclk_min %d pdm_clkmax %d duty_min %hd\n",
3105 config
->dmic
.pdmclk_min
, config
->dmic
.pdmclk_max
,
3106 config
->dmic
.duty_min
);
3107 dev_dbg(scomp
->dev
, "duty_max %hd fifo_fs %d num_pdms active %d\n",
3108 config
->dmic
.duty_max
, config
->dmic
.fifo_fs
,
3109 config
->dmic
.num_pdm_active
);
3110 dev_dbg(scomp
->dev
, "fifo word length %hd\n", config
->dmic
.fifo_bits
);
3112 for (j
= 0; j
< config
->dmic
.num_pdm_active
; j
++) {
3113 dev_dbg(scomp
->dev
, "pdm %hd mic a %hd mic b %hd\n",
3114 config
->dmic
.pdm
[j
].id
,
3115 config
->dmic
.pdm
[j
].enable_mic_a
,
3116 config
->dmic
.pdm
[j
].enable_mic_b
);
3117 dev_dbg(scomp
->dev
, "pdm %hd polarity a %hd polarity b %hd\n",
3118 config
->dmic
.pdm
[j
].id
,
3119 config
->dmic
.pdm
[j
].polarity_mic_a
,
3120 config
->dmic
.pdm
[j
].polarity_mic_b
);
3121 dev_dbg(scomp
->dev
, "pdm %hd clk_edge %hd skew %hd\n",
3122 config
->dmic
.pdm
[j
].id
,
3123 config
->dmic
.pdm
[j
].clk_edge
,
3124 config
->dmic
.pdm
[j
].skew
);
3128 * this takes care of backwards compatible handling of fifo_bits_b.
3129 * It is deprecated since firmware ABI version 3.0.1.
3131 if (SOF_ABI_VER(v
->major
, v
->minor
, v
->micro
) < SOF_ABI_VER(3, 0, 1))
3132 config
->dmic
.fifo_bits_b
= config
->dmic
.fifo_bits
;
3134 /* set config for all DAI's with name matching the link name */
3135 ret
= sof_set_dai_config(sdev
, size
, link
, config
);
3137 dev_err(scomp
->dev
, "error: failed to save DAI config for DMIC%d\n",
3143 static int sof_link_hda_load(struct snd_soc_component
*scomp
, int index
,
3144 struct snd_soc_dai_link
*link
,
3145 struct snd_soc_tplg_link_config
*cfg
,
3146 struct snd_soc_tplg_hw_config
*hw_config
,
3147 struct sof_ipc_dai_config
*config
)
3149 struct snd_sof_dev
*sdev
= snd_soc_component_get_drvdata(scomp
);
3150 struct snd_soc_tplg_private
*private = &cfg
->priv
;
3151 struct snd_soc_dai
*dai
;
3152 u32 size
= sizeof(*config
);
3156 memset(&config
->hda
, 0, sizeof(struct sof_ipc_dai_hda_params
));
3157 config
->hdr
.size
= size
;
3159 /* get any bespoke DAI tokens */
3160 ret
= sof_parse_tokens(scomp
, &config
->hda
, hda_tokens
,
3161 ARRAY_SIZE(hda_tokens
), private->array
,
3162 le32_to_cpu(private->size
));
3164 dev_err(scomp
->dev
, "error: parse hda tokens failed %d\n",
3165 le32_to_cpu(private->size
));
3169 dev_dbg(scomp
->dev
, "HDA config rate %d channels %d\n",
3170 config
->hda
.rate
, config
->hda
.channels
);
3172 dai
= snd_soc_find_dai(link
->cpus
);
3174 dev_err(scomp
->dev
, "error: failed to find dai %s in %s",
3175 link
->cpus
->dai_name
, __func__
);
3179 config
->hda
.link_dma_ch
= DMA_CHAN_INVALID
;
3181 ret
= sof_set_dai_config(sdev
, size
, link
, config
);
3183 dev_err(scomp
->dev
, "error: failed to process hda dai link %s",
3189 static int sof_link_alh_load(struct snd_soc_component
*scomp
, int index
,
3190 struct snd_soc_dai_link
*link
,
3191 struct snd_soc_tplg_link_config
*cfg
,
3192 struct snd_soc_tplg_hw_config
*hw_config
,
3193 struct sof_ipc_dai_config
*config
)
3195 struct snd_sof_dev
*sdev
= snd_soc_component_get_drvdata(scomp
);
3196 struct snd_soc_tplg_private
*private = &cfg
->priv
;
3197 u32 size
= sizeof(*config
);
3200 ret
= sof_parse_tokens(scomp
, &config
->alh
, alh_tokens
,
3201 ARRAY_SIZE(alh_tokens
), private->array
,
3202 le32_to_cpu(private->size
));
3204 dev_err(scomp
->dev
, "error: parse alh tokens failed %d\n",
3205 le32_to_cpu(private->size
));
3210 config
->hdr
.size
= size
;
3212 /* set config for all DAI's with name matching the link name */
3213 ret
= sof_set_dai_config(sdev
, size
, link
, config
);
3215 dev_err(scomp
->dev
, "error: failed to save DAI config for ALH %d\n",
3221 /* DAI link - used for any driver specific init */
3222 static int sof_link_load(struct snd_soc_component
*scomp
, int index
,
3223 struct snd_soc_dai_link
*link
,
3224 struct snd_soc_tplg_link_config
*cfg
)
3226 struct snd_soc_tplg_private
*private = &cfg
->priv
;
3227 struct sof_ipc_dai_config config
;
3228 struct snd_soc_tplg_hw_config
*hw_config
;
3233 if (!link
->platforms
) {
3234 dev_err(scomp
->dev
, "error: no platforms\n");
3237 link
->platforms
->name
= dev_name(scomp
->dev
);
3240 * Set nonatomic property for FE dai links as their trigger action
3243 if (!link
->no_pcm
) {
3244 link
->nonatomic
= true;
3247 * set default trigger order for all links. Exceptions to
3248 * the rule will be handled in sof_pcm_dai_link_fixup()
3249 * For playback, the sequence is the following: start FE,
3250 * start BE, stop BE, stop FE; for Capture the sequence is
3251 * inverted start BE, start FE, stop FE, stop BE
3253 link
->trigger
[SNDRV_PCM_STREAM_PLAYBACK
] =
3254 SND_SOC_DPCM_TRIGGER_PRE
;
3255 link
->trigger
[SNDRV_PCM_STREAM_CAPTURE
] =
3256 SND_SOC_DPCM_TRIGGER_POST
;
3258 /* nothing more to do for FE dai links */
3262 /* check we have some tokens - we need at least DAI type */
3263 if (le32_to_cpu(private->size
) == 0) {
3264 dev_err(scomp
->dev
, "error: expected tokens for DAI, none found\n");
3268 /* Send BE DAI link configurations to DSP */
3269 memset(&config
, 0, sizeof(config
));
3271 /* get any common DAI tokens */
3272 ret
= sof_parse_tokens(scomp
, &config
, dai_link_tokens
,
3273 ARRAY_SIZE(dai_link_tokens
), private->array
,
3274 le32_to_cpu(private->size
));
3276 dev_err(scomp
->dev
, "error: parse link tokens failed %d\n",
3277 le32_to_cpu(private->size
));
3282 * DAI links are expected to have at least 1 hw_config.
3283 * But some older topologies might have no hw_config for HDA dai links.
3285 num_hw_configs
= le32_to_cpu(cfg
->num_hw_configs
);
3286 if (!num_hw_configs
) {
3287 if (config
.type
!= SOF_DAI_INTEL_HDA
) {
3288 dev_err(scomp
->dev
, "error: unexpected DAI config count %d!\n",
3289 le32_to_cpu(cfg
->num_hw_configs
));
3293 dev_dbg(scomp
->dev
, "tplg: %d hw_configs found, default id: %d!\n",
3294 cfg
->num_hw_configs
, le32_to_cpu(cfg
->default_hw_config_id
));
3296 for (i
= 0; i
< num_hw_configs
; i
++) {
3297 if (cfg
->hw_config
[i
].id
== cfg
->default_hw_config_id
)
3301 if (i
== num_hw_configs
) {
3302 dev_err(scomp
->dev
, "error: default hw_config id: %d not found!\n",
3303 le32_to_cpu(cfg
->default_hw_config_id
));
3308 /* configure dai IPC message */
3309 hw_config
= &cfg
->hw_config
[i
];
3311 config
.hdr
.cmd
= SOF_IPC_GLB_DAI_MSG
| SOF_IPC_DAI_CONFIG
;
3312 config
.format
= le32_to_cpu(hw_config
->fmt
);
3314 /* now load DAI specific data and send IPC - type comes from token */
3315 switch (config
.type
) {
3316 case SOF_DAI_INTEL_SSP
:
3317 ret
= sof_link_ssp_load(scomp
, index
, link
, cfg
, hw_config
,
3320 case SOF_DAI_INTEL_DMIC
:
3321 ret
= sof_link_dmic_load(scomp
, index
, link
, cfg
, hw_config
,
3324 case SOF_DAI_INTEL_HDA
:
3325 ret
= sof_link_hda_load(scomp
, index
, link
, cfg
, hw_config
,
3328 case SOF_DAI_INTEL_ALH
:
3329 ret
= sof_link_alh_load(scomp
, index
, link
, cfg
, hw_config
,
3332 case SOF_DAI_IMX_SAI
:
3333 ret
= sof_link_sai_load(scomp
, index
, link
, cfg
, hw_config
,
3336 case SOF_DAI_IMX_ESAI
:
3337 ret
= sof_link_esai_load(scomp
, index
, link
, cfg
, hw_config
,
3341 dev_err(scomp
->dev
, "error: invalid DAI type %d\n",
3352 static int sof_link_hda_unload(struct snd_sof_dev
*sdev
,
3353 struct snd_soc_dai_link
*link
)
3355 struct snd_soc_dai
*dai
;
3357 dai
= snd_soc_find_dai(link
->cpus
);
3359 dev_err(sdev
->dev
, "error: failed to find dai %s in %s",
3360 link
->cpus
->dai_name
, __func__
);
3367 static int sof_link_unload(struct snd_soc_component
*scomp
,
3368 struct snd_soc_dobj
*dobj
)
3370 struct snd_sof_dev
*sdev
= snd_soc_component_get_drvdata(scomp
);
3371 struct snd_soc_dai_link
*link
=
3372 container_of(dobj
, struct snd_soc_dai_link
, dobj
);
3374 struct snd_sof_dai
*sof_dai
;
3377 /* only BE link is loaded by sof */
3381 list_for_each_entry(sof_dai
, &sdev
->dai_list
, list
) {
3385 if (strcmp(link
->name
, sof_dai
->name
) == 0)
3389 dev_err(scomp
->dev
, "error: failed to find dai %s in %s",
3390 link
->name
, __func__
);
3394 switch (sof_dai
->dai_config
->type
) {
3395 case SOF_DAI_INTEL_SSP
:
3396 case SOF_DAI_INTEL_DMIC
:
3397 case SOF_DAI_INTEL_ALH
:
3398 case SOF_DAI_IMX_SAI
:
3399 case SOF_DAI_IMX_ESAI
:
3400 /* no resource needs to be released for all cases above */
3402 case SOF_DAI_INTEL_HDA
:
3403 ret
= sof_link_hda_unload(sdev
, link
);
3406 dev_err(scomp
->dev
, "error: invalid DAI type %d\n",
3407 sof_dai
->dai_config
->type
);
3415 /* DAI link - used for any driver specific init */
3416 static int sof_route_load(struct snd_soc_component
*scomp
, int index
,
3417 struct snd_soc_dapm_route
*route
)
3419 struct snd_sof_dev
*sdev
= snd_soc_component_get_drvdata(scomp
);
3420 struct sof_ipc_pipe_comp_connect
*connect
;
3421 struct snd_sof_widget
*source_swidget
, *sink_swidget
;
3422 struct snd_soc_dobj
*dobj
= &route
->dobj
;
3423 struct snd_sof_route
*sroute
;
3424 struct sof_ipc_reply reply
;
3427 /* allocate memory for sroute and connect */
3428 sroute
= kzalloc(sizeof(*sroute
), GFP_KERNEL
);
3432 sroute
->scomp
= scomp
;
3434 connect
= kzalloc(sizeof(*connect
), GFP_KERNEL
);
3440 connect
->hdr
.size
= sizeof(*connect
);
3441 connect
->hdr
.cmd
= SOF_IPC_GLB_TPLG_MSG
| SOF_IPC_TPLG_COMP_CONNECT
;
3443 dev_dbg(scomp
->dev
, "sink %s control %s source %s\n",
3444 route
->sink
, route
->control
? route
->control
: "none",
3447 /* source component */
3448 source_swidget
= snd_sof_find_swidget(scomp
, (char *)route
->source
);
3449 if (!source_swidget
) {
3450 dev_err(scomp
->dev
, "error: source %s not found\n",
3457 * Virtual widgets of type output/out_drv may be added in topology
3458 * for compatibility. These are not handled by the FW.
3459 * So, don't send routes whose source/sink widget is of such types
3462 if (source_swidget
->id
== snd_soc_dapm_out_drv
||
3463 source_swidget
->id
== snd_soc_dapm_output
)
3466 connect
->source_id
= source_swidget
->comp_id
;
3468 /* sink component */
3469 sink_swidget
= snd_sof_find_swidget(scomp
, (char *)route
->sink
);
3470 if (!sink_swidget
) {
3471 dev_err(scomp
->dev
, "error: sink %s not found\n",
3478 * Don't send routes whose sink widget is of type
3479 * output or out_drv to the DSP
3481 if (sink_swidget
->id
== snd_soc_dapm_out_drv
||
3482 sink_swidget
->id
== snd_soc_dapm_output
)
3485 connect
->sink_id
= sink_swidget
->comp_id
;
3488 * For virtual routes, both sink and source are not
3489 * buffer. Since only buffer linked to component is supported by
3490 * FW, others are reported as error, add check in route function,
3491 * do not send it to FW when both source and sink are not buffer
3493 if (source_swidget
->id
!= snd_soc_dapm_buffer
&&
3494 sink_swidget
->id
!= snd_soc_dapm_buffer
) {
3495 dev_dbg(scomp
->dev
, "warning: neither Linked source component %s nor sink component %s is of buffer type, ignoring link\n",
3496 route
->source
, route
->sink
);
3499 ret
= sof_ipc_tx_message(sdev
->ipc
,
3501 connect
, sizeof(*connect
),
3502 &reply
, sizeof(reply
));
3504 /* check IPC return value */
3506 dev_err(scomp
->dev
, "error: failed to add route sink %s control %s source %s\n",
3508 route
->control
? route
->control
: "none",
3513 /* check IPC reply */
3514 if (reply
.error
< 0) {
3515 dev_err(scomp
->dev
, "error: DSP failed to add route sink %s control %s source %s result %d\n",
3517 route
->control
? route
->control
: "none",
3518 route
->source
, reply
.error
);
3523 sroute
->route
= route
;
3524 dobj
->private = sroute
;
3525 sroute
->private = connect
;
3527 /* add route to route list */
3528 list_add(&sroute
->list
, &sdev
->route_list
);
3539 /* Function to set the initial value of SOF kcontrols.
3540 * The value will be stored in scontrol->control_data
3542 static int snd_sof_cache_kcontrol_val(struct snd_soc_component
*scomp
)
3544 struct snd_sof_dev
*sdev
= snd_soc_component_get_drvdata(scomp
);
3545 struct snd_sof_control
*scontrol
= NULL
;
3546 int ipc_cmd
, ctrl_type
;
3549 list_for_each_entry(scontrol
, &sdev
->kcontrol_list
, list
) {
3551 /* notify DSP of kcontrol values */
3552 switch (scontrol
->cmd
) {
3553 case SOF_CTRL_CMD_VOLUME
:
3554 case SOF_CTRL_CMD_ENUM
:
3555 case SOF_CTRL_CMD_SWITCH
:
3556 ipc_cmd
= SOF_IPC_COMP_GET_VALUE
;
3557 ctrl_type
= SOF_CTRL_TYPE_VALUE_CHAN_GET
;
3559 case SOF_CTRL_CMD_BINARY
:
3560 ipc_cmd
= SOF_IPC_COMP_GET_DATA
;
3561 ctrl_type
= SOF_CTRL_TYPE_DATA_GET
;
3565 "error: Invalid scontrol->cmd: %d\n",
3569 ret
= snd_sof_ipc_set_get_comp_data(scontrol
,
3574 dev_warn(scomp
->dev
,
3575 "error: kcontrol value get for widget: %d\n",
3583 int snd_sof_complete_pipeline(struct device
*dev
,
3584 struct snd_sof_widget
*swidget
)
3586 struct snd_sof_dev
*sdev
= dev_get_drvdata(dev
);
3587 struct sof_ipc_pipe_ready ready
;
3588 struct sof_ipc_reply reply
;
3591 dev_dbg(dev
, "tplg: complete pipeline %s id %d\n",
3592 swidget
->widget
->name
, swidget
->comp_id
);
3594 memset(&ready
, 0, sizeof(ready
));
3595 ready
.hdr
.size
= sizeof(ready
);
3596 ready
.hdr
.cmd
= SOF_IPC_GLB_TPLG_MSG
| SOF_IPC_TPLG_PIPE_COMPLETE
;
3597 ready
.comp_id
= swidget
->comp_id
;
3599 ret
= sof_ipc_tx_message(sdev
->ipc
,
3600 ready
.hdr
.cmd
, &ready
, sizeof(ready
), &reply
,
3607 /* completion - called at completion of firmware loading */
3608 static void sof_complete(struct snd_soc_component
*scomp
)
3610 struct snd_sof_dev
*sdev
= snd_soc_component_get_drvdata(scomp
);
3611 struct snd_sof_widget
*swidget
;
3613 /* some widget types require completion notificattion */
3614 list_for_each_entry(swidget
, &sdev
->widget_list
, list
) {
3615 if (swidget
->complete
)
3618 switch (swidget
->id
) {
3619 case snd_soc_dapm_scheduler
:
3621 snd_sof_complete_pipeline(scomp
->dev
, swidget
);
3628 * cache initial values of SOF kcontrols by reading DSP value over
3629 * IPC. It may be overwritten by alsa-mixer after booting up
3631 snd_sof_cache_kcontrol_val(scomp
);
3634 /* manifest - optional to inform component of manifest */
3635 static int sof_manifest(struct snd_soc_component
*scomp
, int index
,
3636 struct snd_soc_tplg_manifest
*man
)
3641 size
= le32_to_cpu(man
->priv
.size
);
3643 /* backward compatible with tplg without ABI info */
3645 dev_dbg(scomp
->dev
, "No topology ABI info\n");
3649 if (size
!= SOF_TPLG_ABI_SIZE
) {
3650 dev_err(scomp
->dev
, "error: invalid topology ABI size\n");
3654 dev_info(scomp
->dev
,
3655 "Topology: ABI %d:%d:%d Kernel ABI %d:%d:%d\n",
3656 man
->priv
.data
[0], man
->priv
.data
[1],
3657 man
->priv
.data
[2], SOF_ABI_MAJOR
, SOF_ABI_MINOR
,
3660 abi_version
= SOF_ABI_VER(man
->priv
.data
[0],
3664 if (SOF_ABI_VERSION_INCOMPATIBLE(SOF_ABI_VERSION
, abi_version
)) {
3665 dev_err(scomp
->dev
, "error: incompatible topology ABI version\n");
3669 if (abi_version
> SOF_ABI_VERSION
) {
3670 if (!IS_ENABLED(CONFIG_SND_SOC_SOF_STRICT_ABI_CHECKS
)) {
3671 dev_warn(scomp
->dev
, "warn: topology ABI is more recent than kernel\n");
3673 dev_err(scomp
->dev
, "error: topology ABI is more recent than kernel\n");
3681 /* vendor specific kcontrol handlers available for binding */
3682 static const struct snd_soc_tplg_kcontrol_ops sof_io_ops
[] = {
3683 {SOF_TPLG_KCTL_VOL_ID
, snd_sof_volume_get
, snd_sof_volume_put
},
3684 {SOF_TPLG_KCTL_BYTES_ID
, snd_sof_bytes_get
, snd_sof_bytes_put
},
3685 {SOF_TPLG_KCTL_ENUM_ID
, snd_sof_enum_get
, snd_sof_enum_put
},
3686 {SOF_TPLG_KCTL_SWITCH_ID
, snd_sof_switch_get
, snd_sof_switch_put
},
3689 /* vendor specific bytes ext handlers available for binding */
3690 static const struct snd_soc_tplg_bytes_ext_ops sof_bytes_ext_ops
[] = {
3691 {SOF_TPLG_KCTL_BYTES_ID
, snd_sof_bytes_ext_get
, snd_sof_bytes_ext_put
},
3692 {SOF_TPLG_KCTL_BYTES_VOLATILE_RO
, snd_sof_bytes_ext_volatile_get
},
3695 static struct snd_soc_tplg_ops sof_tplg_ops
= {
3696 /* external kcontrol init - used for any driver specific init */
3697 .control_load
= sof_control_load
,
3698 .control_unload
= sof_control_unload
,
3700 /* external kcontrol init - used for any driver specific init */
3701 .dapm_route_load
= sof_route_load
,
3702 .dapm_route_unload
= sof_route_unload
,
3704 /* external widget init - used for any driver specific init */
3705 /* .widget_load is not currently used */
3706 .widget_ready
= sof_widget_ready
,
3707 .widget_unload
= sof_widget_unload
,
3709 /* FE DAI - used for any driver specific init */
3710 .dai_load
= sof_dai_load
,
3711 .dai_unload
= sof_dai_unload
,
3713 /* DAI link - used for any driver specific init */
3714 .link_load
= sof_link_load
,
3715 .link_unload
= sof_link_unload
,
3717 /* completion - called at completion of firmware loading */
3718 .complete
= sof_complete
,
3720 /* manifest - optional to inform component of manifest */
3721 .manifest
= sof_manifest
,
3723 /* vendor specific kcontrol handlers available for binding */
3724 .io_ops
= sof_io_ops
,
3725 .io_ops_count
= ARRAY_SIZE(sof_io_ops
),
3727 /* vendor specific bytes ext handlers available for binding */
3728 .bytes_ext_ops
= sof_bytes_ext_ops
,
3729 .bytes_ext_ops_count
= ARRAY_SIZE(sof_bytes_ext_ops
),
3732 int snd_sof_load_topology(struct snd_soc_component
*scomp
, const char *file
)
3734 const struct firmware
*fw
;
3737 dev_dbg(scomp
->dev
, "loading topology:%s\n", file
);
3739 ret
= request_firmware(&fw
, file
, scomp
->dev
);
3741 dev_err(scomp
->dev
, "error: tplg request firmware %s failed err: %d\n",
3746 ret
= snd_soc_tplg_component_load(scomp
, &sof_tplg_ops
, fw
);
3748 dev_err(scomp
->dev
, "error: tplg component load failed %d\n",
3753 release_firmware(fw
);
3756 EXPORT_SYMBOL(snd_sof_load_topology
);