video: tegra: host: Disable irq when clock gating
Terje Bergstrom [Wed, 22 Aug 2012 06:16:51 +0000 (09:16 +0300)]
Disable host1x interrupts when clock gating host1x. This fixes a race
where host1x interrupt was raised at the same time when host1x clock
is turned off.

Bug 1031724

Change-Id: I169cd5796608b8888a6b48ed99bb5da754559b2c
Signed-off-by: Terje Bergstrom <tbergstrom@nvidia.com>
Reviewed-on: http://git-master/r/125129
Reviewed-by: Automatic_Commit_Validation_User
Reviewed-by: Juha Tukkinen <jtukkinen@nvidia.com>

drivers/video/tegra/host/host1x/host1x.c
drivers/video/tegra/host/nvhost_acm.c
include/linux/nvhost.h

index 33ebc1f..31899c7 100644 (file)
@@ -308,6 +308,19 @@ static int power_off_host(struct nvhost_device *dev)
        return 0;
 }
 
+static void clock_on_host(struct nvhost_device *dev)
+{
+       struct nvhost_master *host = nvhost_get_drvdata(dev);
+       nvhost_intr_start(&host->intr, clk_get_rate(dev->clk[0]));
+}
+
+static int clock_off_host(struct nvhost_device *dev)
+{
+       struct nvhost_master *host = nvhost_get_drvdata(dev);
+       nvhost_intr_stop(&host->intr);
+       return 0;
+}
+
 static int __devinit nvhost_user_init(struct nvhost_master *host)
 {
        int err, devno;
@@ -516,6 +529,8 @@ static struct nvhost_driver nvhost_driver = {
        },
        .finalize_poweron = power_on_host,
        .prepare_poweroff = power_off_host,
+       .finalize_clockon = clock_on_host,
+       .prepare_clockoff = clock_off_host,
 };
 
 static int __init nvhost_mod_init(void)
index 76304d6..5bde55a 100644 (file)
@@ -101,8 +101,17 @@ void nvhost_module_reset(struct nvhost_device *dev)
 
 static void to_state_clockgated_locked(struct nvhost_device *dev)
 {
+       struct nvhost_driver *drv = to_nvhost_driver(dev->dev.driver);
+
        if (dev->powerstate == NVHOST_POWER_STATE_RUNNING) {
-               int i;
+               int i, err;
+               if (drv->prepare_clockoff) {
+                       err = drv->prepare_clockoff(dev);
+                       if (err) {
+                               dev_err(&dev->dev, "error clock gating");
+                               return;
+                       }
+               }
                for (i = 0; i < dev->num_clks; i++)
                        clk_disable(dev->clk[i]);
                if (dev->dev.parent)
@@ -141,6 +150,14 @@ static void to_state_running_locked(struct nvhost_device *dev)
                        }
                }
 
+               /* Invoke callback after enabling clock. This is used for
+                * re-enabling host1x interrupts. */
+               if (prev_state == NVHOST_POWER_STATE_CLOCKGATED
+                               && drv->finalize_clockon)
+                       drv->finalize_clockon(dev);
+
+               /* Invoke callback after power un-gating. This is used for
+                * restoring context. */
                if (prev_state == NVHOST_POWER_STATE_POWERGATED
                                && drv->finalize_poweron)
                        drv->finalize_poweron(dev);
index c89d9b8..d7d8ad0 100644 (file)
@@ -172,6 +172,10 @@ struct nvhost_driver {
        /* Allocates a context handler for the device */
        struct nvhost_hwctx_handler *(*alloc_hwctx_handler)(u32 syncpt,
                        u32 waitbase, struct nvhost_channel *ch);
+
+       /* Clock gating callbacks */
+       int (*prepare_clockoff)(struct nvhost_device *dev);
+       void (*finalize_clockon)(struct nvhost_device *dev);
 };
 
 extern int nvhost_driver_register(struct nvhost_driver *);