1f453ba04SDave Airlie /* 2f453ba04SDave Airlie * Copyright (c) 2006-2008 Intel Corporation 3f453ba04SDave Airlie * Copyright (c) 2007 Dave Airlie <airlied@linux.ie> 4f453ba04SDave Airlie * Copyright (c) 2008 Red Hat Inc. 5f453ba04SDave Airlie * 6f453ba04SDave Airlie * DRM core CRTC related functions 7f453ba04SDave Airlie * 8f453ba04SDave Airlie * Permission to use, copy, modify, distribute, and sell this software and its 9f453ba04SDave Airlie * documentation for any purpose is hereby granted without fee, provided that 10f453ba04SDave Airlie * the above copyright notice appear in all copies and that both that copyright 11f453ba04SDave Airlie * notice and this permission notice appear in supporting documentation, and 12f453ba04SDave Airlie * that the name of the copyright holders not be used in advertising or 13f453ba04SDave Airlie * publicity pertaining to distribution of the software without specific, 14f453ba04SDave Airlie * written prior permission. The copyright holders make no representations 15f453ba04SDave Airlie * about the suitability of this software for any purpose. It is provided "as 16f453ba04SDave Airlie * is" without express or implied warranty. 17f453ba04SDave Airlie * 18f453ba04SDave Airlie * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, 19f453ba04SDave Airlie * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO 20f453ba04SDave Airlie * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR 21f453ba04SDave Airlie * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, 22f453ba04SDave Airlie * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER 23f453ba04SDave Airlie * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE 24f453ba04SDave Airlie * OF THIS SOFTWARE. 25f453ba04SDave Airlie * 26f453ba04SDave Airlie * Authors: 27f453ba04SDave Airlie * Keith Packard 28f453ba04SDave Airlie * Eric Anholt <eric@anholt.net> 29f453ba04SDave Airlie * Dave Airlie <airlied@linux.ie> 30f453ba04SDave Airlie * Jesse Barnes <jesse.barnes@intel.com> 31f453ba04SDave Airlie */ 326ba6d03eSVille Syrjälä #include <linux/ctype.h> 33f453ba04SDave Airlie #include <linux/list.h> 345a0e3ad6STejun Heo #include <linux/slab.h> 352d1a8a48SPaul Gortmaker #include <linux/export.h> 366d6003c4SGustavo Padovan #include <linux/dma-fence.h> 37e6120d64SDaniel Vetter #include <linux/uaccess.h> 38760285e7SDavid Howells #include <drm/drm_crtc.h> 39760285e7SDavid Howells #include <drm/drm_edid.h> 40760285e7SDavid Howells #include <drm/drm_fourcc.h> 41*9dbb70fdSPhilipp Zabel #include <drm/drm_managed.h> 4251fd371bSRob Clark #include <drm/drm_modeset_lock.h> 4388a48e29SRob Clark #include <drm/drm_atomic.h> 443b96a0b1SDaniel Vetter #include <drm/drm_auth.h> 459edbf1faSTomeu Vizoso #include <drm/drm_debugfs_crc.h> 46e6120d64SDaniel Vetter #include <drm/drm_drv.h> 47e6120d64SDaniel Vetter #include <drm/drm_print.h> 48e6120d64SDaniel Vetter #include <drm/drm_file.h> 49f453ba04SDave Airlie 508bd441b2SDaniel Vetter #include "drm_crtc_internal.h" 5167d0ec4eSDaniel Vetter #include "drm_internal.h" 528bd441b2SDaniel Vetter 536a0d9528SLukas Wunner /** 54d5d487ebSDaniel Vetter * DOC: overview 55d5d487ebSDaniel Vetter * 56d5d487ebSDaniel Vetter * A CRTC represents the overall display pipeline. It receives pixel data from 57d5d487ebSDaniel Vetter * &drm_plane and blends them together. The &drm_display_mode is also attached 58d5d487ebSDaniel Vetter * to the CRTC, specifying display timings. On the output side the data is fed 59d5d487ebSDaniel Vetter * to one or more &drm_encoder, which are then each connected to one 60d5d487ebSDaniel Vetter * &drm_connector. 61d5d487ebSDaniel Vetter * 62d5d487ebSDaniel Vetter * To create a CRTC, a KMS drivers allocates and zeroes an instances of 63d5d487ebSDaniel Vetter * &struct drm_crtc (possibly as part of a larger structure) and registers it 64d5d487ebSDaniel Vetter * with a call to drm_crtc_init_with_planes(). 65d5d487ebSDaniel Vetter * 66d5d487ebSDaniel Vetter * The CRTC is also the entry point for legacy modeset operations, see 67d5d487ebSDaniel Vetter * &drm_crtc_funcs.set_config, legacy plane operations, see 68d5d487ebSDaniel Vetter * &drm_crtc_funcs.page_flip and &drm_crtc_funcs.cursor_set2, and other legacy 69d5d487ebSDaniel Vetter * operations like &drm_crtc_funcs.gamma_set. For atomic drivers all these 70d5d487ebSDaniel Vetter * features are controlled through &drm_property and 71a3d0d834SSimon Ser * &drm_mode_config_funcs.atomic_check. 72d5d487ebSDaniel Vetter */ 73d5d487ebSDaniel Vetter 74d5d487ebSDaniel Vetter /** 756d1b81d8SShawn Guo * drm_crtc_from_index - find the registered CRTC at an index 766d1b81d8SShawn Guo * @dev: DRM device 776d1b81d8SShawn Guo * @idx: index of registered CRTC to find for 786d1b81d8SShawn Guo * 796d1b81d8SShawn Guo * Given a CRTC index, return the registered CRTC from DRM device's 80931c670dSShawn Guo * list of CRTCs with matching index. This is the inverse of drm_crtc_index(). 81931c670dSShawn Guo * It's useful in the vblank callbacks (like &drm_driver.enable_vblank or 82931c670dSShawn Guo * &drm_driver.disable_vblank), since that still deals with indices instead 83931c670dSShawn Guo * of pointers to &struct drm_crtc." 846d1b81d8SShawn Guo */ 856d1b81d8SShawn Guo struct drm_crtc *drm_crtc_from_index(struct drm_device *dev, int idx) 866d1b81d8SShawn Guo { 876d1b81d8SShawn Guo struct drm_crtc *crtc; 886d1b81d8SShawn Guo 896d1b81d8SShawn Guo drm_for_each_crtc(crtc, dev) 906d1b81d8SShawn Guo if (idx == crtc->index) 916d1b81d8SShawn Guo return crtc; 926d1b81d8SShawn Guo 936d1b81d8SShawn Guo return NULL; 946d1b81d8SShawn Guo } 956d1b81d8SShawn Guo EXPORT_SYMBOL(drm_crtc_from_index); 966d1b81d8SShawn Guo 976a0d9528SLukas Wunner int drm_crtc_force_disable(struct drm_crtc *crtc) 986a0d9528SLukas Wunner { 996a0d9528SLukas Wunner struct drm_mode_set set = { 1006a0d9528SLukas Wunner .crtc = crtc, 1016a0d9528SLukas Wunner }; 1026a0d9528SLukas Wunner 10318dddadcSDaniel Vetter WARN_ON(drm_drv_uses_atomic_modeset(crtc->dev)); 10418dddadcSDaniel Vetter 1056a0d9528SLukas Wunner return drm_mode_set_config_internal(&set); 1066a0d9528SLukas Wunner } 1076a0d9528SLukas Wunner 108fa3ab4c2SVille Syrjälä static unsigned int drm_num_crtcs(struct drm_device *dev) 109fa3ab4c2SVille Syrjälä { 110fa3ab4c2SVille Syrjälä unsigned int num = 0; 111fa3ab4c2SVille Syrjälä struct drm_crtc *tmp; 112fa3ab4c2SVille Syrjälä 113fa3ab4c2SVille Syrjälä drm_for_each_crtc(tmp, dev) { 114fa3ab4c2SVille Syrjälä num++; 115fa3ab4c2SVille Syrjälä } 116fa3ab4c2SVille Syrjälä 117fa3ab4c2SVille Syrjälä return num; 118fa3ab4c2SVille Syrjälä } 119fa3ab4c2SVille Syrjälä 12028575f16SDaniel Vetter int drm_crtc_register_all(struct drm_device *dev) 12179190ea2SBenjamin Gaignard { 12279190ea2SBenjamin Gaignard struct drm_crtc *crtc; 12379190ea2SBenjamin Gaignard int ret = 0; 12479190ea2SBenjamin Gaignard 12579190ea2SBenjamin Gaignard drm_for_each_crtc(crtc, dev) { 126b792e640SGreg Kroah-Hartman drm_debugfs_crtc_add(crtc); 1279edbf1faSTomeu Vizoso 12879190ea2SBenjamin Gaignard if (crtc->funcs->late_register) 12979190ea2SBenjamin Gaignard ret = crtc->funcs->late_register(crtc); 13079190ea2SBenjamin Gaignard if (ret) 13179190ea2SBenjamin Gaignard return ret; 13279190ea2SBenjamin Gaignard } 13379190ea2SBenjamin Gaignard 13479190ea2SBenjamin Gaignard return 0; 13579190ea2SBenjamin Gaignard } 13679190ea2SBenjamin Gaignard 13728575f16SDaniel Vetter void drm_crtc_unregister_all(struct drm_device *dev) 13879190ea2SBenjamin Gaignard { 13979190ea2SBenjamin Gaignard struct drm_crtc *crtc; 14079190ea2SBenjamin Gaignard 14179190ea2SBenjamin Gaignard drm_for_each_crtc(crtc, dev) { 14279190ea2SBenjamin Gaignard if (crtc->funcs->early_unregister) 14379190ea2SBenjamin Gaignard crtc->funcs->early_unregister(crtc); 1449edbf1faSTomeu Vizoso drm_debugfs_crtc_remove(crtc); 14579190ea2SBenjamin Gaignard } 14679190ea2SBenjamin Gaignard } 14779190ea2SBenjamin Gaignard 1489edbf1faSTomeu Vizoso static int drm_crtc_crc_init(struct drm_crtc *crtc) 1499edbf1faSTomeu Vizoso { 1509edbf1faSTomeu Vizoso #ifdef CONFIG_DEBUG_FS 1519edbf1faSTomeu Vizoso spin_lock_init(&crtc->crc.lock); 1529edbf1faSTomeu Vizoso init_waitqueue_head(&crtc->crc.wq); 1539edbf1faSTomeu Vizoso crtc->crc.source = kstrdup("auto", GFP_KERNEL); 1549edbf1faSTomeu Vizoso if (!crtc->crc.source) 1559edbf1faSTomeu Vizoso return -ENOMEM; 1569edbf1faSTomeu Vizoso #endif 1579edbf1faSTomeu Vizoso return 0; 1589edbf1faSTomeu Vizoso } 1599edbf1faSTomeu Vizoso 1609edbf1faSTomeu Vizoso static void drm_crtc_crc_fini(struct drm_crtc *crtc) 1619edbf1faSTomeu Vizoso { 1629edbf1faSTomeu Vizoso #ifdef CONFIG_DEBUG_FS 1639edbf1faSTomeu Vizoso kfree(crtc->crc.source); 1649edbf1faSTomeu Vizoso #endif 1659edbf1faSTomeu Vizoso } 1669edbf1faSTomeu Vizoso 16735f8cc3bSGustavo Padovan static const struct dma_fence_ops drm_crtc_fence_ops; 16835f8cc3bSGustavo Padovan 1696d6003c4SGustavo Padovan static struct drm_crtc *fence_to_crtc(struct dma_fence *fence) 1706d6003c4SGustavo Padovan { 1716d6003c4SGustavo Padovan BUG_ON(fence->ops != &drm_crtc_fence_ops); 1726d6003c4SGustavo Padovan return container_of(fence->lock, struct drm_crtc, fence_lock); 1736d6003c4SGustavo Padovan } 1746d6003c4SGustavo Padovan 1756d6003c4SGustavo Padovan static const char *drm_crtc_fence_get_driver_name(struct dma_fence *fence) 1766d6003c4SGustavo Padovan { 1776d6003c4SGustavo Padovan struct drm_crtc *crtc = fence_to_crtc(fence); 1786d6003c4SGustavo Padovan 1796d6003c4SGustavo Padovan return crtc->dev->driver->name; 1806d6003c4SGustavo Padovan } 1816d6003c4SGustavo Padovan 1826d6003c4SGustavo Padovan static const char *drm_crtc_fence_get_timeline_name(struct dma_fence *fence) 1836d6003c4SGustavo Padovan { 1846d6003c4SGustavo Padovan struct drm_crtc *crtc = fence_to_crtc(fence); 1856d6003c4SGustavo Padovan 1866d6003c4SGustavo Padovan return crtc->timeline_name; 1876d6003c4SGustavo Padovan } 1886d6003c4SGustavo Padovan 18935f8cc3bSGustavo Padovan static const struct dma_fence_ops drm_crtc_fence_ops = { 1906d6003c4SGustavo Padovan .get_driver_name = drm_crtc_fence_get_driver_name, 1916d6003c4SGustavo Padovan .get_timeline_name = drm_crtc_fence_get_timeline_name, 1926d6003c4SGustavo Padovan }; 1936d6003c4SGustavo Padovan 19435f8cc3bSGustavo Padovan struct dma_fence *drm_crtc_create_fence(struct drm_crtc *crtc) 19535f8cc3bSGustavo Padovan { 19635f8cc3bSGustavo Padovan struct dma_fence *fence; 19735f8cc3bSGustavo Padovan 19835f8cc3bSGustavo Padovan fence = kzalloc(sizeof(*fence), GFP_KERNEL); 19935f8cc3bSGustavo Padovan if (!fence) 20035f8cc3bSGustavo Padovan return NULL; 20135f8cc3bSGustavo Padovan 20235f8cc3bSGustavo Padovan dma_fence_init(fence, &drm_crtc_fence_ops, &crtc->fence_lock, 20335f8cc3bSGustavo Padovan crtc->fence_context, ++crtc->fence_seqno); 20435f8cc3bSGustavo Padovan 20535f8cc3bSGustavo Padovan return fence; 20635f8cc3bSGustavo Padovan } 20735f8cc3bSGustavo Padovan 208f453ba04SDave Airlie /** 209e954f77fSSimon Ser * DOC: standard CRTC properties 210e954f77fSSimon Ser * 211e954f77fSSimon Ser * DRM CRTCs have a few standardized properties: 212e954f77fSSimon Ser * 213e954f77fSSimon Ser * ACTIVE: 214e954f77fSSimon Ser * Atomic property for setting the power state of the CRTC. When set to 1 215e954f77fSSimon Ser * the CRTC will actively display content. When set to 0 the CRTC will be 216e954f77fSSimon Ser * powered off. There is no expectation that user-space will reset CRTC 217e954f77fSSimon Ser * resources like the mode and planes when setting ACTIVE to 0. 218e954f77fSSimon Ser * 219e954f77fSSimon Ser * User-space can rely on an ACTIVE change to 1 to never fail an atomic 220e954f77fSSimon Ser * test as long as no other property has changed. If a change to ACTIVE 221e954f77fSSimon Ser * fails an atomic test, this is a driver bug. For this reason setting 222e954f77fSSimon Ser * ACTIVE to 0 must not release internal resources (like reserved memory 223e954f77fSSimon Ser * bandwidth or clock generators). 224e954f77fSSimon Ser * 225e954f77fSSimon Ser * Note that the legacy DPMS property on connectors is internally routed 226e954f77fSSimon Ser * to control this property for atomic drivers. 227e954f77fSSimon Ser * MODE_ID: 228e954f77fSSimon Ser * Atomic property for setting the CRTC display timings. The value is the 229e954f77fSSimon Ser * ID of a blob containing the DRM mode info. To disable the CRTC, 230e954f77fSSimon Ser * user-space must set this property to 0. 231e954f77fSSimon Ser * 232e954f77fSSimon Ser * Setting MODE_ID to 0 will release reserved resources for the CRTC. 2335c759edaSPankaj Bharadiya * SCALING_FILTER: 2345c759edaSPankaj Bharadiya * Atomic property for setting the scaling filter for CRTC scaler 2355c759edaSPankaj Bharadiya * 2365c759edaSPankaj Bharadiya * The value of this property can be one of the following: 2371187ffc4SSimon Ser * 2385c759edaSPankaj Bharadiya * Default: 2395c759edaSPankaj Bharadiya * Driver's default scaling filter 2405c759edaSPankaj Bharadiya * Nearest Neighbor: 2415c759edaSPankaj Bharadiya * Nearest Neighbor scaling filter 242e954f77fSSimon Ser */ 243e954f77fSSimon Ser 244*9dbb70fdSPhilipp Zabel __printf(6, 0) 245*9dbb70fdSPhilipp Zabel static int __drm_crtc_init_with_planes(struct drm_device *dev, struct drm_crtc *crtc, 246e13161afSMatt Roper struct drm_plane *primary, 247fc1d3e44SMatt Roper struct drm_plane *cursor, 248f9882876SVille Syrjälä const struct drm_crtc_funcs *funcs, 249*9dbb70fdSPhilipp Zabel const char *name, va_list ap) 250f453ba04SDave Airlie { 25151fd371bSRob Clark struct drm_mode_config *config = &dev->mode_config; 2526bfc56aaSVille Syrjälä int ret; 2536bfc56aaSVille Syrjälä 254522cf91fSBenjamin Gaignard WARN_ON(primary && primary->type != DRM_PLANE_TYPE_PRIMARY); 255522cf91fSBenjamin Gaignard WARN_ON(cursor && cursor->type != DRM_PLANE_TYPE_CURSOR); 256522cf91fSBenjamin Gaignard 2572a8d3eacSVille Syrjälä /* crtc index is used with 32bit bitmasks */ 2582a8d3eacSVille Syrjälä if (WARN_ON(config->num_crtc >= 32)) 2592a8d3eacSVille Syrjälä return -EINVAL; 2602a8d3eacSVille Syrjälä 261ba1f665fSHaneen Mohammed WARN_ON(drm_drv_uses_atomic_modeset(dev) && 262ba1f665fSHaneen Mohammed (!funcs->atomic_destroy_state || 263ba1f665fSHaneen Mohammed !funcs->atomic_duplicate_state)); 264ba1f665fSHaneen Mohammed 265f453ba04SDave Airlie crtc->dev = dev; 266f453ba04SDave Airlie crtc->funcs = funcs; 267f453ba04SDave Airlie 2683b24f7d6SDaniel Vetter INIT_LIST_HEAD(&crtc->commit_list); 2693b24f7d6SDaniel Vetter spin_lock_init(&crtc->commit_lock); 2703b24f7d6SDaniel Vetter 27151fd371bSRob Clark drm_modeset_lock_init(&crtc->mutex); 2722135ea7aSThierry Reding ret = drm_mode_object_add(dev, &crtc->base, DRM_MODE_OBJECT_CRTC); 2736bfc56aaSVille Syrjälä if (ret) 274baf698b0SDaniel Vetter return ret; 275f453ba04SDave Airlie 276fa3ab4c2SVille Syrjälä if (name) { 277fa3ab4c2SVille Syrjälä crtc->name = kvasprintf(GFP_KERNEL, name, ap); 278fa3ab4c2SVille Syrjälä } else { 279fa3ab4c2SVille Syrjälä crtc->name = kasprintf(GFP_KERNEL, "crtc-%d", 280fa3ab4c2SVille Syrjälä drm_num_crtcs(dev)); 281fa3ab4c2SVille Syrjälä } 282fa3ab4c2SVille Syrjälä if (!crtc->name) { 2837c8f6d25SDave Airlie drm_mode_object_unregister(dev, &crtc->base); 284fa3ab4c2SVille Syrjälä return -ENOMEM; 285fa3ab4c2SVille Syrjälä } 286fa3ab4c2SVille Syrjälä 2876d6003c4SGustavo Padovan crtc->fence_context = dma_fence_context_alloc(1); 2886d6003c4SGustavo Padovan spin_lock_init(&crtc->fence_lock); 2896d6003c4SGustavo Padovan snprintf(crtc->timeline_name, sizeof(crtc->timeline_name), 2906d6003c4SGustavo Padovan "CRTC:%d-%s", crtc->base.id, crtc->name); 2916d6003c4SGustavo Padovan 292bffd9de0SPaulo Zanoni crtc->base.properties = &crtc->properties; 293bffd9de0SPaulo Zanoni 29451fd371bSRob Clark list_add_tail(&crtc->head, &config->crtc_list); 295490d3d1bSChris Wilson crtc->index = config->num_crtc++; 2966bfc56aaSVille Syrjälä 297e13161afSMatt Roper crtc->primary = primary; 298fc1d3e44SMatt Roper crtc->cursor = cursor; 2997abc7d47SRob Clark if (primary && !primary->possible_crtcs) 3006a52193bSVille Syrjälä primary->possible_crtcs = drm_crtc_mask(crtc); 3017abc7d47SRob Clark if (cursor && !cursor->possible_crtcs) 3026a52193bSVille Syrjälä cursor->possible_crtcs = drm_crtc_mask(crtc); 303e13161afSMatt Roper 3049edbf1faSTomeu Vizoso ret = drm_crtc_crc_init(crtc); 3059edbf1faSTomeu Vizoso if (ret) { 3069edbf1faSTomeu Vizoso drm_mode_object_unregister(dev, &crtc->base); 3079edbf1faSTomeu Vizoso return ret; 3089edbf1faSTomeu Vizoso } 3099edbf1faSTomeu Vizoso 310eab3bbefSDaniel Vetter if (drm_core_check_feature(dev, DRIVER_ATOMIC)) { 311eab3bbefSDaniel Vetter drm_object_attach_property(&crtc->base, config->prop_active, 0); 312955f3c33SDaniel Stone drm_object_attach_property(&crtc->base, config->prop_mode_id, 0); 313beaf5af4SGustavo Padovan drm_object_attach_property(&crtc->base, 314beaf5af4SGustavo Padovan config->prop_out_fence_ptr, 0); 3151398958cSNicholas Kazlauskas drm_object_attach_property(&crtc->base, 3161398958cSNicholas Kazlauskas config->prop_vrr_enabled, 0); 317eab3bbefSDaniel Vetter } 318eab3bbefSDaniel Vetter 319baf698b0SDaniel Vetter return 0; 320f453ba04SDave Airlie } 321*9dbb70fdSPhilipp Zabel 322*9dbb70fdSPhilipp Zabel /** 323*9dbb70fdSPhilipp Zabel * drm_crtc_init_with_planes - Initialise a new CRTC object with 324*9dbb70fdSPhilipp Zabel * specified primary and cursor planes. 325*9dbb70fdSPhilipp Zabel * @dev: DRM device 326*9dbb70fdSPhilipp Zabel * @crtc: CRTC object to init 327*9dbb70fdSPhilipp Zabel * @primary: Primary plane for CRTC 328*9dbb70fdSPhilipp Zabel * @cursor: Cursor plane for CRTC 329*9dbb70fdSPhilipp Zabel * @funcs: callbacks for the new CRTC 330*9dbb70fdSPhilipp Zabel * @name: printf style format string for the CRTC name, or NULL for default name 331*9dbb70fdSPhilipp Zabel * 332*9dbb70fdSPhilipp Zabel * Inits a new object created as base part of a driver crtc object. Drivers 333*9dbb70fdSPhilipp Zabel * should use this function instead of drm_crtc_init(), which is only provided 334*9dbb70fdSPhilipp Zabel * for backwards compatibility with drivers which do not yet support universal 335*9dbb70fdSPhilipp Zabel * planes). For really simple hardware which has only 1 plane look at 336*9dbb70fdSPhilipp Zabel * drm_simple_display_pipe_init() instead. 337*9dbb70fdSPhilipp Zabel * The &drm_crtc_funcs.destroy hook should call drm_crtc_cleanup() and kfree() 338*9dbb70fdSPhilipp Zabel * the crtc structure. The crtc structure should not be allocated with 339*9dbb70fdSPhilipp Zabel * devm_kzalloc(). 340*9dbb70fdSPhilipp Zabel * 341e240cc76SDaniel Vetter * The @primary and @cursor planes are only relevant for legacy uAPI, see 342e240cc76SDaniel Vetter * &drm_crtc.primary and &drm_crtc.cursor. 343e240cc76SDaniel Vetter * 344*9dbb70fdSPhilipp Zabel * Note: consider using drmm_crtc_alloc_with_planes() instead of 345*9dbb70fdSPhilipp Zabel * drm_crtc_init_with_planes() to let the DRM managed resource infrastructure 346*9dbb70fdSPhilipp Zabel * take care of cleanup and deallocation. 347*9dbb70fdSPhilipp Zabel * 348*9dbb70fdSPhilipp Zabel * Returns: 349*9dbb70fdSPhilipp Zabel * Zero on success, error code on failure. 350*9dbb70fdSPhilipp Zabel */ 351*9dbb70fdSPhilipp Zabel int drm_crtc_init_with_planes(struct drm_device *dev, struct drm_crtc *crtc, 352*9dbb70fdSPhilipp Zabel struct drm_plane *primary, 353*9dbb70fdSPhilipp Zabel struct drm_plane *cursor, 354*9dbb70fdSPhilipp Zabel const struct drm_crtc_funcs *funcs, 355*9dbb70fdSPhilipp Zabel const char *name, ...) 356*9dbb70fdSPhilipp Zabel { 357*9dbb70fdSPhilipp Zabel va_list ap; 358*9dbb70fdSPhilipp Zabel int ret; 359*9dbb70fdSPhilipp Zabel 360*9dbb70fdSPhilipp Zabel WARN_ON(!funcs->destroy); 361*9dbb70fdSPhilipp Zabel 362*9dbb70fdSPhilipp Zabel va_start(ap, name); 363*9dbb70fdSPhilipp Zabel ret = __drm_crtc_init_with_planes(dev, crtc, primary, cursor, funcs, 364*9dbb70fdSPhilipp Zabel name, ap); 365*9dbb70fdSPhilipp Zabel va_end(ap); 366*9dbb70fdSPhilipp Zabel 367*9dbb70fdSPhilipp Zabel return ret; 368*9dbb70fdSPhilipp Zabel } 369e13161afSMatt Roper EXPORT_SYMBOL(drm_crtc_init_with_planes); 370f453ba04SDave Airlie 371*9dbb70fdSPhilipp Zabel static void drmm_crtc_alloc_with_planes_cleanup(struct drm_device *dev, 372*9dbb70fdSPhilipp Zabel void *ptr) 373*9dbb70fdSPhilipp Zabel { 374*9dbb70fdSPhilipp Zabel struct drm_crtc *crtc = ptr; 375*9dbb70fdSPhilipp Zabel 376*9dbb70fdSPhilipp Zabel drm_crtc_cleanup(crtc); 377*9dbb70fdSPhilipp Zabel } 378*9dbb70fdSPhilipp Zabel 379*9dbb70fdSPhilipp Zabel void *__drmm_crtc_alloc_with_planes(struct drm_device *dev, 380*9dbb70fdSPhilipp Zabel size_t size, size_t offset, 381*9dbb70fdSPhilipp Zabel struct drm_plane *primary, 382*9dbb70fdSPhilipp Zabel struct drm_plane *cursor, 383*9dbb70fdSPhilipp Zabel const struct drm_crtc_funcs *funcs, 384*9dbb70fdSPhilipp Zabel const char *name, ...) 385*9dbb70fdSPhilipp Zabel { 386*9dbb70fdSPhilipp Zabel void *container; 387*9dbb70fdSPhilipp Zabel struct drm_crtc *crtc; 388*9dbb70fdSPhilipp Zabel va_list ap; 389*9dbb70fdSPhilipp Zabel int ret; 390*9dbb70fdSPhilipp Zabel 391*9dbb70fdSPhilipp Zabel if (WARN_ON(!funcs || funcs->destroy)) 392*9dbb70fdSPhilipp Zabel return ERR_PTR(-EINVAL); 393*9dbb70fdSPhilipp Zabel 394*9dbb70fdSPhilipp Zabel container = drmm_kzalloc(dev, size, GFP_KERNEL); 395*9dbb70fdSPhilipp Zabel if (!container) 396*9dbb70fdSPhilipp Zabel return ERR_PTR(-ENOMEM); 397*9dbb70fdSPhilipp Zabel 398*9dbb70fdSPhilipp Zabel crtc = container + offset; 399*9dbb70fdSPhilipp Zabel 400*9dbb70fdSPhilipp Zabel va_start(ap, name); 401*9dbb70fdSPhilipp Zabel ret = __drm_crtc_init_with_planes(dev, crtc, primary, cursor, funcs, 402*9dbb70fdSPhilipp Zabel name, ap); 403*9dbb70fdSPhilipp Zabel va_end(ap); 404*9dbb70fdSPhilipp Zabel if (ret) 405*9dbb70fdSPhilipp Zabel return ERR_PTR(ret); 406*9dbb70fdSPhilipp Zabel 407*9dbb70fdSPhilipp Zabel ret = drmm_add_action_or_reset(dev, drmm_crtc_alloc_with_planes_cleanup, 408*9dbb70fdSPhilipp Zabel crtc); 409*9dbb70fdSPhilipp Zabel if (ret) 410*9dbb70fdSPhilipp Zabel return ERR_PTR(ret); 411*9dbb70fdSPhilipp Zabel 412*9dbb70fdSPhilipp Zabel return container; 413*9dbb70fdSPhilipp Zabel } 414*9dbb70fdSPhilipp Zabel EXPORT_SYMBOL(__drmm_crtc_alloc_with_planes); 415*9dbb70fdSPhilipp Zabel 416f453ba04SDave Airlie /** 417ad6f5c34SVille Syrjälä * drm_crtc_cleanup - Clean up the core crtc usage 418f453ba04SDave Airlie * @crtc: CRTC to cleanup 419f453ba04SDave Airlie * 420ad6f5c34SVille Syrjälä * This function cleans up @crtc and removes it from the DRM mode setting 421ad6f5c34SVille Syrjälä * core. Note that the function does *not* free the crtc structure itself, 422ad6f5c34SVille Syrjälä * this is the responsibility of the caller. 423f453ba04SDave Airlie */ 424f453ba04SDave Airlie void drm_crtc_cleanup(struct drm_crtc *crtc) 425f453ba04SDave Airlie { 426f453ba04SDave Airlie struct drm_device *dev = crtc->dev; 427f453ba04SDave Airlie 428490d3d1bSChris Wilson /* Note that the crtc_list is considered to be static; should we 429490d3d1bSChris Wilson * remove the drm_crtc at runtime we would have to decrement all 430490d3d1bSChris Wilson * the indices on the drm_crtc after us in the crtc_list. 431490d3d1bSChris Wilson */ 432490d3d1bSChris Wilson 4339edbf1faSTomeu Vizoso drm_crtc_crc_fini(crtc); 4349edbf1faSTomeu Vizoso 435f453ba04SDave Airlie kfree(crtc->gamma_store); 436f453ba04SDave Airlie crtc->gamma_store = NULL; 437f453ba04SDave Airlie 43851fd371bSRob Clark drm_modeset_lock_fini(&crtc->mutex); 43951fd371bSRob Clark 4407c8f6d25SDave Airlie drm_mode_object_unregister(dev, &crtc->base); 441f453ba04SDave Airlie list_del(&crtc->head); 442f453ba04SDave Airlie dev->mode_config.num_crtc--; 4433009c037SThierry Reding 4443009c037SThierry Reding WARN_ON(crtc->state && !crtc->funcs->atomic_destroy_state); 4453009c037SThierry Reding if (crtc->state && crtc->funcs->atomic_destroy_state) 4463009c037SThierry Reding crtc->funcs->atomic_destroy_state(crtc, crtc->state); 447a18c0af1SThierry Reding 448fa3ab4c2SVille Syrjälä kfree(crtc->name); 449fa3ab4c2SVille Syrjälä 450a18c0af1SThierry Reding memset(crtc, 0, sizeof(*crtc)); 451f453ba04SDave Airlie } 452f453ba04SDave Airlie EXPORT_SYMBOL(drm_crtc_cleanup); 453f453ba04SDave Airlie 454f453ba04SDave Airlie /** 455f453ba04SDave Airlie * drm_mode_getcrtc - get CRTC configuration 456065a50edSDaniel Vetter * @dev: drm device for the ioctl 457065a50edSDaniel Vetter * @data: data pointer for the ioctl 458065a50edSDaniel Vetter * @file_priv: drm file for the ioctl call 459f453ba04SDave Airlie * 460f453ba04SDave Airlie * Construct a CRTC configuration structure to return to the user. 461f453ba04SDave Airlie * 462f453ba04SDave Airlie * Called by the user via ioctl. 463f453ba04SDave Airlie * 464c8e32cc1SDaniel Vetter * Returns: 4651a498633SDaniel Vetter * Zero on success, negative errno on failure. 466f453ba04SDave Airlie */ 467f453ba04SDave Airlie int drm_mode_getcrtc(struct drm_device *dev, 468f453ba04SDave Airlie void *data, struct drm_file *file_priv) 469f453ba04SDave Airlie { 470f453ba04SDave Airlie struct drm_mode_crtc *crtc_resp = data; 471f453ba04SDave Airlie struct drm_crtc *crtc; 47264c32b49SVille Syrjälä struct drm_plane *plane; 473f453ba04SDave Airlie 474fb3b06c8SDave Airlie if (!drm_core_check_feature(dev, DRIVER_MODESET)) 47569fdf420SChris Wilson return -EOPNOTSUPP; 476fb3b06c8SDave Airlie 477418da172SKeith Packard crtc = drm_crtc_find(dev, file_priv, crtc_resp->crtc_id); 478fcf93f69SDaniel Vetter if (!crtc) 479fcf93f69SDaniel Vetter return -ENOENT; 480f453ba04SDave Airlie 48164c32b49SVille Syrjälä plane = crtc->primary; 48264c32b49SVille Syrjälä 483f453ba04SDave Airlie crtc_resp->gamma_size = crtc->gamma_size; 484de7b6be7SDaniel Stone 48564c32b49SVille Syrjälä drm_modeset_lock(&plane->mutex, NULL); 48664c32b49SVille Syrjälä if (plane->state && plane->state->fb) 48764c32b49SVille Syrjälä crtc_resp->fb_id = plane->state->fb->base.id; 48864c32b49SVille Syrjälä else if (!plane->state && plane->fb) 48964c32b49SVille Syrjälä crtc_resp->fb_id = plane->fb->base.id; 490f453ba04SDave Airlie else 491f453ba04SDave Airlie crtc_resp->fb_id = 0; 492f453ba04SDave Airlie 49364c32b49SVille Syrjälä if (plane->state) { 49464c32b49SVille Syrjälä crtc_resp->x = plane->state->src_x >> 16; 49564c32b49SVille Syrjälä crtc_resp->y = plane->state->src_y >> 16; 4962c77bb29SDaniel Vetter } 49764c32b49SVille Syrjälä drm_modeset_unlock(&plane->mutex); 4982c77bb29SDaniel Vetter 4992c77bb29SDaniel Vetter drm_modeset_lock(&crtc->mutex, NULL); 5002c77bb29SDaniel Vetter if (crtc->state) { 50131c946e8SDaniel Vetter if (crtc->state->enable) { 502934a8a89SDaniel Stone drm_mode_convert_to_umode(&crtc_resp->mode, &crtc->state->mode); 50331c946e8SDaniel Vetter crtc_resp->mode_valid = 1; 50431c946e8SDaniel Vetter } else { 50531c946e8SDaniel Vetter crtc_resp->mode_valid = 0; 50631c946e8SDaniel Vetter } 50731c946e8SDaniel Vetter } else { 50831c946e8SDaniel Vetter crtc_resp->x = crtc->x; 50931c946e8SDaniel Vetter crtc_resp->y = crtc->y; 510bf2d5eb9SVille Syrjälä 51131c946e8SDaniel Vetter if (crtc->enabled) { 512934a8a89SDaniel Stone drm_mode_convert_to_umode(&crtc_resp->mode, &crtc->mode); 513f453ba04SDave Airlie crtc_resp->mode_valid = 1; 514f453ba04SDave Airlie 515f453ba04SDave Airlie } else { 516f453ba04SDave Airlie crtc_resp->mode_valid = 0; 517f453ba04SDave Airlie } 51831c946e8SDaniel Vetter } 519ace5bf0eSAnkit Nautiyal if (!file_priv->aspect_ratio_allowed) 520ace5bf0eSAnkit Nautiyal crtc_resp->mode.flags &= ~DRM_MODE_FLAG_PIC_AR_MASK; 5212c77bb29SDaniel Vetter drm_modeset_unlock(&crtc->mutex); 522f453ba04SDave Airlie 523baf698b0SDaniel Vetter return 0; 524f453ba04SDave Airlie } 525f453ba04SDave Airlie 5262ceb585aSDaniel Vetter static int __drm_mode_set_config_internal(struct drm_mode_set *set, 5272ceb585aSDaniel Vetter struct drm_modeset_acquire_ctx *ctx) 5282d13b679SDaniel Vetter { 5292d13b679SDaniel Vetter struct drm_crtc *crtc = set->crtc; 5305cef29aaSDaniel Vetter struct drm_framebuffer *fb; 5315cef29aaSDaniel Vetter struct drm_crtc *tmp; 532b0d12325SDaniel Vetter int ret; 5332d13b679SDaniel Vetter 53469a8a196SVille Syrjälä WARN_ON(drm_drv_uses_atomic_modeset(crtc->dev)); 53569a8a196SVille Syrjälä 5365cef29aaSDaniel Vetter /* 5375cef29aaSDaniel Vetter * NOTE: ->set_config can also disable other crtcs (if we steal all 5385cef29aaSDaniel Vetter * connectors from it), hence we need to refcount the fbs across all 5395cef29aaSDaniel Vetter * crtcs. Atomic modeset will have saner semantics ... 5405cef29aaSDaniel Vetter */ 5413ed70ecdSVille Syrjälä drm_for_each_crtc(tmp, crtc->dev) { 5423ed70ecdSVille Syrjälä struct drm_plane *plane = tmp->primary; 5433ed70ecdSVille Syrjälä 5443ed70ecdSVille Syrjälä plane->old_fb = plane->fb; 5453ed70ecdSVille Syrjälä } 5465cef29aaSDaniel Vetter 547b0d12325SDaniel Vetter fb = set->fb; 548b0d12325SDaniel Vetter 549a4eff9aaSDaniel Vetter ret = crtc->funcs->set_config(set, ctx); 550b0d12325SDaniel Vetter if (ret == 0) { 551e00fb856SVille Syrjälä struct drm_plane *plane = crtc->primary; 552e00fb856SVille Syrjälä 553e00fb856SVille Syrjälä plane->crtc = fb ? crtc : NULL; 554e00fb856SVille Syrjälä plane->fb = fb; 555e00fb856SVille Syrjälä } 556cc85e121SDaniel Vetter 557e4f62546SDaniel Vetter drm_for_each_crtc(tmp, crtc->dev) { 5583ed70ecdSVille Syrjälä struct drm_plane *plane = tmp->primary; 5593ed70ecdSVille Syrjälä 5603ed70ecdSVille Syrjälä if (plane->fb) 5613ed70ecdSVille Syrjälä drm_framebuffer_get(plane->fb); 5623ed70ecdSVille Syrjälä if (plane->old_fb) 5633ed70ecdSVille Syrjälä drm_framebuffer_put(plane->old_fb); 5643ed70ecdSVille Syrjälä plane->old_fb = NULL; 565b0d12325SDaniel Vetter } 566b0d12325SDaniel Vetter 567b0d12325SDaniel Vetter return ret; 5682d13b679SDaniel Vetter } 56969a8a196SVille Syrjälä 570d49473a5SDaniel Vetter /** 571d49473a5SDaniel Vetter * drm_mode_set_config_internal - helper to call &drm_mode_config_funcs.set_config 572d49473a5SDaniel Vetter * @set: modeset config to set 573d49473a5SDaniel Vetter * 574d49473a5SDaniel Vetter * This is a little helper to wrap internal calls to the 575d49473a5SDaniel Vetter * &drm_mode_config_funcs.set_config driver interface. The only thing it adds is 576d49473a5SDaniel Vetter * correct refcounting dance. 577d49473a5SDaniel Vetter * 578d49473a5SDaniel Vetter * This should only be used by non-atomic legacy drivers. 579d49473a5SDaniel Vetter * 580d49473a5SDaniel Vetter * Returns: 581d49473a5SDaniel Vetter * Zero on success, negative errno on failure. 582d49473a5SDaniel Vetter */ 583d49473a5SDaniel Vetter int drm_mode_set_config_internal(struct drm_mode_set *set) 584d49473a5SDaniel Vetter { 585d49473a5SDaniel Vetter WARN_ON(drm_drv_uses_atomic_modeset(set->crtc->dev)); 586d49473a5SDaniel Vetter 5872ceb585aSDaniel Vetter return __drm_mode_set_config_internal(set, NULL); 588d49473a5SDaniel Vetter } 5892d13b679SDaniel Vetter EXPORT_SYMBOL(drm_mode_set_config_internal); 5902d13b679SDaniel Vetter 591af93629dSMatt Roper /** 592af93629dSMatt Roper * drm_crtc_check_viewport - Checks that a framebuffer is big enough for the 593af93629dSMatt Roper * CRTC viewport 594af93629dSMatt Roper * @crtc: CRTC that framebuffer will be displayed on 595af93629dSMatt Roper * @x: x panning 596af93629dSMatt Roper * @y: y panning 597af93629dSMatt Roper * @mode: mode that framebuffer will be displayed under 598af93629dSMatt Roper * @fb: framebuffer to check size of 599c11e9283SDamien Lespiau */ 600af93629dSMatt Roper int drm_crtc_check_viewport(const struct drm_crtc *crtc, 601c11e9283SDamien Lespiau int x, int y, 602c11e9283SDamien Lespiau const struct drm_display_mode *mode, 603c11e9283SDamien Lespiau const struct drm_framebuffer *fb) 604c11e9283SDamien Lespiau 605c11e9283SDamien Lespiau { 606c11e9283SDamien Lespiau int hdisplay, vdisplay; 607c11e9283SDamien Lespiau 608196cd5d3SDaniel Vetter drm_mode_get_hv_timing(mode, &hdisplay, &vdisplay); 609a0c1bbb0SDamien Lespiau 61033e0be63SVille Syrjälä if (crtc->state && 611bd2ef25dSVille Syrjälä drm_rotation_90_or_270(crtc->primary->state->rotation)) 612c11e9283SDamien Lespiau swap(hdisplay, vdisplay); 613c11e9283SDamien Lespiau 61443968d7bSDaniel Vetter return drm_framebuffer_check_src_coords(x << 16, y << 16, 61543968d7bSDaniel Vetter hdisplay << 16, vdisplay << 16, 61643968d7bSDaniel Vetter fb); 617c11e9283SDamien Lespiau } 618af93629dSMatt Roper EXPORT_SYMBOL(drm_crtc_check_viewport); 619c11e9283SDamien Lespiau 6202d13b679SDaniel Vetter /** 621f453ba04SDave Airlie * drm_mode_setcrtc - set CRTC configuration 622065a50edSDaniel Vetter * @dev: drm device for the ioctl 623065a50edSDaniel Vetter * @data: data pointer for the ioctl 624065a50edSDaniel Vetter * @file_priv: drm file for the ioctl call 625f453ba04SDave Airlie * 626f453ba04SDave Airlie * Build a new CRTC configuration based on user request. 627f453ba04SDave Airlie * 628f453ba04SDave Airlie * Called by the user via ioctl. 629f453ba04SDave Airlie * 630c8e32cc1SDaniel Vetter * Returns: 6311a498633SDaniel Vetter * Zero on success, negative errno on failure. 632f453ba04SDave Airlie */ 633f453ba04SDave Airlie int drm_mode_setcrtc(struct drm_device *dev, void *data, 634f453ba04SDave Airlie struct drm_file *file_priv) 635f453ba04SDave Airlie { 636f453ba04SDave Airlie struct drm_mode_config *config = &dev->mode_config; 637f453ba04SDave Airlie struct drm_mode_crtc *crtc_req = data; 6386653cc8dSVille Syrjälä struct drm_crtc *crtc; 63964c32b49SVille Syrjälä struct drm_plane *plane; 640c232e9f4SSean Paul struct drm_connector **connector_set = NULL, *connector; 641c232e9f4SSean Paul struct drm_framebuffer *fb = NULL; 642c232e9f4SSean Paul struct drm_display_mode *mode = NULL; 643f453ba04SDave Airlie struct drm_mode_set set; 644f453ba04SDave Airlie uint32_t __user *set_connectors_ptr; 6452ceb585aSDaniel Vetter struct drm_modeset_acquire_ctx ctx; 6464a1b0714SLaurent Pinchart int ret; 647f453ba04SDave Airlie int i; 648f453ba04SDave Airlie 649fb3b06c8SDave Airlie if (!drm_core_check_feature(dev, DRIVER_MODESET)) 65069fdf420SChris Wilson return -EOPNOTSUPP; 651fb3b06c8SDave Airlie 65201447e9fSZhao Junwang /* 65301447e9fSZhao Junwang * Universal plane src offsets are only 16.16, prevent havoc for 65401447e9fSZhao Junwang * drivers using universal plane code internally. 65501447e9fSZhao Junwang */ 65601447e9fSZhao Junwang if (crtc_req->x & 0xffff0000 || crtc_req->y & 0xffff0000) 6571d97e915SVille Syrjälä return -ERANGE; 6581d97e915SVille Syrjälä 659418da172SKeith Packard crtc = drm_crtc_find(dev, file_priv, crtc_req->crtc_id); 660a2b34e22SRob Clark if (!crtc) { 66158367ed6SZhao Yakui DRM_DEBUG_KMS("Unknown CRTC ID %d\n", crtc_req->crtc_id); 6622ceb585aSDaniel Vetter return -ENOENT; 663f453ba04SDave Airlie } 664fa3ab4c2SVille Syrjälä DRM_DEBUG_KMS("[CRTC:%d:%s]\n", crtc->base.id, crtc->name); 665f453ba04SDave Airlie 66664c32b49SVille Syrjälä plane = crtc->primary; 66764c32b49SVille Syrjälä 668204f640dSDaniel Vetter /* allow disabling with the primary plane leased */ 669204f640dSDaniel Vetter if (crtc_req->mode_valid && !drm_lease_held(file_priv, plane->base.id)) 670204f640dSDaniel Vetter return -EACCES; 671204f640dSDaniel Vetter 672b7ea04d2SSean Paul DRM_MODESET_LOCK_ALL_BEGIN(dev, ctx, 673b7ea04d2SSean Paul DRM_MODESET_ACQUIRE_INTERRUPTIBLE, ret); 674bf2d5eb9SVille Syrjälä 675f453ba04SDave Airlie if (crtc_req->mode_valid) { 676f453ba04SDave Airlie /* If we have a mode we need a framebuffer. */ 677f453ba04SDave Airlie /* If we pass -1, set the mode with the currently bound fb */ 678f453ba04SDave Airlie if (crtc_req->fb_id == -1) { 679a36c027dSVille Syrjälä struct drm_framebuffer *old_fb; 680a36c027dSVille Syrjälä 681a36c027dSVille Syrjälä if (plane->state) 682a36c027dSVille Syrjälä old_fb = plane->state->fb; 683a36c027dSVille Syrjälä else 684a36c027dSVille Syrjälä old_fb = plane->fb; 685a36c027dSVille Syrjälä 686a36c027dSVille Syrjälä if (!old_fb) { 6876653cc8dSVille Syrjälä DRM_DEBUG_KMS("CRTC doesn't have current FB\n"); 6886653cc8dSVille Syrjälä ret = -EINVAL; 6896653cc8dSVille Syrjälä goto out; 6906653cc8dSVille Syrjälä } 691bf2d5eb9SVille Syrjälä 692a36c027dSVille Syrjälä fb = old_fb; 693b0d12325SDaniel Vetter /* Make refcounting symmetric with the lookup path. */ 694a4a69da0SThierry Reding drm_framebuffer_get(fb); 695f453ba04SDave Airlie } else { 696418da172SKeith Packard fb = drm_framebuffer_lookup(dev, file_priv, crtc_req->fb_id); 697786b99edSDaniel Vetter if (!fb) { 69858367ed6SZhao Yakui DRM_DEBUG_KMS("Unknown FB ID%d\n", 69958367ed6SZhao Yakui crtc_req->fb_id); 70037c4e705SVille Syrjälä ret = -ENOENT; 701f453ba04SDave Airlie goto out; 702f453ba04SDave Airlie } 703f453ba04SDave Airlie } 704f453ba04SDave Airlie 705f453ba04SDave Airlie mode = drm_mode_create(dev); 706ee34ab5bSVille Syrjälä if (!mode) { 707ee34ab5bSVille Syrjälä ret = -ENOMEM; 708ee34ab5bSVille Syrjälä goto out; 709ee34ab5bSVille Syrjälä } 710ace5bf0eSAnkit Nautiyal if (!file_priv->aspect_ratio_allowed && 711ace5bf0eSAnkit Nautiyal (crtc_req->mode.flags & DRM_MODE_FLAG_PIC_AR_MASK) != DRM_MODE_FLAG_PIC_AR_NONE) { 712ace5bf0eSAnkit Nautiyal DRM_DEBUG_KMS("Unexpected aspect-ratio flag bits\n"); 713ace5bf0eSAnkit Nautiyal ret = -EINVAL; 714ace5bf0eSAnkit Nautiyal goto out; 715ace5bf0eSAnkit Nautiyal } 716ace5bf0eSAnkit Nautiyal 717ee34ab5bSVille Syrjälä 71875a655e0SVille Syrjälä ret = drm_mode_convert_umode(dev, mode, &crtc_req->mode); 71990367bf6SVille Syrjälä if (ret) { 7206ab0edf4SVille Syrjälä DRM_DEBUG_KMS("Invalid mode (ret=%d, status=%s)\n", 7216ab0edf4SVille Syrjälä ret, drm_get_mode_status_name(mode->status)); 7226ab0edf4SVille Syrjälä drm_mode_debug_printmodeline(mode); 72390367bf6SVille Syrjälä goto out; 72490367bf6SVille Syrjälä } 72590367bf6SVille Syrjälä 7267eb5f302SLaurent Pinchart /* 7277eb5f302SLaurent Pinchart * Check whether the primary plane supports the fb pixel format. 7287eb5f302SLaurent Pinchart * Drivers not implementing the universal planes API use a 7297eb5f302SLaurent Pinchart * default formats list provided by the DRM core which doesn't 7307eb5f302SLaurent Pinchart * match real hardware capabilities. Skip the check in that 7317eb5f302SLaurent Pinchart * case. 7327eb5f302SLaurent Pinchart */ 73364c32b49SVille Syrjälä if (!plane->format_default) { 73464c32b49SVille Syrjälä ret = drm_plane_check_pixel_format(plane, 73523163a7dSVille Syrjälä fb->format->format, 73623163a7dSVille Syrjälä fb->modifier); 7377eb5f302SLaurent Pinchart if (ret) { 738b3c11ac2SEric Engestrom struct drm_format_name_buf format_name; 739948de842SSuraj Upadhyay 74023163a7dSVille Syrjälä DRM_DEBUG_KMS("Invalid pixel format %s, modifier 0x%llx\n", 741438b74a5SVille Syrjälä drm_get_format_name(fb->format->format, 74223163a7dSVille Syrjälä &format_name), 74323163a7dSVille Syrjälä fb->modifier); 7447eb5f302SLaurent Pinchart goto out; 7457eb5f302SLaurent Pinchart } 7467eb5f302SLaurent Pinchart } 7477eb5f302SLaurent Pinchart 748c11e9283SDamien Lespiau ret = drm_crtc_check_viewport(crtc, crtc_req->x, crtc_req->y, 749c11e9283SDamien Lespiau mode, fb); 750c11e9283SDamien Lespiau if (ret) 7515f61bb42SVille Syrjälä goto out; 752c11e9283SDamien Lespiau 753f453ba04SDave Airlie } 754f453ba04SDave Airlie 755f453ba04SDave Airlie if (crtc_req->count_connectors == 0 && mode) { 75658367ed6SZhao Yakui DRM_DEBUG_KMS("Count connectors is 0 but mode set\n"); 757f453ba04SDave Airlie ret = -EINVAL; 758f453ba04SDave Airlie goto out; 759f453ba04SDave Airlie } 760f453ba04SDave Airlie 7617781de74SJakob Bornecrantz if (crtc_req->count_connectors > 0 && (!mode || !fb)) { 76258367ed6SZhao Yakui DRM_DEBUG_KMS("Count connectors is %d but no mode or fb set\n", 763f453ba04SDave Airlie crtc_req->count_connectors); 764f453ba04SDave Airlie ret = -EINVAL; 765f453ba04SDave Airlie goto out; 766f453ba04SDave Airlie } 767f453ba04SDave Airlie 768f453ba04SDave Airlie if (crtc_req->count_connectors > 0) { 769f453ba04SDave Airlie u32 out_id; 770f453ba04SDave Airlie 771f453ba04SDave Airlie /* Avoid unbounded kernel memory allocation */ 772f453ba04SDave Airlie if (crtc_req->count_connectors > config->num_connector) { 773f453ba04SDave Airlie ret = -EINVAL; 774f453ba04SDave Airlie goto out; 775f453ba04SDave Airlie } 776f453ba04SDave Airlie 7772f6c5389SThierry Reding connector_set = kmalloc_array(crtc_req->count_connectors, 778f453ba04SDave Airlie sizeof(struct drm_connector *), 779f453ba04SDave Airlie GFP_KERNEL); 780f453ba04SDave Airlie if (!connector_set) { 781f453ba04SDave Airlie ret = -ENOMEM; 782f453ba04SDave Airlie goto out; 783f453ba04SDave Airlie } 784f453ba04SDave Airlie 785f453ba04SDave Airlie for (i = 0; i < crtc_req->count_connectors; i++) { 786b164d31fSDave Airlie connector_set[i] = NULL; 78781f6c7f8SVille Syrjälä set_connectors_ptr = (uint32_t __user *)(unsigned long)crtc_req->set_connectors_ptr; 788f453ba04SDave Airlie if (get_user(out_id, &set_connectors_ptr[i])) { 789f453ba04SDave Airlie ret = -EFAULT; 790f453ba04SDave Airlie goto out; 791f453ba04SDave Airlie } 792f453ba04SDave Airlie 793418da172SKeith Packard connector = drm_connector_lookup(dev, file_priv, out_id); 794a2b34e22SRob Clark if (!connector) { 79558367ed6SZhao Yakui DRM_DEBUG_KMS("Connector id %d unknown\n", 79658367ed6SZhao Yakui out_id); 797f27657f2SVille Syrjälä ret = -ENOENT; 798f453ba04SDave Airlie goto out; 799f453ba04SDave Airlie } 8009440106bSJerome Glisse DRM_DEBUG_KMS("[CONNECTOR:%d:%s]\n", 8019440106bSJerome Glisse connector->base.id, 80225933820SJani Nikula connector->name); 803f453ba04SDave Airlie 804f453ba04SDave Airlie connector_set[i] = connector; 805f453ba04SDave Airlie } 806f453ba04SDave Airlie } 807f453ba04SDave Airlie 808f453ba04SDave Airlie set.crtc = crtc; 809f453ba04SDave Airlie set.x = crtc_req->x; 810f453ba04SDave Airlie set.y = crtc_req->y; 811f453ba04SDave Airlie set.mode = mode; 812f453ba04SDave Airlie set.connectors = connector_set; 813f453ba04SDave Airlie set.num_connectors = crtc_req->count_connectors; 814f453ba04SDave Airlie set.fb = fb; 81569a8a196SVille Syrjälä 81669a8a196SVille Syrjälä if (drm_drv_uses_atomic_modeset(dev)) 81769a8a196SVille Syrjälä ret = crtc->funcs->set_config(&set, &ctx); 81869a8a196SVille Syrjälä else 8192ceb585aSDaniel Vetter ret = __drm_mode_set_config_internal(&set, &ctx); 820f453ba04SDave Airlie 821f453ba04SDave Airlie out: 822b0d12325SDaniel Vetter if (fb) 823a4a69da0SThierry Reding drm_framebuffer_put(fb); 824b0d12325SDaniel Vetter 825b164d31fSDave Airlie if (connector_set) { 826b164d31fSDave Airlie for (i = 0; i < crtc_req->count_connectors; i++) { 827b164d31fSDave Airlie if (connector_set[i]) 828ad093607SThierry Reding drm_connector_put(connector_set[i]); 829b164d31fSDave Airlie } 830b164d31fSDave Airlie } 831f453ba04SDave Airlie kfree(connector_set); 832ee34ab5bSVille Syrjälä drm_mode_destroy(dev, mode); 833c232e9f4SSean Paul 834c232e9f4SSean Paul /* In case we need to retry... */ 835c232e9f4SSean Paul connector_set = NULL; 836c232e9f4SSean Paul fb = NULL; 837c232e9f4SSean Paul mode = NULL; 838c232e9f4SSean Paul 83977ef3857SDaniel Vetter DRM_MODESET_LOCK_ALL_END(dev, ctx, ret); 8402ceb585aSDaniel Vetter 841f453ba04SDave Airlie return ret; 842f453ba04SDave Airlie } 843f453ba04SDave Airlie 844949619f3SDaniel Vetter int drm_mode_crtc_set_obj_prop(struct drm_mode_object *obj, 845bffd9de0SPaulo Zanoni struct drm_property *property, 846bffd9de0SPaulo Zanoni uint64_t value) 847bffd9de0SPaulo Zanoni { 848bffd9de0SPaulo Zanoni int ret = -EINVAL; 849bffd9de0SPaulo Zanoni struct drm_crtc *crtc = obj_to_crtc(obj); 850bffd9de0SPaulo Zanoni 851bffd9de0SPaulo Zanoni if (crtc->funcs->set_property) 852bffd9de0SPaulo Zanoni ret = crtc->funcs->set_property(crtc, property, value); 853144a7999SDaniel Vetter if (!ret) 854bffd9de0SPaulo Zanoni drm_object_property_set_value(obj, property, value); 855bffd9de0SPaulo Zanoni 856bffd9de0SPaulo Zanoni return ret; 857bffd9de0SPaulo Zanoni } 8585c759edaSPankaj Bharadiya 8595c759edaSPankaj Bharadiya /** 8605c759edaSPankaj Bharadiya * drm_crtc_create_scaling_filter_property - create a new scaling filter 8615c759edaSPankaj Bharadiya * property 8625c759edaSPankaj Bharadiya * 8635c759edaSPankaj Bharadiya * @crtc: drm CRTC 8645c759edaSPankaj Bharadiya * @supported_filters: bitmask of supported scaling filters, must include 8655c759edaSPankaj Bharadiya * BIT(DRM_SCALING_FILTER_DEFAULT). 8665c759edaSPankaj Bharadiya * 8675c759edaSPankaj Bharadiya * This function lets driver to enable the scaling filter property on a given 8685c759edaSPankaj Bharadiya * CRTC. 8695c759edaSPankaj Bharadiya * 8705c759edaSPankaj Bharadiya * RETURNS: 8715c759edaSPankaj Bharadiya * Zero for success or -errno 8725c759edaSPankaj Bharadiya */ 8735c759edaSPankaj Bharadiya int drm_crtc_create_scaling_filter_property(struct drm_crtc *crtc, 8745c759edaSPankaj Bharadiya unsigned int supported_filters) 8755c759edaSPankaj Bharadiya { 8765c759edaSPankaj Bharadiya struct drm_property *prop = 8775c759edaSPankaj Bharadiya drm_create_scaling_filter_prop(crtc->dev, supported_filters); 8785c759edaSPankaj Bharadiya 8795c759edaSPankaj Bharadiya if (IS_ERR(prop)) 8805c759edaSPankaj Bharadiya return PTR_ERR(prop); 8815c759edaSPankaj Bharadiya 8825c759edaSPankaj Bharadiya drm_object_attach_property(&crtc->base, prop, 8835c759edaSPankaj Bharadiya DRM_SCALING_FILTER_DEFAULT); 8845c759edaSPankaj Bharadiya crtc->scaling_filter_property = prop; 8855c759edaSPankaj Bharadiya 8865c759edaSPankaj Bharadiya return 0; 8875c759edaSPankaj Bharadiya } 8885c759edaSPankaj Bharadiya EXPORT_SYMBOL(drm_crtc_create_scaling_filter_property); 889