diff options
author | Isaac Richards <irichards@nvidia.com> | 2012-01-24 12:13:05 -0500 |
---|---|---|
committer | Varun Colbert <vcolbert@nvidia.com> | 2012-01-30 12:31:41 -0800 |
commit | a97621dc0ddf4983cdb9a17af3caffe2903abea7 (patch) | |
tree | 3d7d8e65011e4feb44fe75deb8cf49959ee5ae15 /drivers/media | |
parent | a882618b895bfad07b59f97e70964fc3adda82e0 (diff) |
media: video: tegra: nvavp: Fix suspend/resume
Mark host1x as busy only when clocks are enabled, instead of
unconditionally at load/unload and suspend/resume time. Shutdown
the avp device entirely during suspend, and restart it on resume if
if necessary.
Bug 929279
Reviewed-on: http://git-master/r/77054
Change-Id: I0c66c26302fe307bea396e1c547a67b3417e26ec
Signed-off-by: Isaac Richards <irichards@nvidia.com>
Signed-off-by: Varun Wadekar <vwadekar@nvidia.com>
Reviewed-on: http://git-master/r/77749
Reviewed-by: Automatic_Commit_Validation_User
Diffstat (limited to 'drivers/media')
-rw-r--r-- | drivers/media/video/tegra/nvavp/nvavp_dev.c | 42 |
1 files changed, 36 insertions, 6 deletions
diff --git a/drivers/media/video/tegra/nvavp/nvavp_dev.c b/drivers/media/video/tegra/nvavp/nvavp_dev.c index bf4bac987677..58c9f8059a4c 100644 --- a/drivers/media/video/tegra/nvavp/nvavp_dev.c +++ b/drivers/media/video/tegra/nvavp/nvavp_dev.c @@ -89,6 +89,7 @@ struct nvavp_info { struct mutex open_lock; int refcount; + int initialized; struct work_struct clock_disable_work; @@ -145,6 +146,7 @@ static struct clk *nvavp_clk_get(struct nvavp_info *nvavp, int id) static void nvavp_clk_ctrl(struct nvavp_info *nvavp, u32 clk_en) { if (clk_en && !nvavp->clk_enabled) { + nvhost_module_busy(nvhost_get_host(nvavp->nvhost_dev)->dev); clk_enable(nvavp->bsev_clk); clk_enable(nvavp->vde_clk); clk_set_rate(nvavp->emc_clk, nvavp->emc_clk_rate); @@ -159,6 +161,7 @@ static void nvavp_clk_ctrl(struct nvavp_info *nvavp, u32 clk_en) clk_disable(nvavp->vde_clk); clk_set_rate(nvavp->emc_clk, 0); clk_set_rate(nvavp->sclk, 0); + nvhost_module_idle(nvhost_get_host(nvavp->nvhost_dev)->dev); nvavp->clk_enabled = 0; dev_dbg(&nvavp->nvhost_dev->dev, "%s: resetting emc_clk " "and sclk\n", __func__); @@ -289,12 +292,16 @@ static void nvavp_halt_vde(struct nvavp_info *nvavp) clk_disable(nvavp->bsev_clk); tegra_periph_reset_assert(nvavp->vde_clk); clk_disable(nvavp->vde_clk); + nvhost_module_idle(nvhost_get_host(nvavp->nvhost_dev)->dev); nvavp->clk_enabled = 0; } } static int nvavp_reset_vde(struct nvavp_info *nvavp) { + if (!nvavp->clk_enabled) + nvhost_module_busy(nvhost_get_host(nvavp->nvhost_dev)->dev); + clk_enable(nvavp->bsev_clk); tegra_periph_reset_assert(nvavp->bsev_clk); udelay(2); @@ -696,6 +703,9 @@ static int nvavp_init(struct nvavp_info *nvavp) char fw_os_file[32]; int ret = 0; + if (nvavp->initialized) + return ret; + #if defined(CONFIG_TEGRA_AVP_KERNEL_ON_MMU) /* Tegra2 with AVP MMU */ /* paddr is any address returned from nvmap_pin */ /* vaddr is AVP_KERNEL_VIRT_BASE */ @@ -767,12 +777,17 @@ static int nvavp_init(struct nvavp_info *nvavp) nvavp_reset_avp(nvavp, nvavp->os_info.reset_addr); enable_irq(nvavp->mbox_from_avp_pend_irq); + nvavp->initialized = 1; + err_exit: return ret; } static void nvavp_uninit(struct nvavp_info *nvavp) { + if (!nvavp->initialized) + return; + disable_irq(nvavp->mbox_from_avp_pend_irq); cancel_work_sync(&nvavp->clock_disable_work); @@ -784,6 +799,8 @@ static void nvavp_uninit(struct nvavp_info *nvavp) clk_disable(nvavp->sclk); clk_disable(nvavp->emc_clk); + + nvavp->initialized = 0; } static int nvavp_set_clock_ioctl(struct file *filp, unsigned int cmd, @@ -1024,7 +1041,6 @@ static int tegra_nvavp_open(struct inode *inode, struct file *filp) filp->private_data = clientctx; - nvhost_module_busy(nvhost_get_host(nvavp->nvhost_dev)->dev); mutex_unlock(&nvavp->open_lock); return ret; @@ -1039,7 +1055,6 @@ static int tegra_nvavp_release(struct inode *inode, struct file *filp) dev_dbg(&nvavp->nvhost_dev->dev, "%s: ++\n", __func__); filp->private_data = NULL; - nvhost_module_idle(nvhost_get_host(nvavp->nvhost_dev)->dev); mutex_lock(&nvavp->open_lock); @@ -1357,18 +1372,33 @@ static int tegra_nvavp_remove(struct nvhost_device *ndev) static int tegra_nvavp_suspend(struct nvhost_device *ndev, pm_message_t state) { struct nvavp_info *nvavp = nvhost_get_drvdata(ndev); + int ret = 0; - if (nvavp->refcount) - nvhost_module_idle(ndev); - return 0; + mutex_lock(&nvavp->open_lock); + + if (nvavp->refcount) { + if (nvavp_check_idle(nvavp)) + nvavp_uninit(nvavp); + else + ret = -EBUSY; + } + + mutex_unlock(&nvavp->open_lock); + + return ret; } static int tegra_nvavp_resume(struct nvhost_device *ndev) { struct nvavp_info *nvavp = nvhost_get_drvdata(ndev); + mutex_lock(&nvavp->open_lock); + if (nvavp->refcount) - nvhost_module_busy(ndev); + nvavp_init(nvavp); + + mutex_unlock(&nvavp->open_lock); + return 0; } #endif |