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:
Mohan Kumar
2020-09-04 14:32:18 +05:30
committed by Sameer Pujar
parent 79d734adb3
commit 30706b0cef
4 changed files with 85 additions and 56 deletions

View File

@@ -268,7 +268,6 @@ 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,7 +278,6 @@ 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);
} }
@@ -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);

View File

@@ -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 {

View File

@@ -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;
} }
if (adma->icc_path_handle)
icc_set_bw(adma->icc_path_handle, adma->current_bandwidth,
adma->current_bandwidth);
#if IS_ENABLED(CONFIG_TEGRA_ISOMGR) && IS_ENABLED(CONFIG_NV_TEGRA_MC)
if (adma->isomgr_handle) {
int ret;
ret = adma_isomgr_request(adma->current_bandwidth, 1000); ret = adma_isomgr_request(adma->current_bandwidth, 1000);
if (!ret) { if (!ret) {
/* Call LA/PTSA driver which will configure the Memory /* Call LA/PTSA driver which will configure the
controller to support APEDMA's new BW requirement in MBps*/ * Memory controller to support APEDMA's new BW
* requirement in MBps
*/
ret = tegra_set_latency_allowance(TEGRA_LA_APEDMAW, ret = tegra_set_latency_allowance(TEGRA_LA_APEDMAW,
((adma->current_bandwidth + 999)/1000)); ((adma->current_bandwidth + 999)/1000));
if (ret) if (ret)
pr_err("%s: LA/PTSA setting Failed\n", __func__); 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);
switch (tegra_get_chip_id()) {
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.*/ /* Register the required BW for adma usecases.*/
adma->isomgr_handle = tegra_isomgr_register(TEGRA_ISO_CLIENT_APE_ADMA, 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");

View File

@@ -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