]> rtime.felk.cvut.cz Git - sojka/nv-tegra/linux-3.10.git/commitdiff
video: tegra: host: gk20a: Remove acm dependency
authorArto Merilainen <amerilainen@nvidia.com>
Fri, 7 Feb 2014 11:07:50 +0000 (13:07 +0200)
committerTerje Bergstrom <tbergstrom@nvidia.com>
Thu, 6 Mar 2014 07:23:44 +0000 (23:23 -0800)
The gk20a driver has relied on nvhost acm functionality. This
patch adds runtime pm and genpd support to gk20a driver itself so
that nvhost acm calls are not used at any point.

This patch does also the /minimal/ binding to not regress scaling
functionality. Dependencies against nvhost_scale still remains.

Bug 1454499

Change-Id: I7d9e4b170b9672ed9469e4fcd53c1a176a5d44ea
Signed-off-by: Arto Merilainen <amerilainen@nvidia.com>
Reviewed-on: http://git-master/r/365423
Reviewed-by: Automatic_Commit_Validation_User
Reviewed-by: Terje Bergstrom <tbergstrom@nvidia.com>
drivers/video/tegra/host/gk20a/channel_gk20a.c
drivers/video/tegra/host/gk20a/channel_gk20a.h
drivers/video/tegra/host/gk20a/gk20a.c
drivers/video/tegra/host/gk20a/gk20a.h
drivers/video/tegra/host/gk20a/gk20a_scale.c
drivers/video/tegra/host/gk20a/gk20a_sysfs.c
drivers/video/tegra/host/gk20a/platform_gk20a.h
drivers/video/tegra/host/gk20a/platform_gk20a_tegra.c
drivers/video/tegra/host/nvhost_intr.c

index 58b83fa0cad75acf133305f13110f5556b3696b1..b5a240cef6929dfa2908bd7025863e60b58dd94d 100644 (file)
@@ -1375,11 +1375,12 @@ static int gk20a_channel_add_job(struct channel_gk20a *c,
        return 0;
 }
 
-void gk20a_channel_update(struct channel_gk20a *c)
+void gk20a_channel_update(struct channel_gk20a *c, int nr_completed)
 {
        struct gk20a *g = c->g;
        struct vm_gk20a *vm = c->vm;
        struct channel_gk20a_job *job, *n;
+       int i;
 
        mutex_lock(&c->jobs_lock);
        list_for_each_entry_safe(job, n, &c->jobs, list) {
@@ -1399,6 +1400,9 @@ void gk20a_channel_update(struct channel_gk20a *c)
                gk20a_channel_idle(g->dev);
        }
        mutex_unlock(&c->jobs_lock);
+
+       for (i = 0; i < nr_completed; i++)
+               gk20a_channel_idle(c->g->dev);
 }
 
 static int gk20a_submit_channel_gpfifo(struct channel_gk20a *c,
index f77968ccea7a32adb7479586b48edab145c21545..606fac4c5943febeada03c4111ab5a34ed49b784 100644 (file)
@@ -144,7 +144,7 @@ static inline bool gk20a_channel_as_bound(struct channel_gk20a *ch)
 }
 int channel_gk20a_commit_va(struct channel_gk20a *c);
 
-void gk20a_channel_update(struct channel_gk20a *c);
+void gk20a_channel_update(struct channel_gk20a *c, int nr_completed);
 int gk20a_init_channel_support(struct gk20a *, u32 chid);
 void gk20a_free_channel(struct channel_gk20a *ch, bool finish);
 bool gk20a_channel_update_and_check_timeout(struct channel_gk20a *ch,
index 8879aac5be69b74a79e041886a6e9372dba9eeec..056b598acdc33b237077e4076e74f3f9178094fc 100644 (file)
@@ -22,6 +22,7 @@
 #include <trace/events/gk20a.h>
 
 #include <linux/highmem.h>
+#include <linux/string.h>
 #include <linux/cdev.h>
 #include <linux/delay.h>
 #include <linux/firmware.h>
@@ -71,6 +72,9 @@
 
 #define GK20A_NUM_CDEVS 5
 
+static int gk20a_pm_finalize_poweron(struct device *dev);
+static int gk20a_pm_prepare_poweroff(struct device *dev);
+
 static inline void set_gk20a(struct platform_device *dev, struct gk20a *gk20a)
 {
        gk20a_get_platform(dev)->g = gk20a;
@@ -695,7 +699,7 @@ static int gk20a_init_client(struct platform_device *dev)
        nvhost_dbg_fn("");
 
 #ifndef CONFIG_PM_RUNTIME
-       nvhost_gk20a_finalize_poweron(dev);
+       gk20a_pm_finalize_poweron(&dev->dev);
 #endif
 
        err = gk20a_init_mm_setup_sw(g);
@@ -711,7 +715,7 @@ static void gk20a_deinit_client(struct platform_device *dev)
 {
        nvhost_dbg_fn("");
 #ifndef CONFIG_PM_RUNTIME
-       nvhost_gk20a_prepare_poweroff(dev);
+       gk20a_pm_prepare_poweroff(&dev->dev);
 #endif
 }
 
@@ -738,8 +742,9 @@ void gk20a_put_client(struct gk20a *g)
        WARN_ON(g->client_refcount < 0);
 }
 
-int nvhost_gk20a_prepare_poweroff(struct platform_device *dev)
+static int gk20a_pm_prepare_poweroff(struct device *_dev)
 {
+       struct platform_device *dev = to_platform_device(_dev);
        struct gk20a *g = get_gk20a(dev);
        int ret = 0;
 
@@ -791,8 +796,9 @@ static void gk20a_detect_chip(struct gk20a *g)
                        g->gpu_characteristics.rev);
 }
 
-int nvhost_gk20a_finalize_poweron(struct platform_device *dev)
+static int gk20a_pm_finalize_poweron(struct device *_dev)
 {
+       struct platform_device *dev = to_platform_device(_dev);
        struct gk20a *g = get_gk20a(dev);
        int err, nice_value;
 
@@ -1146,6 +1152,153 @@ struct channel_gk20a *gk20a_get_channel_from_file(int fd)
        return ch;
 }
 
+static int gk20a_pm_enable_clk(struct device *dev)
+{
+       int index = 0;
+       struct gk20a_platform *platform;
+
+       platform = dev_get_drvdata(dev);
+       if (!platform)
+               return -EINVAL;
+
+       for (index = 0; index < platform->num_clks; index++) {
+               int err = clk_prepare_enable(platform->clk[index]);
+               if (err)
+                       return -EINVAL;
+       }
+
+       return 0;
+}
+
+static int gk20a_pm_disable_clk(struct device *dev)
+{
+       int index = 0;
+       struct gk20a_platform *platform;
+
+       platform = dev_get_drvdata(dev);
+       if (!platform)
+               return -EINVAL;
+
+       for (index = 0; index < platform->num_clks; index++)
+               clk_disable_unprepare(platform->clk[index]);
+
+       return 0;
+}
+
+#ifdef CONFIG_PM
+const struct dev_pm_ops gk20a_pm_ops = {
+#if defined(CONFIG_PM_RUNTIME) && !defined(CONFIG_PM_GENERIC_DOMAINS)
+       .runtime_resume = gk20a_pm_enable_clk,
+       .runtime_suspend = gk20a_pm_disable_clk,
+#endif
+};
+#endif
+
+static int gk20a_pm_railgate(struct generic_pm_domain *domain)
+{
+       struct gk20a *g = container_of(domain, struct gk20a, pd);
+       struct gk20a_platform *platform = platform_get_drvdata(g->dev);
+       int ret = 0;
+
+       if (platform->railgate)
+               ret = platform->railgate(platform->g->dev);
+
+       return ret;
+}
+
+static int gk20a_pm_unrailgate(struct generic_pm_domain *domain)
+{
+       struct gk20a *g = container_of(domain, struct gk20a, pd);
+       struct gk20a_platform *platform = platform_get_drvdata(g->dev);
+       int ret = 0;
+
+       if (platform->unrailgate)
+               ret = platform->unrailgate(platform->g->dev);
+
+       return ret;
+}
+
+static int gk20a_pm_suspend(struct device *dev)
+{
+       struct gk20a_platform *platform = dev_get_drvdata(dev);
+       int ret = 0;
+
+       if (atomic_read(&dev->power.usage_count) > 1)
+               return -EBUSY;
+
+       ret = gk20a_pm_prepare_poweroff(dev);
+       if (ret)
+               return ret;
+
+       if (platform->suspend)
+               platform->suspend(dev);
+
+       return 0;
+}
+
+
+static int gk20a_pm_initialise_domain(struct platform_device *pdev)
+{
+       struct gk20a_platform *platform = platform_get_drvdata(pdev);
+       struct dev_power_governor *pm_domain_gov = NULL;
+       struct generic_pm_domain *domain = &platform->g->pd;
+       int ret = 0;
+
+       domain->name = kstrdup(pdev->name, GFP_KERNEL);
+
+       if (!platform->can_railgate)
+               pm_domain_gov = &pm_domain_always_on_gov;
+
+       pm_genpd_init(domain, pm_domain_gov, true);
+
+       domain->power_off = gk20a_pm_railgate;
+       domain->power_on = gk20a_pm_unrailgate;
+       domain->dev_ops.start = gk20a_pm_enable_clk;
+       domain->dev_ops.stop = gk20a_pm_disable_clk;
+       domain->dev_ops.save_state = gk20a_pm_prepare_poweroff;
+       domain->dev_ops.restore_state = gk20a_pm_finalize_poweron;
+       domain->dev_ops.suspend = gk20a_pm_suspend;
+       domain->dev_ops.resume = gk20a_pm_finalize_poweron;
+
+       device_set_wakeup_capable(&pdev->dev, 0);
+       ret = pm_genpd_add_device(domain, &pdev->dev);
+
+       if (platform->railgate_delay)
+               pm_genpd_set_poweroff_delay(domain, platform->railgate_delay);
+
+       return ret;
+}
+
+static int gk20a_pm_init(struct platform_device *dev)
+{
+       struct gk20a_platform *platform = platform_get_drvdata(dev);
+       int err = 0;
+
+       /* Initialise pm runtime */
+       if (platform->clockgate_delay) {
+               pm_runtime_set_autosuspend_delay(&dev->dev,
+                                                platform->clockgate_delay);
+               pm_runtime_use_autosuspend(&dev->dev);
+       }
+
+       pm_runtime_enable(&dev->dev);
+       if (!pm_runtime_enabled(&dev->dev))
+               gk20a_pm_enable_clk(&dev->dev);
+
+       /* Enable runtime railgating if possible. If not,
+        * turn on the rail now. */
+       if (platform->can_railgate && IS_ENABLED(CONFIG_PM_GENERIC_DOMAINS))
+               platform->railgate(dev);
+       else
+               platform->unrailgate(dev);
+
+       /* genpd will take care of runtime power management if it is enabled */
+       if (IS_ENABLED(CONFIG_PM_GENERIC_DOMAINS))
+               err = gk20a_pm_initialise_domain(dev);
+
+       return err;
+}
+
 static int gk20a_probe(struct platform_device *dev)
 {
        struct gk20a *gk20a;
@@ -1198,6 +1351,20 @@ static int gk20a_probe(struct platform_device *dev)
                return err;
        }
 
+       err = gk20a_pm_init(dev);
+       if (err) {
+               dev_err(&dev->dev, "pm init failed");
+               return err;
+       }
+
+       if (platform->late_probe) {
+               err = platform->late_probe(dev);
+               if (err) {
+                       dev_err(&dev->dev, "late probe failed");
+                       return err;
+               }
+       }
+
        gpu_cdev = &gk20a->gk20a_cdev;
        gpu_cdev->gk20a_freq_table_size = tegra_gpufreq_table_size_get();
        gpu_cdev->gk20a_freq_state = 0;
@@ -1293,7 +1460,7 @@ static struct platform_driver gk20a_driver = {
                .of_match_table = tegra_gk20a_of_match,
 #endif
 #ifdef CONFIG_PM
-               .pm = &nvhost_module_pm_ops,
+               .pm = &gk20a_pm_ops,
 #endif
        }
 };
index 89a36b4f3cfd7fceeef663323a3a0158db8c1b0c..e8892d390305411df9b6ea6e9d2558b23bd3e89c 100644 (file)
@@ -210,6 +210,9 @@ struct gk20a {
 
        int irq_stall;
        int irq_nonstall;
+
+       /* Power domain representing power partition */
+       struct generic_pm_domain pd;
 };
 
 static inline unsigned long gk20a_get_gr_idle_timeout(struct gk20a *g)
@@ -336,9 +339,6 @@ static inline int support_gk20a_pmu(void)
 static inline int support_gk20a_pmu(void){return 0;}
 #endif
 
-int nvhost_gk20a_finalize_poweron(struct platform_device *dev);
-int nvhost_gk20a_prepare_poweroff(struct platform_device *dev);
-
 void gk20a_create_sysfs(struct platform_device *dev);
 
 #ifdef CONFIG_DEBUG_FS
index bd58383216e1b9022cc74c142551d645fce0f6e8..3f833e6ae6a36fa31f0282caa3359812e6bb092a 100644 (file)
@@ -72,12 +72,14 @@ static DEVICE_ATTR(load, S_IRUGO, nvhost_gk20a_scale_load_show, NULL);
 void nvhost_gk20a_scale_callback(struct nvhost_device_profile *profile,
                                 unsigned long freq)
 {
-       struct gk20a *g = get_gk20a(profile->pdev);
+       struct gk20a_platform *platform = platform_get_drvdata(profile->pdev);
        struct nvhost_emc_params *emc_params = profile->private_data;
+       struct gk20a *g = get_gk20a(profile->pdev);
+
        long after = gk20a_clk_get_rate(g);
        long emc_target = nvhost_scale3d_get_emc_rate(emc_params, after);
 
-       nvhost_module_set_devfreq_rate(profile->pdev, 2, emc_target);
+       clk_set_rate(platform->clk[2], emc_target);
 }
 
 /*
index fd3986c1e5129819fc3b139223368dbfe3141d39..df8ea59ea97b7a5961747a941374c256cef02fed 100644 (file)
@@ -176,6 +176,63 @@ static DEVICE_ATTR(ptimer_scale_factor,
                        ptimer_scale_factor_show,
                        NULL);
 
+static ssize_t railgate_delay_store(struct device *dev,
+                                   struct device_attribute *attr,
+                                   const char *buf, size_t count)
+{
+       struct gk20a_platform *platform = dev_get_drvdata(dev);
+       int railgate_delay = 0, ret = 0;
+
+       if (!platform->can_railgate) {
+               dev_info(dev, "does not support power-gating\n");
+               return count;
+       }
+
+       ret = sscanf(buf, "%d", &railgate_delay);
+       if (ret == 1 && railgate_delay >= 0) {
+               struct generic_pm_domain *genpd = pd_to_genpd(dev->pm_domain);
+               platform->railgate_delay = railgate_delay;
+               pm_genpd_set_poweroff_delay(genpd, platform->railgate_delay);
+       } else
+               dev_err(dev, "Invalid powergate delay\n");
+
+       return count;
+}
+static ssize_t railgate_delay_show(struct device *dev,
+                                  struct device_attribute *attr, char *buf)
+{
+       struct gk20a_platform *platform = dev_get_drvdata(dev);
+       return snprintf(buf, PAGE_SIZE, "%d\n", platform->railgate_delay);
+}
+static DEVICE_ATTR(railgate_delay, S_IRWXUGO, railgate_delay_show,
+                  railgate_delay_store);
+
+static ssize_t clockgate_delay_store(struct device *dev,
+                                    struct device_attribute *attr,
+                                    const char *buf, size_t count)
+{
+       struct gk20a_platform *platform = dev_get_drvdata(dev);
+       int clockgate_delay = 0, ret = 0;
+
+       ret = sscanf(buf, "%d", &clockgate_delay);
+       if (ret == 1 && clockgate_delay >= 0) {
+               platform->clockgate_delay = clockgate_delay;
+               pm_runtime_set_autosuspend_delay(dev,
+                                                platform->clockgate_delay);
+       } else
+               dev_err(dev, "Invalid clockgate delay\n");
+
+       return count;
+}
+static ssize_t clockgate_delay_show(struct device *dev,
+                                   struct device_attribute *attr, char *buf)
+{
+       struct gk20a_platform *platform = dev_get_drvdata(dev);
+       return snprintf(buf, PAGE_SIZE, "%d\n", platform->clockgate_delay);
+}
+static DEVICE_ATTR(clockgate_delay, S_IRWXUGO, clockgate_delay_show,
+                  clockgate_delay_store);
+
 static ssize_t counters_show(struct device *dev,
                             struct device_attribute *attr, char *buf)
 {
@@ -256,6 +313,8 @@ void gk20a_remove_sysfs(struct device *dev)
        device_remove_file(dev, &dev_attr_elpg_enable);
        device_remove_file(dev, &dev_attr_counters);
        device_remove_file(dev, &dev_attr_counters_reset);
+       device_remove_file(dev, &dev_attr_railgate_delay);
+       device_remove_file(dev, &dev_attr_clockgate_delay);
 }
 
 void gk20a_create_sysfs(struct platform_device *dev)
@@ -269,6 +328,8 @@ void gk20a_create_sysfs(struct platform_device *dev)
        error |= device_create_file(&dev->dev, &dev_attr_elpg_enable);
        error |= device_create_file(&dev->dev, &dev_attr_counters);
        error |= device_create_file(&dev->dev, &dev_attr_counters_reset);
+       error |= device_create_file(&dev->dev, &dev_attr_railgate_delay);
+       error |= device_create_file(&dev->dev, &dev_attr_clockgate_delay);
 
        if (error)
                dev_err(&dev->dev, "Failed to create sysfs attributes!\n");
index 626b02518fd0618c4c7232e7dbd3fd918e79a0ad..a118a91662583396fd2c86d27de369b44b675dbe 100644 (file)
@@ -38,7 +38,7 @@ struct gk20a_platform {
        struct gk20a *g;
 
        /* Should be populated at probe. */
-       bool can_powergate;
+       bool can_railgate;
 
        /* Should be populated at probe. */
        bool has_syncpoints;
@@ -46,6 +46,17 @@ struct gk20a_platform {
        /* Should be populated by probe. */
        struct dentry *debugfs;
 
+       /* Clock configuration is stored here. Platform probe is responsible
+        * for filling this data. */
+       struct clk *clk[3];
+       int num_clks;
+
+       /* Delay before rail gated */
+       int railgate_delay;
+
+       /* Delay before clock gated */
+       int clockgate_delay;
+
        /* Initialize the platform interface of the gk20a driver.
         *
         * The platform implementation of this function must
@@ -53,9 +64,17 @@ struct gk20a_platform {
         *     state, and
         *   - populate the gk20a_platform structure (a pointer to the
         *     structure can be obtained by calling gk20a_get_platform).
+        *
+        * After this function is finished, the driver will initialise
+        * pm runtime and genpd based on the platform configuration.
         */
        int (*probe)(struct platform_device *dev);
 
+       /* Second stage initialisation - called once all power management
+        * initialisations are done.
+        */
+       int (*late_probe)(struct platform_device *dev);
+
        /* Called before submitting work to the gpu. The platform may use this
         * hook to ensure that any other hw modules that the gpu depends on are
         * powered. The platform implementation must count refs to this call. */
@@ -74,6 +93,16 @@ struct gk20a_platform {
        int (*secure_alloc)(struct platform_device *dev,
                            struct gr_ctx_buffer_desc *desc,
                            size_t size);
+
+       /* Device is going to be suspended */
+       int (*suspend)(struct device *);
+
+       /* Called to turn off the device */
+       int (*railgate)(struct platform_device *dev);
+
+       /* Called to turn on the device */
+       int (*unrailgate)(struct platform_device *dev);
+
 };
 
 static inline struct gk20a_platform *gk20a_get_platform(
index 436fe3d118b105c8cfa02e67ed6de0c908ff2914..e4dcb1c4f51f5ee879ecfaedb9fa06d923f1c011 100644 (file)
 #include "t124/syncpt_t124.h"
 #include "../../../../../arch/arm/mach-tegra/iomap.h"
 #include <linux/tegra-powergate.h>
+#include <linux/platform_data/tegra_edp.h>
 #include <linux/nvhost_ioctl.h>
 #include <linux/dma-buf.h>
 #include <linux/nvmap.h>
 #include <mach/irqs.h>
+#include <mach/pm_domains.h>
 
 #include "gk20a.h"
 #include "hal_gk20a.h"
@@ -110,32 +112,109 @@ static int gk20a_tegra_secure_alloc(struct platform_device *pdev,
 }
 #endif
 
+/*
+ * gk20a_tegra_railgate()
+ *
+ * Gate (disable) gk20a power rail
+ */
+
+static int gk20a_tegra_railgate(struct platform_device *pdev)
+{
+       if (tegra_powergate_is_powered(TEGRA_POWERGATE_GPU))
+               tegra_powergate_partition(TEGRA_POWERGATE_GPU);
+       return 0;
+}
+
+/*
+ * gk20a_tegra_unrailgate()
+ *
+ * Ungate (enable) gk20a power rail
+ */
+
+static int gk20a_tegra_unrailgate(struct platform_device *pdev)
+{
+       tegra_unpowergate_partition(TEGRA_POWERGATE_GPU);
+       return 0;
+}
+
+struct {
+       char *name;
+       unsigned long default_rate;
+} tegra_gk20a_clocks[] = {
+       {"PLLG_ref", UINT_MAX},
+       {"pwr", 204000000},
+       {"emc", UINT_MAX} };
+
+/*
+ * gk20a_tegra_get_clocks()
+ *
+ * This function finds clocks in tegra platform and populates
+ * the clock information to gk20a platform data.
+ */
+
+static int gk20a_tegra_get_clocks(struct platform_device *pdev)
+{
+       struct gk20a_platform *platform = platform_get_drvdata(pdev);
+       char devname[16];
+       int i;
+       int ret = 0;
+
+       snprintf(devname, sizeof(devname),
+                (pdev->id <= 0) ? "tegra_%s" : "tegra_%s.%d\n",
+                pdev->name, pdev->id);
+
+       platform->num_clks = 0;
+       for (i = 0; i < ARRAY_SIZE(tegra_gk20a_clocks); i++) {
+               long rate = tegra_gk20a_clocks[i].default_rate;
+               struct clk *c;
+
+               c = clk_get_sys(devname, tegra_gk20a_clocks[i].name);
+               if (IS_ERR(c)) {
+                       ret = PTR_ERR(c);
+                       goto err_get_clock;
+               }
+               rate = clk_round_rate(c, rate);
+               clk_set_rate(c, rate);
+               platform->clk[platform->num_clks++] = c;
+               platform->nvhost.clk[platform->nvhost.num_clks++] = c;
+       }
+       platform->num_clks = i;
+       platform->nvhost.num_clks = i;
+
+       return 0;
+
+err_get_clock:
+
+       while (i--)
+               clk_put(platform->clk[i]);
+       return ret;
+}
+
 static int gk20a_tegra_probe(struct platform_device *dev)
 {
-       int err;
        struct gk20a_platform *platform = gk20a_get_platform(dev);
-       struct nvhost_device_data *pdata = &platform->nvhost;
 
        if (tegra_get_chipid() == TEGRA_CHIPID_TEGRA13) {
                t132_gk20a_tegra_platform.g = platform->g;
                *platform = t132_gk20a_tegra_platform;
        }
 
-       pdata->pdev = dev;
-       mutex_init(&pdata->lock);
+       gk20a_tegra_get_clocks(dev);
+
+       return 0;
+}
 
-       /* Initialize clocks and power. */
-       err = nvhost_module_init(dev);
-       if (err)
-               return err;
+static int gk20a_tegra_late_probe(struct platform_device *dev)
+{
+       int err;
+       struct gk20a_platform *platform = gk20a_get_platform(dev);
+       struct nvhost_device_data *pdata = &platform->nvhost;
 
-#ifdef CONFIG_PM_GENERIC_DOMAINS
-       pdata->pd.name = "gk20a";
+       /* Make gk20a power domain a subdomain of mc */
+       tegra_pd_add_sd(&platform->g->pd);
 
-       err = nvhost_module_add_domain(&pdata->pd, dev);
-       if (err)
-               goto fail;
-#endif
+       pdata->pdev = dev;
+       mutex_init(&pdata->lock);
 
        err = nvhost_client_device_init(dev);
        if (err) {
@@ -144,7 +223,6 @@ static int gk20a_tegra_probe(struct platform_device *dev)
                goto fail;
        }
 
-       platform->can_powergate = pdata->can_powergate;
        platform->debugfs = pdata->debugfs;
 
        return 0;
@@ -155,6 +233,14 @@ fail:
        return err;
 }
 
+static int gk20a_tegra_suspend(struct device *dev)
+{
+       nvhost_scale3d_suspend(dev);
+       tegra_edp_notify_gpu_load(0);
+
+       return 0;
+}
+
 static struct resource gk20a_tegra_resources[] = {
        {
        .start = TEGRA_GK20A_BAR0_BASE,
@@ -188,16 +274,7 @@ struct gk20a_platform t132_gk20a_tegra_platform = {
                .syncpts                = {NVSYNCPT_GK20A_BASE},
                .syncpt_base            = NVSYNCPT_GK20A_BASE,
                .class                  = NV_GRAPHICS_GPU_CLASS_ID,
-               .clocks                 = {{"PLLG_ref", UINT_MAX},
-                                          {"pwr", 204000000},
-                                          {"emc", UINT_MAX},
-                                          {} },
-               .powergate_ids          = { TEGRA_POWERGATE_GPU, -1 },
-               NVHOST_DEFAULT_CLOCKGATE_DELAY,
-               .powergate_delay        = 500,
                .moduleid               = NVHOST_MODULE_GPU,
-               .prepare_poweroff       = nvhost_gk20a_prepare_poweroff,
-               .finalize_poweron       = nvhost_gk20a_finalize_poweron,
 #ifdef CONFIG_GK20A_DEVFREQ
                .busy                   = gk20a_scale_notify_busy,
                .idle                   = gk20a_scale_notify_idle,
@@ -210,8 +287,21 @@ struct gk20a_platform t132_gk20a_tegra_platform = {
                .qos_id                 = PM_QOS_GPU_FREQ_MIN,
 #endif
        },
+
        .has_syncpoints = true,
+
+       /* power management configuration */
+       .railgate_delay         = 500,
+       .clockgate_delay        = 50,
+
        .probe = gk20a_tegra_probe,
+       .late_probe = gk20a_tegra_late_probe,
+
+       /* power management callbacks */
+       .suspend = gk20a_tegra_suspend,
+       .railgate = gk20a_tegra_railgate,
+       .unrailgate = gk20a_tegra_unrailgate,
+
        .channel_busy = gk20a_tegra_channel_busy,
        .channel_idle = gk20a_tegra_channel_idle,
        .secure_alloc = gk20a_tegra_secure_alloc,
@@ -222,17 +312,7 @@ struct gk20a_platform gk20a_tegra_platform = {
                .syncpts                = {NVSYNCPT_GK20A_BASE},
                .syncpt_base            = NVSYNCPT_GK20A_BASE,
                .class                  = NV_GRAPHICS_GPU_CLASS_ID,
-               .clocks                 = {{"PLLG_ref", UINT_MAX},
-                                          {"pwr", 204000000},
-                                          {"emc", UINT_MAX},
-                                          {} },
-               .powergate_ids          = { TEGRA_POWERGATE_GPU, -1 },
-               NVHOST_DEFAULT_CLOCKGATE_DELAY,
-               .powergate_delay        = 500,
-               .can_powergate          = true,
                .moduleid               = NVHOST_MODULE_GPU,
-               .prepare_poweroff       = nvhost_gk20a_prepare_poweroff,
-               .finalize_poweron       = nvhost_gk20a_finalize_poweron,
 #ifdef CONFIG_GK20A_DEVFREQ
                .busy                   = gk20a_scale_notify_busy,
                .idle                   = gk20a_scale_notify_idle,
@@ -245,8 +325,22 @@ struct gk20a_platform gk20a_tegra_platform = {
                .qos_id                 = PM_QOS_GPU_FREQ_MIN,
 #endif
        },
+
        .has_syncpoints = true,
+
+       /* power management configuration */
+       .railgate_delay         = 500,
+       .clockgate_delay        = 50,
+       .can_railgate           = true,
+
        .probe = gk20a_tegra_probe,
+       .late_probe = gk20a_tegra_late_probe,
+
+       /* power management callbacks */
+       .suspend = gk20a_tegra_suspend,
+       .railgate = gk20a_tegra_railgate,
+       .unrailgate = gk20a_tegra_unrailgate,
+
        .channel_busy = gk20a_tegra_channel_busy,
        .channel_idle = gk20a_tegra_channel_idle,
        .secure_alloc = gk20a_tegra_secure_alloc,
index 0a3d17d0268bbd52088915d1a3dc2a29658e4a5b..4f8b89f8b72acee68dd2d7128f428c643a143e5f 100644 (file)
@@ -161,13 +161,12 @@ static void action_submit_complete(struct nvhost_waitlist *waiter)
 static void action_gpfifo_submit_complete(struct nvhost_waitlist *waiter)
 {
        struct channel_gk20a *ch20a = waiter->data;
-       int nr_completed = waiter->count;
+
        wake_up(&ch20a->submit_wq);
+
 #if defined(CONFIG_TEGRA_GK20A)
-       gk20a_channel_update(ch20a);
+       gk20a_channel_update(ch20a, waiter->count);
 #endif
-       nvhost_module_idle_mult(ch20a->ch->dev, nr_completed);
-       /* TODO: add trace function */
 }
 
 static void action_wakeup(struct nvhost_waitlist *waiter)