LCOV - code coverage report
Current view: top level - drivers/gpu/drm - drm_plane.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 24 531 4.5 %
Date: 2023-03-27 20:00:47 Functions: 5 32 15.6 %

          Line data    Source code
       1             : /*
       2             :  * Copyright (c) 2016 Intel Corporation
       3             :  *
       4             :  * Permission to use, copy, modify, distribute, and sell this software and its
       5             :  * documentation for any purpose is hereby granted without fee, provided that
       6             :  * the above copyright notice appear in all copies and that both that copyright
       7             :  * notice and this permission notice appear in supporting documentation, and
       8             :  * that the name of the copyright holders not be used in advertising or
       9             :  * publicity pertaining to distribution of the software without specific,
      10             :  * written prior permission.  The copyright holders make no representations
      11             :  * about the suitability of this software for any purpose.  It is provided "as
      12             :  * 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 NO
      16             :  * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
      17             :  * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
      18             :  * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
      19             :  * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
      20             :  * 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: overview
      40             :  *
      41             :  * A plane represents an image source that can be blended with or overlaid on
      42             :  * top of a CRTC during the scanout process. Planes take their input data from a
      43             :  * &drm_framebuffer object. The plane itself specifies the cropping and scaling
      44             :  * of that image, and where it is placed on the visible area of a display
      45             :  * pipeline, represented by &drm_crtc. A plane can also have additional
      46             :  * properties that specify how the pixels are positioned and blended, like
      47             :  * 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 area
      50             :  * of a CRTC will be black by default. This means portions of the active area
      51             :  * which are not covered by a plane will be black, and alpha blending of any
      52             :  * 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 of
      55             :  * &struct drm_plane (possibly as part of a larger structure) and registers it
      56             :  * with a call to drm_universal_plane_init().
      57             :  *
      58             :  * Each plane has a type, see enum drm_plane_type. A plane can be compatible
      59             :  * with multiple CRTCs, see &drm_plane.possible_crtcs.
      60             :  *
      61             :  * Each CRTC must have a unique primary plane userspace can attach to enable
      62             :  * the CRTC. In other words, userspace must be able to attach a different
      63             :  * primary plane to each CRTC at the same time. Primary planes can still be
      64             :  * compatible with multiple CRTCs. There must be exactly as many primary planes
      65             :  * as there are CRTCs.
      66             :  *
      67             :  * Legacy uAPI doesn't expose the primary and cursor planes directly. DRM core
      68             :  * relies on the driver to set the primary and optionally the cursor plane used
      69             :  * for legacy IOCTLs. This is done by calling drm_crtc_init_with_planes(). All
      70             :  * drivers must provide one primary plane per CRTC to avoid surprising legacy
      71             :  * userspace too much.
      72             :  */
      73             : 
      74             : /**
      75             :  * DOC: standard plane properties
      76             :  *
      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 atomic
      84             :  *     test-only commits. The type hint can still be used to come up more
      85             :  *     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 to
      91             :  *         work if it covers the whole CRTC and doesn't have scaling or
      92             :  *         cropping set up.
      93             :  *
      94             :  *         Drivers may support more features for the primary plane, user-space
      95             :  *         can find out with test-only atomic commits.
      96             :  *
      97             :  *         Some primary planes are implicitly used by the kernel in the legacy
      98             :  *         IOCTLs &DRM_IOCTL_MODE_SETCRTC and &DRM_IOCTL_MODE_PAGE_FLIP.
      99             :  *         Therefore user-space must not mix explicit usage of any primary
     100             :  *         plane (e.g. through an atomic commit) with these legacy IOCTLs.
     101             :  *
     102             :  *     "Cursor":
     103             :  *         To enable this plane, using a framebuffer configured without scaling
     104             :  *         or cropping and with the following properties is the most likely to
     105             :  *         work:
     106             :  *
     107             :  *         - If the driver provides the capabilities &DRM_CAP_CURSOR_WIDTH and
     108             :  *           &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 with
     111             :  *           a linear layout. Otherwise, use the IN_FORMATS plane property.
     112             :  *
     113             :  *         Drivers may support more features for the cursor plane, user-space
     114             :  *         can find out with test-only atomic commits.
     115             :  *
     116             :  *         Some cursor planes are implicitly used by the kernel in the legacy
     117             :  *         IOCTLs &DRM_IOCTL_MODE_CURSOR and &DRM_IOCTL_MODE_CURSOR2.
     118             :  *         Therefore user-space must not mix explicit usage of any cursor
     119             :  *         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 the
     123             :  *         cursor.
     124             :  *
     125             :  *     "Overlay":
     126             :  *         Neither primary nor cursor.
     127             :  *
     128             :  *         Overlay planes are the only planes exposed when the
     129             :  *         &DRM_CLIENT_CAP_UNIVERSAL_PLANES capability is disabled.
     130             :  *
     131             :  * IN_FORMATS:
     132             :  *     Blob property which contains the set of buffer format and modifier
     133             :  *     pairs supported by this plane. The blob is a struct
     134             :  *     drm_format_modifier_blob. Without this property the plane doesn't
     135             :  *     support buffers with modifiers. Userspace cannot change this property.
     136             :  *
     137             :  *     Note that userspace can check the &DRM_CAP_ADDFB2_MODIFIERS driver
     138             :  *     capability for general modifier support. If this flag is set then every
     139             :  *     plane will have the IN_FORMATS property, even when it only supports
     140             :  *     DRM_FORMAT_MOD_LINEAR. Before linux kernel release v5.1 there have been
     141             :  *     various bugs in this area with inconsistencies between the capability
     142             :  *     flag and per-plane properties.
     143             :  */
     144             : 
     145             : static unsigned int drm_num_planes(struct drm_device *dev)
     146             : {
     147           0 :         unsigned int num = 0;
     148             :         struct drm_plane *tmp;
     149             : 
     150           0 :         drm_for_each_plane(tmp, dev) {
     151           0 :                 num++;
     152             :         }
     153             : 
     154             :         return num;
     155             : }
     156             : 
     157             : static inline u32 *
     158             : formats_ptr(struct drm_format_modifier_blob *blob)
     159             : {
     160           0 :         return (u32 *)(((char *)blob) + blob->formats_offset);
     161             : }
     162             : 
     163             : static inline struct drm_format_modifier *
     164             : modifiers_ptr(struct drm_format_modifier_blob *blob)
     165             : {
     166           0 :         return (struct drm_format_modifier *)(((char *)blob) + blob->modifiers_offset);
     167             : }
     168             : 
     169           0 : static int create_in_format_blob(struct drm_device *dev, struct drm_plane *plane)
     170             : {
     171           0 :         const struct drm_mode_config *config = &dev->mode_config;
     172             :         struct drm_property_blob *blob;
     173             :         struct drm_format_modifier *mod;
     174             :         size_t blob_size, formats_size, modifiers_size;
     175             :         struct drm_format_modifier_blob *blob_data;
     176             :         unsigned int i, j;
     177             : 
     178           0 :         formats_size = sizeof(__u32) * plane->format_count;
     179           0 :         if (WARN_ON(!formats_size)) {
     180             :                 /* 0 formats are never expected */
     181             :                 return 0;
     182             :         }
     183             : 
     184           0 :         modifiers_size =
     185           0 :                 sizeof(struct drm_format_modifier) * plane->modifier_count;
     186             : 
     187           0 :         blob_size = sizeof(struct drm_format_modifier_blob);
     188             :         /* Modifiers offset is a pointer to a struct with a 64 bit field so it
     189             :          * should be naturally aligned to 8B.
     190             :          */
     191             :         BUILD_BUG_ON(sizeof(struct drm_format_modifier_blob) % 8);
     192           0 :         blob_size += ALIGN(formats_size, 8);
     193           0 :         blob_size += modifiers_size;
     194             : 
     195           0 :         blob = drm_property_create_blob(dev, blob_size, NULL);
     196           0 :         if (IS_ERR(blob))
     197             :                 return -1;
     198             : 
     199           0 :         blob_data = blob->data;
     200           0 :         blob_data->version = FORMAT_BLOB_CURRENT;
     201           0 :         blob_data->count_formats = plane->format_count;
     202           0 :         blob_data->formats_offset = sizeof(struct drm_format_modifier_blob);
     203           0 :         blob_data->count_modifiers = plane->modifier_count;
     204             : 
     205           0 :         blob_data->modifiers_offset =
     206           0 :                 ALIGN(blob_data->formats_offset + formats_size, 8);
     207             : 
     208           0 :         memcpy(formats_ptr(blob_data), plane->format_types, formats_size);
     209             : 
     210           0 :         mod = modifiers_ptr(blob_data);
     211           0 :         for (i = 0; i < plane->modifier_count; i++) {
     212           0 :                 for (j = 0; j < plane->format_count; j++) {
     213           0 :                         if (!plane->funcs->format_mod_supported ||
     214           0 :                             plane->funcs->format_mod_supported(plane,
     215           0 :                                                                plane->format_types[j],
     216           0 :                                                                plane->modifiers[i])) {
     217           0 :                                 mod->formats |= 1ULL << j;
     218             :                         }
     219             :                 }
     220             : 
     221           0 :                 mod->modifier = plane->modifiers[i];
     222           0 :                 mod->offset = 0;
     223           0 :                 mod->pad = 0;
     224           0 :                 mod++;
     225             :         }
     226             : 
     227           0 :         drm_object_attach_property(&plane->base, config->modifiers_property,
     228           0 :                                    blob->base.id);
     229             : 
     230           0 :         return 0;
     231             : }
     232             : 
     233             : __printf(9, 0)
     234           0 : static int __drm_universal_plane_init(struct drm_device *dev,
     235             :                                       struct drm_plane *plane,
     236             :                                       uint32_t possible_crtcs,
     237             :                                       const struct drm_plane_funcs *funcs,
     238             :                                       const uint32_t *formats,
     239             :                                       unsigned int format_count,
     240             :                                       const uint64_t *format_modifiers,
     241             :                                       enum drm_plane_type type,
     242             :                                       const char *name, va_list ap)
     243             : {
     244           0 :         struct drm_mode_config *config = &dev->mode_config;
     245             :         static const uint64_t default_modifiers[] = {
     246             :                 DRM_FORMAT_MOD_LINEAR,
     247             :         };
     248           0 :         unsigned int format_modifier_count = 0;
     249             :         int ret;
     250             : 
     251             :         /* plane index is used with 32bit bitmasks */
     252           0 :         if (WARN_ON(config->num_total_plane >= 32))
     253             :                 return -EINVAL;
     254             : 
     255             :         /*
     256             :          * First driver to need more than 64 formats needs to fix this. Each
     257             :          * format is encoded as a bit and the current code only supports a u64.
     258             :          */
     259           0 :         if (WARN_ON(format_count > 64))
     260             :                 return -EINVAL;
     261             : 
     262           0 :         WARN_ON(drm_drv_uses_atomic_modeset(dev) &&
     263             :                 (!funcs->atomic_destroy_state ||
     264             :                  !funcs->atomic_duplicate_state));
     265             : 
     266           0 :         ret = drm_mode_object_add(dev, &plane->base, DRM_MODE_OBJECT_PLANE);
     267           0 :         if (ret)
     268             :                 return ret;
     269             : 
     270           0 :         drm_modeset_lock_init(&plane->mutex);
     271             : 
     272           0 :         plane->base.properties = &plane->properties;
     273           0 :         plane->dev = dev;
     274           0 :         plane->funcs = funcs;
     275           0 :         plane->format_types = kmalloc_array(format_count, sizeof(uint32_t),
     276             :                                             GFP_KERNEL);
     277           0 :         if (!plane->format_types) {
     278           0 :                 DRM_DEBUG_KMS("out of memory when allocating plane\n");
     279           0 :                 drm_mode_object_unregister(dev, &plane->base);
     280           0 :                 return -ENOMEM;
     281             :         }
     282             : 
     283           0 :         if (format_modifiers) {
     284             :                 const uint64_t *temp_modifiers = format_modifiers;
     285             : 
     286           0 :                 while (*temp_modifiers++ != DRM_FORMAT_MOD_INVALID)
     287           0 :                         format_modifier_count++;
     288             :         } else {
     289           0 :                 if (!dev->mode_config.fb_modifiers_not_supported) {
     290           0 :                         format_modifiers = default_modifiers;
     291           0 :                         format_modifier_count = ARRAY_SIZE(default_modifiers);
     292             :                 }
     293             :         }
     294             : 
     295             :         /* autoset the cap and check for consistency across all planes */
     296           0 :         drm_WARN_ON(dev, config->fb_modifiers_not_supported &&
     297             :                                 format_modifier_count);
     298             : 
     299           0 :         plane->modifier_count = format_modifier_count;
     300           0 :         plane->modifiers = kmalloc_array(format_modifier_count,
     301             :                                          sizeof(format_modifiers[0]),
     302             :                                          GFP_KERNEL);
     303             : 
     304           0 :         if (format_modifier_count && !plane->modifiers) {
     305           0 :                 DRM_DEBUG_KMS("out of memory when allocating plane\n");
     306           0 :                 kfree(plane->format_types);
     307           0 :                 drm_mode_object_unregister(dev, &plane->base);
     308           0 :                 return -ENOMEM;
     309             :         }
     310             : 
     311           0 :         if (name) {
     312           0 :                 plane->name = kvasprintf(GFP_KERNEL, name, ap);
     313             :         } else {
     314           0 :                 plane->name = kasprintf(GFP_KERNEL, "plane-%d",
     315             :                                         drm_num_planes(dev));
     316             :         }
     317           0 :         if (!plane->name) {
     318           0 :                 kfree(plane->format_types);
     319           0 :                 kfree(plane->modifiers);
     320           0 :                 drm_mode_object_unregister(dev, &plane->base);
     321           0 :                 return -ENOMEM;
     322             :         }
     323             : 
     324           0 :         memcpy(plane->format_types, formats, format_count * sizeof(uint32_t));
     325           0 :         plane->format_count = format_count;
     326           0 :         memcpy(plane->modifiers, format_modifiers,
     327             :                format_modifier_count * sizeof(format_modifiers[0]));
     328           0 :         plane->possible_crtcs = possible_crtcs;
     329           0 :         plane->type = type;
     330             : 
     331           0 :         list_add_tail(&plane->head, &config->plane_list);
     332           0 :         plane->index = config->num_total_plane++;
     333             : 
     334           0 :         drm_object_attach_property(&plane->base,
     335             :                                    config->plane_type_property,
     336           0 :                                    plane->type);
     337             : 
     338           0 :         if (drm_core_check_feature(dev, DRIVER_ATOMIC)) {
     339           0 :                 drm_object_attach_property(&plane->base, config->prop_fb_id, 0);
     340           0 :                 drm_object_attach_property(&plane->base, config->prop_in_fence_fd, -1);
     341           0 :                 drm_object_attach_property(&plane->base, config->prop_crtc_id, 0);
     342           0 :                 drm_object_attach_property(&plane->base, config->prop_crtc_x, 0);
     343           0 :                 drm_object_attach_property(&plane->base, config->prop_crtc_y, 0);
     344           0 :                 drm_object_attach_property(&plane->base, config->prop_crtc_w, 0);
     345           0 :                 drm_object_attach_property(&plane->base, config->prop_crtc_h, 0);
     346           0 :                 drm_object_attach_property(&plane->base, config->prop_src_x, 0);
     347           0 :                 drm_object_attach_property(&plane->base, config->prop_src_y, 0);
     348           0 :                 drm_object_attach_property(&plane->base, config->prop_src_w, 0);
     349           0 :                 drm_object_attach_property(&plane->base, config->prop_src_h, 0);
     350             :         }
     351             : 
     352           0 :         if (format_modifier_count)
     353           0 :                 create_in_format_blob(dev, plane);
     354             : 
     355             :         return 0;
     356             : }
     357             : 
     358             : /**
     359             :  * drm_universal_plane_init - Initialize a new universal plane object
     360             :  * @dev: DRM device
     361             :  * @plane: plane object to init
     362             :  * @possible_crtcs: bitmask of possible CRTCs
     363             :  * @funcs: callbacks for the new plane
     364             :  * @formats: array of supported formats (DRM_FORMAT\_\*)
     365             :  * @format_count: number of elements in @formats
     366             :  * @format_modifiers: array of struct drm_format modifiers terminated by
     367             :  *                    DRM_FORMAT_MOD_INVALID
     368             :  * @type: type of plane (overlay, primary, cursor)
     369             :  * @name: printf style format string for the plane name, or NULL for default name
     370             :  *
     371             :  * Initializes a plane object of type @type. The &drm_plane_funcs.destroy hook
     372             :  * should call drm_plane_cleanup() and kfree() the plane structure. The plane
     373             :  * structure should not be allocated with devm_kzalloc().
     374             :  *
     375             :  * Note: consider using drmm_universal_plane_alloc() instead of
     376             :  * drm_universal_plane_init() to let the DRM managed resource infrastructure
     377             :  * take care of cleanup and deallocation.
     378             :  *
     379             :  * Drivers that only support the DRM_FORMAT_MOD_LINEAR modifier support may set
     380             :  * @format_modifiers to NULL. The plane will advertise the linear modifier.
     381             :  *
     382             :  * Returns:
     383             :  * Zero on success, error code on failure.
     384             :  */
     385           0 : int drm_universal_plane_init(struct drm_device *dev, struct drm_plane *plane,
     386             :                              uint32_t possible_crtcs,
     387             :                              const struct drm_plane_funcs *funcs,
     388             :                              const uint32_t *formats, unsigned int format_count,
     389             :                              const uint64_t *format_modifiers,
     390             :                              enum drm_plane_type type,
     391             :                              const char *name, ...)
     392             : {
     393             :         va_list ap;
     394             :         int ret;
     395             : 
     396           0 :         WARN_ON(!funcs->destroy);
     397             : 
     398           0 :         va_start(ap, name);
     399           0 :         ret = __drm_universal_plane_init(dev, plane, possible_crtcs, funcs,
     400             :                                          formats, format_count, format_modifiers,
     401             :                                          type, name, ap);
     402           0 :         va_end(ap);
     403           0 :         return ret;
     404             : }
     405             : EXPORT_SYMBOL(drm_universal_plane_init);
     406             : 
     407           0 : static void drmm_universal_plane_alloc_release(struct drm_device *dev, void *ptr)
     408             : {
     409           0 :         struct drm_plane *plane = ptr;
     410             : 
     411           0 :         if (WARN_ON(!plane->dev))
     412             :                 return;
     413             : 
     414           0 :         drm_plane_cleanup(plane);
     415             : }
     416             : 
     417           0 : void *__drmm_universal_plane_alloc(struct drm_device *dev, size_t size,
     418             :                                    size_t offset, uint32_t possible_crtcs,
     419             :                                    const struct drm_plane_funcs *funcs,
     420             :                                    const uint32_t *formats, unsigned int format_count,
     421             :                                    const uint64_t *format_modifiers,
     422             :                                    enum drm_plane_type type,
     423             :                                    const char *name, ...)
     424             : {
     425             :         void *container;
     426             :         struct drm_plane *plane;
     427             :         va_list ap;
     428             :         int ret;
     429             : 
     430           0 :         if (WARN_ON(!funcs || funcs->destroy))
     431             :                 return ERR_PTR(-EINVAL);
     432             : 
     433           0 :         container = drmm_kzalloc(dev, size, GFP_KERNEL);
     434           0 :         if (!container)
     435             :                 return ERR_PTR(-ENOMEM);
     436             : 
     437           0 :         plane = container + offset;
     438             : 
     439           0 :         va_start(ap, name);
     440           0 :         ret = __drm_universal_plane_init(dev, plane, possible_crtcs, funcs,
     441             :                                          formats, format_count, format_modifiers,
     442             :                                          type, name, ap);
     443           0 :         va_end(ap);
     444           0 :         if (ret)
     445           0 :                 return ERR_PTR(ret);
     446             : 
     447           0 :         ret = drmm_add_action_or_reset(dev, drmm_universal_plane_alloc_release,
     448             :                                        plane);
     449           0 :         if (ret)
     450           0 :                 return ERR_PTR(ret);
     451             : 
     452             :         return container;
     453             : }
     454             : EXPORT_SYMBOL(__drmm_universal_plane_alloc);
     455             : 
     456           0 : void *__drm_universal_plane_alloc(struct drm_device *dev, size_t size,
     457             :                                   size_t offset, uint32_t possible_crtcs,
     458             :                                   const struct drm_plane_funcs *funcs,
     459             :                                   const uint32_t *formats, unsigned int format_count,
     460             :                                   const uint64_t *format_modifiers,
     461             :                                   enum drm_plane_type type,
     462             :                                   const char *name, ...)
     463             : {
     464             :         void *container;
     465             :         struct drm_plane *plane;
     466             :         va_list ap;
     467             :         int ret;
     468             : 
     469           0 :         if (drm_WARN_ON(dev, !funcs))
     470             :                 return ERR_PTR(-EINVAL);
     471             : 
     472           0 :         container = kzalloc(size, GFP_KERNEL);
     473           0 :         if (!container)
     474             :                 return ERR_PTR(-ENOMEM);
     475             : 
     476           0 :         plane = container + offset;
     477             : 
     478           0 :         va_start(ap, name);
     479           0 :         ret = __drm_universal_plane_init(dev, plane, possible_crtcs, funcs,
     480             :                                          formats, format_count, format_modifiers,
     481             :                                          type, name, ap);
     482           0 :         va_end(ap);
     483           0 :         if (ret)
     484             :                 goto err_kfree;
     485             : 
     486             :         return container;
     487             : 
     488             : err_kfree:
     489           0 :         kfree(container);
     490           0 :         return ERR_PTR(ret);
     491             : }
     492             : EXPORT_SYMBOL(__drm_universal_plane_alloc);
     493             : 
     494           1 : int drm_plane_register_all(struct drm_device *dev)
     495             : {
     496           1 :         unsigned int num_planes = 0;
     497           1 :         unsigned int num_zpos = 0;
     498             :         struct drm_plane *plane;
     499           1 :         int ret = 0;
     500             : 
     501           1 :         drm_for_each_plane(plane, dev) {
     502           0 :                 if (plane->funcs->late_register)
     503           0 :                         ret = plane->funcs->late_register(plane);
     504           0 :                 if (ret)
     505             :                         return ret;
     506             : 
     507           0 :                 if (plane->zpos_property)
     508           0 :                         num_zpos++;
     509           0 :                 num_planes++;
     510             :         }
     511             : 
     512           1 :         drm_WARN(dev, num_zpos && num_planes != num_zpos,
     513             :                  "Mixing planes with and without zpos property is invalid\n");
     514             : 
     515             :         return 0;
     516             : }
     517             : 
     518           1 : void drm_plane_unregister_all(struct drm_device *dev)
     519             : {
     520             :         struct drm_plane *plane;
     521             : 
     522           1 :         drm_for_each_plane(plane, dev) {
     523           0 :                 if (plane->funcs->early_unregister)
     524           0 :                         plane->funcs->early_unregister(plane);
     525             :         }
     526           1 : }
     527             : 
     528             : /**
     529             :  * drm_plane_cleanup - Clean up the core plane usage
     530             :  * @plane: plane to cleanup
     531             :  *
     532             :  * This function cleans up @plane and removes it from the DRM mode setting
     533             :  * core. Note that the function does *not* free the plane structure itself,
     534             :  * this is the responsibility of the caller.
     535             :  */
     536           0 : void drm_plane_cleanup(struct drm_plane *plane)
     537             : {
     538           0 :         struct drm_device *dev = plane->dev;
     539             : 
     540           0 :         drm_modeset_lock_fini(&plane->mutex);
     541             : 
     542           0 :         kfree(plane->format_types);
     543           0 :         kfree(plane->modifiers);
     544           0 :         drm_mode_object_unregister(dev, &plane->base);
     545             : 
     546           0 :         BUG_ON(list_empty(&plane->head));
     547             : 
     548             :         /* Note that the plane_list is considered to be static; should we
     549             :          * remove the drm_plane at runtime we would have to decrement all
     550             :          * the indices on the drm_plane after us in the plane_list.
     551             :          */
     552             : 
     553           0 :         list_del(&plane->head);
     554           0 :         dev->mode_config.num_total_plane--;
     555             : 
     556           0 :         WARN_ON(plane->state && !plane->funcs->atomic_destroy_state);
     557           0 :         if (plane->state && plane->funcs->atomic_destroy_state)
     558           0 :                 plane->funcs->atomic_destroy_state(plane, plane->state);
     559             : 
     560           0 :         kfree(plane->name);
     561             : 
     562           0 :         memset(plane, 0, sizeof(*plane));
     563           0 : }
     564             : EXPORT_SYMBOL(drm_plane_cleanup);
     565             : 
     566             : /**
     567             :  * drm_plane_from_index - find the registered plane at an index
     568             :  * @dev: DRM device
     569             :  * @idx: index of registered plane to find for
     570             :  *
     571             :  * Given a plane index, return the registered plane from DRM device's
     572             :  * list of planes with matching index. This is the inverse of drm_plane_index().
     573             :  */
     574             : struct drm_plane *
     575           0 : drm_plane_from_index(struct drm_device *dev, int idx)
     576             : {
     577             :         struct drm_plane *plane;
     578             : 
     579           0 :         drm_for_each_plane(plane, dev)
     580           0 :                 if (idx == plane->index)
     581             :                         return plane;
     582             : 
     583             :         return NULL;
     584             : }
     585             : EXPORT_SYMBOL(drm_plane_from_index);
     586             : 
     587             : /**
     588             :  * drm_plane_force_disable - Forcibly disable a plane
     589             :  * @plane: plane to disable
     590             :  *
     591             :  * Forces the plane to be disabled.
     592             :  *
     593             :  * Used when the plane's current framebuffer is destroyed,
     594             :  * and when restoring fbdev mode.
     595             :  *
     596             :  * Note that this function is not suitable for atomic drivers, since it doesn't
     597             :  * wire through the lock acquisition context properly and hence can't handle
     598             :  * retries or driver private locks. You probably want to use
     599             :  * drm_atomic_helper_disable_plane() or
     600             :  * drm_atomic_helper_disable_planes_on_crtc() instead.
     601             :  */
     602           0 : void drm_plane_force_disable(struct drm_plane *plane)
     603             : {
     604             :         int ret;
     605             : 
     606           0 :         if (!plane->fb)
     607             :                 return;
     608             : 
     609           0 :         WARN_ON(drm_drv_uses_atomic_modeset(plane->dev));
     610             : 
     611           0 :         plane->old_fb = plane->fb;
     612           0 :         ret = plane->funcs->disable_plane(plane, NULL);
     613           0 :         if (ret) {
     614           0 :                 DRM_ERROR("failed to disable plane with busy fb\n");
     615           0 :                 plane->old_fb = NULL;
     616           0 :                 return;
     617             :         }
     618             :         /* disconnect the plane from the fb and crtc: */
     619           0 :         drm_framebuffer_put(plane->old_fb);
     620           0 :         plane->old_fb = NULL;
     621           0 :         plane->fb = NULL;
     622           0 :         plane->crtc = NULL;
     623             : }
     624             : EXPORT_SYMBOL(drm_plane_force_disable);
     625             : 
     626             : /**
     627             :  * drm_mode_plane_set_obj_prop - set the value of a property
     628             :  * @plane: drm plane object to set property value for
     629             :  * @property: property to set
     630             :  * @value: value the property should be set to
     631             :  *
     632             :  * This functions sets a given property on a given plane object. This function
     633             :  * calls the driver's ->set_property callback and changes the software state of
     634             :  * the property if the callback succeeds.
     635             :  *
     636             :  * Returns:
     637             :  * Zero on success, error code on failure.
     638             :  */
     639           0 : int drm_mode_plane_set_obj_prop(struct drm_plane *plane,
     640             :                                 struct drm_property *property,
     641             :                                 uint64_t value)
     642             : {
     643           0 :         int ret = -EINVAL;
     644           0 :         struct drm_mode_object *obj = &plane->base;
     645             : 
     646           0 :         if (plane->funcs->set_property)
     647           0 :                 ret = plane->funcs->set_property(plane, property, value);
     648           0 :         if (!ret)
     649           0 :                 drm_object_property_set_value(obj, property, value);
     650             : 
     651           0 :         return ret;
     652             : }
     653             : EXPORT_SYMBOL(drm_mode_plane_set_obj_prop);
     654             : 
     655           0 : int drm_mode_getplane_res(struct drm_device *dev, void *data,
     656             :                           struct drm_file *file_priv)
     657             : {
     658           0 :         struct drm_mode_get_plane_res *plane_resp = data;
     659             :         struct drm_plane *plane;
     660             :         uint32_t __user *plane_ptr;
     661           0 :         int count = 0;
     662             : 
     663           0 :         if (!drm_core_check_feature(dev, DRIVER_MODESET))
     664             :                 return -EOPNOTSUPP;
     665             : 
     666           0 :         plane_ptr = u64_to_user_ptr(plane_resp->plane_id_ptr);
     667             : 
     668             :         /*
     669             :          * This ioctl is called twice, once to determine how much space is
     670             :          * needed, and the 2nd time to fill it.
     671             :          */
     672           0 :         drm_for_each_plane(plane, dev) {
     673             :                 /*
     674             :                  * Unless userspace set the 'universal planes'
     675             :                  * capability bit, only advertise overlays.
     676             :                  */
     677           0 :                 if (plane->type != DRM_PLANE_TYPE_OVERLAY &&
     678           0 :                     !file_priv->universal_planes)
     679           0 :                         continue;
     680             : 
     681           0 :                 if (drm_lease_held(file_priv, plane->base.id)) {
     682           0 :                         if (count < plane_resp->count_planes &&
     683           0 :                             put_user(plane->base.id, plane_ptr + count))
     684             :                                 return -EFAULT;
     685           0 :                         count++;
     686             :                 }
     687             :         }
     688           0 :         plane_resp->count_planes = count;
     689             : 
     690           0 :         return 0;
     691             : }
     692             : 
     693           0 : int drm_mode_getplane(struct drm_device *dev, void *data,
     694             :                       struct drm_file *file_priv)
     695             : {
     696           0 :         struct drm_mode_get_plane *plane_resp = data;
     697             :         struct drm_plane *plane;
     698             :         uint32_t __user *format_ptr;
     699             : 
     700           0 :         if (!drm_core_check_feature(dev, DRIVER_MODESET))
     701             :                 return -EOPNOTSUPP;
     702             : 
     703           0 :         plane = drm_plane_find(dev, file_priv, plane_resp->plane_id);
     704           0 :         if (!plane)
     705             :                 return -ENOENT;
     706             : 
     707           0 :         drm_modeset_lock(&plane->mutex, NULL);
     708           0 :         if (plane->state && plane->state->crtc && drm_lease_held(file_priv, plane->state->crtc->base.id))
     709           0 :                 plane_resp->crtc_id = plane->state->crtc->base.id;
     710           0 :         else if (!plane->state && plane->crtc && drm_lease_held(file_priv, plane->crtc->base.id))
     711           0 :                 plane_resp->crtc_id = plane->crtc->base.id;
     712             :         else
     713           0 :                 plane_resp->crtc_id = 0;
     714             : 
     715           0 :         if (plane->state && plane->state->fb)
     716           0 :                 plane_resp->fb_id = plane->state->fb->base.id;
     717           0 :         else if (!plane->state && plane->fb)
     718           0 :                 plane_resp->fb_id = plane->fb->base.id;
     719             :         else
     720           0 :                 plane_resp->fb_id = 0;
     721           0 :         drm_modeset_unlock(&plane->mutex);
     722             : 
     723           0 :         plane_resp->plane_id = plane->base.id;
     724           0 :         plane_resp->possible_crtcs = drm_lease_filter_crtcs(file_priv,
     725             :                                                             plane->possible_crtcs);
     726             : 
     727           0 :         plane_resp->gamma_size = 0;
     728             : 
     729             :         /*
     730             :          * This ioctl is called twice, once to determine how much space is
     731             :          * needed, and the 2nd time to fill it.
     732             :          */
     733           0 :         if (plane->format_count &&
     734           0 :             (plane_resp->count_format_types >= plane->format_count)) {
     735           0 :                 format_ptr = (uint32_t __user *)(unsigned long)plane_resp->format_type_ptr;
     736           0 :                 if (copy_to_user(format_ptr,
     737           0 :                                  plane->format_types,
     738           0 :                                  sizeof(uint32_t) * plane->format_count)) {
     739             :                         return -EFAULT;
     740             :                 }
     741             :         }
     742           0 :         plane_resp->count_format_types = plane->format_count;
     743             : 
     744           0 :         return 0;
     745             : }
     746             : 
     747           0 : int drm_plane_check_pixel_format(struct drm_plane *plane,
     748             :                                  u32 format, u64 modifier)
     749             : {
     750             :         unsigned int i;
     751             : 
     752           0 :         for (i = 0; i < plane->format_count; i++) {
     753           0 :                 if (format == plane->format_types[i])
     754             :                         break;
     755             :         }
     756           0 :         if (i == plane->format_count)
     757             :                 return -EINVAL;
     758             : 
     759           0 :         if (plane->funcs->format_mod_supported) {
     760           0 :                 if (!plane->funcs->format_mod_supported(plane, format, modifier))
     761             :                         return -EINVAL;
     762             :         } else {
     763           0 :                 if (!plane->modifier_count)
     764             :                         return 0;
     765             : 
     766           0 :                 for (i = 0; i < plane->modifier_count; i++) {
     767           0 :                         if (modifier == plane->modifiers[i])
     768             :                                 break;
     769             :                 }
     770           0 :                 if (i == plane->modifier_count)
     771             :                         return -EINVAL;
     772             :         }
     773             : 
     774             :         return 0;
     775             : }
     776             : 
     777           0 : static int __setplane_check(struct drm_plane *plane,
     778             :                             struct drm_crtc *crtc,
     779             :                             struct drm_framebuffer *fb,
     780             :                             int32_t crtc_x, int32_t crtc_y,
     781             :                             uint32_t crtc_w, uint32_t crtc_h,
     782             :                             uint32_t src_x, uint32_t src_y,
     783             :                             uint32_t src_w, uint32_t src_h)
     784             : {
     785             :         int ret;
     786             : 
     787             :         /* Check whether this plane is usable on this CRTC */
     788           0 :         if (!(plane->possible_crtcs & drm_crtc_mask(crtc))) {
     789           0 :                 DRM_DEBUG_KMS("Invalid crtc for plane\n");
     790           0 :                 return -EINVAL;
     791             :         }
     792             : 
     793             :         /* Check whether this plane supports the fb pixel format. */
     794           0 :         ret = drm_plane_check_pixel_format(plane, fb->format->format,
     795             :                                            fb->modifier);
     796           0 :         if (ret) {
     797           0 :                 DRM_DEBUG_KMS("Invalid pixel format %p4cc, modifier 0x%llx\n",
     798             :                               &fb->format->format, fb->modifier);
     799           0 :                 return ret;
     800             :         }
     801             : 
     802             :         /* Give drivers some help against integer overflows */
     803           0 :         if (crtc_w > INT_MAX ||
     804           0 :             crtc_x > INT_MAX - (int32_t) crtc_w ||
     805           0 :             crtc_h > INT_MAX ||
     806           0 :             crtc_y > INT_MAX - (int32_t) crtc_h) {
     807           0 :                 DRM_DEBUG_KMS("Invalid CRTC coordinates %ux%u+%d+%d\n",
     808             :                               crtc_w, crtc_h, crtc_x, crtc_y);
     809           0 :                 return -ERANGE;
     810             :         }
     811             : 
     812           0 :         ret = drm_framebuffer_check_src_coords(src_x, src_y, src_w, src_h, fb);
     813           0 :         if (ret)
     814             :                 return ret;
     815             : 
     816           0 :         return 0;
     817             : }
     818             : 
     819             : /**
     820             :  * drm_any_plane_has_format - Check whether any plane supports this format and modifier combination
     821             :  * @dev: DRM device
     822             :  * @format: pixel format (DRM_FORMAT_*)
     823             :  * @modifier: data layout modifier
     824             :  *
     825             :  * Returns:
     826             :  * Whether at least one plane supports the specified format and modifier combination.
     827             :  */
     828           0 : bool drm_any_plane_has_format(struct drm_device *dev,
     829             :                               u32 format, u64 modifier)
     830             : {
     831             :         struct drm_plane *plane;
     832             : 
     833           0 :         drm_for_each_plane(plane, dev) {
     834           0 :                 if (drm_plane_check_pixel_format(plane, format, modifier) == 0)
     835             :                         return true;
     836             :         }
     837             : 
     838             :         return false;
     839             : }
     840             : EXPORT_SYMBOL(drm_any_plane_has_format);
     841             : 
     842             : /*
     843             :  * __setplane_internal - setplane handler for internal callers
     844             :  *
     845             :  * This function will take a reference on the new fb for the plane
     846             :  * on success.
     847             :  *
     848             :  * src_{x,y,w,h} are provided in 16.16 fixed point format
     849             :  */
     850           0 : static int __setplane_internal(struct drm_plane *plane,
     851             :                                struct drm_crtc *crtc,
     852             :                                struct drm_framebuffer *fb,
     853             :                                int32_t crtc_x, int32_t crtc_y,
     854             :                                uint32_t crtc_w, uint32_t crtc_h,
     855             :                                /* src_{x,y,w,h} values are 16.16 fixed point */
     856             :                                uint32_t src_x, uint32_t src_y,
     857             :                                uint32_t src_w, uint32_t src_h,
     858             :                                struct drm_modeset_acquire_ctx *ctx)
     859             : {
     860           0 :         int ret = 0;
     861             : 
     862           0 :         WARN_ON(drm_drv_uses_atomic_modeset(plane->dev));
     863             : 
     864             :         /* No fb means shut it down */
     865           0 :         if (!fb) {
     866           0 :                 plane->old_fb = plane->fb;
     867           0 :                 ret = plane->funcs->disable_plane(plane, ctx);
     868           0 :                 if (!ret) {
     869           0 :                         plane->crtc = NULL;
     870           0 :                         plane->fb = NULL;
     871             :                 } else {
     872           0 :                         plane->old_fb = NULL;
     873             :                 }
     874             :                 goto out;
     875             :         }
     876             : 
     877           0 :         ret = __setplane_check(plane, crtc, fb,
     878             :                                crtc_x, crtc_y, crtc_w, crtc_h,
     879             :                                src_x, src_y, src_w, src_h);
     880           0 :         if (ret)
     881             :                 goto out;
     882             : 
     883           0 :         plane->old_fb = plane->fb;
     884           0 :         ret = plane->funcs->update_plane(plane, crtc, fb,
     885             :                                          crtc_x, crtc_y, crtc_w, crtc_h,
     886             :                                          src_x, src_y, src_w, src_h, ctx);
     887           0 :         if (!ret) {
     888           0 :                 plane->crtc = crtc;
     889           0 :                 plane->fb = fb;
     890           0 :                 drm_framebuffer_get(plane->fb);
     891             :         } else {
     892           0 :                 plane->old_fb = NULL;
     893             :         }
     894             : 
     895             : out:
     896           0 :         if (plane->old_fb)
     897           0 :                 drm_framebuffer_put(plane->old_fb);
     898           0 :         plane->old_fb = NULL;
     899             : 
     900           0 :         return ret;
     901             : }
     902             : 
     903           0 : static int __setplane_atomic(struct drm_plane *plane,
     904             :                              struct drm_crtc *crtc,
     905             :                              struct drm_framebuffer *fb,
     906             :                              int32_t crtc_x, int32_t crtc_y,
     907             :                              uint32_t crtc_w, uint32_t crtc_h,
     908             :                              uint32_t src_x, uint32_t src_y,
     909             :                              uint32_t src_w, uint32_t src_h,
     910             :                              struct drm_modeset_acquire_ctx *ctx)
     911             : {
     912             :         int ret;
     913             : 
     914           0 :         WARN_ON(!drm_drv_uses_atomic_modeset(plane->dev));
     915             : 
     916             :         /* No fb means shut it down */
     917           0 :         if (!fb)
     918           0 :                 return plane->funcs->disable_plane(plane, ctx);
     919             : 
     920             :         /*
     921             :          * FIXME: This is redundant with drm_atomic_plane_check(),
     922             :          * but the legacy cursor/"async" .update_plane() tricks
     923             :          * don't call that so we still need this here. Should remove
     924             :          * this when all .update_plane() implementations have been
     925             :          * fixed to call drm_atomic_plane_check().
     926             :          */
     927           0 :         ret = __setplane_check(plane, crtc, fb,
     928             :                                crtc_x, crtc_y, crtc_w, crtc_h,
     929             :                                src_x, src_y, src_w, src_h);
     930           0 :         if (ret)
     931             :                 return ret;
     932             : 
     933           0 :         return plane->funcs->update_plane(plane, crtc, fb,
     934             :                                           crtc_x, crtc_y, crtc_w, crtc_h,
     935             :                                           src_x, src_y, src_w, src_h, ctx);
     936             : }
     937             : 
     938           0 : static int setplane_internal(struct drm_plane *plane,
     939             :                              struct drm_crtc *crtc,
     940             :                              struct drm_framebuffer *fb,
     941             :                              int32_t crtc_x, int32_t crtc_y,
     942             :                              uint32_t crtc_w, uint32_t crtc_h,
     943             :                              /* src_{x,y,w,h} values are 16.16 fixed point */
     944             :                              uint32_t src_x, uint32_t src_y,
     945             :                              uint32_t src_w, uint32_t src_h)
     946             : {
     947             :         struct drm_modeset_acquire_ctx ctx;
     948             :         int ret;
     949             : 
     950           0 :         DRM_MODESET_LOCK_ALL_BEGIN(plane->dev, ctx,
     951             :                                    DRM_MODESET_ACQUIRE_INTERRUPTIBLE, ret);
     952             : 
     953           0 :         if (drm_drv_uses_atomic_modeset(plane->dev))
     954           0 :                 ret = __setplane_atomic(plane, crtc, fb,
     955             :                                         crtc_x, crtc_y, crtc_w, crtc_h,
     956             :                                         src_x, src_y, src_w, src_h, &ctx);
     957             :         else
     958           0 :                 ret = __setplane_internal(plane, crtc, fb,
     959             :                                           crtc_x, crtc_y, crtc_w, crtc_h,
     960             :                                           src_x, src_y, src_w, src_h, &ctx);
     961             : 
     962           0 :         DRM_MODESET_LOCK_ALL_END(plane->dev, ctx, ret);
     963             : 
     964           0 :         return ret;
     965             : }
     966             : 
     967           0 : int drm_mode_setplane(struct drm_device *dev, void *data,
     968             :                       struct drm_file *file_priv)
     969             : {
     970           0 :         struct drm_mode_set_plane *plane_req = data;
     971             :         struct drm_plane *plane;
     972           0 :         struct drm_crtc *crtc = NULL;
     973           0 :         struct drm_framebuffer *fb = NULL;
     974             :         int ret;
     975             : 
     976           0 :         if (!drm_core_check_feature(dev, DRIVER_MODESET))
     977             :                 return -EOPNOTSUPP;
     978             : 
     979             :         /*
     980             :          * First, find the plane, crtc, and fb objects.  If not available,
     981             :          * we don't bother to call the driver.
     982             :          */
     983           0 :         plane = drm_plane_find(dev, file_priv, plane_req->plane_id);
     984           0 :         if (!plane) {
     985           0 :                 DRM_DEBUG_KMS("Unknown plane ID %d\n",
     986             :                               plane_req->plane_id);
     987           0 :                 return -ENOENT;
     988             :         }
     989             : 
     990           0 :         if (plane_req->fb_id) {
     991           0 :                 fb = drm_framebuffer_lookup(dev, file_priv, plane_req->fb_id);
     992           0 :                 if (!fb) {
     993           0 :                         DRM_DEBUG_KMS("Unknown framebuffer ID %d\n",
     994             :                                       plane_req->fb_id);
     995           0 :                         return -ENOENT;
     996             :                 }
     997             : 
     998           0 :                 crtc = drm_crtc_find(dev, file_priv, plane_req->crtc_id);
     999           0 :                 if (!crtc) {
    1000           0 :                         drm_framebuffer_put(fb);
    1001           0 :                         DRM_DEBUG_KMS("Unknown crtc ID %d\n",
    1002             :                                       plane_req->crtc_id);
    1003           0 :                         return -ENOENT;
    1004             :                 }
    1005             :         }
    1006             : 
    1007           0 :         ret = setplane_internal(plane, crtc, fb,
    1008             :                                 plane_req->crtc_x, plane_req->crtc_y,
    1009             :                                 plane_req->crtc_w, plane_req->crtc_h,
    1010             :                                 plane_req->src_x, plane_req->src_y,
    1011             :                                 plane_req->src_w, plane_req->src_h);
    1012             : 
    1013           0 :         if (fb)
    1014             :                 drm_framebuffer_put(fb);
    1015             : 
    1016             :         return ret;
    1017             : }
    1018             : 
    1019           0 : static int drm_mode_cursor_universal(struct drm_crtc *crtc,
    1020             :                                      struct drm_mode_cursor2 *req,
    1021             :                                      struct drm_file *file_priv,
    1022             :                                      struct drm_modeset_acquire_ctx *ctx)
    1023             : {
    1024           0 :         struct drm_device *dev = crtc->dev;
    1025           0 :         struct drm_plane *plane = crtc->cursor;
    1026           0 :         struct drm_framebuffer *fb = NULL;
    1027           0 :         struct drm_mode_fb_cmd2 fbreq = {
    1028           0 :                 .width = req->width,
    1029           0 :                 .height = req->height,
    1030             :                 .pixel_format = DRM_FORMAT_ARGB8888,
    1031           0 :                 .pitches = { req->width * 4 },
    1032           0 :                 .handles = { req->handle },
    1033             :         };
    1034             :         int32_t crtc_x, crtc_y;
    1035           0 :         uint32_t crtc_w = 0, crtc_h = 0;
    1036           0 :         uint32_t src_w = 0, src_h = 0;
    1037           0 :         int ret = 0;
    1038             : 
    1039           0 :         BUG_ON(!plane);
    1040           0 :         WARN_ON(plane->crtc != crtc && plane->crtc != NULL);
    1041             : 
    1042             :         /*
    1043             :          * Obtain fb we'll be using (either new or existing) and take an extra
    1044             :          * reference to it if fb != null.  setplane will take care of dropping
    1045             :          * the reference if the plane update fails.
    1046             :          */
    1047           0 :         if (req->flags & DRM_MODE_CURSOR_BO) {
    1048           0 :                 if (req->handle) {
    1049           0 :                         fb = drm_internal_framebuffer_create(dev, &fbreq, file_priv);
    1050           0 :                         if (IS_ERR(fb)) {
    1051           0 :                                 DRM_DEBUG_KMS("failed to wrap cursor buffer in drm framebuffer\n");
    1052           0 :                                 return PTR_ERR(fb);
    1053             :                         }
    1054             : 
    1055           0 :                         fb->hot_x = req->hot_x;
    1056           0 :                         fb->hot_y = req->hot_y;
    1057             :                 } else {
    1058             :                         fb = NULL;
    1059             :                 }
    1060             :         } else {
    1061           0 :                 if (plane->state)
    1062           0 :                         fb = plane->state->fb;
    1063             :                 else
    1064           0 :                         fb = plane->fb;
    1065             : 
    1066           0 :                 if (fb)
    1067             :                         drm_framebuffer_get(fb);
    1068             :         }
    1069             : 
    1070           0 :         if (req->flags & DRM_MODE_CURSOR_MOVE) {
    1071           0 :                 crtc_x = req->x;
    1072           0 :                 crtc_y = req->y;
    1073             :         } else {
    1074           0 :                 crtc_x = crtc->cursor_x;
    1075           0 :                 crtc_y = crtc->cursor_y;
    1076             :         }
    1077             : 
    1078           0 :         if (fb) {
    1079           0 :                 crtc_w = fb->width;
    1080           0 :                 crtc_h = fb->height;
    1081           0 :                 src_w = fb->width << 16;
    1082           0 :                 src_h = fb->height << 16;
    1083             :         }
    1084             : 
    1085           0 :         if (drm_drv_uses_atomic_modeset(dev))
    1086           0 :                 ret = __setplane_atomic(plane, crtc, fb,
    1087             :                                         crtc_x, crtc_y, crtc_w, crtc_h,
    1088             :                                         0, 0, src_w, src_h, ctx);
    1089             :         else
    1090           0 :                 ret = __setplane_internal(plane, crtc, fb,
    1091             :                                           crtc_x, crtc_y, crtc_w, crtc_h,
    1092             :                                           0, 0, src_w, src_h, ctx);
    1093             : 
    1094           0 :         if (fb)
    1095             :                 drm_framebuffer_put(fb);
    1096             : 
    1097             :         /* Update successful; save new cursor position, if necessary */
    1098           0 :         if (ret == 0 && req->flags & DRM_MODE_CURSOR_MOVE) {
    1099           0 :                 crtc->cursor_x = req->x;
    1100           0 :                 crtc->cursor_y = req->y;
    1101             :         }
    1102             : 
    1103             :         return ret;
    1104             : }
    1105             : 
    1106           0 : static int drm_mode_cursor_common(struct drm_device *dev,
    1107             :                                   struct drm_mode_cursor2 *req,
    1108             :                                   struct drm_file *file_priv)
    1109             : {
    1110             :         struct drm_crtc *crtc;
    1111             :         struct drm_modeset_acquire_ctx ctx;
    1112           0 :         int ret = 0;
    1113             : 
    1114           0 :         if (!drm_core_check_feature(dev, DRIVER_MODESET))
    1115             :                 return -EOPNOTSUPP;
    1116             : 
    1117           0 :         if (!req->flags || (~DRM_MODE_CURSOR_FLAGS & req->flags))
    1118             :                 return -EINVAL;
    1119             : 
    1120           0 :         crtc = drm_crtc_find(dev, file_priv, req->crtc_id);
    1121           0 :         if (!crtc) {
    1122           0 :                 DRM_DEBUG_KMS("Unknown CRTC ID %d\n", req->crtc_id);
    1123           0 :                 return -ENOENT;
    1124             :         }
    1125             : 
    1126           0 :         drm_modeset_acquire_init(&ctx, DRM_MODESET_ACQUIRE_INTERRUPTIBLE);
    1127             : retry:
    1128           0 :         ret = drm_modeset_lock(&crtc->mutex, &ctx);
    1129           0 :         if (ret)
    1130             :                 goto out;
    1131             :         /*
    1132             :          * If this crtc has a universal cursor plane, call that plane's update
    1133             :          * handler rather than using legacy cursor handlers.
    1134             :          */
    1135           0 :         if (crtc->cursor) {
    1136           0 :                 ret = drm_modeset_lock(&crtc->cursor->mutex, &ctx);
    1137           0 :                 if (ret)
    1138             :                         goto out;
    1139             : 
    1140           0 :                 if (!drm_lease_held(file_priv, crtc->cursor->base.id)) {
    1141             :                         ret = -EACCES;
    1142             :                         goto out;
    1143             :                 }
    1144             : 
    1145           0 :                 ret = drm_mode_cursor_universal(crtc, req, file_priv, &ctx);
    1146           0 :                 goto out;
    1147             :         }
    1148             : 
    1149           0 :         if (req->flags & DRM_MODE_CURSOR_BO) {
    1150           0 :                 if (!crtc->funcs->cursor_set && !crtc->funcs->cursor_set2) {
    1151             :                         ret = -ENXIO;
    1152             :                         goto out;
    1153             :                 }
    1154             :                 /* Turns off the cursor if handle is 0 */
    1155           0 :                 if (crtc->funcs->cursor_set2)
    1156           0 :                         ret = crtc->funcs->cursor_set2(crtc, file_priv, req->handle,
    1157             :                                                       req->width, req->height, req->hot_x, req->hot_y);
    1158             :                 else
    1159           0 :                         ret = crtc->funcs->cursor_set(crtc, file_priv, req->handle,
    1160             :                                                       req->width, req->height);
    1161             :         }
    1162             : 
    1163           0 :         if (req->flags & DRM_MODE_CURSOR_MOVE) {
    1164           0 :                 if (crtc->funcs->cursor_move) {
    1165           0 :                         ret = crtc->funcs->cursor_move(crtc, req->x, req->y);
    1166             :                 } else {
    1167             :                         ret = -EFAULT;
    1168             :                         goto out;
    1169             :                 }
    1170             :         }
    1171             : out:
    1172           0 :         if (ret == -EDEADLK) {
    1173           0 :                 ret = drm_modeset_backoff(&ctx);
    1174           0 :                 if (!ret)
    1175             :                         goto retry;
    1176             :         }
    1177             : 
    1178           0 :         drm_modeset_drop_locks(&ctx);
    1179           0 :         drm_modeset_acquire_fini(&ctx);
    1180             : 
    1181           0 :         return ret;
    1182             : 
    1183             : }
    1184             : 
    1185             : 
    1186           0 : int drm_mode_cursor_ioctl(struct drm_device *dev,
    1187             :                           void *data, struct drm_file *file_priv)
    1188             : {
    1189           0 :         struct drm_mode_cursor *req = data;
    1190             :         struct drm_mode_cursor2 new_req;
    1191             : 
    1192           0 :         memcpy(&new_req, req, sizeof(struct drm_mode_cursor));
    1193           0 :         new_req.hot_x = new_req.hot_y = 0;
    1194             : 
    1195           0 :         return drm_mode_cursor_common(dev, &new_req, file_priv);
    1196             : }
    1197             : 
    1198             : /*
    1199             :  * Set the cursor configuration based on user request. This implements the 2nd
    1200             :  * version of the cursor ioctl, which allows userspace to additionally specify
    1201             :  * the hotspot of the pointer.
    1202             :  */
    1203           0 : int drm_mode_cursor2_ioctl(struct drm_device *dev,
    1204             :                            void *data, struct drm_file *file_priv)
    1205             : {
    1206           0 :         struct drm_mode_cursor2 *req = data;
    1207             : 
    1208           0 :         return drm_mode_cursor_common(dev, req, file_priv);
    1209             : }
    1210             : 
    1211           0 : int drm_mode_page_flip_ioctl(struct drm_device *dev,
    1212             :                              void *data, struct drm_file *file_priv)
    1213             : {
    1214           0 :         struct drm_mode_crtc_page_flip_target *page_flip = data;
    1215             :         struct drm_crtc *crtc;
    1216             :         struct drm_plane *plane;
    1217           0 :         struct drm_framebuffer *fb = NULL, *old_fb;
    1218           0 :         struct drm_pending_vblank_event *e = NULL;
    1219           0 :         u32 target_vblank = page_flip->sequence;
    1220             :         struct drm_modeset_acquire_ctx ctx;
    1221           0 :         int ret = -EINVAL;
    1222             : 
    1223           0 :         if (!drm_core_check_feature(dev, DRIVER_MODESET))
    1224             :                 return -EOPNOTSUPP;
    1225             : 
    1226           0 :         if (page_flip->flags & ~DRM_MODE_PAGE_FLIP_FLAGS)
    1227             :                 return -EINVAL;
    1228             : 
    1229           0 :         if (page_flip->sequence != 0 && !(page_flip->flags & DRM_MODE_PAGE_FLIP_TARGET))
    1230             :                 return -EINVAL;
    1231             : 
    1232             :         /* Only one of the DRM_MODE_PAGE_FLIP_TARGET_ABSOLUTE/RELATIVE flags
    1233             :          * can be specified
    1234             :          */
    1235           0 :         if ((page_flip->flags & DRM_MODE_PAGE_FLIP_TARGET) == DRM_MODE_PAGE_FLIP_TARGET)
    1236             :                 return -EINVAL;
    1237             : 
    1238           0 :         if ((page_flip->flags & DRM_MODE_PAGE_FLIP_ASYNC) && !dev->mode_config.async_page_flip)
    1239             :                 return -EINVAL;
    1240             : 
    1241           0 :         crtc = drm_crtc_find(dev, file_priv, page_flip->crtc_id);
    1242           0 :         if (!crtc)
    1243             :                 return -ENOENT;
    1244             : 
    1245           0 :         plane = crtc->primary;
    1246             : 
    1247           0 :         if (!drm_lease_held(file_priv, plane->base.id))
    1248             :                 return -EACCES;
    1249             : 
    1250           0 :         if (crtc->funcs->page_flip_target) {
    1251             :                 u32 current_vblank;
    1252             :                 int r;
    1253             : 
    1254           0 :                 r = drm_crtc_vblank_get(crtc);
    1255           0 :                 if (r)
    1256             :                         return r;
    1257             : 
    1258           0 :                 current_vblank = (u32)drm_crtc_vblank_count(crtc);
    1259             : 
    1260           0 :                 switch (page_flip->flags & DRM_MODE_PAGE_FLIP_TARGET) {
    1261             :                 case DRM_MODE_PAGE_FLIP_TARGET_ABSOLUTE:
    1262           0 :                         if ((int)(target_vblank - current_vblank) > 1) {
    1263           0 :                                 DRM_DEBUG("Invalid absolute flip target %u, "
    1264             :                                           "must be <= %u\n", target_vblank,
    1265             :                                           current_vblank + 1);
    1266           0 :                                 drm_crtc_vblank_put(crtc);
    1267           0 :                                 return -EINVAL;
    1268             :                         }
    1269             :                         break;
    1270             :                 case DRM_MODE_PAGE_FLIP_TARGET_RELATIVE:
    1271           0 :                         if (target_vblank != 0 && target_vblank != 1) {
    1272           0 :                                 DRM_DEBUG("Invalid relative flip target %u, "
    1273             :                                           "must be 0 or 1\n", target_vblank);
    1274           0 :                                 drm_crtc_vblank_put(crtc);
    1275           0 :                                 return -EINVAL;
    1276             :                         }
    1277           0 :                         target_vblank += current_vblank;
    1278           0 :                         break;
    1279             :                 default:
    1280           0 :                         target_vblank = current_vblank +
    1281           0 :                                 !(page_flip->flags & DRM_MODE_PAGE_FLIP_ASYNC);
    1282           0 :                         break;
    1283             :                 }
    1284           0 :         } else if (crtc->funcs->page_flip == NULL ||
    1285           0 :                    (page_flip->flags & DRM_MODE_PAGE_FLIP_TARGET)) {
    1286             :                 return -EINVAL;
    1287             :         }
    1288             : 
    1289           0 :         drm_modeset_acquire_init(&ctx, DRM_MODESET_ACQUIRE_INTERRUPTIBLE);
    1290             : retry:
    1291           0 :         ret = drm_modeset_lock(&crtc->mutex, &ctx);
    1292           0 :         if (ret)
    1293             :                 goto out;
    1294           0 :         ret = drm_modeset_lock(&plane->mutex, &ctx);
    1295           0 :         if (ret)
    1296             :                 goto out;
    1297             : 
    1298           0 :         if (plane->state)
    1299           0 :                 old_fb = plane->state->fb;
    1300             :         else
    1301           0 :                 old_fb = plane->fb;
    1302             : 
    1303           0 :         if (old_fb == NULL) {
    1304             :                 /* The framebuffer is currently unbound, presumably
    1305             :                  * due to a hotplug event, that userspace has not
    1306             :                  * yet discovered.
    1307             :                  */
    1308             :                 ret = -EBUSY;
    1309             :                 goto out;
    1310             :         }
    1311             : 
    1312           0 :         fb = drm_framebuffer_lookup(dev, file_priv, page_flip->fb_id);
    1313           0 :         if (!fb) {
    1314             :                 ret = -ENOENT;
    1315             :                 goto out;
    1316             :         }
    1317             : 
    1318           0 :         if (plane->state) {
    1319           0 :                 const struct drm_plane_state *state = plane->state;
    1320             : 
    1321           0 :                 ret = drm_framebuffer_check_src_coords(state->src_x,
    1322             :                                                        state->src_y,
    1323             :                                                        state->src_w,
    1324             :                                                        state->src_h,
    1325             :                                                        fb);
    1326             :         } else {
    1327           0 :                 ret = drm_crtc_check_viewport(crtc, crtc->x, crtc->y,
    1328           0 :                                               &crtc->mode, fb);
    1329             :         }
    1330           0 :         if (ret)
    1331             :                 goto out;
    1332             : 
    1333             :         /*
    1334             :          * Only check the FOURCC format code, excluding modifiers. This is
    1335             :          * enough for all legacy drivers. Atomic drivers have their own
    1336             :          * checks in their ->atomic_check implementation, which will
    1337             :          * return -EINVAL if any hw or driver constraint is violated due
    1338             :          * to modifier changes.
    1339             :          */
    1340           0 :         if (old_fb->format->format != fb->format->format) {
    1341           0 :                 DRM_DEBUG_KMS("Page flip is not allowed to change frame buffer format.\n");
    1342           0 :                 ret = -EINVAL;
    1343           0 :                 goto out;
    1344             :         }
    1345             : 
    1346           0 :         if (page_flip->flags & DRM_MODE_PAGE_FLIP_EVENT) {
    1347           0 :                 e = kzalloc(sizeof *e, GFP_KERNEL);
    1348           0 :                 if (!e) {
    1349             :                         ret = -ENOMEM;
    1350             :                         goto out;
    1351             :                 }
    1352             : 
    1353           0 :                 e->event.base.type = DRM_EVENT_FLIP_COMPLETE;
    1354           0 :                 e->event.base.length = sizeof(e->event);
    1355           0 :                 e->event.vbl.user_data = page_flip->user_data;
    1356           0 :                 e->event.vbl.crtc_id = crtc->base.id;
    1357             : 
    1358           0 :                 ret = drm_event_reserve_init(dev, file_priv, &e->base, &e->event.base);
    1359           0 :                 if (ret) {
    1360           0 :                         kfree(e);
    1361           0 :                         e = NULL;
    1362           0 :                         goto out;
    1363             :                 }
    1364             :         }
    1365             : 
    1366           0 :         plane->old_fb = plane->fb;
    1367           0 :         if (crtc->funcs->page_flip_target)
    1368           0 :                 ret = crtc->funcs->page_flip_target(crtc, fb, e,
    1369             :                                                     page_flip->flags,
    1370             :                                                     target_vblank,
    1371             :                                                     &ctx);
    1372             :         else
    1373           0 :                 ret = crtc->funcs->page_flip(crtc, fb, e, page_flip->flags,
    1374             :                                              &ctx);
    1375           0 :         if (ret) {
    1376           0 :                 if (page_flip->flags & DRM_MODE_PAGE_FLIP_EVENT)
    1377           0 :                         drm_event_cancel_free(dev, &e->base);
    1378             :                 /* Keep the old fb, don't unref it. */
    1379           0 :                 plane->old_fb = NULL;
    1380             :         } else {
    1381           0 :                 if (!plane->state) {
    1382           0 :                         plane->fb = fb;
    1383             :                         drm_framebuffer_get(fb);
    1384             :                 }
    1385             :         }
    1386             : 
    1387             : out:
    1388           0 :         if (fb)
    1389             :                 drm_framebuffer_put(fb);
    1390           0 :         if (plane->old_fb)
    1391           0 :                 drm_framebuffer_put(plane->old_fb);
    1392           0 :         plane->old_fb = NULL;
    1393             : 
    1394           0 :         if (ret == -EDEADLK) {
    1395           0 :                 ret = drm_modeset_backoff(&ctx);
    1396           0 :                 if (!ret)
    1397             :                         goto retry;
    1398             :         }
    1399             : 
    1400           0 :         drm_modeset_drop_locks(&ctx);
    1401           0 :         drm_modeset_acquire_fini(&ctx);
    1402             : 
    1403           0 :         if (ret && crtc->funcs->page_flip_target)
    1404           0 :                 drm_crtc_vblank_put(crtc);
    1405             : 
    1406             :         return ret;
    1407             : }
    1408             : 
    1409             : /**
    1410             :  * DOC: damage tracking
    1411             :  *
    1412             :  * FB_DAMAGE_CLIPS is an optional plane property which provides a means to
    1413             :  * specify a list of damage rectangles on a plane in framebuffer coordinates of
    1414             :  * the framebuffer attached to the plane. In current context damage is the area
    1415             :  * of plane framebuffer that has changed since last plane update (also called
    1416             :  * page-flip), irrespective of whether currently attached framebuffer is same as
    1417             :  * framebuffer attached during last plane update or not.
    1418             :  *
    1419             :  * FB_DAMAGE_CLIPS is a hint to kernel which could be helpful for some drivers
    1420             :  * to optimize internally especially for virtual devices where each framebuffer
    1421             :  * change needs to be transmitted over network, usb, etc.
    1422             :  *
    1423             :  * Since FB_DAMAGE_CLIPS is a hint so it is an optional property. User-space can
    1424             :  * ignore damage clips property and in that case driver will do a full plane
    1425             :  * update. In case damage clips are provided then it is guaranteed that the area
    1426             :  * inside damage clips will be updated to plane. For efficiency driver can do
    1427             :  * full update or can update more than specified in damage clips. Since driver
    1428             :  * is free to read more, user-space must always render the entire visible
    1429             :  * framebuffer. Otherwise there can be corruptions. Also, if a user-space
    1430             :  * provides damage clips which doesn't encompass the actual damage to
    1431             :  * framebuffer (since last plane update) can result in incorrect rendering.
    1432             :  *
    1433             :  * FB_DAMAGE_CLIPS is a blob property with the layout of blob data is simply an
    1434             :  * array of &drm_mode_rect. Unlike plane &drm_plane_state.src coordinates,
    1435             :  * damage clips are not in 16.16 fixed point. Similar to plane src in
    1436             :  * framebuffer, damage clips cannot be negative. In damage clip, x1/y1 are
    1437             :  * inclusive and x2/y2 are exclusive. While kernel does not error for overlapped
    1438             :  * damage clips, it is strongly discouraged.
    1439             :  *
    1440             :  * Drivers that are interested in damage interface for plane should enable
    1441             :  * FB_DAMAGE_CLIPS property by calling drm_plane_enable_fb_damage_clips().
    1442             :  * Drivers implementing damage can use drm_atomic_helper_damage_iter_init() and
    1443             :  * drm_atomic_helper_damage_iter_next() helper iterator function to get damage
    1444             :  * rectangles clipped to &drm_plane_state.src.
    1445             :  */
    1446             : 
    1447             : /**
    1448             :  * drm_plane_enable_fb_damage_clips - Enables plane fb damage clips property.
    1449             :  * @plane: Plane on which to enable damage clips property.
    1450             :  *
    1451             :  * This function lets driver to enable the damage clips property on a plane.
    1452             :  */
    1453          21 : void drm_plane_enable_fb_damage_clips(struct drm_plane *plane)
    1454             : {
    1455          21 :         struct drm_device *dev = plane->dev;
    1456          21 :         struct drm_mode_config *config = &dev->mode_config;
    1457             : 
    1458          21 :         drm_object_attach_property(&plane->base, config->prop_fb_damage_clips,
    1459             :                                    0);
    1460          21 : }
    1461             : EXPORT_SYMBOL(drm_plane_enable_fb_damage_clips);
    1462             : 
    1463             : /**
    1464             :  * drm_plane_get_damage_clips_count - Returns damage clips count.
    1465             :  * @state: Plane state.
    1466             :  *
    1467             :  * Simple helper to get the number of &drm_mode_rect clips set by user-space
    1468             :  * during plane update.
    1469             :  *
    1470             :  * Return: Number of clips in plane fb_damage_clips blob property.
    1471             :  */
    1472             : unsigned int
    1473          17 : drm_plane_get_damage_clips_count(const struct drm_plane_state *state)
    1474             : {
    1475          17 :         return (state && state->fb_damage_clips) ?
    1476          30 :                 state->fb_damage_clips->length/sizeof(struct drm_mode_rect) : 0;
    1477             : }
    1478             : EXPORT_SYMBOL(drm_plane_get_damage_clips_count);
    1479             : 
    1480             : struct drm_mode_rect *
    1481           0 : __drm_plane_get_damage_clips(const struct drm_plane_state *state)
    1482             : {
    1483          17 :         return (struct drm_mode_rect *)((state && state->fb_damage_clips) ?
    1484             :                                         state->fb_damage_clips->data : NULL);
    1485             : }
    1486             : 
    1487             : /**
    1488             :  * drm_plane_get_damage_clips - Returns damage clips.
    1489             :  * @state: Plane state.
    1490             :  *
    1491             :  * Note that this function returns uapi type &drm_mode_rect. Drivers might want
    1492             :  * to use the helper functions drm_atomic_helper_damage_iter_init() and
    1493             :  * drm_atomic_helper_damage_iter_next() or drm_atomic_helper_damage_merged() if
    1494             :  * the driver can only handle a single damage region at most.
    1495             :  *
    1496             :  * Return: Damage clips in plane fb_damage_clips blob property.
    1497             :  */
    1498             : struct drm_mode_rect *
    1499          17 : drm_plane_get_damage_clips(const struct drm_plane_state *state)
    1500             : {
    1501          17 :         struct drm_device *dev = state->plane->dev;
    1502          17 :         struct drm_mode_config *config = &dev->mode_config;
    1503             : 
    1504             :         /* check that drm_plane_enable_fb_damage_clips() was called */
    1505          17 :         if (!drm_mode_obj_find_prop_id(&state->plane->base,
    1506          17 :                                        config->prop_fb_damage_clips->base.id))
    1507           0 :                 drm_warn_once(dev, "drm_plane_enable_fb_damage_clips() not called\n");
    1508             : 
    1509          17 :         return __drm_plane_get_damage_clips(state);
    1510             : }
    1511             : EXPORT_SYMBOL(drm_plane_get_damage_clips);
    1512             : 
    1513             : struct drm_property *
    1514           0 : drm_create_scaling_filter_prop(struct drm_device *dev,
    1515             :                                unsigned int supported_filters)
    1516             : {
    1517             :         struct drm_property *prop;
    1518             :         static const struct drm_prop_enum_list props[] = {
    1519             :                 { DRM_SCALING_FILTER_DEFAULT, "Default" },
    1520             :                 { DRM_SCALING_FILTER_NEAREST_NEIGHBOR, "Nearest Neighbor" },
    1521             :         };
    1522           0 :         unsigned int valid_mode_mask = BIT(DRM_SCALING_FILTER_DEFAULT) |
    1523             :                                        BIT(DRM_SCALING_FILTER_NEAREST_NEIGHBOR);
    1524             :         int i;
    1525             : 
    1526           0 :         if (WARN_ON((supported_filters & ~valid_mode_mask) ||
    1527             :                     ((supported_filters & BIT(DRM_SCALING_FILTER_DEFAULT)) == 0)))
    1528             :                 return ERR_PTR(-EINVAL);
    1529             : 
    1530           0 :         prop = drm_property_create(dev, DRM_MODE_PROP_ENUM,
    1531             :                                    "SCALING_FILTER",
    1532           0 :                                    hweight32(supported_filters));
    1533           0 :         if (!prop)
    1534             :                 return ERR_PTR(-ENOMEM);
    1535             : 
    1536           0 :         for (i = 0; i < ARRAY_SIZE(props); i++) {
    1537             :                 int ret;
    1538             : 
    1539           0 :                 if (!(BIT(props[i].type) & supported_filters))
    1540           0 :                         continue;
    1541             : 
    1542           0 :                 ret = drm_property_add_enum(prop, props[i].type,
    1543             :                                             props[i].name);
    1544             : 
    1545           0 :                 if (ret) {
    1546           0 :                         drm_property_destroy(dev, prop);
    1547             : 
    1548           0 :                         return ERR_PTR(ret);
    1549             :                 }
    1550             :         }
    1551             : 
    1552             :         return prop;
    1553             : }
    1554             : 
    1555             : /**
    1556             :  * drm_plane_create_scaling_filter_property - create a new scaling filter
    1557             :  * property
    1558             :  *
    1559             :  * @plane: drm plane
    1560             :  * @supported_filters: bitmask of supported scaling filters, must include
    1561             :  *                     BIT(DRM_SCALING_FILTER_DEFAULT).
    1562             :  *
    1563             :  * This function lets driver to enable the scaling filter property on a given
    1564             :  * plane.
    1565             :  *
    1566             :  * RETURNS:
    1567             :  * Zero for success or -errno
    1568             :  */
    1569           0 : int drm_plane_create_scaling_filter_property(struct drm_plane *plane,
    1570             :                                              unsigned int supported_filters)
    1571             : {
    1572           0 :         struct drm_property *prop =
    1573           0 :                 drm_create_scaling_filter_prop(plane->dev, supported_filters);
    1574             : 
    1575           0 :         if (IS_ERR(prop))
    1576           0 :                 return PTR_ERR(prop);
    1577             : 
    1578           0 :         drm_object_attach_property(&plane->base, prop,
    1579             :                                    DRM_SCALING_FILTER_DEFAULT);
    1580           0 :         plane->scaling_filter_property = prop;
    1581             : 
    1582           0 :         return 0;
    1583             : }
    1584             : EXPORT_SYMBOL(drm_plane_create_scaling_filter_property);

Generated by: LCOV version 1.14