mirror of
git://nv-tegra.nvidia.com/linux-nv-oot.git
synced 2025-12-22 17:25:35 +03:00
ASoC: tegra: Add Interconnect support for ADMA
Add Interconnect API support for ADMA Memory bandwidth requirement handling. From Kernel 4.14 and beyond - On T23X and newer platforms, the interconnects driver will be initialized and calls to BWMGR will be stubbed out. - On T194 and earlier platforms, BWMGR driver will be initialized and calls to interconnect framework will be stubbed out. Jira TAS-1059 Change-Id: I7a26f61517937ac3103222a43f08ee7c4e4ad484 Signed-off-by: Mohan Kumar <mkumard@nvidia.com> Reviewed-on: https://git-master.nvidia.com/r/c/linux-5.9/+/2408552 Tested-by: mobile promotions <svcmobile_promotions@nvidia.com> Reviewed-by: mobile promotions <svcmobile_promotions@nvidia.com>
This commit is contained in:
committed by
Sameer Pujar
parent
79d734adb3
commit
30706b0cef
@@ -268,8 +268,7 @@ static int tegra_admaif_prepare(struct snd_pcm_substream *substream,
|
|||||||
{
|
{
|
||||||
struct tegra_admaif *admaif = snd_soc_dai_get_drvdata(dai);
|
struct tegra_admaif *admaif = snd_soc_dai_get_drvdata(dai);
|
||||||
|
|
||||||
if (admaif->soc_data->is_isomgr_client)
|
tegra_isomgr_adma_setbw(substream, true);
|
||||||
tegra_isomgr_adma_setbw(substream, true);
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -279,8 +278,7 @@ static void tegra_admaif_shutdown(struct snd_pcm_substream *substream,
|
|||||||
{
|
{
|
||||||
struct tegra_admaif *admaif = snd_soc_dai_get_drvdata(dai);
|
struct tegra_admaif *admaif = snd_soc_dai_get_drvdata(dai);
|
||||||
|
|
||||||
if (admaif->soc_data->is_isomgr_client)
|
tegra_isomgr_adma_setbw(substream, false);
|
||||||
tegra_isomgr_adma_setbw(substream, false);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int tegra_admaif_hw_params(struct snd_pcm_substream *substream,
|
static int tegra_admaif_hw_params(struct snd_pcm_substream *substream,
|
||||||
@@ -994,7 +992,6 @@ static const struct tegra_admaif_soc_data soc_data_tegra210 = {
|
|||||||
.global_base = TEGRA210_ADMAIF_GLOBAL_BASE,
|
.global_base = TEGRA210_ADMAIF_GLOBAL_BASE,
|
||||||
.tx_base = TEGRA210_ADMAIF_TX_BASE,
|
.tx_base = TEGRA210_ADMAIF_TX_BASE,
|
||||||
.rx_base = TEGRA210_ADMAIF_RX_BASE,
|
.rx_base = TEGRA210_ADMAIF_RX_BASE,
|
||||||
.is_isomgr_client = false,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
static const struct tegra_admaif_soc_data soc_data_tegra186 = {
|
static const struct tegra_admaif_soc_data soc_data_tegra186 = {
|
||||||
@@ -1005,7 +1002,6 @@ static const struct tegra_admaif_soc_data soc_data_tegra186 = {
|
|||||||
.global_base = TEGRA186_ADMAIF_GLOBAL_BASE,
|
.global_base = TEGRA186_ADMAIF_GLOBAL_BASE,
|
||||||
.tx_base = TEGRA186_ADMAIF_TX_BASE,
|
.tx_base = TEGRA186_ADMAIF_TX_BASE,
|
||||||
.rx_base = TEGRA186_ADMAIF_RX_BASE,
|
.rx_base = TEGRA186_ADMAIF_RX_BASE,
|
||||||
.is_isomgr_client = true,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
static const struct of_device_id tegra_admaif_of_match[] = {
|
static const struct of_device_id tegra_admaif_of_match[] = {
|
||||||
@@ -1089,8 +1085,7 @@ static int tegra_admaif_probe(struct platform_device *pdev)
|
|||||||
|
|
||||||
regcache_cache_only(admaif->regmap, true);
|
regcache_cache_only(admaif->regmap, true);
|
||||||
|
|
||||||
if (admaif->soc_data->is_isomgr_client)
|
tegra_isomgr_adma_register(&pdev->dev);
|
||||||
tegra_isomgr_adma_register();
|
|
||||||
|
|
||||||
regmap_update_bits(admaif->regmap, admaif->soc_data->global_base +
|
regmap_update_bits(admaif->regmap, admaif->soc_data->global_base +
|
||||||
TEGRA_ADMAIF_GLOBAL_ENABLE, 1, 1);
|
TEGRA_ADMAIF_GLOBAL_ENABLE, 1, 1);
|
||||||
@@ -1147,8 +1142,7 @@ static int tegra_admaif_remove(struct platform_device *pdev)
|
|||||||
{
|
{
|
||||||
struct tegra_admaif *admaif = dev_get_drvdata(&pdev->dev);
|
struct tegra_admaif *admaif = dev_get_drvdata(&pdev->dev);
|
||||||
|
|
||||||
if (admaif->soc_data->is_isomgr_client)
|
tegra_isomgr_adma_unregister(&pdev->dev);
|
||||||
tegra_isomgr_adma_unregister();
|
|
||||||
|
|
||||||
pm_runtime_disable(&pdev->dev);
|
pm_runtime_disable(&pdev->dev);
|
||||||
|
|
||||||
|
|||||||
@@ -148,7 +148,6 @@ struct tegra_admaif_soc_data {
|
|||||||
unsigned int tx_base;
|
unsigned int tx_base;
|
||||||
unsigned int rx_base;
|
unsigned int rx_base;
|
||||||
unsigned int num_ch;
|
unsigned int num_ch;
|
||||||
bool is_isomgr_client;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct tegra_admaif {
|
struct tegra_admaif {
|
||||||
|
|||||||
@@ -15,20 +15,20 @@
|
|||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <linux/module.h>
|
#include <linux/module.h>
|
||||||
#include <sound/pcm_params.h>
|
#include <sound/pcm_params.h>
|
||||||
#include <sound/soc.h>
|
#include <sound/soc.h>
|
||||||
#include <linux/platform/tegra/isomgr.h>
|
#include <linux/platform/tegra/isomgr.h>
|
||||||
#include <linux/platform/tegra/latency_allowance.h>
|
#include <linux/platform/tegra/latency_allowance.h>
|
||||||
#include "tegra_isomgr_bw.h"
|
#include "tegra_isomgr_bw.h"
|
||||||
|
#include <soc/tegra/fuse.h>
|
||||||
#if defined(CONFIG_TEGRA_ISOMGR) && defined(CONFIG_NV_TEGRA_MC)
|
#include <linux/interconnect.h>
|
||||||
|
#include <dt-bindings/interconnect/tegra_icc_id.h>
|
||||||
|
|
||||||
#define MAX_BW 393216 /*Maximum KiloByte*/
|
#define MAX_BW 393216 /*Maximum KiloByte*/
|
||||||
#define MAX_DEV_NUM 256
|
#define MAX_DEV_NUM 256
|
||||||
|
|
||||||
static long tegra_adma_calc_min_bandwidth(void);
|
|
||||||
|
|
||||||
static struct adma_isomgr {
|
static struct adma_isomgr {
|
||||||
int current_bandwidth;
|
int current_bandwidth;
|
||||||
bool device_number[MAX_DEV_NUM];
|
bool device_number[MAX_DEV_NUM];
|
||||||
@@ -36,8 +36,11 @@ static struct adma_isomgr {
|
|||||||
struct mutex mutex;
|
struct mutex mutex;
|
||||||
/* iso manager handle */
|
/* iso manager handle */
|
||||||
tegra_isomgr_handle isomgr_handle;
|
tegra_isomgr_handle isomgr_handle;
|
||||||
|
/* icc_path handle handle */
|
||||||
|
struct icc_path *icc_path_handle;
|
||||||
} *adma;
|
} *adma;
|
||||||
|
|
||||||
|
#if IS_ENABLED(CONFIG_TEGRA_ISOMGR) && IS_ENABLED(CONFIG_NV_TEGRA_MC)
|
||||||
static long tegra_adma_calc_min_bandwidth(void)
|
static long tegra_adma_calc_min_bandwidth(void)
|
||||||
{
|
{
|
||||||
int max_srate = 192; /*Khz*/
|
int max_srate = 192; /*Khz*/
|
||||||
@@ -51,6 +54,15 @@ static long tegra_adma_calc_min_bandwidth(void)
|
|||||||
return min_bw;
|
return min_bw;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void tegra_isomgr_adma_renegotiate(void *p, u32 avail_bw)
|
||||||
|
{
|
||||||
|
/* For Audio usecase there is no possibility of renegotiation
|
||||||
|
* as it may lead to glitches. So currently dummy renegotiate call
|
||||||
|
* is added to support bandwidth request more than registered bw which
|
||||||
|
* got initialized during register call
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
|
||||||
static int adma_isomgr_request(uint adma_bw, uint lt)
|
static int adma_isomgr_request(uint adma_bw, uint lt)
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
@@ -78,12 +90,12 @@ static int adma_isomgr_request(uint adma_bw, uint lt)
|
|||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
void tegra_isomgr_adma_setbw(struct snd_pcm_substream *substream,
|
void tegra_isomgr_adma_setbw(struct snd_pcm_substream *substream,
|
||||||
bool is_running)
|
bool is_running)
|
||||||
{
|
{
|
||||||
int bandwidth, sample_bytes;
|
int bandwidth, sample_bytes;
|
||||||
int ret;
|
|
||||||
struct snd_pcm_runtime *runtime = substream->runtime;
|
struct snd_pcm_runtime *runtime = substream->runtime;
|
||||||
struct snd_pcm *pcm = substream->pcm;
|
struct snd_pcm *pcm = substream->pcm;
|
||||||
|
|
||||||
@@ -132,28 +144,31 @@ void tegra_isomgr_adma_setbw(struct snd_pcm_substream *substream,
|
|||||||
adma->current_bandwidth = MAX_BW;
|
adma->current_bandwidth = MAX_BW;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = adma_isomgr_request(adma->current_bandwidth, 1000);
|
if (adma->icc_path_handle)
|
||||||
if (!ret) {
|
icc_set_bw(adma->icc_path_handle, adma->current_bandwidth,
|
||||||
/* Call LA/PTSA driver which will configure the Memory
|
adma->current_bandwidth);
|
||||||
controller to support APEDMA's new BW requirement in MBps*/
|
|
||||||
ret = tegra_set_latency_allowance(TEGRA_LA_APEDMAW,
|
#if IS_ENABLED(CONFIG_TEGRA_ISOMGR) && IS_ENABLED(CONFIG_NV_TEGRA_MC)
|
||||||
((adma->current_bandwidth + 999)/1000));
|
if (adma->isomgr_handle) {
|
||||||
if (ret)
|
int ret;
|
||||||
pr_err("%s: LA/PTSA setting Failed\n", __func__);
|
|
||||||
|
ret = adma_isomgr_request(adma->current_bandwidth, 1000);
|
||||||
|
if (!ret) {
|
||||||
|
/* Call LA/PTSA driver which will configure the
|
||||||
|
* Memory controller to support APEDMA's new BW
|
||||||
|
* requirement in MBps
|
||||||
|
*/
|
||||||
|
ret = tegra_set_latency_allowance(TEGRA_LA_APEDMAW,
|
||||||
|
((adma->current_bandwidth + 999)/1000));
|
||||||
|
if (ret)
|
||||||
|
pr_err("%s: LA/PTSA config Failed\n", __func__);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(tegra_isomgr_adma_setbw);
|
EXPORT_SYMBOL(tegra_isomgr_adma_setbw);
|
||||||
|
|
||||||
void tegra_isomgr_adma_renegotiate(void *p, u32 avail_bw)
|
void tegra_isomgr_adma_register(struct device *dev)
|
||||||
{
|
|
||||||
/* For Audio usecase there is no possibility of renegotiation
|
|
||||||
as it may lead to glitches. So currently dummy renegotiate call
|
|
||||||
is added to support bandwidth request more than registered bw which
|
|
||||||
got initialized during register call */
|
|
||||||
}
|
|
||||||
EXPORT_SYMBOL(tegra_isomgr_adma_renegotiate);
|
|
||||||
|
|
||||||
void tegra_isomgr_adma_register(void)
|
|
||||||
{
|
{
|
||||||
adma = kzalloc(sizeof(struct adma_isomgr), GFP_KERNEL);
|
adma = kzalloc(sizeof(struct adma_isomgr), GFP_KERNEL);
|
||||||
if (!adma) {
|
if (!adma) {
|
||||||
@@ -162,42 +177,72 @@ void tegra_isomgr_adma_register(void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
adma->current_bandwidth = 0;
|
adma->current_bandwidth = 0;
|
||||||
|
adma->isomgr_handle = NULL;
|
||||||
|
adma->icc_path_handle = NULL;
|
||||||
memset(&adma->device_number, 0, sizeof(bool) * MAX_DEV_NUM);
|
memset(&adma->device_number, 0, sizeof(bool) * MAX_DEV_NUM);
|
||||||
memset(&adma->bw_per_device, 0, sizeof(int) * MAX_DEV_NUM);
|
memset(&adma->bw_per_device, 0, sizeof(int) * MAX_DEV_NUM);
|
||||||
|
|
||||||
mutex_init(&adma->mutex);
|
mutex_init(&adma->mutex);
|
||||||
|
|
||||||
/* Register the required BW for adma usecases.*/
|
switch (tegra_get_chip_id()) {
|
||||||
adma->isomgr_handle = tegra_isomgr_register(TEGRA_ISO_CLIENT_APE_ADMA,
|
case TEGRA210:
|
||||||
|
/* No Support added for T210 */
|
||||||
|
tegra_isomgr_adma_unregister(dev);
|
||||||
|
break;
|
||||||
|
case TEGRA186:
|
||||||
|
case TEGRA194:
|
||||||
|
#if IS_ENABLED(CONFIG_TEGRA_ISOMGR) && IS_ENABLED(CONFIG_NV_TEGRA_MC)
|
||||||
|
/* Register the required BW for adma usecases.*/
|
||||||
|
adma->isomgr_handle = tegra_isomgr_register(
|
||||||
|
TEGRA_ISO_CLIENT_APE_ADMA,
|
||||||
tegra_adma_calc_min_bandwidth(),
|
tegra_adma_calc_min_bandwidth(),
|
||||||
tegra_isomgr_adma_renegotiate,
|
tegra_isomgr_adma_renegotiate,
|
||||||
adma);
|
adma);
|
||||||
if (IS_ERR(adma->isomgr_handle)) {
|
if (IS_ERR(adma->isomgr_handle)) {
|
||||||
pr_err("%s: Failed to register adma isomgr client. err=%ld\n",
|
pr_err(
|
||||||
|
"%s: Failed to register adma isomgr client. err=%ld\n",
|
||||||
__func__, PTR_ERR(adma->isomgr_handle));
|
__func__, PTR_ERR(adma->isomgr_handle));
|
||||||
adma->isomgr_handle = NULL;
|
adma->isomgr_handle = NULL;
|
||||||
mutex_destroy(&adma->mutex);
|
tegra_isomgr_adma_unregister(dev);
|
||||||
kfree(adma);
|
}
|
||||||
adma = NULL;
|
#endif
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
adma->icc_path_handle = icc_get(dev, TEGRA_ICC_APEDMA,
|
||||||
|
TEGRA_ICC_PRIMARY);
|
||||||
|
if (IS_ERR(adma->icc_path_handle)) {
|
||||||
|
pr_err("%s: Failed to register Interconnect. err=%ld\n",
|
||||||
|
__func__, PTR_ERR(adma->icc_path_handle));
|
||||||
|
adma->icc_path_handle = NULL;
|
||||||
|
tegra_isomgr_adma_unregister(dev);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(tegra_isomgr_adma_register);
|
EXPORT_SYMBOL(tegra_isomgr_adma_register);
|
||||||
void tegra_isomgr_adma_unregister(void)
|
|
||||||
|
void tegra_isomgr_adma_unregister(struct device *dev)
|
||||||
{
|
{
|
||||||
if (!adma)
|
if (!adma)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
mutex_destroy(&adma->mutex);
|
mutex_destroy(&adma->mutex);
|
||||||
|
|
||||||
|
if (adma->icc_path_handle) {
|
||||||
|
icc_put(adma->icc_path_handle);
|
||||||
|
adma->icc_path_handle = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if IS_ENABLED(CONFIG_TEGRA_ISOMGR) && IS_ENABLED(CONFIG_NV_TEGRA_MC)
|
||||||
if (adma->isomgr_handle) {
|
if (adma->isomgr_handle) {
|
||||||
tegra_isomgr_unregister(adma->isomgr_handle);
|
tegra_isomgr_unregister(adma->isomgr_handle);
|
||||||
adma->isomgr_handle = NULL;
|
adma->isomgr_handle = NULL;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
kfree(adma);
|
kfree(adma);
|
||||||
adma = NULL;
|
adma = NULL;
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(tegra_isomgr_adma_unregister);
|
EXPORT_SYMBOL(tegra_isomgr_adma_unregister);
|
||||||
#endif
|
MODULE_AUTHOR("Mohan Kumar <mkumard@nvidia.com>");
|
||||||
|
MODULE_DESCRIPTION("Tegra ADMA Bandwidth Request driver");
|
||||||
MODULE_LICENSE("GPL");
|
MODULE_LICENSE("GPL");
|
||||||
|
|||||||
@@ -18,18 +18,9 @@
|
|||||||
|
|
||||||
#ifndef __TEGRA_ISOMGR_BW_H__
|
#ifndef __TEGRA_ISOMGR_BW_H__
|
||||||
#define __TEGRA_ISOMGR_BW_H__
|
#define __TEGRA_ISOMGR_BW_H__
|
||||||
|
void tegra_isomgr_adma_register(struct device *dev);
|
||||||
#if defined(CONFIG_TEGRA_ISOMGR) && defined(CONFIG_NV_TEGRA_MC)
|
void tegra_isomgr_adma_unregister(struct device *dev);
|
||||||
void tegra_isomgr_adma_register(void);
|
|
||||||
void tegra_isomgr_adma_unregister(void);
|
|
||||||
void tegra_isomgr_adma_setbw(struct snd_pcm_substream *substream,
|
void tegra_isomgr_adma_setbw(struct snd_pcm_substream *substream,
|
||||||
bool is_running);
|
bool is_running);
|
||||||
void tegra_isomgr_adma_renegotiate(void *p, u32 avail_bw);
|
void tegra_isomgr_adma_renegotiate(void *p, u32 avail_bw);
|
||||||
#else
|
|
||||||
static inline void tegra_isomgr_adma_register(void) { return; }
|
|
||||||
static inline void tegra_isomgr_adma_unregister(void) { return; }
|
|
||||||
static inline void tegra_isomgr_adma_setbw(struct snd_pcm_substream *substream,
|
|
||||||
bool is_running) { return; }
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
Reference in New Issue
Block a user