video: tegra: support icc for nvdla

Support memory bandwidth management for NVDLA through ICC framework. The
bandwidth calculation formula is based on the current rate of NVDLA and
the width of AXI data bus between nvdla and DBB.

Bug 4102415

Signed-off-by: Johnny Liu <johnliu@nvidia.com>
Change-Id: I75690269027b07f819cabaaf1a964c61b9033323
Reviewed-on: https://git-master.nvidia.com/r/c/linux-nv-oot/+/2971732
Reviewed-by: Yilin Zhang <yilinz@nvidia.com>
Reviewed-by: Arvind M <am@nvidia.com>
Reviewed-by: Bibek Basu <bbasu@nvidia.com>
GVS: Gerrit_Virtual_Submit <buildbot_gerritrpt@nvidia.com>
This commit is contained in:
Johnny Liu
2023-08-31 08:42:26 +00:00
committed by mobile promotions
parent 8f976ab022
commit 08c0339264
2 changed files with 93 additions and 6 deletions

View File

@@ -893,12 +893,14 @@ static ssize_t clk_cap_store(struct kobject *kobj,
{
struct nvhost_device_data *pdata =
container_of(kobj, struct nvhost_device_data, clk_cap_kobj);
struct nvdla_device *nvdla = pdata->private_data;
/* i is indeed 'index' here after type conversion */
int ret, i = attr - pdata->clk_cap_attrs;
struct clk_bulk_data *clks = &pdata->clks[i];
struct clk *clk = clks->clk;
unsigned long freq_cap;
long freq_cap_signed;
u32 emc_kbps;
ret = kstrtoul(buf, 0, &freq_cap);
if (ret)
@@ -923,6 +925,16 @@ static ssize_t clk_cap_store(struct kobject *kobj,
if (ret < 0)
return ret;
/* Update bandwidth requirement based on dla frequency */
if (i == 0 && nvdla->icc_write && !pm_runtime_suspended(nvdla->dev)) {
freq_cap = clk_get_rate(clk);
emc_kbps = freq_cap * NVDLA_AXI_DBB_BW_BPC / 1024;
ret = icc_set_bw(nvdla->icc_write, kbps_to_icc(emc_kbps), 0);
if (ret)
dev_warn(&nvdla->pdev->dev,
"failed to set icc_write bw: %d\n", ret);
}
return count;
}
@@ -1093,6 +1105,13 @@ static int nvdla_probe(struct platform_device *pdev)
goto err_alloc_nvdla;
}
nvdla_dev->icc_write = devm_of_icc_get(dev, "write");
if (IS_ERR(nvdla_dev->icc_write)) {
dev_info(dev, "failed to get icc write handle\n");
nvdla_dev->icc_write = NULL;
}
nvdla_dev->dev = dev;
nvdla_dev->pdev = pdev;
pdata->pdev = pdev;
mutex_init(&pdata->lock);
@@ -1315,25 +1334,58 @@ static int __exit nvdla_remove(struct platform_device *pdev)
#ifdef CONFIG_PM
static int nvdla_module_runtime_suspend(struct device *dev)
{
if (nvhost_module_pm_ops.runtime_suspend != NULL)
return nvhost_module_pm_ops.runtime_suspend(dev);
struct nvhost_device_data *pdata = dev_get_drvdata(dev);
struct nvdla_device *nvdla = pdata->private_data;
int err;
if (nvhost_module_pm_ops.runtime_suspend != NULL) {
err = nvhost_module_pm_ops.runtime_suspend(dev);
if (!err && nvdla->icc_write) {
err = icc_set_bw(nvdla->icc_write, 0, 0);
if (err)
dev_warn(&nvdla->pdev->dev,
"failed to set icc_write bw: %d\n", err);
return 0;
}
return err;
}
return -EOPNOTSUPP;
}
static int nvdla_module_runtime_resume(struct device *dev)
{
if (nvhost_module_pm_ops.runtime_resume != NULL)
return nvhost_module_pm_ops.runtime_resume(dev);
struct nvhost_device_data *pdata = dev_get_drvdata(dev);
struct nvdla_device *nvdla = pdata->private_data;
struct clk *clk = pdata->clks[0].clk;
unsigned long rate;
u32 emc_kbps;
int err;
if (nvhost_module_pm_ops.runtime_resume != NULL) {
err = nvhost_module_pm_ops.runtime_resume(dev);
if (!err && nvdla->icc_write) {
rate = clk_get_rate(clk);
emc_kbps = rate * NVDLA_AXI_DBB_BW_BPC / 1024;
err = icc_set_bw(nvdla->icc_write, kbps_to_icc(emc_kbps), 0);
if (err)
dev_warn(&nvdla->pdev->dev,
"failed to set icc_write bw: %d\n", err);
return 0;
}
return err;
}
return -EOPNOTSUPP;
}
static int nvdla_module_suspend(struct device *dev)
{
int err = 0;
struct nvhost_device_data *pdata = dev_get_drvdata(dev);
struct nvdla_device *nvdla_dev = pdata->private_data;
int err = 0;
if (nvhost_module_pm_ops.suspend != NULL) {
err = nvhost_module_pm_ops.suspend(dev);
@@ -1349,6 +1401,13 @@ static int nvdla_module_suspend(struct device *dev)
}
}
if (nvdla_dev->icc_write) {
err = icc_set_bw(nvdla_dev->icc_write, 0, 0);
if (err)
dev_warn(&nvdla_dev->pdev->dev,
"failed to set icc_write bw: %d\n", err);
}
/* Mark module to be in suspend state. */
nvdla_dev->is_suspended = true;
@@ -1358,9 +1417,12 @@ fail_nvhost_module_suspend:
static int nvdla_module_resume(struct device *dev)
{
int err = 0;
struct nvhost_device_data *pdata = dev_get_drvdata(dev);
struct nvdla_device *nvdla_dev = pdata->private_data;
struct clk *clk = pdata->clks[0].clk;
unsigned long rate;
u32 emc_kbps;
int err;
/* Confirm if module is in suspend state. */
if (!nvdla_dev->is_suspended) {
@@ -1382,6 +1444,15 @@ static int nvdla_module_resume(struct device *dev)
}
}
if (nvdla_dev->icc_write) {
rate = clk_get_rate(clk);
emc_kbps = rate * NVDLA_AXI_DBB_BW_BPC / 1024;
err = icc_set_bw(nvdla_dev->icc_write, kbps_to_icc(emc_kbps), 0);
if (err)
dev_warn(&nvdla_dev->pdev->dev,
"failed to set icc_write bw: %d\n", err);
}
return 0;
fail_nvhost_module_resume:

View File

@@ -9,6 +9,7 @@
#define __NVHOST_NVDLA_H__
#include <linux/completion.h>
#include <linux/interconnect.h>
#include <linux/mutex.h>
#include <uapi/linux/nvdev_fence.h>
#include <uapi/linux/nvhost_nvdla_ioctl.h>
@@ -191,6 +192,18 @@ enum {
#define MAX_CMD_SIZE SZ_256
#define NVDLA_CMD_OFFSET(index) (MAX_CMD_SIZE * index)
/*
* Client connectivity bandwidth
*/
#define AXI_READ_WIDTH 512
#define AXI_READ_OUTSTAND 512
#define AXI_WRITE_WIDTH 512
#define AXI_WRITE_OUTSTAND 128
#define AXI_WORST_LATENCY 1600
#define NVDLA_AXI_READ_BPC (2*AXI_READ_WIDTH * AXI_READ_OUTSTAND / AXI_WORST_LATENCY)
#define NVDLA_AXI_WRITE_BPC (2*AXI_WRITE_WIDTH * AXI_WRITE_OUTSTAND / AXI_WORST_LATENCY)
#define NVDLA_AXI_DBB_BW_BPC (NVDLA_AXI_READ_BPC + NVDLA_AXI_WRITE_BPC)
/**
* data structure to keep command memory
*
@@ -242,6 +255,7 @@ enum nvdla_submit_mode {
/**
* data structure to keep per DLA engine device data
*
* @dev pointer to device
* @pdev pointer to platform device
* @pool pointer to queue table
* @dbg_mask debug mask for print level
@@ -267,10 +281,12 @@ enum nvdla_submit_mode {
* @ping_lock lock to synchronize the ping operation requests.
*/
struct nvdla_device {
struct device *dev;
struct platform_device *pdev;
struct nvdla_queue_pool *pool;
struct completion cmd_completion;
struct mutex cmd_lock;
struct icc_path *icc_write;
int cmd_status;
int waiting;
u32 dbg_mask;