xref: /openbmc/linux/drivers/gpu/drm/drm_crtc.c (revision 7e881af7)
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>
3890bb087fSVille Syrjälä #include <drm/drm_blend.h>
39760285e7SDavid Howells #include <drm/drm_crtc.h>
40760285e7SDavid Howells #include <drm/drm_edid.h>
41760285e7SDavid Howells #include <drm/drm_fourcc.h>
42720cf96dSVille Syrjälä #include <drm/drm_framebuffer.h>
439dbb70fdSPhilipp Zabel #include <drm/drm_managed.h>
4451fd371bSRob Clark #include <drm/drm_modeset_lock.h>
4588a48e29SRob Clark #include <drm/drm_atomic.h>
463b96a0b1SDaniel Vetter #include <drm/drm_auth.h>
479edbf1faSTomeu Vizoso #include <drm/drm_debugfs_crc.h>
48e6120d64SDaniel Vetter #include <drm/drm_drv.h>
49e6120d64SDaniel Vetter #include <drm/drm_print.h>
50e6120d64SDaniel Vetter #include <drm/drm_file.h>
51f453ba04SDave Airlie 
528bd441b2SDaniel Vetter #include "drm_crtc_internal.h"
5367d0ec4eSDaniel Vetter #include "drm_internal.h"
548bd441b2SDaniel Vetter 
556a0d9528SLukas Wunner /**
56d5d487ebSDaniel Vetter  * DOC: overview
57d5d487ebSDaniel Vetter  *
58d5d487ebSDaniel Vetter  * A CRTC represents the overall display pipeline. It receives pixel data from
59d5d487ebSDaniel Vetter  * &drm_plane and blends them together. The &drm_display_mode is also attached
60d5d487ebSDaniel Vetter  * to the CRTC, specifying display timings. On the output side the data is fed
61d5d487ebSDaniel Vetter  * to one or more &drm_encoder, which are then each connected to one
62d5d487ebSDaniel Vetter  * &drm_connector.
63d5d487ebSDaniel Vetter  *
64d5d487ebSDaniel Vetter  * To create a CRTC, a KMS drivers allocates and zeroes an instances of
65d5d487ebSDaniel Vetter  * &struct drm_crtc (possibly as part of a larger structure) and registers it
66d5d487ebSDaniel Vetter  * with a call to drm_crtc_init_with_planes().
67d5d487ebSDaniel Vetter  *
68d5d487ebSDaniel Vetter  * The CRTC is also the entry point for legacy modeset operations, see
69d5d487ebSDaniel Vetter  * &drm_crtc_funcs.set_config, legacy plane operations, see
70d5d487ebSDaniel Vetter  * &drm_crtc_funcs.page_flip and &drm_crtc_funcs.cursor_set2, and other legacy
71d5d487ebSDaniel Vetter  * operations like &drm_crtc_funcs.gamma_set. For atomic drivers all these
72d5d487ebSDaniel Vetter  * features are controlled through &drm_property and
73a3d0d834SSimon Ser  * &drm_mode_config_funcs.atomic_check.
74d5d487ebSDaniel Vetter  */
75d5d487ebSDaniel Vetter 
76d5d487ebSDaniel Vetter /**
776d1b81d8SShawn Guo  * drm_crtc_from_index - find the registered CRTC at an index
786d1b81d8SShawn Guo  * @dev: DRM device
796d1b81d8SShawn Guo  * @idx: index of registered CRTC to find for
806d1b81d8SShawn Guo  *
816d1b81d8SShawn Guo  * Given a CRTC index, return the registered CRTC from DRM device's
82931c670dSShawn Guo  * list of CRTCs with matching index. This is the inverse of drm_crtc_index().
83931c670dSShawn Guo  * It's useful in the vblank callbacks (like &drm_driver.enable_vblank or
84931c670dSShawn Guo  * &drm_driver.disable_vblank), since that still deals with indices instead
85931c670dSShawn Guo  * of pointers to &struct drm_crtc."
866d1b81d8SShawn Guo  */
drm_crtc_from_index(struct drm_device * dev,int idx)876d1b81d8SShawn Guo struct drm_crtc *drm_crtc_from_index(struct drm_device *dev, int idx)
886d1b81d8SShawn Guo {
896d1b81d8SShawn Guo 	struct drm_crtc *crtc;
906d1b81d8SShawn Guo 
916d1b81d8SShawn Guo 	drm_for_each_crtc(crtc, dev)
926d1b81d8SShawn Guo 		if (idx == crtc->index)
936d1b81d8SShawn Guo 			return crtc;
946d1b81d8SShawn Guo 
956d1b81d8SShawn Guo 	return NULL;
966d1b81d8SShawn Guo }
976d1b81d8SShawn Guo EXPORT_SYMBOL(drm_crtc_from_index);
986d1b81d8SShawn Guo 
drm_crtc_force_disable(struct drm_crtc * crtc)996a0d9528SLukas Wunner int drm_crtc_force_disable(struct drm_crtc *crtc)
1006a0d9528SLukas Wunner {
1016a0d9528SLukas Wunner 	struct drm_mode_set set = {
1026a0d9528SLukas Wunner 		.crtc = crtc,
1036a0d9528SLukas Wunner 	};
1046a0d9528SLukas Wunner 
10518dddadcSDaniel Vetter 	WARN_ON(drm_drv_uses_atomic_modeset(crtc->dev));
10618dddadcSDaniel Vetter 
1076a0d9528SLukas Wunner 	return drm_mode_set_config_internal(&set);
1086a0d9528SLukas Wunner }
1096a0d9528SLukas Wunner 
drm_num_crtcs(struct drm_device * dev)110fa3ab4c2SVille Syrjälä static unsigned int drm_num_crtcs(struct drm_device *dev)
111fa3ab4c2SVille Syrjälä {
112fa3ab4c2SVille Syrjälä 	unsigned int num = 0;
113fa3ab4c2SVille Syrjälä 	struct drm_crtc *tmp;
114fa3ab4c2SVille Syrjälä 
115fa3ab4c2SVille Syrjälä 	drm_for_each_crtc(tmp, dev) {
116fa3ab4c2SVille Syrjälä 		num++;
117fa3ab4c2SVille Syrjälä 	}
118fa3ab4c2SVille Syrjälä 
119fa3ab4c2SVille Syrjälä 	return num;
120fa3ab4c2SVille Syrjälä }
121fa3ab4c2SVille Syrjälä 
drm_crtc_register_all(struct drm_device * dev)12228575f16SDaniel Vetter int drm_crtc_register_all(struct drm_device *dev)
12379190ea2SBenjamin Gaignard {
12479190ea2SBenjamin Gaignard 	struct drm_crtc *crtc;
12579190ea2SBenjamin Gaignard 	int ret = 0;
12679190ea2SBenjamin Gaignard 
12779190ea2SBenjamin Gaignard 	drm_for_each_crtc(crtc, dev) {
128b792e640SGreg Kroah-Hartman 		drm_debugfs_crtc_add(crtc);
1299edbf1faSTomeu Vizoso 
13079190ea2SBenjamin Gaignard 		if (crtc->funcs->late_register)
13179190ea2SBenjamin Gaignard 			ret = crtc->funcs->late_register(crtc);
13279190ea2SBenjamin Gaignard 		if (ret)
13379190ea2SBenjamin Gaignard 			return ret;
13479190ea2SBenjamin Gaignard 	}
13579190ea2SBenjamin Gaignard 
13679190ea2SBenjamin Gaignard 	return 0;
13779190ea2SBenjamin Gaignard }
13879190ea2SBenjamin Gaignard 
drm_crtc_unregister_all(struct drm_device * dev)13928575f16SDaniel Vetter void drm_crtc_unregister_all(struct drm_device *dev)
14079190ea2SBenjamin Gaignard {
14179190ea2SBenjamin Gaignard 	struct drm_crtc *crtc;
14279190ea2SBenjamin Gaignard 
14379190ea2SBenjamin Gaignard 	drm_for_each_crtc(crtc, dev) {
14479190ea2SBenjamin Gaignard 		if (crtc->funcs->early_unregister)
14579190ea2SBenjamin Gaignard 			crtc->funcs->early_unregister(crtc);
1469edbf1faSTomeu Vizoso 		drm_debugfs_crtc_remove(crtc);
14779190ea2SBenjamin Gaignard 	}
14879190ea2SBenjamin Gaignard }
14979190ea2SBenjamin Gaignard 
drm_crtc_crc_init(struct drm_crtc * crtc)1509edbf1faSTomeu Vizoso static int drm_crtc_crc_init(struct drm_crtc *crtc)
1519edbf1faSTomeu Vizoso {
1529edbf1faSTomeu Vizoso #ifdef CONFIG_DEBUG_FS
1539edbf1faSTomeu Vizoso 	spin_lock_init(&crtc->crc.lock);
1549edbf1faSTomeu Vizoso 	init_waitqueue_head(&crtc->crc.wq);
1559edbf1faSTomeu Vizoso 	crtc->crc.source = kstrdup("auto", GFP_KERNEL);
1569edbf1faSTomeu Vizoso 	if (!crtc->crc.source)
1579edbf1faSTomeu Vizoso 		return -ENOMEM;
1589edbf1faSTomeu Vizoso #endif
1599edbf1faSTomeu Vizoso 	return 0;
1609edbf1faSTomeu Vizoso }
1619edbf1faSTomeu Vizoso 
drm_crtc_crc_fini(struct drm_crtc * crtc)1629edbf1faSTomeu Vizoso static void drm_crtc_crc_fini(struct drm_crtc *crtc)
1639edbf1faSTomeu Vizoso {
1649edbf1faSTomeu Vizoso #ifdef CONFIG_DEBUG_FS
1659edbf1faSTomeu Vizoso 	kfree(crtc->crc.source);
1669edbf1faSTomeu Vizoso #endif
1679edbf1faSTomeu Vizoso }
1689edbf1faSTomeu Vizoso 
16935f8cc3bSGustavo Padovan static const struct dma_fence_ops drm_crtc_fence_ops;
17035f8cc3bSGustavo Padovan 
fence_to_crtc(struct dma_fence * fence)1716d6003c4SGustavo Padovan static struct drm_crtc *fence_to_crtc(struct dma_fence *fence)
1726d6003c4SGustavo Padovan {
1736d6003c4SGustavo Padovan 	BUG_ON(fence->ops != &drm_crtc_fence_ops);
1746d6003c4SGustavo Padovan 	return container_of(fence->lock, struct drm_crtc, fence_lock);
1756d6003c4SGustavo Padovan }
1766d6003c4SGustavo Padovan 
drm_crtc_fence_get_driver_name(struct dma_fence * fence)1776d6003c4SGustavo Padovan static const char *drm_crtc_fence_get_driver_name(struct dma_fence *fence)
1786d6003c4SGustavo Padovan {
1796d6003c4SGustavo Padovan 	struct drm_crtc *crtc = fence_to_crtc(fence);
1806d6003c4SGustavo Padovan 
1816d6003c4SGustavo Padovan 	return crtc->dev->driver->name;
1826d6003c4SGustavo Padovan }
1836d6003c4SGustavo Padovan 
drm_crtc_fence_get_timeline_name(struct dma_fence * fence)1846d6003c4SGustavo Padovan static const char *drm_crtc_fence_get_timeline_name(struct dma_fence *fence)
1856d6003c4SGustavo Padovan {
1866d6003c4SGustavo Padovan 	struct drm_crtc *crtc = fence_to_crtc(fence);
1876d6003c4SGustavo Padovan 
1886d6003c4SGustavo Padovan 	return crtc->timeline_name;
1896d6003c4SGustavo Padovan }
1906d6003c4SGustavo Padovan 
19135f8cc3bSGustavo Padovan static const struct dma_fence_ops drm_crtc_fence_ops = {
1926d6003c4SGustavo Padovan 	.get_driver_name = drm_crtc_fence_get_driver_name,
1936d6003c4SGustavo Padovan 	.get_timeline_name = drm_crtc_fence_get_timeline_name,
1946d6003c4SGustavo Padovan };
1956d6003c4SGustavo Padovan 
drm_crtc_create_fence(struct drm_crtc * crtc)19635f8cc3bSGustavo Padovan struct dma_fence *drm_crtc_create_fence(struct drm_crtc *crtc)
19735f8cc3bSGustavo Padovan {
19835f8cc3bSGustavo Padovan 	struct dma_fence *fence;
19935f8cc3bSGustavo Padovan 
20035f8cc3bSGustavo Padovan 	fence = kzalloc(sizeof(*fence), GFP_KERNEL);
20135f8cc3bSGustavo Padovan 	if (!fence)
20235f8cc3bSGustavo Padovan 		return NULL;
20335f8cc3bSGustavo Padovan 
20435f8cc3bSGustavo Padovan 	dma_fence_init(fence, &drm_crtc_fence_ops, &crtc->fence_lock,
20535f8cc3bSGustavo Padovan 		       crtc->fence_context, ++crtc->fence_seqno);
20635f8cc3bSGustavo Padovan 
20735f8cc3bSGustavo Padovan 	return fence;
20835f8cc3bSGustavo Padovan }
20935f8cc3bSGustavo Padovan 
210f453ba04SDave Airlie /**
211e954f77fSSimon Ser  * DOC: standard CRTC properties
212e954f77fSSimon Ser  *
213e954f77fSSimon Ser  * DRM CRTCs have a few standardized properties:
214e954f77fSSimon Ser  *
215e954f77fSSimon Ser  * ACTIVE:
216e954f77fSSimon Ser  * 	Atomic property for setting the power state of the CRTC. When set to 1
217e954f77fSSimon Ser  * 	the CRTC will actively display content. When set to 0 the CRTC will be
218e954f77fSSimon Ser  * 	powered off. There is no expectation that user-space will reset CRTC
219e954f77fSSimon Ser  * 	resources like the mode and planes when setting ACTIVE to 0.
220e954f77fSSimon Ser  *
221e954f77fSSimon Ser  * 	User-space can rely on an ACTIVE change to 1 to never fail an atomic
222e954f77fSSimon Ser  * 	test as long as no other property has changed. If a change to ACTIVE
223e954f77fSSimon Ser  * 	fails an atomic test, this is a driver bug. For this reason setting
224e954f77fSSimon Ser  * 	ACTIVE to 0 must not release internal resources (like reserved memory
225e954f77fSSimon Ser  * 	bandwidth or clock generators).
226e954f77fSSimon Ser  *
227e954f77fSSimon Ser  * 	Note that the legacy DPMS property on connectors is internally routed
228e954f77fSSimon Ser  * 	to control this property for atomic drivers.
229e954f77fSSimon Ser  * MODE_ID:
230e954f77fSSimon Ser  * 	Atomic property for setting the CRTC display timings. The value is the
231e954f77fSSimon Ser  * 	ID of a blob containing the DRM mode info. To disable the CRTC,
232e954f77fSSimon Ser  * 	user-space must set this property to 0.
233e954f77fSSimon Ser  *
234e954f77fSSimon Ser  * 	Setting MODE_ID to 0 will release reserved resources for the CRTC.
2355c759edaSPankaj Bharadiya  * SCALING_FILTER:
2365c759edaSPankaj Bharadiya  * 	Atomic property for setting the scaling filter for CRTC scaler
2375c759edaSPankaj Bharadiya  *
2385c759edaSPankaj Bharadiya  * 	The value of this property can be one of the following:
2391187ffc4SSimon Ser  *
2405c759edaSPankaj Bharadiya  * 	Default:
2415c759edaSPankaj Bharadiya  * 		Driver's default scaling filter
2425c759edaSPankaj Bharadiya  * 	Nearest Neighbor:
2435c759edaSPankaj Bharadiya  * 		Nearest Neighbor scaling filter
244e954f77fSSimon Ser  */
245e954f77fSSimon Ser 
2469dbb70fdSPhilipp Zabel __printf(6, 0)
__drm_crtc_init_with_planes(struct drm_device * dev,struct drm_crtc * crtc,struct drm_plane * primary,struct drm_plane * cursor,const struct drm_crtc_funcs * funcs,const char * name,va_list ap)2479dbb70fdSPhilipp Zabel static int __drm_crtc_init_with_planes(struct drm_device *dev, struct drm_crtc *crtc,
248e13161afSMatt Roper 				       struct drm_plane *primary,
249fc1d3e44SMatt Roper 				       struct drm_plane *cursor,
250f9882876SVille Syrjälä 				       const struct drm_crtc_funcs *funcs,
2519dbb70fdSPhilipp Zabel 				       const char *name, va_list ap)
252f453ba04SDave Airlie {
25351fd371bSRob Clark 	struct drm_mode_config *config = &dev->mode_config;
2546bfc56aaSVille Syrjälä 	int ret;
2556bfc56aaSVille Syrjälä 
256522cf91fSBenjamin Gaignard 	WARN_ON(primary && primary->type != DRM_PLANE_TYPE_PRIMARY);
257522cf91fSBenjamin Gaignard 	WARN_ON(cursor && cursor->type != DRM_PLANE_TYPE_CURSOR);
258522cf91fSBenjamin Gaignard 
2592a8d3eacSVille Syrjälä 	/* crtc index is used with 32bit bitmasks */
2602a8d3eacSVille Syrjälä 	if (WARN_ON(config->num_crtc >= 32))
2612a8d3eacSVille Syrjälä 		return -EINVAL;
2622a8d3eacSVille Syrjälä 
263ba1f665fSHaneen Mohammed 	WARN_ON(drm_drv_uses_atomic_modeset(dev) &&
264ba1f665fSHaneen Mohammed 		(!funcs->atomic_destroy_state ||
265ba1f665fSHaneen Mohammed 		 !funcs->atomic_duplicate_state));
266ba1f665fSHaneen Mohammed 
267f453ba04SDave Airlie 	crtc->dev = dev;
268f453ba04SDave Airlie 	crtc->funcs = funcs;
269f453ba04SDave Airlie 
2703b24f7d6SDaniel Vetter 	INIT_LIST_HEAD(&crtc->commit_list);
2713b24f7d6SDaniel Vetter 	spin_lock_init(&crtc->commit_lock);
2723b24f7d6SDaniel Vetter 
27351fd371bSRob Clark 	drm_modeset_lock_init(&crtc->mutex);
2742135ea7aSThierry Reding 	ret = drm_mode_object_add(dev, &crtc->base, DRM_MODE_OBJECT_CRTC);
2756bfc56aaSVille Syrjälä 	if (ret)
276baf698b0SDaniel Vetter 		return ret;
277f453ba04SDave Airlie 
278fa3ab4c2SVille Syrjälä 	if (name) {
279fa3ab4c2SVille Syrjälä 		crtc->name = kvasprintf(GFP_KERNEL, name, ap);
280fa3ab4c2SVille Syrjälä 	} else {
281fa3ab4c2SVille Syrjälä 		crtc->name = kasprintf(GFP_KERNEL, "crtc-%d",
282fa3ab4c2SVille Syrjälä 				       drm_num_crtcs(dev));
283fa3ab4c2SVille Syrjälä 	}
284fa3ab4c2SVille Syrjälä 	if (!crtc->name) {
2857c8f6d25SDave Airlie 		drm_mode_object_unregister(dev, &crtc->base);
286fa3ab4c2SVille Syrjälä 		return -ENOMEM;
287fa3ab4c2SVille Syrjälä 	}
288fa3ab4c2SVille Syrjälä 
2896d6003c4SGustavo Padovan 	crtc->fence_context = dma_fence_context_alloc(1);
2906d6003c4SGustavo Padovan 	spin_lock_init(&crtc->fence_lock);
2916d6003c4SGustavo Padovan 	snprintf(crtc->timeline_name, sizeof(crtc->timeline_name),
2926d6003c4SGustavo Padovan 		 "CRTC:%d-%s", crtc->base.id, crtc->name);
2936d6003c4SGustavo Padovan 
294bffd9de0SPaulo Zanoni 	crtc->base.properties = &crtc->properties;
295bffd9de0SPaulo Zanoni 
29651fd371bSRob Clark 	list_add_tail(&crtc->head, &config->crtc_list);
297490d3d1bSChris Wilson 	crtc->index = config->num_crtc++;
2986bfc56aaSVille Syrjälä 
299e13161afSMatt Roper 	crtc->primary = primary;
300fc1d3e44SMatt Roper 	crtc->cursor = cursor;
3017abc7d47SRob Clark 	if (primary && !primary->possible_crtcs)
3026a52193bSVille Syrjälä 		primary->possible_crtcs = drm_crtc_mask(crtc);
3037abc7d47SRob Clark 	if (cursor && !cursor->possible_crtcs)
3046a52193bSVille Syrjälä 		cursor->possible_crtcs = drm_crtc_mask(crtc);
305e13161afSMatt Roper 
3069edbf1faSTomeu Vizoso 	ret = drm_crtc_crc_init(crtc);
3079edbf1faSTomeu Vizoso 	if (ret) {
3089edbf1faSTomeu Vizoso 		drm_mode_object_unregister(dev, &crtc->base);
3099edbf1faSTomeu Vizoso 		return ret;
3109edbf1faSTomeu Vizoso 	}
3119edbf1faSTomeu Vizoso 
312eab3bbefSDaniel Vetter 	if (drm_core_check_feature(dev, DRIVER_ATOMIC)) {
313eab3bbefSDaniel Vetter 		drm_object_attach_property(&crtc->base, config->prop_active, 0);
314955f3c33SDaniel Stone 		drm_object_attach_property(&crtc->base, config->prop_mode_id, 0);
315beaf5af4SGustavo Padovan 		drm_object_attach_property(&crtc->base,
316beaf5af4SGustavo Padovan 					   config->prop_out_fence_ptr, 0);
3171398958cSNicholas Kazlauskas 		drm_object_attach_property(&crtc->base,
3181398958cSNicholas Kazlauskas 					   config->prop_vrr_enabled, 0);
319eab3bbefSDaniel Vetter 	}
320eab3bbefSDaniel Vetter 
321baf698b0SDaniel Vetter 	return 0;
322f453ba04SDave Airlie }
3239dbb70fdSPhilipp Zabel 
3249dbb70fdSPhilipp Zabel /**
3259dbb70fdSPhilipp Zabel  * drm_crtc_init_with_planes - Initialise a new CRTC object with
3269dbb70fdSPhilipp Zabel  *    specified primary and cursor planes.
3279dbb70fdSPhilipp Zabel  * @dev: DRM device
3289dbb70fdSPhilipp Zabel  * @crtc: CRTC object to init
3299dbb70fdSPhilipp Zabel  * @primary: Primary plane for CRTC
3309dbb70fdSPhilipp Zabel  * @cursor: Cursor plane for CRTC
3319dbb70fdSPhilipp Zabel  * @funcs: callbacks for the new CRTC
3329dbb70fdSPhilipp Zabel  * @name: printf style format string for the CRTC name, or NULL for default name
3339dbb70fdSPhilipp Zabel  *
3349dbb70fdSPhilipp Zabel  * Inits a new object created as base part of a driver crtc object. Drivers
3359dbb70fdSPhilipp Zabel  * should use this function instead of drm_crtc_init(), which is only provided
3369dbb70fdSPhilipp Zabel  * for backwards compatibility with drivers which do not yet support universal
3379dbb70fdSPhilipp Zabel  * planes). For really simple hardware which has only 1 plane look at
3389dbb70fdSPhilipp Zabel  * drm_simple_display_pipe_init() instead.
3399dbb70fdSPhilipp Zabel  * The &drm_crtc_funcs.destroy hook should call drm_crtc_cleanup() and kfree()
3409dbb70fdSPhilipp Zabel  * the crtc structure. The crtc structure should not be allocated with
3419dbb70fdSPhilipp Zabel  * devm_kzalloc().
3429dbb70fdSPhilipp Zabel  *
343e240cc76SDaniel Vetter  * The @primary and @cursor planes are only relevant for legacy uAPI, see
344e240cc76SDaniel Vetter  * &drm_crtc.primary and &drm_crtc.cursor.
345e240cc76SDaniel Vetter  *
346917dd054SMaxime Ripard  * Note: consider using drmm_crtc_alloc_with_planes() or
347917dd054SMaxime Ripard  * drmm_crtc_init_with_planes() instead of drm_crtc_init_with_planes()
348917dd054SMaxime Ripard  * to let the DRM managed resource infrastructure take care of cleanup
349917dd054SMaxime Ripard  * and deallocation.
3509dbb70fdSPhilipp Zabel  *
3519dbb70fdSPhilipp Zabel  * Returns:
3529dbb70fdSPhilipp Zabel  * Zero on success, error code on failure.
3539dbb70fdSPhilipp Zabel  */
drm_crtc_init_with_planes(struct drm_device * dev,struct drm_crtc * crtc,struct drm_plane * primary,struct drm_plane * cursor,const struct drm_crtc_funcs * funcs,const char * name,...)3549dbb70fdSPhilipp Zabel int drm_crtc_init_with_planes(struct drm_device *dev, struct drm_crtc *crtc,
3559dbb70fdSPhilipp Zabel 			      struct drm_plane *primary,
3569dbb70fdSPhilipp Zabel 			      struct drm_plane *cursor,
3579dbb70fdSPhilipp Zabel 			      const struct drm_crtc_funcs *funcs,
3589dbb70fdSPhilipp Zabel 			      const char *name, ...)
3599dbb70fdSPhilipp Zabel {
3609dbb70fdSPhilipp Zabel 	va_list ap;
3619dbb70fdSPhilipp Zabel 	int ret;
3629dbb70fdSPhilipp Zabel 
3639dbb70fdSPhilipp Zabel 	WARN_ON(!funcs->destroy);
3649dbb70fdSPhilipp Zabel 
3659dbb70fdSPhilipp Zabel 	va_start(ap, name);
3669dbb70fdSPhilipp Zabel 	ret = __drm_crtc_init_with_planes(dev, crtc, primary, cursor, funcs,
3679dbb70fdSPhilipp Zabel 					  name, ap);
3689dbb70fdSPhilipp Zabel 	va_end(ap);
3699dbb70fdSPhilipp Zabel 
3709dbb70fdSPhilipp Zabel 	return ret;
3719dbb70fdSPhilipp Zabel }
372e13161afSMatt Roper EXPORT_SYMBOL(drm_crtc_init_with_planes);
373f453ba04SDave Airlie 
drmm_crtc_init_with_planes_cleanup(struct drm_device * dev,void * ptr)374917dd054SMaxime Ripard static void drmm_crtc_init_with_planes_cleanup(struct drm_device *dev,
3759dbb70fdSPhilipp Zabel 					       void *ptr)
3769dbb70fdSPhilipp Zabel {
3779dbb70fdSPhilipp Zabel 	struct drm_crtc *crtc = ptr;
3789dbb70fdSPhilipp Zabel 
3799dbb70fdSPhilipp Zabel 	drm_crtc_cleanup(crtc);
3809dbb70fdSPhilipp Zabel }
3819dbb70fdSPhilipp Zabel 
382917dd054SMaxime Ripard __printf(6, 0)
__drmm_crtc_init_with_planes(struct drm_device * dev,struct drm_crtc * crtc,struct drm_plane * primary,struct drm_plane * cursor,const struct drm_crtc_funcs * funcs,const char * name,va_list args)383917dd054SMaxime Ripard static int __drmm_crtc_init_with_planes(struct drm_device *dev,
384917dd054SMaxime Ripard 					struct drm_crtc *crtc,
385917dd054SMaxime Ripard 					struct drm_plane *primary,
386917dd054SMaxime Ripard 					struct drm_plane *cursor,
387917dd054SMaxime Ripard 					const struct drm_crtc_funcs *funcs,
388917dd054SMaxime Ripard 					const char *name,
389917dd054SMaxime Ripard 					va_list args)
390917dd054SMaxime Ripard {
391917dd054SMaxime Ripard 	int ret;
392917dd054SMaxime Ripard 
393917dd054SMaxime Ripard 	drm_WARN_ON(dev, funcs && funcs->destroy);
394917dd054SMaxime Ripard 
395917dd054SMaxime Ripard 	ret = __drm_crtc_init_with_planes(dev, crtc, primary, cursor, funcs,
396917dd054SMaxime Ripard 					  name, args);
397917dd054SMaxime Ripard 	if (ret)
398917dd054SMaxime Ripard 		return ret;
399917dd054SMaxime Ripard 
400917dd054SMaxime Ripard 	ret = drmm_add_action_or_reset(dev, drmm_crtc_init_with_planes_cleanup,
401917dd054SMaxime Ripard 				       crtc);
402917dd054SMaxime Ripard 	if (ret)
403917dd054SMaxime Ripard 		return ret;
404917dd054SMaxime Ripard 
405917dd054SMaxime Ripard 	return 0;
406917dd054SMaxime Ripard }
407917dd054SMaxime Ripard 
408917dd054SMaxime Ripard /**
409917dd054SMaxime Ripard  * drmm_crtc_init_with_planes - Initialise a new CRTC object with
410917dd054SMaxime Ripard  *    specified primary and cursor planes.
411917dd054SMaxime Ripard  * @dev: DRM device
412917dd054SMaxime Ripard  * @crtc: CRTC object to init
413917dd054SMaxime Ripard  * @primary: Primary plane for CRTC
414917dd054SMaxime Ripard  * @cursor: Cursor plane for CRTC
415917dd054SMaxime Ripard  * @funcs: callbacks for the new CRTC
416917dd054SMaxime Ripard  * @name: printf style format string for the CRTC name, or NULL for default name
417917dd054SMaxime Ripard  *
418917dd054SMaxime Ripard  * Inits a new object created as base part of a driver crtc object. Drivers
419917dd054SMaxime Ripard  * should use this function instead of drm_crtc_init(), which is only provided
420917dd054SMaxime Ripard  * for backwards compatibility with drivers which do not yet support universal
421917dd054SMaxime Ripard  * planes). For really simple hardware which has only 1 plane look at
422917dd054SMaxime Ripard  * drm_simple_display_pipe_init() instead.
423917dd054SMaxime Ripard  *
424917dd054SMaxime Ripard  * Cleanup is automatically handled through registering
425917dd054SMaxime Ripard  * drmm_crtc_cleanup() with drmm_add_action(). The crtc structure should
426917dd054SMaxime Ripard  * be allocated with drmm_kzalloc().
427917dd054SMaxime Ripard  *
428917dd054SMaxime Ripard  * The @drm_crtc_funcs.destroy hook must be NULL.
429917dd054SMaxime Ripard  *
430917dd054SMaxime Ripard  * The @primary and @cursor planes are only relevant for legacy uAPI, see
431917dd054SMaxime Ripard  * &drm_crtc.primary and &drm_crtc.cursor.
432917dd054SMaxime Ripard  *
433917dd054SMaxime Ripard  * Returns:
434917dd054SMaxime Ripard  * Zero on success, error code on failure.
435917dd054SMaxime Ripard  */
drmm_crtc_init_with_planes(struct drm_device * dev,struct drm_crtc * crtc,struct drm_plane * primary,struct drm_plane * cursor,const struct drm_crtc_funcs * funcs,const char * name,...)436917dd054SMaxime Ripard int drmm_crtc_init_with_planes(struct drm_device *dev, struct drm_crtc *crtc,
437917dd054SMaxime Ripard 			       struct drm_plane *primary,
438917dd054SMaxime Ripard 			       struct drm_plane *cursor,
439917dd054SMaxime Ripard 			       const struct drm_crtc_funcs *funcs,
440917dd054SMaxime Ripard 			       const char *name, ...)
441917dd054SMaxime Ripard {
442917dd054SMaxime Ripard 	va_list ap;
443917dd054SMaxime Ripard 	int ret;
444917dd054SMaxime Ripard 
445917dd054SMaxime Ripard 	va_start(ap, name);
446917dd054SMaxime Ripard 	ret = __drmm_crtc_init_with_planes(dev, crtc, primary, cursor, funcs,
447917dd054SMaxime Ripard 					   name, ap);
448917dd054SMaxime Ripard 	va_end(ap);
449917dd054SMaxime Ripard 	if (ret)
450917dd054SMaxime Ripard 		return ret;
451917dd054SMaxime Ripard 
452917dd054SMaxime Ripard 	return 0;
453917dd054SMaxime Ripard }
454917dd054SMaxime Ripard EXPORT_SYMBOL(drmm_crtc_init_with_planes);
455917dd054SMaxime Ripard 
__drmm_crtc_alloc_with_planes(struct drm_device * dev,size_t size,size_t offset,struct drm_plane * primary,struct drm_plane * cursor,const struct drm_crtc_funcs * funcs,const char * name,...)4569dbb70fdSPhilipp Zabel void *__drmm_crtc_alloc_with_planes(struct drm_device *dev,
4579dbb70fdSPhilipp Zabel 				    size_t size, size_t offset,
4589dbb70fdSPhilipp Zabel 				    struct drm_plane *primary,
4599dbb70fdSPhilipp Zabel 				    struct drm_plane *cursor,
4609dbb70fdSPhilipp Zabel 				    const struct drm_crtc_funcs *funcs,
4619dbb70fdSPhilipp Zabel 				    const char *name, ...)
4629dbb70fdSPhilipp Zabel {
4639dbb70fdSPhilipp Zabel 	void *container;
4649dbb70fdSPhilipp Zabel 	struct drm_crtc *crtc;
4659dbb70fdSPhilipp Zabel 	va_list ap;
4669dbb70fdSPhilipp Zabel 	int ret;
4679dbb70fdSPhilipp Zabel 
4689dbb70fdSPhilipp Zabel 	if (WARN_ON(!funcs || funcs->destroy))
4699dbb70fdSPhilipp Zabel 		return ERR_PTR(-EINVAL);
4709dbb70fdSPhilipp Zabel 
4719dbb70fdSPhilipp Zabel 	container = drmm_kzalloc(dev, size, GFP_KERNEL);
4729dbb70fdSPhilipp Zabel 	if (!container)
4739dbb70fdSPhilipp Zabel 		return ERR_PTR(-ENOMEM);
4749dbb70fdSPhilipp Zabel 
4759dbb70fdSPhilipp Zabel 	crtc = container + offset;
4769dbb70fdSPhilipp Zabel 
4779dbb70fdSPhilipp Zabel 	va_start(ap, name);
478917dd054SMaxime Ripard 	ret = __drmm_crtc_init_with_planes(dev, crtc, primary, cursor, funcs,
4799dbb70fdSPhilipp Zabel 					   name, ap);
4809dbb70fdSPhilipp Zabel 	va_end(ap);
4819dbb70fdSPhilipp Zabel 	if (ret)
4829dbb70fdSPhilipp Zabel 		return ERR_PTR(ret);
4839dbb70fdSPhilipp Zabel 
4849dbb70fdSPhilipp Zabel 	return container;
4859dbb70fdSPhilipp Zabel }
4869dbb70fdSPhilipp Zabel EXPORT_SYMBOL(__drmm_crtc_alloc_with_planes);
4879dbb70fdSPhilipp Zabel 
488f453ba04SDave Airlie /**
489ad6f5c34SVille Syrjälä  * drm_crtc_cleanup - Clean up the core crtc usage
490f453ba04SDave Airlie  * @crtc: CRTC to cleanup
491f453ba04SDave Airlie  *
492ad6f5c34SVille Syrjälä  * This function cleans up @crtc and removes it from the DRM mode setting
493ad6f5c34SVille Syrjälä  * core. Note that the function does *not* free the crtc structure itself,
494ad6f5c34SVille Syrjälä  * this is the responsibility of the caller.
495f453ba04SDave Airlie  */
drm_crtc_cleanup(struct drm_crtc * crtc)496f453ba04SDave Airlie void drm_crtc_cleanup(struct drm_crtc *crtc)
497f453ba04SDave Airlie {
498f453ba04SDave Airlie 	struct drm_device *dev = crtc->dev;
499f453ba04SDave Airlie 
500490d3d1bSChris Wilson 	/* Note that the crtc_list is considered to be static; should we
501490d3d1bSChris Wilson 	 * remove the drm_crtc at runtime we would have to decrement all
502490d3d1bSChris Wilson 	 * the indices on the drm_crtc after us in the crtc_list.
503490d3d1bSChris Wilson 	 */
504490d3d1bSChris Wilson 
5059edbf1faSTomeu Vizoso 	drm_crtc_crc_fini(crtc);
5069edbf1faSTomeu Vizoso 
507f453ba04SDave Airlie 	kfree(crtc->gamma_store);
508f453ba04SDave Airlie 	crtc->gamma_store = NULL;
509f453ba04SDave Airlie 
51051fd371bSRob Clark 	drm_modeset_lock_fini(&crtc->mutex);
51151fd371bSRob Clark 
5127c8f6d25SDave Airlie 	drm_mode_object_unregister(dev, &crtc->base);
513f453ba04SDave Airlie 	list_del(&crtc->head);
514f453ba04SDave Airlie 	dev->mode_config.num_crtc--;
5153009c037SThierry Reding 
5163009c037SThierry Reding 	WARN_ON(crtc->state && !crtc->funcs->atomic_destroy_state);
5173009c037SThierry Reding 	if (crtc->state && crtc->funcs->atomic_destroy_state)
5183009c037SThierry Reding 		crtc->funcs->atomic_destroy_state(crtc, crtc->state);
519a18c0af1SThierry Reding 
520fa3ab4c2SVille Syrjälä 	kfree(crtc->name);
521fa3ab4c2SVille Syrjälä 
522a18c0af1SThierry Reding 	memset(crtc, 0, sizeof(*crtc));
523f453ba04SDave Airlie }
524f453ba04SDave Airlie EXPORT_SYMBOL(drm_crtc_cleanup);
525f453ba04SDave Airlie 
526f453ba04SDave Airlie /**
527f453ba04SDave Airlie  * drm_mode_getcrtc - get CRTC configuration
528065a50edSDaniel Vetter  * @dev: drm device for the ioctl
529065a50edSDaniel Vetter  * @data: data pointer for the ioctl
530065a50edSDaniel Vetter  * @file_priv: drm file for the ioctl call
531f453ba04SDave Airlie  *
532f453ba04SDave Airlie  * Construct a CRTC configuration structure to return to the user.
533f453ba04SDave Airlie  *
534f453ba04SDave Airlie  * Called by the user via ioctl.
535f453ba04SDave Airlie  *
536c8e32cc1SDaniel Vetter  * Returns:
5371a498633SDaniel Vetter  * Zero on success, negative errno on failure.
538f453ba04SDave Airlie  */
drm_mode_getcrtc(struct drm_device * dev,void * data,struct drm_file * file_priv)539f453ba04SDave Airlie int drm_mode_getcrtc(struct drm_device *dev,
540f453ba04SDave Airlie 		     void *data, struct drm_file *file_priv)
541f453ba04SDave Airlie {
542f453ba04SDave Airlie 	struct drm_mode_crtc *crtc_resp = data;
543f453ba04SDave Airlie 	struct drm_crtc *crtc;
54464c32b49SVille Syrjälä 	struct drm_plane *plane;
545f453ba04SDave Airlie 
546fb3b06c8SDave Airlie 	if (!drm_core_check_feature(dev, DRIVER_MODESET))
54769fdf420SChris Wilson 		return -EOPNOTSUPP;
548fb3b06c8SDave Airlie 
549418da172SKeith Packard 	crtc = drm_crtc_find(dev, file_priv, crtc_resp->crtc_id);
550fcf93f69SDaniel Vetter 	if (!crtc)
551fcf93f69SDaniel Vetter 		return -ENOENT;
552f453ba04SDave Airlie 
55364c32b49SVille Syrjälä 	plane = crtc->primary;
55464c32b49SVille Syrjälä 
555f453ba04SDave Airlie 	crtc_resp->gamma_size = crtc->gamma_size;
556de7b6be7SDaniel Stone 
55764c32b49SVille Syrjälä 	drm_modeset_lock(&plane->mutex, NULL);
55864c32b49SVille Syrjälä 	if (plane->state && plane->state->fb)
55964c32b49SVille Syrjälä 		crtc_resp->fb_id = plane->state->fb->base.id;
56064c32b49SVille Syrjälä 	else if (!plane->state && plane->fb)
56164c32b49SVille Syrjälä 		crtc_resp->fb_id = plane->fb->base.id;
562f453ba04SDave Airlie 	else
563f453ba04SDave Airlie 		crtc_resp->fb_id = 0;
564f453ba04SDave Airlie 
56564c32b49SVille Syrjälä 	if (plane->state) {
56664c32b49SVille Syrjälä 		crtc_resp->x = plane->state->src_x >> 16;
56764c32b49SVille Syrjälä 		crtc_resp->y = plane->state->src_y >> 16;
5682c77bb29SDaniel Vetter 	}
56964c32b49SVille Syrjälä 	drm_modeset_unlock(&plane->mutex);
5702c77bb29SDaniel Vetter 
5712c77bb29SDaniel Vetter 	drm_modeset_lock(&crtc->mutex, NULL);
5722c77bb29SDaniel Vetter 	if (crtc->state) {
57331c946e8SDaniel Vetter 		if (crtc->state->enable) {
574934a8a89SDaniel Stone 			drm_mode_convert_to_umode(&crtc_resp->mode, &crtc->state->mode);
57531c946e8SDaniel Vetter 			crtc_resp->mode_valid = 1;
57631c946e8SDaniel Vetter 		} else {
57731c946e8SDaniel Vetter 			crtc_resp->mode_valid = 0;
57831c946e8SDaniel Vetter 		}
57931c946e8SDaniel Vetter 	} else {
58031c946e8SDaniel Vetter 		crtc_resp->x = crtc->x;
58131c946e8SDaniel Vetter 		crtc_resp->y = crtc->y;
582bf2d5eb9SVille Syrjälä 
58331c946e8SDaniel Vetter 		if (crtc->enabled) {
584934a8a89SDaniel Stone 			drm_mode_convert_to_umode(&crtc_resp->mode, &crtc->mode);
585f453ba04SDave Airlie 			crtc_resp->mode_valid = 1;
586f453ba04SDave Airlie 
587f453ba04SDave Airlie 		} else {
588f453ba04SDave Airlie 			crtc_resp->mode_valid = 0;
589f453ba04SDave Airlie 		}
59031c946e8SDaniel Vetter 	}
591ace5bf0eSAnkit Nautiyal 	if (!file_priv->aspect_ratio_allowed)
592ace5bf0eSAnkit Nautiyal 		crtc_resp->mode.flags &= ~DRM_MODE_FLAG_PIC_AR_MASK;
5932c77bb29SDaniel Vetter 	drm_modeset_unlock(&crtc->mutex);
594f453ba04SDave Airlie 
595baf698b0SDaniel Vetter 	return 0;
596f453ba04SDave Airlie }
597f453ba04SDave Airlie 
__drm_mode_set_config_internal(struct drm_mode_set * set,struct drm_modeset_acquire_ctx * ctx)5982ceb585aSDaniel Vetter static int __drm_mode_set_config_internal(struct drm_mode_set *set,
5992ceb585aSDaniel Vetter 					  struct drm_modeset_acquire_ctx *ctx)
6002d13b679SDaniel Vetter {
6012d13b679SDaniel Vetter 	struct drm_crtc *crtc = set->crtc;
6025cef29aaSDaniel Vetter 	struct drm_framebuffer *fb;
6035cef29aaSDaniel Vetter 	struct drm_crtc *tmp;
604b0d12325SDaniel Vetter 	int ret;
6052d13b679SDaniel Vetter 
60669a8a196SVille Syrjälä 	WARN_ON(drm_drv_uses_atomic_modeset(crtc->dev));
60769a8a196SVille Syrjälä 
6085cef29aaSDaniel Vetter 	/*
6095cef29aaSDaniel Vetter 	 * NOTE: ->set_config can also disable other crtcs (if we steal all
6105cef29aaSDaniel Vetter 	 * connectors from it), hence we need to refcount the fbs across all
6115cef29aaSDaniel Vetter 	 * crtcs. Atomic modeset will have saner semantics ...
6125cef29aaSDaniel Vetter 	 */
6133ed70ecdSVille Syrjälä 	drm_for_each_crtc(tmp, crtc->dev) {
6143ed70ecdSVille Syrjälä 		struct drm_plane *plane = tmp->primary;
6153ed70ecdSVille Syrjälä 
6163ed70ecdSVille Syrjälä 		plane->old_fb = plane->fb;
6173ed70ecdSVille Syrjälä 	}
6185cef29aaSDaniel Vetter 
619b0d12325SDaniel Vetter 	fb = set->fb;
620b0d12325SDaniel Vetter 
621a4eff9aaSDaniel Vetter 	ret = crtc->funcs->set_config(set, ctx);
622b0d12325SDaniel Vetter 	if (ret == 0) {
623e00fb856SVille Syrjälä 		struct drm_plane *plane = crtc->primary;
624e00fb856SVille Syrjälä 
625e00fb856SVille Syrjälä 		plane->crtc = fb ? crtc : NULL;
626e00fb856SVille Syrjälä 		plane->fb = fb;
627e00fb856SVille Syrjälä 	}
628cc85e121SDaniel Vetter 
629e4f62546SDaniel Vetter 	drm_for_each_crtc(tmp, crtc->dev) {
6303ed70ecdSVille Syrjälä 		struct drm_plane *plane = tmp->primary;
6313ed70ecdSVille Syrjälä 
6323ed70ecdSVille Syrjälä 		if (plane->fb)
6333ed70ecdSVille Syrjälä 			drm_framebuffer_get(plane->fb);
6343ed70ecdSVille Syrjälä 		if (plane->old_fb)
6353ed70ecdSVille Syrjälä 			drm_framebuffer_put(plane->old_fb);
6363ed70ecdSVille Syrjälä 		plane->old_fb = NULL;
637b0d12325SDaniel Vetter 	}
638b0d12325SDaniel Vetter 
639b0d12325SDaniel Vetter 	return ret;
6402d13b679SDaniel Vetter }
64169a8a196SVille Syrjälä 
642d49473a5SDaniel Vetter /**
643d49473a5SDaniel Vetter  * drm_mode_set_config_internal - helper to call &drm_mode_config_funcs.set_config
644d49473a5SDaniel Vetter  * @set: modeset config to set
645d49473a5SDaniel Vetter  *
646d49473a5SDaniel Vetter  * This is a little helper to wrap internal calls to the
647d49473a5SDaniel Vetter  * &drm_mode_config_funcs.set_config driver interface. The only thing it adds is
648d49473a5SDaniel Vetter  * correct refcounting dance.
649d49473a5SDaniel Vetter  *
650d49473a5SDaniel Vetter  * This should only be used by non-atomic legacy drivers.
651d49473a5SDaniel Vetter  *
652d49473a5SDaniel Vetter  * Returns:
653d49473a5SDaniel Vetter  * Zero on success, negative errno on failure.
654d49473a5SDaniel Vetter  */
drm_mode_set_config_internal(struct drm_mode_set * set)655d49473a5SDaniel Vetter int drm_mode_set_config_internal(struct drm_mode_set *set)
656d49473a5SDaniel Vetter {
657d49473a5SDaniel Vetter 	WARN_ON(drm_drv_uses_atomic_modeset(set->crtc->dev));
658d49473a5SDaniel Vetter 
6592ceb585aSDaniel Vetter 	return __drm_mode_set_config_internal(set, NULL);
660d49473a5SDaniel Vetter }
6612d13b679SDaniel Vetter EXPORT_SYMBOL(drm_mode_set_config_internal);
6622d13b679SDaniel Vetter 
663af93629dSMatt Roper /**
664af93629dSMatt Roper  * drm_crtc_check_viewport - Checks that a framebuffer is big enough for the
665af93629dSMatt Roper  *     CRTC viewport
666af93629dSMatt Roper  * @crtc: CRTC that framebuffer will be displayed on
667af93629dSMatt Roper  * @x: x panning
668af93629dSMatt Roper  * @y: y panning
669af93629dSMatt Roper  * @mode: mode that framebuffer will be displayed under
670af93629dSMatt Roper  * @fb: framebuffer to check size of
671c11e9283SDamien Lespiau  */
drm_crtc_check_viewport(const struct drm_crtc * crtc,int x,int y,const struct drm_display_mode * mode,const struct drm_framebuffer * fb)672af93629dSMatt Roper int drm_crtc_check_viewport(const struct drm_crtc *crtc,
673c11e9283SDamien Lespiau 			    int x, int y,
674c11e9283SDamien Lespiau 			    const struct drm_display_mode *mode,
675c11e9283SDamien Lespiau 			    const struct drm_framebuffer *fb)
676c11e9283SDamien Lespiau 
677c11e9283SDamien Lespiau {
678c11e9283SDamien Lespiau 	int hdisplay, vdisplay;
679c11e9283SDamien Lespiau 
680196cd5d3SDaniel Vetter 	drm_mode_get_hv_timing(mode, &hdisplay, &vdisplay);
681a0c1bbb0SDamien Lespiau 
68233e0be63SVille Syrjälä 	if (crtc->state &&
683bd2ef25dSVille Syrjälä 	    drm_rotation_90_or_270(crtc->primary->state->rotation))
684c11e9283SDamien Lespiau 		swap(hdisplay, vdisplay);
685c11e9283SDamien Lespiau 
68643968d7bSDaniel Vetter 	return drm_framebuffer_check_src_coords(x << 16, y << 16,
68743968d7bSDaniel Vetter 						hdisplay << 16, vdisplay << 16,
68843968d7bSDaniel Vetter 						fb);
689c11e9283SDamien Lespiau }
690af93629dSMatt Roper EXPORT_SYMBOL(drm_crtc_check_viewport);
691c11e9283SDamien Lespiau 
6922d13b679SDaniel Vetter /**
693f453ba04SDave Airlie  * drm_mode_setcrtc - set CRTC configuration
694065a50edSDaniel Vetter  * @dev: drm device for the ioctl
695065a50edSDaniel Vetter  * @data: data pointer for the ioctl
696065a50edSDaniel Vetter  * @file_priv: drm file for the ioctl call
697f453ba04SDave Airlie  *
698f453ba04SDave Airlie  * Build a new CRTC configuration based on user request.
699f453ba04SDave Airlie  *
700f453ba04SDave Airlie  * Called by the user via ioctl.
701f453ba04SDave Airlie  *
702c8e32cc1SDaniel Vetter  * Returns:
7031a498633SDaniel Vetter  * Zero on success, negative errno on failure.
704f453ba04SDave Airlie  */
drm_mode_setcrtc(struct drm_device * dev,void * data,struct drm_file * file_priv)705f453ba04SDave Airlie int drm_mode_setcrtc(struct drm_device *dev, void *data,
706f453ba04SDave Airlie 		     struct drm_file *file_priv)
707f453ba04SDave Airlie {
708f453ba04SDave Airlie 	struct drm_mode_config *config = &dev->mode_config;
709f453ba04SDave Airlie 	struct drm_mode_crtc *crtc_req = data;
7106653cc8dSVille Syrjälä 	struct drm_crtc *crtc;
71164c32b49SVille Syrjälä 	struct drm_plane *plane;
712c232e9f4SSean Paul 	struct drm_connector **connector_set = NULL, *connector;
713c232e9f4SSean Paul 	struct drm_framebuffer *fb = NULL;
714c232e9f4SSean Paul 	struct drm_display_mode *mode = NULL;
715f453ba04SDave Airlie 	struct drm_mode_set set;
716f453ba04SDave Airlie 	uint32_t __user *set_connectors_ptr;
7172ceb585aSDaniel Vetter 	struct drm_modeset_acquire_ctx ctx;
718*7e881af7SJani Nikula 	int ret, i, num_connectors = 0;
719f453ba04SDave Airlie 
720fb3b06c8SDave Airlie 	if (!drm_core_check_feature(dev, DRIVER_MODESET))
72169fdf420SChris Wilson 		return -EOPNOTSUPP;
722fb3b06c8SDave Airlie 
72301447e9fSZhao Junwang 	/*
72401447e9fSZhao Junwang 	 * Universal plane src offsets are only 16.16, prevent havoc for
72501447e9fSZhao Junwang 	 * drivers using universal plane code internally.
72601447e9fSZhao Junwang 	 */
72701447e9fSZhao Junwang 	if (crtc_req->x & 0xffff0000 || crtc_req->y & 0xffff0000)
7281d97e915SVille Syrjälä 		return -ERANGE;
7291d97e915SVille Syrjälä 
730418da172SKeith Packard 	crtc = drm_crtc_find(dev, file_priv, crtc_req->crtc_id);
731a2b34e22SRob Clark 	if (!crtc) {
73258367ed6SZhao Yakui 		DRM_DEBUG_KMS("Unknown CRTC ID %d\n", crtc_req->crtc_id);
7332ceb585aSDaniel Vetter 		return -ENOENT;
734f453ba04SDave Airlie 	}
735fa3ab4c2SVille Syrjälä 	DRM_DEBUG_KMS("[CRTC:%d:%s]\n", crtc->base.id, crtc->name);
736f453ba04SDave Airlie 
73764c32b49SVille Syrjälä 	plane = crtc->primary;
73864c32b49SVille Syrjälä 
739204f640dSDaniel Vetter 	/* allow disabling with the primary plane leased */
740204f640dSDaniel Vetter 	if (crtc_req->mode_valid && !drm_lease_held(file_priv, plane->base.id))
741204f640dSDaniel Vetter 		return -EACCES;
742204f640dSDaniel Vetter 
743b7ea04d2SSean Paul 	DRM_MODESET_LOCK_ALL_BEGIN(dev, ctx,
744b7ea04d2SSean Paul 				   DRM_MODESET_ACQUIRE_INTERRUPTIBLE, ret);
745bf2d5eb9SVille Syrjälä 
746f453ba04SDave Airlie 	if (crtc_req->mode_valid) {
747f453ba04SDave Airlie 		/* If we have a mode we need a framebuffer. */
748f453ba04SDave Airlie 		/* If we pass -1, set the mode with the currently bound fb */
749f453ba04SDave Airlie 		if (crtc_req->fb_id == -1) {
750a36c027dSVille Syrjälä 			struct drm_framebuffer *old_fb;
751a36c027dSVille Syrjälä 
752a36c027dSVille Syrjälä 			if (plane->state)
753a36c027dSVille Syrjälä 				old_fb = plane->state->fb;
754a36c027dSVille Syrjälä 			else
755a36c027dSVille Syrjälä 				old_fb = plane->fb;
756a36c027dSVille Syrjälä 
757a36c027dSVille Syrjälä 			if (!old_fb) {
7586653cc8dSVille Syrjälä 				DRM_DEBUG_KMS("CRTC doesn't have current FB\n");
7596653cc8dSVille Syrjälä 				ret = -EINVAL;
7606653cc8dSVille Syrjälä 				goto out;
7616653cc8dSVille Syrjälä 			}
762bf2d5eb9SVille Syrjälä 
763a36c027dSVille Syrjälä 			fb = old_fb;
764b0d12325SDaniel Vetter 			/* Make refcounting symmetric with the lookup path. */
765a4a69da0SThierry Reding 			drm_framebuffer_get(fb);
766f453ba04SDave Airlie 		} else {
767418da172SKeith Packard 			fb = drm_framebuffer_lookup(dev, file_priv, crtc_req->fb_id);
768786b99edSDaniel Vetter 			if (!fb) {
76958367ed6SZhao Yakui 				DRM_DEBUG_KMS("Unknown FB ID%d\n",
77058367ed6SZhao Yakui 						crtc_req->fb_id);
77137c4e705SVille Syrjälä 				ret = -ENOENT;
772f453ba04SDave Airlie 				goto out;
773f453ba04SDave Airlie 			}
774f453ba04SDave Airlie 		}
775f453ba04SDave Airlie 
776f453ba04SDave Airlie 		mode = drm_mode_create(dev);
777ee34ab5bSVille Syrjälä 		if (!mode) {
778ee34ab5bSVille Syrjälä 			ret = -ENOMEM;
779ee34ab5bSVille Syrjälä 			goto out;
780ee34ab5bSVille Syrjälä 		}
781ace5bf0eSAnkit Nautiyal 		if (!file_priv->aspect_ratio_allowed &&
782ace5bf0eSAnkit Nautiyal 		    (crtc_req->mode.flags & DRM_MODE_FLAG_PIC_AR_MASK) != DRM_MODE_FLAG_PIC_AR_NONE) {
783ace5bf0eSAnkit Nautiyal 			DRM_DEBUG_KMS("Unexpected aspect-ratio flag bits\n");
784ace5bf0eSAnkit Nautiyal 			ret = -EINVAL;
785ace5bf0eSAnkit Nautiyal 			goto out;
786ace5bf0eSAnkit Nautiyal 		}
787ace5bf0eSAnkit Nautiyal 
788ee34ab5bSVille Syrjälä 
78975a655e0SVille Syrjälä 		ret = drm_mode_convert_umode(dev, mode, &crtc_req->mode);
79090367bf6SVille Syrjälä 		if (ret) {
7916ab0edf4SVille Syrjälä 			DRM_DEBUG_KMS("Invalid mode (ret=%d, status=%s)\n",
7926ab0edf4SVille Syrjälä 				      ret, drm_get_mode_status_name(mode->status));
7936ab0edf4SVille Syrjälä 			drm_mode_debug_printmodeline(mode);
79490367bf6SVille Syrjälä 			goto out;
79590367bf6SVille Syrjälä 		}
79690367bf6SVille Syrjälä 
7977eb5f302SLaurent Pinchart 		/*
7987eb5f302SLaurent Pinchart 		 * Check whether the primary plane supports the fb pixel format.
7997eb5f302SLaurent Pinchart 		 * Drivers not implementing the universal planes API use a
8007eb5f302SLaurent Pinchart 		 * default formats list provided by the DRM core which doesn't
8017eb5f302SLaurent Pinchart 		 * match real hardware capabilities. Skip the check in that
8027eb5f302SLaurent Pinchart 		 * case.
8037eb5f302SLaurent Pinchart 		 */
80464c32b49SVille Syrjälä 		if (!plane->format_default) {
80564c32b49SVille Syrjälä 			ret = drm_plane_check_pixel_format(plane,
80623163a7dSVille Syrjälä 							   fb->format->format,
80723163a7dSVille Syrjälä 							   fb->modifier);
8087eb5f302SLaurent Pinchart 			if (ret) {
80992f1d09cSSakari Ailus 				DRM_DEBUG_KMS("Invalid pixel format %p4cc, modifier 0x%llx\n",
81092f1d09cSSakari Ailus 					      &fb->format->format,
81123163a7dSVille Syrjälä 					      fb->modifier);
8127eb5f302SLaurent Pinchart 				goto out;
8137eb5f302SLaurent Pinchart 			}
8147eb5f302SLaurent Pinchart 		}
8157eb5f302SLaurent Pinchart 
816c11e9283SDamien Lespiau 		ret = drm_crtc_check_viewport(crtc, crtc_req->x, crtc_req->y,
817c11e9283SDamien Lespiau 					      mode, fb);
818c11e9283SDamien Lespiau 		if (ret)
8195f61bb42SVille Syrjälä 			goto out;
820c11e9283SDamien Lespiau 
821f453ba04SDave Airlie 	}
822f453ba04SDave Airlie 
823f453ba04SDave Airlie 	if (crtc_req->count_connectors == 0 && mode) {
82458367ed6SZhao Yakui 		DRM_DEBUG_KMS("Count connectors is 0 but mode set\n");
825f453ba04SDave Airlie 		ret = -EINVAL;
826f453ba04SDave Airlie 		goto out;
827f453ba04SDave Airlie 	}
828f453ba04SDave Airlie 
8297781de74SJakob Bornecrantz 	if (crtc_req->count_connectors > 0 && (!mode || !fb)) {
83058367ed6SZhao Yakui 		DRM_DEBUG_KMS("Count connectors is %d but no mode or fb set\n",
831f453ba04SDave Airlie 			  crtc_req->count_connectors);
832f453ba04SDave Airlie 		ret = -EINVAL;
833f453ba04SDave Airlie 		goto out;
834f453ba04SDave Airlie 	}
835f453ba04SDave Airlie 
836f453ba04SDave Airlie 	if (crtc_req->count_connectors > 0) {
837f453ba04SDave Airlie 		u32 out_id;
838f453ba04SDave Airlie 
839f453ba04SDave Airlie 		/* Avoid unbounded kernel memory allocation */
840f453ba04SDave Airlie 		if (crtc_req->count_connectors > config->num_connector) {
841f453ba04SDave Airlie 			ret = -EINVAL;
842f453ba04SDave Airlie 			goto out;
843f453ba04SDave Airlie 		}
844f453ba04SDave Airlie 
8452f6c5389SThierry Reding 		connector_set = kmalloc_array(crtc_req->count_connectors,
846f453ba04SDave Airlie 					      sizeof(struct drm_connector *),
847f453ba04SDave Airlie 					      GFP_KERNEL);
848f453ba04SDave Airlie 		if (!connector_set) {
849f453ba04SDave Airlie 			ret = -ENOMEM;
850f453ba04SDave Airlie 			goto out;
851f453ba04SDave Airlie 		}
852f453ba04SDave Airlie 
853f453ba04SDave Airlie 		for (i = 0; i < crtc_req->count_connectors; i++) {
854b164d31fSDave Airlie 			connector_set[i] = NULL;
85581f6c7f8SVille Syrjälä 			set_connectors_ptr = (uint32_t __user *)(unsigned long)crtc_req->set_connectors_ptr;
856f453ba04SDave Airlie 			if (get_user(out_id, &set_connectors_ptr[i])) {
857f453ba04SDave Airlie 				ret = -EFAULT;
858f453ba04SDave Airlie 				goto out;
859f453ba04SDave Airlie 			}
860f453ba04SDave Airlie 
861418da172SKeith Packard 			connector = drm_connector_lookup(dev, file_priv, out_id);
862a2b34e22SRob Clark 			if (!connector) {
86358367ed6SZhao Yakui 				DRM_DEBUG_KMS("Connector id %d unknown\n",
86458367ed6SZhao Yakui 						out_id);
865f27657f2SVille Syrjälä 				ret = -ENOENT;
866f453ba04SDave Airlie 				goto out;
867f453ba04SDave Airlie 			}
8689440106bSJerome Glisse 			DRM_DEBUG_KMS("[CONNECTOR:%d:%s]\n",
8699440106bSJerome Glisse 					connector->base.id,
87025933820SJani Nikula 					connector->name);
871f453ba04SDave Airlie 
872f453ba04SDave Airlie 			connector_set[i] = connector;
873ff89e507SZiqi Zhao 			num_connectors++;
874f453ba04SDave Airlie 		}
875f453ba04SDave Airlie 	}
876f453ba04SDave Airlie 
877f453ba04SDave Airlie 	set.crtc = crtc;
878f453ba04SDave Airlie 	set.x = crtc_req->x;
879f453ba04SDave Airlie 	set.y = crtc_req->y;
880f453ba04SDave Airlie 	set.mode = mode;
881f453ba04SDave Airlie 	set.connectors = connector_set;
882ff89e507SZiqi Zhao 	set.num_connectors = num_connectors;
883f453ba04SDave Airlie 	set.fb = fb;
88469a8a196SVille Syrjälä 
88569a8a196SVille Syrjälä 	if (drm_drv_uses_atomic_modeset(dev))
88669a8a196SVille Syrjälä 		ret = crtc->funcs->set_config(&set, &ctx);
88769a8a196SVille Syrjälä 	else
8882ceb585aSDaniel Vetter 		ret = __drm_mode_set_config_internal(&set, &ctx);
889f453ba04SDave Airlie 
890f453ba04SDave Airlie out:
891b0d12325SDaniel Vetter 	if (fb)
892a4a69da0SThierry Reding 		drm_framebuffer_put(fb);
893b0d12325SDaniel Vetter 
894b164d31fSDave Airlie 	if (connector_set) {
895ff89e507SZiqi Zhao 		for (i = 0; i < num_connectors; i++) {
896b164d31fSDave Airlie 			if (connector_set[i])
897ad093607SThierry Reding 				drm_connector_put(connector_set[i]);
898b164d31fSDave Airlie 		}
899b164d31fSDave Airlie 	}
900f453ba04SDave Airlie 	kfree(connector_set);
901ee34ab5bSVille Syrjälä 	drm_mode_destroy(dev, mode);
902c232e9f4SSean Paul 
903c232e9f4SSean Paul 	/* In case we need to retry... */
904c232e9f4SSean Paul 	connector_set = NULL;
905c232e9f4SSean Paul 	fb = NULL;
906c232e9f4SSean Paul 	mode = NULL;
907c232e9f4SSean Paul 
90877ef3857SDaniel Vetter 	DRM_MODESET_LOCK_ALL_END(dev, ctx, ret);
9092ceb585aSDaniel Vetter 
910f453ba04SDave Airlie 	return ret;
911f453ba04SDave Airlie }
912f453ba04SDave Airlie 
drm_mode_crtc_set_obj_prop(struct drm_mode_object * obj,struct drm_property * property,uint64_t value)913949619f3SDaniel Vetter int drm_mode_crtc_set_obj_prop(struct drm_mode_object *obj,
914bffd9de0SPaulo Zanoni 			       struct drm_property *property,
915bffd9de0SPaulo Zanoni 			       uint64_t value)
916bffd9de0SPaulo Zanoni {
917bffd9de0SPaulo Zanoni 	int ret = -EINVAL;
918bffd9de0SPaulo Zanoni 	struct drm_crtc *crtc = obj_to_crtc(obj);
919bffd9de0SPaulo Zanoni 
920bffd9de0SPaulo Zanoni 	if (crtc->funcs->set_property)
921bffd9de0SPaulo Zanoni 		ret = crtc->funcs->set_property(crtc, property, value);
922144a7999SDaniel Vetter 	if (!ret)
923bffd9de0SPaulo Zanoni 		drm_object_property_set_value(obj, property, value);
924bffd9de0SPaulo Zanoni 
925bffd9de0SPaulo Zanoni 	return ret;
926bffd9de0SPaulo Zanoni }
9275c759edaSPankaj Bharadiya 
9285c759edaSPankaj Bharadiya /**
9295c759edaSPankaj Bharadiya  * drm_crtc_create_scaling_filter_property - create a new scaling filter
9305c759edaSPankaj Bharadiya  * property
9315c759edaSPankaj Bharadiya  *
9325c759edaSPankaj Bharadiya  * @crtc: drm CRTC
9335c759edaSPankaj Bharadiya  * @supported_filters: bitmask of supported scaling filters, must include
9345c759edaSPankaj Bharadiya  *		       BIT(DRM_SCALING_FILTER_DEFAULT).
9355c759edaSPankaj Bharadiya  *
9365c759edaSPankaj Bharadiya  * This function lets driver to enable the scaling filter property on a given
9375c759edaSPankaj Bharadiya  * CRTC.
9385c759edaSPankaj Bharadiya  *
9395c759edaSPankaj Bharadiya  * RETURNS:
9405c759edaSPankaj Bharadiya  * Zero for success or -errno
9415c759edaSPankaj Bharadiya  */
drm_crtc_create_scaling_filter_property(struct drm_crtc * crtc,unsigned int supported_filters)9425c759edaSPankaj Bharadiya int drm_crtc_create_scaling_filter_property(struct drm_crtc *crtc,
9435c759edaSPankaj Bharadiya 					    unsigned int supported_filters)
9445c759edaSPankaj Bharadiya {
9455c759edaSPankaj Bharadiya 	struct drm_property *prop =
9465c759edaSPankaj Bharadiya 		drm_create_scaling_filter_prop(crtc->dev, supported_filters);
9475c759edaSPankaj Bharadiya 
9485c759edaSPankaj Bharadiya 	if (IS_ERR(prop))
9495c759edaSPankaj Bharadiya 		return PTR_ERR(prop);
9505c759edaSPankaj Bharadiya 
9515c759edaSPankaj Bharadiya 	drm_object_attach_property(&crtc->base, prop,
9525c759edaSPankaj Bharadiya 				   DRM_SCALING_FILTER_DEFAULT);
9535c759edaSPankaj Bharadiya 	crtc->scaling_filter_property = prop;
9545c759edaSPankaj Bharadiya 
9555c759edaSPankaj Bharadiya 	return 0;
9565c759edaSPankaj Bharadiya }
9575c759edaSPankaj Bharadiya EXPORT_SYMBOL(drm_crtc_create_scaling_filter_property);
958