From b5d22f0cd4420ecda832b0bf2b80d53e809a9c9c Mon Sep 17 00:00:00 2001 From: Sameer Pujar Date: Wed, 13 Mar 2024 18:08:57 +0000 Subject: [PATCH] NVIDIA: SAUCE: ASoC: tegra: codec2codec mode for AHUB DAI links BugLink: https://bugs.launchpad.net/bugs/2072591 Add support to use AHUB internal modules with codec2codec DAI links. This can be enabled by using DT property "nvidia,ahub-c2c-links" in the sound node. The FE DAI links use normal PCM interfaces and thus are normal DAI links. Rest of the AHUB modules are connected via codec2codec DAI links. This is enabled with graph card driver now. http://nvbugs/4451662 Signed-off-by: Sameer Pujar Reviewed-by: Sharad Gupta Reviewed-by: Mohan kumar Signed-off-by: Laxman Dewangan Acked-by: Jacob Martin Acked-by: Noah Wager Signed-off-by: Noah Wager --- include/sound/simple_card_utils.h | 1 + sound/soc/generic/audio-graph-card.c | 8 +- sound/soc/generic/simple-card-utils.c | 3 + sound/soc/soc-link.c | 1 + sound/soc/tegra/tegra186_asrc.c | 1 + sound/soc/tegra/tegra186_dspk.c | 1 + sound/soc/tegra/tegra210_adx.c | 1 + sound/soc/tegra/tegra210_ahub.c | 6 +- sound/soc/tegra/tegra210_amx.c | 1 + sound/soc/tegra/tegra210_dmic.c | 1 + sound/soc/tegra/tegra210_i2s.c | 1 + sound/soc/tegra/tegra210_mixer.c | 1 + sound/soc/tegra/tegra210_mvc.c | 1 + sound/soc/tegra/tegra210_ope.c | 1 + sound/soc/tegra/tegra210_sfc.c | 1 + sound/soc/tegra/tegra_audio_graph_card.c | 111 +++++++++++++++++++++-- 16 files changed, 131 insertions(+), 9 deletions(-) diff --git a/include/sound/simple_card_utils.h b/include/sound/simple_card_utils.h index ad67957b7b48..bd7842096b69 100644 --- a/include/sound/simple_card_utils.h +++ b/include/sound/simple_card_utils.h @@ -70,6 +70,7 @@ struct simple_util_priv { struct snd_soc_dai_link *dai_link; struct simple_util_dai *dais; struct snd_soc_dai_link_component *dlcs; + struct snd_soc_dai_link_component *dummy_dlc; struct snd_soc_codec_conf *codec_conf; struct gpio_desc *pa_gpio; const struct snd_soc_ops *ops; diff --git a/sound/soc/generic/audio-graph-card.c b/sound/soc/generic/audio-graph-card.c index 83e3ba773fbd..04dd82f67096 100644 --- a/sound/soc/generic/audio-graph-card.c +++ b/sound/soc/generic/audio-graph-card.c @@ -274,12 +274,18 @@ static int graph_dai_link_of(struct simple_util_priv *priv, if (ret < 0) return ret; + if (!codec_ep) { + codecs = priv->dummy_dlc; + dai_link->codecs = priv->dummy_dlc; + } + ret = graph_parse_node(priv, codec_ep, li, NULL); if (ret < 0) return ret; snprintf(dai_name, sizeof(dai_name), - "%s-%s", cpus->dai_name, codecs->dai_name); + "%pOFP.%s-%pOFP.%s", dai_link->cpus->of_node, cpus->dai_name, + dai_link->codecs->of_node, codecs->dai_name); simple_util_canonicalize_cpu(cpus, is_single_links); simple_util_canonicalize_platform(platforms, cpus); diff --git a/sound/soc/generic/simple-card-utils.c b/sound/soc/generic/simple-card-utils.c index 81077d16d22f..66300ab39264 100644 --- a/sound/soc/generic/simple-card-utils.c +++ b/sound/soc/generic/simple-card-utils.c @@ -230,6 +230,9 @@ int simple_util_parse_clk(struct device *dev, struct clk *clk; u32 val; + if (!node) + return 0; + /* * Parse dai->sysclk come from "clocks = <&xxx>" * (if system has common clock) diff --git a/sound/soc/soc-link.c b/sound/soc/soc-link.c index fee4022708bc..ce110890b64c 100644 --- a/sound/soc/soc-link.c +++ b/sound/soc/soc-link.c @@ -64,6 +64,7 @@ int snd_soc_link_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd, return soc_link_ret(rtd, ret); } +EXPORT_SYMBOL_GPL(snd_soc_link_be_hw_params_fixup); int snd_soc_link_startup(struct snd_pcm_substream *substream) { diff --git a/sound/soc/tegra/tegra186_asrc.c b/sound/soc/tegra/tegra186_asrc.c index 66cdaef6fa66..a8c4af84355c 100644 --- a/sound/soc/tegra/tegra186_asrc.c +++ b/sound/soc/tegra/tegra186_asrc.c @@ -927,6 +927,7 @@ static const struct snd_soc_component_driver tegra186_asrc_cmpnt = { .num_dapm_widgets = ARRAY_SIZE(tegra186_asrc_widgets), .controls = tegra186_asrc_controls, .num_controls = ARRAY_SIZE(tegra186_asrc_controls), + .endianness = 1, }; static bool tegra186_asrc_wr_reg(struct device *dev, unsigned int reg) diff --git a/sound/soc/tegra/tegra186_dspk.c b/sound/soc/tegra/tegra186_dspk.c index 88e6e530eea8..99ad0f1efee8 100644 --- a/sound/soc/tegra/tegra186_dspk.c +++ b/sound/soc/tegra/tegra186_dspk.c @@ -446,6 +446,7 @@ static const struct snd_soc_component_driver tegra186_dspk_cmpnt = { .num_dapm_widgets = ARRAY_SIZE(tegra186_dspk_widgets), .controls = tegrat186_dspk_controls, .num_controls = ARRAY_SIZE(tegrat186_dspk_controls), + .endianness = 1, }; static bool tegra186_dspk_wr_reg(struct device *dev, unsigned int reg) diff --git a/sound/soc/tegra/tegra210_adx.c b/sound/soc/tegra/tegra210_adx.c index 45b4f420270b..a2853d12726f 100644 --- a/sound/soc/tegra/tegra210_adx.c +++ b/sound/soc/tegra/tegra210_adx.c @@ -440,6 +440,7 @@ static const struct snd_soc_component_driver tegra210_adx_cmpnt = { .num_dapm_widgets = ARRAY_SIZE(tegra210_adx_widgets), .controls = tegra210_adx_controls, .num_controls = ARRAY_SIZE(tegra210_adx_controls), + .endianness = 1, }; static bool tegra210_adx_wr_reg(struct device *dev, diff --git a/sound/soc/tegra/tegra210_ahub.c b/sound/soc/tegra/tegra210_ahub.c index ab3c6b2544d2..80df2fcf774a 100644 --- a/sound/soc/tegra/tegra210_ahub.c +++ b/sound/soc/tegra/tegra210_ahub.c @@ -1,8 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-only +// SPDX-FileCopyrightText: Copyright (c) 2020-2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved. // // tegra210_ahub.c - Tegra210 AHUB driver -// -// Copyright (c) 2020-2024, NVIDIA CORPORATION. All rights reserved. #include #include @@ -1243,6 +1242,7 @@ static const struct snd_soc_component_driver tegra210_ahub_component = { .num_dapm_widgets = ARRAY_SIZE(tegra210_ahub_widgets), .dapm_routes = tegra210_ahub_routes, .num_dapm_routes = ARRAY_SIZE(tegra210_ahub_routes), + .endianness = 1, }; static const struct snd_soc_component_driver tegra186_ahub_component = { @@ -1250,6 +1250,7 @@ static const struct snd_soc_component_driver tegra186_ahub_component = { .num_dapm_widgets = ARRAY_SIZE(tegra186_ahub_widgets), .dapm_routes = tegra186_ahub_routes, .num_dapm_routes = ARRAY_SIZE(tegra186_ahub_routes), + .endianness = 1, }; static const struct snd_soc_component_driver tegra234_ahub_component = { @@ -1257,6 +1258,7 @@ static const struct snd_soc_component_driver tegra234_ahub_component = { .num_dapm_widgets = ARRAY_SIZE(tegra234_ahub_widgets), .dapm_routes = tegra186_ahub_routes, .num_dapm_routes = ARRAY_SIZE(tegra186_ahub_routes), + .endianness = 1, }; static const struct regmap_config tegra210_ahub_regmap_config = { diff --git a/sound/soc/tegra/tegra210_amx.c b/sound/soc/tegra/tegra210_amx.c index b9d338d6a848..a17fe653f099 100644 --- a/sound/soc/tegra/tegra210_amx.c +++ b/sound/soc/tegra/tegra210_amx.c @@ -456,6 +456,7 @@ static const struct snd_soc_component_driver tegra210_amx_cmpnt = { .num_dapm_widgets = ARRAY_SIZE(tegra210_amx_widgets), .controls = tegra210_amx_controls, .num_controls = ARRAY_SIZE(tegra210_amx_controls), + .endianness = 1, }; static bool tegra210_amx_wr_reg(struct device *dev, unsigned int reg) diff --git a/sound/soc/tegra/tegra210_dmic.c b/sound/soc/tegra/tegra210_dmic.c index 3102d06ff410..f869c0e8949b 100644 --- a/sound/soc/tegra/tegra210_dmic.c +++ b/sound/soc/tegra/tegra210_dmic.c @@ -457,6 +457,7 @@ static const struct snd_soc_component_driver tegra210_dmic_compnt = { .num_dapm_widgets = ARRAY_SIZE(tegra210_dmic_widgets), .controls = tegra210_dmic_controls, .num_controls = ARRAY_SIZE(tegra210_dmic_controls), + .endianness = 1, }; static bool tegra210_dmic_wr_reg(struct device *dev, unsigned int reg) diff --git a/sound/soc/tegra/tegra210_i2s.c b/sound/soc/tegra/tegra210_i2s.c index cc6d789ca51c..da16f5e5d717 100644 --- a/sound/soc/tegra/tegra210_i2s.c +++ b/sound/soc/tegra/tegra210_i2s.c @@ -836,6 +836,7 @@ static const struct snd_soc_component_driver tegra210_i2s_cmpnt = { .num_dapm_widgets = ARRAY_SIZE(tegra210_i2s_widgets), .controls = tegra210_i2s_controls, .num_controls = ARRAY_SIZE(tegra210_i2s_controls), + .endianness = 1, }; static bool tegra210_i2s_wr_reg(struct device *dev, unsigned int reg) diff --git a/sound/soc/tegra/tegra210_mixer.c b/sound/soc/tegra/tegra210_mixer.c index 9d290e36d246..a8188b47cfe4 100644 --- a/sound/soc/tegra/tegra210_mixer.c +++ b/sound/soc/tegra/tegra210_mixer.c @@ -577,6 +577,7 @@ static const struct snd_soc_component_driver tegra210_mixer_cmpnt = { .num_dapm_widgets = ARRAY_SIZE(tegra210_mixer_widgets), .controls = tegra210_mixer_gain_ctls, .num_controls = ARRAY_SIZE(tegra210_mixer_gain_ctls), + .endianness = 1, }; static bool tegra210_mixer_wr_reg(struct device *dev, diff --git a/sound/soc/tegra/tegra210_mvc.c b/sound/soc/tegra/tegra210_mvc.c index 72fef04fc067..7eaaed957983 100644 --- a/sound/soc/tegra/tegra210_mvc.c +++ b/sound/soc/tegra/tegra210_mvc.c @@ -662,6 +662,7 @@ static const struct snd_soc_component_driver tegra210_mvc_cmpnt = { .num_dapm_widgets = ARRAY_SIZE(tegra210_mvc_widgets), .controls = tegra210_mvc_vol_ctrl, .num_controls = ARRAY_SIZE(tegra210_mvc_vol_ctrl), + .endianness = 1, }; static bool tegra210_mvc_rd_reg(struct device *dev, unsigned int reg) diff --git a/sound/soc/tegra/tegra210_ope.c b/sound/soc/tegra/tegra210_ope.c index 91275dc90663..d4caf6b1e71b 100644 --- a/sound/soc/tegra/tegra210_ope.c +++ b/sound/soc/tegra/tegra210_ope.c @@ -253,6 +253,7 @@ static const struct snd_soc_component_driver tegra210_ope_cmpnt = { .num_dapm_widgets = ARRAY_SIZE(tegra210_ope_widgets), .controls = tegra210_ope_controls, .num_controls = ARRAY_SIZE(tegra210_ope_controls), + .endianness = 1, }; static bool tegra210_ope_wr_reg(struct device *dev, unsigned int reg) diff --git a/sound/soc/tegra/tegra210_sfc.c b/sound/soc/tegra/tegra210_sfc.c index 7ba824fa210d..febf95b94635 100644 --- a/sound/soc/tegra/tegra210_sfc.c +++ b/sound/soc/tegra/tegra210_sfc.c @@ -3520,6 +3520,7 @@ static const struct snd_soc_component_driver tegra210_sfc_cmpnt = { .num_dapm_widgets = ARRAY_SIZE(tegra210_sfc_widgets), .controls = tegra210_sfc_controls, .num_controls = ARRAY_SIZE(tegra210_sfc_controls), + .endianness = 1, }; static bool tegra210_sfc_wr_reg(struct device *dev, unsigned int reg) diff --git a/sound/soc/tegra/tegra_audio_graph_card.c b/sound/soc/tegra/tegra_audio_graph_card.c index feba9d42bbc5..bc594766a07d 100644 --- a/sound/soc/tegra/tegra_audio_graph_card.c +++ b/sound/soc/tegra/tegra_audio_graph_card.c @@ -1,16 +1,17 @@ // SPDX-License-Identifier: GPL-2.0-only +// SPDX-FileCopyrightText: Copyright (c) 2020-2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved. // // tegra_audio_graph_card.c - Audio Graph based Tegra Machine Driver -// -// Copyright (c) 2020-2021 NVIDIA CORPORATION. All rights reserved. #include #include #include +#include #include #include #include #include +#include #define MAX_PLLA_OUT0_DIV 128 @@ -154,6 +155,9 @@ static int tegra_audio_graph_hw_params(struct snd_pcm_substream *substream, { struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0); + struct snd_soc_pcm_stream *dai_params; + struct snd_soc_pcm_runtime *vrtd; + struct snd_pcm_hw_params codec_params; int err; if (need_clk_update(cpu_dai)) { @@ -162,6 +166,34 @@ static int tegra_audio_graph_hw_params(struct snd_pcm_substream *substream, return err; } + /* + * For AHUB in c2c mode, hw_params() call here happens only for + * FE links. The PLL update is required to take care of I/O + * configuration. + * + */ + if (cpu_dai->driver->ops && !rtd->card->component_chaining) { + for_each_card_rtds(rtd->card, vrtd) { + if (!vrtd->dai_link->c2c_params) + continue; + + codec_params = *params; + snd_soc_link_be_hw_params_fixup(vrtd, &codec_params); + + dai_params = (struct snd_soc_pcm_stream *)vrtd->dai_link->c2c_params; + dai_params->rate_min = params_rate(&codec_params); + dai_params->channels_min = params_channels(&codec_params); + dai_params->formats = 1 << params_format(&codec_params); + + cpu_dai = snd_soc_rtd_to_cpu(vrtd, 0); + if (need_clk_update(cpu_dai)) { + err = tegra_audio_graph_update_pll(substream, &codec_params); + if (err) + return err; + } + } + } + return simple_util_hw_params(substream, params); } @@ -191,11 +223,58 @@ static int tegra_audio_graph_card_probe(struct snd_soc_card *card) return graph_util_card_probe(card); } +static struct snd_soc_dai_driver tegra_dummy_dai = { + .name = "tegra-snd-dummy-dai", + .playback = { + .stream_name = "Dummy Playback", + .channels_min = 1, + .channels_max = 32, + .rates = SNDRV_PCM_RATE_8000_192000, + .formats = SNDRV_PCM_FMTBIT_S8 | + SNDRV_PCM_FMTBIT_S16_LE | + SNDRV_PCM_FMTBIT_S32_LE, + }, + .capture = { + .stream_name = "Dummy Capture", + .channels_min = 1, + .channels_max = 32, + .rates = SNDRV_PCM_RATE_8000_192000, + .formats = SNDRV_PCM_FMTBIT_S8 | + SNDRV_PCM_FMTBIT_S16_LE | + SNDRV_PCM_FMTBIT_S32_LE, + }, +}; + +static const struct snd_soc_dapm_widget tegra_dummy_widgets[] = { + SND_SOC_DAPM_MIC("Dummy MIC", NULL), + SND_SOC_DAPM_SPK("Dummy SPK", NULL), +}; + +static const struct snd_soc_dapm_route tegra_dummy_routes[] = { + {"Dummy SPK", NULL, "Dummy Playback"}, + {"Dummy Capture", NULL, "Dummy MIC"}, +}; + +static const struct snd_soc_component_driver tegra_dummy_component = { + .dapm_widgets = tegra_dummy_widgets, + .num_dapm_widgets = ARRAY_SIZE(tegra_dummy_widgets), + .dapm_routes = tegra_dummy_routes, + .num_dapm_routes = ARRAY_SIZE(tegra_dummy_routes), + .endianness = 1, +}; + +static struct snd_soc_dai_link_component tegra_dummy_dlc = { + .of_node = NULL, + .dai_name = "tegra-snd-dummy-dai", + .name = "sound", +}; + static int tegra_audio_graph_probe(struct platform_device *pdev) { struct tegra_audio_priv *priv; struct device *dev = &pdev->dev; struct snd_soc_card *card; + int ret; priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); if (!priv) @@ -207,11 +286,31 @@ static int tegra_audio_graph_probe(struct platform_device *pdev) card->probe = tegra_audio_graph_card_probe; /* audio_graph_parse_of() depends on below */ - card->component_chaining = 1; - priv->simple.ops = &tegra_audio_graph_ops; - priv->simple.force_dpcm = 1; + if (!of_property_read_bool(dev->of_node, "nvidia,ahub-c2c-links")) { + card->component_chaining = 1; + priv->simple.force_dpcm = 1; + } - return audio_graph_parse_of(&priv->simple, dev); + ret = devm_snd_soc_register_component(dev, &tegra_dummy_component, + &tegra_dummy_dai, 1); + if (ret < 0) { + dev_err(dev, "Tegra dummy component registration fails\n"); + return ret; + } + + priv->simple.dummy_dlc = &tegra_dummy_dlc; + priv->simple.ops = &tegra_audio_graph_ops; + + ret = audio_graph_parse_of(&priv->simple, dev); + if (ret < 0) + return ret; + + of_platform_populate(pdev->dev.of_node, NULL, NULL, &pdev->dev); + + dev_info(&pdev->dev, "Registered APE graph sound card with %s links for AHUB\n", + card->component_chaining ? "DPCM" : "codec2codec"); + + return 0; } static const struct tegra_audio_cdata tegra210_data = {