diff options
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/media/video/tegra/nvavp/nvavp_dev.c | 44 |
1 files changed, 43 insertions, 1 deletions
diff --git a/drivers/media/video/tegra/nvavp/nvavp_dev.c b/drivers/media/video/tegra/nvavp/nvavp_dev.c index d692be54c538..3741043eb1d2 100644 --- a/drivers/media/video/tegra/nvavp/nvavp_dev.c +++ b/drivers/media/video/tegra/nvavp/nvavp_dev.c @@ -117,6 +117,7 @@ struct nvavp_info { struct nvhost_device *nvhost_dev; struct miscdevice misc_dev; + atomic_t clock_stay_on_refcount; }; struct nvavp_clientctx { @@ -126,6 +127,7 @@ struct nvavp_clientctx { struct nvmap_handle_ref *gather_mem; int num_relocs; struct nvavp_info *nvavp; + int clock_stay_on; }; static struct clk *nvavp_clk_get(struct nvavp_info *nvavp, int id) @@ -171,7 +173,8 @@ static void nvavp_clk_ctrl(struct nvavp_info *nvavp, u32 clk_en) static u32 nvavp_check_idle(struct nvavp_info *nvavp) { struct nv_e276_control *control = nvavp->os_control; - return (control->put == control->get) ? 1 : 0; + return ((control->put == control->get) + && (!atomic_read(&nvavp->clock_stay_on_refcount))) ? 1 : 0; } static void clock_disable_handler(struct work_struct *work) @@ -1022,6 +1025,39 @@ static int nvavp_wake_avp_ioctl(struct file *filp, unsigned int cmd, return 0; } +static int nvavp_force_clock_stay_on_ioctl(struct file *filp, unsigned int cmd, + unsigned long arg) +{ + struct nvavp_clientctx *clientctx = filp->private_data; + struct nvavp_info *nvavp = clientctx->nvavp; + struct nvavp_clock_stay_on_state_args clock; + + if (copy_from_user(&clock, (void __user *)arg, + sizeof(struct nvavp_clock_stay_on_state_args))) + return -EFAULT; + + dev_dbg(&nvavp->nvhost_dev->dev, "%s: state=%d\n", + __func__, clock.state); + + if (clock.state != NVAVP_CLOCK_STAY_ON_DISABLED && + clock.state != NVAVP_CLOCK_STAY_ON_ENABLED) { + dev_err(&nvavp->nvhost_dev->dev, "%s: invalid argument=%d\n", + __func__, clock.state); + return -EINVAL; + } + + if (clientctx->clock_stay_on == clock.state) + return 0; + + clientctx->clock_stay_on = clock.state; + + if (clientctx->clock_stay_on == NVAVP_CLOCK_STAY_ON_ENABLED) + atomic_inc(&nvavp->clock_stay_on_refcount); + else if (clientctx->clock_stay_on == NVAVP_CLOCK_STAY_ON_DISABLED) + atomic_dec(&nvavp->clock_stay_on_refcount); + + return 0; +} static int tegra_nvavp_open(struct inode *inode, struct file *filp) { @@ -1048,6 +1084,7 @@ static int tegra_nvavp_open(struct inode *inode, struct file *filp) clientctx->nvmap = nvavp->nvmap; clientctx->nvavp = nvavp; + clientctx->clock_stay_on = NVAVP_CLOCK_STAY_ON_DISABLED; filp->private_data = clientctx; @@ -1075,6 +1112,8 @@ static int tegra_nvavp_release(struct inode *inode, struct file *filp) goto out; } + if (clientctx->clock_stay_on == NVAVP_CLOCK_STAY_ON_ENABLED) + atomic_dec(&nvavp->clock_stay_on_refcount); if (nvavp->refcount > 0) nvavp->refcount--; if (!nvavp->refcount) @@ -1116,6 +1155,9 @@ static long tegra_nvavp_ioctl(struct file *filp, unsigned int cmd, case NVAVP_IOCTL_WAKE_AVP: ret = nvavp_wake_avp_ioctl(filp, cmd, arg); break; + case NVAVP_IOCTL_FORCE_CLOCK_STAY_ON: + ret = nvavp_force_clock_stay_on_ioctl(filp, cmd, arg); + break; default: ret = -EINVAL; break; |