LCOV - code coverage report
Current view: top level - dev/pci/drm - drm_plane_helper.c (source / functions) Hit Total Coverage
Test: 6.4 Lines: 0 162 0.0 %
Date: 2018-10-19 03:25:38 Functions: 0 10 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             :  * Copyright (C) 2014 Intel Corporation
       3             :  *
       4             :  * DRM universal plane helper functions
       5             :  *
       6             :  * Permission is hereby granted, free of charge, to any person obtaining a
       7             :  * copy of this software and associated documentation files (the "Software"),
       8             :  * to deal in the Software without restriction, including without limitation
       9             :  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
      10             :  * and/or sell copies of the Software, and to permit persons to whom the
      11             :  * Software is furnished to do so, subject to the following conditions:
      12             :  *
      13             :  * The above copyright notice and this permission notice (including the next
      14             :  * paragraph) shall be included in all copies or substantial portions of the
      15             :  * Software.
      16             :  *
      17             :  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
      18             :  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
      19             :  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
      20             :  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
      21             :  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
      22             :  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
      23             :  * SOFTWARE.
      24             :  */
      25             : 
      26             : #ifdef __linux__
      27             : #include <linux/list.h>
      28             : #endif
      29             : #include <dev/pci/drm/drmP.h>
      30             : #include <dev/pci/drm/drm_plane_helper.h>
      31             : #include <dev/pci/drm/drm_rect.h>
      32             : #include <dev/pci/drm/drm_atomic.h>
      33             : #include <dev/pci/drm/drm_crtc_helper.h>
      34             : #include <dev/pci/drm/drm_atomic_helper.h>
      35             : 
      36             : #define SUBPIXEL_MASK 0xffff
      37             : 
      38             : /**
      39             :  * DOC: overview
      40             :  *
      41             :  * This helper library has two parts. The first part has support to implement
      42             :  * primary plane support on top of the normal CRTC configuration interface.
      43             :  * Since the legacy ->set_config interface ties the primary plane together with
      44             :  * the CRTC state this does not allow userspace to disable the primary plane
      45             :  * itself.  To avoid too much duplicated code use
      46             :  * drm_plane_helper_check_update() which can be used to enforce the same
      47             :  * restrictions as primary planes had thus. The default primary plane only
      48             :  * expose XRBG8888 and ARGB8888 as valid pixel formats for the attached
      49             :  * framebuffer.
      50             :  *
      51             :  * Drivers are highly recommended to implement proper support for primary
      52             :  * planes, and newly merged drivers must not rely upon these transitional
      53             :  * helpers.
      54             :  *
      55             :  * The second part also implements transitional helpers which allow drivers to
      56             :  * gradually switch to the atomic helper infrastructure for plane updates. Once
      57             :  * that switch is complete drivers shouldn't use these any longer, instead using
      58             :  * the proper legacy implementations for update and disable plane hooks provided
      59             :  * by the atomic helpers.
      60             :  *
      61             :  * Again drivers are strongly urged to switch to the new interfaces.
      62             :  */
      63             : 
      64             : /*
      65             :  * This is the minimal list of formats that seem to be safe for modeset use
      66             :  * with all current DRM drivers.  Most hardware can actually support more
      67             :  * formats than this and drivers may specify a more accurate list when
      68             :  * creating the primary plane.  However drivers that still call
      69             :  * drm_plane_init() will use this minimal format list as the default.
      70             :  */
      71             : static const uint32_t safe_modeset_formats[] = {
      72             :         DRM_FORMAT_XRGB8888,
      73             :         DRM_FORMAT_ARGB8888,
      74             : };
      75             : 
      76             : /*
      77             :  * Returns the connectors currently associated with a CRTC.  This function
      78             :  * should be called twice:  once with a NULL connector list to retrieve
      79             :  * the list size, and once with the properly allocated list to be filled in.
      80             :  */
      81           0 : static int get_connectors_for_crtc(struct drm_crtc *crtc,
      82             :                                    struct drm_connector **connector_list,
      83             :                                    int num_connectors)
      84             : {
      85           0 :         struct drm_device *dev = crtc->dev;
      86             :         struct drm_connector *connector;
      87             :         int count = 0;
      88             : 
      89             :         /*
      90             :          * Note: Once we change the plane hooks to more fine-grained locking we
      91             :          * need to grab the connection_mutex here to be able to make these
      92             :          * checks.
      93             :          */
      94           0 :         WARN_ON(!drm_modeset_is_locked(&dev->mode_config.connection_mutex));
      95             : 
      96           0 :         drm_for_each_connector(connector, dev) {
      97           0 :                 if (connector->encoder && connector->encoder->crtc == crtc) {
      98           0 :                         if (connector_list != NULL && count < num_connectors)
      99           0 :                                 *(connector_list++) = connector;
     100             : 
     101           0 :                         count++;
     102           0 :                 }
     103             :         }
     104             : 
     105           0 :         return count;
     106             : }
     107             : 
     108             : /**
     109             :  * drm_plane_helper_check_update() - Check plane update for validity
     110             :  * @plane: plane object to update
     111             :  * @crtc: owning CRTC of owning plane
     112             :  * @fb: framebuffer to flip onto plane
     113             :  * @src: source coordinates in 16.16 fixed point
     114             :  * @dest: integer destination coordinates
     115             :  * @clip: integer clipping coordinates
     116             :  * @min_scale: minimum @src:@dest scaling factor in 16.16 fixed point
     117             :  * @max_scale: maximum @src:@dest scaling factor in 16.16 fixed point
     118             :  * @can_position: is it legal to position the plane such that it
     119             :  *                doesn't cover the entire crtc?  This will generally
     120             :  *                only be false for primary planes.
     121             :  * @can_update_disabled: can the plane be updated while the crtc
     122             :  *                       is disabled?
     123             :  * @visible: output parameter indicating whether plane is still visible after
     124             :  *           clipping
     125             :  *
     126             :  * Checks that a desired plane update is valid.  Drivers that provide
     127             :  * their own plane handling rather than helper-provided implementations may
     128             :  * still wish to call this function to avoid duplication of error checking
     129             :  * code.
     130             :  *
     131             :  * RETURNS:
     132             :  * Zero if update appears valid, error code on failure
     133             :  */
     134           0 : int drm_plane_helper_check_update(struct drm_plane *plane,
     135             :                                     struct drm_crtc *crtc,
     136             :                                     struct drm_framebuffer *fb,
     137             :                                     struct drm_rect *src,
     138             :                                     struct drm_rect *dest,
     139             :                                     const struct drm_rect *clip,
     140             :                                     int min_scale,
     141             :                                     int max_scale,
     142             :                                     bool can_position,
     143             :                                     bool can_update_disabled,
     144             :                                     bool *visible)
     145             : {
     146             :         int hscale, vscale;
     147             : 
     148           0 :         if (!fb) {
     149           0 :                 *visible = false;
     150           0 :                 return 0;
     151             :         }
     152             : 
     153             :         /* crtc should only be NULL when disabling (i.e., !fb) */
     154           0 :         if (WARN_ON(!crtc)) {
     155           0 :                 *visible = false;
     156           0 :                 return 0;
     157             :         }
     158             : 
     159           0 :         if (!crtc->enabled && !can_update_disabled) {
     160             :                 DRM_DEBUG_KMS("Cannot update plane of a disabled CRTC.\n");
     161           0 :                 return -EINVAL;
     162             :         }
     163             : 
     164             :         /* Check scaling */
     165           0 :         hscale = drm_rect_calc_hscale(src, dest, min_scale, max_scale);
     166           0 :         vscale = drm_rect_calc_vscale(src, dest, min_scale, max_scale);
     167           0 :         if (hscale < 0 || vscale < 0) {
     168             :                 DRM_DEBUG_KMS("Invalid scaling of plane\n");
     169           0 :                 return -ERANGE;
     170             :         }
     171             : 
     172           0 :         *visible = drm_rect_clip_scaled(src, dest, clip, hscale, vscale);
     173           0 :         if (!*visible)
     174             :                 /*
     175             :                  * Plane isn't visible; some drivers can handle this
     176             :                  * so we just return success here.  Drivers that can't
     177             :                  * (including those that use the primary plane helper's
     178             :                  * update function) will return an error from their
     179             :                  * update_plane handler.
     180             :                  */
     181           0 :                 return 0;
     182             : 
     183           0 :         if (!can_position && !drm_rect_equals(dest, clip)) {
     184             :                 DRM_DEBUG_KMS("Plane must cover entire CRTC\n");
     185           0 :                 return -EINVAL;
     186             :         }
     187             : 
     188           0 :         return 0;
     189           0 : }
     190             : EXPORT_SYMBOL(drm_plane_helper_check_update);
     191             : 
     192             : /**
     193             :  * drm_primary_helper_update() - Helper for primary plane update
     194             :  * @plane: plane object to update
     195             :  * @crtc: owning CRTC of owning plane
     196             :  * @fb: framebuffer to flip onto plane
     197             :  * @crtc_x: x offset of primary plane on crtc
     198             :  * @crtc_y: y offset of primary plane on crtc
     199             :  * @crtc_w: width of primary plane rectangle on crtc
     200             :  * @crtc_h: height of primary plane rectangle on crtc
     201             :  * @src_x: x offset of @fb for panning
     202             :  * @src_y: y offset of @fb for panning
     203             :  * @src_w: width of source rectangle in @fb
     204             :  * @src_h: height of source rectangle in @fb
     205             :  *
     206             :  * Provides a default plane update handler for primary planes.  This is handler
     207             :  * is called in response to a userspace SetPlane operation on the plane with a
     208             :  * non-NULL framebuffer.  We call the driver's modeset handler to update the
     209             :  * framebuffer.
     210             :  *
     211             :  * SetPlane() on a primary plane of a disabled CRTC is not supported, and will
     212             :  * return an error.
     213             :  *
     214             :  * Note that we make some assumptions about hardware limitations that may not be
     215             :  * true for all hardware --
     216             :  *   1) Primary plane cannot be repositioned.
     217             :  *   2) Primary plane cannot be scaled.
     218             :  *   3) Primary plane must cover the entire CRTC.
     219             :  *   4) Subpixel positioning is not supported.
     220             :  * Drivers for hardware that don't have these restrictions can provide their
     221             :  * own implementation rather than using this helper.
     222             :  *
     223             :  * RETURNS:
     224             :  * Zero on success, error code on failure
     225             :  */
     226           0 : int drm_primary_helper_update(struct drm_plane *plane, struct drm_crtc *crtc,
     227             :                               struct drm_framebuffer *fb,
     228             :                               int crtc_x, int crtc_y,
     229             :                               unsigned int crtc_w, unsigned int crtc_h,
     230             :                               uint32_t src_x, uint32_t src_y,
     231             :                               uint32_t src_w, uint32_t src_h)
     232             : {
     233           0 :         struct drm_mode_set set = {
     234             :                 .crtc = crtc,
     235             :                 .fb = fb,
     236           0 :                 .mode = &crtc->mode,
     237           0 :                 .x = src_x >> 16,
     238           0 :                 .y = src_y >> 16,
     239             :         };
     240           0 :         struct drm_rect src = {
     241             :                 .x1 = src_x,
     242             :                 .y1 = src_y,
     243           0 :                 .x2 = src_x + src_w,
     244           0 :                 .y2 = src_y + src_h,
     245             :         };
     246           0 :         struct drm_rect dest = {
     247             :                 .x1 = crtc_x,
     248             :                 .y1 = crtc_y,
     249           0 :                 .x2 = crtc_x + crtc_w,
     250           0 :                 .y2 = crtc_y + crtc_h,
     251             :         };
     252           0 :         const struct drm_rect clip = {
     253           0 :                 .x2 = crtc->mode.hdisplay,
     254           0 :                 .y2 = crtc->mode.vdisplay,
     255             :         };
     256             :         struct drm_connector **connector_list;
     257             :         int num_connectors, ret;
     258           0 :         bool visible;
     259             : 
     260           0 :         ret = drm_plane_helper_check_update(plane, crtc, fb,
     261             :                                             &src, &dest, &clip,
     262             :                                             DRM_PLANE_HELPER_NO_SCALING,
     263             :                                             DRM_PLANE_HELPER_NO_SCALING,
     264             :                                             false, false, &visible);
     265           0 :         if (ret)
     266           0 :                 return ret;
     267             : 
     268           0 :         if (!visible)
     269             :                 /*
     270             :                  * Primary plane isn't visible.  Note that unless a driver
     271             :                  * provides their own disable function, this will just
     272             :                  * wind up returning -EINVAL to userspace.
     273             :                  */
     274           0 :                 return plane->funcs->disable_plane(plane);
     275             : 
     276             :         /* Find current connectors for CRTC */
     277           0 :         num_connectors = get_connectors_for_crtc(crtc, NULL, 0);
     278           0 :         BUG_ON(num_connectors == 0);
     279           0 :         connector_list = kzalloc(num_connectors * sizeof(*connector_list),
     280             :                                  GFP_KERNEL);
     281           0 :         if (!connector_list)
     282           0 :                 return -ENOMEM;
     283           0 :         get_connectors_for_crtc(crtc, connector_list, num_connectors);
     284             : 
     285           0 :         set.connectors = connector_list;
     286           0 :         set.num_connectors = num_connectors;
     287             : 
     288             :         /*
     289             :          * We call set_config() directly here rather than using
     290             :          * drm_mode_set_config_internal.  We're reprogramming the same
     291             :          * connectors that were already in use, so we shouldn't need the extra
     292             :          * cross-CRTC fb refcounting to accomodate stealing connectors.
     293             :          * drm_mode_setplane() already handles the basic refcounting for the
     294             :          * framebuffers involved in this operation.
     295             :          */
     296           0 :         ret = crtc->funcs->set_config(&set);
     297             : 
     298           0 :         kfree(connector_list);
     299           0 :         return ret;
     300           0 : }
     301             : EXPORT_SYMBOL(drm_primary_helper_update);
     302             : 
     303             : /**
     304             :  * drm_primary_helper_disable() - Helper for primary plane disable
     305             :  * @plane: plane to disable
     306             :  *
     307             :  * Provides a default plane disable handler for primary planes.  This is handler
     308             :  * is called in response to a userspace SetPlane operation on the plane with a
     309             :  * NULL framebuffer parameter.  It unconditionally fails the disable call with
     310             :  * -EINVAL the only way to disable the primary plane without driver support is
     311             :  * to disable the entier CRTC. Which does not match the plane ->disable hook.
     312             :  *
     313             :  * Note that some hardware may be able to disable the primary plane without
     314             :  * disabling the whole CRTC.  Drivers for such hardware should provide their
     315             :  * own disable handler that disables just the primary plane (and they'll likely
     316             :  * need to provide their own update handler as well to properly re-enable a
     317             :  * disabled primary plane).
     318             :  *
     319             :  * RETURNS:
     320             :  * Unconditionally returns -EINVAL.
     321             :  */
     322           0 : int drm_primary_helper_disable(struct drm_plane *plane)
     323             : {
     324           0 :         return -EINVAL;
     325             : }
     326             : EXPORT_SYMBOL(drm_primary_helper_disable);
     327             : 
     328             : /**
     329             :  * drm_primary_helper_destroy() - Helper for primary plane destruction
     330             :  * @plane: plane to destroy
     331             :  *
     332             :  * Provides a default plane destroy handler for primary planes.  This handler
     333             :  * is called during CRTC destruction.  We disable the primary plane, remove
     334             :  * it from the DRM plane list, and deallocate the plane structure.
     335             :  */
     336           0 : void drm_primary_helper_destroy(struct drm_plane *plane)
     337             : {
     338           0 :         drm_plane_cleanup(plane);
     339           0 :         kfree(plane);
     340           0 : }
     341             : EXPORT_SYMBOL(drm_primary_helper_destroy);
     342             : 
     343             : const struct drm_plane_funcs drm_primary_helper_funcs = {
     344             :         .update_plane = drm_primary_helper_update,
     345             :         .disable_plane = drm_primary_helper_disable,
     346             :         .destroy = drm_primary_helper_destroy,
     347             : };
     348             : EXPORT_SYMBOL(drm_primary_helper_funcs);
     349             : 
     350           0 : static struct drm_plane *create_primary_plane(struct drm_device *dev)
     351             : {
     352             :         struct drm_plane *primary;
     353             :         int ret;
     354             : 
     355           0 :         primary = kzalloc(sizeof(*primary), GFP_KERNEL);
     356           0 :         if (primary == NULL) {
     357             :                 DRM_DEBUG_KMS("Failed to allocate primary plane\n");
     358           0 :                 return NULL;
     359             :         }
     360             : 
     361             :         /*
     362             :          * Remove the format_default field from drm_plane when dropping
     363             :          * this helper.
     364             :          */
     365           0 :         primary->format_default = true;
     366             : 
     367             :         /* possible_crtc's will be filled in later by crtc_init */
     368           0 :         ret = drm_universal_plane_init(dev, primary, 0,
     369             :                                        &drm_primary_helper_funcs,
     370             :                                        safe_modeset_formats,
     371             :                                        ARRAY_SIZE(safe_modeset_formats),
     372             :                                        DRM_PLANE_TYPE_PRIMARY);
     373           0 :         if (ret) {
     374           0 :                 kfree(primary);
     375             :                 primary = NULL;
     376           0 :         }
     377             : 
     378           0 :         return primary;
     379           0 : }
     380             : 
     381             : /**
     382             :  * drm_crtc_init - Legacy CRTC initialization function
     383             :  * @dev: DRM device
     384             :  * @crtc: CRTC object to init
     385             :  * @funcs: callbacks for the new CRTC
     386             :  *
     387             :  * Initialize a CRTC object with a default helper-provided primary plane and no
     388             :  * cursor plane.
     389             :  *
     390             :  * Returns:
     391             :  * Zero on success, error code on failure.
     392             :  */
     393           0 : int drm_crtc_init(struct drm_device *dev, struct drm_crtc *crtc,
     394             :                   const struct drm_crtc_funcs *funcs)
     395             : {
     396             :         struct drm_plane *primary;
     397             : 
     398           0 :         primary = create_primary_plane(dev);
     399           0 :         return drm_crtc_init_with_planes(dev, crtc, primary, NULL, funcs);
     400             : }
     401             : EXPORT_SYMBOL(drm_crtc_init);
     402             : 
     403           0 : int drm_plane_helper_commit(struct drm_plane *plane,
     404             :                             struct drm_plane_state *plane_state,
     405             :                             struct drm_framebuffer *old_fb)
     406             : {
     407             :         const struct drm_plane_helper_funcs *plane_funcs;
     408           0 :         struct drm_crtc *crtc[2];
     409           0 :         const struct drm_crtc_helper_funcs *crtc_funcs[2];
     410             :         int i, ret = 0;
     411             : 
     412           0 :         plane_funcs = plane->helper_private;
     413             : 
     414             :         /* Since this is a transitional helper we can't assume that plane->state
     415             :          * is always valid. Hence we need to use plane->crtc instead of
     416             :          * plane->state->crtc as the old crtc. */
     417           0 :         crtc[0] = plane->crtc;
     418           0 :         crtc[1] = crtc[0] != plane_state->crtc ? plane_state->crtc : NULL;
     419             : 
     420           0 :         for (i = 0; i < 2; i++)
     421           0 :                 crtc_funcs[i] = crtc[i] ? crtc[i]->helper_private : NULL;
     422             : 
     423           0 :         if (plane_funcs->atomic_check) {
     424           0 :                 ret = plane_funcs->atomic_check(plane, plane_state);
     425           0 :                 if (ret)
     426             :                         goto out;
     427             :         }
     428             : 
     429           0 :         if (plane_funcs->prepare_fb && plane_state->fb &&
     430           0 :             plane_state->fb != old_fb) {
     431           0 :                 ret = plane_funcs->prepare_fb(plane,
     432             :                                               plane_state);
     433           0 :                 if (ret)
     434             :                         goto out;
     435             :         }
     436             : 
     437             :         /* Point of no return, commit sw state. */
     438           0 :         swap(plane->state, plane_state);
     439             : 
     440           0 :         for (i = 0; i < 2; i++) {
     441           0 :                 if (crtc_funcs[i] && crtc_funcs[i]->atomic_begin)
     442           0 :                         crtc_funcs[i]->atomic_begin(crtc[i], crtc[i]->state);
     443             :         }
     444             : 
     445             :         /*
     446             :          * Drivers may optionally implement the ->atomic_disable callback, so
     447             :          * special-case that here.
     448             :          */
     449           0 :         if (drm_atomic_plane_disabling(plane, plane_state) &&
     450           0 :             plane_funcs->atomic_disable)
     451           0 :                 plane_funcs->atomic_disable(plane, plane_state);
     452             :         else
     453           0 :                 plane_funcs->atomic_update(plane, plane_state);
     454             : 
     455           0 :         for (i = 0; i < 2; i++) {
     456           0 :                 if (crtc_funcs[i] && crtc_funcs[i]->atomic_flush)
     457           0 :                         crtc_funcs[i]->atomic_flush(crtc[i], crtc[i]->state);
     458             :         }
     459             : 
     460             :         /*
     461             :          * If we only moved the plane and didn't change fb's, there's no need to
     462             :          * wait for vblank.
     463             :          */
     464           0 :         if (plane->state->fb == old_fb)
     465             :                 goto out;
     466             : 
     467           0 :         for (i = 0; i < 2; i++) {
     468           0 :                 if (!crtc[i])
     469             :                         continue;
     470             : 
     471           0 :                 if (crtc[i]->cursor == plane)
     472             :                         continue;
     473             : 
     474             :                 /* There's no other way to figure out whether the crtc is running. */
     475           0 :                 ret = drm_crtc_vblank_get(crtc[i]);
     476           0 :                 if (ret == 0) {
     477           0 :                         drm_crtc_wait_one_vblank(crtc[i]);
     478           0 :                         drm_crtc_vblank_put(crtc[i]);
     479           0 :                 }
     480             : 
     481             :                 ret = 0;
     482           0 :         }
     483             : 
     484           0 :         if (plane_funcs->cleanup_fb)
     485           0 :                 plane_funcs->cleanup_fb(plane, plane_state);
     486             : out:
     487           0 :         if (plane_state) {
     488           0 :                 if (plane->funcs->atomic_destroy_state)
     489           0 :                         plane->funcs->atomic_destroy_state(plane, plane_state);
     490             :                 else
     491           0 :                         drm_atomic_helper_plane_destroy_state(plane, plane_state);
     492             :         }
     493             : 
     494           0 :         return ret;
     495           0 : }
     496             : 
     497             : /**
     498             :  * drm_plane_helper_update() - Transitional helper for plane update
     499             :  * @plane: plane object to update
     500             :  * @crtc: owning CRTC of owning plane
     501             :  * @fb: framebuffer to flip onto plane
     502             :  * @crtc_x: x offset of primary plane on crtc
     503             :  * @crtc_y: y offset of primary plane on crtc
     504             :  * @crtc_w: width of primary plane rectangle on crtc
     505             :  * @crtc_h: height of primary plane rectangle on crtc
     506             :  * @src_x: x offset of @fb for panning
     507             :  * @src_y: y offset of @fb for panning
     508             :  * @src_w: width of source rectangle in @fb
     509             :  * @src_h: height of source rectangle in @fb
     510             :  *
     511             :  * Provides a default plane update handler using the atomic plane update
     512             :  * functions. It is fully left to the driver to check plane constraints and
     513             :  * handle corner-cases like a fully occluded or otherwise invisible plane.
     514             :  *
     515             :  * This is useful for piecewise transitioning of a driver to the atomic helpers.
     516             :  *
     517             :  * RETURNS:
     518             :  * Zero on success, error code on failure
     519             :  */
     520           0 : int drm_plane_helper_update(struct drm_plane *plane, struct drm_crtc *crtc,
     521             :                             struct drm_framebuffer *fb,
     522             :                             int crtc_x, int crtc_y,
     523             :                             unsigned int crtc_w, unsigned int crtc_h,
     524             :                             uint32_t src_x, uint32_t src_y,
     525             :                             uint32_t src_w, uint32_t src_h)
     526             : {
     527             :         struct drm_plane_state *plane_state;
     528             : 
     529           0 :         if (plane->funcs->atomic_duplicate_state)
     530           0 :                 plane_state = plane->funcs->atomic_duplicate_state(plane);
     531             :         else {
     532           0 :                 if (!plane->state)
     533           0 :                         drm_atomic_helper_plane_reset(plane);
     534             : 
     535           0 :                 plane_state = drm_atomic_helper_plane_duplicate_state(plane);
     536             :         }
     537           0 :         if (!plane_state)
     538           0 :                 return -ENOMEM;
     539           0 :         plane_state->plane = plane;
     540             : 
     541           0 :         plane_state->crtc = crtc;
     542           0 :         drm_atomic_set_fb_for_plane(plane_state, fb);
     543           0 :         plane_state->crtc_x = crtc_x;
     544           0 :         plane_state->crtc_y = crtc_y;
     545           0 :         plane_state->crtc_h = crtc_h;
     546           0 :         plane_state->crtc_w = crtc_w;
     547           0 :         plane_state->src_x = src_x;
     548           0 :         plane_state->src_y = src_y;
     549           0 :         plane_state->src_h = src_h;
     550           0 :         plane_state->src_w = src_w;
     551             : 
     552           0 :         return drm_plane_helper_commit(plane, plane_state, plane->fb);
     553           0 : }
     554             : EXPORT_SYMBOL(drm_plane_helper_update);
     555             : 
     556             : /**
     557             :  * drm_plane_helper_disable() - Transitional helper for plane disable
     558             :  * @plane: plane to disable
     559             :  *
     560             :  * Provides a default plane disable handler using the atomic plane update
     561             :  * functions. It is fully left to the driver to check plane constraints and
     562             :  * handle corner-cases like a fully occluded or otherwise invisible plane.
     563             :  *
     564             :  * This is useful for piecewise transitioning of a driver to the atomic helpers.
     565             :  *
     566             :  * RETURNS:
     567             :  * Zero on success, error code on failure
     568             :  */
     569           0 : int drm_plane_helper_disable(struct drm_plane *plane)
     570             : {
     571             :         struct drm_plane_state *plane_state;
     572             : 
     573             :         /* crtc helpers love to call disable functions for already disabled hw
     574             :          * functions. So cope with that. */
     575           0 :         if (!plane->crtc)
     576           0 :                 return 0;
     577             : 
     578           0 :         if (plane->funcs->atomic_duplicate_state)
     579           0 :                 plane_state = plane->funcs->atomic_duplicate_state(plane);
     580             :         else {
     581           0 :                 if (!plane->state)
     582           0 :                         drm_atomic_helper_plane_reset(plane);
     583             : 
     584           0 :                 plane_state = drm_atomic_helper_plane_duplicate_state(plane);
     585             :         }
     586           0 :         if (!plane_state)
     587           0 :                 return -ENOMEM;
     588           0 :         plane_state->plane = plane;
     589             : 
     590           0 :         plane_state->crtc = NULL;
     591           0 :         drm_atomic_set_fb_for_plane(plane_state, NULL);
     592             : 
     593           0 :         return drm_plane_helper_commit(plane, plane_state, plane->fb);
     594           0 : }
     595             : EXPORT_SYMBOL(drm_plane_helper_disable);

Generated by: LCOV version 1.13