xref: /linux/sound/soc/sof/ipc3-topology.c (revision 7006d20e5e9d25c079a82e2bc0ea7e292fdea6e6)
1 // SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause)
2 //
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.
5 //
6 // Copyright(c) 2021 Intel Corporation. All rights reserved.
7 //
8 //
9 
10 #include <uapi/sound/sof/tokens.h>
11 #include <sound/pcm_params.h>
12 #include "sof-priv.h"
13 #include "sof-audio.h"
14 #include "ops.h"
15 
16 /* PCM */
17 static const struct sof_topology_token pcm_tokens[] = {
18 	{SOF_TKN_PCM_DMAC_CONFIG, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
19 		offsetof(struct sof_ipc_comp_host, dmac_config)},
20 };
21 
22 /* Generic components */
23 static const struct sof_topology_token comp_tokens[] = {
24 	{SOF_TKN_COMP_PERIOD_SINK_COUNT, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
25 		offsetof(struct sof_ipc_comp_config, periods_sink)},
26 	{SOF_TKN_COMP_PERIOD_SOURCE_COUNT, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
27 		offsetof(struct sof_ipc_comp_config, periods_source)},
28 	{SOF_TKN_COMP_FORMAT,
29 		SND_SOC_TPLG_TUPLE_TYPE_STRING, get_token_comp_format,
30 		offsetof(struct sof_ipc_comp_config, frame_fmt)},
31 };
32 
33 /* Core tokens */
34 static const struct sof_topology_token core_tokens[] = {
35 	{SOF_TKN_COMP_CORE_ID, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
36 		offsetof(struct sof_ipc_comp, core)},
37 };
38 
39 /* Component extended tokens */
40 static const struct sof_topology_token comp_ext_tokens[] = {
41 	{SOF_TKN_COMP_UUID, SND_SOC_TPLG_TUPLE_TYPE_UUID, get_token_uuid,
42 		offsetof(struct snd_sof_widget, uuid)},
43 };
44 
45 static const struct sof_token_info ipc3_token_list[SOF_TOKEN_COUNT] = {
46 	[SOF_PCM_TOKENS] = {"PCM tokens", pcm_tokens, ARRAY_SIZE(pcm_tokens)},
47 	[SOF_COMP_TOKENS] = {"Comp tokens", comp_tokens, ARRAY_SIZE(comp_tokens)},
48 	[SOF_CORE_TOKENS] = {"Core tokens", core_tokens, ARRAY_SIZE(core_tokens)},
49 	[SOF_COMP_EXT_TOKENS] = {"AFE tokens", comp_ext_tokens, ARRAY_SIZE(comp_ext_tokens)},
50 };
51 
52 /**
53  * sof_comp_alloc - allocate and initialize buffer for a new component
54  * @swidget: pointer to struct snd_sof_widget containing extended data
55  * @ipc_size: IPC payload size that will be updated depending on valid
56  *  extended data.
57  * @index: ID of the pipeline the component belongs to
58  *
59  * Return: The pointer to the new allocated component, NULL if failed.
60  */
61 static void *sof_comp_alloc(struct snd_sof_widget *swidget, size_t *ipc_size,
62 			    int index)
63 {
64 	struct sof_ipc_comp *comp;
65 	size_t total_size = *ipc_size;
66 	size_t ext_size = sizeof(swidget->uuid);
67 
68 	/* only non-zero UUID is valid */
69 	if (!guid_is_null(&swidget->uuid))
70 		total_size += ext_size;
71 
72 	comp = kzalloc(total_size, GFP_KERNEL);
73 	if (!comp)
74 		return NULL;
75 
76 	/* configure comp new IPC message */
77 	comp->hdr.size = total_size;
78 	comp->hdr.cmd = SOF_IPC_GLB_TPLG_MSG | SOF_IPC_TPLG_COMP_NEW;
79 	comp->id = swidget->comp_id;
80 	comp->pipeline_id = index;
81 	comp->core = swidget->core;
82 
83 	/* handle the extended data if needed */
84 	if (total_size > *ipc_size) {
85 		/* append extended data to the end of the component */
86 		memcpy((u8 *)comp + *ipc_size, &swidget->uuid, ext_size);
87 		comp->ext_data_length = ext_size;
88 	}
89 
90 	/* update ipc_size and return */
91 	*ipc_size = total_size;
92 	return comp;
93 }
94 
95 static void sof_dbg_comp_config(struct snd_soc_component *scomp, struct sof_ipc_comp_config *config)
96 {
97 	dev_dbg(scomp->dev, " config: periods snk %d src %d fmt %d\n",
98 		config->periods_sink, config->periods_source,
99 		config->frame_fmt);
100 }
101 
102 static int sof_ipc3_widget_setup_comp_host(struct snd_sof_widget *swidget)
103 {
104 	struct snd_soc_component *scomp = swidget->scomp;
105 	struct sof_ipc_comp_host *host;
106 	size_t ipc_size = sizeof(*host);
107 	int ret;
108 
109 	host = sof_comp_alloc(swidget, &ipc_size, swidget->pipeline_id);
110 	if (!host)
111 		return -ENOMEM;
112 	swidget->private = host;
113 
114 	/* configure host comp IPC message */
115 	host->comp.type = SOF_COMP_HOST;
116 	host->config.hdr.size = sizeof(host->config);
117 
118 	if (swidget->id == snd_soc_dapm_aif_out)
119 		host->direction = SOF_IPC_STREAM_CAPTURE;
120 	else
121 		host->direction = SOF_IPC_STREAM_PLAYBACK;
122 
123 	/* parse one set of pcm_tokens */
124 	ret = sof_update_ipc_object(scomp, host, SOF_PCM_TOKENS, swidget->tuples,
125 				    swidget->num_tuples, sizeof(*host), 1);
126 	if (ret < 0)
127 		goto err;
128 
129 	/* parse one set of comp_tokens */
130 	ret = sof_update_ipc_object(scomp, &host->config, SOF_COMP_TOKENS, swidget->tuples,
131 				    swidget->num_tuples, sizeof(host->config), 1);
132 	if (ret < 0)
133 		goto err;
134 
135 	dev_dbg(scomp->dev, "loaded host %s\n", swidget->widget->name);
136 	sof_dbg_comp_config(scomp, &host->config);
137 
138 	return 0;
139 err:
140 	kfree(swidget->private);
141 	swidget->private = NULL;
142 
143 	return ret;
144 }
145 
146 static void sof_ipc3_widget_free_comp(struct snd_sof_widget *swidget)
147 {
148 	kfree(swidget->private);
149 }
150 
151 /* token list for each topology object */
152 static enum sof_tokens host_token_list[] = {
153 	SOF_CORE_TOKENS,
154 	SOF_COMP_EXT_TOKENS,
155 	SOF_PCM_TOKENS,
156 	SOF_COMP_TOKENS,
157 };
158 
159 static const struct sof_ipc_tplg_widget_ops tplg_ipc3_widget_ops[SND_SOC_DAPM_TYPE_COUNT] = {
160 	[snd_soc_dapm_aif_in] =  {sof_ipc3_widget_setup_comp_host, sof_ipc3_widget_free_comp,
161 				  host_token_list, ARRAY_SIZE(host_token_list), NULL},
162 	[snd_soc_dapm_aif_out] = {sof_ipc3_widget_setup_comp_host, sof_ipc3_widget_free_comp,
163 				  host_token_list, ARRAY_SIZE(host_token_list), NULL},
164 };
165 
166 static const struct sof_ipc_tplg_ops ipc3_tplg_ops = {
167 	.widget = tplg_ipc3_widget_ops,
168 	.token_list = ipc3_token_list,
169 };
170 
171 const struct sof_ipc_ops ipc3_ops = {
172 	.tplg = &ipc3_tplg_ops,
173 };
174