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