summaryrefslogtreecommitdiff
path: root/drivers/video/tegra
diff options
context:
space:
mode:
authorIlan Aelion <iaelion@nvidia.com>2012-07-16 17:31:57 -0600
committerLokesh Pathak <lpathak@nvidia.com>2012-07-30 09:39:41 -0700
commit859f9bddcb10fd1fe2890a59181f8388facd1117 (patch)
treedeab6447181d8414ec6e37408c86c913648583c4 /drivers/video/tegra
parent97f9f654114aad07c828b05d057a11e03b1af803 (diff)
video: tegra: host: adding throughput hint in 3dfs
adding support for using a throughput hint given by the tegra-gfx misc device in the 3d scaling code. If throughput hint usage is enabled and the latest throughput hint is recent enough (less than 1 second old), the throughput hint is used to control 3d frequency scaling. Otherwise the existing idle time percentage estimate is used. Bug 991589 Change-Id: I68893e5ce7ef922b95ce5f5b3664eb8e1fdd4027 Signed-off-by: Ilan Aelion <iaelion@nvidia.com> Reviewed-on: http://git-master/r/116866 Reviewed-by: Lokesh Pathak <lpathak@nvidia.com> Tested-by: Lokesh Pathak <lpathak@nvidia.com>
Diffstat (limited to 'drivers/video/tegra')
-rw-r--r--drivers/video/tegra/host/gr3d/scale3d.c87
1 files changed, 87 insertions, 0 deletions
diff --git a/drivers/video/tegra/host/gr3d/scale3d.c b/drivers/video/tegra/host/gr3d/scale3d.c
index 5922b55..025c7e0 100644
--- a/drivers/video/tegra/host/gr3d/scale3d.c
+++ b/drivers/video/tegra/host/gr3d/scale3d.c
@@ -85,9 +85,14 @@ struct scale3d_info_rec {
long emc_dip_offset;
long emc_xmid;
unsigned long min_rate_3d;
+ ktime_t last_throughput_hint;
struct work_struct work;
struct delayed_work idle_timer;
unsigned int scale;
+ unsigned int p_use_throughput_hint;
+ unsigned int p_throughput_lo_limit;
+ unsigned int p_throughput_hi_limit;
+ unsigned int p_scale_step;
unsigned int p_period;
unsigned int period;
unsigned int p_idle_min;
@@ -382,6 +387,13 @@ void nvhost_scale3d_notify_idle(struct nvhost_device *dev)
if (!scale3d.enable)
return;
+ /* if throughput hint enabled, and last hint is recent enough, return */
+ if (scale3d.p_use_throughput_hint) {
+ t = ktime_get();
+ if (ktime_us_delta(t, scale3d.last_throughput_hint) < 1000000)
+ return;
+ }
+
mutex_lock(&scale3d.lock);
t = ktime_get();
@@ -416,6 +428,13 @@ void nvhost_scale3d_notify_busy(struct nvhost_device *dev)
if (!scale3d.enable)
return;
+ /* if throughput hint enabled, and last hint is recent enough, return */
+ if (scale3d.p_use_throughput_hint) {
+ t = ktime_get();
+ if (ktime_us_delta(t, scale3d.last_throughput_hint) < 1000000)
+ return;
+ }
+
mutex_lock(&scale3d.lock);
cancel_delayed_work(&scale3d.idle_timer);
@@ -437,6 +456,66 @@ void nvhost_scale3d_notify_busy(struct nvhost_device *dev)
mutex_unlock(&scale3d.lock);
}
+static void do_scale(int diff)
+{
+ unsigned long hz, curr;
+
+ if (!tegra_is_clk_enabled(scale3d.clk_3d))
+ return;
+
+ if (tegra_get_chipid() == TEGRA_CHIPID_TEGRA3)
+ if (!tegra_is_clk_enabled(scale3d.clk_3d2))
+ return;
+
+ curr = clk_get_rate(scale3d.clk_3d);
+ hz = curr + diff;
+
+ if (hz < scale3d.min_rate_3d)
+ hz = scale3d.min_rate_3d;
+
+ if (hz > scale3d.max_rate_3d)
+ hz = scale3d.max_rate_3d;
+
+ if (hz == curr) return;
+
+ if (tegra_get_chipid() == TEGRA_CHIPID_TEGRA3)
+ clk_set_rate(scale3d.clk_3d2, 0);
+ clk_set_rate(scale3d.clk_3d, hz);
+
+ if (scale3d.p_scale_emc) {
+ long after = (long) clk_get_rate(scale3d.clk_3d);
+ hz = after * scale3d.emc_slope + scale3d.emc_offset;
+ if (scale3d.p_emc_dip)
+ hz -=
+ (scale3d.emc_dip_slope *
+ POW2(after / 1000 - scale3d.emc_xmid) +
+ scale3d.emc_dip_offset);
+ clk_set_rate(scale3d.clk_3d_emc, hz);
+ }
+}
+
+#define scale_up() do_scale(scale3d.p_scale_step)
+#define scale_down() do_scale(-scale3d.p_scale_step)
+
+void nvhost_scale3d_set_throughput_hint(int hint)
+{
+ if (!scale3d.enable)
+ return;
+
+ if (!scale3d.p_use_throughput_hint)
+ return;
+
+ scale3d.last_throughput_hint = ktime_get();
+
+ if (scale3d.p_use_throughput_hint) {
+ if (hint >= scale3d.p_throughput_hi_limit)
+ scale_down();
+ else if (hint <= scale3d.p_throughput_lo_limit)
+ scale_up();
+ }
+}
+EXPORT_SYMBOL(nvhost_scale3d_set_throughput_hint);
+
static void scale3d_idle_handler(struct work_struct *work)
{
int notify_idle = 0;
@@ -502,6 +581,10 @@ void nvhost_scale3d_debug_init(struct dentry *de)
CREATE_SCALE3D_FILE(adjust);
CREATE_SCALE3D_FILE(scale_emc);
CREATE_SCALE3D_FILE(emc_dip);
+ CREATE_SCALE3D_FILE(use_throughput_hint);
+ CREATE_SCALE3D_FILE(throughput_hi_limit);
+ CREATE_SCALE3D_FILE(throughput_lo_limit);
+ CREATE_SCALE3D_FILE(scale_step);
CREATE_SCALE3D_FILE(verbosity);
#undef CREATE_SCALE3D_FILE
}
@@ -642,6 +725,10 @@ void nvhost_scale3d_init(struct nvhost_device *d)
scale3d.p_emc_dip = 1;
scale3d.p_verbosity = 0;
scale3d.p_adjust = 1;
+ scale3d.p_use_throughput_hint = 0;
+ scale3d.p_throughput_lo_limit = 95;
+ scale3d.p_throughput_hi_limit = 100;
+ scale3d.p_scale_step = 60000000;
error = device_create_file(&d->dev,
&dev_attr_enable_3d_scaling);