LCOV - code coverage report
Current view: top level - drivers/gpu/drm - drm_plane.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 0 523 0.0 %
Date: 2022-12-09 01:23:36 Functions: 0 32 0.0 %

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

Generated by: LCOV version 1.14