nvadsp: Add Interconnect support for ADSP

Add Interconnect API support for ADSP 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.

Added code check with K5.9 as mc_utils.h header is present from K5.9 build

For Kernel 4.9 and earlier

- T23x will not be supported.
- T194 and earlier platforms will use BWMGR. Interconnect framework is not
  available.

JIRA TAS-1060

Change-Id: Ie0b4040f374a3c6102cb7aff2506d8cf2f0eab69
Signed-off-by: Mohan Kumar <mkumard@nvidia.com>
Reviewed-on: https://git-master.nvidia.com/r/c/linux-nvidia/+/2414369
Reviewed-by: Viswanath L <viswanathl@nvidia.com>
Reviewed-by: Sameer Pujar <spujar@nvidia.com>
Reviewed-by: Sharad Gupta <sharadg@nvidia.com>
Reviewed-by: mobile promotions <svcmobile_promotions@nvidia.com>
GVS: Gerrit_Virtual_Submit
Tested-by: mobile promotions <svcmobile_promotions@nvidia.com>
This commit is contained in:
Mohan Kumar
2020-09-16 12:47:36 +05:30
committed by Laxman Dewangan
parent 3b69d4961c
commit 4464d26007
4 changed files with 91 additions and 34 deletions

View File

@@ -3,7 +3,7 @@
* *
* adsp dynamic frequency scaling * adsp dynamic frequency scaling
* *
* Copyright (C) 2014-2019, NVIDIA Corporation. All rights reserved. * Copyright (C) 2014-2020, NVIDIA Corporation. All rights reserved.
* *
* This software is licensed under the terms of the GNU General Public * This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and * License version 2, as published by the Free Software Foundation, and
@@ -361,10 +361,8 @@ static unsigned long update_freq(unsigned long freq_khz)
efreq = adsp_to_emc_freq(tfreq_hz / 1000); efreq = adsp_to_emc_freq(tfreq_hz / 1000);
ret = tegra_bwmgr_set_emc(drv->bwmgr, efreq * 1000, ret = nvadsp_set_bw(drv, efreq);
TEGRA_BWMGR_SET_EMC_FLOOR);
if (ret) { if (ret) {
dev_err(device, "failed to set emc freq rate:%d\n", ret);
policy->update_freq_flag = false; policy->update_freq_flag = false;
goto err_out; goto err_out;
} }
@@ -401,13 +399,10 @@ err_out:
efreq = adsp_to_emc_freq(old_freq_khz); efreq = adsp_to_emc_freq(old_freq_khz);
ret = tegra_bwmgr_set_emc(drv->bwmgr, efreq * 1000, ret = nvadsp_set_bw(drv, efreq);
TEGRA_BWMGR_SET_EMC_FLOOR); if (ret)
if (ret) {
dev_err(device, "failed to set emc freq rate:%d\n",
ret);
policy->update_freq_flag = false; policy->update_freq_flag = false;
}
tfreq_hz = old_freq_khz * 1000; tfreq_hz = old_freq_khz * 1000;
} }
return tfreq_hz / 1000; return tfreq_hz / 1000;
@@ -829,12 +824,9 @@ int adsp_dfs_core_init(struct platform_device *pdev)
efreq = adsp_to_emc_freq(policy->cur); efreq = adsp_to_emc_freq(policy->cur);
ret = tegra_bwmgr_set_emc(drv->bwmgr, efreq * 1000, ret = nvadsp_set_bw(drv, efreq);
TEGRA_BWMGR_SET_EMC_FLOOR); if (ret)
if (ret) {
dev_err(device, "failed to set emc freq rate:%d\n", ret);
goto end; goto end;
}
adsp_get_target_freq(policy->cur * 1000, &freq_stats.last_index); adsp_get_target_freq(policy->cur * 1000, &freq_stats.last_index);
freq_stats.last_time = get_jiffies_64(); freq_stats.last_time = get_jiffies_64();

View File

@@ -136,6 +136,73 @@ uint64_t nvadsp_get_timestamp_counter(void)
} }
EXPORT_SYMBOL(nvadsp_get_timestamp_counter); EXPORT_SYMBOL(nvadsp_get_timestamp_counter);
int nvadsp_set_bw(struct nvadsp_drv_data *drv_data, u32 efreq)
{
int ret = -EINVAL;
if (drv_data->bwmgr)
ret = tegra_bwmgr_set_emc(drv_data->bwmgr, efreq * 1000,
TEGRA_BWMGR_SET_EMC_FLOOR);
#if KERNEL_VERSION(5, 9, 0) <= LINUX_VERSION_CODE
else if (drv_data->icc_path_handle)
ret = icc_set_bw(drv_data->icc_path_handle, 0,
(unsigned long)FREQ2ICC(efreq * 1000));
#endif
if (ret)
dev_err(&drv_data->pdev->dev,
"failed to set emc freq rate:%d\n", ret);
return ret;
}
static void nvadsp_bw_register(struct nvadsp_drv_data *drv_data)
{
struct device *dev = &drv_data->pdev->dev;
switch (tegra_get_chip_id()) {
case TEGRA210:
case TEGRA186:
case TEGRA194:
drv_data->bwmgr = tegra_bwmgr_register(
TEGRA_BWMGR_CLIENT_APE_ADSP);
if (IS_ERR(drv_data->bwmgr)) {
dev_err(dev, "unable to register bwmgr\n");
drv_data->bwmgr = NULL;
}
break;
default:
#if KERNEL_VERSION(5, 9, 0) <= LINUX_VERSION_CODE
/* Interconnect Support */
drv_data->icc_path_handle = icc_get(dev, TEGRA_ICC_APE,
TEGRA_ICC_PRIMARY);
if (IS_ERR(drv_data->icc_path_handle)) {
dev_err(dev,
"%s: Failed to register Interconnect. err=%ld\n",
__func__, PTR_ERR(drv_data->icc_path_handle));
drv_data->icc_path_handle = NULL;
}
#endif
break;
}
}
static void nvadsp_bw_unregister(struct nvadsp_drv_data *drv_data)
{
nvadsp_set_bw(drv_data, 0);
if (drv_data->bwmgr) {
tegra_bwmgr_unregister(drv_data->bwmgr);
drv_data->bwmgr = NULL;
}
#if KERNEL_VERSION(5, 9, 0) <= LINUX_VERSION_CODE
if (drv_data->icc_path_handle) {
icc_put(drv_data->icc_path_handle);
drv_data->icc_path_handle = NULL;
}
#endif
}
static void __init nvadsp_parse_clk_entries(struct platform_device *pdev) static void __init nvadsp_parse_clk_entries(struct platform_device *pdev)
{ {
struct nvadsp_drv_data *drv_data = platform_get_drvdata(pdev); struct nvadsp_drv_data *drv_data = platform_get_drvdata(pdev);
@@ -376,10 +443,7 @@ static int __init nvadsp_probe(struct platform_device *pdev)
if (ret) if (ret)
dev_err(dev, "Failed to init aram\n"); dev_err(dev, "Failed to init aram\n");
drv_data->bwmgr = tegra_bwmgr_register(TEGRA_BWMGR_CLIENT_APE_ADSP); nvadsp_bw_register(drv_data);
ret = IS_ERR_OR_NULL(drv_data->bwmgr);
if (ret)
dev_err(&pdev->dev, "unable to register bwmgr\n");
err: err:
#ifdef CONFIG_PM #ifdef CONFIG_PM
ret = pm_runtime_put_sync(dev); ret = pm_runtime_put_sync(dev);
@@ -393,17 +457,9 @@ out:
static int nvadsp_remove(struct platform_device *pdev) static int nvadsp_remove(struct platform_device *pdev)
{ {
struct nvadsp_drv_data *drv_data = platform_get_drvdata(pdev); struct nvadsp_drv_data *drv_data = platform_get_drvdata(pdev);
int err;
if (drv_data->bwmgr) { nvadsp_bw_unregister(drv_data);
err = tegra_bwmgr_set_emc(drv_data->bwmgr, 0,
TEGRA_BWMGR_SET_EMC_FLOOR);
if (err) {
dev_err(&pdev->dev, "failed to set emc freq rate:%d\n",
err);
}
tegra_bwmgr_unregister(drv_data->bwmgr);
}
nvadsp_aram_exit(); nvadsp_aram_exit();
pm_runtime_disable(&pdev->dev); pm_runtime_disable(&pdev->dev);

View File

@@ -3,7 +3,7 @@
* *
* A header file for Host driver for ADSP and APE * A header file for Host driver for ADSP and APE
* *
* Copyright (C) 2014-2019, NVIDIA Corporation. All rights reserved. * Copyright (C) 2014-2020, NVIDIA Corporation. All rights reserved.
* *
* This software is licensed under the terms of the GNU General Public * This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and * License version 2, as published by the Free Software Foundation, and
@@ -25,6 +25,11 @@
#include <linux/debugfs.h> #include <linux/debugfs.h>
#include <linux/platform/tegra/emc_bwmgr.h> #include <linux/platform/tegra/emc_bwmgr.h>
#if KERNEL_VERSION(5, 9, 0) <= LINUX_VERSION_CODE
#include <linux/platform/tegra/mc_utils.h>
#include <dt-bindings/interconnect/tegra_icc_id.h>
#include <linux/interconnect.h>
#endif
#include "hwmailbox.h" #include "hwmailbox.h"
#include "amc.h" #include "amc.h"
@@ -89,6 +94,9 @@ enum adsp_unit_fpga_reset {
#define AMISC_REG_MBOX_OFFSET 0x64 #define AMISC_REG_MBOX_OFFSET 0x64
#define ADSP_ACTMON_REG_START_OFFSET 0x800 #define ADSP_ACTMON_REG_START_OFFSET 0x800
#define ADSP_ACTMON_REG_END_OFFSET 0x828 #define ADSP_ACTMON_REG_END_OFFSET 0x828
#if KERNEL_VERSION(5, 9, 0) <= LINUX_VERSION_CODE
#define FREQ2ICC(x) (Bps_to_icc(emc_freq_to_bw(x)))
#endif
enum nvadsp_virqs { enum nvadsp_virqs {
MBOX_SEND_VIRQ, MBOX_SEND_VIRQ,
@@ -214,6 +222,9 @@ struct nvadsp_drv_data {
int agic_irqs[NVADSP_VIRQ_MAX]; int agic_irqs[NVADSP_VIRQ_MAX];
struct tegra_bwmgr_client *bwmgr; struct tegra_bwmgr_client *bwmgr;
#if KERNEL_VERSION(5, 9, 0) <= LINUX_VERSION_CODE
struct icc_path *icc_path_handle; /* icc_path handle handle */
#endif
u32 evp_base[ADSP_EVP_END]; u32 evp_base[ADSP_EVP_END];
const struct nvadsp_chipdata *chip_data; const struct nvadsp_chipdata *chip_data;
@@ -227,6 +238,7 @@ status_t nvadsp_mbox_init(struct platform_device *pdev);
int nvadsp_setup_amc_interrupts(struct platform_device *pdev); int nvadsp_setup_amc_interrupts(struct platform_device *pdev);
void nvadsp_free_amc_interrupts(struct platform_device *pdev); void nvadsp_free_amc_interrupts(struct platform_device *pdev);
int nvadsp_set_bw(struct nvadsp_drv_data *drv, u32 efreq);
#ifdef CONFIG_TEGRA_ADSP_DFS #ifdef CONFIG_TEGRA_ADSP_DFS
void adsp_cpu_set_rate(unsigned long freq); void adsp_cpu_set_rate(unsigned long freq);

View File

@@ -936,10 +936,7 @@ static int nvadsp_set_ape_emc_freq(struct nvadsp_drv_data *drv_data)
if (!ape_emc_freq) if (!ape_emc_freq)
return 0; return 0;
ret = tegra_bwmgr_set_emc(drv_data->bwmgr, ape_emc_freq * 1000, ret = nvadsp_set_bw(drv_data, ape_emc_freq);
TEGRA_BWMGR_SET_EMC_FLOOR);
if (ret)
dev_err(dev, "failed to set emc freq rate:%d\n", ret);
dev_dbg(dev, "ape.emc freq %luKHz\n", dev_dbg(dev, "ape.emc freq %luKHz\n",
tegra_bwmgr_get_emc_rate() / 1000); tegra_bwmgr_get_emc_rate() / 1000);