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 #define MAX_SAMPLE_RATE 192 /* KHz*/ 15 #define MAX_BYTES_PER_SAMPLE 4 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 79 int tegra_isomgr_adma_register(struct device *dev) 80 { 81 struct tegra_admaif *admaif = dev_get_drvdata(dev); 82 struct tegra_adma_isomgr *adma_isomgr; 83 int i; 84 85 adma_isomgr = devm_kzalloc(dev, sizeof(struct tegra_adma_isomgr), GFP_KERNEL); 86 if (!adma_isomgr) 87 return -ENOMEM; 88 89 adma_isomgr->icc_path_handle = devm_of_icc_get(dev, "write"); 90 if (IS_ERR(adma_isomgr->icc_path_handle)) 91 return dev_err_probe(dev, PTR_ERR(adma_isomgr->icc_path_handle), 92 "failed to acquire interconnect path\n"); 93 94 /* Either INTERCONNECT config OR interconnect property is not defined */ 95 if (!adma_isomgr->icc_path_handle) { 96 devm_kfree(dev, adma_isomgr); 97 return 0; 98 } 99 100 adma_isomgr->max_pcm_device = admaif->soc_data->num_ch; 101 adma_isomgr->max_bw = STREAM_TYPE * MAX_SAMPLE_RATE * MAX_BYTES_PER_SAMPLE * 102 admaif->soc_data->max_stream_ch * 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 118 void tegra_isomgr_adma_unregister(struct device *dev) 119 { 120 struct tegra_admaif *admaif = dev_get_drvdata(dev); 121 122 if (!admaif->adma_isomgr) 123 return; 124 125 mutex_destroy(&admaif->adma_isomgr->mutex); 126 } 127 128 MODULE_AUTHOR("Mohan Kumar <mkumard@nvidia.com>"); 129 MODULE_DESCRIPTION("Tegra ADMA Bandwidth Request driver"); 130 MODULE_LICENSE("GPL"); 131