video: tegra: nvavp: Add force clock stay on API
Hyung Taek Ryoo [Mon, 16 Apr 2012 18:33:49 +0000 (11:33 -0700)]
Add nvavp_force_clock_stay_on ioctl which provides way for user-mode driver
to stay on AVP clock state. This change is to fix LP0 resume fail during
Widevine playback. Since VDE/BSEV clocks are used by OTF driver in secure
world during closing sesssion, the change makes VDE/BSEV clocks running
while entering LP0.

Bug 960130
Bug 961015

Change-Id: I7eaaa9a33537a72b6ae0a016372bc513fef532e2
Reviewed-on: http://git-master/r/96302
Reviewed-by: Hyung Taek Ryoo <hryoo@nvidia.com>
Tested-by: Hyung Taek Ryoo <hryoo@nvidia.com>
Reviewed-by: Automatic_Commit_Validation_User
Reviewed-by: Karan Jhavar <kjhavar@nvidia.com>
Reviewed-by: Dan Willemsen <dwillemsen@nvidia.com>

drivers/media/video/tegra/nvavp/nvavp_dev.c
include/linux/tegra_nvavp.h

index d692be5..3741043 100644 (file)
@@ -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;
index 9710544..6774d0e 100644 (file)
@@ -64,6 +64,15 @@ struct nvavp_clock_args {
        __u32 rate;
 };
 
+enum nvavp_clock_stay_on_state {
+       NVAVP_CLOCK_STAY_ON_DISABLED = 0,
+       NVAVP_CLOCK_STAY_ON_ENABLED
+};
+
+struct nvavp_clock_stay_on_state_args {
+       enum nvavp_clock_stay_on_state  state;
+};
+
 #define NVAVP_IOCTL_MAGIC              'n'
 
 #define NVAVP_IOCTL_SET_NVMAP_FD       _IOW(NVAVP_IOCTL_MAGIC, 0x60, \
@@ -78,8 +87,10 @@ struct nvavp_clock_args {
                                        struct nvavp_clock_args)
 #define NVAVP_IOCTL_WAKE_AVP           _IOR(NVAVP_IOCTL_MAGIC, 0x66, \
                                        __u32)
+#define NVAVP_IOCTL_FORCE_CLOCK_STAY_ON        _IOW(NVAVP_IOCTL_MAGIC, 0x67, \
+                                       struct nvavp_clock_stay_on_state_args)
 
 #define NVAVP_IOCTL_MIN_NR             _IOC_NR(NVAVP_IOCTL_SET_NVMAP_FD)
-#define NVAVP_IOCTL_MAX_NR             _IOC_NR(NVAVP_IOCTL_WAKE_AVP)
+#define NVAVP_IOCTL_MAX_NR             _IOC_NR(NVAVP_IOCTL_FORCE_CLOCK_STAY_ON)
 
 #endif /* __LINUX_TEGRA_NVAVP_H */