tegra: dc: ext: Add TEGRA_DC_EXT_FLIP4 support
Arun Swain [Wed, 23 Sep 2015 21:17:01 +0000 (14:17 -0700)]
Add FLIP4 support for the follwing reasons:
1. Cuurent FLIP3 doesn't have enough space in
order to pass head-specific info.
2. In order to pass HDR metadata we need at least
26 bytes and the current FLIP3 doesn't support
that.

The new FLIP4 has
1. A pointer to a array of 32 bytes of data to
pass head-specific info.
2. A nr_elements variabel that indicates the no.
of elements in the above array.

A new "tegra_dc_ext_flip_user_data" is defined
that has 6 bytes of tag info and 26 bytes of
payload data.

Bug 200122117

Change-Id: I4831b89ec25f877a948406feb4589824e82e3f3e
Reviewed-on: http://git-master/r/803991
(cherry picked from commit 83f6cd1eaebf1384c95a48069807407fb7beccf2)
Signed-off-by: Arun Swain <arswain@nvidia.com>
Reviewed-on: http://git-master/r/821188
Reviewed-by: Automatic_Commit_Validation_User
Reviewed-by: Mitch Luban <mluban@nvidia.com>
GVS: Gerrit_Virtual_Submit

drivers/video/tegra/dc/ext/dev.c
include/video/tegra_dc_ext.h

index c25a428..fdf25cb 100644 (file)
@@ -1104,11 +1104,21 @@ static void tegra_dc_ext_unpin_window(struct tegra_dc_ext_win *win)
        tegra_dc_ext_unpin_handles(unpin_handles, nr_unpin);
 }
 
+static void tegra_dc_ext_read_user_data(struct tegra_dc_ext_flip_data *data,
+                       struct tegra_dc_ext_flip_user_data *flip_user_data,
+                       int nr_user_data)
+{
+       /*Add support for reading user data (HDR data for intance) here*/
+}
+
+
 static int tegra_dc_ext_flip(struct tegra_dc_ext_user *user,
                             struct tegra_dc_ext_flip_windowattr *win,
                             int win_num,
                             __u32 *syncpt_id, __u32 *syncpt_val,
-                            int *syncpt_fd, __u16 *dirty_rect, u8 flip_flags)
+                            int *syncpt_fd, __u16 *dirty_rect, u8 flip_flags,
+                            struct tegra_dc_ext_flip_user_data *flip_user_data,
+                            int nr_user_data)
 {
        struct tegra_dc_ext *ext = user->ext;
        struct tegra_dc_ext_flip_data *data;
@@ -1154,6 +1164,8 @@ static int tegra_dc_ext_flip(struct tegra_dc_ext_user *user,
                goto unlock;
        }
 
+       tegra_dc_ext_read_user_data(data, flip_user_data, nr_user_data);
+
        BUG_ON(win_num > DC_N_WINDOWS);
        for (i = 0; i < win_num; i++) {
                u32 syncpt_max;
@@ -1730,7 +1742,7 @@ static long tegra_dc_ioctl(struct file *filp, unsigned int cmd,
                ret = tegra_dc_ext_flip(user, args.win,
                        TEGRA_DC_EXT_FLIP_N_WINDOWS,
                        &args.post_syncpt_id, &args.post_syncpt_val, NULL,
-                       NULL, 0);
+                       NULL, 0, NULL, 0);
 
                if (copy_to_user(user_arg, &args, sizeof(args)))
                        return -EFAULT;
@@ -1760,7 +1772,7 @@ static long tegra_dc_ioctl(struct file *filp, unsigned int cmd,
 
                ret = tegra_dc_ext_flip(user, win, win_num,
                        &args.post_syncpt_id, &args.post_syncpt_val, NULL,
-                       args.dirty_rect, 0);
+                       args.dirty_rect, 0, NULL, 0);
 
                if (copy_to_user(compat_ptr(args.win), win,
                        sizeof(*win) * win_num) ||
@@ -1794,7 +1806,7 @@ static long tegra_dc_ioctl(struct file *filp, unsigned int cmd,
 
                ret = tegra_dc_ext_flip(user, win, win_num,
                        &args.post_syncpt_id, &args.post_syncpt_val, NULL,
-                       args.dirty_rect, 0);
+                       args.dirty_rect, 0, NULL, 0);
 
                if (copy_to_user(args.win, win, sizeof(*win) * win_num) ||
                        copy_to_user(user_arg, &args, sizeof(args))) {
@@ -1835,7 +1847,7 @@ static long tegra_dc_ioctl(struct file *filp, unsigned int cmd,
 
                ret = tegra_dc_ext_flip(user, win, win_num,
                        NULL, NULL, &args.post_syncpt_fd, args.dirty_rect,
-                       args.flags);
+                       args.flags, NULL, 0);
 
                if (copy_to_user((void __user *)(uintptr_t)args.win, win,
                                 sizeof(*win) * win_num) ||
@@ -1847,6 +1859,64 @@ static long tegra_dc_ioctl(struct file *filp, unsigned int cmd,
                kfree(win);
                return ret;
        }
+       case TEGRA_DC_EXT_FLIP4:
+       {
+               int ret;
+               int win_num;
+               int nr_user_data;
+               struct tegra_dc_ext_flip_4 args;
+               struct tegra_dc_ext_flip_windowattr *win;
+               struct tegra_dc_ext_flip_user_data *flip_user_data;
+               bool bypass;
+
+               if (copy_from_user(&args, user_arg, sizeof(args)))
+                       return -EFAULT;
+
+               bypass = !!(args.flags & TEGRA_DC_EXT_FLIP_HEAD_FLAG_YUVBYPASS);
+
+               if (!!(user->ext->dc->mode.vmode & FB_VMODE_YUV_MASK) !=
+                   bypass)
+                       return -EINVAL;
+
+               user->ext->dc->yuv_bypass = bypass;
+               win_num = args.win_num;
+               win = kzalloc(sizeof(*win) * win_num, GFP_KERNEL);
+
+               if (copy_from_user(win,  (void __user *) (uintptr_t)args.win,
+                                  sizeof(*win) * win_num)) {
+                       kfree(win);
+                       return -EFAULT;
+               }
+
+               nr_user_data = args.nr_elements;
+               flip_user_data = kzalloc(sizeof(*flip_user_data)
+                                       * nr_user_data, GFP_KERNEL);
+               if (nr_user_data > 0) {
+                       if (copy_from_user(flip_user_data,
+                               (void __user *) (uintptr_t)args.data,
+                               sizeof(*flip_user_data) * nr_user_data)) {
+                               kfree(win);
+                               return -EFAULT;
+                       }
+               }
+               ret = tegra_dc_ext_flip(user, win, win_num,
+                       NULL, NULL, &args.post_syncpt_fd, args.dirty_rect,
+                       args.flags, flip_user_data, nr_user_data);
+
+               if (nr_user_data > 0)
+                       kfree(flip_user_data);
+
+               if (copy_to_user((void __user *)(uintptr_t)args.win, win,
+                                sizeof(*win) * win_num) ||
+                       copy_to_user(user_arg, &args, sizeof(args))) {
+                       kfree(win);
+                       return -EFAULT;
+               }
+
+               kfree(win);
+               return ret;
+       }
+
 #ifdef CONFIG_TEGRA_ISOMGR
 #ifdef CONFIG_COMPAT
        case TEGRA_DC_EXT_SET_PROPOSED_BW32:
index 6dc65d3..2ed3f29 100644 (file)
@@ -321,6 +321,35 @@ struct tegra_dc_ext_flip_3 {
        __u16 dirty_rect[4]; /* x,y,w,h for partial screen update. 0 ignores */
 };
 
+/* size of the this sturct is 32 bytes */
+struct tegra_dc_ext_flip_user_data {
+       __u8 data_type;
+       __u8 reserved0;
+       __u16 flags;
+       __u16 reserved1;
+       union { /* data to be packed into 26 bytes */
+               __u8 data8[26];
+               __u16 data16[13];
+               /*Add HDR data struct here*/
+       };
+};
+
+/*
+ *tegra_dc_flip_4 : Incorporates a new pointer to an array of 32 bytes of data
+ *to pass head specific info. The new nr_elements carries the number of such
+ *elements. Everything else remains the same as in tegra_dc_ext_flip_3
+ */
+struct tegra_dc_ext_flip_4 {
+       __u64 __user win;
+       __u8 win_num;
+       __u8 flags;
+       __u16 reserved2; /* unused - must be 0 */
+       __s32 post_syncpt_fd;
+       __u16 dirty_rect[4]; /* x,y,w,h for partial screen update. 0 ignores */
+       __u32 nr_elements; /* number of data entities pointed to by data */
+       __u64 __user data; /* pointer to struct tegra_dc_ext_flip_user_data*/
+};
+
 /*
  * vblank control - enable or disable vblank events
  */
@@ -661,6 +690,9 @@ struct tegra_dc_ext_feature {
 #define TEGRA_DC_EXT_GET_CMU_ADBRGB\
        _IOR('D', 0x1C, struct tegra_dc_ext_cmu)
 
+#define TEGRA_DC_EXT_FLIP4\
+       _IOW('D', 0x1D, struct tegra_dc_ext_flip_4)
+
 enum tegra_dc_ext_control_output_type {
        TEGRA_DC_EXT_DSI,
        TEGRA_DC_EXT_LVDS,