From: Ville Syrjälä <ville.syrjala@xxxxxxxxxxxxxxx> 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@xxxxxxxxxxxxxxx> --- drivers/gpu/drm/drm_crtc.c | 168 +++++++++++++++++++++++++++++++++++++ drivers/gpu/drm/drm_crtc_helper.c | 19 ++++ drivers/gpu/drm/drm_drv.c | 3 +- include/drm/drm.h | 2 + include/drm/drm_crtc.h | 60 +++++++++++++ include/drm/drm_crtc_helper.h | 1 + include/drm/drm_mode.h | 111 ++++++++++++++++++++++++ 7 files changed, 363 insertions(+), 1 deletions(-) diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c index 0d1faa7..9cec7f0 100644 --- a/drivers/gpu/drm/drm_crtc.c +++ b/drivers/gpu/drm/drm_crtc.c @@ -1772,6 +1772,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 diff --git a/drivers/gpu/drm/drm_crtc_helper.c b/drivers/gpu/drm/drm_crtc_helper.c index 5e0b94c..0153187 100644 --- a/drivers/gpu/drm/drm_crtc_helper.c +++ b/drivers/gpu/drm/drm_crtc_helper.c @@ -1460,3 +1460,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); diff --git a/drivers/gpu/drm/drm_drv.c b/drivers/gpu/drm/drm_drv.c index eaf25ff..5759baa 100644 --- a/drivers/gpu/drm/drm_drv.c +++ b/drivers/gpu/drm/drm_drv.c @@ -159,7 +159,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 ) diff --git a/include/drm/drm.h b/include/drm/drm.h index 49d94ed..e59ec20 100644 --- a/include/drm/drm.h +++ b/include/drm/drm.h @@ -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 diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h index 2deb6f9..cf99643 100644 --- a/include/drm/drm_crtc.h +++ b/include/drm/drm_crtc.h @@ -277,6 +277,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; @@ -595,6 +645,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, @@ -605,6 +656,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); }; /** @@ -644,6 +697,9 @@ struct drm_plane { const struct drm_plane_funcs *funcs; void *helper_private; + + uint32_t opts_flags; + struct drm_plane_opts opts; }; /** @@ -1007,4 +1063,8 @@ extern int drm_mode_destroy_dumb_ioctl(struct drm_device *dev, extern void drm_fb_get_bpp_depth(uint32_t format, unsigned int *depth, int *bpp); + +extern int drm_mode_plane_opts(struct drm_device *dev, void *data, + struct drm_file *file_priv); + #endif /* __DRM_CRTC_H__ */ diff --git a/include/drm/drm_crtc_helper.h b/include/drm/drm_crtc_helper.h index 78e77af..e4946a5 100644 --- a/include/drm/drm_crtc_helper.h +++ b/include/drm/drm_crtc_helper.h @@ -179,5 +179,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 diff --git a/include/drm/drm_mode.h b/include/drm/drm_mode.h index 966fe7d..be8a9fd 100644 --- a/include/drm/drm_mode.h +++ b/include/drm/drm_mode.h @@ -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 -- 1.7.3.4 _______________________________________________ dri-devel mailing list dri-devel@xxxxxxxxxxxxxxxxxxxxx http://lists.freedesktop.org/mailman/listinfo/dri-devel