LCOV - code coverage report
Current view: top level - drivers/gpu/drm - drm_crtc.c (source / functions) Hit Total Coverage
Test: combined.info Lines: 0 312 0.0 %
Date: 2022-03-28 13:20:08 Functions: 0 16 0.0 %
Branches: 0 216 0.0 %

           Branch data     Line data    Source code
       1                 :            : /*
       2                 :            :  * Copyright (c) 2006-2008 Intel Corporation
       3                 :            :  * Copyright (c) 2007 Dave Airlie <airlied@linux.ie>
       4                 :            :  * Copyright (c) 2008 Red Hat Inc.
       5                 :            :  *
       6                 :            :  * DRM core CRTC related functions
       7                 :            :  *
       8                 :            :  * Permission to use, copy, modify, distribute, and sell this software and its
       9                 :            :  * documentation for any purpose is hereby granted without fee, provided that
      10                 :            :  * the above copyright notice appear in all copies and that both that copyright
      11                 :            :  * notice and this permission notice appear in supporting documentation, and
      12                 :            :  * that the name of the copyright holders not be used in advertising or
      13                 :            :  * publicity pertaining to distribution of the software without specific,
      14                 :            :  * written prior permission.  The copyright holders make no representations
      15                 :            :  * about the suitability of this software for any purpose.  It is provided "as
      16                 :            :  * is" without express or implied warranty.
      17                 :            :  *
      18                 :            :  * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
      19                 :            :  * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
      20                 :            :  * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
      21                 :            :  * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
      22                 :            :  * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
      23                 :            :  * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
      24                 :            :  * OF THIS SOFTWARE.
      25                 :            :  *
      26                 :            :  * Authors:
      27                 :            :  *      Keith Packard
      28                 :            :  *      Eric Anholt <eric@anholt.net>
      29                 :            :  *      Dave Airlie <airlied@linux.ie>
      30                 :            :  *      Jesse Barnes <jesse.barnes@intel.com>
      31                 :            :  */
      32                 :            : #include <linux/ctype.h>
      33                 :            : #include <linux/list.h>
      34                 :            : #include <linux/slab.h>
      35                 :            : #include <linux/export.h>
      36                 :            : #include <linux/dma-fence.h>
      37                 :            : #include <linux/uaccess.h>
      38                 :            : #include <drm/drm_crtc.h>
      39                 :            : #include <drm/drm_edid.h>
      40                 :            : #include <drm/drm_fourcc.h>
      41                 :            : #include <drm/drm_modeset_lock.h>
      42                 :            : #include <drm/drm_atomic.h>
      43                 :            : #include <drm/drm_auth.h>
      44                 :            : #include <drm/drm_debugfs_crc.h>
      45                 :            : #include <drm/drm_drv.h>
      46                 :            : #include <drm/drm_print.h>
      47                 :            : #include <drm/drm_file.h>
      48                 :            : 
      49                 :            : #include "drm_crtc_internal.h"
      50                 :            : #include "drm_internal.h"
      51                 :            : 
      52                 :            : /**
      53                 :            :  * DOC: overview
      54                 :            :  *
      55                 :            :  * A CRTC represents the overall display pipeline. It receives pixel data from
      56                 :            :  * &drm_plane and blends them together. The &drm_display_mode is also attached
      57                 :            :  * to the CRTC, specifying display timings. On the output side the data is fed
      58                 :            :  * to one or more &drm_encoder, which are then each connected to one
      59                 :            :  * &drm_connector.
      60                 :            :  *
      61                 :            :  * To create a CRTC, a KMS drivers allocates and zeroes an instances of
      62                 :            :  * &struct drm_crtc (possibly as part of a larger structure) and registers it
      63                 :            :  * with a call to drm_crtc_init_with_planes().
      64                 :            :  *
      65                 :            :  * The CRTC is also the entry point for legacy modeset operations, see
      66                 :            :  * &drm_crtc_funcs.set_config, legacy plane operations, see
      67                 :            :  * &drm_crtc_funcs.page_flip and &drm_crtc_funcs.cursor_set2, and other legacy
      68                 :            :  * operations like &drm_crtc_funcs.gamma_set. For atomic drivers all these
      69                 :            :  * features are controlled through &drm_property and
      70                 :            :  * &drm_mode_config_funcs.atomic_check and &drm_mode_config_funcs.atomic_check.
      71                 :            :  */
      72                 :            : 
      73                 :            : /**
      74                 :            :  * drm_crtc_from_index - find the registered CRTC at an index
      75                 :            :  * @dev: DRM device
      76                 :            :  * @idx: index of registered CRTC to find for
      77                 :            :  *
      78                 :            :  * Given a CRTC index, return the registered CRTC from DRM device's
      79                 :            :  * list of CRTCs with matching index. This is the inverse of drm_crtc_index().
      80                 :            :  * It's useful in the vblank callbacks (like &drm_driver.enable_vblank or
      81                 :            :  * &drm_driver.disable_vblank), since that still deals with indices instead
      82                 :            :  * of pointers to &struct drm_crtc."
      83                 :            :  */
      84                 :          0 : struct drm_crtc *drm_crtc_from_index(struct drm_device *dev, int idx)
      85                 :            : {
      86                 :          0 :         struct drm_crtc *crtc;
      87                 :            : 
      88         [ #  # ]:          0 :         drm_for_each_crtc(crtc, dev)
      89         [ #  # ]:          0 :                 if (idx == crtc->index)
      90                 :          0 :                         return crtc;
      91                 :            : 
      92                 :            :         return NULL;
      93                 :            : }
      94                 :            : EXPORT_SYMBOL(drm_crtc_from_index);
      95                 :            : 
      96                 :          0 : int drm_crtc_force_disable(struct drm_crtc *crtc)
      97                 :            : {
      98                 :          0 :         struct drm_mode_set set = {
      99                 :            :                 .crtc = crtc,
     100                 :            :         };
     101                 :            : 
     102   [ #  #  #  # ]:          0 :         WARN_ON(drm_drv_uses_atomic_modeset(crtc->dev));
     103                 :            : 
     104                 :          0 :         return drm_mode_set_config_internal(&set);
     105                 :            : }
     106                 :            : 
     107                 :          0 : static unsigned int drm_num_crtcs(struct drm_device *dev)
     108                 :            : {
     109                 :          0 :         unsigned int num = 0;
     110                 :          0 :         struct drm_crtc *tmp;
     111                 :            : 
     112         [ #  # ]:          0 :         drm_for_each_crtc(tmp, dev) {
     113                 :          0 :                 num++;
     114                 :            :         }
     115                 :            : 
     116                 :          0 :         return num;
     117                 :            : }
     118                 :            : 
     119                 :          0 : int drm_crtc_register_all(struct drm_device *dev)
     120                 :            : {
     121                 :          0 :         struct drm_crtc *crtc;
     122                 :          0 :         int ret = 0;
     123                 :            : 
     124         [ #  # ]:          0 :         drm_for_each_crtc(crtc, dev) {
     125                 :          0 :                 drm_debugfs_crtc_add(crtc);
     126                 :            : 
     127         [ #  # ]:          0 :                 if (crtc->funcs->late_register)
     128                 :          0 :                         ret = crtc->funcs->late_register(crtc);
     129         [ #  # ]:          0 :                 if (ret)
     130                 :          0 :                         return ret;
     131                 :            :         }
     132                 :            : 
     133                 :            :         return 0;
     134                 :            : }
     135                 :            : 
     136                 :          0 : void drm_crtc_unregister_all(struct drm_device *dev)
     137                 :            : {
     138                 :          0 :         struct drm_crtc *crtc;
     139                 :            : 
     140         [ #  # ]:          0 :         drm_for_each_crtc(crtc, dev) {
     141         [ #  # ]:          0 :                 if (crtc->funcs->early_unregister)
     142                 :          0 :                         crtc->funcs->early_unregister(crtc);
     143                 :          0 :                 drm_debugfs_crtc_remove(crtc);
     144                 :            :         }
     145                 :          0 : }
     146                 :            : 
     147                 :          0 : static int drm_crtc_crc_init(struct drm_crtc *crtc)
     148                 :            : {
     149                 :            : #ifdef CONFIG_DEBUG_FS
     150                 :          0 :         spin_lock_init(&crtc->crc.lock);
     151                 :          0 :         init_waitqueue_head(&crtc->crc.wq);
     152                 :          0 :         crtc->crc.source = kstrdup("auto", GFP_KERNEL);
     153         [ #  # ]:          0 :         if (!crtc->crc.source)
     154                 :          0 :                 return -ENOMEM;
     155                 :            : #endif
     156                 :            :         return 0;
     157                 :            : }
     158                 :            : 
     159                 :          0 : static void drm_crtc_crc_fini(struct drm_crtc *crtc)
     160                 :            : {
     161                 :            : #ifdef CONFIG_DEBUG_FS
     162                 :          0 :         kfree(crtc->crc.source);
     163                 :            : #endif
     164                 :            : }
     165                 :            : 
     166                 :            : static const struct dma_fence_ops drm_crtc_fence_ops;
     167                 :            : 
     168                 :          0 : static struct drm_crtc *fence_to_crtc(struct dma_fence *fence)
     169                 :            : {
     170                 :          0 :         BUG_ON(fence->ops != &drm_crtc_fence_ops);
     171                 :          0 :         return container_of(fence->lock, struct drm_crtc, fence_lock);
     172                 :            : }
     173                 :            : 
     174                 :          0 : static const char *drm_crtc_fence_get_driver_name(struct dma_fence *fence)
     175                 :            : {
     176         [ #  # ]:          0 :         struct drm_crtc *crtc = fence_to_crtc(fence);
     177                 :            : 
     178                 :          0 :         return crtc->dev->driver->name;
     179                 :            : }
     180                 :            : 
     181                 :          0 : static const char *drm_crtc_fence_get_timeline_name(struct dma_fence *fence)
     182                 :            : {
     183         [ #  # ]:          0 :         struct drm_crtc *crtc = fence_to_crtc(fence);
     184                 :            : 
     185                 :          0 :         return crtc->timeline_name;
     186                 :            : }
     187                 :            : 
     188                 :            : static const struct dma_fence_ops drm_crtc_fence_ops = {
     189                 :            :         .get_driver_name = drm_crtc_fence_get_driver_name,
     190                 :            :         .get_timeline_name = drm_crtc_fence_get_timeline_name,
     191                 :            : };
     192                 :            : 
     193                 :          0 : struct dma_fence *drm_crtc_create_fence(struct drm_crtc *crtc)
     194                 :            : {
     195                 :          0 :         struct dma_fence *fence;
     196                 :            : 
     197                 :          0 :         fence = kzalloc(sizeof(*fence), GFP_KERNEL);
     198         [ #  # ]:          0 :         if (!fence)
     199                 :            :                 return NULL;
     200                 :            : 
     201                 :          0 :         dma_fence_init(fence, &drm_crtc_fence_ops, &crtc->fence_lock,
     202                 :          0 :                        crtc->fence_context, ++crtc->fence_seqno);
     203                 :            : 
     204                 :          0 :         return fence;
     205                 :            : }
     206                 :            : 
     207                 :            : /**
     208                 :            :  * drm_crtc_init_with_planes - Initialise a new CRTC object with
     209                 :            :  *    specified primary and cursor planes.
     210                 :            :  * @dev: DRM device
     211                 :            :  * @crtc: CRTC object to init
     212                 :            :  * @primary: Primary plane for CRTC
     213                 :            :  * @cursor: Cursor plane for CRTC
     214                 :            :  * @funcs: callbacks for the new CRTC
     215                 :            :  * @name: printf style format string for the CRTC name, or NULL for default name
     216                 :            :  *
     217                 :            :  * Inits a new object created as base part of a driver crtc object. Drivers
     218                 :            :  * should use this function instead of drm_crtc_init(), which is only provided
     219                 :            :  * for backwards compatibility with drivers which do not yet support universal
     220                 :            :  * planes). For really simple hardware which has only 1 plane look at
     221                 :            :  * drm_simple_display_pipe_init() instead.
     222                 :            :  *
     223                 :            :  * Returns:
     224                 :            :  * Zero on success, error code on failure.
     225                 :            :  */
     226                 :          0 : int drm_crtc_init_with_planes(struct drm_device *dev, struct drm_crtc *crtc,
     227                 :            :                               struct drm_plane *primary,
     228                 :            :                               struct drm_plane *cursor,
     229                 :            :                               const struct drm_crtc_funcs *funcs,
     230                 :            :                               const char *name, ...)
     231                 :            : {
     232                 :          0 :         struct drm_mode_config *config = &dev->mode_config;
     233                 :          0 :         int ret;
     234                 :            : 
     235   [ #  #  #  #  :          0 :         WARN_ON(primary && primary->type != DRM_PLANE_TYPE_PRIMARY);
                   #  # ]
     236   [ #  #  #  #  :          0 :         WARN_ON(cursor && cursor->type != DRM_PLANE_TYPE_CURSOR);
                   #  # ]
     237                 :            : 
     238                 :            :         /* crtc index is used with 32bit bitmasks */
     239   [ #  #  #  # ]:          0 :         if (WARN_ON(config->num_crtc >= 32))
     240                 :            :                 return -EINVAL;
     241                 :            : 
     242   [ #  #  #  #  :          0 :         WARN_ON(drm_drv_uses_atomic_modeset(dev) &&
          #  #  #  #  #  
                      # ]
     243                 :            :                 (!funcs->atomic_destroy_state ||
     244                 :            :                  !funcs->atomic_duplicate_state));
     245                 :            : 
     246                 :          0 :         crtc->dev = dev;
     247                 :          0 :         crtc->funcs = funcs;
     248                 :            : 
     249                 :          0 :         INIT_LIST_HEAD(&crtc->commit_list);
     250                 :          0 :         spin_lock_init(&crtc->commit_lock);
     251                 :            : 
     252                 :          0 :         drm_modeset_lock_init(&crtc->mutex);
     253                 :          0 :         ret = drm_mode_object_add(dev, &crtc->base, DRM_MODE_OBJECT_CRTC);
     254         [ #  # ]:          0 :         if (ret)
     255                 :            :                 return ret;
     256                 :            : 
     257         [ #  # ]:          0 :         if (name) {
     258                 :          0 :                 va_list ap;
     259                 :            : 
     260                 :          0 :                 va_start(ap, name);
     261                 :          0 :                 crtc->name = kvasprintf(GFP_KERNEL, name, ap);
     262                 :          0 :                 va_end(ap);
     263                 :            :         } else {
     264                 :          0 :                 crtc->name = kasprintf(GFP_KERNEL, "crtc-%d",
     265                 :            :                                        drm_num_crtcs(dev));
     266                 :            :         }
     267         [ #  # ]:          0 :         if (!crtc->name) {
     268                 :          0 :                 drm_mode_object_unregister(dev, &crtc->base);
     269                 :          0 :                 return -ENOMEM;
     270                 :            :         }
     271                 :            : 
     272                 :          0 :         crtc->fence_context = dma_fence_context_alloc(1);
     273         [ #  # ]:          0 :         spin_lock_init(&crtc->fence_lock);
     274                 :          0 :         snprintf(crtc->timeline_name, sizeof(crtc->timeline_name),
     275                 :            :                  "CRTC:%d-%s", crtc->base.id, crtc->name);
     276                 :            : 
     277                 :          0 :         crtc->base.properties = &crtc->properties;
     278                 :            : 
     279         [ #  # ]:          0 :         list_add_tail(&crtc->head, &config->crtc_list);
     280                 :          0 :         crtc->index = config->num_crtc++;
     281                 :            : 
     282                 :          0 :         crtc->primary = primary;
     283                 :          0 :         crtc->cursor = cursor;
     284   [ #  #  #  # ]:          0 :         if (primary && !primary->possible_crtcs)
     285                 :          0 :                 primary->possible_crtcs = drm_crtc_mask(crtc);
     286   [ #  #  #  # ]:          0 :         if (cursor && !cursor->possible_crtcs)
     287                 :          0 :                 cursor->possible_crtcs = drm_crtc_mask(crtc);
     288                 :            : 
     289                 :          0 :         ret = drm_crtc_crc_init(crtc);
     290         [ #  # ]:          0 :         if (ret) {
     291                 :          0 :                 drm_mode_object_unregister(dev, &crtc->base);
     292                 :          0 :                 return ret;
     293                 :            :         }
     294                 :            : 
     295         [ #  # ]:          0 :         if (drm_core_check_feature(dev, DRIVER_ATOMIC)) {
     296                 :          0 :                 drm_object_attach_property(&crtc->base, config->prop_active, 0);
     297                 :          0 :                 drm_object_attach_property(&crtc->base, config->prop_mode_id, 0);
     298                 :          0 :                 drm_object_attach_property(&crtc->base,
     299                 :            :                                            config->prop_out_fence_ptr, 0);
     300                 :          0 :                 drm_object_attach_property(&crtc->base,
     301                 :            :                                            config->prop_vrr_enabled, 0);
     302                 :            :         }
     303                 :            : 
     304                 :            :         return 0;
     305                 :            : }
     306                 :            : EXPORT_SYMBOL(drm_crtc_init_with_planes);
     307                 :            : 
     308                 :            : /**
     309                 :            :  * drm_crtc_cleanup - Clean up the core crtc usage
     310                 :            :  * @crtc: CRTC to cleanup
     311                 :            :  *
     312                 :            :  * This function cleans up @crtc and removes it from the DRM mode setting
     313                 :            :  * core. Note that the function does *not* free the crtc structure itself,
     314                 :            :  * this is the responsibility of the caller.
     315                 :            :  */
     316                 :          0 : void drm_crtc_cleanup(struct drm_crtc *crtc)
     317                 :            : {
     318                 :          0 :         struct drm_device *dev = crtc->dev;
     319                 :            : 
     320                 :            :         /* Note that the crtc_list is considered to be static; should we
     321                 :            :          * remove the drm_crtc at runtime we would have to decrement all
     322                 :            :          * the indices on the drm_crtc after us in the crtc_list.
     323                 :            :          */
     324                 :            : 
     325                 :          0 :         drm_crtc_crc_fini(crtc);
     326                 :            : 
     327                 :          0 :         kfree(crtc->gamma_store);
     328                 :          0 :         crtc->gamma_store = NULL;
     329                 :            : 
     330         [ #  # ]:          0 :         drm_modeset_lock_fini(&crtc->mutex);
     331                 :            : 
     332                 :          0 :         drm_mode_object_unregister(dev, &crtc->base);
     333         [ #  # ]:          0 :         list_del(&crtc->head);
     334                 :          0 :         dev->mode_config.num_crtc--;
     335                 :            : 
     336   [ #  #  #  #  :          0 :         WARN_ON(crtc->state && !crtc->funcs->atomic_destroy_state);
                   #  # ]
     337   [ #  #  #  # ]:          0 :         if (crtc->state && crtc->funcs->atomic_destroy_state)
     338                 :          0 :                 crtc->funcs->atomic_destroy_state(crtc, crtc->state);
     339                 :            : 
     340                 :          0 :         kfree(crtc->name);
     341                 :            : 
     342                 :          0 :         memset(crtc, 0, sizeof(*crtc));
     343                 :          0 : }
     344                 :            : EXPORT_SYMBOL(drm_crtc_cleanup);
     345                 :            : 
     346                 :            : /**
     347                 :            :  * drm_mode_getcrtc - get CRTC configuration
     348                 :            :  * @dev: drm device for the ioctl
     349                 :            :  * @data: data pointer for the ioctl
     350                 :            :  * @file_priv: drm file for the ioctl call
     351                 :            :  *
     352                 :            :  * Construct a CRTC configuration structure to return to the user.
     353                 :            :  *
     354                 :            :  * Called by the user via ioctl.
     355                 :            :  *
     356                 :            :  * Returns:
     357                 :            :  * Zero on success, negative errno on failure.
     358                 :            :  */
     359                 :          0 : int drm_mode_getcrtc(struct drm_device *dev,
     360                 :            :                      void *data, struct drm_file *file_priv)
     361                 :            : {
     362                 :          0 :         struct drm_mode_crtc *crtc_resp = data;
     363                 :          0 :         struct drm_crtc *crtc;
     364                 :          0 :         struct drm_plane *plane;
     365                 :            : 
     366         [ #  # ]:          0 :         if (!drm_core_check_feature(dev, DRIVER_MODESET))
     367                 :            :                 return -EOPNOTSUPP;
     368                 :            : 
     369                 :          0 :         crtc = drm_crtc_find(dev, file_priv, crtc_resp->crtc_id);
     370         [ #  # ]:          0 :         if (!crtc)
     371                 :            :                 return -ENOENT;
     372                 :            : 
     373                 :          0 :         plane = crtc->primary;
     374                 :            : 
     375                 :          0 :         crtc_resp->gamma_size = crtc->gamma_size;
     376                 :            : 
     377                 :          0 :         drm_modeset_lock(&plane->mutex, NULL);
     378   [ #  #  #  # ]:          0 :         if (plane->state && plane->state->fb)
     379                 :          0 :                 crtc_resp->fb_id = plane->state->fb->base.id;
     380   [ #  #  #  # ]:          0 :         else if (!plane->state && plane->fb)
     381                 :          0 :                 crtc_resp->fb_id = plane->fb->base.id;
     382                 :            :         else
     383                 :          0 :                 crtc_resp->fb_id = 0;
     384                 :            : 
     385         [ #  # ]:          0 :         if (plane->state) {
     386                 :          0 :                 crtc_resp->x = plane->state->src_x >> 16;
     387                 :          0 :                 crtc_resp->y = plane->state->src_y >> 16;
     388                 :            :         }
     389                 :          0 :         drm_modeset_unlock(&plane->mutex);
     390                 :            : 
     391                 :          0 :         drm_modeset_lock(&crtc->mutex, NULL);
     392         [ #  # ]:          0 :         if (crtc->state) {
     393         [ #  # ]:          0 :                 if (crtc->state->enable) {
     394                 :          0 :                         drm_mode_convert_to_umode(&crtc_resp->mode, &crtc->state->mode);
     395                 :          0 :                         crtc_resp->mode_valid = 1;
     396                 :            :                 } else {
     397                 :          0 :                         crtc_resp->mode_valid = 0;
     398                 :            :                 }
     399                 :            :         } else {
     400                 :          0 :                 crtc_resp->x = crtc->x;
     401                 :          0 :                 crtc_resp->y = crtc->y;
     402                 :            : 
     403         [ #  # ]:          0 :                 if (crtc->enabled) {
     404                 :          0 :                         drm_mode_convert_to_umode(&crtc_resp->mode, &crtc->mode);
     405                 :          0 :                         crtc_resp->mode_valid = 1;
     406                 :            : 
     407                 :            :                 } else {
     408                 :          0 :                         crtc_resp->mode_valid = 0;
     409                 :            :                 }
     410                 :            :         }
     411         [ #  # ]:          0 :         if (!file_priv->aspect_ratio_allowed)
     412                 :          0 :                 crtc_resp->mode.flags &= ~DRM_MODE_FLAG_PIC_AR_MASK;
     413                 :          0 :         drm_modeset_unlock(&crtc->mutex);
     414                 :            : 
     415                 :          0 :         return 0;
     416                 :            : }
     417                 :            : 
     418                 :          0 : static int __drm_mode_set_config_internal(struct drm_mode_set *set,
     419                 :            :                                           struct drm_modeset_acquire_ctx *ctx)
     420                 :            : {
     421                 :          0 :         struct drm_crtc *crtc = set->crtc;
     422                 :          0 :         struct drm_framebuffer *fb;
     423                 :          0 :         struct drm_crtc *tmp;
     424                 :          0 :         int ret;
     425                 :            : 
     426   [ #  #  #  # ]:          0 :         WARN_ON(drm_drv_uses_atomic_modeset(crtc->dev));
     427                 :            : 
     428                 :            :         /*
     429                 :            :          * NOTE: ->set_config can also disable other crtcs (if we steal all
     430                 :            :          * connectors from it), hence we need to refcount the fbs across all
     431                 :            :          * crtcs. Atomic modeset will have saner semantics ...
     432                 :            :          */
     433         [ #  # ]:          0 :         drm_for_each_crtc(tmp, crtc->dev) {
     434                 :          0 :                 struct drm_plane *plane = tmp->primary;
     435                 :            : 
     436                 :          0 :                 plane->old_fb = plane->fb;
     437                 :            :         }
     438                 :            : 
     439                 :          0 :         fb = set->fb;
     440                 :            : 
     441                 :          0 :         ret = crtc->funcs->set_config(set, ctx);
     442         [ #  # ]:          0 :         if (ret == 0) {
     443                 :          0 :                 struct drm_plane *plane = crtc->primary;
     444                 :            : 
     445         [ #  # ]:          0 :                 plane->crtc = fb ? crtc : NULL;
     446                 :          0 :                 plane->fb = fb;
     447                 :            :         }
     448                 :            : 
     449         [ #  # ]:          0 :         drm_for_each_crtc(tmp, crtc->dev) {
     450                 :          0 :                 struct drm_plane *plane = tmp->primary;
     451                 :            : 
     452         [ #  # ]:          0 :                 if (plane->fb)
     453                 :          0 :                         drm_framebuffer_get(plane->fb);
     454         [ #  # ]:          0 :                 if (plane->old_fb)
     455                 :          0 :                         drm_framebuffer_put(plane->old_fb);
     456                 :          0 :                 plane->old_fb = NULL;
     457                 :            :         }
     458                 :            : 
     459                 :          0 :         return ret;
     460                 :            : }
     461                 :            : 
     462                 :            : /**
     463                 :            :  * drm_mode_set_config_internal - helper to call &drm_mode_config_funcs.set_config
     464                 :            :  * @set: modeset config to set
     465                 :            :  *
     466                 :            :  * This is a little helper to wrap internal calls to the
     467                 :            :  * &drm_mode_config_funcs.set_config driver interface. The only thing it adds is
     468                 :            :  * correct refcounting dance.
     469                 :            :  *
     470                 :            :  * This should only be used by non-atomic legacy drivers.
     471                 :            :  *
     472                 :            :  * Returns:
     473                 :            :  * Zero on success, negative errno on failure.
     474                 :            :  */
     475                 :          0 : int drm_mode_set_config_internal(struct drm_mode_set *set)
     476                 :            : {
     477   [ #  #  #  # ]:          0 :         WARN_ON(drm_drv_uses_atomic_modeset(set->crtc->dev));
     478                 :            : 
     479                 :          0 :         return __drm_mode_set_config_internal(set, NULL);
     480                 :            : }
     481                 :            : EXPORT_SYMBOL(drm_mode_set_config_internal);
     482                 :            : 
     483                 :            : /**
     484                 :            :  * drm_crtc_check_viewport - Checks that a framebuffer is big enough for the
     485                 :            :  *     CRTC viewport
     486                 :            :  * @crtc: CRTC that framebuffer will be displayed on
     487                 :            :  * @x: x panning
     488                 :            :  * @y: y panning
     489                 :            :  * @mode: mode that framebuffer will be displayed under
     490                 :            :  * @fb: framebuffer to check size of
     491                 :            :  */
     492                 :          0 : int drm_crtc_check_viewport(const struct drm_crtc *crtc,
     493                 :            :                             int x, int y,
     494                 :            :                             const struct drm_display_mode *mode,
     495                 :            :                             const struct drm_framebuffer *fb)
     496                 :            : 
     497                 :            : {
     498                 :          0 :         int hdisplay, vdisplay;
     499                 :            : 
     500                 :          0 :         drm_mode_get_hv_timing(mode, &hdisplay, &vdisplay);
     501                 :            : 
     502   [ #  #  #  # ]:          0 :         if (crtc->state &&
     503         [ #  # ]:          0 :             drm_rotation_90_or_270(crtc->primary->state->rotation))
     504                 :          0 :                 swap(hdisplay, vdisplay);
     505                 :            : 
     506                 :          0 :         return drm_framebuffer_check_src_coords(x << 16, y << 16,
     507                 :          0 :                                                 hdisplay << 16, vdisplay << 16,
     508                 :            :                                                 fb);
     509                 :            : }
     510                 :            : EXPORT_SYMBOL(drm_crtc_check_viewport);
     511                 :            : 
     512                 :            : /**
     513                 :            :  * drm_mode_setcrtc - set CRTC configuration
     514                 :            :  * @dev: drm device for the ioctl
     515                 :            :  * @data: data pointer for the ioctl
     516                 :            :  * @file_priv: drm file for the ioctl call
     517                 :            :  *
     518                 :            :  * Build a new CRTC configuration based on user request.
     519                 :            :  *
     520                 :            :  * Called by the user via ioctl.
     521                 :            :  *
     522                 :            :  * Returns:
     523                 :            :  * Zero on success, negative errno on failure.
     524                 :            :  */
     525                 :          0 : int drm_mode_setcrtc(struct drm_device *dev, void *data,
     526                 :            :                      struct drm_file *file_priv)
     527                 :            : {
     528                 :          0 :         struct drm_mode_config *config = &dev->mode_config;
     529                 :          0 :         struct drm_mode_crtc *crtc_req = data;
     530                 :          0 :         struct drm_crtc *crtc;
     531                 :          0 :         struct drm_plane *plane;
     532                 :          0 :         struct drm_connector **connector_set = NULL, *connector;
     533                 :          0 :         struct drm_framebuffer *fb = NULL;
     534                 :          0 :         struct drm_display_mode *mode = NULL;
     535                 :          0 :         struct drm_mode_set set;
     536                 :          0 :         uint32_t __user *set_connectors_ptr;
     537                 :          0 :         struct drm_modeset_acquire_ctx ctx;
     538                 :          0 :         int ret;
     539                 :          0 :         int i;
     540                 :            : 
     541         [ #  # ]:          0 :         if (!drm_core_check_feature(dev, DRIVER_MODESET))
     542                 :            :                 return -EOPNOTSUPP;
     543                 :            : 
     544                 :            :         /*
     545                 :            :          * Universal plane src offsets are only 16.16, prevent havoc for
     546                 :            :          * drivers using universal plane code internally.
     547                 :            :          */
     548   [ #  #  #  # ]:          0 :         if (crtc_req->x & 0xffff0000 || crtc_req->y & 0xffff0000)
     549                 :            :                 return -ERANGE;
     550                 :            : 
     551                 :          0 :         crtc = drm_crtc_find(dev, file_priv, crtc_req->crtc_id);
     552         [ #  # ]:          0 :         if (!crtc) {
     553                 :          0 :                 DRM_DEBUG_KMS("Unknown CRTC ID %d\n", crtc_req->crtc_id);
     554                 :          0 :                 return -ENOENT;
     555                 :            :         }
     556                 :          0 :         DRM_DEBUG_KMS("[CRTC:%d:%s]\n", crtc->base.id, crtc->name);
     557                 :            : 
     558                 :          0 :         plane = crtc->primary;
     559                 :            : 
     560                 :            :         /* allow disabling with the primary plane leased */
     561   [ #  #  #  # ]:          0 :         if (crtc_req->mode_valid && !drm_lease_held(file_priv, plane->base.id))
     562                 :            :                 return -EACCES;
     563                 :            : 
     564                 :          0 :         mutex_lock(&crtc->dev->mode_config.mutex);
     565         [ #  # ]:          0 :         DRM_MODESET_LOCK_ALL_BEGIN(dev, ctx,
     566                 :          0 :                                    DRM_MODESET_ACQUIRE_INTERRUPTIBLE, ret);
     567                 :            : 
     568         [ #  # ]:          0 :         if (crtc_req->mode_valid) {
     569                 :            :                 /* If we have a mode we need a framebuffer. */
     570                 :            :                 /* If we pass -1, set the mode with the currently bound fb */
     571         [ #  # ]:          0 :                 if (crtc_req->fb_id == -1) {
     572                 :          0 :                         struct drm_framebuffer *old_fb;
     573                 :            : 
     574         [ #  # ]:          0 :                         if (plane->state)
     575                 :          0 :                                 old_fb = plane->state->fb;
     576                 :            :                         else
     577                 :          0 :                                 old_fb = plane->fb;
     578                 :            : 
     579         [ #  # ]:          0 :                         if (!old_fb) {
     580                 :          0 :                                 DRM_DEBUG_KMS("CRTC doesn't have current FB\n");
     581                 :          0 :                                 ret = -EINVAL;
     582                 :          0 :                                 goto out;
     583                 :            :                         }
     584                 :            : 
     585                 :          0 :                         fb = old_fb;
     586                 :            :                         /* Make refcounting symmetric with the lookup path. */
     587                 :          0 :                         drm_framebuffer_get(fb);
     588                 :            :                 } else {
     589                 :          0 :                         fb = drm_framebuffer_lookup(dev, file_priv, crtc_req->fb_id);
     590         [ #  # ]:          0 :                         if (!fb) {
     591                 :          0 :                                 DRM_DEBUG_KMS("Unknown FB ID%d\n",
     592                 :            :                                                 crtc_req->fb_id);
     593                 :          0 :                                 ret = -ENOENT;
     594                 :          0 :                                 goto out;
     595                 :            :                         }
     596                 :            :                 }
     597                 :            : 
     598                 :          0 :                 mode = drm_mode_create(dev);
     599         [ #  # ]:          0 :                 if (!mode) {
     600                 :          0 :                         ret = -ENOMEM;
     601                 :          0 :                         goto out;
     602                 :            :                 }
     603         [ #  # ]:          0 :                 if (!file_priv->aspect_ratio_allowed &&
     604         [ #  # ]:          0 :                     (crtc_req->mode.flags & DRM_MODE_FLAG_PIC_AR_MASK) != DRM_MODE_FLAG_PIC_AR_NONE) {
     605                 :          0 :                         DRM_DEBUG_KMS("Unexpected aspect-ratio flag bits\n");
     606                 :          0 :                         ret = -EINVAL;
     607                 :          0 :                         goto out;
     608                 :            :                 }
     609                 :            : 
     610                 :            : 
     611                 :          0 :                 ret = drm_mode_convert_umode(dev, mode, &crtc_req->mode);
     612         [ #  # ]:          0 :                 if (ret) {
     613                 :          0 :                         DRM_DEBUG_KMS("Invalid mode (ret=%d, status=%s)\n",
     614                 :            :                                       ret, drm_get_mode_status_name(mode->status));
     615                 :          0 :                         drm_mode_debug_printmodeline(mode);
     616                 :          0 :                         goto out;
     617                 :            :                 }
     618                 :            : 
     619                 :            :                 /*
     620                 :            :                  * Check whether the primary plane supports the fb pixel format.
     621                 :            :                  * Drivers not implementing the universal planes API use a
     622                 :            :                  * default formats list provided by the DRM core which doesn't
     623                 :            :                  * match real hardware capabilities. Skip the check in that
     624                 :            :                  * case.
     625                 :            :                  */
     626         [ #  # ]:          0 :                 if (!plane->format_default) {
     627                 :          0 :                         ret = drm_plane_check_pixel_format(plane,
     628                 :          0 :                                                            fb->format->format,
     629                 :            :                                                            fb->modifier);
     630         [ #  # ]:          0 :                         if (ret) {
     631                 :          0 :                                 struct drm_format_name_buf format_name;
     632                 :          0 :                                 DRM_DEBUG_KMS("Invalid pixel format %s, modifier 0x%llx\n",
     633                 :            :                                               drm_get_format_name(fb->format->format,
     634                 :            :                                                                   &format_name),
     635                 :            :                                               fb->modifier);
     636                 :          0 :                                 goto out;
     637                 :            :                         }
     638                 :            :                 }
     639                 :            : 
     640                 :          0 :                 ret = drm_crtc_check_viewport(crtc, crtc_req->x, crtc_req->y,
     641                 :            :                                               mode, fb);
     642         [ #  # ]:          0 :                 if (ret)
     643                 :          0 :                         goto out;
     644                 :            : 
     645                 :            :         }
     646                 :            : 
     647   [ #  #  #  # ]:          0 :         if (crtc_req->count_connectors == 0 && mode) {
     648                 :          0 :                 DRM_DEBUG_KMS("Count connectors is 0 but mode set\n");
     649                 :          0 :                 ret = -EINVAL;
     650                 :          0 :                 goto out;
     651                 :            :         }
     652                 :            : 
     653   [ #  #  #  # ]:          0 :         if (crtc_req->count_connectors > 0 && (!mode || !fb)) {
     654                 :          0 :                 DRM_DEBUG_KMS("Count connectors is %d but no mode or fb set\n",
     655                 :            :                           crtc_req->count_connectors);
     656                 :          0 :                 ret = -EINVAL;
     657                 :          0 :                 goto out;
     658                 :            :         }
     659                 :            : 
     660         [ #  # ]:          0 :         if (crtc_req->count_connectors > 0) {
     661                 :          0 :                 u32 out_id;
     662                 :            : 
     663                 :            :                 /* Avoid unbounded kernel memory allocation */
     664         [ #  # ]:          0 :                 if (crtc_req->count_connectors > config->num_connector) {
     665                 :          0 :                         ret = -EINVAL;
     666                 :          0 :                         goto out;
     667                 :            :                 }
     668                 :            : 
     669                 :          0 :                 connector_set = kmalloc_array(crtc_req->count_connectors,
     670                 :            :                                               sizeof(struct drm_connector *),
     671                 :            :                                               GFP_KERNEL);
     672         [ #  # ]:          0 :                 if (!connector_set) {
     673                 :          0 :                         ret = -ENOMEM;
     674                 :          0 :                         goto out;
     675                 :            :                 }
     676                 :            : 
     677         [ #  # ]:          0 :                 for (i = 0; i < crtc_req->count_connectors; i++) {
     678                 :          0 :                         connector_set[i] = NULL;
     679                 :          0 :                         set_connectors_ptr = (uint32_t __user *)(unsigned long)crtc_req->set_connectors_ptr;
     680         [ #  # ]:          0 :                         if (get_user(out_id, &set_connectors_ptr[i])) {
     681                 :          0 :                                 ret = -EFAULT;
     682                 :          0 :                                 goto out;
     683                 :            :                         }
     684                 :            : 
     685                 :          0 :                         connector = drm_connector_lookup(dev, file_priv, out_id);
     686         [ #  # ]:          0 :                         if (!connector) {
     687                 :          0 :                                 DRM_DEBUG_KMS("Connector id %d unknown\n",
     688                 :            :                                                 out_id);
     689                 :          0 :                                 ret = -ENOENT;
     690                 :          0 :                                 goto out;
     691                 :            :                         }
     692                 :          0 :                         DRM_DEBUG_KMS("[CONNECTOR:%d:%s]\n",
     693                 :            :                                         connector->base.id,
     694                 :            :                                         connector->name);
     695                 :            : 
     696                 :          0 :                         connector_set[i] = connector;
     697                 :            :                 }
     698                 :            :         }
     699                 :            : 
     700                 :          0 :         set.crtc = crtc;
     701                 :          0 :         set.x = crtc_req->x;
     702                 :          0 :         set.y = crtc_req->y;
     703                 :          0 :         set.mode = mode;
     704                 :          0 :         set.connectors = connector_set;
     705                 :          0 :         set.num_connectors = crtc_req->count_connectors;
     706                 :          0 :         set.fb = fb;
     707                 :            : 
     708   [ #  #  #  # ]:          0 :         if (drm_drv_uses_atomic_modeset(dev))
     709                 :          0 :                 ret = crtc->funcs->set_config(&set, &ctx);
     710                 :            :         else
     711                 :          0 :                 ret = __drm_mode_set_config_internal(&set, &ctx);
     712                 :            : 
     713                 :          0 : out:
     714         [ #  # ]:          0 :         if (fb)
     715                 :          0 :                 drm_framebuffer_put(fb);
     716                 :            : 
     717         [ #  # ]:          0 :         if (connector_set) {
     718         [ #  # ]:          0 :                 for (i = 0; i < crtc_req->count_connectors; i++) {
     719         [ #  # ]:          0 :                         if (connector_set[i])
     720                 :          0 :                                 drm_connector_put(connector_set[i]);
     721                 :            :                 }
     722                 :            :         }
     723                 :          0 :         kfree(connector_set);
     724                 :          0 :         drm_mode_destroy(dev, mode);
     725                 :            : 
     726                 :            :         /* In case we need to retry... */
     727                 :          0 :         connector_set = NULL;
     728                 :          0 :         fb = NULL;
     729                 :          0 :         mode = NULL;
     730                 :            : 
     731   [ #  #  #  # ]:          0 :         DRM_MODESET_LOCK_ALL_END(ctx, ret);
     732                 :          0 :         mutex_unlock(&crtc->dev->mode_config.mutex);
     733                 :            : 
     734                 :          0 :         return ret;
     735                 :            : }
     736                 :            : 
     737                 :          0 : int drm_mode_crtc_set_obj_prop(struct drm_mode_object *obj,
     738                 :            :                                struct drm_property *property,
     739                 :            :                                uint64_t value)
     740                 :            : {
     741                 :          0 :         int ret = -EINVAL;
     742                 :          0 :         struct drm_crtc *crtc = obj_to_crtc(obj);
     743                 :            : 
     744         [ #  # ]:          0 :         if (crtc->funcs->set_property)
     745                 :          0 :                 ret = crtc->funcs->set_property(crtc, property, value);
     746         [ #  # ]:          0 :         if (!ret)
     747                 :          0 :                 drm_object_property_set_value(obj, property, value);
     748                 :            : 
     749                 :          0 :         return ret;
     750                 :            : }

Generated by: LCOV version 1.14