video: tegra: gk20a: add elpg_enable sysfs node
Prashant Malani [Tue, 17 Sep 2013 21:31:57 +0000 (14:31 -0700)]
Add the ability to toggle elpg on/off at runtime.

Bug 1365937

Change-Id: I2cae49f0eddd116406c50e87a61b6cfab49c4fdf
Signed-off-by: Prashant Malani <pmalani@nvidia.com>
(cherry picked from commit beb42c16d939d2df932dcd174ba38b888ad93b46)
Signed-off-by: Ajay Nandakumar <anandakumarm@nvidia.com>

drivers/video/tegra/host/gk20a/gk20a.c
drivers/video/tegra/host/gk20a/gk20a.h
drivers/video/tegra/host/gk20a/gk20a_sysfs.c
drivers/video/tegra/host/gk20a/pmu_gk20a.c

index e28eaf0..13610b3 100644 (file)
@@ -890,6 +890,7 @@ static int gk20a_probe(struct platform_device *dev)
        gk20a->slcg_enabled = true;
        gk20a->blcg_enabled = true;
        gk20a->elcg_enabled = true;
+       gk20a->elpg_enabled = true;
 
        gk20a_create_sysfs(dev);
 
index 066b7aa..3249467 100644 (file)
@@ -88,6 +88,7 @@ struct gk20a {
        bool slcg_enabled;
        bool blcg_enabled;
        bool elcg_enabled;
+       bool elpg_enabled;
 
 #ifdef CONFIG_DEBUG_FS
        spinlock_t debugfs_lock;
index d2ab2ff..62ad816 100644 (file)
@@ -176,12 +176,54 @@ static DEVICE_ATTR(ptimer_scale_factor,
                        ptimer_scale_factor_show,
                        NULL);
 
+static ssize_t elpg_enable_store(struct device *device,
+       struct device_attribute *attr, const char *buf, size_t count)
+{
+       struct platform_device *ndev = to_platform_device(device);
+       struct gk20a *g = get_gk20a(ndev);
+       unsigned long val = 0;
+
+       if (kstrtoul(buf, 10, &val) < 0)
+               return -EINVAL;
+
+       /*
+        * Since elpg is refcounted, we should not unnecessarily call
+        * enable/disable if it is already so.
+        */
+       nvhost_module_busy(g->dev);
+       if (val && !g->elpg_enabled) {
+               g->elpg_enabled = true;
+               gk20a_pmu_enable_elpg(g);
+       } else if (!val && g->elpg_enabled) {
+               g->elpg_enabled = false;
+               gk20a_pmu_disable_elpg(g);
+       }
+       nvhost_module_idle(g->dev);
+
+       dev_info(device, "ELPG is %s.\n", g->elpg_enabled ? "enabled" :
+                       "disabled");
+
+       return count;
+}
+
+static ssize_t elpg_enable_read(struct device *device,
+       struct device_attribute *attr, char *buf)
+{
+       struct platform_device *ndev = to_platform_device(device);
+       struct gk20a *g = get_gk20a(ndev);
+
+       return sprintf(buf, "%d\n", g->elpg_enabled ? 1 : 0);
+}
+
+static DEVICE_ATTR(elpg_enable, S_IRWXUGO, elpg_enable_read, elpg_enable_store);
+
 void gk20a_remove_sysfs(struct device *dev)
 {
        device_remove_file(dev, &dev_attr_elcg_enable);
        device_remove_file(dev, &dev_attr_blcg_enable);
        device_remove_file(dev, &dev_attr_slcg_enable);
        device_remove_file(dev, &dev_attr_ptimer_scale_factor);
+       device_remove_file(dev, &dev_attr_elpg_enable);
 }
 
 void gk20a_create_sysfs(struct platform_device *dev)
@@ -192,6 +234,7 @@ void gk20a_create_sysfs(struct platform_device *dev)
        error |= device_create_file(&dev->dev, &dev_attr_blcg_enable);
        error |= device_create_file(&dev->dev, &dev_attr_slcg_enable);
        error |= device_create_file(&dev->dev, &dev_attr_ptimer_scale_factor);
+       error |= device_create_file(&dev->dev, &dev_attr_elpg_enable);
 
        if (error)
                dev_err(&dev->dev, "Failed to create sysfs attributes!\n");
index 832909e..736dddf 100644 (file)
@@ -2420,6 +2420,9 @@ int gk20a_pmu_enable_elpg(struct gk20a *g)
                goto exit_unlock;
        }
 
+       if (!g->elpg_enabled)
+               goto exit_unlock;
+
        /* do NOT enable elpg until golden ctx is created,
           which is related with the ctx that ELPG save and restore. */
        if (unlikely(!gr->ctx_vars.golden_image_initialized)) {