10caf1120SChunxu Li // SPDX-License-Identifier: GPL-2.0
20caf1120SChunxu Li /*
30caf1120SChunxu Li * mtk-dsp-sof-common.c -- MediaTek dsp sof common ctrl
40caf1120SChunxu Li *
50caf1120SChunxu Li * Copyright (c) 2022 MediaTek Inc.
60caf1120SChunxu Li * Author: Chunxu Li <chunxu.li@mediatek.com>
70caf1120SChunxu Li */
80caf1120SChunxu Li
90caf1120SChunxu Li #include "mtk-dsp-sof-common.h"
100caf1120SChunxu Li #include "mtk-soc-card.h"
110caf1120SChunxu Li
120caf1120SChunxu Li /* fixup the BE DAI link to match any values from topology */
mtk_sof_dai_link_fixup(struct snd_soc_pcm_runtime * rtd,struct snd_pcm_hw_params * params)130caf1120SChunxu Li int mtk_sof_dai_link_fixup(struct snd_soc_pcm_runtime *rtd,
140caf1120SChunxu Li struct snd_pcm_hw_params *params)
150caf1120SChunxu Li {
160caf1120SChunxu Li struct snd_soc_card *card = rtd->card;
170caf1120SChunxu Li struct mtk_soc_card_data *soc_card_data = snd_soc_card_get_drvdata(card);
18*f8782f77SAngeloGioacchino Del Regno const struct mtk_sof_priv *sof_priv = soc_card_data->sof_priv;
190caf1120SChunxu Li int i, j, ret = 0;
200caf1120SChunxu Li
210caf1120SChunxu Li for (i = 0; i < sof_priv->num_streams; i++) {
220caf1120SChunxu Li struct snd_soc_dai *cpu_dai;
230caf1120SChunxu Li struct snd_soc_pcm_runtime *runtime;
240caf1120SChunxu Li struct snd_soc_dai_link *sof_dai_link = NULL;
250caf1120SChunxu Li const struct sof_conn_stream *conn = &sof_priv->conn_streams[i];
260caf1120SChunxu Li
27e3b3ec96SAngeloGioacchino Del Regno if (conn->normal_link && strcmp(rtd->dai_link->name, conn->normal_link))
280caf1120SChunxu Li continue;
290caf1120SChunxu Li
300caf1120SChunxu Li for_each_card_rtds(card, runtime) {
310caf1120SChunxu Li if (strcmp(runtime->dai_link->name, conn->sof_link))
320caf1120SChunxu Li continue;
330caf1120SChunxu Li
340caf1120SChunxu Li for_each_rtd_cpu_dais(runtime, j, cpu_dai) {
350df2ec8eSKuninori Morimoto if (snd_soc_dai_stream_active(cpu_dai, conn->stream_dir) > 0) {
360caf1120SChunxu Li sof_dai_link = runtime->dai_link;
370caf1120SChunxu Li break;
380caf1120SChunxu Li }
390caf1120SChunxu Li }
400caf1120SChunxu Li break;
410caf1120SChunxu Li }
420caf1120SChunxu Li
430caf1120SChunxu Li if (sof_dai_link && sof_dai_link->be_hw_params_fixup)
440caf1120SChunxu Li ret = sof_dai_link->be_hw_params_fixup(runtime, params);
450caf1120SChunxu Li
460caf1120SChunxu Li break;
470caf1120SChunxu Li }
480caf1120SChunxu Li
490caf1120SChunxu Li return ret;
500caf1120SChunxu Li }
510caf1120SChunxu Li EXPORT_SYMBOL_GPL(mtk_sof_dai_link_fixup);
520caf1120SChunxu Li
mtk_sof_card_probe(struct snd_soc_card * card)530caf1120SChunxu Li int mtk_sof_card_probe(struct snd_soc_card *card)
540caf1120SChunxu Li {
550caf1120SChunxu Li int i;
560caf1120SChunxu Li struct snd_soc_dai_link *dai_link;
574047b35cSTrevor Wu struct mtk_soc_card_data *soc_card_data = snd_soc_card_get_drvdata(card);
580caf1120SChunxu Li
590caf1120SChunxu Li /* Set stream_name to help sof bind widgets */
600caf1120SChunxu Li for_each_card_prelinks(card, i, dai_link) {
610caf1120SChunxu Li if (dai_link->no_pcm && !dai_link->stream_name && dai_link->name)
620caf1120SChunxu Li dai_link->stream_name = dai_link->name;
630caf1120SChunxu Li }
640caf1120SChunxu Li
65*f8782f77SAngeloGioacchino Del Regno INIT_LIST_HEAD(&soc_card_data->sof_dai_link_list);
664047b35cSTrevor Wu
670caf1120SChunxu Li return 0;
680caf1120SChunxu Li }
690caf1120SChunxu Li EXPORT_SYMBOL_GPL(mtk_sof_card_probe);
700caf1120SChunxu Li
mtk_sof_find_tplg_be(struct snd_soc_pcm_runtime * rtd)714047b35cSTrevor Wu static struct snd_soc_pcm_runtime *mtk_sof_find_tplg_be(struct snd_soc_pcm_runtime *rtd)
724047b35cSTrevor Wu {
734047b35cSTrevor Wu struct snd_soc_card *card = rtd->card;
744047b35cSTrevor Wu struct mtk_soc_card_data *soc_card_data = snd_soc_card_get_drvdata(card);
75*f8782f77SAngeloGioacchino Del Regno const struct mtk_sof_priv *sof_priv = soc_card_data->sof_priv;
764047b35cSTrevor Wu struct snd_soc_pcm_runtime *fe;
774047b35cSTrevor Wu struct snd_soc_pcm_runtime *be;
784047b35cSTrevor Wu struct snd_soc_dpcm *dpcm;
794047b35cSTrevor Wu int i, stream;
804047b35cSTrevor Wu
814047b35cSTrevor Wu for_each_pcm_streams(stream) {
824047b35cSTrevor Wu fe = NULL;
834047b35cSTrevor Wu for_each_dpcm_fe(rtd, stream, dpcm) {
844047b35cSTrevor Wu fe = dpcm->fe;
854047b35cSTrevor Wu if (fe)
864047b35cSTrevor Wu break;
874047b35cSTrevor Wu }
884047b35cSTrevor Wu
894047b35cSTrevor Wu if (!fe)
904047b35cSTrevor Wu continue;
914047b35cSTrevor Wu
924047b35cSTrevor Wu for_each_dpcm_be(fe, stream, dpcm) {
934047b35cSTrevor Wu be = dpcm->be;
944047b35cSTrevor Wu if (be == rtd)
954047b35cSTrevor Wu continue;
964047b35cSTrevor Wu
974047b35cSTrevor Wu for (i = 0; i < sof_priv->num_streams; i++) {
984047b35cSTrevor Wu const struct sof_conn_stream *conn = &sof_priv->conn_streams[i];
994047b35cSTrevor Wu
1004047b35cSTrevor Wu if (!strcmp(be->dai_link->name, conn->sof_link))
1014047b35cSTrevor Wu return be;
1024047b35cSTrevor Wu }
1034047b35cSTrevor Wu }
1044047b35cSTrevor Wu }
1054047b35cSTrevor Wu
1064047b35cSTrevor Wu return NULL;
1074047b35cSTrevor Wu }
1084047b35cSTrevor Wu
1094047b35cSTrevor Wu /* fixup the BE DAI link to match any values from topology */
mtk_sof_check_tplg_be_dai_link_fixup(struct snd_soc_pcm_runtime * rtd,struct snd_pcm_hw_params * params)1104047b35cSTrevor Wu static int mtk_sof_check_tplg_be_dai_link_fixup(struct snd_soc_pcm_runtime *rtd,
1114047b35cSTrevor Wu struct snd_pcm_hw_params *params)
1124047b35cSTrevor Wu {
1134047b35cSTrevor Wu struct snd_soc_card *card = rtd->card;
1144047b35cSTrevor Wu struct mtk_soc_card_data *soc_card_data = snd_soc_card_get_drvdata(card);
115*f8782f77SAngeloGioacchino Del Regno const struct mtk_sof_priv *sof_priv = soc_card_data->sof_priv;
1164047b35cSTrevor Wu struct snd_soc_pcm_runtime *sof_be;
1174047b35cSTrevor Wu struct mtk_dai_link *dai_link;
1184047b35cSTrevor Wu int ret = 0;
1194047b35cSTrevor Wu
1204047b35cSTrevor Wu sof_be = mtk_sof_find_tplg_be(rtd);
1214047b35cSTrevor Wu if (sof_be) {
1224047b35cSTrevor Wu if (sof_priv->sof_dai_link_fixup)
1234047b35cSTrevor Wu ret = sof_priv->sof_dai_link_fixup(rtd, params);
1244047b35cSTrevor Wu else if (sof_be->dai_link->be_hw_params_fixup)
1254047b35cSTrevor Wu ret = sof_be->dai_link->be_hw_params_fixup(sof_be, params);
1264047b35cSTrevor Wu } else {
127*f8782f77SAngeloGioacchino Del Regno list_for_each_entry(dai_link, &soc_card_data->sof_dai_link_list, list) {
1284047b35cSTrevor Wu if (strcmp(dai_link->name, rtd->dai_link->name) == 0) {
1294047b35cSTrevor Wu if (dai_link->be_hw_params_fixup)
1304047b35cSTrevor Wu ret = dai_link->be_hw_params_fixup(rtd, params);
1314047b35cSTrevor Wu
1324047b35cSTrevor Wu break;
1334047b35cSTrevor Wu }
1344047b35cSTrevor Wu }
1354047b35cSTrevor Wu }
1364047b35cSTrevor Wu
1374047b35cSTrevor Wu return ret;
1384047b35cSTrevor Wu }
1394047b35cSTrevor Wu
mtk_sof_card_late_probe(struct snd_soc_card * card)1400caf1120SChunxu Li int mtk_sof_card_late_probe(struct snd_soc_card *card)
1410caf1120SChunxu Li {
1420caf1120SChunxu Li struct snd_soc_pcm_runtime *rtd;
1430caf1120SChunxu Li struct snd_soc_component *sof_comp = NULL;
1440caf1120SChunxu Li struct mtk_soc_card_data *soc_card_data =
1450caf1120SChunxu Li snd_soc_card_get_drvdata(card);
146*f8782f77SAngeloGioacchino Del Regno const struct mtk_sof_priv *sof_priv = soc_card_data->sof_priv;
1474047b35cSTrevor Wu struct snd_soc_dai_link *dai_link;
1484047b35cSTrevor Wu struct mtk_dai_link *mtk_dai_link;
1490caf1120SChunxu Li int i;
1500caf1120SChunxu Li
1510caf1120SChunxu Li /* 1. find sof component */
1520caf1120SChunxu Li for_each_card_rtds(card, rtd) {
1530caf1120SChunxu Li sof_comp = snd_soc_rtdcom_lookup(rtd, "sof-audio-component");
1540caf1120SChunxu Li if (sof_comp)
1550caf1120SChunxu Li break;
1560caf1120SChunxu Li }
1570caf1120SChunxu Li
1580caf1120SChunxu Li if (!sof_comp) {
1590caf1120SChunxu Li dev_info(card->dev, "probe without sof-audio-component\n");
1600caf1120SChunxu Li return 0;
1610caf1120SChunxu Li }
1620caf1120SChunxu Li
1634047b35cSTrevor Wu /* 2. overwrite all BE fixups, and backup the existing fixup */
1644047b35cSTrevor Wu for_each_card_prelinks(card, i, dai_link) {
1654047b35cSTrevor Wu if (dai_link->be_hw_params_fixup) {
1664047b35cSTrevor Wu mtk_dai_link = devm_kzalloc(card->dev,
1674047b35cSTrevor Wu sizeof(*mtk_dai_link),
1684047b35cSTrevor Wu GFP_KERNEL);
1694047b35cSTrevor Wu if (!mtk_dai_link)
1704047b35cSTrevor Wu return -ENOMEM;
1714047b35cSTrevor Wu
1724047b35cSTrevor Wu mtk_dai_link->be_hw_params_fixup = dai_link->be_hw_params_fixup;
1734047b35cSTrevor Wu mtk_dai_link->name = dai_link->name;
1744047b35cSTrevor Wu
175*f8782f77SAngeloGioacchino Del Regno list_add(&mtk_dai_link->list, &soc_card_data->sof_dai_link_list);
1764047b35cSTrevor Wu }
1774047b35cSTrevor Wu
1784047b35cSTrevor Wu if (dai_link->no_pcm)
1794047b35cSTrevor Wu dai_link->be_hw_params_fixup = mtk_sof_check_tplg_be_dai_link_fixup;
1804047b35cSTrevor Wu }
1814047b35cSTrevor Wu
1824047b35cSTrevor Wu /* 3. add route path and SOF_BE fixup callback */
1830caf1120SChunxu Li for (i = 0; i < sof_priv->num_streams; i++) {
1840caf1120SChunxu Li const struct sof_conn_stream *conn = &sof_priv->conn_streams[i];
1850caf1120SChunxu Li struct snd_soc_pcm_runtime *sof_rtd = NULL;
1860caf1120SChunxu Li
1870caf1120SChunxu Li for_each_card_rtds(card, rtd) {
1880caf1120SChunxu Li if (!strcmp(rtd->dai_link->name, conn->sof_link)) {
1890caf1120SChunxu Li sof_rtd = rtd;
1900caf1120SChunxu Li break;
1910caf1120SChunxu Li }
1924047b35cSTrevor Wu }
1934047b35cSTrevor Wu if (sof_rtd) {
1940caf1120SChunxu Li int j;
1950caf1120SChunxu Li struct snd_soc_dai *cpu_dai;
1960caf1120SChunxu Li
1970caf1120SChunxu Li for_each_rtd_cpu_dais(sof_rtd, j, cpu_dai) {
1980caf1120SChunxu Li struct snd_soc_dapm_route route;
1990caf1120SChunxu Li struct snd_soc_dapm_path *p = NULL;
2000df2ec8eSKuninori Morimoto struct snd_soc_dapm_widget *widget = snd_soc_dai_get_widget(cpu_dai, conn->stream_dir);
2010df2ec8eSKuninori Morimoto
2020caf1120SChunxu Li memset(&route, 0, sizeof(route));
2030df2ec8eSKuninori Morimoto if (conn->stream_dir == SNDRV_PCM_STREAM_CAPTURE && widget) {
2040df2ec8eSKuninori Morimoto snd_soc_dapm_widget_for_each_sink_path(widget, p) {
2050caf1120SChunxu Li route.source = conn->sof_dma;
2060caf1120SChunxu Li route.sink = p->sink->name;
2070caf1120SChunxu Li snd_soc_dapm_add_routes(&card->dapm, &route, 1);
2080caf1120SChunxu Li }
2090df2ec8eSKuninori Morimoto } else if (conn->stream_dir == SNDRV_PCM_STREAM_PLAYBACK && widget) {
2100df2ec8eSKuninori Morimoto snd_soc_dapm_widget_for_each_source_path(widget, p) {
2110caf1120SChunxu Li route.source = p->source->name;
2120caf1120SChunxu Li route.sink = conn->sof_dma;
2130caf1120SChunxu Li snd_soc_dapm_add_routes(&card->dapm, &route, 1);
2140caf1120SChunxu Li }
2150caf1120SChunxu Li } else {
2160caf1120SChunxu Li dev_err(cpu_dai->dev, "stream dir and widget not pair\n");
2170caf1120SChunxu Li }
2180caf1120SChunxu Li }
2190caf1120SChunxu Li
2204047b35cSTrevor Wu /* overwrite SOF BE fixup */
2210caf1120SChunxu Li sof_rtd->dai_link->be_hw_params_fixup =
2220caf1120SChunxu Li sof_comp->driver->be_hw_params_fixup;
2230caf1120SChunxu Li }
2240caf1120SChunxu Li }
2250caf1120SChunxu Li
2260caf1120SChunxu Li return 0;
2270caf1120SChunxu Li }
2280caf1120SChunxu Li EXPORT_SYMBOL_GPL(mtk_sof_card_late_probe);
2290caf1120SChunxu Li
mtk_sof_dailink_parse_of(struct snd_soc_card * card,struct device_node * np,const char * propname,struct snd_soc_dai_link * pre_dai_links,int pre_num_links)2300caf1120SChunxu Li int mtk_sof_dailink_parse_of(struct snd_soc_card *card, struct device_node *np,
2310caf1120SChunxu Li const char *propname, struct snd_soc_dai_link *pre_dai_links,
2320caf1120SChunxu Li int pre_num_links)
2330caf1120SChunxu Li {
2340caf1120SChunxu Li struct device *dev = card->dev;
2350caf1120SChunxu Li struct snd_soc_dai_link *parsed_dai_link;
2360caf1120SChunxu Li const char *dai_name = NULL;
2370caf1120SChunxu Li int i, j, ret, num_links, parsed_num_links = 0;
2380caf1120SChunxu Li
2390caf1120SChunxu Li num_links = of_property_count_strings(np, "mediatek,dai-link");
2400caf1120SChunxu Li if (num_links < 0 || num_links > card->num_links) {
2410caf1120SChunxu Li dev_dbg(dev, "number of dai-link is invalid\n");
2420caf1120SChunxu Li return -EINVAL;
2430caf1120SChunxu Li }
2440caf1120SChunxu Li
2450caf1120SChunxu Li parsed_dai_link = devm_kcalloc(dev, num_links, sizeof(*parsed_dai_link), GFP_KERNEL);
2460caf1120SChunxu Li if (!parsed_dai_link)
2470caf1120SChunxu Li return -ENOMEM;
2480caf1120SChunxu Li
2490caf1120SChunxu Li for (i = 0; i < num_links; i++) {
2500caf1120SChunxu Li ret = of_property_read_string_index(np, propname, i, &dai_name);
2510caf1120SChunxu Li if (ret) {
2520caf1120SChunxu Li dev_dbg(dev, "ASoC: Property '%s' index %d could not be read: %d\n",
2530caf1120SChunxu Li propname, i, ret);
2540caf1120SChunxu Li return ret;
2550caf1120SChunxu Li }
2560caf1120SChunxu Li dev_dbg(dev, "ASoC: Property get dai_name:%s\n", dai_name);
2570caf1120SChunxu Li for (j = 0; j < pre_num_links; j++) {
2580caf1120SChunxu Li if (!strcmp(dai_name, pre_dai_links[j].name)) {
2590caf1120SChunxu Li memcpy(&parsed_dai_link[parsed_num_links++], &pre_dai_links[j],
2600caf1120SChunxu Li sizeof(struct snd_soc_dai_link));
2610caf1120SChunxu Li break;
2620caf1120SChunxu Li }
2630caf1120SChunxu Li }
2640caf1120SChunxu Li }
2650caf1120SChunxu Li
2660caf1120SChunxu Li if (parsed_num_links != num_links)
2670caf1120SChunxu Li return -EINVAL;
2680caf1120SChunxu Li
2690caf1120SChunxu Li card->dai_link = parsed_dai_link;
2700caf1120SChunxu Li card->num_links = parsed_num_links;
2710caf1120SChunxu Li
2720caf1120SChunxu Li return 0;
2730caf1120SChunxu Li }
2740caf1120SChunxu Li EXPORT_SYMBOL_GPL(mtk_sof_dailink_parse_of);
275