Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

ASoC: tegra: Add interconnect support

Add interconnect framework support to set required audio bandwidth
based on PCM device usage. The maximum bandwidth is determined by
the number of APE PCM devices and maximum audio format supported.

If interconnect property is not defined or INTERCONNECT config
is not enabled then the audio usecase will still function.

Validate bandwidth updates by reading the interconnect summary sysfs
node during PCM device open and close operations.

Signed-off-by: Sheetal <sheetal@nvidia.com>
Link: https://patch.msgid.link/20250203105304.4155542-1-sheetal@nvidia.com
Signed-off-by: Mark Brown <broonie@kernel.org>

authored by

Sheetal and committed by
Mark Brown
4a91fe4c 299ce4be

+192 -6
+1 -1
sound/soc/tegra/Makefile
··· 13 13 snd-soc-tegra210-i2s-y := tegra210_i2s.o 14 14 snd-soc-tegra186-asrc-y := tegra186_asrc.o 15 15 snd-soc-tegra186-dspk-y := tegra186_dspk.o 16 - snd-soc-tegra210-admaif-y := tegra210_admaif.o 16 + snd-soc-tegra210-admaif-y := tegra210_admaif.o tegra_isomgr_bw.o 17 17 snd-soc-tegra210-mvc-y := tegra210_mvc.o 18 18 snd-soc-tegra210-sfc-y := tegra210_sfc.o 19 19 snd-soc-tegra210-amx-y := tegra210_amx.o
+23 -1
sound/soc/tegra/tegra210_admaif.c
··· 1 1 // SPDX-License-Identifier: GPL-2.0-only 2 - // SPDX-FileCopyrightText: Copyright (c) 2020-2024 NVIDIA CORPORATION & AFFILIATES. 2 + // SPDX-FileCopyrightText: Copyright (c) 2020-2025 NVIDIA CORPORATION & AFFILIATES. 3 3 // All rights reserved. 4 4 // 5 5 // tegra210_admaif.c - Tegra ADMAIF driver ··· 13 13 #include <linux/regmap.h> 14 14 #include <sound/pcm_params.h> 15 15 #include <sound/soc.h> 16 + #include "tegra_isomgr_bw.h" 16 17 #include "tegra210_admaif.h" 17 18 #include "tegra_cif.h" 18 19 #include "tegra_pcm.h" ··· 261 260 } 262 261 263 262 return 0; 263 + } 264 + 265 + static int tegra_admaif_prepare(struct snd_pcm_substream *substream, 266 + struct snd_soc_dai *dai) 267 + { 268 + return tegra_isomgr_adma_setbw(substream, dai, true); 269 + } 270 + 271 + static void tegra_admaif_shutdown(struct snd_pcm_substream *substream, 272 + struct snd_soc_dai *dai) 273 + { 274 + tegra_isomgr_adma_setbw(substream, dai, false); 264 275 } 265 276 266 277 static int tegra_admaif_hw_params(struct snd_pcm_substream *substream, ··· 567 554 .probe = tegra_admaif_dai_probe, 568 555 .hw_params = tegra_admaif_hw_params, 569 556 .trigger = tegra_admaif_trigger, 557 + .shutdown = tegra_admaif_shutdown, 558 + .prepare = tegra_admaif_prepare, 570 559 }; 571 560 572 561 #define DAI(dai_name) \ ··· 815 800 816 801 regcache_cache_only(admaif->regmap, true); 817 802 803 + err = tegra_isomgr_adma_register(&pdev->dev); 804 + if (err) { 805 + dev_err(&pdev->dev, "Failed to add interconnect path\n"); 806 + return err; 807 + } 808 + 818 809 regmap_update_bits(admaif->regmap, admaif->soc_data->global_base + 819 810 TEGRA_ADMAIF_GLOBAL_ENABLE, 1, 1); 820 811 ··· 872 851 873 852 static void tegra_admaif_remove(struct platform_device *pdev) 874 853 { 854 + tegra_isomgr_adma_unregister(&pdev->dev); 875 855 pm_runtime_disable(&pdev->dev); 876 856 } 877 857
+5 -4
sound/soc/tegra/tegra210_admaif.h
··· 1 - /* SPDX-License-Identifier: GPL-2.0-only */ 2 - /* 3 - * tegra210_admaif.h - Tegra ADMAIF registers 1 + /* SPDX-License-Identifier: GPL-2.0-only 2 + * SPDX-FileCopyrightText: Copyright (c) 2020-2025 NVIDIA CORPORATION & AFFILIATES. 3 + * All rights reserved. 4 4 * 5 - * Copyright (c) 2020 NVIDIA CORPORATION. All rights reserved. 5 + * tegra210_admaif.h - Tegra ADMAIF registers 6 6 * 7 7 */ 8 8 ··· 157 157 unsigned int *mono_to_stereo[ADMAIF_PATHS]; 158 158 unsigned int *stereo_to_mono[ADMAIF_PATHS]; 159 159 struct regmap *regmap; 160 + struct tegra_adma_isomgr *adma_isomgr; 160 161 }; 161 162 162 163 #endif
+132
sound/soc/tegra/tegra_isomgr_bw.c
··· 1 + // SPDX-License-Identifier: GPL-2.0-only 2 + // SPDX-FileCopyrightText: Copyright (c) 2025 NVIDIA CORPORATION & AFFILIATES. 3 + // All rights reserved. 4 + // 5 + // ADMA bandwidth calculation 6 + 7 + #include <linux/interconnect.h> 8 + #include <linux/module.h> 9 + #include <sound/pcm_params.h> 10 + #include <sound/soc.h> 11 + #include "tegra_isomgr_bw.h" 12 + #include "tegra210_admaif.h" 13 + 14 + /* Max possible rate is 192KHz x 16channel x 4bytes */ 15 + #define MAX_BW_PER_DEV 12288 16 + 17 + int tegra_isomgr_adma_setbw(struct snd_pcm_substream *substream, 18 + struct snd_soc_dai *dai, bool is_running) 19 + { 20 + struct device *dev = dai->dev; 21 + struct tegra_admaif *admaif = snd_soc_dai_get_drvdata(dai); 22 + struct tegra_adma_isomgr *adma_isomgr = admaif->adma_isomgr; 23 + struct snd_pcm_runtime *runtime = substream->runtime; 24 + struct snd_pcm *pcm = substream->pcm; 25 + u32 type = substream->stream, bandwidth = 0; 26 + int sample_bytes; 27 + 28 + if (!adma_isomgr) 29 + return 0; 30 + 31 + if (!runtime || !pcm) 32 + return -EINVAL; 33 + 34 + if (pcm->device >= adma_isomgr->max_pcm_device) { 35 + dev_err(dev, "%s: PCM device number %d is greater than %d\n", __func__, 36 + pcm->device, adma_isomgr->max_pcm_device); 37 + return -EINVAL; 38 + } 39 + 40 + /* 41 + * No action if stream is running and bandwidth is already set or 42 + * stream is not running and bandwidth is already reset 43 + */ 44 + if ((adma_isomgr->bw_per_dev[type][pcm->device] && is_running) || 45 + (!adma_isomgr->bw_per_dev[type][pcm->device] && !is_running)) 46 + return 0; 47 + 48 + if (is_running) { 49 + sample_bytes = snd_pcm_format_width(runtime->format) / 8; 50 + if (sample_bytes < 0) 51 + return sample_bytes; 52 + 53 + /* KB/s kilo bytes per sec */ 54 + bandwidth = runtime->channels * (runtime->rate / 1000) * 55 + sample_bytes; 56 + } 57 + 58 + mutex_lock(&adma_isomgr->mutex); 59 + 60 + if (is_running) { 61 + if (bandwidth + adma_isomgr->current_bandwidth > adma_isomgr->max_bw) 62 + bandwidth = adma_isomgr->max_bw - adma_isomgr->current_bandwidth; 63 + 64 + adma_isomgr->current_bandwidth += bandwidth; 65 + } else { 66 + adma_isomgr->current_bandwidth -= adma_isomgr->bw_per_dev[type][pcm->device]; 67 + } 68 + 69 + mutex_unlock(&adma_isomgr->mutex); 70 + 71 + adma_isomgr->bw_per_dev[type][pcm->device] = bandwidth; 72 + 73 + dev_dbg(dev, "Setting up bandwidth to %d KBps\n", adma_isomgr->current_bandwidth); 74 + 75 + return icc_set_bw(adma_isomgr->icc_path_handle, 76 + adma_isomgr->current_bandwidth, adma_isomgr->max_bw); 77 + } 78 + EXPORT_SYMBOL(tegra_isomgr_adma_setbw); 79 + 80 + int tegra_isomgr_adma_register(struct device *dev) 81 + { 82 + struct tegra_admaif *admaif = dev_get_drvdata(dev); 83 + struct tegra_adma_isomgr *adma_isomgr; 84 + int i; 85 + 86 + adma_isomgr = devm_kzalloc(dev, sizeof(struct tegra_adma_isomgr), GFP_KERNEL); 87 + if (!adma_isomgr) 88 + return -ENOMEM; 89 + 90 + adma_isomgr->icc_path_handle = devm_of_icc_get(dev, "write"); 91 + if (IS_ERR(adma_isomgr->icc_path_handle)) 92 + return dev_err_probe(dev, PTR_ERR(adma_isomgr->icc_path_handle), 93 + "failed to acquire interconnect path\n"); 94 + 95 + /* Either INTERCONNECT config OR interconnect property is not defined */ 96 + if (!adma_isomgr->icc_path_handle) { 97 + devm_kfree(dev, adma_isomgr); 98 + return 0; 99 + } 100 + 101 + adma_isomgr->max_pcm_device = admaif->soc_data->num_ch; 102 + adma_isomgr->max_bw = STREAM_TYPE * MAX_BW_PER_DEV * adma_isomgr->max_pcm_device; 103 + 104 + for (i = 0; i < STREAM_TYPE; i++) { 105 + adma_isomgr->bw_per_dev[i] = devm_kzalloc(dev, adma_isomgr->max_pcm_device * 106 + sizeof(u32), GFP_KERNEL); 107 + if (!adma_isomgr->bw_per_dev[i]) 108 + return -ENOMEM; 109 + } 110 + 111 + adma_isomgr->current_bandwidth = 0; 112 + mutex_init(&adma_isomgr->mutex); 113 + admaif->adma_isomgr = adma_isomgr; 114 + 115 + return 0; 116 + } 117 + EXPORT_SYMBOL(tegra_isomgr_adma_register); 118 + 119 + void tegra_isomgr_adma_unregister(struct device *dev) 120 + { 121 + struct tegra_admaif *admaif = dev_get_drvdata(dev); 122 + 123 + if (!admaif->adma_isomgr) 124 + return; 125 + 126 + mutex_destroy(&admaif->adma_isomgr->mutex); 127 + } 128 + EXPORT_SYMBOL(tegra_isomgr_adma_unregister); 129 + 130 + MODULE_AUTHOR("Mohan Kumar <mkumard@nvidia.com>"); 131 + MODULE_DESCRIPTION("Tegra ADMA Bandwidth Request driver"); 132 + MODULE_LICENSE("GPL");
+31
sound/soc/tegra/tegra_isomgr_bw.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0-only 2 + * SPDX-FileCopyrightText: Copyright (c) 2025 NVIDIA CORPORATION & AFFILIATES. 3 + * All rights reserved. 4 + * 5 + * tegra_isomgr_bw.h - Definitions for ADMA bandwidth calculation 6 + * 7 + */ 8 + 9 + #ifndef __TEGRA_ISOMGR_BW_H__ 10 + #define __TEGRA_ISOMGR_BW_H__ 11 + 12 + /* Playback and Capture streams */ 13 + #define STREAM_TYPE 2 14 + 15 + struct tegra_adma_isomgr { 16 + /* Protect pcm devices bandwidth */ 17 + struct mutex mutex; 18 + /* interconnect path handle */ 19 + struct icc_path *icc_path_handle; 20 + u32 *bw_per_dev[STREAM_TYPE]; 21 + u32 current_bandwidth; 22 + u32 max_pcm_device; 23 + u32 max_bw; 24 + }; 25 + 26 + int tegra_isomgr_adma_register(struct device *dev); 27 + void tegra_isomgr_adma_unregister(struct device *dev); 28 + int tegra_isomgr_adma_setbw(struct snd_pcm_substream *substream, 29 + struct snd_soc_dai *dai, bool is_running); 30 + 31 + #endif