cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

drm_blend.c (21344B)


      1/*
      2 * Copyright (C) 2016 Samsung Electronics Co.Ltd
      3 * Authors:
      4 *	Marek Szyprowski <m.szyprowski@samsung.com>
      5 *
      6 * DRM core plane blending related functions
      7 *
      8 * Permission to use, copy, modify, distribute, and sell this software and its
      9 * documentation for any purpose is hereby granted without fee, provided that
     10 * the above copyright notice appear in all copies and that both that copyright
     11 * notice and this permission notice appear in supporting documentation, and
     12 * that the name of the copyright holders not be used in advertising or
     13 * publicity pertaining to distribution of the software without specific,
     14 * written prior permission.  The copyright holders make no representations
     15 * about the suitability of this software for any purpose.  It is provided "as
     16 * is" without express or implied warranty.
     17 *
     18 * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
     19 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
     20 * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
     21 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
     22 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
     23 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
     24 * OF THIS SOFTWARE.
     25 */
     26
     27#include <linux/export.h>
     28#include <linux/slab.h>
     29#include <linux/sort.h>
     30
     31#include <drm/drm_atomic.h>
     32#include <drm/drm_blend.h>
     33#include <drm/drm_device.h>
     34#include <drm/drm_print.h>
     35
     36#include "drm_crtc_internal.h"
     37
     38/**
     39 * DOC: overview
     40 *
     41 * The basic plane composition model supported by standard plane properties only
     42 * has a source rectangle (in logical pixels within the &drm_framebuffer), with
     43 * sub-pixel accuracy, which is scaled up to a pixel-aligned destination
     44 * rectangle in the visible area of a &drm_crtc. The visible area of a CRTC is
     45 * defined by the horizontal and vertical visible pixels (stored in @hdisplay
     46 * and @vdisplay) of the requested mode (stored in &drm_crtc_state.mode). These
     47 * two rectangles are both stored in the &drm_plane_state.
     48 *
     49 * For the atomic ioctl the following standard (atomic) properties on the plane object
     50 * encode the basic plane composition model:
     51 *
     52 * SRC_X:
     53 * 	X coordinate offset for the source rectangle within the
     54 * 	&drm_framebuffer, in 16.16 fixed point. Must be positive.
     55 * SRC_Y:
     56 * 	Y coordinate offset for the source rectangle within the
     57 * 	&drm_framebuffer, in 16.16 fixed point. Must be positive.
     58 * SRC_W:
     59 * 	Width for the source rectangle within the &drm_framebuffer, in 16.16
     60 * 	fixed point. SRC_X plus SRC_W must be within the width of the source
     61 * 	framebuffer. Must be positive.
     62 * SRC_H:
     63 * 	Height for the source rectangle within the &drm_framebuffer, in 16.16
     64 * 	fixed point. SRC_Y plus SRC_H must be within the height of the source
     65 * 	framebuffer. Must be positive.
     66 * CRTC_X:
     67 * 	X coordinate offset for the destination rectangle. Can be negative.
     68 * CRTC_Y:
     69 * 	Y coordinate offset for the destination rectangle. Can be negative.
     70 * CRTC_W:
     71 * 	Width for the destination rectangle. CRTC_X plus CRTC_W can extend past
     72 * 	the currently visible horizontal area of the &drm_crtc.
     73 * CRTC_H:
     74 * 	Height for the destination rectangle. CRTC_Y plus CRTC_H can extend past
     75 * 	the currently visible vertical area of the &drm_crtc.
     76 * FB_ID:
     77 * 	Mode object ID of the &drm_framebuffer this plane should scan out.
     78 * CRTC_ID:
     79 * 	Mode object ID of the &drm_crtc this plane should be connected to.
     80 *
     81 * Note that the source rectangle must fully lie within the bounds of the
     82 * &drm_framebuffer. The destination rectangle can lie outside of the visible
     83 * area of the current mode of the CRTC. It must be apprpriately clipped by the
     84 * driver, which can be done by calling drm_plane_helper_check_update(). Drivers
     85 * are also allowed to round the subpixel sampling positions appropriately, but
     86 * only to the next full pixel. No pixel outside of the source rectangle may
     87 * ever be sampled, which is important when applying more sophisticated
     88 * filtering than just a bilinear one when scaling. The filtering mode when
     89 * scaling is unspecified.
     90 *
     91 * On top of this basic transformation additional properties can be exposed by
     92 * the driver:
     93 *
     94 * alpha:
     95 * 	Alpha is setup with drm_plane_create_alpha_property(). It controls the
     96 * 	plane-wide opacity, from transparent (0) to opaque (0xffff). It can be
     97 * 	combined with pixel alpha.
     98 *	The pixel values in the framebuffers are expected to not be
     99 *	pre-multiplied by the global alpha associated to the plane.
    100 *
    101 * rotation:
    102 *	Rotation is set up with drm_plane_create_rotation_property(). It adds a
    103 *	rotation and reflection step between the source and destination rectangles.
    104 *	Without this property the rectangle is only scaled, but not rotated or
    105 *	reflected.
    106 *
    107 *	Possbile values:
    108 *
    109 *	"rotate-<degrees>":
    110 *		Signals that a drm plane is rotated <degrees> degrees in counter
    111 *		clockwise direction.
    112 *
    113 *	"reflect-<axis>":
    114 *		Signals that the contents of a drm plane is reflected along the
    115 *		<axis> axis, in the same way as mirroring.
    116 *
    117 *	reflect-x::
    118 *
    119 *			|o |    | o|
    120 *			|  | -> |  |
    121 *			| v|    |v |
    122 *
    123 *	reflect-y::
    124 *
    125 *			|o |    | ^|
    126 *			|  | -> |  |
    127 *			| v|    |o |
    128 *
    129 * zpos:
    130 *	Z position is set up with drm_plane_create_zpos_immutable_property() and
    131 *	drm_plane_create_zpos_property(). It controls the visibility of overlapping
    132 *	planes. Without this property the primary plane is always below the cursor
    133 *	plane, and ordering between all other planes is undefined. The positive
    134 *	Z axis points towards the user, i.e. planes with lower Z position values
    135 *	are underneath planes with higher Z position values. Two planes with the
    136 *	same Z position value have undefined ordering. Note that the Z position
    137 *	value can also be immutable, to inform userspace about the hard-coded
    138 *	stacking of planes, see drm_plane_create_zpos_immutable_property(). If
    139 *	any plane has a zpos property (either mutable or immutable), then all
    140 *	planes shall have a zpos property.
    141 *
    142 * pixel blend mode:
    143 *	Pixel blend mode is set up with drm_plane_create_blend_mode_property().
    144 *	It adds a blend mode for alpha blending equation selection, describing
    145 *	how the pixels from the current plane are composited with the
    146 *	background.
    147 *
    148 *	 Three alpha blending equations are defined:
    149 *
    150 *	 "None":
    151 *		 Blend formula that ignores the pixel alpha::
    152 *
    153 *			 out.rgb = plane_alpha * fg.rgb +
    154 *				 (1 - plane_alpha) * bg.rgb
    155 *
    156 *	 "Pre-multiplied":
    157 *		 Blend formula that assumes the pixel color values
    158 *		 have been already pre-multiplied with the alpha
    159 *		 channel values::
    160 *
    161 *			 out.rgb = plane_alpha * fg.rgb +
    162 *				 (1 - (plane_alpha * fg.alpha)) * bg.rgb
    163 *
    164 *	 "Coverage":
    165 *		 Blend formula that assumes the pixel color values have not
    166 *		 been pre-multiplied and will do so when blending them to the
    167 *		 background color values::
    168 *
    169 *			 out.rgb = plane_alpha * fg.alpha * fg.rgb +
    170 *				 (1 - (plane_alpha * fg.alpha)) * bg.rgb
    171 *
    172 *	 Using the following symbols:
    173 *
    174 *	 "fg.rgb":
    175 *		 Each of the RGB component values from the plane's pixel
    176 *	 "fg.alpha":
    177 *		 Alpha component value from the plane's pixel. If the plane's
    178 *		 pixel format has no alpha component, then this is assumed to be
    179 *		 1.0. In these cases, this property has no effect, as all three
    180 *		 equations become equivalent.
    181 *	 "bg.rgb":
    182 *		 Each of the RGB component values from the background
    183 *	 "plane_alpha":
    184 *		 Plane alpha value set by the plane "alpha" property. If the
    185 *		 plane does not expose the "alpha" property, then this is
    186 *		 assumed to be 1.0
    187 *
    188 * Note that all the property extensions described here apply either to the
    189 * plane or the CRTC (e.g. for the background color, which currently is not
    190 * exposed and assumed to be black).
    191 *
    192 * SCALING_FILTER:
    193 *     Indicates scaling filter to be used for plane scaler
    194 *
    195 *     The value of this property can be one of the following:
    196 *
    197 *     Default:
    198 *             Driver's default scaling filter
    199 *     Nearest Neighbor:
    200 *             Nearest Neighbor scaling filter
    201 *
    202 * Drivers can set up this property for a plane by calling
    203 * drm_plane_create_scaling_filter_property
    204 */
    205
    206/**
    207 * drm_plane_create_alpha_property - create a new alpha property
    208 * @plane: drm plane
    209 *
    210 * This function creates a generic, mutable, alpha property and enables support
    211 * for it in the DRM core. It is attached to @plane.
    212 *
    213 * The alpha property will be allowed to be within the bounds of 0
    214 * (transparent) to 0xffff (opaque).
    215 *
    216 * Returns:
    217 * 0 on success, negative error code on failure.
    218 */
    219int drm_plane_create_alpha_property(struct drm_plane *plane)
    220{
    221	struct drm_property *prop;
    222
    223	prop = drm_property_create_range(plane->dev, 0, "alpha",
    224					 0, DRM_BLEND_ALPHA_OPAQUE);
    225	if (!prop)
    226		return -ENOMEM;
    227
    228	drm_object_attach_property(&plane->base, prop, DRM_BLEND_ALPHA_OPAQUE);
    229	plane->alpha_property = prop;
    230
    231	if (plane->state)
    232		plane->state->alpha = DRM_BLEND_ALPHA_OPAQUE;
    233
    234	return 0;
    235}
    236EXPORT_SYMBOL(drm_plane_create_alpha_property);
    237
    238/**
    239 * drm_plane_create_rotation_property - create a new rotation property
    240 * @plane: drm plane
    241 * @rotation: initial value of the rotation property
    242 * @supported_rotations: bitmask of supported rotations and reflections
    243 *
    244 * This creates a new property with the selected support for transformations.
    245 *
    246 * Since a rotation by 180° degress is the same as reflecting both along the x
    247 * and the y axis the rotation property is somewhat redundant. Drivers can use
    248 * drm_rotation_simplify() to normalize values of this property.
    249 *
    250 * The property exposed to userspace is a bitmask property (see
    251 * drm_property_create_bitmask()) called "rotation" and has the following
    252 * bitmask enumaration values:
    253 *
    254 * DRM_MODE_ROTATE_0:
    255 * 	"rotate-0"
    256 * DRM_MODE_ROTATE_90:
    257 * 	"rotate-90"
    258 * DRM_MODE_ROTATE_180:
    259 * 	"rotate-180"
    260 * DRM_MODE_ROTATE_270:
    261 * 	"rotate-270"
    262 * DRM_MODE_REFLECT_X:
    263 * 	"reflect-x"
    264 * DRM_MODE_REFLECT_Y:
    265 * 	"reflect-y"
    266 *
    267 * Rotation is the specified amount in degrees in counter clockwise direction,
    268 * the X and Y axis are within the source rectangle, i.e.  the X/Y axis before
    269 * rotation. After reflection, the rotation is applied to the image sampled from
    270 * the source rectangle, before scaling it to fit the destination rectangle.
    271 */
    272int drm_plane_create_rotation_property(struct drm_plane *plane,
    273				       unsigned int rotation,
    274				       unsigned int supported_rotations)
    275{
    276	static const struct drm_prop_enum_list props[] = {
    277		{ __builtin_ffs(DRM_MODE_ROTATE_0) - 1,   "rotate-0" },
    278		{ __builtin_ffs(DRM_MODE_ROTATE_90) - 1,  "rotate-90" },
    279		{ __builtin_ffs(DRM_MODE_ROTATE_180) - 1, "rotate-180" },
    280		{ __builtin_ffs(DRM_MODE_ROTATE_270) - 1, "rotate-270" },
    281		{ __builtin_ffs(DRM_MODE_REFLECT_X) - 1,  "reflect-x" },
    282		{ __builtin_ffs(DRM_MODE_REFLECT_Y) - 1,  "reflect-y" },
    283	};
    284	struct drm_property *prop;
    285
    286	WARN_ON((supported_rotations & DRM_MODE_ROTATE_MASK) == 0);
    287	WARN_ON(!is_power_of_2(rotation & DRM_MODE_ROTATE_MASK));
    288	WARN_ON(rotation & ~supported_rotations);
    289
    290	prop = drm_property_create_bitmask(plane->dev, 0, "rotation",
    291					   props, ARRAY_SIZE(props),
    292					   supported_rotations);
    293	if (!prop)
    294		return -ENOMEM;
    295
    296	drm_object_attach_property(&plane->base, prop, rotation);
    297
    298	if (plane->state)
    299		plane->state->rotation = rotation;
    300
    301	plane->rotation_property = prop;
    302
    303	return 0;
    304}
    305EXPORT_SYMBOL(drm_plane_create_rotation_property);
    306
    307/**
    308 * drm_rotation_simplify() - Try to simplify the rotation
    309 * @rotation: Rotation to be simplified
    310 * @supported_rotations: Supported rotations
    311 *
    312 * Attempt to simplify the rotation to a form that is supported.
    313 * Eg. if the hardware supports everything except DRM_MODE_REFLECT_X
    314 * one could call this function like this:
    315 *
    316 * drm_rotation_simplify(rotation, DRM_MODE_ROTATE_0 |
    317 *                       DRM_MODE_ROTATE_90 | DRM_MODE_ROTATE_180 |
    318 *                       DRM_MODE_ROTATE_270 | DRM_MODE_REFLECT_Y);
    319 *
    320 * to eliminate the DRM_MODE_REFLECT_X flag. Depending on what kind of
    321 * transforms the hardware supports, this function may not
    322 * be able to produce a supported transform, so the caller should
    323 * check the result afterwards.
    324 */
    325unsigned int drm_rotation_simplify(unsigned int rotation,
    326				   unsigned int supported_rotations)
    327{
    328	if (rotation & ~supported_rotations) {
    329		rotation ^= DRM_MODE_REFLECT_X | DRM_MODE_REFLECT_Y;
    330		rotation = (rotation & DRM_MODE_REFLECT_MASK) |
    331			    BIT((ffs(rotation & DRM_MODE_ROTATE_MASK) + 1)
    332			    % 4);
    333	}
    334
    335	return rotation;
    336}
    337EXPORT_SYMBOL(drm_rotation_simplify);
    338
    339/**
    340 * drm_plane_create_zpos_property - create mutable zpos property
    341 * @plane: drm plane
    342 * @zpos: initial value of zpos property
    343 * @min: minimal possible value of zpos property
    344 * @max: maximal possible value of zpos property
    345 *
    346 * This function initializes generic mutable zpos property and enables support
    347 * for it in drm core. Drivers can then attach this property to planes to enable
    348 * support for configurable planes arrangement during blending operation.
    349 * Drivers that attach a mutable zpos property to any plane should call the
    350 * drm_atomic_normalize_zpos() helper during their implementation of
    351 * &drm_mode_config_funcs.atomic_check(), which will update the normalized zpos
    352 * values and store them in &drm_plane_state.normalized_zpos. Usually min
    353 * should be set to 0 and max to maximal number of planes for given crtc - 1.
    354 *
    355 * If zpos of some planes cannot be changed (like fixed background or
    356 * cursor/topmost planes), drivers shall adjust the min/max values and assign
    357 * those planes immutable zpos properties with lower or higher values (for more
    358 * information, see drm_plane_create_zpos_immutable_property() function). In such
    359 * case drivers shall also assign proper initial zpos values for all planes in
    360 * its plane_reset() callback, so the planes will be always sorted properly.
    361 *
    362 * See also drm_atomic_normalize_zpos().
    363 *
    364 * The property exposed to userspace is called "zpos".
    365 *
    366 * Returns:
    367 * Zero on success, negative errno on failure.
    368 */
    369int drm_plane_create_zpos_property(struct drm_plane *plane,
    370				   unsigned int zpos,
    371				   unsigned int min, unsigned int max)
    372{
    373	struct drm_property *prop;
    374
    375	prop = drm_property_create_range(plane->dev, 0, "zpos", min, max);
    376	if (!prop)
    377		return -ENOMEM;
    378
    379	drm_object_attach_property(&plane->base, prop, zpos);
    380
    381	plane->zpos_property = prop;
    382
    383	if (plane->state) {
    384		plane->state->zpos = zpos;
    385		plane->state->normalized_zpos = zpos;
    386	}
    387
    388	return 0;
    389}
    390EXPORT_SYMBOL(drm_plane_create_zpos_property);
    391
    392/**
    393 * drm_plane_create_zpos_immutable_property - create immuttable zpos property
    394 * @plane: drm plane
    395 * @zpos: value of zpos property
    396 *
    397 * This function initializes generic immutable zpos property and enables
    398 * support for it in drm core. Using this property driver lets userspace
    399 * to get the arrangement of the planes for blending operation and notifies
    400 * it that the hardware (or driver) doesn't support changing of the planes'
    401 * order. For mutable zpos see drm_plane_create_zpos_property().
    402 *
    403 * The property exposed to userspace is called "zpos".
    404 *
    405 * Returns:
    406 * Zero on success, negative errno on failure.
    407 */
    408int drm_plane_create_zpos_immutable_property(struct drm_plane *plane,
    409					     unsigned int zpos)
    410{
    411	struct drm_property *prop;
    412
    413	prop = drm_property_create_range(plane->dev, DRM_MODE_PROP_IMMUTABLE,
    414					 "zpos", zpos, zpos);
    415	if (!prop)
    416		return -ENOMEM;
    417
    418	drm_object_attach_property(&plane->base, prop, zpos);
    419
    420	plane->zpos_property = prop;
    421
    422	if (plane->state) {
    423		plane->state->zpos = zpos;
    424		plane->state->normalized_zpos = zpos;
    425	}
    426
    427	return 0;
    428}
    429EXPORT_SYMBOL(drm_plane_create_zpos_immutable_property);
    430
    431static int drm_atomic_state_zpos_cmp(const void *a, const void *b)
    432{
    433	const struct drm_plane_state *sa = *(struct drm_plane_state **)a;
    434	const struct drm_plane_state *sb = *(struct drm_plane_state **)b;
    435
    436	if (sa->zpos != sb->zpos)
    437		return sa->zpos - sb->zpos;
    438	else
    439		return sa->plane->base.id - sb->plane->base.id;
    440}
    441
    442static int drm_atomic_helper_crtc_normalize_zpos(struct drm_crtc *crtc,
    443					  struct drm_crtc_state *crtc_state)
    444{
    445	struct drm_atomic_state *state = crtc_state->state;
    446	struct drm_device *dev = crtc->dev;
    447	int total_planes = dev->mode_config.num_total_plane;
    448	struct drm_plane_state **states;
    449	struct drm_plane *plane;
    450	int i, n = 0;
    451	int ret = 0;
    452
    453	DRM_DEBUG_ATOMIC("[CRTC:%d:%s] calculating normalized zpos values\n",
    454			 crtc->base.id, crtc->name);
    455
    456	states = kmalloc_array(total_planes, sizeof(*states), GFP_KERNEL);
    457	if (!states)
    458		return -ENOMEM;
    459
    460	/*
    461	 * Normalization process might create new states for planes which
    462	 * normalized_zpos has to be recalculated.
    463	 */
    464	drm_for_each_plane_mask(plane, dev, crtc_state->plane_mask) {
    465		struct drm_plane_state *plane_state =
    466			drm_atomic_get_plane_state(state, plane);
    467		if (IS_ERR(plane_state)) {
    468			ret = PTR_ERR(plane_state);
    469			goto done;
    470		}
    471		states[n++] = plane_state;
    472		DRM_DEBUG_ATOMIC("[PLANE:%d:%s] processing zpos value %d\n",
    473				 plane->base.id, plane->name,
    474				 plane_state->zpos);
    475	}
    476
    477	sort(states, n, sizeof(*states), drm_atomic_state_zpos_cmp, NULL);
    478
    479	for (i = 0; i < n; i++) {
    480		plane = states[i]->plane;
    481
    482		states[i]->normalized_zpos = i;
    483		DRM_DEBUG_ATOMIC("[PLANE:%d:%s] normalized zpos value %d\n",
    484				 plane->base.id, plane->name, i);
    485	}
    486	crtc_state->zpos_changed = true;
    487
    488done:
    489	kfree(states);
    490	return ret;
    491}
    492
    493/**
    494 * drm_atomic_normalize_zpos - calculate normalized zpos values for all crtcs
    495 * @dev: DRM device
    496 * @state: atomic state of DRM device
    497 *
    498 * This function calculates normalized zpos value for all modified planes in
    499 * the provided atomic state of DRM device.
    500 *
    501 * For every CRTC this function checks new states of all planes assigned to
    502 * it and calculates normalized zpos value for these planes. Planes are compared
    503 * first by their zpos values, then by plane id (if zpos is equal). The plane
    504 * with lowest zpos value is at the bottom. The &drm_plane_state.normalized_zpos
    505 * is then filled with unique values from 0 to number of active planes in crtc
    506 * minus one.
    507 *
    508 * RETURNS
    509 * Zero for success or -errno
    510 */
    511int drm_atomic_normalize_zpos(struct drm_device *dev,
    512			      struct drm_atomic_state *state)
    513{
    514	struct drm_crtc *crtc;
    515	struct drm_crtc_state *old_crtc_state, *new_crtc_state;
    516	struct drm_plane *plane;
    517	struct drm_plane_state *old_plane_state, *new_plane_state;
    518	int i, ret = 0;
    519
    520	for_each_oldnew_plane_in_state(state, plane, old_plane_state, new_plane_state, i) {
    521		crtc = new_plane_state->crtc;
    522		if (!crtc)
    523			continue;
    524		if (old_plane_state->zpos != new_plane_state->zpos) {
    525			new_crtc_state = drm_atomic_get_new_crtc_state(state, crtc);
    526			new_crtc_state->zpos_changed = true;
    527		}
    528	}
    529
    530	for_each_oldnew_crtc_in_state(state, crtc, old_crtc_state, new_crtc_state, i) {
    531		if (old_crtc_state->plane_mask != new_crtc_state->plane_mask ||
    532		    new_crtc_state->zpos_changed) {
    533			ret = drm_atomic_helper_crtc_normalize_zpos(crtc,
    534								    new_crtc_state);
    535			if (ret)
    536				return ret;
    537		}
    538	}
    539	return 0;
    540}
    541EXPORT_SYMBOL(drm_atomic_normalize_zpos);
    542
    543/**
    544 * drm_plane_create_blend_mode_property - create a new blend mode property
    545 * @plane: drm plane
    546 * @supported_modes: bitmask of supported modes, must include
    547 *		     BIT(DRM_MODE_BLEND_PREMULTI). Current DRM assumption is
    548 *		     that alpha is premultiplied, and old userspace can break if
    549 *		     the property defaults to anything else.
    550 *
    551 * This creates a new property describing the blend mode.
    552 *
    553 * The property exposed to userspace is an enumeration property (see
    554 * drm_property_create_enum()) called "pixel blend mode" and has the
    555 * following enumeration values:
    556 *
    557 * "None":
    558 *	Blend formula that ignores the pixel alpha.
    559 *
    560 * "Pre-multiplied":
    561 *	Blend formula that assumes the pixel color values have been already
    562 *	pre-multiplied with the alpha channel values.
    563 *
    564 * "Coverage":
    565 *	Blend formula that assumes the pixel color values have not been
    566 *	pre-multiplied and will do so when blending them to the background color
    567 *	values.
    568 *
    569 * RETURNS:
    570 * Zero for success or -errno
    571 */
    572int drm_plane_create_blend_mode_property(struct drm_plane *plane,
    573					 unsigned int supported_modes)
    574{
    575	struct drm_device *dev = plane->dev;
    576	struct drm_property *prop;
    577	static const struct drm_prop_enum_list props[] = {
    578		{ DRM_MODE_BLEND_PIXEL_NONE, "None" },
    579		{ DRM_MODE_BLEND_PREMULTI, "Pre-multiplied" },
    580		{ DRM_MODE_BLEND_COVERAGE, "Coverage" },
    581	};
    582	unsigned int valid_mode_mask = BIT(DRM_MODE_BLEND_PIXEL_NONE) |
    583				       BIT(DRM_MODE_BLEND_PREMULTI)   |
    584				       BIT(DRM_MODE_BLEND_COVERAGE);
    585	int i;
    586
    587	if (WARN_ON((supported_modes & ~valid_mode_mask) ||
    588		    ((supported_modes & BIT(DRM_MODE_BLEND_PREMULTI)) == 0)))
    589		return -EINVAL;
    590
    591	prop = drm_property_create(dev, DRM_MODE_PROP_ENUM,
    592				   "pixel blend mode",
    593				   hweight32(supported_modes));
    594	if (!prop)
    595		return -ENOMEM;
    596
    597	for (i = 0; i < ARRAY_SIZE(props); i++) {
    598		int ret;
    599
    600		if (!(BIT(props[i].type) & supported_modes))
    601			continue;
    602
    603		ret = drm_property_add_enum(prop, props[i].type,
    604					    props[i].name);
    605
    606		if (ret) {
    607			drm_property_destroy(dev, prop);
    608
    609			return ret;
    610		}
    611	}
    612
    613	drm_object_attach_property(&plane->base, prop, DRM_MODE_BLEND_PREMULTI);
    614	plane->blend_mode_property = prop;
    615
    616	return 0;
    617}
    618EXPORT_SYMBOL(drm_plane_create_blend_mode_property);