brintos

brintos / linux-shallow public Read only

0
0
Text · 54.3 KiB · a28b22f Raw
1796 lines · c
1/*2 * Copyright (c) 2016 Intel Corporation3 *4 * Permission to use, copy, modify, distribute, and sell this software and its5 * documentation for any purpose is hereby granted without fee, provided that6 * the above copyright notice appear in all copies and that both that copyright7 * notice and this permission notice appear in supporting documentation, and8 * that the name of the copyright holders not be used in advertising or9 * publicity pertaining to distribution of the software without specific,10 * written prior permission.  The copyright holders make no representations11 * about the suitability of this software for any purpose.  It is provided "as12 * is" without express or implied warranty.13 *14 * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,15 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO16 * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR17 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,18 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER19 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE20 * OF THIS SOFTWARE.21 */22 23#include <linux/slab.h>24#include <linux/uaccess.h>25 26#include <drm/drm_plane.h>27#include <drm/drm_drv.h>28#include <drm/drm_print.h>29#include <drm/drm_framebuffer.h>30#include <drm/drm_file.h>31#include <drm/drm_crtc.h>32#include <drm/drm_fourcc.h>33#include <drm/drm_managed.h>34#include <drm/drm_vblank.h>35 36#include "drm_crtc_internal.h"37 38/**39 * DOC: overview40 *41 * A plane represents an image source that can be blended with or overlaid on42 * top of a CRTC during the scanout process. Planes take their input data from a43 * &drm_framebuffer object. The plane itself specifies the cropping and scaling44 * of that image, and where it is placed on the visible area of a display45 * pipeline, represented by &drm_crtc. A plane can also have additional46 * properties that specify how the pixels are positioned and blended, like47 * rotation or Z-position. All these properties are stored in &drm_plane_state.48 *49 * Unless explicitly specified (via CRTC property or otherwise), the active area50 * of a CRTC will be black by default. This means portions of the active area51 * which are not covered by a plane will be black, and alpha blending of any52 * planes with the CRTC background will blend with black at the lowest zpos.53 *54 * To create a plane, a KMS drivers allocates and zeroes an instances of55 * &struct drm_plane (possibly as part of a larger structure) and registers it56 * with a call to drm_universal_plane_init().57 *58 * Each plane has a type, see enum drm_plane_type. A plane can be compatible59 * with multiple CRTCs, see &drm_plane.possible_crtcs.60 *61 * Each CRTC must have a unique primary plane userspace can attach to enable62 * the CRTC. In other words, userspace must be able to attach a different63 * primary plane to each CRTC at the same time. Primary planes can still be64 * compatible with multiple CRTCs. There must be exactly as many primary planes65 * as there are CRTCs.66 *67 * Legacy uAPI doesn't expose the primary and cursor planes directly. DRM core68 * relies on the driver to set the primary and optionally the cursor plane used69 * for legacy IOCTLs. This is done by calling drm_crtc_init_with_planes(). All70 * drivers must provide one primary plane per CRTC to avoid surprising legacy71 * userspace too much.72 */73 74/**75 * DOC: standard plane properties76 *77 * DRM planes have a few standardized properties:78 *79 * type:80 *     Immutable property describing the type of the plane.81 *82 *     For user-space which has enabled the &DRM_CLIENT_CAP_ATOMIC capability,83 *     the plane type is just a hint and is mostly superseded by atomic84 *     test-only commits. The type hint can still be used to come up more85 *     easily with a plane configuration accepted by the driver.86 *87 *     The value of this property can be one of the following:88 *89 *     "Primary":90 *         To light up a CRTC, attaching a primary plane is the most likely to91 *         work if it covers the whole CRTC and doesn't have scaling or92 *         cropping set up.93 *94 *         Drivers may support more features for the primary plane, user-space95 *         can find out with test-only atomic commits.96 *97 *         Some primary planes are implicitly used by the kernel in the legacy98 *         IOCTLs &DRM_IOCTL_MODE_SETCRTC and &DRM_IOCTL_MODE_PAGE_FLIP.99 *         Therefore user-space must not mix explicit usage of any primary100 *         plane (e.g. through an atomic commit) with these legacy IOCTLs.101 *102 *     "Cursor":103 *         To enable this plane, using a framebuffer configured without scaling104 *         or cropping and with the following properties is the most likely to105 *         work:106 *107 *         - If the driver provides the capabilities &DRM_CAP_CURSOR_WIDTH and108 *           &DRM_CAP_CURSOR_HEIGHT, create the framebuffer with this size.109 *           Otherwise, create a framebuffer with the size 64x64.110 *         - If the driver doesn't support modifiers, create a framebuffer with111 *           a linear layout. Otherwise, use the IN_FORMATS plane property.112 *113 *         Drivers may support more features for the cursor plane, user-space114 *         can find out with test-only atomic commits.115 *116 *         Some cursor planes are implicitly used by the kernel in the legacy117 *         IOCTLs &DRM_IOCTL_MODE_CURSOR and &DRM_IOCTL_MODE_CURSOR2.118 *         Therefore user-space must not mix explicit usage of any cursor119 *         plane (e.g. through an atomic commit) with these legacy IOCTLs.120 *121 *         Some drivers may support cursors even if no cursor plane is exposed.122 *         In this case, the legacy cursor IOCTLs can be used to configure the123 *         cursor.124 *125 *     "Overlay":126 *         Neither primary nor cursor.127 *128 *         Overlay planes are the only planes exposed when the129 *         &DRM_CLIENT_CAP_UNIVERSAL_PLANES capability is disabled.130 *131 * IN_FORMATS:132 *     Blob property which contains the set of buffer format and modifier133 *     pairs supported by this plane. The blob is a struct134 *     drm_format_modifier_blob. Without this property the plane doesn't135 *     support buffers with modifiers. Userspace cannot change this property.136 *137 *     Note that userspace can check the &DRM_CAP_ADDFB2_MODIFIERS driver138 *     capability for general modifier support. If this flag is set then every139 *     plane will have the IN_FORMATS property, even when it only supports140 *     DRM_FORMAT_MOD_LINEAR. Before linux kernel release v5.1 there have been141 *     various bugs in this area with inconsistencies between the capability142 *     flag and per-plane properties.143 *144 * SIZE_HINTS:145 *     Blob property which contains the set of recommended plane size146 *     which can used for simple "cursor like" use cases (eg. no scaling).147 *     Using these hints frees userspace from extensive probing of148 *     supported plane sizes through atomic/setcursor ioctls.149 *150 *     The blob contains an array of struct drm_plane_size_hint, in151 *     order of preference. For optimal usage userspace should pick152 *     the first size that satisfies its own requirements.153 *154 *     Drivers should only attach this property to planes that155 *     support a very limited set of sizes.156 *157 *     Note that property value 0 (ie. no blob) is reserved for potential158 *     future use. Current userspace is expected to ignore the property159 *     if the value is 0, and fall back to some other means (eg.160 *     &DRM_CAP_CURSOR_WIDTH and &DRM_CAP_CURSOR_HEIGHT) to determine161 *     the appropriate plane size to use.162 */163 164static unsigned int drm_num_planes(struct drm_device *dev)165{166	unsigned int num = 0;167	struct drm_plane *tmp;168 169	drm_for_each_plane(tmp, dev) {170		num++;171	}172 173	return num;174}175 176static inline u32 *177formats_ptr(struct drm_format_modifier_blob *blob)178{179	return (u32 *)(((char *)blob) + blob->formats_offset);180}181 182static inline struct drm_format_modifier *183modifiers_ptr(struct drm_format_modifier_blob *blob)184{185	return (struct drm_format_modifier *)(((char *)blob) + blob->modifiers_offset);186}187 188static int create_in_format_blob(struct drm_device *dev, struct drm_plane *plane)189{190	const struct drm_mode_config *config = &dev->mode_config;191	struct drm_property_blob *blob;192	struct drm_format_modifier *mod;193	size_t blob_size, formats_size, modifiers_size;194	struct drm_format_modifier_blob *blob_data;195	unsigned int i, j;196 197	formats_size = sizeof(__u32) * plane->format_count;198	if (WARN_ON(!formats_size)) {199		/* 0 formats are never expected */200		return 0;201	}202 203	modifiers_size =204		sizeof(struct drm_format_modifier) * plane->modifier_count;205 206	blob_size = sizeof(struct drm_format_modifier_blob);207	/* Modifiers offset is a pointer to a struct with a 64 bit field so it208	 * should be naturally aligned to 8B.209	 */210	BUILD_BUG_ON(sizeof(struct drm_format_modifier_blob) % 8);211	blob_size += ALIGN(formats_size, 8);212	blob_size += modifiers_size;213 214	blob = drm_property_create_blob(dev, blob_size, NULL);215	if (IS_ERR(blob))216		return -1;217 218	blob_data = blob->data;219	blob_data->version = FORMAT_BLOB_CURRENT;220	blob_data->count_formats = plane->format_count;221	blob_data->formats_offset = sizeof(struct drm_format_modifier_blob);222	blob_data->count_modifiers = plane->modifier_count;223 224	blob_data->modifiers_offset =225		ALIGN(blob_data->formats_offset + formats_size, 8);226 227	memcpy(formats_ptr(blob_data), plane->format_types, formats_size);228 229	mod = modifiers_ptr(blob_data);230	for (i = 0; i < plane->modifier_count; i++) {231		for (j = 0; j < plane->format_count; j++) {232			if (!plane->funcs->format_mod_supported ||233			    plane->funcs->format_mod_supported(plane,234							       plane->format_types[j],235							       plane->modifiers[i])) {236				mod->formats |= 1ULL << j;237			}238		}239 240		mod->modifier = plane->modifiers[i];241		mod->offset = 0;242		mod->pad = 0;243		mod++;244	}245 246	drm_object_attach_property(&plane->base, config->modifiers_property,247				   blob->base.id);248 249	return 0;250}251 252/**253 * DOC: hotspot properties254 *255 * HOTSPOT_X: property to set mouse hotspot x offset.256 * HOTSPOT_Y: property to set mouse hotspot y offset.257 *258 * When the plane is being used as a cursor image to display a mouse pointer,259 * the "hotspot" is the offset within the cursor image where mouse events260 * are expected to go.261 *262 * Positive values move the hotspot from the top-left corner of the cursor263 * plane towards the right and bottom.264 *265 * Most display drivers do not need this information because the266 * hotspot is not actually connected to anything visible on screen.267 * However, this is necessary for display drivers like the para-virtualized268 * drivers (eg qxl, vbox, virtio, vmwgfx), that are attached to a user console269 * with a mouse pointer.  Since these consoles are often being remoted over a270 * network, they would otherwise have to wait to display the pointer movement to271 * the user until a full network round-trip has occurred.  New mouse events have272 * to be sent from the user's console, over the network to the virtual input273 * devices, forwarded to the desktop for processing, and then the cursor plane's274 * position can be updated and sent back to the user's console over the network.275 * Instead, with the hotspot information, the console can anticipate the new276 * location, and draw the mouse cursor there before the confirmation comes in.277 * To do that correctly, the user's console must be able predict how the278 * desktop will process mouse events, which normally requires the desktop's279 * mouse topology information, ie where each CRTC sits in the mouse coordinate280 * space.  This is typically sent to the para-virtualized drivers using some281 * driver-specific method, and the driver then forwards it to the console by282 * way of the virtual display device or hypervisor.283 *284 * The assumption is generally made that there is only one cursor plane being285 * used this way at a time, and that the desktop is feeding all mouse devices286 * into the same global pointer.  Para-virtualized drivers that require this287 * should only be exposing a single cursor plane, or find some other way288 * to coordinate with a userspace desktop that supports multiple pointers.289 * If the hotspot properties are set, the cursor plane is therefore assumed to be290 * used only for displaying a mouse cursor image, and the position of the combined291 * cursor plane + offset can therefore be used for coordinating with input from a292 * mouse device.293 *294 * The cursor will then be drawn either at the location of the plane in the CRTC295 * console, or as a free-floating cursor plane on the user's console296 * corresponding to their desktop mouse position.297 *298 * DRM clients which would like to work correctly on drivers which expose299 * hotspot properties should advertise DRM_CLIENT_CAP_CURSOR_PLANE_HOTSPOT.300 * Setting this property on drivers which do not special case301 * cursor planes will return EOPNOTSUPP, which can be used by userspace to302 * gauge requirements of the hardware/drivers they're running on. Advertising303 * DRM_CLIENT_CAP_CURSOR_PLANE_HOTSPOT implies that the userspace client will be304 * correctly setting the hotspot properties.305 */306 307/**308 * drm_plane_create_hotspot_properties - creates the mouse hotspot309 * properties and attaches them to the given cursor plane310 *311 * @plane: drm cursor plane312 *313 * This function enables the mouse hotspot property on a given314 * cursor plane. Look at the documentation for hotspot properties315 * to get a better understanding for what they're used for.316 *317 * RETURNS:318 * Zero for success or -errno319 */320static int drm_plane_create_hotspot_properties(struct drm_plane *plane)321{322	struct drm_property *prop_x;323	struct drm_property *prop_y;324 325	drm_WARN_ON(plane->dev,326		    !drm_core_check_feature(plane->dev,327					    DRIVER_CURSOR_HOTSPOT));328 329	prop_x = drm_property_create_signed_range(plane->dev, 0, "HOTSPOT_X",330						  INT_MIN, INT_MAX);331	if (IS_ERR(prop_x))332		return PTR_ERR(prop_x);333 334	prop_y = drm_property_create_signed_range(plane->dev, 0, "HOTSPOT_Y",335						  INT_MIN, INT_MAX);336	if (IS_ERR(prop_y)) {337		drm_property_destroy(plane->dev, prop_x);338		return PTR_ERR(prop_y);339	}340 341	drm_object_attach_property(&plane->base, prop_x, 0);342	drm_object_attach_property(&plane->base, prop_y, 0);343	plane->hotspot_x_property = prop_x;344	plane->hotspot_y_property = prop_y;345 346	return 0;347}348 349__printf(9, 0)350static int __drm_universal_plane_init(struct drm_device *dev,351				      struct drm_plane *plane,352				      uint32_t possible_crtcs,353				      const struct drm_plane_funcs *funcs,354				      const uint32_t *formats,355				      unsigned int format_count,356				      const uint64_t *format_modifiers,357				      enum drm_plane_type type,358				      const char *name, va_list ap)359{360	struct drm_mode_config *config = &dev->mode_config;361	static const uint64_t default_modifiers[] = {362		DRM_FORMAT_MOD_LINEAR,363	};364	unsigned int format_modifier_count = 0;365	int ret;366 367	/* plane index is used with 32bit bitmasks */368	if (WARN_ON(config->num_total_plane >= 32))369		return -EINVAL;370 371	/*372	 * First driver to need more than 64 formats needs to fix this. Each373	 * format is encoded as a bit and the current code only supports a u64.374	 */375	if (WARN_ON(format_count > 64))376		return -EINVAL;377 378	WARN_ON(drm_drv_uses_atomic_modeset(dev) &&379		(!funcs->atomic_destroy_state ||380		 !funcs->atomic_duplicate_state));381 382	ret = drm_mode_object_add(dev, &plane->base, DRM_MODE_OBJECT_PLANE);383	if (ret)384		return ret;385 386	drm_modeset_lock_init(&plane->mutex);387 388	plane->base.properties = &plane->properties;389	plane->dev = dev;390	plane->funcs = funcs;391	plane->format_types = kmalloc_array(format_count, sizeof(uint32_t),392					    GFP_KERNEL);393	if (!plane->format_types) {394		DRM_DEBUG_KMS("out of memory when allocating plane\n");395		drm_mode_object_unregister(dev, &plane->base);396		return -ENOMEM;397	}398 399	if (format_modifiers) {400		const uint64_t *temp_modifiers = format_modifiers;401 402		while (*temp_modifiers++ != DRM_FORMAT_MOD_INVALID)403			format_modifier_count++;404	} else {405		if (!dev->mode_config.fb_modifiers_not_supported) {406			format_modifiers = default_modifiers;407			format_modifier_count = ARRAY_SIZE(default_modifiers);408		}409	}410 411	/* autoset the cap and check for consistency across all planes */412	drm_WARN_ON(dev, config->fb_modifiers_not_supported &&413				format_modifier_count);414 415	plane->modifier_count = format_modifier_count;416	plane->modifiers = kmalloc_array(format_modifier_count,417					 sizeof(format_modifiers[0]),418					 GFP_KERNEL);419 420	if (format_modifier_count && !plane->modifiers) {421		DRM_DEBUG_KMS("out of memory when allocating plane\n");422		kfree(plane->format_types);423		drm_mode_object_unregister(dev, &plane->base);424		return -ENOMEM;425	}426 427	if (name) {428		plane->name = kvasprintf(GFP_KERNEL, name, ap);429	} else {430		plane->name = kasprintf(GFP_KERNEL, "plane-%d",431					drm_num_planes(dev));432	}433	if (!plane->name) {434		kfree(plane->format_types);435		kfree(plane->modifiers);436		drm_mode_object_unregister(dev, &plane->base);437		return -ENOMEM;438	}439 440	memcpy(plane->format_types, formats, format_count * sizeof(uint32_t));441	plane->format_count = format_count;442	memcpy(plane->modifiers, format_modifiers,443	       format_modifier_count * sizeof(format_modifiers[0]));444	plane->possible_crtcs = possible_crtcs;445	plane->type = type;446 447	list_add_tail(&plane->head, &config->plane_list);448	plane->index = config->num_total_plane++;449 450	drm_object_attach_property(&plane->base,451				   config->plane_type_property,452				   plane->type);453 454	if (drm_core_check_feature(dev, DRIVER_ATOMIC)) {455		drm_object_attach_property(&plane->base, config->prop_fb_id, 0);456		drm_object_attach_property(&plane->base, config->prop_in_fence_fd, -1);457		drm_object_attach_property(&plane->base, config->prop_crtc_id, 0);458		drm_object_attach_property(&plane->base, config->prop_crtc_x, 0);459		drm_object_attach_property(&plane->base, config->prop_crtc_y, 0);460		drm_object_attach_property(&plane->base, config->prop_crtc_w, 0);461		drm_object_attach_property(&plane->base, config->prop_crtc_h, 0);462		drm_object_attach_property(&plane->base, config->prop_src_x, 0);463		drm_object_attach_property(&plane->base, config->prop_src_y, 0);464		drm_object_attach_property(&plane->base, config->prop_src_w, 0);465		drm_object_attach_property(&plane->base, config->prop_src_h, 0);466	}467	if (drm_core_check_feature(dev, DRIVER_CURSOR_HOTSPOT) &&468	    type == DRM_PLANE_TYPE_CURSOR) {469		drm_plane_create_hotspot_properties(plane);470	}471 472	if (format_modifier_count)473		create_in_format_blob(dev, plane);474 475	return 0;476}477 478/**479 * drm_universal_plane_init - Initialize a new universal plane object480 * @dev: DRM device481 * @plane: plane object to init482 * @possible_crtcs: bitmask of possible CRTCs483 * @funcs: callbacks for the new plane484 * @formats: array of supported formats (DRM_FORMAT\_\*)485 * @format_count: number of elements in @formats486 * @format_modifiers: array of struct drm_format modifiers terminated by487 *                    DRM_FORMAT_MOD_INVALID488 * @type: type of plane (overlay, primary, cursor)489 * @name: printf style format string for the plane name, or NULL for default name490 *491 * Initializes a plane object of type @type. The &drm_plane_funcs.destroy hook492 * should call drm_plane_cleanup() and kfree() the plane structure. The plane493 * structure should not be allocated with devm_kzalloc().494 *495 * Note: consider using drmm_universal_plane_alloc() instead of496 * drm_universal_plane_init() to let the DRM managed resource infrastructure497 * take care of cleanup and deallocation.498 *499 * Drivers that only support the DRM_FORMAT_MOD_LINEAR modifier support may set500 * @format_modifiers to NULL. The plane will advertise the linear modifier.501 *502 * Returns:503 * Zero on success, error code on failure.504 */505int drm_universal_plane_init(struct drm_device *dev, struct drm_plane *plane,506			     uint32_t possible_crtcs,507			     const struct drm_plane_funcs *funcs,508			     const uint32_t *formats, unsigned int format_count,509			     const uint64_t *format_modifiers,510			     enum drm_plane_type type,511			     const char *name, ...)512{513	va_list ap;514	int ret;515 516	WARN_ON(!funcs->destroy);517 518	va_start(ap, name);519	ret = __drm_universal_plane_init(dev, plane, possible_crtcs, funcs,520					 formats, format_count, format_modifiers,521					 type, name, ap);522	va_end(ap);523	return ret;524}525EXPORT_SYMBOL(drm_universal_plane_init);526 527static void drmm_universal_plane_alloc_release(struct drm_device *dev, void *ptr)528{529	struct drm_plane *plane = ptr;530 531	if (WARN_ON(!plane->dev))532		return;533 534	drm_plane_cleanup(plane);535}536 537void *__drmm_universal_plane_alloc(struct drm_device *dev, size_t size,538				   size_t offset, uint32_t possible_crtcs,539				   const struct drm_plane_funcs *funcs,540				   const uint32_t *formats, unsigned int format_count,541				   const uint64_t *format_modifiers,542				   enum drm_plane_type type,543				   const char *name, ...)544{545	void *container;546	struct drm_plane *plane;547	va_list ap;548	int ret;549 550	if (WARN_ON(!funcs || funcs->destroy))551		return ERR_PTR(-EINVAL);552 553	container = drmm_kzalloc(dev, size, GFP_KERNEL);554	if (!container)555		return ERR_PTR(-ENOMEM);556 557	plane = container + offset;558 559	va_start(ap, name);560	ret = __drm_universal_plane_init(dev, plane, possible_crtcs, funcs,561					 formats, format_count, format_modifiers,562					 type, name, ap);563	va_end(ap);564	if (ret)565		return ERR_PTR(ret);566 567	ret = drmm_add_action_or_reset(dev, drmm_universal_plane_alloc_release,568				       plane);569	if (ret)570		return ERR_PTR(ret);571 572	return container;573}574EXPORT_SYMBOL(__drmm_universal_plane_alloc);575 576void *__drm_universal_plane_alloc(struct drm_device *dev, size_t size,577				  size_t offset, uint32_t possible_crtcs,578				  const struct drm_plane_funcs *funcs,579				  const uint32_t *formats, unsigned int format_count,580				  const uint64_t *format_modifiers,581				  enum drm_plane_type type,582				  const char *name, ...)583{584	void *container;585	struct drm_plane *plane;586	va_list ap;587	int ret;588 589	if (drm_WARN_ON(dev, !funcs))590		return ERR_PTR(-EINVAL);591 592	container = kzalloc(size, GFP_KERNEL);593	if (!container)594		return ERR_PTR(-ENOMEM);595 596	plane = container + offset;597 598	va_start(ap, name);599	ret = __drm_universal_plane_init(dev, plane, possible_crtcs, funcs,600					 formats, format_count, format_modifiers,601					 type, name, ap);602	va_end(ap);603	if (ret)604		goto err_kfree;605 606	return container;607 608err_kfree:609	kfree(container);610	return ERR_PTR(ret);611}612EXPORT_SYMBOL(__drm_universal_plane_alloc);613 614int drm_plane_register_all(struct drm_device *dev)615{616	unsigned int num_planes = 0;617	unsigned int num_zpos = 0;618	struct drm_plane *plane;619	int ret = 0;620 621	drm_for_each_plane(plane, dev) {622		if (plane->funcs->late_register)623			ret = plane->funcs->late_register(plane);624		if (ret)625			return ret;626 627		if (plane->zpos_property)628			num_zpos++;629		num_planes++;630	}631 632	drm_WARN(dev, num_zpos && num_planes != num_zpos,633		 "Mixing planes with and without zpos property is invalid\n");634 635	return 0;636}637 638void drm_plane_unregister_all(struct drm_device *dev)639{640	struct drm_plane *plane;641 642	drm_for_each_plane(plane, dev) {643		if (plane->funcs->early_unregister)644			plane->funcs->early_unregister(plane);645	}646}647 648/**649 * drm_plane_cleanup - Clean up the core plane usage650 * @plane: plane to cleanup651 *652 * This function cleans up @plane and removes it from the DRM mode setting653 * core. Note that the function does *not* free the plane structure itself,654 * this is the responsibility of the caller.655 */656void drm_plane_cleanup(struct drm_plane *plane)657{658	struct drm_device *dev = plane->dev;659 660	drm_modeset_lock_fini(&plane->mutex);661 662	kfree(plane->format_types);663	kfree(plane->modifiers);664	drm_mode_object_unregister(dev, &plane->base);665 666	BUG_ON(list_empty(&plane->head));667 668	/* Note that the plane_list is considered to be static; should we669	 * remove the drm_plane at runtime we would have to decrement all670	 * the indices on the drm_plane after us in the plane_list.671	 */672 673	list_del(&plane->head);674	dev->mode_config.num_total_plane--;675 676	WARN_ON(plane->state && !plane->funcs->atomic_destroy_state);677	if (plane->state && plane->funcs->atomic_destroy_state)678		plane->funcs->atomic_destroy_state(plane, plane->state);679 680	kfree(plane->name);681 682	memset(plane, 0, sizeof(*plane));683}684EXPORT_SYMBOL(drm_plane_cleanup);685 686/**687 * drm_plane_from_index - find the registered plane at an index688 * @dev: DRM device689 * @idx: index of registered plane to find for690 *691 * Given a plane index, return the registered plane from DRM device's692 * list of planes with matching index. This is the inverse of drm_plane_index().693 */694struct drm_plane *695drm_plane_from_index(struct drm_device *dev, int idx)696{697	struct drm_plane *plane;698 699	drm_for_each_plane(plane, dev)700		if (idx == plane->index)701			return plane;702 703	return NULL;704}705EXPORT_SYMBOL(drm_plane_from_index);706 707/**708 * drm_plane_force_disable - Forcibly disable a plane709 * @plane: plane to disable710 *711 * Forces the plane to be disabled.712 *713 * Used when the plane's current framebuffer is destroyed,714 * and when restoring fbdev mode.715 *716 * Note that this function is not suitable for atomic drivers, since it doesn't717 * wire through the lock acquisition context properly and hence can't handle718 * retries or driver private locks. You probably want to use719 * drm_atomic_helper_disable_plane() or720 * drm_atomic_helper_disable_planes_on_crtc() instead.721 */722void drm_plane_force_disable(struct drm_plane *plane)723{724	int ret;725 726	if (!plane->fb)727		return;728 729	WARN_ON(drm_drv_uses_atomic_modeset(plane->dev));730 731	plane->old_fb = plane->fb;732	ret = plane->funcs->disable_plane(plane, NULL);733	if (ret) {734		DRM_ERROR("failed to disable plane with busy fb\n");735		plane->old_fb = NULL;736		return;737	}738	/* disconnect the plane from the fb and crtc: */739	drm_framebuffer_put(plane->old_fb);740	plane->old_fb = NULL;741	plane->fb = NULL;742	plane->crtc = NULL;743}744EXPORT_SYMBOL(drm_plane_force_disable);745 746/**747 * drm_mode_plane_set_obj_prop - set the value of a property748 * @plane: drm plane object to set property value for749 * @property: property to set750 * @value: value the property should be set to751 *752 * This functions sets a given property on a given plane object. This function753 * calls the driver's ->set_property callback and changes the software state of754 * the property if the callback succeeds.755 *756 * Returns:757 * Zero on success, error code on failure.758 */759int drm_mode_plane_set_obj_prop(struct drm_plane *plane,760				struct drm_property *property,761				uint64_t value)762{763	int ret = -EINVAL;764	struct drm_mode_object *obj = &plane->base;765 766	if (plane->funcs->set_property)767		ret = plane->funcs->set_property(plane, property, value);768	if (!ret)769		drm_object_property_set_value(obj, property, value);770 771	return ret;772}773EXPORT_SYMBOL(drm_mode_plane_set_obj_prop);774 775int drm_mode_getplane_res(struct drm_device *dev, void *data,776			  struct drm_file *file_priv)777{778	struct drm_mode_get_plane_res *plane_resp = data;779	struct drm_plane *plane;780	uint32_t __user *plane_ptr;781	int count = 0;782 783	if (!drm_core_check_feature(dev, DRIVER_MODESET))784		return -EOPNOTSUPP;785 786	plane_ptr = u64_to_user_ptr(plane_resp->plane_id_ptr);787 788	/*789	 * This ioctl is called twice, once to determine how much space is790	 * needed, and the 2nd time to fill it.791	 */792	drm_for_each_plane(plane, dev) {793		/*794		 * Unless userspace set the 'universal planes'795		 * capability bit, only advertise overlays.796		 */797		if (plane->type != DRM_PLANE_TYPE_OVERLAY &&798		    !file_priv->universal_planes)799			continue;800 801		/*802		 * If we're running on a virtualized driver then,803		 * unless userspace advertizes support for the804		 * virtualized cursor plane, disable cursor planes805		 * because they'll be broken due to missing cursor806		 * hotspot info.807		 */808		if (plane->type == DRM_PLANE_TYPE_CURSOR &&809		    drm_core_check_feature(dev, DRIVER_CURSOR_HOTSPOT) &&810		    file_priv->atomic &&811		    !file_priv->supports_virtualized_cursor_plane)812			continue;813 814		if (drm_lease_held(file_priv, plane->base.id)) {815			if (count < plane_resp->count_planes &&816			    put_user(plane->base.id, plane_ptr + count))817				return -EFAULT;818			count++;819		}820	}821	plane_resp->count_planes = count;822 823	return 0;824}825 826int drm_mode_getplane(struct drm_device *dev, void *data,827		      struct drm_file *file_priv)828{829	struct drm_mode_get_plane *plane_resp = data;830	struct drm_plane *plane;831	uint32_t __user *format_ptr;832 833	if (!drm_core_check_feature(dev, DRIVER_MODESET))834		return -EOPNOTSUPP;835 836	plane = drm_plane_find(dev, file_priv, plane_resp->plane_id);837	if (!plane)838		return -ENOENT;839 840	drm_modeset_lock(&plane->mutex, NULL);841	if (plane->state && plane->state->crtc && drm_lease_held(file_priv, plane->state->crtc->base.id))842		plane_resp->crtc_id = plane->state->crtc->base.id;843	else if (!plane->state && plane->crtc && drm_lease_held(file_priv, plane->crtc->base.id))844		plane_resp->crtc_id = plane->crtc->base.id;845	else846		plane_resp->crtc_id = 0;847 848	if (plane->state && plane->state->fb)849		plane_resp->fb_id = plane->state->fb->base.id;850	else if (!plane->state && plane->fb)851		plane_resp->fb_id = plane->fb->base.id;852	else853		plane_resp->fb_id = 0;854	drm_modeset_unlock(&plane->mutex);855 856	plane_resp->plane_id = plane->base.id;857	plane_resp->possible_crtcs = drm_lease_filter_crtcs(file_priv,858							    plane->possible_crtcs);859 860	plane_resp->gamma_size = 0;861 862	/*863	 * This ioctl is called twice, once to determine how much space is864	 * needed, and the 2nd time to fill it.865	 */866	if (plane->format_count &&867	    (plane_resp->count_format_types >= plane->format_count)) {868		format_ptr = (uint32_t __user *)(unsigned long)plane_resp->format_type_ptr;869		if (copy_to_user(format_ptr,870				 plane->format_types,871				 sizeof(uint32_t) * plane->format_count)) {872			return -EFAULT;873		}874	}875	plane_resp->count_format_types = plane->format_count;876 877	return 0;878}879 880/**881 * drm_plane_has_format - Check whether the plane supports this format and modifier combination882 * @plane: drm plane883 * @format: pixel format (DRM_FORMAT_*)884 * @modifier: data layout modifier885 *886 * Returns:887 * Whether the plane supports the specified format and modifier combination.888 */889bool drm_plane_has_format(struct drm_plane *plane,890			  u32 format, u64 modifier)891{892	unsigned int i;893 894	for (i = 0; i < plane->format_count; i++) {895		if (format == plane->format_types[i])896			break;897	}898	if (i == plane->format_count)899		return false;900 901	if (plane->funcs->format_mod_supported) {902		if (!plane->funcs->format_mod_supported(plane, format, modifier))903			return false;904	} else {905		if (!plane->modifier_count)906			return true;907 908		for (i = 0; i < plane->modifier_count; i++) {909			if (modifier == plane->modifiers[i])910				break;911		}912		if (i == plane->modifier_count)913			return false;914	}915 916	return true;917}918EXPORT_SYMBOL(drm_plane_has_format);919 920static int __setplane_check(struct drm_plane *plane,921			    struct drm_crtc *crtc,922			    struct drm_framebuffer *fb,923			    int32_t crtc_x, int32_t crtc_y,924			    uint32_t crtc_w, uint32_t crtc_h,925			    uint32_t src_x, uint32_t src_y,926			    uint32_t src_w, uint32_t src_h)927{928	int ret;929 930	/* Check whether this plane is usable on this CRTC */931	if (!(plane->possible_crtcs & drm_crtc_mask(crtc))) {932		DRM_DEBUG_KMS("Invalid crtc for plane\n");933		return -EINVAL;934	}935 936	/* Check whether this plane supports the fb pixel format. */937	if (!drm_plane_has_format(plane, fb->format->format, fb->modifier)) {938		DRM_DEBUG_KMS("Invalid pixel format %p4cc, modifier 0x%llx\n",939			      &fb->format->format, fb->modifier);940		return -EINVAL;941	}942 943	/* Give drivers some help against integer overflows */944	if (crtc_w > INT_MAX ||945	    crtc_x > INT_MAX - (int32_t) crtc_w ||946	    crtc_h > INT_MAX ||947	    crtc_y > INT_MAX - (int32_t) crtc_h) {948		DRM_DEBUG_KMS("Invalid CRTC coordinates %ux%u+%d+%d\n",949			      crtc_w, crtc_h, crtc_x, crtc_y);950		return -ERANGE;951	}952 953	ret = drm_framebuffer_check_src_coords(src_x, src_y, src_w, src_h, fb);954	if (ret)955		return ret;956 957	return 0;958}959 960/**961 * drm_any_plane_has_format - Check whether any plane supports this format and modifier combination962 * @dev: DRM device963 * @format: pixel format (DRM_FORMAT_*)964 * @modifier: data layout modifier965 *966 * Returns:967 * Whether at least one plane supports the specified format and modifier combination.968 */969bool drm_any_plane_has_format(struct drm_device *dev,970			      u32 format, u64 modifier)971{972	struct drm_plane *plane;973 974	drm_for_each_plane(plane, dev) {975		if (drm_plane_has_format(plane, format, modifier))976			return true;977	}978 979	return false;980}981EXPORT_SYMBOL(drm_any_plane_has_format);982 983/*984 * __setplane_internal - setplane handler for internal callers985 *986 * This function will take a reference on the new fb for the plane987 * on success.988 *989 * src_{x,y,w,h} are provided in 16.16 fixed point format990 */991static int __setplane_internal(struct drm_plane *plane,992			       struct drm_crtc *crtc,993			       struct drm_framebuffer *fb,994			       int32_t crtc_x, int32_t crtc_y,995			       uint32_t crtc_w, uint32_t crtc_h,996			       /* src_{x,y,w,h} values are 16.16 fixed point */997			       uint32_t src_x, uint32_t src_y,998			       uint32_t src_w, uint32_t src_h,999			       struct drm_modeset_acquire_ctx *ctx)1000{1001	int ret = 0;1002 1003	WARN_ON(drm_drv_uses_atomic_modeset(plane->dev));1004 1005	/* No fb means shut it down */1006	if (!fb) {1007		plane->old_fb = plane->fb;1008		ret = plane->funcs->disable_plane(plane, ctx);1009		if (!ret) {1010			plane->crtc = NULL;1011			plane->fb = NULL;1012		} else {1013			plane->old_fb = NULL;1014		}1015		goto out;1016	}1017 1018	ret = __setplane_check(plane, crtc, fb,1019			       crtc_x, crtc_y, crtc_w, crtc_h,1020			       src_x, src_y, src_w, src_h);1021	if (ret)1022		goto out;1023 1024	plane->old_fb = plane->fb;1025	ret = plane->funcs->update_plane(plane, crtc, fb,1026					 crtc_x, crtc_y, crtc_w, crtc_h,1027					 src_x, src_y, src_w, src_h, ctx);1028	if (!ret) {1029		plane->crtc = crtc;1030		plane->fb = fb;1031		drm_framebuffer_get(plane->fb);1032	} else {1033		plane->old_fb = NULL;1034	}1035 1036out:1037	if (plane->old_fb)1038		drm_framebuffer_put(plane->old_fb);1039	plane->old_fb = NULL;1040 1041	return ret;1042}1043 1044static int __setplane_atomic(struct drm_plane *plane,1045			     struct drm_crtc *crtc,1046			     struct drm_framebuffer *fb,1047			     int32_t crtc_x, int32_t crtc_y,1048			     uint32_t crtc_w, uint32_t crtc_h,1049			     uint32_t src_x, uint32_t src_y,1050			     uint32_t src_w, uint32_t src_h,1051			     struct drm_modeset_acquire_ctx *ctx)1052{1053	int ret;1054 1055	WARN_ON(!drm_drv_uses_atomic_modeset(plane->dev));1056 1057	/* No fb means shut it down */1058	if (!fb)1059		return plane->funcs->disable_plane(plane, ctx);1060 1061	/*1062	 * FIXME: This is redundant with drm_atomic_plane_check(),1063	 * but the legacy cursor/"async" .update_plane() tricks1064	 * don't call that so we still need this here. Should remove1065	 * this when all .update_plane() implementations have been1066	 * fixed to call drm_atomic_plane_check().1067	 */1068	ret = __setplane_check(plane, crtc, fb,1069			       crtc_x, crtc_y, crtc_w, crtc_h,1070			       src_x, src_y, src_w, src_h);1071	if (ret)1072		return ret;1073 1074	return plane->funcs->update_plane(plane, crtc, fb,1075					  crtc_x, crtc_y, crtc_w, crtc_h,1076					  src_x, src_y, src_w, src_h, ctx);1077}1078 1079static int setplane_internal(struct drm_plane *plane,1080			     struct drm_crtc *crtc,1081			     struct drm_framebuffer *fb,1082			     int32_t crtc_x, int32_t crtc_y,1083			     uint32_t crtc_w, uint32_t crtc_h,1084			     /* src_{x,y,w,h} values are 16.16 fixed point */1085			     uint32_t src_x, uint32_t src_y,1086			     uint32_t src_w, uint32_t src_h)1087{1088	struct drm_modeset_acquire_ctx ctx;1089	int ret;1090 1091	DRM_MODESET_LOCK_ALL_BEGIN(plane->dev, ctx,1092				   DRM_MODESET_ACQUIRE_INTERRUPTIBLE, ret);1093 1094	if (drm_drv_uses_atomic_modeset(plane->dev))1095		ret = __setplane_atomic(plane, crtc, fb,1096					crtc_x, crtc_y, crtc_w, crtc_h,1097					src_x, src_y, src_w, src_h, &ctx);1098	else1099		ret = __setplane_internal(plane, crtc, fb,1100					  crtc_x, crtc_y, crtc_w, crtc_h,1101					  src_x, src_y, src_w, src_h, &ctx);1102 1103	DRM_MODESET_LOCK_ALL_END(plane->dev, ctx, ret);1104 1105	return ret;1106}1107 1108int drm_mode_setplane(struct drm_device *dev, void *data,1109		      struct drm_file *file_priv)1110{1111	struct drm_mode_set_plane *plane_req = data;1112	struct drm_plane *plane;1113	struct drm_crtc *crtc = NULL;1114	struct drm_framebuffer *fb = NULL;1115	int ret;1116 1117	if (!drm_core_check_feature(dev, DRIVER_MODESET))1118		return -EOPNOTSUPP;1119 1120	/*1121	 * First, find the plane, crtc, and fb objects.  If not available,1122	 * we don't bother to call the driver.1123	 */1124	plane = drm_plane_find(dev, file_priv, plane_req->plane_id);1125	if (!plane) {1126		DRM_DEBUG_KMS("Unknown plane ID %d\n",1127			      plane_req->plane_id);1128		return -ENOENT;1129	}1130 1131	if (plane_req->fb_id) {1132		fb = drm_framebuffer_lookup(dev, file_priv, plane_req->fb_id);1133		if (!fb) {1134			DRM_DEBUG_KMS("Unknown framebuffer ID %d\n",1135				      plane_req->fb_id);1136			return -ENOENT;1137		}1138 1139		crtc = drm_crtc_find(dev, file_priv, plane_req->crtc_id);1140		if (!crtc) {1141			drm_framebuffer_put(fb);1142			DRM_DEBUG_KMS("Unknown crtc ID %d\n",1143				      plane_req->crtc_id);1144			return -ENOENT;1145		}1146	}1147 1148	ret = setplane_internal(plane, crtc, fb,1149				plane_req->crtc_x, plane_req->crtc_y,1150				plane_req->crtc_w, plane_req->crtc_h,1151				plane_req->src_x, plane_req->src_y,1152				plane_req->src_w, plane_req->src_h);1153 1154	if (fb)1155		drm_framebuffer_put(fb);1156 1157	return ret;1158}1159 1160static int drm_mode_cursor_universal(struct drm_crtc *crtc,1161				     struct drm_mode_cursor2 *req,1162				     struct drm_file *file_priv,1163				     struct drm_modeset_acquire_ctx *ctx)1164{1165	struct drm_device *dev = crtc->dev;1166	struct drm_plane *plane = crtc->cursor;1167	struct drm_framebuffer *fb = NULL;1168	struct drm_mode_fb_cmd2 fbreq = {1169		.width = req->width,1170		.height = req->height,1171		.pixel_format = DRM_FORMAT_ARGB8888,1172		.pitches = { req->width * 4 },1173		.handles = { req->handle },1174	};1175	int32_t crtc_x, crtc_y;1176	uint32_t crtc_w = 0, crtc_h = 0;1177	uint32_t src_w = 0, src_h = 0;1178	int ret = 0;1179 1180	BUG_ON(!plane);1181	WARN_ON(plane->crtc != crtc && plane->crtc != NULL);1182 1183	/*1184	 * Obtain fb we'll be using (either new or existing) and take an extra1185	 * reference to it if fb != null.  setplane will take care of dropping1186	 * the reference if the plane update fails.1187	 */1188	if (req->flags & DRM_MODE_CURSOR_BO) {1189		if (req->handle) {1190			fb = drm_internal_framebuffer_create(dev, &fbreq, file_priv);1191			if (IS_ERR(fb)) {1192				DRM_DEBUG_KMS("failed to wrap cursor buffer in drm framebuffer\n");1193				return PTR_ERR(fb);1194			}1195 1196			if (plane->hotspot_x_property && plane->state)1197				plane->state->hotspot_x = req->hot_x;1198			if (plane->hotspot_y_property && plane->state)1199				plane->state->hotspot_y = req->hot_y;1200		} else {1201			fb = NULL;1202		}1203	} else {1204		if (plane->state)1205			fb = plane->state->fb;1206		else1207			fb = plane->fb;1208 1209		if (fb)1210			drm_framebuffer_get(fb);1211	}1212 1213	if (req->flags & DRM_MODE_CURSOR_MOVE) {1214		crtc_x = req->x;1215		crtc_y = req->y;1216	} else {1217		crtc_x = crtc->cursor_x;1218		crtc_y = crtc->cursor_y;1219	}1220 1221	if (fb) {1222		crtc_w = fb->width;1223		crtc_h = fb->height;1224		src_w = fb->width << 16;1225		src_h = fb->height << 16;1226	}1227 1228	if (drm_drv_uses_atomic_modeset(dev))1229		ret = __setplane_atomic(plane, crtc, fb,1230					crtc_x, crtc_y, crtc_w, crtc_h,1231					0, 0, src_w, src_h, ctx);1232	else1233		ret = __setplane_internal(plane, crtc, fb,1234					  crtc_x, crtc_y, crtc_w, crtc_h,1235					  0, 0, src_w, src_h, ctx);1236 1237	if (fb)1238		drm_framebuffer_put(fb);1239 1240	/* Update successful; save new cursor position, if necessary */1241	if (ret == 0 && req->flags & DRM_MODE_CURSOR_MOVE) {1242		crtc->cursor_x = req->x;1243		crtc->cursor_y = req->y;1244	}1245 1246	return ret;1247}1248 1249static int drm_mode_cursor_common(struct drm_device *dev,1250				  struct drm_mode_cursor2 *req,1251				  struct drm_file *file_priv)1252{1253	struct drm_crtc *crtc;1254	struct drm_modeset_acquire_ctx ctx;1255	int ret = 0;1256 1257	if (!drm_core_check_feature(dev, DRIVER_MODESET))1258		return -EOPNOTSUPP;1259 1260	if (!req->flags || (~DRM_MODE_CURSOR_FLAGS & req->flags))1261		return -EINVAL;1262 1263	crtc = drm_crtc_find(dev, file_priv, req->crtc_id);1264	if (!crtc) {1265		DRM_DEBUG_KMS("Unknown CRTC ID %d\n", req->crtc_id);1266		return -ENOENT;1267	}1268 1269	drm_modeset_acquire_init(&ctx, DRM_MODESET_ACQUIRE_INTERRUPTIBLE);1270retry:1271	ret = drm_modeset_lock(&crtc->mutex, &ctx);1272	if (ret)1273		goto out;1274	/*1275	 * If this crtc has a universal cursor plane, call that plane's update1276	 * handler rather than using legacy cursor handlers.1277	 */1278	if (crtc->cursor) {1279		ret = drm_modeset_lock(&crtc->cursor->mutex, &ctx);1280		if (ret)1281			goto out;1282 1283		if (!drm_lease_held(file_priv, crtc->cursor->base.id)) {1284			ret = -EACCES;1285			goto out;1286		}1287 1288		ret = drm_mode_cursor_universal(crtc, req, file_priv, &ctx);1289		goto out;1290	}1291 1292	if (req->flags & DRM_MODE_CURSOR_BO) {1293		if (!crtc->funcs->cursor_set && !crtc->funcs->cursor_set2) {1294			ret = -ENXIO;1295			goto out;1296		}1297		/* Turns off the cursor if handle is 0 */1298		if (crtc->funcs->cursor_set2)1299			ret = crtc->funcs->cursor_set2(crtc, file_priv, req->handle,1300						      req->width, req->height, req->hot_x, req->hot_y);1301		else1302			ret = crtc->funcs->cursor_set(crtc, file_priv, req->handle,1303						      req->width, req->height);1304	}1305 1306	if (req->flags & DRM_MODE_CURSOR_MOVE) {1307		if (crtc->funcs->cursor_move) {1308			ret = crtc->funcs->cursor_move(crtc, req->x, req->y);1309		} else {1310			ret = -EFAULT;1311			goto out;1312		}1313	}1314out:1315	if (ret == -EDEADLK) {1316		ret = drm_modeset_backoff(&ctx);1317		if (!ret)1318			goto retry;1319	}1320 1321	drm_modeset_drop_locks(&ctx);1322	drm_modeset_acquire_fini(&ctx);1323 1324	return ret;1325 1326}1327 1328 1329int drm_mode_cursor_ioctl(struct drm_device *dev,1330			  void *data, struct drm_file *file_priv)1331{1332	struct drm_mode_cursor *req = data;1333	struct drm_mode_cursor2 new_req;1334 1335	memcpy(&new_req, req, sizeof(struct drm_mode_cursor));1336	new_req.hot_x = new_req.hot_y = 0;1337 1338	return drm_mode_cursor_common(dev, &new_req, file_priv);1339}1340 1341/*1342 * Set the cursor configuration based on user request. This implements the 2nd1343 * version of the cursor ioctl, which allows userspace to additionally specify1344 * the hotspot of the pointer.1345 */1346int drm_mode_cursor2_ioctl(struct drm_device *dev,1347			   void *data, struct drm_file *file_priv)1348{1349	struct drm_mode_cursor2 *req = data;1350 1351	return drm_mode_cursor_common(dev, req, file_priv);1352}1353 1354int drm_mode_page_flip_ioctl(struct drm_device *dev,1355			     void *data, struct drm_file *file_priv)1356{1357	struct drm_mode_crtc_page_flip_target *page_flip = data;1358	struct drm_crtc *crtc;1359	struct drm_plane *plane;1360	struct drm_framebuffer *fb = NULL, *old_fb;1361	struct drm_pending_vblank_event *e = NULL;1362	u32 target_vblank = page_flip->sequence;1363	struct drm_modeset_acquire_ctx ctx;1364	int ret = -EINVAL;1365 1366	if (!drm_core_check_feature(dev, DRIVER_MODESET))1367		return -EOPNOTSUPP;1368 1369	if (page_flip->flags & ~DRM_MODE_PAGE_FLIP_FLAGS)1370		return -EINVAL;1371 1372	if (page_flip->sequence != 0 && !(page_flip->flags & DRM_MODE_PAGE_FLIP_TARGET))1373		return -EINVAL;1374 1375	/* Only one of the DRM_MODE_PAGE_FLIP_TARGET_ABSOLUTE/RELATIVE flags1376	 * can be specified1377	 */1378	if ((page_flip->flags & DRM_MODE_PAGE_FLIP_TARGET) == DRM_MODE_PAGE_FLIP_TARGET)1379		return -EINVAL;1380 1381	if ((page_flip->flags & DRM_MODE_PAGE_FLIP_ASYNC) && !dev->mode_config.async_page_flip)1382		return -EINVAL;1383 1384	crtc = drm_crtc_find(dev, file_priv, page_flip->crtc_id);1385	if (!crtc)1386		return -ENOENT;1387 1388	plane = crtc->primary;1389 1390	if (!drm_lease_held(file_priv, plane->base.id))1391		return -EACCES;1392 1393	if (crtc->funcs->page_flip_target) {1394		u32 current_vblank;1395		int r;1396 1397		r = drm_crtc_vblank_get(crtc);1398		if (r)1399			return r;1400 1401		current_vblank = (u32)drm_crtc_vblank_count(crtc);1402 1403		switch (page_flip->flags & DRM_MODE_PAGE_FLIP_TARGET) {1404		case DRM_MODE_PAGE_FLIP_TARGET_ABSOLUTE:1405			if ((int)(target_vblank - current_vblank) > 1) {1406				DRM_DEBUG("Invalid absolute flip target %u, "1407					  "must be <= %u\n", target_vblank,1408					  current_vblank + 1);1409				drm_crtc_vblank_put(crtc);1410				return -EINVAL;1411			}1412			break;1413		case DRM_MODE_PAGE_FLIP_TARGET_RELATIVE:1414			if (target_vblank != 0 && target_vblank != 1) {1415				DRM_DEBUG("Invalid relative flip target %u, "1416					  "must be 0 or 1\n", target_vblank);1417				drm_crtc_vblank_put(crtc);1418				return -EINVAL;1419			}1420			target_vblank += current_vblank;1421			break;1422		default:1423			target_vblank = current_vblank +1424				!(page_flip->flags & DRM_MODE_PAGE_FLIP_ASYNC);1425			break;1426		}1427	} else if (crtc->funcs->page_flip == NULL ||1428		   (page_flip->flags & DRM_MODE_PAGE_FLIP_TARGET)) {1429		return -EINVAL;1430	}1431 1432	drm_modeset_acquire_init(&ctx, DRM_MODESET_ACQUIRE_INTERRUPTIBLE);1433retry:1434	ret = drm_modeset_lock(&crtc->mutex, &ctx);1435	if (ret)1436		goto out;1437	ret = drm_modeset_lock(&plane->mutex, &ctx);1438	if (ret)1439		goto out;1440 1441	if (plane->state)1442		old_fb = plane->state->fb;1443	else1444		old_fb = plane->fb;1445 1446	if (old_fb == NULL) {1447		/* The framebuffer is currently unbound, presumably1448		 * due to a hotplug event, that userspace has not1449		 * yet discovered.1450		 */1451		ret = -EBUSY;1452		goto out;1453	}1454 1455	fb = drm_framebuffer_lookup(dev, file_priv, page_flip->fb_id);1456	if (!fb) {1457		ret = -ENOENT;1458		goto out;1459	}1460 1461	if (plane->state) {1462		const struct drm_plane_state *state = plane->state;1463 1464		ret = drm_framebuffer_check_src_coords(state->src_x,1465						       state->src_y,1466						       state->src_w,1467						       state->src_h,1468						       fb);1469	} else {1470		ret = drm_crtc_check_viewport(crtc, crtc->x, crtc->y,1471					      &crtc->mode, fb);1472	}1473	if (ret)1474		goto out;1475 1476	/*1477	 * Only check the FOURCC format code, excluding modifiers. This is1478	 * enough for all legacy drivers. Atomic drivers have their own1479	 * checks in their ->atomic_check implementation, which will1480	 * return -EINVAL if any hw or driver constraint is violated due1481	 * to modifier changes.1482	 */1483	if (old_fb->format->format != fb->format->format) {1484		DRM_DEBUG_KMS("Page flip is not allowed to change frame buffer format.\n");1485		ret = -EINVAL;1486		goto out;1487	}1488 1489	if (page_flip->flags & DRM_MODE_PAGE_FLIP_EVENT) {1490		e = kzalloc(sizeof *e, GFP_KERNEL);1491		if (!e) {1492			ret = -ENOMEM;1493			goto out;1494		}1495 1496		e->event.base.type = DRM_EVENT_FLIP_COMPLETE;1497		e->event.base.length = sizeof(e->event);1498		e->event.vbl.user_data = page_flip->user_data;1499		e->event.vbl.crtc_id = crtc->base.id;1500 1501		ret = drm_event_reserve_init(dev, file_priv, &e->base, &e->event.base);1502		if (ret) {1503			kfree(e);1504			e = NULL;1505			goto out;1506		}1507	}1508 1509	plane->old_fb = plane->fb;1510	if (crtc->funcs->page_flip_target)1511		ret = crtc->funcs->page_flip_target(crtc, fb, e,1512						    page_flip->flags,1513						    target_vblank,1514						    &ctx);1515	else1516		ret = crtc->funcs->page_flip(crtc, fb, e, page_flip->flags,1517					     &ctx);1518	if (ret) {1519		if (page_flip->flags & DRM_MODE_PAGE_FLIP_EVENT)1520			drm_event_cancel_free(dev, &e->base);1521		/* Keep the old fb, don't unref it. */1522		plane->old_fb = NULL;1523	} else {1524		if (!plane->state) {1525			plane->fb = fb;1526			drm_framebuffer_get(fb);1527		}1528	}1529 1530out:1531	if (fb)1532		drm_framebuffer_put(fb);1533	fb = NULL;1534	if (plane->old_fb)1535		drm_framebuffer_put(plane->old_fb);1536	plane->old_fb = NULL;1537 1538	if (ret == -EDEADLK) {1539		ret = drm_modeset_backoff(&ctx);1540		if (!ret)1541			goto retry;1542	}1543 1544	drm_modeset_drop_locks(&ctx);1545	drm_modeset_acquire_fini(&ctx);1546 1547	if (ret && crtc->funcs->page_flip_target)1548		drm_crtc_vblank_put(crtc);1549 1550	return ret;1551}1552 1553/**1554 * DOC: damage tracking1555 *1556 * FB_DAMAGE_CLIPS is an optional plane property which provides a means to1557 * specify a list of damage rectangles on a plane in framebuffer coordinates of1558 * the framebuffer attached to the plane. In current context damage is the area1559 * of plane framebuffer that has changed since last plane update (also called1560 * page-flip), irrespective of whether currently attached framebuffer is same as1561 * framebuffer attached during last plane update or not.1562 *1563 * FB_DAMAGE_CLIPS is a hint to kernel which could be helpful for some drivers1564 * to optimize internally especially for virtual devices where each framebuffer1565 * change needs to be transmitted over network, usb, etc.1566 *1567 * Since FB_DAMAGE_CLIPS is a hint so it is an optional property. User-space can1568 * ignore damage clips property and in that case driver will do a full plane1569 * update. In case damage clips are provided then it is guaranteed that the area1570 * inside damage clips will be updated to plane. For efficiency driver can do1571 * full update or can update more than specified in damage clips. Since driver1572 * is free to read more, user-space must always render the entire visible1573 * framebuffer. Otherwise there can be corruptions. Also, if a user-space1574 * provides damage clips which doesn't encompass the actual damage to1575 * framebuffer (since last plane update) can result in incorrect rendering.1576 *1577 * FB_DAMAGE_CLIPS is a blob property with the layout of blob data is simply an1578 * array of &drm_mode_rect. Unlike plane &drm_plane_state.src coordinates,1579 * damage clips are not in 16.16 fixed point. Similar to plane src in1580 * framebuffer, damage clips cannot be negative. In damage clip, x1/y1 are1581 * inclusive and x2/y2 are exclusive. While kernel does not error for overlapped1582 * damage clips, it is strongly discouraged.1583 *1584 * Drivers that are interested in damage interface for plane should enable1585 * FB_DAMAGE_CLIPS property by calling drm_plane_enable_fb_damage_clips().1586 * Drivers implementing damage can use drm_atomic_helper_damage_iter_init() and1587 * drm_atomic_helper_damage_iter_next() helper iterator function to get damage1588 * rectangles clipped to &drm_plane_state.src.1589 *1590 * Note that there are two types of damage handling: frame damage and buffer1591 * damage, the type of damage handling implemented depends on a driver's upload1592 * target. Drivers implementing a per-plane or per-CRTC upload target need to1593 * handle frame damage, while drivers implementing a per-buffer upload target1594 * need to handle buffer damage.1595 *1596 * The existing damage helpers only support the frame damage type, there is no1597 * buffer age support or similar damage accumulation algorithm implemented yet.1598 *1599 * Only drivers handling frame damage can use the mentioned damage helpers to1600 * iterate over the damaged regions. Drivers that handle buffer damage, must set1601 * &drm_plane_state.ignore_damage_clips for drm_atomic_helper_damage_iter_init()1602 * to know that damage clips should be ignored and return &drm_plane_state.src1603 * as the damage rectangle, to force a full plane update.1604 *1605 * Drivers with a per-buffer upload target could compare the &drm_plane_state.fb1606 * of the old and new plane states to determine if the framebuffer attached to a1607 * plane has changed or not since the last plane update. If &drm_plane_state.fb1608 * has changed, then &drm_plane_state.ignore_damage_clips must be set to true.1609 *1610 * That is because drivers with a per-plane upload target, expect the backing1611 * storage buffer to not change for a given plane. If the upload buffer changes1612 * between page flips, the new upload buffer has to be updated as a whole. This1613 * can be improved in the future if support for frame damage is added to the DRM1614 * damage helpers, similarly to how user-space already handle this case as it is1615 * explained in the following documents:1616 *1617 *     https://registry.khronos.org/EGL/extensions/KHR/EGL_KHR_swap_buffers_with_damage.txt1618 *     https://emersion.fr/blog/2019/intro-to-damage-tracking/1619 */1620 1621/**1622 * drm_plane_enable_fb_damage_clips - Enables plane fb damage clips property.1623 * @plane: Plane on which to enable damage clips property.1624 *1625 * This function lets driver to enable the damage clips property on a plane.1626 */1627void drm_plane_enable_fb_damage_clips(struct drm_plane *plane)1628{1629	struct drm_device *dev = plane->dev;1630	struct drm_mode_config *config = &dev->mode_config;1631 1632	drm_object_attach_property(&plane->base, config->prop_fb_damage_clips,1633				   0);1634}1635EXPORT_SYMBOL(drm_plane_enable_fb_damage_clips);1636 1637/**1638 * drm_plane_get_damage_clips_count - Returns damage clips count.1639 * @state: Plane state.1640 *1641 * Simple helper to get the number of &drm_mode_rect clips set by user-space1642 * during plane update.1643 *1644 * Return: Number of clips in plane fb_damage_clips blob property.1645 */1646unsigned int1647drm_plane_get_damage_clips_count(const struct drm_plane_state *state)1648{1649	return (state && state->fb_damage_clips) ?1650		state->fb_damage_clips->length/sizeof(struct drm_mode_rect) : 0;1651}1652EXPORT_SYMBOL(drm_plane_get_damage_clips_count);1653 1654struct drm_mode_rect *1655__drm_plane_get_damage_clips(const struct drm_plane_state *state)1656{1657	return (struct drm_mode_rect *)((state && state->fb_damage_clips) ?1658					state->fb_damage_clips->data : NULL);1659}1660 1661/**1662 * drm_plane_get_damage_clips - Returns damage clips.1663 * @state: Plane state.1664 *1665 * Note that this function returns uapi type &drm_mode_rect. Drivers might want1666 * to use the helper functions drm_atomic_helper_damage_iter_init() and1667 * drm_atomic_helper_damage_iter_next() or drm_atomic_helper_damage_merged() if1668 * the driver can only handle a single damage region at most.1669 *1670 * Return: Damage clips in plane fb_damage_clips blob property.1671 */1672struct drm_mode_rect *1673drm_plane_get_damage_clips(const struct drm_plane_state *state)1674{1675	struct drm_device *dev = state->plane->dev;1676	struct drm_mode_config *config = &dev->mode_config;1677 1678	/* check that drm_plane_enable_fb_damage_clips() was called */1679	if (!drm_mode_obj_find_prop_id(&state->plane->base,1680				       config->prop_fb_damage_clips->base.id))1681		drm_warn_once(dev, "drm_plane_enable_fb_damage_clips() not called\n");1682 1683	return __drm_plane_get_damage_clips(state);1684}1685EXPORT_SYMBOL(drm_plane_get_damage_clips);1686 1687struct drm_property *1688drm_create_scaling_filter_prop(struct drm_device *dev,1689			       unsigned int supported_filters)1690{1691	struct drm_property *prop;1692	static const struct drm_prop_enum_list props[] = {1693		{ DRM_SCALING_FILTER_DEFAULT, "Default" },1694		{ DRM_SCALING_FILTER_NEAREST_NEIGHBOR, "Nearest Neighbor" },1695	};1696	unsigned int valid_mode_mask = BIT(DRM_SCALING_FILTER_DEFAULT) |1697				       BIT(DRM_SCALING_FILTER_NEAREST_NEIGHBOR);1698	int i;1699 1700	if (WARN_ON((supported_filters & ~valid_mode_mask) ||1701		    ((supported_filters & BIT(DRM_SCALING_FILTER_DEFAULT)) == 0)))1702		return ERR_PTR(-EINVAL);1703 1704	prop = drm_property_create(dev, DRM_MODE_PROP_ENUM,1705				   "SCALING_FILTER",1706				   hweight32(supported_filters));1707	if (!prop)1708		return ERR_PTR(-ENOMEM);1709 1710	for (i = 0; i < ARRAY_SIZE(props); i++) {1711		int ret;1712 1713		if (!(BIT(props[i].type) & supported_filters))1714			continue;1715 1716		ret = drm_property_add_enum(prop, props[i].type,1717					    props[i].name);1718 1719		if (ret) {1720			drm_property_destroy(dev, prop);1721 1722			return ERR_PTR(ret);1723		}1724	}1725 1726	return prop;1727}1728 1729/**1730 * drm_plane_create_scaling_filter_property - create a new scaling filter1731 * property1732 *1733 * @plane: drm plane1734 * @supported_filters: bitmask of supported scaling filters, must include1735 *		       BIT(DRM_SCALING_FILTER_DEFAULT).1736 *1737 * This function lets driver to enable the scaling filter property on a given1738 * plane.1739 *1740 * RETURNS:1741 * Zero for success or -errno1742 */1743int drm_plane_create_scaling_filter_property(struct drm_plane *plane,1744					     unsigned int supported_filters)1745{1746	struct drm_property *prop =1747		drm_create_scaling_filter_prop(plane->dev, supported_filters);1748 1749	if (IS_ERR(prop))1750		return PTR_ERR(prop);1751 1752	drm_object_attach_property(&plane->base, prop,1753				   DRM_SCALING_FILTER_DEFAULT);1754	plane->scaling_filter_property = prop;1755 1756	return 0;1757}1758EXPORT_SYMBOL(drm_plane_create_scaling_filter_property);1759 1760/**1761 * drm_plane_add_size_hints_property - create a size hints property1762 *1763 * @plane: drm plane1764 * @hints: size hints1765 * @num_hints: number of size hints1766 *1767 * Create a size hints property for the plane.1768 *1769 * RETURNS:1770 * Zero for success or -errno1771 */1772int drm_plane_add_size_hints_property(struct drm_plane *plane,1773				      const struct drm_plane_size_hint *hints,1774				      int num_hints)1775{1776	struct drm_device *dev = plane->dev;1777	struct drm_mode_config *config = &dev->mode_config;1778	struct drm_property_blob *blob;1779 1780	/* extending to other plane types needs actual thought */1781	if (drm_WARN_ON(dev, plane->type != DRM_PLANE_TYPE_CURSOR))1782		return -EINVAL;1783 1784	blob = drm_property_create_blob(dev,1785					array_size(sizeof(hints[0]), num_hints),1786					hints);1787	if (IS_ERR(blob))1788		return PTR_ERR(blob);1789 1790	drm_object_attach_property(&plane->base, config->size_hints_property,1791				   blob->base.id);1792 1793	return 0;1794}1795EXPORT_SYMBOL(drm_plane_add_size_hints_property);1796