275 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 * mtk-dsp-sof-common.c -- MediaTek dsp sof common ctrl4 *5 * Copyright (c) 2022 MediaTek Inc.6 * Author: Chunxu Li <chunxu.li@mediatek.com>7 */8 9#include "mtk-dsp-sof-common.h"10#include "mtk-soc-card.h"11 12/* fixup the BE DAI link to match any values from topology */13int mtk_sof_dai_link_fixup(struct snd_soc_pcm_runtime *rtd,14 struct snd_pcm_hw_params *params)15{16 struct snd_soc_card *card = rtd->card;17 struct mtk_soc_card_data *soc_card_data = snd_soc_card_get_drvdata(card);18 const struct mtk_sof_priv *sof_priv = soc_card_data->sof_priv;19 int i, j, ret = 0;20 21 for (i = 0; i < sof_priv->num_streams; i++) {22 struct snd_soc_dai *cpu_dai;23 struct snd_soc_pcm_runtime *runtime;24 struct snd_soc_dai_link *sof_dai_link = NULL;25 const struct sof_conn_stream *conn = &sof_priv->conn_streams[i];26 27 if (conn->normal_link && strcmp(rtd->dai_link->name, conn->normal_link))28 continue;29 30 for_each_card_rtds(card, runtime) {31 if (strcmp(runtime->dai_link->name, conn->sof_link))32 continue;33 34 for_each_rtd_cpu_dais(runtime, j, cpu_dai) {35 if (snd_soc_dai_stream_active(cpu_dai, conn->stream_dir) > 0) {36 sof_dai_link = runtime->dai_link;37 break;38 }39 }40 break;41 }42 43 if (sof_dai_link && sof_dai_link->be_hw_params_fixup)44 ret = sof_dai_link->be_hw_params_fixup(runtime, params);45 46 break;47 }48 49 return ret;50}51EXPORT_SYMBOL_GPL(mtk_sof_dai_link_fixup);52 53int mtk_sof_card_probe(struct snd_soc_card *card)54{55 int i;56 struct snd_soc_dai_link *dai_link;57 struct mtk_soc_card_data *soc_card_data = snd_soc_card_get_drvdata(card);58 59 /* Set stream_name to help sof bind widgets */60 for_each_card_prelinks(card, i, dai_link) {61 if (dai_link->no_pcm && !dai_link->stream_name && dai_link->name)62 dai_link->stream_name = dai_link->name;63 }64 65 INIT_LIST_HEAD(&soc_card_data->sof_dai_link_list);66 67 return 0;68}69EXPORT_SYMBOL_GPL(mtk_sof_card_probe);70 71static struct snd_soc_pcm_runtime *mtk_sof_find_tplg_be(struct snd_soc_pcm_runtime *rtd)72{73 struct snd_soc_card *card = rtd->card;74 struct mtk_soc_card_data *soc_card_data = snd_soc_card_get_drvdata(card);75 const struct mtk_sof_priv *sof_priv = soc_card_data->sof_priv;76 struct snd_soc_pcm_runtime *fe;77 struct snd_soc_pcm_runtime *be;78 struct snd_soc_dpcm *dpcm;79 int i, stream;80 81 for_each_pcm_streams(stream) {82 fe = NULL;83 for_each_dpcm_fe(rtd, stream, dpcm) {84 fe = dpcm->fe;85 if (fe)86 break;87 }88 89 if (!fe)90 continue;91 92 for_each_dpcm_be(fe, stream, dpcm) {93 be = dpcm->be;94 if (be == rtd)95 continue;96 97 for (i = 0; i < sof_priv->num_streams; i++) {98 const struct sof_conn_stream *conn = &sof_priv->conn_streams[i];99 100 if (!strcmp(be->dai_link->name, conn->sof_link))101 return be;102 }103 }104 }105 106 return NULL;107}108 109/* fixup the BE DAI link to match any values from topology */110static int mtk_sof_check_tplg_be_dai_link_fixup(struct snd_soc_pcm_runtime *rtd,111 struct snd_pcm_hw_params *params)112{113 struct snd_soc_card *card = rtd->card;114 struct mtk_soc_card_data *soc_card_data = snd_soc_card_get_drvdata(card);115 const struct mtk_sof_priv *sof_priv = soc_card_data->sof_priv;116 struct snd_soc_pcm_runtime *sof_be;117 struct mtk_dai_link *dai_link;118 int ret = 0;119 120 sof_be = mtk_sof_find_tplg_be(rtd);121 if (sof_be) {122 if (sof_priv->sof_dai_link_fixup)123 ret = sof_priv->sof_dai_link_fixup(rtd, params);124 else if (sof_be->dai_link->be_hw_params_fixup)125 ret = sof_be->dai_link->be_hw_params_fixup(sof_be, params);126 } else {127 list_for_each_entry(dai_link, &soc_card_data->sof_dai_link_list, list) {128 if (strcmp(dai_link->name, rtd->dai_link->name) == 0) {129 if (dai_link->be_hw_params_fixup)130 ret = dai_link->be_hw_params_fixup(rtd, params);131 132 break;133 }134 }135 }136 137 return ret;138}139 140int mtk_sof_card_late_probe(struct snd_soc_card *card)141{142 struct snd_soc_pcm_runtime *rtd;143 struct snd_soc_component *sof_comp = NULL;144 struct mtk_soc_card_data *soc_card_data =145 snd_soc_card_get_drvdata(card);146 const struct mtk_sof_priv *sof_priv = soc_card_data->sof_priv;147 struct snd_soc_dai_link *dai_link;148 struct mtk_dai_link *mtk_dai_link;149 int i;150 151 /* 1. find sof component */152 for_each_card_rtds(card, rtd) {153 sof_comp = snd_soc_rtdcom_lookup(rtd, "sof-audio-component");154 if (sof_comp)155 break;156 }157 158 if (!sof_comp) {159 dev_info(card->dev, "probe without sof-audio-component\n");160 return 0;161 }162 163 /* 2. overwrite all BE fixups, and backup the existing fixup */164 for_each_card_prelinks(card, i, dai_link) {165 if (dai_link->be_hw_params_fixup) {166 mtk_dai_link = devm_kzalloc(card->dev,167 sizeof(*mtk_dai_link),168 GFP_KERNEL);169 if (!mtk_dai_link)170 return -ENOMEM;171 172 mtk_dai_link->be_hw_params_fixup = dai_link->be_hw_params_fixup;173 mtk_dai_link->name = dai_link->name;174 175 list_add(&mtk_dai_link->list, &soc_card_data->sof_dai_link_list);176 }177 178 if (dai_link->no_pcm)179 dai_link->be_hw_params_fixup = mtk_sof_check_tplg_be_dai_link_fixup;180 }181 182 /* 3. add route path and SOF_BE fixup callback */183 for (i = 0; i < sof_priv->num_streams; i++) {184 const struct sof_conn_stream *conn = &sof_priv->conn_streams[i];185 struct snd_soc_pcm_runtime *sof_rtd = NULL;186 187 for_each_card_rtds(card, rtd) {188 if (!strcmp(rtd->dai_link->name, conn->sof_link)) {189 sof_rtd = rtd;190 break;191 }192 }193 if (sof_rtd) {194 int j;195 struct snd_soc_dai *cpu_dai;196 197 for_each_rtd_cpu_dais(sof_rtd, j, cpu_dai) {198 struct snd_soc_dapm_route route;199 struct snd_soc_dapm_path *p = NULL;200 struct snd_soc_dapm_widget *widget = snd_soc_dai_get_widget(cpu_dai, conn->stream_dir);201 202 memset(&route, 0, sizeof(route));203 if (conn->stream_dir == SNDRV_PCM_STREAM_CAPTURE && widget) {204 snd_soc_dapm_widget_for_each_sink_path(widget, p) {205 route.source = conn->sof_dma;206 route.sink = p->sink->name;207 snd_soc_dapm_add_routes(&card->dapm, &route, 1);208 }209 } else if (conn->stream_dir == SNDRV_PCM_STREAM_PLAYBACK && widget) {210 snd_soc_dapm_widget_for_each_source_path(widget, p) {211 route.source = p->source->name;212 route.sink = conn->sof_dma;213 snd_soc_dapm_add_routes(&card->dapm, &route, 1);214 }215 } else {216 dev_err(cpu_dai->dev, "stream dir and widget not pair\n");217 }218 }219 220 /* overwrite SOF BE fixup */221 sof_rtd->dai_link->be_hw_params_fixup =222 sof_comp->driver->be_hw_params_fixup;223 }224 }225 226 return 0;227}228EXPORT_SYMBOL_GPL(mtk_sof_card_late_probe);229 230int mtk_sof_dailink_parse_of(struct snd_soc_card *card, struct device_node *np,231 const char *propname, struct snd_soc_dai_link *pre_dai_links,232 int pre_num_links)233{234 struct device *dev = card->dev;235 struct snd_soc_dai_link *parsed_dai_link;236 const char *dai_name = NULL;237 int i, j, ret, num_links, parsed_num_links = 0;238 239 num_links = of_property_count_strings(np, "mediatek,dai-link");240 if (num_links < 0 || num_links > card->num_links) {241 dev_dbg(dev, "number of dai-link is invalid\n");242 return -EINVAL;243 }244 245 parsed_dai_link = devm_kcalloc(dev, num_links, sizeof(*parsed_dai_link), GFP_KERNEL);246 if (!parsed_dai_link)247 return -ENOMEM;248 249 for (i = 0; i < num_links; i++) {250 ret = of_property_read_string_index(np, propname, i, &dai_name);251 if (ret) {252 dev_dbg(dev, "ASoC: Property '%s' index %d could not be read: %d\n",253 propname, i, ret);254 return ret;255 }256 dev_dbg(dev, "ASoC: Property get dai_name:%s\n", dai_name);257 for (j = 0; j < pre_num_links; j++) {258 if (!strcmp(dai_name, pre_dai_links[j].name)) {259 memcpy(&parsed_dai_link[parsed_num_links++], &pre_dai_links[j],260 sizeof(struct snd_soc_dai_link));261 break;262 }263 }264 }265 266 if (parsed_num_links != num_links)267 return -EINVAL;268 269 card->dai_link = parsed_dai_link;270 card->num_links = parsed_num_links;271 272 return 0;273}274EXPORT_SYMBOL_GPL(mtk_sof_dailink_parse_of);275