drm: plane: Add plane options ioctl
authorVille Syrjälä <ville.syrjala@linux.intel.com>
Wed, 14 Dec 2011 22:12:00 +0000 (00:12 +0200)
committerMarkus Lehtonen <markus.lehtonen@linux.intel.com>
Tue, 3 Jul 2012 09:29:03 +0000 (12:29 +0300)
Add a new ioctl DRM_IOCTL_MODE_PLANE_OPTS which is used to configure
various settings for the plane.

I left out gamma correction thinking that it could be added using a
separate ioctl, since there's already a gamma ioctl for CRTCs.

Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
Acked-by: Pauli Nieminen <pauli.nieminen@linux.intel.com>
Reviewed-by: Jani Nikula <jani.nikula@intel.com>
Signed-off-by: Kirill A. Shutemov <kirill.shutemov@linux.intel.com>
drivers/gpu/drm/drm_crtc.c
drivers/gpu/drm/drm_crtc_helper.c
drivers/gpu/drm/drm_drv.c
include/drm/drm.h
include/drm/drm_crtc.h
include/drm/drm_crtc_helper.h
include/drm/drm_mode.h

index 1747d3e..57d5c42 100644 (file)
@@ -1770,6 +1770,174 @@ out:
 }
 
 /**
+ * drm_mode_plane_opts - set and get plane options
+ * @dev: DRM device
+ * @data: ioctl data*
+ * @file_prive: DRM file info
+ *
+ */
+int drm_mode_plane_opts(struct drm_device *dev, void *data,
+                       struct drm_file *file_priv)
+{
+       struct drm_mode_plane_opts_cmd *req = data;
+       struct drm_mode_object *obj;
+       struct drm_plane *plane;
+       int ret = 0;
+
+       if (!drm_core_check_feature(dev, DRIVER_MODESET))
+               return -EINVAL;
+
+       mutex_lock(&dev->mode_config.mutex);
+
+       /*
+        * First, find the plane object.  If not available,
+        * we don't bother to call the driver.
+        */
+       obj = drm_mode_object_find(dev, req->plane_id,
+                                  DRM_MODE_OBJECT_PLANE);
+       if (!obj) {
+               DRM_DEBUG_KMS("Unknown plane ID %d\n",
+                             req->plane_id);
+               ret = -ENOENT;
+               goto out;
+       }
+       plane = obj_to_plane(obj);
+
+       if (req->flags & ~plane->opts_flags) {
+               ret = -ENOTSUPP;
+               goto out;
+       }
+
+       if (req->flags) {
+               /* Start with the current values. */
+               struct drm_plane_opts opts = plane->opts;
+               uint32_t flags = 0;
+
+               /* Overwrite with user provided values. */
+               if (req->flags & DRM_MODE_PLANE_BRIGHTNESS &&
+                   opts.brightness != req->brightness) {
+                       flags |= DRM_MODE_PLANE_BRIGHTNESS;
+                       opts.brightness = req->brightness;
+               }
+               if (req->flags & DRM_MODE_PLANE_CONTRAST &&
+                   opts.contrast != req->contrast) {
+                       flags |= DRM_MODE_PLANE_CONTRAST;
+                       opts.contrast = req->contrast;
+               }
+               if (req->flags & DRM_MODE_PLANE_HUE &&
+                   opts.hue != req->hue) {
+                       flags |= DRM_MODE_PLANE_HUE;
+                       opts.hue = req->hue;
+               }
+               if (req->flags & DRM_MODE_PLANE_SATURATION &&
+                   opts.saturation != req->saturation) {
+                       flags |= DRM_MODE_PLANE_SATURATION;
+                       opts.saturation = req->saturation;
+               }
+               if (req->flags & DRM_MODE_PLANE_SRC_KEY &&
+                   (opts.src_key_low != req->src_key_low ||
+                    opts.src_key_high != req->src_key_high)) {
+                       flags |= DRM_MODE_PLANE_SRC_KEY;
+                       opts.src_key_low = req->src_key_low;
+                       opts.src_key_high = req->src_key_high;
+               }
+               if (req->flags & DRM_MODE_PLANE_DST_KEY &&
+                   (opts.dst_key_value != req->dst_key_value ||
+                    opts.dst_key_mask != req->dst_key_mask)) {
+                       flags |= DRM_MODE_PLANE_DST_KEY;
+                       opts.dst_key_value = req->dst_key_value;
+                       opts.dst_key_mask = req->dst_key_mask;
+               }
+               if (req->flags & DRM_MODE_PLANE_CONST_ALPHA &&
+                   opts.const_alpha != req->const_alpha) {
+                       flags |= DRM_MODE_PLANE_CONST_ALPHA;
+                       opts.const_alpha = req->const_alpha;
+               }
+               if (req->flags & DRM_MODE_PLANE_ZORDER &&
+                   opts.zorder != req->zorder) {
+                       if (req->zorder == 0) {
+                               ret = -EINVAL;
+                               goto out;
+                       }
+                       flags |= DRM_MODE_PLANE_ZORDER;
+                       opts.zorder = req->zorder;
+               }
+               if (req->flags & DRM_MODE_PLANE_CSC_MATRIX &&
+                   opts.csc_matrix != req->csc_matrix) {
+                       flags |= DRM_MODE_PLANE_CSC_MATRIX;
+                       opts.csc_matrix = req->csc_matrix;
+               }
+               if (req->flags & DRM_MODE_PLANE_CSC_RANGE &&
+                   opts.csc_range != req->csc_range) {
+                       flags |= DRM_MODE_PLANE_CSC_RANGE;
+                       opts.csc_range = req->csc_range;
+               }
+               if (req->flags & DRM_MODE_PLANE_CHROMA_SITING &&
+                   opts.chroma_siting != req->chroma_siting) {
+                       flags |= DRM_MODE_PLANE_CHROMA_SITING;
+                       opts.chroma_siting = req->chroma_siting;
+               }
+               if (req->flags & DRM_MODE_PLANE_VC1_RANGE_MAPY &&
+                   opts.vc1_range_mapy != req->vc1_range_mapy) {
+                       flags |= DRM_MODE_PLANE_VC1_RANGE_MAPY;
+                       opts.vc1_range_mapy = req->vc1_range_mapy;
+               }
+               if (req->flags & DRM_MODE_PLANE_VC1_RANGE_MAPUV &&
+                   opts.vc1_range_mapuv != req->vc1_range_mapuv) {
+                       flags |= DRM_MODE_PLANE_VC1_RANGE_MAPUV;
+                       opts.vc1_range_mapuv = req->vc1_range_mapuv;
+               }
+
+               if (flags) {
+                       ret = plane->funcs->set_plane_opts(plane, flags, &opts);
+                       if (ret)
+                               goto out;
+
+                       plane->opts = opts;
+               }
+       }
+
+       /* Copy the current values back to the user. */
+       req->flags = plane->opts_flags;
+
+       if (req->flags & DRM_MODE_PLANE_BRIGHTNESS)
+               req->brightness = plane->opts.brightness;
+       if (req->flags & DRM_MODE_PLANE_CONTRAST)
+               req->contrast = plane->opts.contrast;
+       if (req->flags & DRM_MODE_PLANE_HUE)
+               req->hue = plane->opts.hue;
+       if (req->flags & DRM_MODE_PLANE_SATURATION)
+               req->saturation = plane->opts.saturation;
+       if (req->flags & DRM_MODE_PLANE_SRC_KEY) {
+               req->src_key_low = plane->opts.src_key_low;
+               req->src_key_high = plane->opts.src_key_high;
+       }
+       if (req->flags & DRM_MODE_PLANE_DST_KEY) {
+               req->dst_key_value = plane->opts.dst_key_value;
+               req->dst_key_mask = plane->opts.dst_key_mask;
+       }
+       if (req->flags & DRM_MODE_PLANE_CONST_ALPHA)
+               req->const_alpha = plane->opts.const_alpha;
+       if (req->flags & DRM_MODE_PLANE_ZORDER)
+               req->zorder = plane->opts.zorder;
+       if (req->flags & DRM_MODE_PLANE_CSC_MATRIX)
+               req->csc_matrix = plane->opts.csc_matrix;
+       if (req->flags & DRM_MODE_PLANE_CSC_RANGE)
+               req->csc_range = plane->opts.csc_range;
+       if (req->flags & DRM_MODE_PLANE_CHROMA_SITING)
+               req->chroma_siting = plane->opts.chroma_siting;
+       if (req->flags & DRM_MODE_PLANE_VC1_RANGE_MAPY)
+               req->vc1_range_mapy = plane->opts.vc1_range_mapy;
+       if (req->flags & DRM_MODE_PLANE_VC1_RANGE_MAPUV)
+               req->vc1_range_mapuv = plane->opts.vc1_range_mapuv;
+
+ out:
+       mutex_unlock(&dev->mode_config.mutex);
+
+       return ret;
+}
+
+/**
  * drm_mode_setcrtc - set CRTC configuration
  * @inode: inode from the ioctl
  * @filp: file * from the ioctl
index 39c5b45..52dacc5 100644 (file)
@@ -1504,3 +1504,22 @@ int drm_calc_vscale(struct drm_region *src, struct drm_region *dst,
        return vscale;
 }
 EXPORT_SYMBOL(drm_calc_vscale);
+
+/**
+ * drm_plane_opts_defaults - fill the plane opts with default values
+ */
+void drm_plane_opts_defaults(struct drm_plane_opts *opts)
+{
+       memset(opts, 0, sizeof *opts);
+
+       opts->brightness = 0x8000;
+       opts->contrast = 0x8000;
+       opts->hue = 0x8000;
+       opts->saturation = 0x8000;
+
+       /* disable source color keying */
+       opts->src_key_low = ~0ULL;
+
+       opts->const_alpha = 0xffff;
+}
+EXPORT_SYMBOL(drm_plane_opts_defaults);
index e312885..4493fd4 100644 (file)
@@ -158,7 +158,8 @@ static struct drm_ioctl_desc drm_ioctls[] = {
        DRM_IOCTL_DEF(DRM_IOCTL_MODE_DIRTYFB, drm_mode_dirtyfb_ioctl, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED),
        DRM_IOCTL_DEF(DRM_IOCTL_MODE_CREATE_DUMB, drm_mode_create_dumb_ioctl, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED),
        DRM_IOCTL_DEF(DRM_IOCTL_MODE_MAP_DUMB, drm_mode_mmap_dumb_ioctl, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED),
-       DRM_IOCTL_DEF(DRM_IOCTL_MODE_DESTROY_DUMB, drm_mode_destroy_dumb_ioctl, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED)
+       DRM_IOCTL_DEF(DRM_IOCTL_MODE_DESTROY_DUMB, drm_mode_destroy_dumb_ioctl, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED),
+       DRM_IOCTL_DEF(DRM_IOCTL_MODE_PLANE_OPTS, drm_mode_plane_opts, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED),
 };
 
 #define DRM_CORE_IOCTL_COUNT   ARRAY_SIZE( drm_ioctls )
index 49d94ed..e59ec20 100644 (file)
@@ -718,6 +718,8 @@ struct drm_get_cap {
 #define DRM_IOCTL_MODE_GETPLANE        DRM_IOWR(0xB6, struct drm_mode_get_plane)
 #define DRM_IOCTL_MODE_SETPLANE        DRM_IOWR(0xB7, struct drm_mode_set_plane)
 #define DRM_IOCTL_MODE_ADDFB2          DRM_IOWR(0xB8, struct drm_mode_fb_cmd2)
+#define DRM_IOCTL_MODE_PLANE_OPTS      DRM_IOWR(0xB9, struct drm_mode_plane_opts_cmd)
+
 
 /**
  * Device specific ioctls should only be in their respective headers
index 415a6e2..efc84c1 100644 (file)
@@ -276,6 +276,56 @@ struct drm_property {
        struct list_head enum_blob_list;
 };
 
+/**
+ * drm_plane_opts - plane options
+ * @brightness: brightness value
+ * @contrast: contrast value
+ * @hue: hue value
+ * @saturation: saturation value
+ * @src_key_low: minimum source color key value
+ * @src_key_high: maximum source color key value
+ * @dst_key_value: destination color key value
+ * @dst_key_mask: destination color key mask
+ * @const_alpha: constant alpha blending factor
+ * @zorder: plane Z order
+ * @csc_matrix: transfer matrix
+ * @csc_range: Y/Cb/Cb range information
+ * @chroma_siting: chroma siting information
+ * @vc1_range_mapy: VC-1 range mapping for Y
+ * @vc1_range_mapuv: VC-1 range mapping for Cb/Cr
+ *
+ * @brightness, @contrast, @hue and @saturation have a range of 0x0000 to
+ * 0xffff. Values of 0x0000 to 0x7fff indicate a decrease, a value of
+ * 0x8000 indicates a default level, and values from 0x8001 to 0xffff
+ * indicate an increase.
+ *
+ * The actual change in the level per a change in the value is implementation
+ * defined, as is the exact meaning of the default level. The only strict
+ * requirement is that the mapping between the value and the actual level is
+ * a monotonically non-decreasing function.
+ *
+ * It is recommended that the full range of values be utilized eg. by
+ * using coarsers step size, piecewise functions, etc. This helps to
+ * isolate the user from the hardware details as much as possible.
+ */
+struct drm_plane_opts {
+       uint16_t brightness;
+       uint16_t contrast;
+       uint16_t hue;
+       uint16_t saturation;
+       uint64_t src_key_low;
+       uint64_t src_key_high;
+       uint64_t dst_key_value;
+       uint64_t dst_key_mask;
+       uint16_t const_alpha;
+       int8_t zorder;
+       uint8_t csc_matrix;
+       uint8_t csc_range;
+       uint8_t chroma_siting;
+       uint8_t vc1_range_mapy;
+       uint8_t vc1_range_mapuv;
+};
+
 struct drm_crtc;
 struct drm_connector;
 struct drm_encoder;
@@ -534,6 +584,7 @@ struct drm_connector {
  * @update_plane: update the plane configuration
  * @disable_plane: shut down the plane
  * @destroy: clean up plane resources
+ * @set_plane_opts: set plane options
  */
 struct drm_plane_funcs {
        int (*update_plane)(struct drm_plane *plane,
@@ -544,6 +595,8 @@ struct drm_plane_funcs {
                            uint32_t src_w, uint32_t src_h);
        int (*disable_plane)(struct drm_plane *plane);
        void (*destroy)(struct drm_plane *plane);
+       int (*set_plane_opts)(struct drm_plane *plane, uint32_t flags,
+                             struct drm_plane_opts *opts);
 };
 
 /**
@@ -583,6 +636,9 @@ struct drm_plane {
 
        const struct drm_plane_funcs *funcs;
        void *helper_private;
+
+       uint32_t opts_flags;
+       struct drm_plane_opts opts;
 };
 
 /**
@@ -892,4 +948,8 @@ extern int drm_mode_mmap_dumb_ioctl(struct drm_device *dev,
                                    void *data, struct drm_file *file_priv);
 extern int drm_mode_destroy_dumb_ioctl(struct drm_device *dev,
                                      void *data, struct drm_file *file_priv);
+
+extern int drm_mode_plane_opts(struct drm_device *dev, void *data,
+                              struct drm_file *file_priv);
+
 #endif /* __DRM_CRTC_H__ */
index ab29316..156aa10 100644 (file)
@@ -181,5 +181,6 @@ extern int drm_calc_hscale(struct drm_region *src, struct drm_region *dst,
                           int min_hscale, int max_hscale);
 extern int drm_calc_vscale(struct drm_region *src, struct drm_region *dst,
                           int min_vscale, int max_vscale);
+extern void drm_plane_opts_defaults(struct drm_plane_opts *opts);
 
 #endif
index 4675dc9..51380c0 100644 (file)
@@ -157,6 +157,117 @@ struct drm_mode_get_plane_res {
        __u32 count_planes;
 };
 
+/* Valid YCbCr range */
+#define DRM_CSC_RANGE_UNKNOWN          0x0 /* not specified, implementation defined result */
+#define DRM_CSC_RANGE_MPEG             0x1 /* "MPEG" range (16-235 for Y, 16-240 for Cb/Cr) */
+#define DRM_CSC_RANGE_JPEG             0x2 /* "JPEG" or full range (0-255 for Y/Cb/Cr) */
+
+/* Color space conversion transfer matrix */
+#define DRM_CSC_MATRIX_UNKNOWN         0x0 /* not specified, implementation defined result */
+#define DRM_CSC_MATRIX_BT601           0x1 /* ITU-R BT.601 */
+#define DRM_CSC_MATRIX_BT709           0x2 /* ITU-R BT.709 */
+
+/* Chroma siting information */
+#define DRM_CHROMA_SITING_UNKNOWN              0x0 /* not specified, implementation defined result */
+#define DRM_CHROMA_SITING_HORZ_LEFT            0x1 /* horizontally co-sited with the first luma sample */
+#define DRM_CHROMA_SITING_HORZ_CENTER          0x2 /* horizontally interstitially sited with luma samples */
+#define DRM_CHROMA_SITING_VERT_TOP             0x4 /* vertically co-sited with the first luma sample */
+#define DRM_CHROMA_SITING_VERT_CENTER          0x8 /* vertically interstitially sited with luma samples */
+#define DRM_CHROMA_SITING_MISALIGNED_PLANES    0x10 /* chroma planes out of phase with each other by 0.5 lines */
+/* Typical chroma siting configurations */
+#define DRM_CHROMA_SITING_MPEG1                        (DRM_CHROMA_SITING_HORZ_CENTER |\
+                                                DRM_CHROMA_SITING_VERT_CENTER)
+#define DRM_CHROMA_SITING_MPEG2                        (DRM_CHROMA_SITING_HORZ_LEFT |\
+                                                DRM_CHROMA_SITING_VERT_CENTER)
+#define DRM_CHROMA_SITING_DV                   (DRM_CHROMA_SITING_HORZ_LEFT |\
+                                                DRM_CHROMA_SITING_VERT_TOP |\
+                                                DRM_CHROMA_SITING_MISALIGNED_PLANES)
+
+/*
+ * Plane option flags.
+ * If a flag is set the corresponding value is valid
+ */
+#define DRM_MODE_PLANE_BRIGHTNESS      (1<<0)
+#define DRM_MODE_PLANE_CONTRAST                (1<<1)
+#define        DRM_MODE_PLANE_HUE              (1<<2)
+#define DRM_MODE_PLANE_SATURATION      (1<<3)
+#define DRM_MODE_PLANE_SRC_KEY         (1<<4)
+#define DRM_MODE_PLANE_DST_KEY         (1<<5)
+#define DRM_MODE_PLANE_CONST_ALPHA     (1<<6)
+#define DRM_MODE_PLANE_ZORDER          (1<<7)
+#define DRM_MODE_PLANE_CSC_MATRIX      (1<<8)
+#define DRM_MODE_PLANE_CSC_RANGE       (1<<9)
+#define        DRM_MODE_PLANE_CHROMA_SITING    (1<<10)
+#define        DRM_MODE_PLANE_VC1_RANGE_MAPY   (1<<11)
+#define        DRM_MODE_PLANE_VC1_RANGE_MAPUV  (1<<12)
+
+struct drm_mode_plane_opts_cmd {
+       __u32 plane_id;
+
+       __u32 flags;
+
+       /*
+        * 0x0000 - 0x7fff = decrease
+        * 0x8000          = no change
+        * 0x8001 - 0xffff = increase
+        */
+       __u16 brightness;
+       __u16 contrast;
+       __u16 hue;
+       __u16 saturation;
+
+       /*
+        * [47:32] R [31:16] G [15:0] B or [47:32] Y [31:16] Cb [15:0] Cr
+        * The size and color space of the components depends on the
+        * used pixel format. If the actual component size is less than
+        * 16 bits, the most significat bits of of each component are
+        * used.
+        * The plane is invisible when the following equation evaluates
+        * to true (for each component):
+        * src_pixel >= src_key_low && src_pixel <= src_key_high
+        *
+        * To disable source color keying set src_key_high < src_key_low
+        * for each compnent.
+        */
+       __u64 src_key_low;
+       __u64 src_key_high;
+
+       /* See src_key_low/src_key_high */
+       __u64 dst_key_value;
+       /*
+        * Layout matches that of dst_key_value. The plane is visible
+        * if the following equation evaluates to true:
+        * (dst_pixel & dst_key_mask) == (dst_key_value & dst_key_mask)
+        *
+        * To disable destination color keying set dst_key_mask to 0.
+        */
+       __u64 dst_key_mask;
+
+       /* If the hardware uses less bits, the most significat bits are used. */
+       __u16 const_alpha;
+
+       /*
+        * CRTC is at 0, < 0 is below it, > 0 is above it
+        * If two planes are configured with the same zorder
+        * on the same CRTC, the plane with the lower plane_id
+        * will be stacked closer to the CRTC.
+        */
+       __s8 zorder;
+
+       /* DRM_CSC_MATRIX_* */
+       __u8 csc_matrix;
+
+       /* DRM_CSC_RANGE_* */
+       __u8 csc_range;
+
+       /* DRM_CHROMA_SITING_* */
+       __u8 chroma_siting;
+
+       /* as defined by VC-1 */
+       __u8 vc1_range_mapy;
+       __u8 vc1_range_mapuv;
+};
+
 #define DRM_MODE_ENCODER_NONE  0
 #define DRM_MODE_ENCODER_DAC   1
 #define DRM_MODE_ENCODER_TMDS  2