drm/tegra: Enabling ICC for NVDEC

In order to avoid the NVDEC performance bottleneck from EMC,
NVDEC needs to ask for the required memory bandwidth for itself
according to its current frequency and load.

Bug 4097374

Signed-off-by: Johnny Liu <johnliu@nvidia.com>
Change-Id: I2daff5d3616db03d7576e8e9433aebbf3d566e86
Reviewed-on: https://git-master.nvidia.com/r/c/linux-nv-oot/+/2914610
Reviewed-by: Mikko Perttunen <mperttunen@nvidia.com>
GVS: Gerrit_Virtual_Submit <buildbot_gerritrpt@nvidia.com>
This commit is contained in:
Johnny Liu
2023-06-02 06:42:58 +00:00
committed by mobile promotions
parent 856af79422
commit 6fc7c1ad7c

View File

@@ -9,6 +9,7 @@
#include <linux/devfreq/tegra_wmark.h> #include <linux/devfreq/tegra_wmark.h>
#include <linux/dma-mapping.h> #include <linux/dma-mapping.h>
#include <linux/host1x-next.h> #include <linux/host1x-next.h>
#include <linux/interconnect.h>
#include <linux/iommu.h> #include <linux/iommu.h>
#include <linux/iopoll.h> #include <linux/iopoll.h>
#include <linux/module.h> #include <linux/module.h>
@@ -19,6 +20,7 @@
#include <linux/pm_opp.h> #include <linux/pm_opp.h>
#include <linux/pm_runtime.h> #include <linux/pm_runtime.h>
#include <linux/reset.h> #include <linux/reset.h>
#include <linux/version.h>
#include <soc/tegra/mc.h> #include <soc/tegra/mc.h>
@@ -33,6 +35,7 @@
#define NVDEC_FALCON_DEBUGINFO 0x1094 #define NVDEC_FALCON_DEBUGINFO 0x1094
#define NVDEC_TFBIF_TRANSCFG 0x2c44 #define NVDEC_TFBIF_TRANSCFG 0x2c44
#define NVDEC_TFBIF_ACTMON_ACTIVE_WEIGHT 0x2c54 #define NVDEC_TFBIF_ACTMON_ACTIVE_WEIGHT 0x2c54
#define NVDEC_AXI_RW_BANDWIDTH 512
struct nvdec_config { struct nvdec_config {
const char *firmware; const char *firmware;
@@ -55,6 +58,7 @@ struct nvdec {
struct reset_control *reset; struct reset_control *reset;
struct devfreq *devfreq; struct devfreq *devfreq;
struct devfreq_dev_profile *devfreq_profile; struct devfreq_dev_profile *devfreq_profile;
struct icc_path *icc_write;
/* Platform configuration */ /* Platform configuration */
const struct nvdec_config *config; const struct nvdec_config *config;
@@ -80,7 +84,7 @@ static int nvdec_set_rate(struct nvdec *nvdec, unsigned long rate)
struct nvdec_config *config = nvdec->config; struct nvdec_config *config = nvdec->config;
struct host1x_client *client = &nvdec->client.base; struct host1x_client *client = &nvdec->client.base;
unsigned long dev_rate; unsigned long dev_rate;
u32 weight; u32 weight, emc_kbps;
int err; int err;
err = clk_set_rate(nvdec->clks[0].clk, rate); err = clk_set_rate(nvdec->clks[0].clk, rate);
@@ -89,6 +93,13 @@ static int nvdec_set_rate(struct nvdec *nvdec, unsigned long rate)
dev_rate = clk_get_rate(nvdec->clks[0].clk); dev_rate = clk_get_rate(nvdec->clks[0].clk);
if (nvdec->icc_write) {
emc_kbps = dev_rate * NVDEC_AXI_RW_BANDWIDTH / 1024;
err = icc_set_bw(nvdec->icc_write, kbps_to_icc(emc_kbps), 0);
if (err)
dev_warn(nvdec->dev, "failed to set icc bw: %d\n", err);
}
host1x_actmon_update_client_rate(client, dev_rate, &weight); host1x_actmon_update_client_rate(client, dev_rate, &weight);
if (!weight) if (!weight)
@@ -534,6 +545,7 @@ disable:
static __maybe_unused int nvdec_runtime_suspend(struct device *dev) static __maybe_unused int nvdec_runtime_suspend(struct device *dev)
{ {
struct nvdec *nvdec = dev_get_drvdata(dev); struct nvdec *nvdec = dev_get_drvdata(dev);
int err;
devfreq_suspend_device(nvdec->devfreq); devfreq_suspend_device(nvdec->devfreq);
@@ -541,6 +553,12 @@ static __maybe_unused int nvdec_runtime_suspend(struct device *dev)
clk_bulk_disable_unprepare(nvdec->num_clks, nvdec->clks); clk_bulk_disable_unprepare(nvdec->num_clks, nvdec->clks);
if (nvdec->icc_write) {
err = icc_set_bw(nvdec->icc_write, 0, 0);
if (err)
dev_warn(nvdec->dev, "failed to set icc bw: %d\n", err);
}
return 0; return 0;
} }
@@ -716,6 +734,17 @@ static int nvdec_probe(struct platform_device *pdev)
return err; return err;
} }
nvdec->icc_write = devm_of_icc_get(dev, "write");
#if LINUX_VERSION_CODE < KERNEL_VERSION(6, 2, 0)
if (IS_ERR(nvdec->icc_write)) {
dev_err(&pdev->dev, "failed to get icc write handle\n");
return PTR_ERR(nvdec->icc_write);
}
#else
if (IS_ERR(nvdec->icc_write))
nvdec->icc_write = NULL;
#endif
platform_set_drvdata(pdev, nvdec); platform_set_drvdata(pdev, nvdec);
INIT_LIST_HEAD(&nvdec->client.base.list); INIT_LIST_HEAD(&nvdec->client.base.list);
@@ -744,13 +773,13 @@ static int nvdec_probe(struct platform_device *pdev)
err = clk_set_rate(nvdec->clks[0].clk, ULONG_MAX); err = clk_set_rate(nvdec->clks[0].clk, ULONG_MAX);
if (err < 0) { if (err < 0) {
dev_err(&pdev->dev, "failed to set clock rate: %d\n", err); dev_err(&pdev->dev, "failed to set clock rate: %d\n", err);
return err; goto exit_falcon;
} }
err = nvdec_devfreq_init(nvdec); err = nvdec_devfreq_init(nvdec);
if (err < 0) { if (err < 0) {
dev_err(&pdev->dev, "failed to init devfreq: %d\n", err); dev_err(&pdev->dev, "failed to init devfreq: %d\n", err);
return err; goto exit_falcon;
} }
pm_runtime_enable(dev); pm_runtime_enable(dev);
@@ -761,6 +790,7 @@ static int nvdec_probe(struct platform_device *pdev)
exit_falcon: exit_falcon:
falcon_exit(&nvdec->falcon); falcon_exit(&nvdec->falcon);
icc_put(nvdec->icc_write);
return err; return err;
} }
@@ -788,6 +818,8 @@ static int nvdec_remove(struct platform_device *pdev)
falcon_exit(&nvdec->falcon); falcon_exit(&nvdec->falcon);
icc_put(nvdec->icc_write);
return 0; return 0;
} }