mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/chenhuacai/linux-loongson
synced 2025-08-27 06:50:37 +00:00

Tegra264 supports max 32 channels, hence calculating the max bandwidth using the channel info from soc_data. Signed-off-by: Sheetal <sheetal@nvidia.com> Link: https://patch.msgid.link/20250512051747.1026770-12-sheetal@nvidia.com Signed-off-by: Mark Brown <broonie@kernel.org>
131 lines
3.7 KiB
C
131 lines
3.7 KiB
C
// SPDX-License-Identifier: GPL-2.0-only
|
|
// SPDX-FileCopyrightText: Copyright (c) 2025 NVIDIA CORPORATION & AFFILIATES.
|
|
// All rights reserved.
|
|
//
|
|
// ADMA bandwidth calculation
|
|
|
|
#include <linux/interconnect.h>
|
|
#include <linux/module.h>
|
|
#include <sound/pcm_params.h>
|
|
#include <sound/soc.h>
|
|
#include "tegra_isomgr_bw.h"
|
|
#include "tegra210_admaif.h"
|
|
|
|
#define MAX_SAMPLE_RATE 192 /* KHz*/
|
|
#define MAX_BYTES_PER_SAMPLE 4
|
|
|
|
int tegra_isomgr_adma_setbw(struct snd_pcm_substream *substream,
|
|
struct snd_soc_dai *dai, bool is_running)
|
|
{
|
|
struct device *dev = dai->dev;
|
|
struct tegra_admaif *admaif = snd_soc_dai_get_drvdata(dai);
|
|
struct tegra_adma_isomgr *adma_isomgr = admaif->adma_isomgr;
|
|
struct snd_pcm_runtime *runtime = substream->runtime;
|
|
struct snd_pcm *pcm = substream->pcm;
|
|
u32 type = substream->stream, bandwidth = 0;
|
|
int sample_bytes;
|
|
|
|
if (!adma_isomgr)
|
|
return 0;
|
|
|
|
if (!runtime || !pcm)
|
|
return -EINVAL;
|
|
|
|
if (pcm->device >= adma_isomgr->max_pcm_device) {
|
|
dev_err(dev, "%s: PCM device number %d is greater than %d\n", __func__,
|
|
pcm->device, adma_isomgr->max_pcm_device);
|
|
return -EINVAL;
|
|
}
|
|
|
|
/*
|
|
* No action if stream is running and bandwidth is already set or
|
|
* stream is not running and bandwidth is already reset
|
|
*/
|
|
if ((adma_isomgr->bw_per_dev[type][pcm->device] && is_running) ||
|
|
(!adma_isomgr->bw_per_dev[type][pcm->device] && !is_running))
|
|
return 0;
|
|
|
|
if (is_running) {
|
|
sample_bytes = snd_pcm_format_width(runtime->format) / 8;
|
|
if (sample_bytes < 0)
|
|
return sample_bytes;
|
|
|
|
/* KB/s kilo bytes per sec */
|
|
bandwidth = runtime->channels * (runtime->rate / 1000) *
|
|
sample_bytes;
|
|
}
|
|
|
|
mutex_lock(&adma_isomgr->mutex);
|
|
|
|
if (is_running) {
|
|
if (bandwidth + adma_isomgr->current_bandwidth > adma_isomgr->max_bw)
|
|
bandwidth = adma_isomgr->max_bw - adma_isomgr->current_bandwidth;
|
|
|
|
adma_isomgr->current_bandwidth += bandwidth;
|
|
} else {
|
|
adma_isomgr->current_bandwidth -= adma_isomgr->bw_per_dev[type][pcm->device];
|
|
}
|
|
|
|
mutex_unlock(&adma_isomgr->mutex);
|
|
|
|
adma_isomgr->bw_per_dev[type][pcm->device] = bandwidth;
|
|
|
|
dev_dbg(dev, "Setting up bandwidth to %d KBps\n", adma_isomgr->current_bandwidth);
|
|
|
|
return icc_set_bw(adma_isomgr->icc_path_handle,
|
|
adma_isomgr->current_bandwidth, adma_isomgr->max_bw);
|
|
}
|
|
|
|
int tegra_isomgr_adma_register(struct device *dev)
|
|
{
|
|
struct tegra_admaif *admaif = dev_get_drvdata(dev);
|
|
struct tegra_adma_isomgr *adma_isomgr;
|
|
int i;
|
|
|
|
adma_isomgr = devm_kzalloc(dev, sizeof(struct tegra_adma_isomgr), GFP_KERNEL);
|
|
if (!adma_isomgr)
|
|
return -ENOMEM;
|
|
|
|
adma_isomgr->icc_path_handle = devm_of_icc_get(dev, "write");
|
|
if (IS_ERR(adma_isomgr->icc_path_handle))
|
|
return dev_err_probe(dev, PTR_ERR(adma_isomgr->icc_path_handle),
|
|
"failed to acquire interconnect path\n");
|
|
|
|
/* Either INTERCONNECT config OR interconnect property is not defined */
|
|
if (!adma_isomgr->icc_path_handle) {
|
|
devm_kfree(dev, adma_isomgr);
|
|
return 0;
|
|
}
|
|
|
|
adma_isomgr->max_pcm_device = admaif->soc_data->num_ch;
|
|
adma_isomgr->max_bw = STREAM_TYPE * MAX_SAMPLE_RATE * MAX_BYTES_PER_SAMPLE *
|
|
admaif->soc_data->max_stream_ch * adma_isomgr->max_pcm_device;
|
|
|
|
for (i = 0; i < STREAM_TYPE; i++) {
|
|
adma_isomgr->bw_per_dev[i] = devm_kzalloc(dev, adma_isomgr->max_pcm_device *
|
|
sizeof(u32), GFP_KERNEL);
|
|
if (!adma_isomgr->bw_per_dev[i])
|
|
return -ENOMEM;
|
|
}
|
|
|
|
adma_isomgr->current_bandwidth = 0;
|
|
mutex_init(&adma_isomgr->mutex);
|
|
admaif->adma_isomgr = adma_isomgr;
|
|
|
|
return 0;
|
|
}
|
|
|
|
void tegra_isomgr_adma_unregister(struct device *dev)
|
|
{
|
|
struct tegra_admaif *admaif = dev_get_drvdata(dev);
|
|
|
|
if (!admaif->adma_isomgr)
|
|
return;
|
|
|
|
mutex_destroy(&admaif->adma_isomgr->mutex);
|
|
}
|
|
|
|
MODULE_AUTHOR("Mohan Kumar <mkumard@nvidia.com>");
|
|
MODULE_DESCRIPTION("Tegra ADMA Bandwidth Request driver");
|
|
MODULE_LICENSE("GPL");
|