xref: /openbmc/linux/drivers/gpu/drm/drm_crtc.c (revision c7e1c59a)
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>
36760285e7SDavid Howells #include <drm/drmP.h>
37760285e7SDavid Howells #include <drm/drm_crtc.h>
38760285e7SDavid Howells #include <drm/drm_edid.h>
39760285e7SDavid Howells #include <drm/drm_fourcc.h>
4051fd371bSRob Clark #include <drm/drm_modeset_lock.h>
4188a48e29SRob Clark #include <drm/drm_atomic.h>
42f453ba04SDave Airlie 
438bd441b2SDaniel Vetter #include "drm_crtc_internal.h"
4467d0ec4eSDaniel Vetter #include "drm_internal.h"
458bd441b2SDaniel Vetter 
469a6f5130SChris Wilson static struct drm_framebuffer *
479a6f5130SChris Wilson internal_framebuffer_create(struct drm_device *dev,
481eb83451SVille Syrjälä 			    const struct drm_mode_fb_cmd2 *r,
49c394c2b0SMatt Roper 			    struct drm_file *file_priv);
50c394c2b0SMatt Roper 
51f453ba04SDave Airlie /* Avoid boilerplate.  I'm tired of typing. */
52f453ba04SDave Airlie #define DRM_ENUM_NAME_FN(fnname, list)				\
53d20d3174SVille Syrjälä 	const char *fnname(int val)				\
54f453ba04SDave Airlie 	{							\
55f453ba04SDave Airlie 		int i;						\
56f453ba04SDave Airlie 		for (i = 0; i < ARRAY_SIZE(list); i++) {	\
57f453ba04SDave Airlie 			if (list[i].type == val)		\
58f453ba04SDave Airlie 				return list[i].name;		\
59f453ba04SDave Airlie 		}						\
60f453ba04SDave Airlie 		return "(unknown)";				\
61f453ba04SDave Airlie 	}
62f453ba04SDave Airlie 
63f453ba04SDave Airlie /*
64f453ba04SDave Airlie  * Global properties
65f453ba04SDave Airlie  */
664dfd909fSThierry Reding static const struct drm_prop_enum_list drm_dpms_enum_list[] = {
674dfd909fSThierry Reding 	{ DRM_MODE_DPMS_ON, "On" },
68f453ba04SDave Airlie 	{ DRM_MODE_DPMS_STANDBY, "Standby" },
69f453ba04SDave Airlie 	{ DRM_MODE_DPMS_SUSPEND, "Suspend" },
70f453ba04SDave Airlie 	{ DRM_MODE_DPMS_OFF, "Off" }
71f453ba04SDave Airlie };
72f453ba04SDave Airlie 
73f453ba04SDave Airlie DRM_ENUM_NAME_FN(drm_get_dpms_name, drm_dpms_enum_list)
74f453ba04SDave Airlie 
754dfd909fSThierry Reding static const struct drm_prop_enum_list drm_plane_type_enum_list[] = {
769922ab5aSRob Clark 	{ DRM_PLANE_TYPE_OVERLAY, "Overlay" },
779922ab5aSRob Clark 	{ DRM_PLANE_TYPE_PRIMARY, "Primary" },
789922ab5aSRob Clark 	{ DRM_PLANE_TYPE_CURSOR, "Cursor" },
799922ab5aSRob Clark };
809922ab5aSRob Clark 
81f453ba04SDave Airlie /*
82f453ba04SDave Airlie  * Optional properties
83f453ba04SDave Airlie  */
844dfd909fSThierry Reding static const struct drm_prop_enum_list drm_scaling_mode_enum_list[] = {
8553bd8389SJesse Barnes 	{ DRM_MODE_SCALE_NONE, "None" },
8653bd8389SJesse Barnes 	{ DRM_MODE_SCALE_FULLSCREEN, "Full" },
8753bd8389SJesse Barnes 	{ DRM_MODE_SCALE_CENTER, "Center" },
8853bd8389SJesse Barnes 	{ DRM_MODE_SCALE_ASPECT, "Full aspect" },
89f453ba04SDave Airlie };
90f453ba04SDave Airlie 
91ff587e45SVandana Kannan static const struct drm_prop_enum_list drm_aspect_ratio_enum_list[] = {
92ff587e45SVandana Kannan 	{ DRM_MODE_PICTURE_ASPECT_NONE, "Automatic" },
93ff587e45SVandana Kannan 	{ DRM_MODE_PICTURE_ASPECT_4_3, "4:3" },
94ff587e45SVandana Kannan 	{ DRM_MODE_PICTURE_ASPECT_16_9, "16:9" },
95ff587e45SVandana Kannan };
96ff587e45SVandana Kannan 
97f453ba04SDave Airlie /*
98f453ba04SDave Airlie  * Non-global properties, but "required" for certain connectors.
99f453ba04SDave Airlie  */
1004dfd909fSThierry Reding static const struct drm_prop_enum_list drm_dvi_i_select_enum_list[] = {
101f453ba04SDave Airlie 	{ DRM_MODE_SUBCONNECTOR_Automatic, "Automatic" }, /* DVI-I and TV-out */
102f453ba04SDave Airlie 	{ DRM_MODE_SUBCONNECTOR_DVID,      "DVI-D"     }, /* DVI-I  */
103f453ba04SDave Airlie 	{ DRM_MODE_SUBCONNECTOR_DVIA,      "DVI-A"     }, /* DVI-I  */
104f453ba04SDave Airlie };
105f453ba04SDave Airlie 
106f453ba04SDave Airlie DRM_ENUM_NAME_FN(drm_get_dvi_i_select_name, drm_dvi_i_select_enum_list)
107f453ba04SDave Airlie 
1084dfd909fSThierry Reding static const struct drm_prop_enum_list drm_dvi_i_subconnector_enum_list[] = {
109f453ba04SDave Airlie 	{ DRM_MODE_SUBCONNECTOR_Unknown,   "Unknown"   }, /* DVI-I and TV-out */
110f453ba04SDave Airlie 	{ DRM_MODE_SUBCONNECTOR_DVID,      "DVI-D"     }, /* DVI-I  */
111f453ba04SDave Airlie 	{ DRM_MODE_SUBCONNECTOR_DVIA,      "DVI-A"     }, /* DVI-I  */
112f453ba04SDave Airlie };
113f453ba04SDave Airlie 
114f453ba04SDave Airlie DRM_ENUM_NAME_FN(drm_get_dvi_i_subconnector_name,
115f453ba04SDave Airlie 		 drm_dvi_i_subconnector_enum_list)
116f453ba04SDave Airlie 
1174dfd909fSThierry Reding static const struct drm_prop_enum_list drm_tv_select_enum_list[] = {
118f453ba04SDave Airlie 	{ DRM_MODE_SUBCONNECTOR_Automatic, "Automatic" }, /* DVI-I and TV-out */
119f453ba04SDave Airlie 	{ DRM_MODE_SUBCONNECTOR_Composite, "Composite" }, /* TV-out */
120f453ba04SDave Airlie 	{ DRM_MODE_SUBCONNECTOR_SVIDEO,    "SVIDEO"    }, /* TV-out */
121f453ba04SDave Airlie 	{ DRM_MODE_SUBCONNECTOR_Component, "Component" }, /* TV-out */
122aeaa1ad3SFrancisco Jerez 	{ DRM_MODE_SUBCONNECTOR_SCART,     "SCART"     }, /* TV-out */
123f453ba04SDave Airlie };
124f453ba04SDave Airlie 
125f453ba04SDave Airlie DRM_ENUM_NAME_FN(drm_get_tv_select_name, drm_tv_select_enum_list)
126f453ba04SDave Airlie 
1274dfd909fSThierry Reding static const struct drm_prop_enum_list drm_tv_subconnector_enum_list[] = {
128f453ba04SDave Airlie 	{ DRM_MODE_SUBCONNECTOR_Unknown,   "Unknown"   }, /* DVI-I and TV-out */
129f453ba04SDave Airlie 	{ DRM_MODE_SUBCONNECTOR_Composite, "Composite" }, /* TV-out */
130f453ba04SDave Airlie 	{ DRM_MODE_SUBCONNECTOR_SVIDEO,    "SVIDEO"    }, /* TV-out */
131f453ba04SDave Airlie 	{ DRM_MODE_SUBCONNECTOR_Component, "Component" }, /* TV-out */
132aeaa1ad3SFrancisco Jerez 	{ DRM_MODE_SUBCONNECTOR_SCART,     "SCART"     }, /* TV-out */
133f453ba04SDave Airlie };
134f453ba04SDave Airlie 
135f453ba04SDave Airlie DRM_ENUM_NAME_FN(drm_get_tv_subconnector_name,
136f453ba04SDave Airlie 		 drm_tv_subconnector_enum_list)
137f453ba04SDave Airlie 
138d20d3174SVille Syrjälä static const struct drm_prop_enum_list drm_dirty_info_enum_list[] = {
139884840aaSJakob Bornecrantz 	{ DRM_MODE_DIRTY_OFF,      "Off"      },
140884840aaSJakob Bornecrantz 	{ DRM_MODE_DIRTY_ON,       "On"       },
141884840aaSJakob Bornecrantz 	{ DRM_MODE_DIRTY_ANNOTATE, "Annotate" },
142884840aaSJakob Bornecrantz };
143884840aaSJakob Bornecrantz 
144f453ba04SDave Airlie struct drm_conn_prop_enum_list {
145f453ba04SDave Airlie 	int type;
146d20d3174SVille Syrjälä 	const char *name;
147b21e3afeSIlia Mirkin 	struct ida ida;
148f453ba04SDave Airlie };
149f453ba04SDave Airlie 
150f453ba04SDave Airlie /*
151f453ba04SDave Airlie  * Connector and encoder types.
152f453ba04SDave Airlie  */
1534dfd909fSThierry Reding static struct drm_conn_prop_enum_list drm_connector_enum_list[] = {
1544dfd909fSThierry Reding 	{ DRM_MODE_CONNECTOR_Unknown, "Unknown" },
155b21e3afeSIlia Mirkin 	{ DRM_MODE_CONNECTOR_VGA, "VGA" },
156b21e3afeSIlia Mirkin 	{ DRM_MODE_CONNECTOR_DVII, "DVI-I" },
157b21e3afeSIlia Mirkin 	{ DRM_MODE_CONNECTOR_DVID, "DVI-D" },
158b21e3afeSIlia Mirkin 	{ DRM_MODE_CONNECTOR_DVIA, "DVI-A" },
159b21e3afeSIlia Mirkin 	{ DRM_MODE_CONNECTOR_Composite, "Composite" },
160b21e3afeSIlia Mirkin 	{ DRM_MODE_CONNECTOR_SVIDEO, "SVIDEO" },
161b21e3afeSIlia Mirkin 	{ DRM_MODE_CONNECTOR_LVDS, "LVDS" },
162b21e3afeSIlia Mirkin 	{ DRM_MODE_CONNECTOR_Component, "Component" },
163b21e3afeSIlia Mirkin 	{ DRM_MODE_CONNECTOR_9PinDIN, "DIN" },
164b21e3afeSIlia Mirkin 	{ DRM_MODE_CONNECTOR_DisplayPort, "DP" },
165b21e3afeSIlia Mirkin 	{ DRM_MODE_CONNECTOR_HDMIA, "HDMI-A" },
166b21e3afeSIlia Mirkin 	{ DRM_MODE_CONNECTOR_HDMIB, "HDMI-B" },
167b21e3afeSIlia Mirkin 	{ DRM_MODE_CONNECTOR_TV, "TV" },
168b21e3afeSIlia Mirkin 	{ DRM_MODE_CONNECTOR_eDP, "eDP" },
169b21e3afeSIlia Mirkin 	{ DRM_MODE_CONNECTOR_VIRTUAL, "Virtual" },
170b8923273SShobhit Kumar 	{ DRM_MODE_CONNECTOR_DSI, "DSI" },
171f453ba04SDave Airlie };
172f453ba04SDave Airlie 
1734dfd909fSThierry Reding static const struct drm_prop_enum_list drm_encoder_enum_list[] = {
1744dfd909fSThierry Reding 	{ DRM_MODE_ENCODER_NONE, "None" },
175f453ba04SDave Airlie 	{ DRM_MODE_ENCODER_DAC, "DAC" },
176f453ba04SDave Airlie 	{ DRM_MODE_ENCODER_TMDS, "TMDS" },
177f453ba04SDave Airlie 	{ DRM_MODE_ENCODER_LVDS, "LVDS" },
178f453ba04SDave Airlie 	{ DRM_MODE_ENCODER_TVDAC, "TV" },
179a7331e5cSThomas Hellstrom 	{ DRM_MODE_ENCODER_VIRTUAL, "Virtual" },
180b8923273SShobhit Kumar 	{ DRM_MODE_ENCODER_DSI, "DSI" },
181182407a6SDave Airlie 	{ DRM_MODE_ENCODER_DPMST, "DP MST" },
182f453ba04SDave Airlie };
183f453ba04SDave Airlie 
1844dfd909fSThierry Reding static const struct drm_prop_enum_list drm_subpixel_enum_list[] = {
185ac1bb36cSJesse Barnes 	{ SubPixelUnknown, "Unknown" },
186ac1bb36cSJesse Barnes 	{ SubPixelHorizontalRGB, "Horizontal RGB" },
187ac1bb36cSJesse Barnes 	{ SubPixelHorizontalBGR, "Horizontal BGR" },
188ac1bb36cSJesse Barnes 	{ SubPixelVerticalRGB, "Vertical RGB" },
189ac1bb36cSJesse Barnes 	{ SubPixelVerticalBGR, "Vertical BGR" },
190ac1bb36cSJesse Barnes 	{ SubPixelNone, "None" },
191ac1bb36cSJesse Barnes };
192ac1bb36cSJesse Barnes 
193b21e3afeSIlia Mirkin void drm_connector_ida_init(void)
194b21e3afeSIlia Mirkin {
195b21e3afeSIlia Mirkin 	int i;
196b21e3afeSIlia Mirkin 
197b21e3afeSIlia Mirkin 	for (i = 0; i < ARRAY_SIZE(drm_connector_enum_list); i++)
198b21e3afeSIlia Mirkin 		ida_init(&drm_connector_enum_list[i].ida);
199b21e3afeSIlia Mirkin }
200b21e3afeSIlia Mirkin 
201b21e3afeSIlia Mirkin void drm_connector_ida_destroy(void)
202b21e3afeSIlia Mirkin {
203b21e3afeSIlia Mirkin 	int i;
204b21e3afeSIlia Mirkin 
205b21e3afeSIlia Mirkin 	for (i = 0; i < ARRAY_SIZE(drm_connector_enum_list); i++)
206b21e3afeSIlia Mirkin 		ida_destroy(&drm_connector_enum_list[i].ida);
207b21e3afeSIlia Mirkin }
208b21e3afeSIlia Mirkin 
209c8e32cc1SDaniel Vetter /**
210c8e32cc1SDaniel Vetter  * drm_get_connector_status_name - return a string for connector status
211c8e32cc1SDaniel Vetter  * @status: connector status to compute name of
212c8e32cc1SDaniel Vetter  *
213c8e32cc1SDaniel Vetter  * In contrast to the other drm_get_*_name functions this one here returns a
214c8e32cc1SDaniel Vetter  * const pointer and hence is threadsafe.
215c8e32cc1SDaniel Vetter  */
216d20d3174SVille Syrjälä const char *drm_get_connector_status_name(enum drm_connector_status status)
217f453ba04SDave Airlie {
218f453ba04SDave Airlie 	if (status == connector_status_connected)
219f453ba04SDave Airlie 		return "connected";
220f453ba04SDave Airlie 	else if (status == connector_status_disconnected)
221f453ba04SDave Airlie 		return "disconnected";
222f453ba04SDave Airlie 	else
223f453ba04SDave Airlie 		return "unknown";
224f453ba04SDave Airlie }
225ed7951dcSLespiau, Damien EXPORT_SYMBOL(drm_get_connector_status_name);
226f453ba04SDave Airlie 
227ac1bb36cSJesse Barnes /**
228ac1bb36cSJesse Barnes  * drm_get_subpixel_order_name - return a string for a given subpixel enum
229ac1bb36cSJesse Barnes  * @order: enum of subpixel_order
230ac1bb36cSJesse Barnes  *
231ac1bb36cSJesse Barnes  * Note you could abuse this and return something out of bounds, but that
232ac1bb36cSJesse Barnes  * would be a caller error.  No unscrubbed user data should make it here.
233ac1bb36cSJesse Barnes  */
234ac1bb36cSJesse Barnes const char *drm_get_subpixel_order_name(enum subpixel_order order)
235ac1bb36cSJesse Barnes {
236ac1bb36cSJesse Barnes 	return drm_subpixel_enum_list[order].name;
237ac1bb36cSJesse Barnes }
238ac1bb36cSJesse Barnes EXPORT_SYMBOL(drm_get_subpixel_order_name);
239ac1bb36cSJesse Barnes 
2406ba6d03eSVille Syrjälä static char printable_char(int c)
2416ba6d03eSVille Syrjälä {
2426ba6d03eSVille Syrjälä 	return isascii(c) && isprint(c) ? c : '?';
2436ba6d03eSVille Syrjälä }
2446ba6d03eSVille Syrjälä 
245c8e32cc1SDaniel Vetter /**
246c8e32cc1SDaniel Vetter  * drm_get_format_name - return a string for drm fourcc format
247c8e32cc1SDaniel Vetter  * @format: format to compute name of
248c8e32cc1SDaniel Vetter  *
249c8e32cc1SDaniel Vetter  * Note that the buffer used by this function is globally shared and owned by
250c8e32cc1SDaniel Vetter  * the function itself.
251c8e32cc1SDaniel Vetter  *
252c8e32cc1SDaniel Vetter  * FIXME: This isn't really multithreading safe.
253c8e32cc1SDaniel Vetter  */
254d20d3174SVille Syrjälä const char *drm_get_format_name(uint32_t format)
2556ba6d03eSVille Syrjälä {
2566ba6d03eSVille Syrjälä 	static char buf[32];
2576ba6d03eSVille Syrjälä 
2586ba6d03eSVille Syrjälä 	snprintf(buf, sizeof(buf),
2596ba6d03eSVille Syrjälä 		 "%c%c%c%c %s-endian (0x%08x)",
2606ba6d03eSVille Syrjälä 		 printable_char(format & 0xff),
2616ba6d03eSVille Syrjälä 		 printable_char((format >> 8) & 0xff),
2626ba6d03eSVille Syrjälä 		 printable_char((format >> 16) & 0xff),
2636ba6d03eSVille Syrjälä 		 printable_char((format >> 24) & 0x7f),
2646ba6d03eSVille Syrjälä 		 format & DRM_FORMAT_BIG_ENDIAN ? "big" : "little",
2656ba6d03eSVille Syrjälä 		 format);
2666ba6d03eSVille Syrjälä 
2676ba6d03eSVille Syrjälä 	return buf;
2686ba6d03eSVille Syrjälä }
2696ba6d03eSVille Syrjälä EXPORT_SYMBOL(drm_get_format_name);
2706ba6d03eSVille Syrjälä 
2712ee39452SDave Airlie /*
2722ee39452SDave Airlie  * Internal function to assign a slot in the object idr and optionally
2732ee39452SDave Airlie  * register the object into the idr.
2742ee39452SDave Airlie  */
2752ee39452SDave Airlie static int drm_mode_object_get_reg(struct drm_device *dev,
2762ee39452SDave Airlie 				   struct drm_mode_object *obj,
2772ee39452SDave Airlie 				   uint32_t obj_type,
278d0f37cf6SDave Airlie 				   bool register_obj,
279d0f37cf6SDave Airlie 				   void (*obj_free_cb)(struct kref *kref))
2802ee39452SDave Airlie {
2812ee39452SDave Airlie 	int ret;
2822ee39452SDave Airlie 
2832ee39452SDave Airlie 	mutex_lock(&dev->mode_config.idr_mutex);
2842ee39452SDave Airlie 	ret = idr_alloc(&dev->mode_config.crtc_idr, register_obj ? obj : NULL, 1, 0, GFP_KERNEL);
2852ee39452SDave Airlie 	if (ret >= 0) {
2862ee39452SDave Airlie 		/*
2872ee39452SDave Airlie 		 * Set up the object linking under the protection of the idr
2882ee39452SDave Airlie 		 * lock so that other users can't see inconsistent state.
2892ee39452SDave Airlie 		 */
2902ee39452SDave Airlie 		obj->id = ret;
2912ee39452SDave Airlie 		obj->type = obj_type;
292d0f37cf6SDave Airlie 		if (obj_free_cb) {
293d0f37cf6SDave Airlie 			obj->free_cb = obj_free_cb;
294d0f37cf6SDave Airlie 			kref_init(&obj->refcount);
295d0f37cf6SDave Airlie 		}
2962ee39452SDave Airlie 	}
2972ee39452SDave Airlie 	mutex_unlock(&dev->mode_config.idr_mutex);
2982ee39452SDave Airlie 
2992ee39452SDave Airlie 	return ret < 0 ? ret : 0;
3002ee39452SDave Airlie }
3012ee39452SDave Airlie 
302f453ba04SDave Airlie /**
303065a50edSDaniel Vetter  * drm_mode_object_get - allocate a new modeset identifier
304f453ba04SDave Airlie  * @dev: DRM device
305065a50edSDaniel Vetter  * @obj: object pointer, used to generate unique ID
306065a50edSDaniel Vetter  * @obj_type: object type
307f453ba04SDave Airlie  *
308f453ba04SDave Airlie  * Create a unique identifier based on @ptr in @dev's identifier space.  Used
309c8e32cc1SDaniel Vetter  * for tracking modes, CRTCs and connectors. Note that despite the _get postfix
310c8e32cc1SDaniel Vetter  * modeset identifiers are _not_ reference counted. Hence don't use this for
311c8e32cc1SDaniel Vetter  * reference counted modeset objects like framebuffers.
312f453ba04SDave Airlie  *
313c8e32cc1SDaniel Vetter  * Returns:
3143c67d839SLukas Wunner  * Zero on success, error code on failure.
315f453ba04SDave Airlie  */
3168bd441b2SDaniel Vetter int drm_mode_object_get(struct drm_device *dev,
317f453ba04SDave Airlie 			struct drm_mode_object *obj, uint32_t obj_type)
318f453ba04SDave Airlie {
319d0f37cf6SDave Airlie 	return drm_mode_object_get_reg(dev, obj, obj_type, true, NULL);
3204b096ac1SDaniel Vetter }
3214b096ac1SDaniel Vetter 
3222ee39452SDave Airlie static void drm_mode_object_register(struct drm_device *dev,
3232ee39452SDave Airlie 				     struct drm_mode_object *obj)
3242ee39452SDave Airlie {
3252ee39452SDave Airlie 	mutex_lock(&dev->mode_config.idr_mutex);
3262ee39452SDave Airlie 	idr_replace(&dev->mode_config.crtc_idr, obj, obj->id);
3272ee39452SDave Airlie 	mutex_unlock(&dev->mode_config.idr_mutex);
328f453ba04SDave Airlie }
329f453ba04SDave Airlie 
330f453ba04SDave Airlie /**
3317c8f6d25SDave Airlie  * drm_mode_object_unregister - free a modeset identifer
332f453ba04SDave Airlie  * @dev: DRM device
333065a50edSDaniel Vetter  * @object: object to free
334f453ba04SDave Airlie  *
3357c8f6d25SDave Airlie  * Free @id from @dev's unique identifier pool.
3367c8f6d25SDave Airlie  * This function can be called multiple times, and guards against
3377c8f6d25SDave Airlie  * multiple removals.
3387c8f6d25SDave Airlie  * These modeset identifiers are _not_ reference counted. Hence don't use this
339c8e32cc1SDaniel Vetter  * for reference counted modeset objects like framebuffers.
340f453ba04SDave Airlie  */
3417c8f6d25SDave Airlie void drm_mode_object_unregister(struct drm_device *dev,
342f453ba04SDave Airlie 			 struct drm_mode_object *object)
343f453ba04SDave Airlie {
344ad2563c2SJesse Barnes 	mutex_lock(&dev->mode_config.idr_mutex);
3457c8f6d25SDave Airlie 	if (object->id) {
346f453ba04SDave Airlie 		idr_remove(&dev->mode_config.crtc_idr, object->id);
3477c8f6d25SDave Airlie 		object->id = 0;
3487c8f6d25SDave Airlie 	}
349ad2563c2SJesse Barnes 	mutex_unlock(&dev->mode_config.idr_mutex);
350f453ba04SDave Airlie }
351f453ba04SDave Airlie 
35298f75de4SRob Clark static struct drm_mode_object *_object_find(struct drm_device *dev,
35398f75de4SRob Clark 		uint32_t id, uint32_t type)
35498f75de4SRob Clark {
35598f75de4SRob Clark 	struct drm_mode_object *obj = NULL;
35698f75de4SRob Clark 
35798f75de4SRob Clark 	mutex_lock(&dev->mode_config.idr_mutex);
35898f75de4SRob Clark 	obj = idr_find(&dev->mode_config.crtc_idr, id);
359168c02ecSDaniel Vetter 	if (obj && type != DRM_MODE_OBJECT_ANY && obj->type != type)
360168c02ecSDaniel Vetter 		obj = NULL;
361168c02ecSDaniel Vetter 	if (obj && obj->id != id)
362168c02ecSDaniel Vetter 		obj = NULL;
363168c02ecSDaniel Vetter 	/* don't leak out unref'd fb's */
3646bcacf51SDaniel Stone 	if (obj &&
365cee26ac4SDave Airlie 	    obj->type == DRM_MODE_OBJECT_BLOB)
36698f75de4SRob Clark 		obj = NULL;
36798f75de4SRob Clark 	mutex_unlock(&dev->mode_config.idr_mutex);
36898f75de4SRob Clark 
36998f75de4SRob Clark 	return obj;
37098f75de4SRob Clark }
37198f75de4SRob Clark 
372786b99edSDaniel Vetter /**
373786b99edSDaniel Vetter  * drm_mode_object_find - look up a drm object with static lifetime
374786b99edSDaniel Vetter  * @dev: drm device
375786b99edSDaniel Vetter  * @id: id of the mode object
376786b99edSDaniel Vetter  * @type: type of the mode object
377786b99edSDaniel Vetter  *
378786b99edSDaniel Vetter  * Note that framebuffers cannot be looked up with this functions - since those
37998f75de4SRob Clark  * are reference counted, they need special treatment.  Even with
38098f75de4SRob Clark  * DRM_MODE_OBJECT_ANY (although that will simply return NULL
38198f75de4SRob Clark  * rather than WARN_ON()).
382786b99edSDaniel Vetter  */
3837a9c9060SDaniel Vetter struct drm_mode_object *drm_mode_object_find(struct drm_device *dev,
3847a9c9060SDaniel Vetter 		uint32_t id, uint32_t type)
385f453ba04SDave Airlie {
386ad2563c2SJesse Barnes 	struct drm_mode_object *obj = NULL;
387f453ba04SDave Airlie 
388786b99edSDaniel Vetter 	/* Framebuffers are reference counted and need their own lookup
389786b99edSDaniel Vetter 	 * function.*/
3906bcacf51SDaniel Stone 	WARN_ON(type == DRM_MODE_OBJECT_FB || type == DRM_MODE_OBJECT_BLOB);
39198f75de4SRob Clark 	obj = _object_find(dev, id, type);
392f453ba04SDave Airlie 	return obj;
393f453ba04SDave Airlie }
394f453ba04SDave Airlie EXPORT_SYMBOL(drm_mode_object_find);
395f453ba04SDave Airlie 
396d0f37cf6SDave Airlie void drm_mode_object_unreference(struct drm_mode_object *obj)
397d0f37cf6SDave Airlie {
398d0f37cf6SDave Airlie 	if (obj->free_cb) {
399d0f37cf6SDave Airlie 		DRM_DEBUG("OBJ ID: %d (%d)\n", obj->id, atomic_read(&obj->refcount.refcount));
400d0f37cf6SDave Airlie 		kref_put(&obj->refcount, obj->free_cb);
401d0f37cf6SDave Airlie 	}
402d0f37cf6SDave Airlie }
403d0f37cf6SDave Airlie EXPORT_SYMBOL(drm_mode_object_unreference);
404d0f37cf6SDave Airlie 
405d0f37cf6SDave Airlie /**
406d0f37cf6SDave Airlie  * drm_mode_object_reference - incr the fb refcnt
407d0f37cf6SDave Airlie  * @obj: mode_object
408d0f37cf6SDave Airlie  *
409d0f37cf6SDave Airlie  * This function operates only on refcounted objects.
410d0f37cf6SDave Airlie  * This functions increments the object's refcount.
411d0f37cf6SDave Airlie  */
412d0f37cf6SDave Airlie void drm_mode_object_reference(struct drm_mode_object *obj)
413d0f37cf6SDave Airlie {
414d0f37cf6SDave Airlie 	if (obj->free_cb) {
415d0f37cf6SDave Airlie 		DRM_DEBUG("OBJ ID: %d (%d)\n", obj->id, atomic_read(&obj->refcount.refcount));
416d0f37cf6SDave Airlie 		kref_get(&obj->refcount);
417d0f37cf6SDave Airlie 	}
418d0f37cf6SDave Airlie }
419d0f37cf6SDave Airlie EXPORT_SYMBOL(drm_mode_object_reference);
420d0f37cf6SDave Airlie 
421f55f1f91SDave Airlie static void drm_framebuffer_free(struct kref *kref)
422f55f1f91SDave Airlie {
423f55f1f91SDave Airlie 	struct drm_framebuffer *fb =
424d0f37cf6SDave Airlie 			container_of(kref, struct drm_framebuffer, base.refcount);
425f55f1f91SDave Airlie 	struct drm_device *dev = fb->dev;
426f55f1f91SDave Airlie 
427f55f1f91SDave Airlie 	/*
428f55f1f91SDave Airlie 	 * The lookup idr holds a weak reference, which has not necessarily been
429f55f1f91SDave Airlie 	 * removed at this point. Check for that.
430f55f1f91SDave Airlie 	 */
431f55f1f91SDave Airlie 	mutex_lock(&dev->mode_config.fb_lock);
43219ab3f8bSDave Airlie 	drm_mode_object_unregister(dev, &fb->base);
433f55f1f91SDave Airlie 	mutex_unlock(&dev->mode_config.fb_lock);
434f55f1f91SDave Airlie 
435f55f1f91SDave Airlie 	fb->funcs->destroy(fb);
436f55f1f91SDave Airlie }
437f55f1f91SDave Airlie 
438f453ba04SDave Airlie /**
439f453ba04SDave Airlie  * drm_framebuffer_init - initialize a framebuffer
440f453ba04SDave Airlie  * @dev: DRM device
441065a50edSDaniel Vetter  * @fb: framebuffer to be initialized
442065a50edSDaniel Vetter  * @funcs: ... with these functions
443f453ba04SDave Airlie  *
444f453ba04SDave Airlie  * Allocates an ID for the framebuffer's parent mode object, sets its mode
445f453ba04SDave Airlie  * functions & device file and adds it to the master fd list.
446f453ba04SDave Airlie  *
4474b096ac1SDaniel Vetter  * IMPORTANT:
4484b096ac1SDaniel Vetter  * This functions publishes the fb and makes it available for concurrent access
4494b096ac1SDaniel Vetter  * by other users. Which means by this point the fb _must_ be fully set up -
4504b096ac1SDaniel Vetter  * since all the fb attributes are invariant over its lifetime, no further
4514b096ac1SDaniel Vetter  * locking but only correct reference counting is required.
4524b096ac1SDaniel Vetter  *
453c8e32cc1SDaniel Vetter  * Returns:
454af901ca1SAndré Goddard Rosa  * Zero on success, error code on failure.
455f453ba04SDave Airlie  */
456f453ba04SDave Airlie int drm_framebuffer_init(struct drm_device *dev, struct drm_framebuffer *fb,
457f453ba04SDave Airlie 			 const struct drm_framebuffer_funcs *funcs)
458f453ba04SDave Airlie {
459f453ba04SDave Airlie 	int ret;
460f453ba04SDave Airlie 
4614b096ac1SDaniel Vetter 	INIT_LIST_HEAD(&fb->filp_head);
4624b096ac1SDaniel Vetter 	fb->dev = dev;
4634b096ac1SDaniel Vetter 	fb->funcs = funcs;
464f7eff60eSRob Clark 
465d0f37cf6SDave Airlie 	ret = drm_mode_object_get_reg(dev, &fb->base, DRM_MODE_OBJECT_FB,
4669cd47424SDave Airlie 				      false, drm_framebuffer_free);
4676bfc56aaSVille Syrjälä 	if (ret)
4684b096ac1SDaniel Vetter 		goto out;
469f453ba04SDave Airlie 
4709cd47424SDave Airlie 	mutex_lock(&dev->mode_config.fb_lock);
471f453ba04SDave Airlie 	dev->mode_config.num_fb++;
472f453ba04SDave Airlie 	list_add(&fb->head, &dev->mode_config.fb_list);
473f453ba04SDave Airlie 
4749cd47424SDave Airlie 	drm_mode_object_register(dev, &fb->base);
4759cd47424SDave Airlie 	mutex_unlock(&dev->mode_config.fb_lock);
4769cd47424SDave Airlie out:
4773c67d839SLukas Wunner 	return ret;
478f453ba04SDave Airlie }
479f453ba04SDave Airlie EXPORT_SYMBOL(drm_framebuffer_init);
480f453ba04SDave Airlie 
481f7eff60eSRob Clark /**
482786b99edSDaniel Vetter  * drm_framebuffer_lookup - look up a drm framebuffer and grab a reference
483786b99edSDaniel Vetter  * @dev: drm device
484786b99edSDaniel Vetter  * @id: id of the fb object
485786b99edSDaniel Vetter  *
486786b99edSDaniel Vetter  * If successful, this grabs an additional reference to the framebuffer -
487786b99edSDaniel Vetter  * callers need to make sure to eventually unreference the returned framebuffer
488c8e32cc1SDaniel Vetter  * again, using @drm_framebuffer_unreference.
489786b99edSDaniel Vetter  */
490786b99edSDaniel Vetter struct drm_framebuffer *drm_framebuffer_lookup(struct drm_device *dev,
491786b99edSDaniel Vetter 					       uint32_t id)
492786b99edSDaniel Vetter {
493cee26ac4SDave Airlie 	struct drm_mode_object *obj;
494cee26ac4SDave Airlie 	struct drm_framebuffer *fb = NULL;
495786b99edSDaniel Vetter 
496786b99edSDaniel Vetter 	mutex_lock(&dev->mode_config.fb_lock);
497cee26ac4SDave Airlie 	obj = _object_find(dev, id, DRM_MODE_OBJECT_FB);
498cee26ac4SDave Airlie 	if (obj) {
499cee26ac4SDave Airlie 		fb = obj_to_fb(obj);
500d0f37cf6SDave Airlie 		if (!kref_get_unless_zero(&fb->base.refcount))
50183f45fc3SDaniel Vetter 			fb = NULL;
50283f45fc3SDaniel Vetter 	}
503786b99edSDaniel Vetter 	mutex_unlock(&dev->mode_config.fb_lock);
504786b99edSDaniel Vetter 
505786b99edSDaniel Vetter 	return fb;
506786b99edSDaniel Vetter }
507786b99edSDaniel Vetter EXPORT_SYMBOL(drm_framebuffer_lookup);
508786b99edSDaniel Vetter 
509786b99edSDaniel Vetter /**
51036206361SDaniel Vetter  * drm_framebuffer_unregister_private - unregister a private fb from the lookup idr
51136206361SDaniel Vetter  * @fb: fb to unregister
51236206361SDaniel Vetter  *
51336206361SDaniel Vetter  * Drivers need to call this when cleaning up driver-private framebuffers, e.g.
51436206361SDaniel Vetter  * those used for fbdev. Note that the caller must hold a reference of it's own,
51536206361SDaniel Vetter  * i.e. the object may not be destroyed through this call (since it'll lead to a
51636206361SDaniel Vetter  * locking inversion).
51736206361SDaniel Vetter  */
51836206361SDaniel Vetter void drm_framebuffer_unregister_private(struct drm_framebuffer *fb)
51936206361SDaniel Vetter {
520a39a357cSDaniel Vetter 	struct drm_device *dev;
521a39a357cSDaniel Vetter 
522a39a357cSDaniel Vetter 	if (!fb)
523a39a357cSDaniel Vetter 		return;
524a39a357cSDaniel Vetter 
525a39a357cSDaniel Vetter 	dev = fb->dev;
5262b677e8cSDaniel Vetter 
5272b677e8cSDaniel Vetter 	mutex_lock(&dev->mode_config.fb_lock);
5282b677e8cSDaniel Vetter 	/* Mark fb as reaped and drop idr ref. */
52919ab3f8bSDave Airlie 	drm_mode_object_unregister(dev, &fb->base);
5302b677e8cSDaniel Vetter 	mutex_unlock(&dev->mode_config.fb_lock);
53136206361SDaniel Vetter }
53236206361SDaniel Vetter EXPORT_SYMBOL(drm_framebuffer_unregister_private);
53336206361SDaniel Vetter 
53436206361SDaniel Vetter /**
535f453ba04SDave Airlie  * drm_framebuffer_cleanup - remove a framebuffer object
536f453ba04SDave Airlie  * @fb: framebuffer to remove
537f453ba04SDave Airlie  *
538c8e32cc1SDaniel Vetter  * Cleanup framebuffer. This function is intended to be used from the drivers
539c8e32cc1SDaniel Vetter  * ->destroy callback. It can also be used to clean up driver private
540c8e32cc1SDaniel Vetter  *  framebuffers embedded into a larger structure.
54136206361SDaniel Vetter  *
54236206361SDaniel Vetter  * Note that this function does not remove the fb from active usuage - if it is
54336206361SDaniel Vetter  * still used anywhere, hilarity can ensue since userspace could call getfb on
54436206361SDaniel Vetter  * the id and get back -EINVAL. Obviously no concern at driver unload time.
54536206361SDaniel Vetter  *
54636206361SDaniel Vetter  * Also, the framebuffer will not be removed from the lookup idr - for
54736206361SDaniel Vetter  * user-created framebuffers this will happen in in the rmfb ioctl. For
54836206361SDaniel Vetter  * driver-private objects (e.g. for fbdev) drivers need to explicitly call
54936206361SDaniel Vetter  * drm_framebuffer_unregister_private.
550f453ba04SDave Airlie  */
551f453ba04SDave Airlie void drm_framebuffer_cleanup(struct drm_framebuffer *fb)
552f453ba04SDave Airlie {
553f453ba04SDave Airlie 	struct drm_device *dev = fb->dev;
5548faf6b18SDaniel Vetter 
5554b096ac1SDaniel Vetter 	mutex_lock(&dev->mode_config.fb_lock);
556f7eff60eSRob Clark 	list_del(&fb->head);
557f7eff60eSRob Clark 	dev->mode_config.num_fb--;
5584b096ac1SDaniel Vetter 	mutex_unlock(&dev->mode_config.fb_lock);
559f7eff60eSRob Clark }
560f7eff60eSRob Clark EXPORT_SYMBOL(drm_framebuffer_cleanup);
561f7eff60eSRob Clark 
562f7eff60eSRob Clark /**
563f7eff60eSRob Clark  * drm_framebuffer_remove - remove and unreference a framebuffer object
564f7eff60eSRob Clark  * @fb: framebuffer to remove
565f7eff60eSRob Clark  *
566f7eff60eSRob Clark  * Scans all the CRTCs and planes in @dev's mode_config.  If they're
56736206361SDaniel Vetter  * using @fb, removes it, setting it to NULL. Then drops the reference to the
568b62584e3SDaniel Vetter  * passed-in framebuffer. Might take the modeset locks.
569b62584e3SDaniel Vetter  *
570b62584e3SDaniel Vetter  * Note that this function optimizes the cleanup away if the caller holds the
571b62584e3SDaniel Vetter  * last reference to the framebuffer. It is also guaranteed to not take the
572b62584e3SDaniel Vetter  * modeset locks in this case.
573f7eff60eSRob Clark  */
574f7eff60eSRob Clark void drm_framebuffer_remove(struct drm_framebuffer *fb)
575f7eff60eSRob Clark {
576a39a357cSDaniel Vetter 	struct drm_device *dev;
577f453ba04SDave Airlie 	struct drm_crtc *crtc;
5788cf5c917SJesse Barnes 	struct drm_plane *plane;
5795ef5f72fSDave Airlie 	struct drm_mode_set set;
5805ef5f72fSDave Airlie 	int ret;
581f453ba04SDave Airlie 
582a39a357cSDaniel Vetter 	if (!fb)
583a39a357cSDaniel Vetter 		return;
584a39a357cSDaniel Vetter 
585a39a357cSDaniel Vetter 	dev = fb->dev;
586a39a357cSDaniel Vetter 
5874b096ac1SDaniel Vetter 	WARN_ON(!list_empty(&fb->filp_head));
5888faf6b18SDaniel Vetter 
589b62584e3SDaniel Vetter 	/*
590b62584e3SDaniel Vetter 	 * drm ABI mandates that we remove any deleted framebuffers from active
591b62584e3SDaniel Vetter 	 * useage. But since most sane clients only remove framebuffers they no
592b62584e3SDaniel Vetter 	 * longer need, try to optimize this away.
593b62584e3SDaniel Vetter 	 *
594b62584e3SDaniel Vetter 	 * Since we're holding a reference ourselves, observing a refcount of 1
595b62584e3SDaniel Vetter 	 * means that we're the last holder and can skip it. Also, the refcount
596b62584e3SDaniel Vetter 	 * can never increase from 1 again, so we don't need any barriers or
597b62584e3SDaniel Vetter 	 * locks.
598b62584e3SDaniel Vetter 	 *
599b62584e3SDaniel Vetter 	 * Note that userspace could try to race with use and instate a new
600b62584e3SDaniel Vetter 	 * usage _after_ we've cleared all current ones. End result will be an
601b62584e3SDaniel Vetter 	 * in-use fb with fb-id == 0. Userspace is allowed to shoot its own foot
602b62584e3SDaniel Vetter 	 * in this manner.
603b62584e3SDaniel Vetter 	 */
604747a598fSDave Airlie 	if (drm_framebuffer_read_refcount(fb) > 1) {
605b62584e3SDaniel Vetter 		drm_modeset_lock_all(dev);
606f453ba04SDave Airlie 		/* remove from any CRTC */
6076295d607SDaniel Vetter 		drm_for_each_crtc(crtc, dev) {
608f4510a27SMatt Roper 			if (crtc->primary->fb == fb) {
6095ef5f72fSDave Airlie 				/* should turn off the crtc */
6105ef5f72fSDave Airlie 				memset(&set, 0, sizeof(struct drm_mode_set));
6115ef5f72fSDave Airlie 				set.crtc = crtc;
6125ef5f72fSDave Airlie 				set.fb = NULL;
6132d13b679SDaniel Vetter 				ret = drm_mode_set_config_internal(&set);
6145ef5f72fSDave Airlie 				if (ret)
6155ef5f72fSDave Airlie 					DRM_ERROR("failed to reset crtc %p when fb was deleted\n", crtc);
6165ef5f72fSDave Airlie 			}
617f453ba04SDave Airlie 		}
618f453ba04SDave Airlie 
6196295d607SDaniel Vetter 		drm_for_each_plane(plane, dev) {
6209125e618SVille Syrjälä 			if (plane->fb == fb)
6219125e618SVille Syrjälä 				drm_plane_force_disable(plane);
6228cf5c917SJesse Barnes 		}
623b62584e3SDaniel Vetter 		drm_modeset_unlock_all(dev);
624b62584e3SDaniel Vetter 	}
6258cf5c917SJesse Barnes 
626f7eff60eSRob Clark 	drm_framebuffer_unreference(fb);
627f453ba04SDave Airlie }
628f7eff60eSRob Clark EXPORT_SYMBOL(drm_framebuffer_remove);
629f453ba04SDave Airlie 
63051fd371bSRob Clark DEFINE_WW_CLASS(crtc_ww_class);
63151fd371bSRob Clark 
632fa3ab4c2SVille Syrjälä static unsigned int drm_num_crtcs(struct drm_device *dev)
633fa3ab4c2SVille Syrjälä {
634fa3ab4c2SVille Syrjälä 	unsigned int num = 0;
635fa3ab4c2SVille Syrjälä 	struct drm_crtc *tmp;
636fa3ab4c2SVille Syrjälä 
637fa3ab4c2SVille Syrjälä 	drm_for_each_crtc(tmp, dev) {
638fa3ab4c2SVille Syrjälä 		num++;
639fa3ab4c2SVille Syrjälä 	}
640fa3ab4c2SVille Syrjälä 
641fa3ab4c2SVille Syrjälä 	return num;
642fa3ab4c2SVille Syrjälä }
643fa3ab4c2SVille Syrjälä 
644f453ba04SDave Airlie /**
645e13161afSMatt Roper  * drm_crtc_init_with_planes - Initialise a new CRTC object with
646e13161afSMatt Roper  *    specified primary and cursor planes.
647f453ba04SDave Airlie  * @dev: DRM device
648f453ba04SDave Airlie  * @crtc: CRTC object to init
649e13161afSMatt Roper  * @primary: Primary plane for CRTC
650e13161afSMatt Roper  * @cursor: Cursor plane for CRTC
651f453ba04SDave Airlie  * @funcs: callbacks for the new CRTC
652f9882876SVille Syrjälä  * @name: printf style format string for the CRTC name, or NULL for default name
653f453ba04SDave Airlie  *
654ad6f5c34SVille Syrjälä  * Inits a new object created as base part of a driver crtc object.
6556bfc56aaSVille Syrjälä  *
656c8e32cc1SDaniel Vetter  * Returns:
6576bfc56aaSVille Syrjälä  * Zero on success, error code on failure.
658f453ba04SDave Airlie  */
659e13161afSMatt Roper int drm_crtc_init_with_planes(struct drm_device *dev, struct drm_crtc *crtc,
660e13161afSMatt Roper 			      struct drm_plane *primary,
661fc1d3e44SMatt Roper 			      struct drm_plane *cursor,
662f9882876SVille Syrjälä 			      const struct drm_crtc_funcs *funcs,
663f9882876SVille Syrjälä 			      const char *name, ...)
664f453ba04SDave Airlie {
66551fd371bSRob Clark 	struct drm_mode_config *config = &dev->mode_config;
6666bfc56aaSVille Syrjälä 	int ret;
6676bfc56aaSVille Syrjälä 
668522cf91fSBenjamin Gaignard 	WARN_ON(primary && primary->type != DRM_PLANE_TYPE_PRIMARY);
669522cf91fSBenjamin Gaignard 	WARN_ON(cursor && cursor->type != DRM_PLANE_TYPE_CURSOR);
670522cf91fSBenjamin Gaignard 
671f453ba04SDave Airlie 	crtc->dev = dev;
672f453ba04SDave Airlie 	crtc->funcs = funcs;
673f453ba04SDave Airlie 
67451fd371bSRob Clark 	drm_modeset_lock_init(&crtc->mutex);
6756bfc56aaSVille Syrjälä 	ret = drm_mode_object_get(dev, &crtc->base, DRM_MODE_OBJECT_CRTC);
6766bfc56aaSVille Syrjälä 	if (ret)
677baf698b0SDaniel Vetter 		return ret;
678f453ba04SDave Airlie 
679fa3ab4c2SVille Syrjälä 	if (name) {
680fa3ab4c2SVille Syrjälä 		va_list ap;
681fa3ab4c2SVille Syrjälä 
682fa3ab4c2SVille Syrjälä 		va_start(ap, name);
683fa3ab4c2SVille Syrjälä 		crtc->name = kvasprintf(GFP_KERNEL, name, ap);
684fa3ab4c2SVille Syrjälä 		va_end(ap);
685fa3ab4c2SVille Syrjälä 	} else {
686fa3ab4c2SVille Syrjälä 		crtc->name = kasprintf(GFP_KERNEL, "crtc-%d",
687fa3ab4c2SVille Syrjälä 				       drm_num_crtcs(dev));
688fa3ab4c2SVille Syrjälä 	}
689fa3ab4c2SVille Syrjälä 	if (!crtc->name) {
6907c8f6d25SDave Airlie 		drm_mode_object_unregister(dev, &crtc->base);
691fa3ab4c2SVille Syrjälä 		return -ENOMEM;
692fa3ab4c2SVille Syrjälä 	}
693fa3ab4c2SVille Syrjälä 
694bffd9de0SPaulo Zanoni 	crtc->base.properties = &crtc->properties;
695bffd9de0SPaulo Zanoni 
69651fd371bSRob Clark 	list_add_tail(&crtc->head, &config->crtc_list);
69751fd371bSRob Clark 	config->num_crtc++;
6986bfc56aaSVille Syrjälä 
699e13161afSMatt Roper 	crtc->primary = primary;
700fc1d3e44SMatt Roper 	crtc->cursor = cursor;
701e13161afSMatt Roper 	if (primary)
702e13161afSMatt Roper 		primary->possible_crtcs = 1 << drm_crtc_index(crtc);
703fc1d3e44SMatt Roper 	if (cursor)
704fc1d3e44SMatt Roper 		cursor->possible_crtcs = 1 << drm_crtc_index(crtc);
705e13161afSMatt Roper 
706eab3bbefSDaniel Vetter 	if (drm_core_check_feature(dev, DRIVER_ATOMIC)) {
707eab3bbefSDaniel Vetter 		drm_object_attach_property(&crtc->base, config->prop_active, 0);
708955f3c33SDaniel Stone 		drm_object_attach_property(&crtc->base, config->prop_mode_id, 0);
709eab3bbefSDaniel Vetter 	}
710eab3bbefSDaniel Vetter 
711baf698b0SDaniel Vetter 	return 0;
712f453ba04SDave Airlie }
713e13161afSMatt Roper EXPORT_SYMBOL(drm_crtc_init_with_planes);
714f453ba04SDave Airlie 
715f453ba04SDave Airlie /**
716ad6f5c34SVille Syrjälä  * drm_crtc_cleanup - Clean up the core crtc usage
717f453ba04SDave Airlie  * @crtc: CRTC to cleanup
718f453ba04SDave Airlie  *
719ad6f5c34SVille Syrjälä  * This function cleans up @crtc and removes it from the DRM mode setting
720ad6f5c34SVille Syrjälä  * core. Note that the function does *not* free the crtc structure itself,
721ad6f5c34SVille Syrjälä  * this is the responsibility of the caller.
722f453ba04SDave Airlie  */
723f453ba04SDave Airlie void drm_crtc_cleanup(struct drm_crtc *crtc)
724f453ba04SDave Airlie {
725f453ba04SDave Airlie 	struct drm_device *dev = crtc->dev;
726f453ba04SDave Airlie 
727f453ba04SDave Airlie 	kfree(crtc->gamma_store);
728f453ba04SDave Airlie 	crtc->gamma_store = NULL;
729f453ba04SDave Airlie 
73051fd371bSRob Clark 	drm_modeset_lock_fini(&crtc->mutex);
73151fd371bSRob Clark 
7327c8f6d25SDave Airlie 	drm_mode_object_unregister(dev, &crtc->base);
733f453ba04SDave Airlie 	list_del(&crtc->head);
734f453ba04SDave Airlie 	dev->mode_config.num_crtc--;
7353009c037SThierry Reding 
7363009c037SThierry Reding 	WARN_ON(crtc->state && !crtc->funcs->atomic_destroy_state);
7373009c037SThierry Reding 	if (crtc->state && crtc->funcs->atomic_destroy_state)
7383009c037SThierry Reding 		crtc->funcs->atomic_destroy_state(crtc, crtc->state);
739a18c0af1SThierry Reding 
740fa3ab4c2SVille Syrjälä 	kfree(crtc->name);
741fa3ab4c2SVille Syrjälä 
742a18c0af1SThierry Reding 	memset(crtc, 0, sizeof(*crtc));
743f453ba04SDave Airlie }
744f453ba04SDave Airlie EXPORT_SYMBOL(drm_crtc_cleanup);
745f453ba04SDave Airlie 
746f453ba04SDave Airlie /**
747db5f7a6eSRussell King  * drm_crtc_index - find the index of a registered CRTC
748db5f7a6eSRussell King  * @crtc: CRTC to find index for
749db5f7a6eSRussell King  *
750db5f7a6eSRussell King  * Given a registered CRTC, return the index of that CRTC within a DRM
751db5f7a6eSRussell King  * device's list of CRTCs.
752db5f7a6eSRussell King  */
753db5f7a6eSRussell King unsigned int drm_crtc_index(struct drm_crtc *crtc)
754db5f7a6eSRussell King {
755db5f7a6eSRussell King 	unsigned int index = 0;
756db5f7a6eSRussell King 	struct drm_crtc *tmp;
757db5f7a6eSRussell King 
758e4f62546SDaniel Vetter 	drm_for_each_crtc(tmp, crtc->dev) {
759db5f7a6eSRussell King 		if (tmp == crtc)
760db5f7a6eSRussell King 			return index;
761db5f7a6eSRussell King 
762db5f7a6eSRussell King 		index++;
763db5f7a6eSRussell King 	}
764db5f7a6eSRussell King 
765db5f7a6eSRussell King 	BUG();
766db5f7a6eSRussell King }
767db5f7a6eSRussell King EXPORT_SYMBOL(drm_crtc_index);
768db5f7a6eSRussell King 
76986f422d5SLespiau, Damien /*
770f453ba04SDave Airlie  * drm_mode_remove - remove and free a mode
771f453ba04SDave Airlie  * @connector: connector list to modify
772f453ba04SDave Airlie  * @mode: mode to remove
773f453ba04SDave Airlie  *
774f453ba04SDave Airlie  * Remove @mode from @connector's mode list, then free it.
775f453ba04SDave Airlie  */
77686f422d5SLespiau, Damien static void drm_mode_remove(struct drm_connector *connector,
777f453ba04SDave Airlie 			    struct drm_display_mode *mode)
778f453ba04SDave Airlie {
779f453ba04SDave Airlie 	list_del(&mode->head);
780554f1d78SSascha Hauer 	drm_mode_destroy(connector->dev, mode);
781f453ba04SDave Airlie }
782f453ba04SDave Airlie 
783f453ba04SDave Airlie /**
784b5571e9dSBoris Brezillon  * drm_display_info_set_bus_formats - set the supported bus formats
785b5571e9dSBoris Brezillon  * @info: display info to store bus formats in
786e37bfa1aSBoris Brezillon  * @formats: array containing the supported bus formats
787e37bfa1aSBoris Brezillon  * @num_formats: the number of entries in the fmts array
788b5571e9dSBoris Brezillon  *
789b5571e9dSBoris Brezillon  * Store the supported bus formats in display info structure.
790b5571e9dSBoris Brezillon  * See MEDIA_BUS_FMT_* definitions in include/uapi/linux/media-bus-format.h for
791b5571e9dSBoris Brezillon  * a full list of available formats.
792b5571e9dSBoris Brezillon  */
793b5571e9dSBoris Brezillon int drm_display_info_set_bus_formats(struct drm_display_info *info,
794b5571e9dSBoris Brezillon 				     const u32 *formats,
795b5571e9dSBoris Brezillon 				     unsigned int num_formats)
796b5571e9dSBoris Brezillon {
797b5571e9dSBoris Brezillon 	u32 *fmts = NULL;
798b5571e9dSBoris Brezillon 
799b5571e9dSBoris Brezillon 	if (!formats && num_formats)
800b5571e9dSBoris Brezillon 		return -EINVAL;
801b5571e9dSBoris Brezillon 
802b5571e9dSBoris Brezillon 	if (formats && num_formats) {
803b5571e9dSBoris Brezillon 		fmts = kmemdup(formats, sizeof(*formats) * num_formats,
804b5571e9dSBoris Brezillon 			       GFP_KERNEL);
805944579c5SDan Carpenter 		if (!fmts)
806b5571e9dSBoris Brezillon 			return -ENOMEM;
807b5571e9dSBoris Brezillon 	}
808b5571e9dSBoris Brezillon 
809b5571e9dSBoris Brezillon 	kfree(info->bus_formats);
810b5571e9dSBoris Brezillon 	info->bus_formats = fmts;
811b5571e9dSBoris Brezillon 	info->num_bus_formats = num_formats;
812b5571e9dSBoris Brezillon 
813b5571e9dSBoris Brezillon 	return 0;
814b5571e9dSBoris Brezillon }
815b5571e9dSBoris Brezillon EXPORT_SYMBOL(drm_display_info_set_bus_formats);
816b5571e9dSBoris Brezillon 
817b5571e9dSBoris Brezillon /**
818eaf99c74SChris Wilson  * drm_connector_get_cmdline_mode - reads the user's cmdline mode
819eaf99c74SChris Wilson  * @connector: connector to quwery
820eaf99c74SChris Wilson  *
821eaf99c74SChris Wilson  * The kernel supports per-connector configration of its consoles through
822eaf99c74SChris Wilson  * use of the video= parameter. This function parses that option and
823eaf99c74SChris Wilson  * extracts the user's specified mode (or enable/disable status) for a
824eaf99c74SChris Wilson  * particular connector. This is typically only used during the early fbdev
825eaf99c74SChris Wilson  * setup.
826eaf99c74SChris Wilson  */
827eaf99c74SChris Wilson static void drm_connector_get_cmdline_mode(struct drm_connector *connector)
828eaf99c74SChris Wilson {
829eaf99c74SChris Wilson 	struct drm_cmdline_mode *mode = &connector->cmdline_mode;
830eaf99c74SChris Wilson 	char *option = NULL;
831eaf99c74SChris Wilson 
832eaf99c74SChris Wilson 	if (fb_get_options(connector->name, &option))
833eaf99c74SChris Wilson 		return;
834eaf99c74SChris Wilson 
835eaf99c74SChris Wilson 	if (!drm_mode_parse_command_line_for_connector(option,
836eaf99c74SChris Wilson 						       connector,
837eaf99c74SChris Wilson 						       mode))
838eaf99c74SChris Wilson 		return;
839eaf99c74SChris Wilson 
840eaf99c74SChris Wilson 	if (mode->force) {
841eaf99c74SChris Wilson 		const char *s;
842eaf99c74SChris Wilson 
843eaf99c74SChris Wilson 		switch (mode->force) {
844eaf99c74SChris Wilson 		case DRM_FORCE_OFF:
845eaf99c74SChris Wilson 			s = "OFF";
846eaf99c74SChris Wilson 			break;
847eaf99c74SChris Wilson 		case DRM_FORCE_ON_DIGITAL:
848eaf99c74SChris Wilson 			s = "ON - dig";
849eaf99c74SChris Wilson 			break;
850eaf99c74SChris Wilson 		default:
851eaf99c74SChris Wilson 		case DRM_FORCE_ON:
852eaf99c74SChris Wilson 			s = "ON";
853eaf99c74SChris Wilson 			break;
854eaf99c74SChris Wilson 		}
855eaf99c74SChris Wilson 
856eaf99c74SChris Wilson 		DRM_INFO("forcing %s connector %s\n", connector->name, s);
857eaf99c74SChris Wilson 		connector->force = mode->force;
858eaf99c74SChris Wilson 	}
859eaf99c74SChris Wilson 
860eaf99c74SChris Wilson 	DRM_DEBUG_KMS("cmdline mode for connector %s %dx%d@%dHz%s%s%s\n",
861eaf99c74SChris Wilson 		      connector->name,
862eaf99c74SChris Wilson 		      mode->xres, mode->yres,
863eaf99c74SChris Wilson 		      mode->refresh_specified ? mode->refresh : 60,
864eaf99c74SChris Wilson 		      mode->rb ? " reduced blanking" : "",
865eaf99c74SChris Wilson 		      mode->margins ? " with margins" : "",
866eaf99c74SChris Wilson 		      mode->interlace ?  " interlaced" : "");
867eaf99c74SChris Wilson }
868eaf99c74SChris Wilson 
869eaf99c74SChris Wilson /**
870f453ba04SDave Airlie  * drm_connector_init - Init a preallocated connector
871f453ba04SDave Airlie  * @dev: DRM device
872f453ba04SDave Airlie  * @connector: the connector to init
873f453ba04SDave Airlie  * @funcs: callbacks for this connector
874065a50edSDaniel Vetter  * @connector_type: user visible type of the connector
875f453ba04SDave Airlie  *
876f453ba04SDave Airlie  * Initialises a preallocated connector. Connectors should be
877f453ba04SDave Airlie  * subclassed as part of driver connector objects.
8786bfc56aaSVille Syrjälä  *
879c8e32cc1SDaniel Vetter  * Returns:
8806bfc56aaSVille Syrjälä  * Zero on success, error code on failure.
881f453ba04SDave Airlie  */
8826bfc56aaSVille Syrjälä int drm_connector_init(struct drm_device *dev,
883f453ba04SDave Airlie 		       struct drm_connector *connector,
884f453ba04SDave Airlie 		       const struct drm_connector_funcs *funcs,
885f453ba04SDave Airlie 		       int connector_type)
886f453ba04SDave Airlie {
887ae16c597SRob Clark 	struct drm_mode_config *config = &dev->mode_config;
8886bfc56aaSVille Syrjälä 	int ret;
889b21e3afeSIlia Mirkin 	struct ida *connector_ida =
890b21e3afeSIlia Mirkin 		&drm_connector_enum_list[connector_type].ida;
8916bfc56aaSVille Syrjälä 
89284849903SDaniel Vetter 	drm_modeset_lock_all(dev);
893f453ba04SDave Airlie 
894d0f37cf6SDave Airlie 	ret = drm_mode_object_get_reg(dev, &connector->base, DRM_MODE_OBJECT_CONNECTOR, false, NULL);
8956bfc56aaSVille Syrjälä 	if (ret)
8962abdd313SJani Nikula 		goto out_unlock;
8976bfc56aaSVille Syrjälä 
8987e3bdf4aSPaulo Zanoni 	connector->base.properties = &connector->properties;
899f453ba04SDave Airlie 	connector->dev = dev;
900f453ba04SDave Airlie 	connector->funcs = funcs;
9015fff80bbSMaarten Lankhorst 
9025fff80bbSMaarten Lankhorst 	connector->connector_id = ida_simple_get(&config->connector_ida, 0, 0, GFP_KERNEL);
9035fff80bbSMaarten Lankhorst 	if (connector->connector_id < 0) {
9045fff80bbSMaarten Lankhorst 		ret = connector->connector_id;
9055fff80bbSMaarten Lankhorst 		goto out_put;
9065fff80bbSMaarten Lankhorst 	}
9075fff80bbSMaarten Lankhorst 
908f453ba04SDave Airlie 	connector->connector_type = connector_type;
909f453ba04SDave Airlie 	connector->connector_type_id =
910b21e3afeSIlia Mirkin 		ida_simple_get(connector_ida, 1, 0, GFP_KERNEL);
911b21e3afeSIlia Mirkin 	if (connector->connector_type_id < 0) {
912b21e3afeSIlia Mirkin 		ret = connector->connector_type_id;
9135fff80bbSMaarten Lankhorst 		goto out_put_id;
914b21e3afeSIlia Mirkin 	}
9152abdd313SJani Nikula 	connector->name =
9162abdd313SJani Nikula 		kasprintf(GFP_KERNEL, "%s-%d",
9172abdd313SJani Nikula 			  drm_connector_enum_list[connector_type].name,
9182abdd313SJani Nikula 			  connector->connector_type_id);
9192abdd313SJani Nikula 	if (!connector->name) {
9202abdd313SJani Nikula 		ret = -ENOMEM;
9215fff80bbSMaarten Lankhorst 		goto out_put_type_id;
9222abdd313SJani Nikula 	}
9232abdd313SJani Nikula 
924f453ba04SDave Airlie 	INIT_LIST_HEAD(&connector->probed_modes);
925f453ba04SDave Airlie 	INIT_LIST_HEAD(&connector->modes);
926f453ba04SDave Airlie 	connector->edid_blob_ptr = NULL;
9275e2cb2f6SDaniel Vetter 	connector->status = connector_status_unknown;
928f453ba04SDave Airlie 
929eaf99c74SChris Wilson 	drm_connector_get_cmdline_mode(connector);
930eaf99c74SChris Wilson 
931c7eb76f4SDaniel Vetter 	/* We should add connectors at the end to avoid upsetting the connector
932c7eb76f4SDaniel Vetter 	 * index too much. */
933ae16c597SRob Clark 	list_add_tail(&connector->head, &config->connector_list);
934ae16c597SRob Clark 	config->num_connector++;
935f453ba04SDave Airlie 
936a7331e5cSThomas Hellstrom 	if (connector_type != DRM_MODE_CONNECTOR_VIRTUAL)
93758495563SRob Clark 		drm_object_attach_property(&connector->base,
938ae16c597SRob Clark 					      config->edid_property,
939a7331e5cSThomas Hellstrom 					      0);
940f453ba04SDave Airlie 
94158495563SRob Clark 	drm_object_attach_property(&connector->base,
942ae16c597SRob Clark 				      config->dpms_property, 0);
943ae16c597SRob Clark 
944ae16c597SRob Clark 	if (drm_core_check_feature(dev, DRIVER_ATOMIC)) {
945ae16c597SRob Clark 		drm_object_attach_property(&connector->base, config->prop_crtc_id, 0);
946ae16c597SRob Clark 	}
947f453ba04SDave Airlie 
94830f65707SThomas Wood 	connector->debugfs_entry = NULL;
9495fff80bbSMaarten Lankhorst out_put_type_id:
9505fff80bbSMaarten Lankhorst 	if (ret)
9515fff80bbSMaarten Lankhorst 		ida_remove(connector_ida, connector->connector_type_id);
9525fff80bbSMaarten Lankhorst out_put_id:
9535fff80bbSMaarten Lankhorst 	if (ret)
9545fff80bbSMaarten Lankhorst 		ida_remove(&config->connector_ida, connector->connector_id);
9552abdd313SJani Nikula out_put:
9562abdd313SJani Nikula 	if (ret)
9577c8f6d25SDave Airlie 		drm_mode_object_unregister(dev, &connector->base);
9582abdd313SJani Nikula 
9592abdd313SJani Nikula out_unlock:
96084849903SDaniel Vetter 	drm_modeset_unlock_all(dev);
9616bfc56aaSVille Syrjälä 
9626bfc56aaSVille Syrjälä 	return ret;
963f453ba04SDave Airlie }
964f453ba04SDave Airlie EXPORT_SYMBOL(drm_connector_init);
965f453ba04SDave Airlie 
966f453ba04SDave Airlie /**
967f453ba04SDave Airlie  * drm_connector_cleanup - cleans up an initialised connector
968f453ba04SDave Airlie  * @connector: connector to cleanup
969f453ba04SDave Airlie  *
970f453ba04SDave Airlie  * Cleans up the connector but doesn't free the object.
971f453ba04SDave Airlie  */
972f453ba04SDave Airlie void drm_connector_cleanup(struct drm_connector *connector)
973f453ba04SDave Airlie {
974f453ba04SDave Airlie 	struct drm_device *dev = connector->dev;
975f453ba04SDave Airlie 	struct drm_display_mode *mode, *t;
976f453ba04SDave Airlie 
97740d9b043SDave Airlie 	if (connector->tile_group) {
97840d9b043SDave Airlie 		drm_mode_put_tile_group(dev, connector->tile_group);
97940d9b043SDave Airlie 		connector->tile_group = NULL;
98040d9b043SDave Airlie 	}
98140d9b043SDave Airlie 
982f453ba04SDave Airlie 	list_for_each_entry_safe(mode, t, &connector->probed_modes, head)
983f453ba04SDave Airlie 		drm_mode_remove(connector, mode);
984f453ba04SDave Airlie 
985f453ba04SDave Airlie 	list_for_each_entry_safe(mode, t, &connector->modes, head)
986f453ba04SDave Airlie 		drm_mode_remove(connector, mode);
987f453ba04SDave Airlie 
988b21e3afeSIlia Mirkin 	ida_remove(&drm_connector_enum_list[connector->connector_type].ida,
989b21e3afeSIlia Mirkin 		   connector->connector_type_id);
990b21e3afeSIlia Mirkin 
9915fff80bbSMaarten Lankhorst 	ida_remove(&dev->mode_config.connector_ida,
9925fff80bbSMaarten Lankhorst 		   connector->connector_id);
9935fff80bbSMaarten Lankhorst 
994b5571e9dSBoris Brezillon 	kfree(connector->display_info.bus_formats);
9957c8f6d25SDave Airlie 	drm_mode_object_unregister(dev, &connector->base);
9962abdd313SJani Nikula 	kfree(connector->name);
9972abdd313SJani Nikula 	connector->name = NULL;
998f453ba04SDave Airlie 	list_del(&connector->head);
9996380c509SJoonyoung Shim 	dev->mode_config.num_connector--;
10003009c037SThierry Reding 
10013009c037SThierry Reding 	WARN_ON(connector->state && !connector->funcs->atomic_destroy_state);
10023009c037SThierry Reding 	if (connector->state && connector->funcs->atomic_destroy_state)
10033009c037SThierry Reding 		connector->funcs->atomic_destroy_state(connector,
10043009c037SThierry Reding 						       connector->state);
1005a18c0af1SThierry Reding 
1006a18c0af1SThierry Reding 	memset(connector, 0, sizeof(*connector));
1007f453ba04SDave Airlie }
1008f453ba04SDave Airlie EXPORT_SYMBOL(drm_connector_cleanup);
1009f453ba04SDave Airlie 
1010c8e32cc1SDaniel Vetter /**
101134ea3d38SThomas Wood  * drm_connector_register - register a connector
101234ea3d38SThomas Wood  * @connector: the connector to register
101334ea3d38SThomas Wood  *
101434ea3d38SThomas Wood  * Register userspace interfaces for a connector
101534ea3d38SThomas Wood  *
101634ea3d38SThomas Wood  * Returns:
101734ea3d38SThomas Wood  * Zero on success, error code on failure.
101834ea3d38SThomas Wood  */
101934ea3d38SThomas Wood int drm_connector_register(struct drm_connector *connector)
102034ea3d38SThomas Wood {
102130f65707SThomas Wood 	int ret;
102230f65707SThomas Wood 
10232ee39452SDave Airlie 	drm_mode_object_register(connector->dev, &connector->base);
10242ee39452SDave Airlie 
102530f65707SThomas Wood 	ret = drm_sysfs_connector_add(connector);
102630f65707SThomas Wood 	if (ret)
102730f65707SThomas Wood 		return ret;
102830f65707SThomas Wood 
102930f65707SThomas Wood 	ret = drm_debugfs_connector_add(connector);
103030f65707SThomas Wood 	if (ret) {
103130f65707SThomas Wood 		drm_sysfs_connector_remove(connector);
103230f65707SThomas Wood 		return ret;
103330f65707SThomas Wood 	}
103430f65707SThomas Wood 
103530f65707SThomas Wood 	return 0;
103634ea3d38SThomas Wood }
103734ea3d38SThomas Wood EXPORT_SYMBOL(drm_connector_register);
103834ea3d38SThomas Wood 
103934ea3d38SThomas Wood /**
104034ea3d38SThomas Wood  * drm_connector_unregister - unregister a connector
104134ea3d38SThomas Wood  * @connector: the connector to unregister
104234ea3d38SThomas Wood  *
104334ea3d38SThomas Wood  * Unregister userspace interfaces for a connector
104434ea3d38SThomas Wood  */
104534ea3d38SThomas Wood void drm_connector_unregister(struct drm_connector *connector)
104634ea3d38SThomas Wood {
104734ea3d38SThomas Wood 	drm_sysfs_connector_remove(connector);
104830f65707SThomas Wood 	drm_debugfs_connector_remove(connector);
104934ea3d38SThomas Wood }
105034ea3d38SThomas Wood EXPORT_SYMBOL(drm_connector_unregister);
105134ea3d38SThomas Wood 
105234ea3d38SThomas Wood /**
105354d2c2daSAlexey Brodkin  * drm_connector_register_all - register all connectors
105454d2c2daSAlexey Brodkin  * @dev: drm device
105554d2c2daSAlexey Brodkin  *
105654d2c2daSAlexey Brodkin  * This function registers all connectors in sysfs and other places so that
105754d2c2daSAlexey Brodkin  * userspace can start to access them. Drivers can call it after calling
105854d2c2daSAlexey Brodkin  * drm_dev_register() to complete the device registration, if they don't call
105954d2c2daSAlexey Brodkin  * drm_connector_register() on each connector individually.
106054d2c2daSAlexey Brodkin  *
106154d2c2daSAlexey Brodkin  * When a device is unplugged and should be removed from userspace access,
106254d2c2daSAlexey Brodkin  * call drm_connector_unregister_all(), which is the inverse of this
106354d2c2daSAlexey Brodkin  * function.
106454d2c2daSAlexey Brodkin  *
106554d2c2daSAlexey Brodkin  * Returns:
106654d2c2daSAlexey Brodkin  * Zero on success, error code on failure.
106754d2c2daSAlexey Brodkin  */
106854d2c2daSAlexey Brodkin int drm_connector_register_all(struct drm_device *dev)
106954d2c2daSAlexey Brodkin {
107054d2c2daSAlexey Brodkin 	struct drm_connector *connector;
107154d2c2daSAlexey Brodkin 	int ret;
107254d2c2daSAlexey Brodkin 
107354d2c2daSAlexey Brodkin 	mutex_lock(&dev->mode_config.mutex);
107454d2c2daSAlexey Brodkin 
107554d2c2daSAlexey Brodkin 	drm_for_each_connector(connector, dev) {
107654d2c2daSAlexey Brodkin 		ret = drm_connector_register(connector);
107754d2c2daSAlexey Brodkin 		if (ret)
107854d2c2daSAlexey Brodkin 			goto err;
107954d2c2daSAlexey Brodkin 	}
108054d2c2daSAlexey Brodkin 
108154d2c2daSAlexey Brodkin 	mutex_unlock(&dev->mode_config.mutex);
108254d2c2daSAlexey Brodkin 
108354d2c2daSAlexey Brodkin 	return 0;
108454d2c2daSAlexey Brodkin 
108554d2c2daSAlexey Brodkin err:
108654d2c2daSAlexey Brodkin 	mutex_unlock(&dev->mode_config.mutex);
108754d2c2daSAlexey Brodkin 	drm_connector_unregister_all(dev);
108854d2c2daSAlexey Brodkin 	return ret;
108954d2c2daSAlexey Brodkin }
109054d2c2daSAlexey Brodkin EXPORT_SYMBOL(drm_connector_register_all);
109154d2c2daSAlexey Brodkin 
109254d2c2daSAlexey Brodkin /**
10936c87e5c3SAlexey Brodkin  * drm_connector_unregister_all - unregister connector userspace interfaces
1094c8e32cc1SDaniel Vetter  * @dev: drm device
1095c8e32cc1SDaniel Vetter  *
10966c87e5c3SAlexey Brodkin  * This functions unregisters all connectors from sysfs and other places so
10976c87e5c3SAlexey Brodkin  * that userspace can no longer access them. Drivers should call this as the
10986c87e5c3SAlexey Brodkin  * first step tearing down the device instace, or when the underlying
10996c87e5c3SAlexey Brodkin  * physical device disappeared (e.g. USB unplug), right before calling
11006c87e5c3SAlexey Brodkin  * drm_dev_unregister().
1101c8e32cc1SDaniel Vetter  */
11026c87e5c3SAlexey Brodkin void drm_connector_unregister_all(struct drm_device *dev)
1103cbc7e221SDave Airlie {
1104cbc7e221SDave Airlie 	struct drm_connector *connector;
1105cbc7e221SDave Airlie 
11069a9f5ce8SDaniel Vetter 	/* FIXME: taking the mode config mutex ends up in a clash with sysfs */
110714ba0031SLaurent Pinchart 	list_for_each_entry(connector, &dev->mode_config.connector_list, head)
110834ea3d38SThomas Wood 		drm_connector_unregister(connector);
1109cbc7e221SDave Airlie }
11106c87e5c3SAlexey Brodkin EXPORT_SYMBOL(drm_connector_unregister_all);
1111cbc7e221SDave Airlie 
1112c8e32cc1SDaniel Vetter /**
1113c8e32cc1SDaniel Vetter  * drm_encoder_init - Init a preallocated encoder
1114c8e32cc1SDaniel Vetter  * @dev: drm device
1115c8e32cc1SDaniel Vetter  * @encoder: the encoder to init
1116c8e32cc1SDaniel Vetter  * @funcs: callbacks for this encoder
1117c8e32cc1SDaniel Vetter  * @encoder_type: user visible type of the encoder
111813a3d91fSVille Syrjälä  * @name: printf style format string for the encoder name, or NULL for default name
1119c8e32cc1SDaniel Vetter  *
1120c8e32cc1SDaniel Vetter  * Initialises a preallocated encoder. Encoder should be
1121c8e32cc1SDaniel Vetter  * subclassed as part of driver encoder objects.
1122c8e32cc1SDaniel Vetter  *
1123c8e32cc1SDaniel Vetter  * Returns:
1124c8e32cc1SDaniel Vetter  * Zero on success, error code on failure.
1125c8e32cc1SDaniel Vetter  */
11266bfc56aaSVille Syrjälä int drm_encoder_init(struct drm_device *dev,
1127f453ba04SDave Airlie 		      struct drm_encoder *encoder,
1128f453ba04SDave Airlie 		      const struct drm_encoder_funcs *funcs,
112913a3d91fSVille Syrjälä 		      int encoder_type, const char *name, ...)
1130f453ba04SDave Airlie {
11316bfc56aaSVille Syrjälä 	int ret;
11326bfc56aaSVille Syrjälä 
113384849903SDaniel Vetter 	drm_modeset_lock_all(dev);
1134f453ba04SDave Airlie 
11356bfc56aaSVille Syrjälä 	ret = drm_mode_object_get(dev, &encoder->base, DRM_MODE_OBJECT_ENCODER);
11366bfc56aaSVille Syrjälä 	if (ret)
1137e5748946SJani Nikula 		goto out_unlock;
1138f453ba04SDave Airlie 
11396bfc56aaSVille Syrjälä 	encoder->dev = dev;
1140f453ba04SDave Airlie 	encoder->encoder_type = encoder_type;
1141f453ba04SDave Airlie 	encoder->funcs = funcs;
114286bf546bSVille Syrjälä 	if (name) {
114386bf546bSVille Syrjälä 		va_list ap;
114486bf546bSVille Syrjälä 
114586bf546bSVille Syrjälä 		va_start(ap, name);
114686bf546bSVille Syrjälä 		encoder->name = kvasprintf(GFP_KERNEL, name, ap);
114786bf546bSVille Syrjälä 		va_end(ap);
114886bf546bSVille Syrjälä 	} else {
1149e5748946SJani Nikula 		encoder->name = kasprintf(GFP_KERNEL, "%s-%d",
1150e5748946SJani Nikula 					  drm_encoder_enum_list[encoder_type].name,
1151e5748946SJani Nikula 					  encoder->base.id);
115286bf546bSVille Syrjälä 	}
1153e5748946SJani Nikula 	if (!encoder->name) {
1154e5748946SJani Nikula 		ret = -ENOMEM;
1155e5748946SJani Nikula 		goto out_put;
1156e5748946SJani Nikula 	}
1157f453ba04SDave Airlie 
1158f453ba04SDave Airlie 	list_add_tail(&encoder->head, &dev->mode_config.encoder_list);
1159f453ba04SDave Airlie 	dev->mode_config.num_encoder++;
1160f453ba04SDave Airlie 
1161e5748946SJani Nikula out_put:
1162e5748946SJani Nikula 	if (ret)
11637c8f6d25SDave Airlie 		drm_mode_object_unregister(dev, &encoder->base);
1164e5748946SJani Nikula 
1165e5748946SJani Nikula out_unlock:
116684849903SDaniel Vetter 	drm_modeset_unlock_all(dev);
11676bfc56aaSVille Syrjälä 
11686bfc56aaSVille Syrjälä 	return ret;
1169f453ba04SDave Airlie }
1170f453ba04SDave Airlie EXPORT_SYMBOL(drm_encoder_init);
1171f453ba04SDave Airlie 
1172c8e32cc1SDaniel Vetter /**
117347d7777fSMaarten Lankhorst  * drm_encoder_index - find the index of a registered encoder
117447d7777fSMaarten Lankhorst  * @encoder: encoder to find index for
117547d7777fSMaarten Lankhorst  *
117647d7777fSMaarten Lankhorst  * Given a registered encoder, return the index of that encoder within a DRM
117747d7777fSMaarten Lankhorst  * device's list of encoders.
117847d7777fSMaarten Lankhorst  */
117947d7777fSMaarten Lankhorst unsigned int drm_encoder_index(struct drm_encoder *encoder)
118047d7777fSMaarten Lankhorst {
118147d7777fSMaarten Lankhorst 	unsigned int index = 0;
118247d7777fSMaarten Lankhorst 	struct drm_encoder *tmp;
118347d7777fSMaarten Lankhorst 
118447d7777fSMaarten Lankhorst 	drm_for_each_encoder(tmp, encoder->dev) {
118547d7777fSMaarten Lankhorst 		if (tmp == encoder)
118647d7777fSMaarten Lankhorst 			return index;
118747d7777fSMaarten Lankhorst 
118847d7777fSMaarten Lankhorst 		index++;
118947d7777fSMaarten Lankhorst 	}
119047d7777fSMaarten Lankhorst 
119147d7777fSMaarten Lankhorst 	BUG();
119247d7777fSMaarten Lankhorst }
119347d7777fSMaarten Lankhorst EXPORT_SYMBOL(drm_encoder_index);
119447d7777fSMaarten Lankhorst 
119547d7777fSMaarten Lankhorst /**
1196c8e32cc1SDaniel Vetter  * drm_encoder_cleanup - cleans up an initialised encoder
1197c8e32cc1SDaniel Vetter  * @encoder: encoder to cleanup
1198c8e32cc1SDaniel Vetter  *
1199c8e32cc1SDaniel Vetter  * Cleans up the encoder but doesn't free the object.
1200c8e32cc1SDaniel Vetter  */
1201f453ba04SDave Airlie void drm_encoder_cleanup(struct drm_encoder *encoder)
1202f453ba04SDave Airlie {
1203f453ba04SDave Airlie 	struct drm_device *dev = encoder->dev;
12044dfd909fSThierry Reding 
120584849903SDaniel Vetter 	drm_modeset_lock_all(dev);
12067c8f6d25SDave Airlie 	drm_mode_object_unregister(dev, &encoder->base);
1207e5748946SJani Nikula 	kfree(encoder->name);
1208f453ba04SDave Airlie 	list_del(&encoder->head);
12096380c509SJoonyoung Shim 	dev->mode_config.num_encoder--;
121084849903SDaniel Vetter 	drm_modeset_unlock_all(dev);
1211a18c0af1SThierry Reding 
1212a18c0af1SThierry Reding 	memset(encoder, 0, sizeof(*encoder));
1213f453ba04SDave Airlie }
1214f453ba04SDave Airlie EXPORT_SYMBOL(drm_encoder_cleanup);
1215f453ba04SDave Airlie 
12169f4c97a2SVille Syrjälä static unsigned int drm_num_planes(struct drm_device *dev)
12179f4c97a2SVille Syrjälä {
12189f4c97a2SVille Syrjälä 	unsigned int num = 0;
12199f4c97a2SVille Syrjälä 	struct drm_plane *tmp;
12209f4c97a2SVille Syrjälä 
12219f4c97a2SVille Syrjälä 	drm_for_each_plane(tmp, dev) {
12229f4c97a2SVille Syrjälä 		num++;
12239f4c97a2SVille Syrjälä 	}
12249f4c97a2SVille Syrjälä 
12259f4c97a2SVille Syrjälä 	return num;
12269f4c97a2SVille Syrjälä }
12279f4c97a2SVille Syrjälä 
122835f2c3aeSVille Syrjälä /**
1229dc415ff9SMatt Roper  * drm_universal_plane_init - Initialize a new universal plane object
123035f2c3aeSVille Syrjälä  * @dev: DRM device
123135f2c3aeSVille Syrjälä  * @plane: plane object to init
123235f2c3aeSVille Syrjälä  * @possible_crtcs: bitmask of possible CRTCs
123335f2c3aeSVille Syrjälä  * @funcs: callbacks for the new plane
123435f2c3aeSVille Syrjälä  * @formats: array of supported formats (%DRM_FORMAT_*)
123535f2c3aeSVille Syrjälä  * @format_count: number of elements in @formats
1236dc415ff9SMatt Roper  * @type: type of plane (overlay, primary, cursor)
1237b0b3b795SVille Syrjälä  * @name: printf style format string for the plane name, or NULL for default name
123835f2c3aeSVille Syrjälä  *
1239dc415ff9SMatt Roper  * Initializes a plane object of type @type.
124035f2c3aeSVille Syrjälä  *
1241c8e32cc1SDaniel Vetter  * Returns:
124235f2c3aeSVille Syrjälä  * Zero on success, error code on failure.
124335f2c3aeSVille Syrjälä  */
1244dc415ff9SMatt Roper int drm_universal_plane_init(struct drm_device *dev, struct drm_plane *plane,
12458cf5c917SJesse Barnes 			     unsigned long possible_crtcs,
12468cf5c917SJesse Barnes 			     const struct drm_plane_funcs *funcs,
124745e3743aSThierry Reding 			     const uint32_t *formats, unsigned int format_count,
1248b0b3b795SVille Syrjälä 			     enum drm_plane_type type,
1249b0b3b795SVille Syrjälä 			     const char *name, ...)
12508cf5c917SJesse Barnes {
12516b4959f4SRob Clark 	struct drm_mode_config *config = &dev->mode_config;
12526bfc56aaSVille Syrjälä 	int ret;
12536bfc56aaSVille Syrjälä 
12546bfc56aaSVille Syrjälä 	ret = drm_mode_object_get(dev, &plane->base, DRM_MODE_OBJECT_PLANE);
12556bfc56aaSVille Syrjälä 	if (ret)
1256baf698b0SDaniel Vetter 		return ret;
12576bfc56aaSVille Syrjälä 
12584d02e2deSDaniel Vetter 	drm_modeset_lock_init(&plane->mutex);
12594d02e2deSDaniel Vetter 
12604d93914aSRob Clark 	plane->base.properties = &plane->properties;
12618cf5c917SJesse Barnes 	plane->dev = dev;
12628cf5c917SJesse Barnes 	plane->funcs = funcs;
12632f6c5389SThierry Reding 	plane->format_types = kmalloc_array(format_count, sizeof(uint32_t),
12648cf5c917SJesse Barnes 					    GFP_KERNEL);
12658cf5c917SJesse Barnes 	if (!plane->format_types) {
12668cf5c917SJesse Barnes 		DRM_DEBUG_KMS("out of memory when allocating plane\n");
12677c8f6d25SDave Airlie 		drm_mode_object_unregister(dev, &plane->base);
1268baf698b0SDaniel Vetter 		return -ENOMEM;
12698cf5c917SJesse Barnes 	}
12708cf5c917SJesse Barnes 
12719f4c97a2SVille Syrjälä 	if (name) {
12729f4c97a2SVille Syrjälä 		va_list ap;
12739f4c97a2SVille Syrjälä 
12749f4c97a2SVille Syrjälä 		va_start(ap, name);
12759f4c97a2SVille Syrjälä 		plane->name = kvasprintf(GFP_KERNEL, name, ap);
12769f4c97a2SVille Syrjälä 		va_end(ap);
12779f4c97a2SVille Syrjälä 	} else {
12789f4c97a2SVille Syrjälä 		plane->name = kasprintf(GFP_KERNEL, "plane-%d",
12799f4c97a2SVille Syrjälä 					drm_num_planes(dev));
12809f4c97a2SVille Syrjälä 	}
12819f4c97a2SVille Syrjälä 	if (!plane->name) {
12829f4c97a2SVille Syrjälä 		kfree(plane->format_types);
12837c8f6d25SDave Airlie 		drm_mode_object_unregister(dev, &plane->base);
12849f4c97a2SVille Syrjälä 		return -ENOMEM;
12859f4c97a2SVille Syrjälä 	}
12869f4c97a2SVille Syrjälä 
1287308e5bcbSJesse Barnes 	memcpy(plane->format_types, formats, format_count * sizeof(uint32_t));
12888cf5c917SJesse Barnes 	plane->format_count = format_count;
12898cf5c917SJesse Barnes 	plane->possible_crtcs = possible_crtcs;
1290dc415ff9SMatt Roper 	plane->type = type;
12918cf5c917SJesse Barnes 
12926b4959f4SRob Clark 	list_add_tail(&plane->head, &config->plane_list);
12936b4959f4SRob Clark 	config->num_total_plane++;
1294e27dde3eSMatt Roper 	if (plane->type == DRM_PLANE_TYPE_OVERLAY)
12956b4959f4SRob Clark 		config->num_overlay_plane++;
12968cf5c917SJesse Barnes 
12979922ab5aSRob Clark 	drm_object_attach_property(&plane->base,
12986b4959f4SRob Clark 				   config->plane_type_property,
12999922ab5aSRob Clark 				   plane->type);
13009922ab5aSRob Clark 
13016b4959f4SRob Clark 	if (drm_core_check_feature(dev, DRIVER_ATOMIC)) {
13026b4959f4SRob Clark 		drm_object_attach_property(&plane->base, config->prop_fb_id, 0);
13036b4959f4SRob Clark 		drm_object_attach_property(&plane->base, config->prop_crtc_id, 0);
13046b4959f4SRob Clark 		drm_object_attach_property(&plane->base, config->prop_crtc_x, 0);
13056b4959f4SRob Clark 		drm_object_attach_property(&plane->base, config->prop_crtc_y, 0);
13066b4959f4SRob Clark 		drm_object_attach_property(&plane->base, config->prop_crtc_w, 0);
13076b4959f4SRob Clark 		drm_object_attach_property(&plane->base, config->prop_crtc_h, 0);
13086b4959f4SRob Clark 		drm_object_attach_property(&plane->base, config->prop_src_x, 0);
13096b4959f4SRob Clark 		drm_object_attach_property(&plane->base, config->prop_src_y, 0);
13106b4959f4SRob Clark 		drm_object_attach_property(&plane->base, config->prop_src_w, 0);
13116b4959f4SRob Clark 		drm_object_attach_property(&plane->base, config->prop_src_h, 0);
13126b4959f4SRob Clark 	}
13136b4959f4SRob Clark 
1314baf698b0SDaniel Vetter 	return 0;
13158cf5c917SJesse Barnes }
1316dc415ff9SMatt Roper EXPORT_SYMBOL(drm_universal_plane_init);
1317dc415ff9SMatt Roper 
1318dc415ff9SMatt Roper /**
1319dc415ff9SMatt Roper  * drm_plane_init - Initialize a legacy plane
1320dc415ff9SMatt Roper  * @dev: DRM device
1321dc415ff9SMatt Roper  * @plane: plane object to init
1322dc415ff9SMatt Roper  * @possible_crtcs: bitmask of possible CRTCs
1323dc415ff9SMatt Roper  * @funcs: callbacks for the new plane
1324dc415ff9SMatt Roper  * @formats: array of supported formats (%DRM_FORMAT_*)
1325dc415ff9SMatt Roper  * @format_count: number of elements in @formats
1326dc415ff9SMatt Roper  * @is_primary: plane type (primary vs overlay)
1327dc415ff9SMatt Roper  *
1328dc415ff9SMatt Roper  * Legacy API to initialize a DRM plane.
1329dc415ff9SMatt Roper  *
1330dc415ff9SMatt Roper  * New drivers should call drm_universal_plane_init() instead.
1331dc415ff9SMatt Roper  *
1332dc415ff9SMatt Roper  * Returns:
1333dc415ff9SMatt Roper  * Zero on success, error code on failure.
1334dc415ff9SMatt Roper  */
1335dc415ff9SMatt Roper int drm_plane_init(struct drm_device *dev, struct drm_plane *plane,
1336dc415ff9SMatt Roper 		   unsigned long possible_crtcs,
1337dc415ff9SMatt Roper 		   const struct drm_plane_funcs *funcs,
133845e3743aSThierry Reding 		   const uint32_t *formats, unsigned int format_count,
1339dc415ff9SMatt Roper 		   bool is_primary)
1340dc415ff9SMatt Roper {
1341dc415ff9SMatt Roper 	enum drm_plane_type type;
1342dc415ff9SMatt Roper 
1343dc415ff9SMatt Roper 	type = is_primary ? DRM_PLANE_TYPE_PRIMARY : DRM_PLANE_TYPE_OVERLAY;
1344dc415ff9SMatt Roper 	return drm_universal_plane_init(dev, plane, possible_crtcs, funcs,
1345b0b3b795SVille Syrjälä 					formats, format_count, type, NULL);
1346dc415ff9SMatt Roper }
13478cf5c917SJesse Barnes EXPORT_SYMBOL(drm_plane_init);
13488cf5c917SJesse Barnes 
134935f2c3aeSVille Syrjälä /**
135035f2c3aeSVille Syrjälä  * drm_plane_cleanup - Clean up the core plane usage
135135f2c3aeSVille Syrjälä  * @plane: plane to cleanup
135235f2c3aeSVille Syrjälä  *
135335f2c3aeSVille Syrjälä  * This function cleans up @plane and removes it from the DRM mode setting
135435f2c3aeSVille Syrjälä  * core. Note that the function does *not* free the plane structure itself,
135535f2c3aeSVille Syrjälä  * this is the responsibility of the caller.
135635f2c3aeSVille Syrjälä  */
13578cf5c917SJesse Barnes void drm_plane_cleanup(struct drm_plane *plane)
13588cf5c917SJesse Barnes {
13598cf5c917SJesse Barnes 	struct drm_device *dev = plane->dev;
13608cf5c917SJesse Barnes 
136184849903SDaniel Vetter 	drm_modeset_lock_all(dev);
13628cf5c917SJesse Barnes 	kfree(plane->format_types);
13637c8f6d25SDave Airlie 	drm_mode_object_unregister(dev, &plane->base);
1364dc415ff9SMatt Roper 
1365dc415ff9SMatt Roper 	BUG_ON(list_empty(&plane->head));
1366dc415ff9SMatt Roper 
13678cf5c917SJesse Barnes 	list_del(&plane->head);
1368e27dde3eSMatt Roper 	dev->mode_config.num_total_plane--;
1369e27dde3eSMatt Roper 	if (plane->type == DRM_PLANE_TYPE_OVERLAY)
1370e27dde3eSMatt Roper 		dev->mode_config.num_overlay_plane--;
137184849903SDaniel Vetter 	drm_modeset_unlock_all(dev);
13723009c037SThierry Reding 
13733009c037SThierry Reding 	WARN_ON(plane->state && !plane->funcs->atomic_destroy_state);
13743009c037SThierry Reding 	if (plane->state && plane->funcs->atomic_destroy_state)
13753009c037SThierry Reding 		plane->funcs->atomic_destroy_state(plane, plane->state);
1376a18c0af1SThierry Reding 
13779f4c97a2SVille Syrjälä 	kfree(plane->name);
13789f4c97a2SVille Syrjälä 
1379a18c0af1SThierry Reding 	memset(plane, 0, sizeof(*plane));
13808cf5c917SJesse Barnes }
13818cf5c917SJesse Barnes EXPORT_SYMBOL(drm_plane_cleanup);
13828cf5c917SJesse Barnes 
138335f2c3aeSVille Syrjälä /**
138410f637bfSDaniel Vetter  * drm_plane_index - find the index of a registered plane
138510f637bfSDaniel Vetter  * @plane: plane to find index for
138610f637bfSDaniel Vetter  *
138710f637bfSDaniel Vetter  * Given a registered plane, return the index of that CRTC within a DRM
138810f637bfSDaniel Vetter  * device's list of planes.
138910f637bfSDaniel Vetter  */
139010f637bfSDaniel Vetter unsigned int drm_plane_index(struct drm_plane *plane)
139110f637bfSDaniel Vetter {
139210f637bfSDaniel Vetter 	unsigned int index = 0;
139310f637bfSDaniel Vetter 	struct drm_plane *tmp;
139410f637bfSDaniel Vetter 
1395e4f62546SDaniel Vetter 	drm_for_each_plane(tmp, plane->dev) {
139610f637bfSDaniel Vetter 		if (tmp == plane)
139710f637bfSDaniel Vetter 			return index;
139810f637bfSDaniel Vetter 
139910f637bfSDaniel Vetter 		index++;
140010f637bfSDaniel Vetter 	}
140110f637bfSDaniel Vetter 
140210f637bfSDaniel Vetter 	BUG();
140310f637bfSDaniel Vetter }
140410f637bfSDaniel Vetter EXPORT_SYMBOL(drm_plane_index);
140510f637bfSDaniel Vetter 
140610f637bfSDaniel Vetter /**
1407f81338a5SChandra Konduru  * drm_plane_from_index - find the registered plane at an index
1408f81338a5SChandra Konduru  * @dev: DRM device
1409f81338a5SChandra Konduru  * @idx: index of registered plane to find for
1410f81338a5SChandra Konduru  *
1411f81338a5SChandra Konduru  * Given a plane index, return the registered plane from DRM device's
1412f81338a5SChandra Konduru  * list of planes with matching index.
1413f81338a5SChandra Konduru  */
1414f81338a5SChandra Konduru struct drm_plane *
1415f81338a5SChandra Konduru drm_plane_from_index(struct drm_device *dev, int idx)
1416f81338a5SChandra Konduru {
1417f81338a5SChandra Konduru 	struct drm_plane *plane;
1418f81338a5SChandra Konduru 	unsigned int i = 0;
1419f81338a5SChandra Konduru 
14206295d607SDaniel Vetter 	drm_for_each_plane(plane, dev) {
1421f81338a5SChandra Konduru 		if (i == idx)
1422f81338a5SChandra Konduru 			return plane;
1423f81338a5SChandra Konduru 		i++;
1424f81338a5SChandra Konduru 	}
1425f81338a5SChandra Konduru 	return NULL;
1426f81338a5SChandra Konduru }
1427f81338a5SChandra Konduru EXPORT_SYMBOL(drm_plane_from_index);
1428f81338a5SChandra Konduru 
1429f81338a5SChandra Konduru /**
143035f2c3aeSVille Syrjälä  * drm_plane_force_disable - Forcibly disable a plane
143135f2c3aeSVille Syrjälä  * @plane: plane to disable
143235f2c3aeSVille Syrjälä  *
143335f2c3aeSVille Syrjälä  * Forces the plane to be disabled.
143435f2c3aeSVille Syrjälä  *
143535f2c3aeSVille Syrjälä  * Used when the plane's current framebuffer is destroyed,
143635f2c3aeSVille Syrjälä  * and when restoring fbdev mode.
143735f2c3aeSVille Syrjälä  */
14389125e618SVille Syrjälä void drm_plane_force_disable(struct drm_plane *plane)
14399125e618SVille Syrjälä {
14409125e618SVille Syrjälä 	int ret;
14419125e618SVille Syrjälä 
14423d30a59bSDaniel Vetter 	if (!plane->fb)
14439125e618SVille Syrjälä 		return;
14449125e618SVille Syrjälä 
14453d30a59bSDaniel Vetter 	plane->old_fb = plane->fb;
14469125e618SVille Syrjälä 	ret = plane->funcs->disable_plane(plane);
1447731cce48SDaniel Vetter 	if (ret) {
14489125e618SVille Syrjälä 		DRM_ERROR("failed to disable plane with busy fb\n");
14493d30a59bSDaniel Vetter 		plane->old_fb = NULL;
1450731cce48SDaniel Vetter 		return;
1451731cce48SDaniel Vetter 	}
14529125e618SVille Syrjälä 	/* disconnect the plane from the fb and crtc: */
1453220dd2bcSDaniel Vetter 	drm_framebuffer_unreference(plane->old_fb);
14543d30a59bSDaniel Vetter 	plane->old_fb = NULL;
14559125e618SVille Syrjälä 	plane->fb = NULL;
14569125e618SVille Syrjälä 	plane->crtc = NULL;
14579125e618SVille Syrjälä }
14589125e618SVille Syrjälä EXPORT_SYMBOL(drm_plane_force_disable);
14599125e618SVille Syrjälä 
14606b4959f4SRob Clark static int drm_mode_create_standard_properties(struct drm_device *dev)
1461f453ba04SDave Airlie {
1462356af0e1SRob Clark 	struct drm_property *prop;
1463f453ba04SDave Airlie 
1464f453ba04SDave Airlie 	/*
1465f453ba04SDave Airlie 	 * Standard properties (apply to all connectors)
1466f453ba04SDave Airlie 	 */
1467356af0e1SRob Clark 	prop = drm_property_create(dev, DRM_MODE_PROP_BLOB |
1468f453ba04SDave Airlie 				   DRM_MODE_PROP_IMMUTABLE,
1469f453ba04SDave Airlie 				   "EDID", 0);
1470356af0e1SRob Clark 	if (!prop)
1471356af0e1SRob Clark 		return -ENOMEM;
1472356af0e1SRob Clark 	dev->mode_config.edid_property = prop;
1473f453ba04SDave Airlie 
1474356af0e1SRob Clark 	prop = drm_property_create_enum(dev, 0,
14754a67d391SSascha Hauer 				   "DPMS", drm_dpms_enum_list,
14764a67d391SSascha Hauer 				   ARRAY_SIZE(drm_dpms_enum_list));
1477356af0e1SRob Clark 	if (!prop)
1478356af0e1SRob Clark 		return -ENOMEM;
1479356af0e1SRob Clark 	dev->mode_config.dpms_property = prop;
1480f453ba04SDave Airlie 
1481356af0e1SRob Clark 	prop = drm_property_create(dev,
148243aba7ebSDave Airlie 				   DRM_MODE_PROP_BLOB |
148343aba7ebSDave Airlie 				   DRM_MODE_PROP_IMMUTABLE,
148443aba7ebSDave Airlie 				   "PATH", 0);
1485356af0e1SRob Clark 	if (!prop)
1486356af0e1SRob Clark 		return -ENOMEM;
1487356af0e1SRob Clark 	dev->mode_config.path_property = prop;
148843aba7ebSDave Airlie 
1489356af0e1SRob Clark 	prop = drm_property_create(dev,
14906f134d7bSDave Airlie 				   DRM_MODE_PROP_BLOB |
14916f134d7bSDave Airlie 				   DRM_MODE_PROP_IMMUTABLE,
14926f134d7bSDave Airlie 				   "TILE", 0);
1493356af0e1SRob Clark 	if (!prop)
1494356af0e1SRob Clark 		return -ENOMEM;
1495356af0e1SRob Clark 	dev->mode_config.tile_property = prop;
14966f134d7bSDave Airlie 
14976b4959f4SRob Clark 	prop = drm_property_create_enum(dev, DRM_MODE_PROP_IMMUTABLE,
14989922ab5aSRob Clark 					"type", drm_plane_type_enum_list,
14999922ab5aSRob Clark 					ARRAY_SIZE(drm_plane_type_enum_list));
15006b4959f4SRob Clark 	if (!prop)
15016b4959f4SRob Clark 		return -ENOMEM;
15026b4959f4SRob Clark 	dev->mode_config.plane_type_property = prop;
15036b4959f4SRob Clark 
15046b4959f4SRob Clark 	prop = drm_property_create_range(dev, DRM_MODE_PROP_ATOMIC,
15056b4959f4SRob Clark 			"SRC_X", 0, UINT_MAX);
15066b4959f4SRob Clark 	if (!prop)
15076b4959f4SRob Clark 		return -ENOMEM;
15086b4959f4SRob Clark 	dev->mode_config.prop_src_x = prop;
15096b4959f4SRob Clark 
15106b4959f4SRob Clark 	prop = drm_property_create_range(dev, DRM_MODE_PROP_ATOMIC,
15116b4959f4SRob Clark 			"SRC_Y", 0, UINT_MAX);
15126b4959f4SRob Clark 	if (!prop)
15136b4959f4SRob Clark 		return -ENOMEM;
15146b4959f4SRob Clark 	dev->mode_config.prop_src_y = prop;
15156b4959f4SRob Clark 
15166b4959f4SRob Clark 	prop = drm_property_create_range(dev, DRM_MODE_PROP_ATOMIC,
15176b4959f4SRob Clark 			"SRC_W", 0, UINT_MAX);
15186b4959f4SRob Clark 	if (!prop)
15196b4959f4SRob Clark 		return -ENOMEM;
15206b4959f4SRob Clark 	dev->mode_config.prop_src_w = prop;
15216b4959f4SRob Clark 
15226b4959f4SRob Clark 	prop = drm_property_create_range(dev, DRM_MODE_PROP_ATOMIC,
15236b4959f4SRob Clark 			"SRC_H", 0, UINT_MAX);
15246b4959f4SRob Clark 	if (!prop)
15256b4959f4SRob Clark 		return -ENOMEM;
15266b4959f4SRob Clark 	dev->mode_config.prop_src_h = prop;
15276b4959f4SRob Clark 
15286b4959f4SRob Clark 	prop = drm_property_create_signed_range(dev, DRM_MODE_PROP_ATOMIC,
15296b4959f4SRob Clark 			"CRTC_X", INT_MIN, INT_MAX);
15306b4959f4SRob Clark 	if (!prop)
15316b4959f4SRob Clark 		return -ENOMEM;
15326b4959f4SRob Clark 	dev->mode_config.prop_crtc_x = prop;
15336b4959f4SRob Clark 
15346b4959f4SRob Clark 	prop = drm_property_create_signed_range(dev, DRM_MODE_PROP_ATOMIC,
15356b4959f4SRob Clark 			"CRTC_Y", INT_MIN, INT_MAX);
15366b4959f4SRob Clark 	if (!prop)
15376b4959f4SRob Clark 		return -ENOMEM;
15386b4959f4SRob Clark 	dev->mode_config.prop_crtc_y = prop;
15396b4959f4SRob Clark 
15406b4959f4SRob Clark 	prop = drm_property_create_range(dev, DRM_MODE_PROP_ATOMIC,
15416b4959f4SRob Clark 			"CRTC_W", 0, INT_MAX);
15426b4959f4SRob Clark 	if (!prop)
15436b4959f4SRob Clark 		return -ENOMEM;
15446b4959f4SRob Clark 	dev->mode_config.prop_crtc_w = prop;
15456b4959f4SRob Clark 
15466b4959f4SRob Clark 	prop = drm_property_create_range(dev, DRM_MODE_PROP_ATOMIC,
15476b4959f4SRob Clark 			"CRTC_H", 0, INT_MAX);
15486b4959f4SRob Clark 	if (!prop)
15496b4959f4SRob Clark 		return -ENOMEM;
15506b4959f4SRob Clark 	dev->mode_config.prop_crtc_h = prop;
15516b4959f4SRob Clark 
15526b4959f4SRob Clark 	prop = drm_property_create_object(dev, DRM_MODE_PROP_ATOMIC,
15536b4959f4SRob Clark 			"FB_ID", DRM_MODE_OBJECT_FB);
15546b4959f4SRob Clark 	if (!prop)
15556b4959f4SRob Clark 		return -ENOMEM;
15566b4959f4SRob Clark 	dev->mode_config.prop_fb_id = prop;
15576b4959f4SRob Clark 
15586b4959f4SRob Clark 	prop = drm_property_create_object(dev, DRM_MODE_PROP_ATOMIC,
15596b4959f4SRob Clark 			"CRTC_ID", DRM_MODE_OBJECT_CRTC);
15606b4959f4SRob Clark 	if (!prop)
15616b4959f4SRob Clark 		return -ENOMEM;
15626b4959f4SRob Clark 	dev->mode_config.prop_crtc_id = prop;
15639922ab5aSRob Clark 
1564eab3bbefSDaniel Vetter 	prop = drm_property_create_bool(dev, DRM_MODE_PROP_ATOMIC,
1565eab3bbefSDaniel Vetter 			"ACTIVE");
1566eab3bbefSDaniel Vetter 	if (!prop)
1567eab3bbefSDaniel Vetter 		return -ENOMEM;
1568eab3bbefSDaniel Vetter 	dev->mode_config.prop_active = prop;
1569eab3bbefSDaniel Vetter 
1570955f3c33SDaniel Stone 	prop = drm_property_create(dev,
1571955f3c33SDaniel Stone 			DRM_MODE_PROP_ATOMIC | DRM_MODE_PROP_BLOB,
1572955f3c33SDaniel Stone 			"MODE_ID", 0);
1573955f3c33SDaniel Stone 	if (!prop)
1574955f3c33SDaniel Stone 		return -ENOMEM;
1575955f3c33SDaniel Stone 	dev->mode_config.prop_mode_id = prop;
1576955f3c33SDaniel Stone 
15775488dc16SLionel Landwerlin 	prop = drm_property_create(dev,
15785488dc16SLionel Landwerlin 			DRM_MODE_PROP_BLOB,
15795488dc16SLionel Landwerlin 			"DEGAMMA_LUT", 0);
15805488dc16SLionel Landwerlin 	if (!prop)
15815488dc16SLionel Landwerlin 		return -ENOMEM;
15825488dc16SLionel Landwerlin 	dev->mode_config.degamma_lut_property = prop;
15835488dc16SLionel Landwerlin 
15845488dc16SLionel Landwerlin 	prop = drm_property_create_range(dev,
15855488dc16SLionel Landwerlin 			DRM_MODE_PROP_IMMUTABLE,
15865488dc16SLionel Landwerlin 			"DEGAMMA_LUT_SIZE", 0, UINT_MAX);
15875488dc16SLionel Landwerlin 	if (!prop)
15885488dc16SLionel Landwerlin 		return -ENOMEM;
15895488dc16SLionel Landwerlin 	dev->mode_config.degamma_lut_size_property = prop;
15905488dc16SLionel Landwerlin 
15915488dc16SLionel Landwerlin 	prop = drm_property_create(dev,
15925488dc16SLionel Landwerlin 			DRM_MODE_PROP_BLOB,
15935488dc16SLionel Landwerlin 			"CTM", 0);
15945488dc16SLionel Landwerlin 	if (!prop)
15955488dc16SLionel Landwerlin 		return -ENOMEM;
15965488dc16SLionel Landwerlin 	dev->mode_config.ctm_property = prop;
15975488dc16SLionel Landwerlin 
15985488dc16SLionel Landwerlin 	prop = drm_property_create(dev,
15995488dc16SLionel Landwerlin 			DRM_MODE_PROP_BLOB,
16005488dc16SLionel Landwerlin 			"GAMMA_LUT", 0);
16015488dc16SLionel Landwerlin 	if (!prop)
16025488dc16SLionel Landwerlin 		return -ENOMEM;
16035488dc16SLionel Landwerlin 	dev->mode_config.gamma_lut_property = prop;
16045488dc16SLionel Landwerlin 
16055488dc16SLionel Landwerlin 	prop = drm_property_create_range(dev,
16065488dc16SLionel Landwerlin 			DRM_MODE_PROP_IMMUTABLE,
16075488dc16SLionel Landwerlin 			"GAMMA_LUT_SIZE", 0, UINT_MAX);
16085488dc16SLionel Landwerlin 	if (!prop)
16095488dc16SLionel Landwerlin 		return -ENOMEM;
16105488dc16SLionel Landwerlin 	dev->mode_config.gamma_lut_size_property = prop;
16115488dc16SLionel Landwerlin 
16129922ab5aSRob Clark 	return 0;
16139922ab5aSRob Clark }
16149922ab5aSRob Clark 
1615f453ba04SDave Airlie /**
1616f453ba04SDave Airlie  * drm_mode_create_dvi_i_properties - create DVI-I specific connector properties
1617f453ba04SDave Airlie  * @dev: DRM device
1618f453ba04SDave Airlie  *
1619f453ba04SDave Airlie  * Called by a driver the first time a DVI-I connector is made.
1620f453ba04SDave Airlie  */
1621f453ba04SDave Airlie int drm_mode_create_dvi_i_properties(struct drm_device *dev)
1622f453ba04SDave Airlie {
1623f453ba04SDave Airlie 	struct drm_property *dvi_i_selector;
1624f453ba04SDave Airlie 	struct drm_property *dvi_i_subconnector;
1625f453ba04SDave Airlie 
1626f453ba04SDave Airlie 	if (dev->mode_config.dvi_i_select_subconnector_property)
1627f453ba04SDave Airlie 		return 0;
1628f453ba04SDave Airlie 
1629f453ba04SDave Airlie 	dvi_i_selector =
16304a67d391SSascha Hauer 		drm_property_create_enum(dev, 0,
1631f453ba04SDave Airlie 				    "select subconnector",
16324a67d391SSascha Hauer 				    drm_dvi_i_select_enum_list,
1633f453ba04SDave Airlie 				    ARRAY_SIZE(drm_dvi_i_select_enum_list));
1634f453ba04SDave Airlie 	dev->mode_config.dvi_i_select_subconnector_property = dvi_i_selector;
1635f453ba04SDave Airlie 
16364a67d391SSascha Hauer 	dvi_i_subconnector = drm_property_create_enum(dev, DRM_MODE_PROP_IMMUTABLE,
1637f453ba04SDave Airlie 				    "subconnector",
16384a67d391SSascha Hauer 				    drm_dvi_i_subconnector_enum_list,
1639f453ba04SDave Airlie 				    ARRAY_SIZE(drm_dvi_i_subconnector_enum_list));
1640f453ba04SDave Airlie 	dev->mode_config.dvi_i_subconnector_property = dvi_i_subconnector;
1641f453ba04SDave Airlie 
1642f453ba04SDave Airlie 	return 0;
1643f453ba04SDave Airlie }
1644f453ba04SDave Airlie EXPORT_SYMBOL(drm_mode_create_dvi_i_properties);
1645f453ba04SDave Airlie 
1646f453ba04SDave Airlie /**
1647f453ba04SDave Airlie  * drm_create_tv_properties - create TV specific connector properties
1648f453ba04SDave Airlie  * @dev: DRM device
1649f453ba04SDave Airlie  * @num_modes: number of different TV formats (modes) supported
1650f453ba04SDave Airlie  * @modes: array of pointers to strings containing name of each format
1651f453ba04SDave Airlie  *
1652f453ba04SDave Airlie  * Called by a driver's TV initialization routine, this function creates
1653f453ba04SDave Airlie  * the TV specific connector properties for a given device.  Caller is
1654f453ba04SDave Airlie  * responsible for allocating a list of format names and passing them to
1655f453ba04SDave Airlie  * this routine.
1656f453ba04SDave Airlie  */
16572f763312SThierry Reding int drm_mode_create_tv_properties(struct drm_device *dev,
16582f763312SThierry Reding 				  unsigned int num_modes,
1659b7c914b3SVille Syrjälä 				  const char * const modes[])
1660f453ba04SDave Airlie {
1661f453ba04SDave Airlie 	struct drm_property *tv_selector;
1662f453ba04SDave Airlie 	struct drm_property *tv_subconnector;
16632f763312SThierry Reding 	unsigned int i;
1664f453ba04SDave Airlie 
1665f453ba04SDave Airlie 	if (dev->mode_config.tv_select_subconnector_property)
1666f453ba04SDave Airlie 		return 0;
1667f453ba04SDave Airlie 
1668f453ba04SDave Airlie 	/*
1669f453ba04SDave Airlie 	 * Basic connector properties
1670f453ba04SDave Airlie 	 */
16714a67d391SSascha Hauer 	tv_selector = drm_property_create_enum(dev, 0,
1672f453ba04SDave Airlie 					  "select subconnector",
16734a67d391SSascha Hauer 					  drm_tv_select_enum_list,
1674f453ba04SDave Airlie 					  ARRAY_SIZE(drm_tv_select_enum_list));
167548aa1e74SInsu Yun 	if (!tv_selector)
167648aa1e74SInsu Yun 		goto nomem;
167748aa1e74SInsu Yun 
1678f453ba04SDave Airlie 	dev->mode_config.tv_select_subconnector_property = tv_selector;
1679f453ba04SDave Airlie 
1680f453ba04SDave Airlie 	tv_subconnector =
16814a67d391SSascha Hauer 		drm_property_create_enum(dev, DRM_MODE_PROP_IMMUTABLE,
16824a67d391SSascha Hauer 				    "subconnector",
16834a67d391SSascha Hauer 				    drm_tv_subconnector_enum_list,
1684f453ba04SDave Airlie 				    ARRAY_SIZE(drm_tv_subconnector_enum_list));
168548aa1e74SInsu Yun 	if (!tv_subconnector)
168648aa1e74SInsu Yun 		goto nomem;
1687f453ba04SDave Airlie 	dev->mode_config.tv_subconnector_property = tv_subconnector;
1688f453ba04SDave Airlie 
1689f453ba04SDave Airlie 	/*
1690f453ba04SDave Airlie 	 * Other, TV specific properties: margins & TV modes.
1691f453ba04SDave Airlie 	 */
1692f453ba04SDave Airlie 	dev->mode_config.tv_left_margin_property =
1693d9bc3c02SSascha Hauer 		drm_property_create_range(dev, 0, "left margin", 0, 100);
169448aa1e74SInsu Yun 	if (!dev->mode_config.tv_left_margin_property)
169548aa1e74SInsu Yun 		goto nomem;
1696f453ba04SDave Airlie 
1697f453ba04SDave Airlie 	dev->mode_config.tv_right_margin_property =
1698d9bc3c02SSascha Hauer 		drm_property_create_range(dev, 0, "right margin", 0, 100);
169948aa1e74SInsu Yun 	if (!dev->mode_config.tv_right_margin_property)
170048aa1e74SInsu Yun 		goto nomem;
1701f453ba04SDave Airlie 
1702f453ba04SDave Airlie 	dev->mode_config.tv_top_margin_property =
1703d9bc3c02SSascha Hauer 		drm_property_create_range(dev, 0, "top margin", 0, 100);
170448aa1e74SInsu Yun 	if (!dev->mode_config.tv_top_margin_property)
170548aa1e74SInsu Yun 		goto nomem;
1706f453ba04SDave Airlie 
1707f453ba04SDave Airlie 	dev->mode_config.tv_bottom_margin_property =
1708d9bc3c02SSascha Hauer 		drm_property_create_range(dev, 0, "bottom margin", 0, 100);
170948aa1e74SInsu Yun 	if (!dev->mode_config.tv_bottom_margin_property)
171048aa1e74SInsu Yun 		goto nomem;
1711f453ba04SDave Airlie 
1712f453ba04SDave Airlie 	dev->mode_config.tv_mode_property =
1713f453ba04SDave Airlie 		drm_property_create(dev, DRM_MODE_PROP_ENUM,
1714f453ba04SDave Airlie 				    "mode", num_modes);
171548aa1e74SInsu Yun 	if (!dev->mode_config.tv_mode_property)
171648aa1e74SInsu Yun 		goto nomem;
171748aa1e74SInsu Yun 
1718f453ba04SDave Airlie 	for (i = 0; i < num_modes; i++)
1719f453ba04SDave Airlie 		drm_property_add_enum(dev->mode_config.tv_mode_property, i,
1720f453ba04SDave Airlie 				      i, modes[i]);
1721f453ba04SDave Airlie 
1722b6b7902eSFrancisco Jerez 	dev->mode_config.tv_brightness_property =
1723d9bc3c02SSascha Hauer 		drm_property_create_range(dev, 0, "brightness", 0, 100);
172448aa1e74SInsu Yun 	if (!dev->mode_config.tv_brightness_property)
172548aa1e74SInsu Yun 		goto nomem;
1726b6b7902eSFrancisco Jerez 
1727b6b7902eSFrancisco Jerez 	dev->mode_config.tv_contrast_property =
1728d9bc3c02SSascha Hauer 		drm_property_create_range(dev, 0, "contrast", 0, 100);
172948aa1e74SInsu Yun 	if (!dev->mode_config.tv_contrast_property)
173048aa1e74SInsu Yun 		goto nomem;
1731b6b7902eSFrancisco Jerez 
1732b6b7902eSFrancisco Jerez 	dev->mode_config.tv_flicker_reduction_property =
1733d9bc3c02SSascha Hauer 		drm_property_create_range(dev, 0, "flicker reduction", 0, 100);
173448aa1e74SInsu Yun 	if (!dev->mode_config.tv_flicker_reduction_property)
173548aa1e74SInsu Yun 		goto nomem;
1736b6b7902eSFrancisco Jerez 
1737a75f0236SFrancisco Jerez 	dev->mode_config.tv_overscan_property =
1738d9bc3c02SSascha Hauer 		drm_property_create_range(dev, 0, "overscan", 0, 100);
173948aa1e74SInsu Yun 	if (!dev->mode_config.tv_overscan_property)
174048aa1e74SInsu Yun 		goto nomem;
1741a75f0236SFrancisco Jerez 
1742a75f0236SFrancisco Jerez 	dev->mode_config.tv_saturation_property =
1743d9bc3c02SSascha Hauer 		drm_property_create_range(dev, 0, "saturation", 0, 100);
174448aa1e74SInsu Yun 	if (!dev->mode_config.tv_saturation_property)
174548aa1e74SInsu Yun 		goto nomem;
1746a75f0236SFrancisco Jerez 
1747a75f0236SFrancisco Jerez 	dev->mode_config.tv_hue_property =
1748d9bc3c02SSascha Hauer 		drm_property_create_range(dev, 0, "hue", 0, 100);
174948aa1e74SInsu Yun 	if (!dev->mode_config.tv_hue_property)
175048aa1e74SInsu Yun 		goto nomem;
1751a75f0236SFrancisco Jerez 
1752f453ba04SDave Airlie 	return 0;
175348aa1e74SInsu Yun nomem:
175448aa1e74SInsu Yun 	return -ENOMEM;
1755f453ba04SDave Airlie }
1756f453ba04SDave Airlie EXPORT_SYMBOL(drm_mode_create_tv_properties);
1757f453ba04SDave Airlie 
1758f453ba04SDave Airlie /**
1759f453ba04SDave Airlie  * drm_mode_create_scaling_mode_property - create scaling mode property
1760f453ba04SDave Airlie  * @dev: DRM device
1761f453ba04SDave Airlie  *
1762f453ba04SDave Airlie  * Called by a driver the first time it's needed, must be attached to desired
1763f453ba04SDave Airlie  * connectors.
1764f453ba04SDave Airlie  */
1765f453ba04SDave Airlie int drm_mode_create_scaling_mode_property(struct drm_device *dev)
1766f453ba04SDave Airlie {
1767f453ba04SDave Airlie 	struct drm_property *scaling_mode;
1768f453ba04SDave Airlie 
1769f453ba04SDave Airlie 	if (dev->mode_config.scaling_mode_property)
1770f453ba04SDave Airlie 		return 0;
1771f453ba04SDave Airlie 
1772f453ba04SDave Airlie 	scaling_mode =
17734a67d391SSascha Hauer 		drm_property_create_enum(dev, 0, "scaling mode",
17744a67d391SSascha Hauer 				drm_scaling_mode_enum_list,
1775f453ba04SDave Airlie 				    ARRAY_SIZE(drm_scaling_mode_enum_list));
1776f453ba04SDave Airlie 
1777f453ba04SDave Airlie 	dev->mode_config.scaling_mode_property = scaling_mode;
1778f453ba04SDave Airlie 
1779f453ba04SDave Airlie 	return 0;
1780f453ba04SDave Airlie }
1781f453ba04SDave Airlie EXPORT_SYMBOL(drm_mode_create_scaling_mode_property);
1782f453ba04SDave Airlie 
1783f453ba04SDave Airlie /**
1784ff587e45SVandana Kannan  * drm_mode_create_aspect_ratio_property - create aspect ratio property
1785ff587e45SVandana Kannan  * @dev: DRM device
1786ff587e45SVandana Kannan  *
1787ff587e45SVandana Kannan  * Called by a driver the first time it's needed, must be attached to desired
1788ff587e45SVandana Kannan  * connectors.
1789ff587e45SVandana Kannan  *
1790ff587e45SVandana Kannan  * Returns:
17911a498633SDaniel Vetter  * Zero on success, negative errno on failure.
1792ff587e45SVandana Kannan  */
1793ff587e45SVandana Kannan int drm_mode_create_aspect_ratio_property(struct drm_device *dev)
1794ff587e45SVandana Kannan {
1795ff587e45SVandana Kannan 	if (dev->mode_config.aspect_ratio_property)
1796ff587e45SVandana Kannan 		return 0;
1797ff587e45SVandana Kannan 
1798ff587e45SVandana Kannan 	dev->mode_config.aspect_ratio_property =
1799ff587e45SVandana Kannan 		drm_property_create_enum(dev, 0, "aspect ratio",
1800ff587e45SVandana Kannan 				drm_aspect_ratio_enum_list,
1801ff587e45SVandana Kannan 				ARRAY_SIZE(drm_aspect_ratio_enum_list));
1802ff587e45SVandana Kannan 
1803ff587e45SVandana Kannan 	if (dev->mode_config.aspect_ratio_property == NULL)
1804ff587e45SVandana Kannan 		return -ENOMEM;
1805ff587e45SVandana Kannan 
1806ff587e45SVandana Kannan 	return 0;
1807ff587e45SVandana Kannan }
1808ff587e45SVandana Kannan EXPORT_SYMBOL(drm_mode_create_aspect_ratio_property);
1809ff587e45SVandana Kannan 
1810ff587e45SVandana Kannan /**
1811884840aaSJakob Bornecrantz  * drm_mode_create_dirty_property - create dirty property
1812884840aaSJakob Bornecrantz  * @dev: DRM device
1813884840aaSJakob Bornecrantz  *
1814884840aaSJakob Bornecrantz  * Called by a driver the first time it's needed, must be attached to desired
1815884840aaSJakob Bornecrantz  * connectors.
1816884840aaSJakob Bornecrantz  */
1817884840aaSJakob Bornecrantz int drm_mode_create_dirty_info_property(struct drm_device *dev)
1818884840aaSJakob Bornecrantz {
1819884840aaSJakob Bornecrantz 	struct drm_property *dirty_info;
1820884840aaSJakob Bornecrantz 
1821884840aaSJakob Bornecrantz 	if (dev->mode_config.dirty_info_property)
1822884840aaSJakob Bornecrantz 		return 0;
1823884840aaSJakob Bornecrantz 
1824884840aaSJakob Bornecrantz 	dirty_info =
18254a67d391SSascha Hauer 		drm_property_create_enum(dev, DRM_MODE_PROP_IMMUTABLE,
1826884840aaSJakob Bornecrantz 				    "dirty",
18274a67d391SSascha Hauer 				    drm_dirty_info_enum_list,
1828884840aaSJakob Bornecrantz 				    ARRAY_SIZE(drm_dirty_info_enum_list));
1829884840aaSJakob Bornecrantz 	dev->mode_config.dirty_info_property = dirty_info;
1830884840aaSJakob Bornecrantz 
1831884840aaSJakob Bornecrantz 	return 0;
1832884840aaSJakob Bornecrantz }
1833884840aaSJakob Bornecrantz EXPORT_SYMBOL(drm_mode_create_dirty_info_property);
1834884840aaSJakob Bornecrantz 
18355bb2bbf5SDave Airlie /**
18365bb2bbf5SDave Airlie  * drm_mode_create_suggested_offset_properties - create suggests offset properties
18375bb2bbf5SDave Airlie  * @dev: DRM device
18385bb2bbf5SDave Airlie  *
18395bb2bbf5SDave Airlie  * Create the the suggested x/y offset property for connectors.
18405bb2bbf5SDave Airlie  */
18415bb2bbf5SDave Airlie int drm_mode_create_suggested_offset_properties(struct drm_device *dev)
18425bb2bbf5SDave Airlie {
18435bb2bbf5SDave Airlie 	if (dev->mode_config.suggested_x_property && dev->mode_config.suggested_y_property)
18445bb2bbf5SDave Airlie 		return 0;
18455bb2bbf5SDave Airlie 
18465bb2bbf5SDave Airlie 	dev->mode_config.suggested_x_property =
18475bb2bbf5SDave Airlie 		drm_property_create_range(dev, DRM_MODE_PROP_IMMUTABLE, "suggested X", 0, 0xffffffff);
18485bb2bbf5SDave Airlie 
18495bb2bbf5SDave Airlie 	dev->mode_config.suggested_y_property =
18505bb2bbf5SDave Airlie 		drm_property_create_range(dev, DRM_MODE_PROP_IMMUTABLE, "suggested Y", 0, 0xffffffff);
18515bb2bbf5SDave Airlie 
18525bb2bbf5SDave Airlie 	if (dev->mode_config.suggested_x_property == NULL ||
18535bb2bbf5SDave Airlie 	    dev->mode_config.suggested_y_property == NULL)
18545bb2bbf5SDave Airlie 		return -ENOMEM;
18555bb2bbf5SDave Airlie 	return 0;
18565bb2bbf5SDave Airlie }
18575bb2bbf5SDave Airlie EXPORT_SYMBOL(drm_mode_create_suggested_offset_properties);
18585bb2bbf5SDave Airlie 
1859f453ba04SDave Airlie /**
1860f453ba04SDave Airlie  * drm_mode_getresources - get graphics configuration
1861065a50edSDaniel Vetter  * @dev: drm device for the ioctl
1862065a50edSDaniel Vetter  * @data: data pointer for the ioctl
1863065a50edSDaniel Vetter  * @file_priv: drm file for the ioctl call
1864f453ba04SDave Airlie  *
1865f453ba04SDave Airlie  * Construct a set of configuration description structures and return
1866f453ba04SDave Airlie  * them to the user, including CRTC, connector and framebuffer configuration.
1867f453ba04SDave Airlie  *
1868f453ba04SDave Airlie  * Called by the user via ioctl.
1869f453ba04SDave Airlie  *
1870c8e32cc1SDaniel Vetter  * Returns:
18711a498633SDaniel Vetter  * Zero on success, negative errno on failure.
1872f453ba04SDave Airlie  */
1873f453ba04SDave Airlie int drm_mode_getresources(struct drm_device *dev, void *data,
1874f453ba04SDave Airlie 			  struct drm_file *file_priv)
1875f453ba04SDave Airlie {
1876f453ba04SDave Airlie 	struct drm_mode_card_res *card_res = data;
1877f453ba04SDave Airlie 	struct list_head *lh;
1878f453ba04SDave Airlie 	struct drm_framebuffer *fb;
1879f453ba04SDave Airlie 	struct drm_connector *connector;
1880f453ba04SDave Airlie 	struct drm_crtc *crtc;
1881f453ba04SDave Airlie 	struct drm_encoder *encoder;
1882f453ba04SDave Airlie 	int ret = 0;
1883f453ba04SDave Airlie 	int connector_count = 0;
1884f453ba04SDave Airlie 	int crtc_count = 0;
1885f453ba04SDave Airlie 	int fb_count = 0;
1886f453ba04SDave Airlie 	int encoder_count = 0;
18879c7060f7SDaniel Vetter 	int copied = 0;
1888f453ba04SDave Airlie 	uint32_t __user *fb_id;
1889f453ba04SDave Airlie 	uint32_t __user *crtc_id;
1890f453ba04SDave Airlie 	uint32_t __user *connector_id;
1891f453ba04SDave Airlie 	uint32_t __user *encoder_id;
1892f453ba04SDave Airlie 
1893fb3b06c8SDave Airlie 	if (!drm_core_check_feature(dev, DRIVER_MODESET))
1894fb3b06c8SDave Airlie 		return -EINVAL;
1895fb3b06c8SDave Airlie 
1896f453ba04SDave Airlie 
18974b096ac1SDaniel Vetter 	mutex_lock(&file_priv->fbs_lock);
1898f453ba04SDave Airlie 	/*
1899f453ba04SDave Airlie 	 * For the non-control nodes we need to limit the list of resources
1900f453ba04SDave Airlie 	 * by IDs in the group list for this node
1901f453ba04SDave Airlie 	 */
1902f453ba04SDave Airlie 	list_for_each(lh, &file_priv->fbs)
1903f453ba04SDave Airlie 		fb_count++;
1904f453ba04SDave Airlie 
19054b096ac1SDaniel Vetter 	/* handle this in 4 parts */
19064b096ac1SDaniel Vetter 	/* FBs */
19074b096ac1SDaniel Vetter 	if (card_res->count_fbs >= fb_count) {
19084b096ac1SDaniel Vetter 		copied = 0;
19094b096ac1SDaniel Vetter 		fb_id = (uint32_t __user *)(unsigned long)card_res->fb_id_ptr;
19104b096ac1SDaniel Vetter 		list_for_each_entry(fb, &file_priv->fbs, filp_head) {
19114b096ac1SDaniel Vetter 			if (put_user(fb->base.id, fb_id + copied)) {
19124b096ac1SDaniel Vetter 				mutex_unlock(&file_priv->fbs_lock);
19134b096ac1SDaniel Vetter 				return -EFAULT;
19144b096ac1SDaniel Vetter 			}
19154b096ac1SDaniel Vetter 			copied++;
19164b096ac1SDaniel Vetter 		}
19174b096ac1SDaniel Vetter 	}
19184b096ac1SDaniel Vetter 	card_res->count_fbs = fb_count;
19194b096ac1SDaniel Vetter 	mutex_unlock(&file_priv->fbs_lock);
19204b096ac1SDaniel Vetter 
1921fcf93f69SDaniel Vetter 	/* mode_config.mutex protects the connector list against e.g. DP MST
1922fcf93f69SDaniel Vetter 	 * connector hot-adding. CRTC/Plane lists are invariant. */
1923fcf93f69SDaniel Vetter 	mutex_lock(&dev->mode_config.mutex);
1924e4f62546SDaniel Vetter 	drm_for_each_crtc(crtc, dev)
1925f453ba04SDave Airlie 		crtc_count++;
1926f453ba04SDave Airlie 
19279a9f5ce8SDaniel Vetter 	drm_for_each_connector(connector, dev)
1928f453ba04SDave Airlie 		connector_count++;
1929f453ba04SDave Airlie 
1930e4f62546SDaniel Vetter 	drm_for_each_encoder(encoder, dev)
1931f453ba04SDave Airlie 		encoder_count++;
1932f453ba04SDave Airlie 
1933f453ba04SDave Airlie 	card_res->max_height = dev->mode_config.max_height;
1934f453ba04SDave Airlie 	card_res->min_height = dev->mode_config.min_height;
1935f453ba04SDave Airlie 	card_res->max_width = dev->mode_config.max_width;
1936f453ba04SDave Airlie 	card_res->min_width = dev->mode_config.min_width;
1937f453ba04SDave Airlie 
1938f453ba04SDave Airlie 	/* CRTCs */
1939f453ba04SDave Airlie 	if (card_res->count_crtcs >= crtc_count) {
1940f453ba04SDave Airlie 		copied = 0;
1941f453ba04SDave Airlie 		crtc_id = (uint32_t __user *)(unsigned long)card_res->crtc_id_ptr;
19426295d607SDaniel Vetter 		drm_for_each_crtc(crtc, dev) {
1943fa3ab4c2SVille Syrjälä 			DRM_DEBUG_KMS("[CRTC:%d:%s]\n",
1944fa3ab4c2SVille Syrjälä 				      crtc->base.id, crtc->name);
1945f453ba04SDave Airlie 			if (put_user(crtc->base.id, crtc_id + copied)) {
1946f453ba04SDave Airlie 				ret = -EFAULT;
1947f453ba04SDave Airlie 				goto out;
1948f453ba04SDave Airlie 			}
1949f453ba04SDave Airlie 			copied++;
1950f453ba04SDave Airlie 		}
1951f453ba04SDave Airlie 	}
1952f453ba04SDave Airlie 	card_res->count_crtcs = crtc_count;
1953f453ba04SDave Airlie 
1954f453ba04SDave Airlie 	/* Encoders */
1955f453ba04SDave Airlie 	if (card_res->count_encoders >= encoder_count) {
1956f453ba04SDave Airlie 		copied = 0;
1957f453ba04SDave Airlie 		encoder_id = (uint32_t __user *)(unsigned long)card_res->encoder_id_ptr;
19586295d607SDaniel Vetter 		drm_for_each_encoder(encoder, dev) {
19599440106bSJerome Glisse 			DRM_DEBUG_KMS("[ENCODER:%d:%s]\n", encoder->base.id,
196083a8cfd3SJani Nikula 					encoder->name);
1961f453ba04SDave Airlie 			if (put_user(encoder->base.id, encoder_id +
1962f453ba04SDave Airlie 				     copied)) {
1963f453ba04SDave Airlie 				ret = -EFAULT;
1964f453ba04SDave Airlie 				goto out;
1965f453ba04SDave Airlie 			}
1966f453ba04SDave Airlie 			copied++;
1967f453ba04SDave Airlie 		}
1968f453ba04SDave Airlie 	}
1969f453ba04SDave Airlie 	card_res->count_encoders = encoder_count;
1970f453ba04SDave Airlie 
1971f453ba04SDave Airlie 	/* Connectors */
1972f453ba04SDave Airlie 	if (card_res->count_connectors >= connector_count) {
1973f453ba04SDave Airlie 		copied = 0;
1974f453ba04SDave Airlie 		connector_id = (uint32_t __user *)(unsigned long)card_res->connector_id_ptr;
19756295d607SDaniel Vetter 		drm_for_each_connector(connector, dev) {
19769440106bSJerome Glisse 			DRM_DEBUG_KMS("[CONNECTOR:%d:%s]\n",
19779440106bSJerome Glisse 				connector->base.id,
197825933820SJani Nikula 				connector->name);
1979f453ba04SDave Airlie 			if (put_user(connector->base.id,
1980f453ba04SDave Airlie 				     connector_id + copied)) {
1981f453ba04SDave Airlie 				ret = -EFAULT;
1982f453ba04SDave Airlie 				goto out;
1983f453ba04SDave Airlie 			}
1984f453ba04SDave Airlie 			copied++;
1985f453ba04SDave Airlie 		}
1986f453ba04SDave Airlie 	}
1987f453ba04SDave Airlie 	card_res->count_connectors = connector_count;
1988f453ba04SDave Airlie 
19899440106bSJerome Glisse 	DRM_DEBUG_KMS("CRTC[%d] CONNECTORS[%d] ENCODERS[%d]\n", card_res->count_crtcs,
1990f453ba04SDave Airlie 		  card_res->count_connectors, card_res->count_encoders);
1991f453ba04SDave Airlie 
1992f453ba04SDave Airlie out:
1993fcf93f69SDaniel Vetter 	mutex_unlock(&dev->mode_config.mutex);
1994f453ba04SDave Airlie 	return ret;
1995f453ba04SDave Airlie }
1996f453ba04SDave Airlie 
1997f453ba04SDave Airlie /**
1998f453ba04SDave Airlie  * drm_mode_getcrtc - get CRTC configuration
1999065a50edSDaniel Vetter  * @dev: drm device for the ioctl
2000065a50edSDaniel Vetter  * @data: data pointer for the ioctl
2001065a50edSDaniel Vetter  * @file_priv: drm file for the ioctl call
2002f453ba04SDave Airlie  *
2003f453ba04SDave Airlie  * Construct a CRTC configuration structure to return to the user.
2004f453ba04SDave Airlie  *
2005f453ba04SDave Airlie  * Called by the user via ioctl.
2006f453ba04SDave Airlie  *
2007c8e32cc1SDaniel Vetter  * Returns:
20081a498633SDaniel Vetter  * Zero on success, negative errno on failure.
2009f453ba04SDave Airlie  */
2010f453ba04SDave Airlie int drm_mode_getcrtc(struct drm_device *dev,
2011f453ba04SDave Airlie 		     void *data, struct drm_file *file_priv)
2012f453ba04SDave Airlie {
2013f453ba04SDave Airlie 	struct drm_mode_crtc *crtc_resp = data;
2014f453ba04SDave Airlie 	struct drm_crtc *crtc;
2015f453ba04SDave Airlie 
2016fb3b06c8SDave Airlie 	if (!drm_core_check_feature(dev, DRIVER_MODESET))
2017fb3b06c8SDave Airlie 		return -EINVAL;
2018fb3b06c8SDave Airlie 
2019a2b34e22SRob Clark 	crtc = drm_crtc_find(dev, crtc_resp->crtc_id);
2020fcf93f69SDaniel Vetter 	if (!crtc)
2021fcf93f69SDaniel Vetter 		return -ENOENT;
2022f453ba04SDave Airlie 
2023fcf93f69SDaniel Vetter 	drm_modeset_lock_crtc(crtc, crtc->primary);
2024f453ba04SDave Airlie 	crtc_resp->gamma_size = crtc->gamma_size;
2025f4510a27SMatt Roper 	if (crtc->primary->fb)
2026f4510a27SMatt Roper 		crtc_resp->fb_id = crtc->primary->fb->base.id;
2027f453ba04SDave Airlie 	else
2028f453ba04SDave Airlie 		crtc_resp->fb_id = 0;
2029f453ba04SDave Airlie 
203031c946e8SDaniel Vetter 	if (crtc->state) {
203131c946e8SDaniel Vetter 		crtc_resp->x = crtc->primary->state->src_x >> 16;
203231c946e8SDaniel Vetter 		crtc_resp->y = crtc->primary->state->src_y >> 16;
203331c946e8SDaniel Vetter 		if (crtc->state->enable) {
2034934a8a89SDaniel Stone 			drm_mode_convert_to_umode(&crtc_resp->mode, &crtc->state->mode);
203531c946e8SDaniel Vetter 			crtc_resp->mode_valid = 1;
2036f453ba04SDave Airlie 
203731c946e8SDaniel Vetter 		} else {
203831c946e8SDaniel Vetter 			crtc_resp->mode_valid = 0;
203931c946e8SDaniel Vetter 		}
204031c946e8SDaniel Vetter 	} else {
204131c946e8SDaniel Vetter 		crtc_resp->x = crtc->x;
204231c946e8SDaniel Vetter 		crtc_resp->y = crtc->y;
204331c946e8SDaniel Vetter 		if (crtc->enabled) {
2044934a8a89SDaniel Stone 			drm_mode_convert_to_umode(&crtc_resp->mode, &crtc->mode);
2045f453ba04SDave Airlie 			crtc_resp->mode_valid = 1;
2046f453ba04SDave Airlie 
2047f453ba04SDave Airlie 		} else {
2048f453ba04SDave Airlie 			crtc_resp->mode_valid = 0;
2049f453ba04SDave Airlie 		}
205031c946e8SDaniel Vetter 	}
2051fcf93f69SDaniel Vetter 	drm_modeset_unlock_crtc(crtc);
2052f453ba04SDave Airlie 
2053baf698b0SDaniel Vetter 	return 0;
2054f453ba04SDave Airlie }
2055f453ba04SDave Airlie 
205661d8e328SDamien Lespiau static bool drm_mode_expose_to_userspace(const struct drm_display_mode *mode,
205761d8e328SDamien Lespiau 					 const struct drm_file *file_priv)
205861d8e328SDamien Lespiau {
205961d8e328SDamien Lespiau 	/*
206061d8e328SDamien Lespiau 	 * If user-space hasn't configured the driver to expose the stereo 3D
206161d8e328SDamien Lespiau 	 * modes, don't expose them.
206261d8e328SDamien Lespiau 	 */
206361d8e328SDamien Lespiau 	if (!file_priv->stereo_allowed && drm_mode_is_stereo(mode))
206461d8e328SDamien Lespiau 		return false;
206561d8e328SDamien Lespiau 
206661d8e328SDamien Lespiau 	return true;
206761d8e328SDamien Lespiau }
206861d8e328SDamien Lespiau 
2069abd69c55SDaniel Vetter static struct drm_encoder *drm_connector_get_encoder(struct drm_connector *connector)
2070abd69c55SDaniel Vetter {
2071abd69c55SDaniel Vetter 	/* For atomic drivers only state objects are synchronously updated and
2072abd69c55SDaniel Vetter 	 * protected by modeset locks, so check those first. */
2073abd69c55SDaniel Vetter 	if (connector->state)
2074abd69c55SDaniel Vetter 		return connector->state->best_encoder;
2075abd69c55SDaniel Vetter 	return connector->encoder;
2076abd69c55SDaniel Vetter }
2077abd69c55SDaniel Vetter 
207895cbf110SRob Clark /* helper for getconnector and getproperties ioctls */
207988a48e29SRob Clark static int get_properties(struct drm_mode_object *obj, bool atomic,
208095cbf110SRob Clark 		uint32_t __user *prop_ptr, uint64_t __user *prop_values,
208195cbf110SRob Clark 		uint32_t *arg_count_props)
208295cbf110SRob Clark {
208388a48e29SRob Clark 	int props_count;
208488a48e29SRob Clark 	int i, ret, copied;
208588a48e29SRob Clark 
208688a48e29SRob Clark 	props_count = obj->properties->count;
208788a48e29SRob Clark 	if (!atomic)
208888a48e29SRob Clark 		props_count -= obj->properties->atomic_count;
208995cbf110SRob Clark 
209095cbf110SRob Clark 	if ((*arg_count_props >= props_count) && props_count) {
209188a48e29SRob Clark 		for (i = 0, copied = 0; copied < props_count; i++) {
209295cbf110SRob Clark 			struct drm_property *prop = obj->properties->properties[i];
209395cbf110SRob Clark 			uint64_t val;
209495cbf110SRob Clark 
209588a48e29SRob Clark 			if ((prop->flags & DRM_MODE_PROP_ATOMIC) && !atomic)
209688a48e29SRob Clark 				continue;
209788a48e29SRob Clark 
209895cbf110SRob Clark 			ret = drm_object_property_get_value(obj, prop, &val);
209995cbf110SRob Clark 			if (ret)
210095cbf110SRob Clark 				return ret;
210195cbf110SRob Clark 
210295cbf110SRob Clark 			if (put_user(prop->base.id, prop_ptr + copied))
210395cbf110SRob Clark 				return -EFAULT;
210495cbf110SRob Clark 
210595cbf110SRob Clark 			if (put_user(val, prop_values + copied))
210695cbf110SRob Clark 				return -EFAULT;
210795cbf110SRob Clark 
210895cbf110SRob Clark 			copied++;
210995cbf110SRob Clark 		}
211095cbf110SRob Clark 	}
211195cbf110SRob Clark 	*arg_count_props = props_count;
211295cbf110SRob Clark 
211395cbf110SRob Clark 	return 0;
211495cbf110SRob Clark }
211595cbf110SRob Clark 
2116f453ba04SDave Airlie /**
2117f453ba04SDave Airlie  * drm_mode_getconnector - get connector configuration
2118065a50edSDaniel Vetter  * @dev: drm device for the ioctl
2119065a50edSDaniel Vetter  * @data: data pointer for the ioctl
2120065a50edSDaniel Vetter  * @file_priv: drm file for the ioctl call
2121f453ba04SDave Airlie  *
2122f453ba04SDave Airlie  * Construct a connector configuration structure to return to the user.
2123f453ba04SDave Airlie  *
2124f453ba04SDave Airlie  * Called by the user via ioctl.
2125f453ba04SDave Airlie  *
2126c8e32cc1SDaniel Vetter  * Returns:
21271a498633SDaniel Vetter  * Zero on success, negative errno on failure.
2128f453ba04SDave Airlie  */
2129f453ba04SDave Airlie int drm_mode_getconnector(struct drm_device *dev, void *data,
2130f453ba04SDave Airlie 			  struct drm_file *file_priv)
2131f453ba04SDave Airlie {
2132f453ba04SDave Airlie 	struct drm_mode_get_connector *out_resp = data;
2133f453ba04SDave Airlie 	struct drm_connector *connector;
2134abd69c55SDaniel Vetter 	struct drm_encoder *encoder;
2135f453ba04SDave Airlie 	struct drm_display_mode *mode;
2136f453ba04SDave Airlie 	int mode_count = 0;
2137f453ba04SDave Airlie 	int encoders_count = 0;
2138f453ba04SDave Airlie 	int ret = 0;
2139f453ba04SDave Airlie 	int copied = 0;
2140f453ba04SDave Airlie 	int i;
2141f453ba04SDave Airlie 	struct drm_mode_modeinfo u_mode;
2142f453ba04SDave Airlie 	struct drm_mode_modeinfo __user *mode_ptr;
2143f453ba04SDave Airlie 	uint32_t __user *encoder_ptr;
2144f453ba04SDave Airlie 
2145fb3b06c8SDave Airlie 	if (!drm_core_check_feature(dev, DRIVER_MODESET))
2146fb3b06c8SDave Airlie 		return -EINVAL;
2147fb3b06c8SDave Airlie 
2148f453ba04SDave Airlie 	memset(&u_mode, 0, sizeof(struct drm_mode_modeinfo));
2149f453ba04SDave Airlie 
21509440106bSJerome Glisse 	DRM_DEBUG_KMS("[CONNECTOR:%d:?]\n", out_resp->connector_id);
2151f453ba04SDave Airlie 
21527b24056bSDaniel Vetter 	mutex_lock(&dev->mode_config.mutex);
2153f453ba04SDave Airlie 
2154a2b34e22SRob Clark 	connector = drm_connector_find(dev, out_resp->connector_id);
2155a2b34e22SRob Clark 	if (!connector) {
2156f27657f2SVille Syrjälä 		ret = -ENOENT;
215704bdf441STommi Rantala 		goto out_unlock;
2158f453ba04SDave Airlie 	}
2159f453ba04SDave Airlie 
216001073b08SThierry Reding 	for (i = 0; i < DRM_CONNECTOR_MAX_ENCODER; i++)
216101073b08SThierry Reding 		if (connector->encoder_ids[i] != 0)
2162f453ba04SDave Airlie 			encoders_count++;
2163f453ba04SDave Airlie 
2164f453ba04SDave Airlie 	if (out_resp->count_modes == 0) {
2165f453ba04SDave Airlie 		connector->funcs->fill_modes(connector,
2166f453ba04SDave Airlie 					     dev->mode_config.max_width,
2167f453ba04SDave Airlie 					     dev->mode_config.max_height);
2168f453ba04SDave Airlie 	}
2169f453ba04SDave Airlie 
2170f453ba04SDave Airlie 	/* delayed so we get modes regardless of pre-fill_modes state */
2171f453ba04SDave Airlie 	list_for_each_entry(mode, &connector->modes, head)
217261d8e328SDamien Lespiau 		if (drm_mode_expose_to_userspace(mode, file_priv))
2173f453ba04SDave Airlie 			mode_count++;
2174f453ba04SDave Airlie 
2175f453ba04SDave Airlie 	out_resp->connector_id = connector->base.id;
2176f453ba04SDave Airlie 	out_resp->connector_type = connector->connector_type;
2177f453ba04SDave Airlie 	out_resp->connector_type_id = connector->connector_type_id;
2178f453ba04SDave Airlie 	out_resp->mm_width = connector->display_info.width_mm;
2179f453ba04SDave Airlie 	out_resp->mm_height = connector->display_info.height_mm;
2180f453ba04SDave Airlie 	out_resp->subpixel = connector->display_info.subpixel_order;
2181f453ba04SDave Airlie 	out_resp->connection = connector->status;
21822caa80e7SDaniel Vetter 
21832caa80e7SDaniel Vetter 	drm_modeset_lock(&dev->mode_config.connection_mutex, NULL);
2184abd69c55SDaniel Vetter 	encoder = drm_connector_get_encoder(connector);
2185abd69c55SDaniel Vetter 	if (encoder)
2186abd69c55SDaniel Vetter 		out_resp->encoder_id = encoder->base.id;
2187f453ba04SDave Airlie 	else
2188f453ba04SDave Airlie 		out_resp->encoder_id = 0;
2189f453ba04SDave Airlie 
2190f453ba04SDave Airlie 	/*
2191f453ba04SDave Airlie 	 * This ioctl is called twice, once to determine how much space is
2192f453ba04SDave Airlie 	 * needed, and the 2nd time to fill it.
2193f453ba04SDave Airlie 	 */
2194f453ba04SDave Airlie 	if ((out_resp->count_modes >= mode_count) && mode_count) {
2195f453ba04SDave Airlie 		copied = 0;
219681f6c7f8SVille Syrjälä 		mode_ptr = (struct drm_mode_modeinfo __user *)(unsigned long)out_resp->modes_ptr;
2197f453ba04SDave Airlie 		list_for_each_entry(mode, &connector->modes, head) {
219861d8e328SDamien Lespiau 			if (!drm_mode_expose_to_userspace(mode, file_priv))
219961d8e328SDamien Lespiau 				continue;
220061d8e328SDamien Lespiau 
2201934a8a89SDaniel Stone 			drm_mode_convert_to_umode(&u_mode, mode);
2202f453ba04SDave Airlie 			if (copy_to_user(mode_ptr + copied,
2203f453ba04SDave Airlie 					 &u_mode, sizeof(u_mode))) {
2204f453ba04SDave Airlie 				ret = -EFAULT;
2205f453ba04SDave Airlie 				goto out;
2206f453ba04SDave Airlie 			}
2207f453ba04SDave Airlie 			copied++;
2208f453ba04SDave Airlie 		}
2209f453ba04SDave Airlie 	}
2210f453ba04SDave Airlie 	out_resp->count_modes = mode_count;
2211f453ba04SDave Airlie 
221288a48e29SRob Clark 	ret = get_properties(&connector->base, file_priv->atomic,
221395cbf110SRob Clark 			(uint32_t __user *)(unsigned long)(out_resp->props_ptr),
221495cbf110SRob Clark 			(uint64_t __user *)(unsigned long)(out_resp->prop_values_ptr),
221595cbf110SRob Clark 			&out_resp->count_props);
221622b8b13bSRob Clark 	if (ret)
2217f453ba04SDave Airlie 		goto out;
2218f453ba04SDave Airlie 
2219f453ba04SDave Airlie 	if ((out_resp->count_encoders >= encoders_count) && encoders_count) {
2220f453ba04SDave Airlie 		copied = 0;
222181f6c7f8SVille Syrjälä 		encoder_ptr = (uint32_t __user *)(unsigned long)(out_resp->encoders_ptr);
2222f453ba04SDave Airlie 		for (i = 0; i < DRM_CONNECTOR_MAX_ENCODER; i++) {
2223f453ba04SDave Airlie 			if (connector->encoder_ids[i] != 0) {
2224f453ba04SDave Airlie 				if (put_user(connector->encoder_ids[i],
2225f453ba04SDave Airlie 					     encoder_ptr + copied)) {
2226f453ba04SDave Airlie 					ret = -EFAULT;
2227f453ba04SDave Airlie 					goto out;
2228f453ba04SDave Airlie 				}
2229f453ba04SDave Airlie 				copied++;
2230f453ba04SDave Airlie 			}
2231f453ba04SDave Airlie 		}
2232f453ba04SDave Airlie 	}
2233f453ba04SDave Airlie 	out_resp->count_encoders = encoders_count;
2234f453ba04SDave Airlie 
2235f453ba04SDave Airlie out:
2236ccfc0865SRob Clark 	drm_modeset_unlock(&dev->mode_config.connection_mutex);
223704bdf441STommi Rantala 
223804bdf441STommi Rantala out_unlock:
22397b24056bSDaniel Vetter 	mutex_unlock(&dev->mode_config.mutex);
22407b24056bSDaniel Vetter 
2241f453ba04SDave Airlie 	return ret;
2242f453ba04SDave Airlie }
2243f453ba04SDave Airlie 
2244abd69c55SDaniel Vetter static struct drm_crtc *drm_encoder_get_crtc(struct drm_encoder *encoder)
2245abd69c55SDaniel Vetter {
2246abd69c55SDaniel Vetter 	struct drm_connector *connector;
2247abd69c55SDaniel Vetter 	struct drm_device *dev = encoder->dev;
2248abd69c55SDaniel Vetter 	bool uses_atomic = false;
2249abd69c55SDaniel Vetter 
2250abd69c55SDaniel Vetter 	/* For atomic drivers only state objects are synchronously updated and
2251abd69c55SDaniel Vetter 	 * protected by modeset locks, so check those first. */
22526295d607SDaniel Vetter 	drm_for_each_connector(connector, dev) {
2253abd69c55SDaniel Vetter 		if (!connector->state)
2254abd69c55SDaniel Vetter 			continue;
2255abd69c55SDaniel Vetter 
2256abd69c55SDaniel Vetter 		uses_atomic = true;
2257abd69c55SDaniel Vetter 
2258abd69c55SDaniel Vetter 		if (connector->state->best_encoder != encoder)
2259abd69c55SDaniel Vetter 			continue;
2260abd69c55SDaniel Vetter 
2261abd69c55SDaniel Vetter 		return connector->state->crtc;
2262abd69c55SDaniel Vetter 	}
2263abd69c55SDaniel Vetter 
2264abd69c55SDaniel Vetter 	/* Don't return stale data (e.g. pending async disable). */
2265abd69c55SDaniel Vetter 	if (uses_atomic)
2266abd69c55SDaniel Vetter 		return NULL;
2267abd69c55SDaniel Vetter 
2268abd69c55SDaniel Vetter 	return encoder->crtc;
2269abd69c55SDaniel Vetter }
2270abd69c55SDaniel Vetter 
2271c8e32cc1SDaniel Vetter /**
2272c8e32cc1SDaniel Vetter  * drm_mode_getencoder - get encoder configuration
2273c8e32cc1SDaniel Vetter  * @dev: drm device for the ioctl
2274c8e32cc1SDaniel Vetter  * @data: data pointer for the ioctl
2275c8e32cc1SDaniel Vetter  * @file_priv: drm file for the ioctl call
2276c8e32cc1SDaniel Vetter  *
2277c8e32cc1SDaniel Vetter  * Construct a encoder configuration structure to return to the user.
2278c8e32cc1SDaniel Vetter  *
2279c8e32cc1SDaniel Vetter  * Called by the user via ioctl.
2280c8e32cc1SDaniel Vetter  *
2281c8e32cc1SDaniel Vetter  * Returns:
22821a498633SDaniel Vetter  * Zero on success, negative errno on failure.
2283c8e32cc1SDaniel Vetter  */
2284f453ba04SDave Airlie int drm_mode_getencoder(struct drm_device *dev, void *data,
2285f453ba04SDave Airlie 			struct drm_file *file_priv)
2286f453ba04SDave Airlie {
2287f453ba04SDave Airlie 	struct drm_mode_get_encoder *enc_resp = data;
2288f453ba04SDave Airlie 	struct drm_encoder *encoder;
2289abd69c55SDaniel Vetter 	struct drm_crtc *crtc;
2290f453ba04SDave Airlie 
2291fb3b06c8SDave Airlie 	if (!drm_core_check_feature(dev, DRIVER_MODESET))
2292fb3b06c8SDave Airlie 		return -EINVAL;
2293fb3b06c8SDave Airlie 
2294a2b34e22SRob Clark 	encoder = drm_encoder_find(dev, enc_resp->encoder_id);
2295fcf93f69SDaniel Vetter 	if (!encoder)
2296fcf93f69SDaniel Vetter 		return -ENOENT;
2297f453ba04SDave Airlie 
2298fcf93f69SDaniel Vetter 	drm_modeset_lock(&dev->mode_config.connection_mutex, NULL);
2299abd69c55SDaniel Vetter 	crtc = drm_encoder_get_crtc(encoder);
2300abd69c55SDaniel Vetter 	if (crtc)
2301abd69c55SDaniel Vetter 		enc_resp->crtc_id = crtc->base.id;
2302f453ba04SDave Airlie 	else
2303f453ba04SDave Airlie 		enc_resp->crtc_id = 0;
2304fcf93f69SDaniel Vetter 	drm_modeset_unlock(&dev->mode_config.connection_mutex);
2305fcf93f69SDaniel Vetter 
2306f453ba04SDave Airlie 	enc_resp->encoder_type = encoder->encoder_type;
2307f453ba04SDave Airlie 	enc_resp->encoder_id = encoder->base.id;
2308f453ba04SDave Airlie 	enc_resp->possible_crtcs = encoder->possible_crtcs;
2309f453ba04SDave Airlie 	enc_resp->possible_clones = encoder->possible_clones;
2310f453ba04SDave Airlie 
2311baf698b0SDaniel Vetter 	return 0;
2312f453ba04SDave Airlie }
2313f453ba04SDave Airlie 
2314f453ba04SDave Airlie /**
2315c8e32cc1SDaniel Vetter  * drm_mode_getplane_res - enumerate all plane resources
23168cf5c917SJesse Barnes  * @dev: DRM device
23178cf5c917SJesse Barnes  * @data: ioctl data
23188cf5c917SJesse Barnes  * @file_priv: DRM file info
23198cf5c917SJesse Barnes  *
2320c8e32cc1SDaniel Vetter  * Construct a list of plane ids to return to the user.
2321c8e32cc1SDaniel Vetter  *
2322c8e32cc1SDaniel Vetter  * Called by the user via ioctl.
2323c8e32cc1SDaniel Vetter  *
2324c8e32cc1SDaniel Vetter  * Returns:
23251a498633SDaniel Vetter  * Zero on success, negative errno on failure.
23268cf5c917SJesse Barnes  */
23278cf5c917SJesse Barnes int drm_mode_getplane_res(struct drm_device *dev, void *data,
23288cf5c917SJesse Barnes 			  struct drm_file *file_priv)
23298cf5c917SJesse Barnes {
23308cf5c917SJesse Barnes 	struct drm_mode_get_plane_res *plane_resp = data;
23318cf5c917SJesse Barnes 	struct drm_mode_config *config;
23328cf5c917SJesse Barnes 	struct drm_plane *plane;
23338cf5c917SJesse Barnes 	uint32_t __user *plane_ptr;
2334fcf93f69SDaniel Vetter 	int copied = 0;
2335681e7ec7SMatt Roper 	unsigned num_planes;
23368cf5c917SJesse Barnes 
23378cf5c917SJesse Barnes 	if (!drm_core_check_feature(dev, DRIVER_MODESET))
23388cf5c917SJesse Barnes 		return -EINVAL;
23398cf5c917SJesse Barnes 
23408cf5c917SJesse Barnes 	config = &dev->mode_config;
23418cf5c917SJesse Barnes 
2342681e7ec7SMatt Roper 	if (file_priv->universal_planes)
2343681e7ec7SMatt Roper 		num_planes = config->num_total_plane;
2344681e7ec7SMatt Roper 	else
2345681e7ec7SMatt Roper 		num_planes = config->num_overlay_plane;
2346681e7ec7SMatt Roper 
23478cf5c917SJesse Barnes 	/*
23488cf5c917SJesse Barnes 	 * This ioctl is called twice, once to determine how much space is
23498cf5c917SJesse Barnes 	 * needed, and the 2nd time to fill it.
23508cf5c917SJesse Barnes 	 */
2351681e7ec7SMatt Roper 	if (num_planes &&
2352681e7ec7SMatt Roper 	    (plane_resp->count_planes >= num_planes)) {
235381f6c7f8SVille Syrjälä 		plane_ptr = (uint32_t __user *)(unsigned long)plane_resp->plane_id_ptr;
23548cf5c917SJesse Barnes 
2355fcf93f69SDaniel Vetter 		/* Plane lists are invariant, no locking needed. */
2356e4f62546SDaniel Vetter 		drm_for_each_plane(plane, dev) {
2357681e7ec7SMatt Roper 			/*
2358681e7ec7SMatt Roper 			 * Unless userspace set the 'universal planes'
2359681e7ec7SMatt Roper 			 * capability bit, only advertise overlays.
2360681e7ec7SMatt Roper 			 */
2361681e7ec7SMatt Roper 			if (plane->type != DRM_PLANE_TYPE_OVERLAY &&
2362681e7ec7SMatt Roper 			    !file_priv->universal_planes)
2363e27dde3eSMatt Roper 				continue;
2364e27dde3eSMatt Roper 
2365fcf93f69SDaniel Vetter 			if (put_user(plane->base.id, plane_ptr + copied))
2366fcf93f69SDaniel Vetter 				return -EFAULT;
23678cf5c917SJesse Barnes 			copied++;
23688cf5c917SJesse Barnes 		}
23698cf5c917SJesse Barnes 	}
2370681e7ec7SMatt Roper 	plane_resp->count_planes = num_planes;
23718cf5c917SJesse Barnes 
2372fcf93f69SDaniel Vetter 	return 0;
23738cf5c917SJesse Barnes }
23748cf5c917SJesse Barnes 
23758cf5c917SJesse Barnes /**
2376c8e32cc1SDaniel Vetter  * drm_mode_getplane - get plane configuration
23778cf5c917SJesse Barnes  * @dev: DRM device
23788cf5c917SJesse Barnes  * @data: ioctl data
23798cf5c917SJesse Barnes  * @file_priv: DRM file info
23808cf5c917SJesse Barnes  *
2381c8e32cc1SDaniel Vetter  * Construct a plane configuration structure to return to the user.
2382c8e32cc1SDaniel Vetter  *
2383c8e32cc1SDaniel Vetter  * Called by the user via ioctl.
2384c8e32cc1SDaniel Vetter  *
2385c8e32cc1SDaniel Vetter  * Returns:
23861a498633SDaniel Vetter  * Zero on success, negative errno on failure.
23878cf5c917SJesse Barnes  */
23888cf5c917SJesse Barnes int drm_mode_getplane(struct drm_device *dev, void *data,
23898cf5c917SJesse Barnes 		      struct drm_file *file_priv)
23908cf5c917SJesse Barnes {
23918cf5c917SJesse Barnes 	struct drm_mode_get_plane *plane_resp = data;
23928cf5c917SJesse Barnes 	struct drm_plane *plane;
23938cf5c917SJesse Barnes 	uint32_t __user *format_ptr;
23948cf5c917SJesse Barnes 
23958cf5c917SJesse Barnes 	if (!drm_core_check_feature(dev, DRIVER_MODESET))
23968cf5c917SJesse Barnes 		return -EINVAL;
23978cf5c917SJesse Barnes 
2398a2b34e22SRob Clark 	plane = drm_plane_find(dev, plane_resp->plane_id);
2399fcf93f69SDaniel Vetter 	if (!plane)
2400fcf93f69SDaniel Vetter 		return -ENOENT;
24018cf5c917SJesse Barnes 
2402fcf93f69SDaniel Vetter 	drm_modeset_lock(&plane->mutex, NULL);
24038cf5c917SJesse Barnes 	if (plane->crtc)
24048cf5c917SJesse Barnes 		plane_resp->crtc_id = plane->crtc->base.id;
24058cf5c917SJesse Barnes 	else
24068cf5c917SJesse Barnes 		plane_resp->crtc_id = 0;
24078cf5c917SJesse Barnes 
24088cf5c917SJesse Barnes 	if (plane->fb)
24098cf5c917SJesse Barnes 		plane_resp->fb_id = plane->fb->base.id;
24108cf5c917SJesse Barnes 	else
24118cf5c917SJesse Barnes 		plane_resp->fb_id = 0;
2412fcf93f69SDaniel Vetter 	drm_modeset_unlock(&plane->mutex);
24138cf5c917SJesse Barnes 
24148cf5c917SJesse Barnes 	plane_resp->plane_id = plane->base.id;
24158cf5c917SJesse Barnes 	plane_resp->possible_crtcs = plane->possible_crtcs;
2416778ad903SVille Syrjälä 	plane_resp->gamma_size = 0;
24178cf5c917SJesse Barnes 
24188cf5c917SJesse Barnes 	/*
24198cf5c917SJesse Barnes 	 * This ioctl is called twice, once to determine how much space is
24208cf5c917SJesse Barnes 	 * needed, and the 2nd time to fill it.
24218cf5c917SJesse Barnes 	 */
24228cf5c917SJesse Barnes 	if (plane->format_count &&
24238cf5c917SJesse Barnes 	    (plane_resp->count_format_types >= plane->format_count)) {
242481f6c7f8SVille Syrjälä 		format_ptr = (uint32_t __user *)(unsigned long)plane_resp->format_type_ptr;
24258cf5c917SJesse Barnes 		if (copy_to_user(format_ptr,
24268cf5c917SJesse Barnes 				 plane->format_types,
24278cf5c917SJesse Barnes 				 sizeof(uint32_t) * plane->format_count)) {
2428fcf93f69SDaniel Vetter 			return -EFAULT;
24298cf5c917SJesse Barnes 		}
24308cf5c917SJesse Barnes 	}
24318cf5c917SJesse Barnes 	plane_resp->count_format_types = plane->format_count;
24328cf5c917SJesse Barnes 
2433baf698b0SDaniel Vetter 	return 0;
24348cf5c917SJesse Barnes }
24358cf5c917SJesse Barnes 
2436ead8610dSLaurent Pinchart /**
2437ead8610dSLaurent Pinchart  * drm_plane_check_pixel_format - Check if the plane supports the pixel format
2438ead8610dSLaurent Pinchart  * @plane: plane to check for format support
2439ead8610dSLaurent Pinchart  * @format: the pixel format
2440ead8610dSLaurent Pinchart  *
2441ead8610dSLaurent Pinchart  * Returns:
2442ead8610dSLaurent Pinchart  * Zero of @plane has @format in its list of supported pixel formats, -EINVAL
2443ead8610dSLaurent Pinchart  * otherwise.
2444ead8610dSLaurent Pinchart  */
2445ead8610dSLaurent Pinchart int drm_plane_check_pixel_format(const struct drm_plane *plane, u32 format)
2446ead8610dSLaurent Pinchart {
2447ead8610dSLaurent Pinchart 	unsigned int i;
2448ead8610dSLaurent Pinchart 
2449ead8610dSLaurent Pinchart 	for (i = 0; i < plane->format_count; i++) {
2450ead8610dSLaurent Pinchart 		if (format == plane->format_types[i])
2451ead8610dSLaurent Pinchart 			return 0;
2452ead8610dSLaurent Pinchart 	}
2453ead8610dSLaurent Pinchart 
2454ead8610dSLaurent Pinchart 	return -EINVAL;
2455ead8610dSLaurent Pinchart }
2456ead8610dSLaurent Pinchart 
2457ce8d9eccSVille Syrjälä static int check_src_coords(uint32_t src_x, uint32_t src_y,
2458ce8d9eccSVille Syrjälä 			    uint32_t src_w, uint32_t src_h,
2459ce8d9eccSVille Syrjälä 			    const struct drm_framebuffer *fb)
2460ce8d9eccSVille Syrjälä {
2461ce8d9eccSVille Syrjälä 	unsigned int fb_width, fb_height;
2462ce8d9eccSVille Syrjälä 
2463ce8d9eccSVille Syrjälä 	fb_width = fb->width << 16;
2464ce8d9eccSVille Syrjälä 	fb_height = fb->height << 16;
2465ce8d9eccSVille Syrjälä 
2466ce8d9eccSVille Syrjälä 	/* Make sure source coordinates are inside the fb. */
2467ce8d9eccSVille Syrjälä 	if (src_w > fb_width ||
2468ce8d9eccSVille Syrjälä 	    src_x > fb_width - src_w ||
2469ce8d9eccSVille Syrjälä 	    src_h > fb_height ||
2470ce8d9eccSVille Syrjälä 	    src_y > fb_height - src_h) {
2471ce8d9eccSVille Syrjälä 		DRM_DEBUG_KMS("Invalid source coordinates "
2472ce8d9eccSVille Syrjälä 			      "%u.%06ux%u.%06u+%u.%06u+%u.%06u\n",
2473ce8d9eccSVille Syrjälä 			      src_w >> 16, ((src_w & 0xffff) * 15625) >> 10,
2474ce8d9eccSVille Syrjälä 			      src_h >> 16, ((src_h & 0xffff) * 15625) >> 10,
2475ce8d9eccSVille Syrjälä 			      src_x >> 16, ((src_x & 0xffff) * 15625) >> 10,
2476ce8d9eccSVille Syrjälä 			      src_y >> 16, ((src_y & 0xffff) * 15625) >> 10);
2477ce8d9eccSVille Syrjälä 		return -ENOSPC;
2478ce8d9eccSVille Syrjälä 	}
2479ce8d9eccSVille Syrjälä 
2480ce8d9eccSVille Syrjälä 	return 0;
2481ce8d9eccSVille Syrjälä }
2482ce8d9eccSVille Syrjälä 
2483b36552b3SMatt Roper /*
2484b36552b3SMatt Roper  * setplane_internal - setplane handler for internal callers
24858cf5c917SJesse Barnes  *
2486b36552b3SMatt Roper  * Note that we assume an extra reference has already been taken on fb.  If the
2487b36552b3SMatt Roper  * update fails, this reference will be dropped before return; if it succeeds,
2488b36552b3SMatt Roper  * the previous framebuffer (if any) will be unreferenced instead.
2489c8e32cc1SDaniel Vetter  *
2490b36552b3SMatt Roper  * src_{x,y,w,h} are provided in 16.16 fixed point format
24918cf5c917SJesse Barnes  */
2492f2b50c11SDaniel Vetter static int __setplane_internal(struct drm_plane *plane,
249317cfd91fSChris Wilson 			       struct drm_crtc *crtc,
2494b36552b3SMatt Roper 			       struct drm_framebuffer *fb,
2495b36552b3SMatt Roper 			       int32_t crtc_x, int32_t crtc_y,
2496b36552b3SMatt Roper 			       uint32_t crtc_w, uint32_t crtc_h,
2497b36552b3SMatt Roper 			       /* src_{x,y,w,h} values are 16.16 fixed point */
2498b36552b3SMatt Roper 			       uint32_t src_x, uint32_t src_y,
2499b36552b3SMatt Roper 			       uint32_t src_w, uint32_t src_h)
25008cf5c917SJesse Barnes {
25018cf5c917SJesse Barnes 	int ret = 0;
25028cf5c917SJesse Barnes 
25038cf5c917SJesse Barnes 	/* No fb means shut it down */
2504b36552b3SMatt Roper 	if (!fb) {
25053d30a59bSDaniel Vetter 		plane->old_fb = plane->fb;
2506731cce48SDaniel Vetter 		ret = plane->funcs->disable_plane(plane);
2507731cce48SDaniel Vetter 		if (!ret) {
2508e5e3b44cSVille Syrjälä 			plane->crtc = NULL;
2509e5e3b44cSVille Syrjälä 			plane->fb = NULL;
2510731cce48SDaniel Vetter 		} else {
25113d30a59bSDaniel Vetter 			plane->old_fb = NULL;
2512731cce48SDaniel Vetter 		}
25138cf5c917SJesse Barnes 		goto out;
25148cf5c917SJesse Barnes 	}
25158cf5c917SJesse Barnes 
25167f994f3fSMatt Roper 	/* Check whether this plane is usable on this CRTC */
25177f994f3fSMatt Roper 	if (!(plane->possible_crtcs & drm_crtc_mask(crtc))) {
25187f994f3fSMatt Roper 		DRM_DEBUG_KMS("Invalid crtc for plane\n");
25197f994f3fSMatt Roper 		ret = -EINVAL;
25207f994f3fSMatt Roper 		goto out;
25217f994f3fSMatt Roper 	}
25227f994f3fSMatt Roper 
252362443be6SVille Syrjälä 	/* Check whether this plane supports the fb pixel format. */
2524ead8610dSLaurent Pinchart 	ret = drm_plane_check_pixel_format(plane, fb->pixel_format);
2525ead8610dSLaurent Pinchart 	if (ret) {
25266ba6d03eSVille Syrjälä 		DRM_DEBUG_KMS("Invalid pixel format %s\n",
25276ba6d03eSVille Syrjälä 			      drm_get_format_name(fb->pixel_format));
252862443be6SVille Syrjälä 		goto out;
252962443be6SVille Syrjälä 	}
253062443be6SVille Syrjälä 
25313968be94SMatt Roper 	/* Give drivers some help against integer overflows */
25323968be94SMatt Roper 	if (crtc_w > INT_MAX ||
25333968be94SMatt Roper 	    crtc_x > INT_MAX - (int32_t) crtc_w ||
25343968be94SMatt Roper 	    crtc_h > INT_MAX ||
25353968be94SMatt Roper 	    crtc_y > INT_MAX - (int32_t) crtc_h) {
25363968be94SMatt Roper 		DRM_DEBUG_KMS("Invalid CRTC coordinates %ux%u+%d+%d\n",
25373968be94SMatt Roper 			      crtc_w, crtc_h, crtc_x, crtc_y);
2538c390eed0SVille Syrjälä 		ret = -ERANGE;
253942ef8789SVille Syrjälä 		goto out;
254042ef8789SVille Syrjälä 	}
254142ef8789SVille Syrjälä 
2542ce8d9eccSVille Syrjälä 	ret = check_src_coords(src_x, src_y, src_w, src_h, fb);
2543ce8d9eccSVille Syrjälä 	if (ret)
2544f453ba04SDave Airlie 		goto out;
2545f453ba04SDave Airlie 
25463d30a59bSDaniel Vetter 	plane->old_fb = plane->fb;
2547f453ba04SDave Airlie 	ret = plane->funcs->update_plane(plane, crtc, fb,
2548b36552b3SMatt Roper 					 crtc_x, crtc_y, crtc_w, crtc_h,
2549b36552b3SMatt Roper 					 src_x, src_y, src_w, src_h);
2550f453ba04SDave Airlie 	if (!ret) {
2551f453ba04SDave Airlie 		plane->crtc = crtc;
2552f453ba04SDave Airlie 		plane->fb = fb;
255335f8badcSDaniel Vetter 		fb = NULL;
25540fe27f06SDaniel Vetter 	} else {
25553d30a59bSDaniel Vetter 		plane->old_fb = NULL;
2556f453ba04SDave Airlie 	}
2557f453ba04SDave Airlie 
2558f453ba04SDave Airlie out:
25596c2a7532SDaniel Vetter 	if (fb)
25606c2a7532SDaniel Vetter 		drm_framebuffer_unreference(fb);
25613d30a59bSDaniel Vetter 	if (plane->old_fb)
25623d30a59bSDaniel Vetter 		drm_framebuffer_unreference(plane->old_fb);
25633d30a59bSDaniel Vetter 	plane->old_fb = NULL;
2564f453ba04SDave Airlie 
2565f453ba04SDave Airlie 	return ret;
2566f2b50c11SDaniel Vetter }
2567b36552b3SMatt Roper 
2568f2b50c11SDaniel Vetter static int setplane_internal(struct drm_plane *plane,
2569f2b50c11SDaniel Vetter 			     struct drm_crtc *crtc,
2570f2b50c11SDaniel Vetter 			     struct drm_framebuffer *fb,
2571f2b50c11SDaniel Vetter 			     int32_t crtc_x, int32_t crtc_y,
2572f2b50c11SDaniel Vetter 			     uint32_t crtc_w, uint32_t crtc_h,
2573f2b50c11SDaniel Vetter 			     /* src_{x,y,w,h} values are 16.16 fixed point */
2574f2b50c11SDaniel Vetter 			     uint32_t src_x, uint32_t src_y,
2575f2b50c11SDaniel Vetter 			     uint32_t src_w, uint32_t src_h)
2576f2b50c11SDaniel Vetter {
2577f2b50c11SDaniel Vetter 	int ret;
2578f2b50c11SDaniel Vetter 
2579f2b50c11SDaniel Vetter 	drm_modeset_lock_all(plane->dev);
2580f2b50c11SDaniel Vetter 	ret = __setplane_internal(plane, crtc, fb,
2581f2b50c11SDaniel Vetter 				  crtc_x, crtc_y, crtc_w, crtc_h,
2582f2b50c11SDaniel Vetter 				  src_x, src_y, src_w, src_h);
2583f2b50c11SDaniel Vetter 	drm_modeset_unlock_all(plane->dev);
2584f2b50c11SDaniel Vetter 
2585f2b50c11SDaniel Vetter 	return ret;
2586b36552b3SMatt Roper }
2587b36552b3SMatt Roper 
2588b36552b3SMatt Roper /**
2589b36552b3SMatt Roper  * drm_mode_setplane - configure a plane's configuration
2590b36552b3SMatt Roper  * @dev: DRM device
2591b36552b3SMatt Roper  * @data: ioctl data*
2592b36552b3SMatt Roper  * @file_priv: DRM file info
2593b36552b3SMatt Roper  *
2594b36552b3SMatt Roper  * Set plane configuration, including placement, fb, scaling, and other factors.
2595b36552b3SMatt Roper  * Or pass a NULL fb to disable (planes may be disabled without providing a
2596b36552b3SMatt Roper  * valid crtc).
2597b36552b3SMatt Roper  *
2598b36552b3SMatt Roper  * Returns:
25991a498633SDaniel Vetter  * Zero on success, negative errno on failure.
2600b36552b3SMatt Roper  */
2601b36552b3SMatt Roper int drm_mode_setplane(struct drm_device *dev, void *data,
2602b36552b3SMatt Roper 		      struct drm_file *file_priv)
2603b36552b3SMatt Roper {
2604b36552b3SMatt Roper 	struct drm_mode_set_plane *plane_req = data;
2605b36552b3SMatt Roper 	struct drm_plane *plane;
2606b36552b3SMatt Roper 	struct drm_crtc *crtc = NULL;
2607b36552b3SMatt Roper 	struct drm_framebuffer *fb = NULL;
2608b36552b3SMatt Roper 
2609b36552b3SMatt Roper 	if (!drm_core_check_feature(dev, DRIVER_MODESET))
2610b36552b3SMatt Roper 		return -EINVAL;
2611b36552b3SMatt Roper 
2612b36552b3SMatt Roper 	/*
2613b36552b3SMatt Roper 	 * First, find the plane, crtc, and fb objects.  If not available,
2614b36552b3SMatt Roper 	 * we don't bother to call the driver.
2615b36552b3SMatt Roper 	 */
2616933f622fSRob Clark 	plane = drm_plane_find(dev, plane_req->plane_id);
2617933f622fSRob Clark 	if (!plane) {
2618b36552b3SMatt Roper 		DRM_DEBUG_KMS("Unknown plane ID %d\n",
2619b36552b3SMatt Roper 			      plane_req->plane_id);
2620b36552b3SMatt Roper 		return -ENOENT;
2621b36552b3SMatt Roper 	}
2622b36552b3SMatt Roper 
2623b36552b3SMatt Roper 	if (plane_req->fb_id) {
2624b36552b3SMatt Roper 		fb = drm_framebuffer_lookup(dev, plane_req->fb_id);
2625b36552b3SMatt Roper 		if (!fb) {
2626b36552b3SMatt Roper 			DRM_DEBUG_KMS("Unknown framebuffer ID %d\n",
2627b36552b3SMatt Roper 				      plane_req->fb_id);
2628b36552b3SMatt Roper 			return -ENOENT;
2629b36552b3SMatt Roper 		}
2630b36552b3SMatt Roper 
2631933f622fSRob Clark 		crtc = drm_crtc_find(dev, plane_req->crtc_id);
2632933f622fSRob Clark 		if (!crtc) {
2633b36552b3SMatt Roper 			DRM_DEBUG_KMS("Unknown crtc ID %d\n",
2634b36552b3SMatt Roper 				      plane_req->crtc_id);
2635b36552b3SMatt Roper 			return -ENOENT;
2636b36552b3SMatt Roper 		}
2637b36552b3SMatt Roper 	}
2638b36552b3SMatt Roper 
2639161d0dc1SMatt Roper 	/*
2640161d0dc1SMatt Roper 	 * setplane_internal will take care of deref'ing either the old or new
2641161d0dc1SMatt Roper 	 * framebuffer depending on success.
2642161d0dc1SMatt Roper 	 */
264317cfd91fSChris Wilson 	return setplane_internal(plane, crtc, fb,
2644b36552b3SMatt Roper 				 plane_req->crtc_x, plane_req->crtc_y,
2645b36552b3SMatt Roper 				 plane_req->crtc_w, plane_req->crtc_h,
2646b36552b3SMatt Roper 				 plane_req->src_x, plane_req->src_y,
2647b36552b3SMatt Roper 				 plane_req->src_w, plane_req->src_h);
2648f453ba04SDave Airlie }
2649f453ba04SDave Airlie 
2650f453ba04SDave Airlie /**
26512d13b679SDaniel Vetter  * drm_mode_set_config_internal - helper to call ->set_config
26522d13b679SDaniel Vetter  * @set: modeset config to set
26532d13b679SDaniel Vetter  *
26542d13b679SDaniel Vetter  * This is a little helper to wrap internal calls to the ->set_config driver
26552d13b679SDaniel Vetter  * interface. The only thing it adds is correct refcounting dance.
2656c8e32cc1SDaniel Vetter  *
2657c8e32cc1SDaniel Vetter  * Returns:
26581a498633SDaniel Vetter  * Zero on success, negative errno on failure.
26592d13b679SDaniel Vetter  */
26602d13b679SDaniel Vetter int drm_mode_set_config_internal(struct drm_mode_set *set)
26612d13b679SDaniel Vetter {
26622d13b679SDaniel Vetter 	struct drm_crtc *crtc = set->crtc;
26635cef29aaSDaniel Vetter 	struct drm_framebuffer *fb;
26645cef29aaSDaniel Vetter 	struct drm_crtc *tmp;
2665b0d12325SDaniel Vetter 	int ret;
26662d13b679SDaniel Vetter 
26675cef29aaSDaniel Vetter 	/*
26685cef29aaSDaniel Vetter 	 * NOTE: ->set_config can also disable other crtcs (if we steal all
26695cef29aaSDaniel Vetter 	 * connectors from it), hence we need to refcount the fbs across all
26705cef29aaSDaniel Vetter 	 * crtcs. Atomic modeset will have saner semantics ...
26715cef29aaSDaniel Vetter 	 */
2672e4f62546SDaniel Vetter 	drm_for_each_crtc(tmp, crtc->dev)
26733d30a59bSDaniel Vetter 		tmp->primary->old_fb = tmp->primary->fb;
26745cef29aaSDaniel Vetter 
2675b0d12325SDaniel Vetter 	fb = set->fb;
2676b0d12325SDaniel Vetter 
2677b0d12325SDaniel Vetter 	ret = crtc->funcs->set_config(set);
2678b0d12325SDaniel Vetter 	if (ret == 0) {
2679e13161afSMatt Roper 		crtc->primary->crtc = crtc;
26800fe27f06SDaniel Vetter 		crtc->primary->fb = fb;
26815cef29aaSDaniel Vetter 	}
2682cc85e121SDaniel Vetter 
2683e4f62546SDaniel Vetter 	drm_for_each_crtc(tmp, crtc->dev) {
2684f4510a27SMatt Roper 		if (tmp->primary->fb)
2685f4510a27SMatt Roper 			drm_framebuffer_reference(tmp->primary->fb);
26863d30a59bSDaniel Vetter 		if (tmp->primary->old_fb)
26873d30a59bSDaniel Vetter 			drm_framebuffer_unreference(tmp->primary->old_fb);
26883d30a59bSDaniel Vetter 		tmp->primary->old_fb = NULL;
2689b0d12325SDaniel Vetter 	}
2690b0d12325SDaniel Vetter 
2691b0d12325SDaniel Vetter 	return ret;
26922d13b679SDaniel Vetter }
26932d13b679SDaniel Vetter EXPORT_SYMBOL(drm_mode_set_config_internal);
26942d13b679SDaniel Vetter 
2695af93629dSMatt Roper /**
2696ecb7e16bSGustavo Padovan  * drm_crtc_get_hv_timing - Fetches hdisplay/vdisplay for given mode
2697ecb7e16bSGustavo Padovan  * @mode: mode to query
2698ecb7e16bSGustavo Padovan  * @hdisplay: hdisplay value to fill in
2699ecb7e16bSGustavo Padovan  * @vdisplay: vdisplay value to fill in
2700ecb7e16bSGustavo Padovan  *
2701ecb7e16bSGustavo Padovan  * The vdisplay value will be doubled if the specified mode is a stereo mode of
2702ecb7e16bSGustavo Padovan  * the appropriate layout.
2703ecb7e16bSGustavo Padovan  */
2704ecb7e16bSGustavo Padovan void drm_crtc_get_hv_timing(const struct drm_display_mode *mode,
2705ecb7e16bSGustavo Padovan 			    int *hdisplay, int *vdisplay)
2706ecb7e16bSGustavo Padovan {
2707ecb7e16bSGustavo Padovan 	struct drm_display_mode adjusted;
2708ecb7e16bSGustavo Padovan 
2709ecb7e16bSGustavo Padovan 	drm_mode_copy(&adjusted, mode);
2710ecb7e16bSGustavo Padovan 	drm_mode_set_crtcinfo(&adjusted, CRTC_STEREO_DOUBLE_ONLY);
2711ecb7e16bSGustavo Padovan 	*hdisplay = adjusted.crtc_hdisplay;
2712ecb7e16bSGustavo Padovan 	*vdisplay = adjusted.crtc_vdisplay;
2713ecb7e16bSGustavo Padovan }
2714ecb7e16bSGustavo Padovan EXPORT_SYMBOL(drm_crtc_get_hv_timing);
2715ecb7e16bSGustavo Padovan 
2716ecb7e16bSGustavo Padovan /**
2717af93629dSMatt Roper  * drm_crtc_check_viewport - Checks that a framebuffer is big enough for the
2718af93629dSMatt Roper  *     CRTC viewport
2719af93629dSMatt Roper  * @crtc: CRTC that framebuffer will be displayed on
2720af93629dSMatt Roper  * @x: x panning
2721af93629dSMatt Roper  * @y: y panning
2722af93629dSMatt Roper  * @mode: mode that framebuffer will be displayed under
2723af93629dSMatt Roper  * @fb: framebuffer to check size of
2724c11e9283SDamien Lespiau  */
2725af93629dSMatt Roper int drm_crtc_check_viewport(const struct drm_crtc *crtc,
2726c11e9283SDamien Lespiau 			    int x, int y,
2727c11e9283SDamien Lespiau 			    const struct drm_display_mode *mode,
2728c11e9283SDamien Lespiau 			    const struct drm_framebuffer *fb)
2729c11e9283SDamien Lespiau 
2730c11e9283SDamien Lespiau {
2731c11e9283SDamien Lespiau 	int hdisplay, vdisplay;
2732c11e9283SDamien Lespiau 
2733ecb7e16bSGustavo Padovan 	drm_crtc_get_hv_timing(mode, &hdisplay, &vdisplay);
2734a0c1bbb0SDamien Lespiau 
273533e0be63SVille Syrjälä 	if (crtc->state &&
273633e0be63SVille Syrjälä 	    crtc->primary->state->rotation & (BIT(DRM_ROTATE_90) |
273733e0be63SVille Syrjälä 					      BIT(DRM_ROTATE_270)))
2738c11e9283SDamien Lespiau 		swap(hdisplay, vdisplay);
2739c11e9283SDamien Lespiau 
2740ce8d9eccSVille Syrjälä 	return check_src_coords(x << 16, y << 16,
2741ce8d9eccSVille Syrjälä 				hdisplay << 16, vdisplay << 16, fb);
2742c11e9283SDamien Lespiau }
2743af93629dSMatt Roper EXPORT_SYMBOL(drm_crtc_check_viewport);
2744c11e9283SDamien Lespiau 
27452d13b679SDaniel Vetter /**
2746f453ba04SDave Airlie  * drm_mode_setcrtc - set CRTC configuration
2747065a50edSDaniel Vetter  * @dev: drm device for the ioctl
2748065a50edSDaniel Vetter  * @data: data pointer for the ioctl
2749065a50edSDaniel Vetter  * @file_priv: drm file for the ioctl call
2750f453ba04SDave Airlie  *
2751f453ba04SDave Airlie  * Build a new CRTC configuration based on user request.
2752f453ba04SDave Airlie  *
2753f453ba04SDave Airlie  * Called by the user via ioctl.
2754f453ba04SDave Airlie  *
2755c8e32cc1SDaniel Vetter  * Returns:
27561a498633SDaniel Vetter  * Zero on success, negative errno on failure.
2757f453ba04SDave Airlie  */
2758f453ba04SDave Airlie int drm_mode_setcrtc(struct drm_device *dev, void *data,
2759f453ba04SDave Airlie 		     struct drm_file *file_priv)
2760f453ba04SDave Airlie {
2761f453ba04SDave Airlie 	struct drm_mode_config *config = &dev->mode_config;
2762f453ba04SDave Airlie 	struct drm_mode_crtc *crtc_req = data;
27636653cc8dSVille Syrjälä 	struct drm_crtc *crtc;
2764f453ba04SDave Airlie 	struct drm_connector **connector_set = NULL, *connector;
2765f453ba04SDave Airlie 	struct drm_framebuffer *fb = NULL;
2766f453ba04SDave Airlie 	struct drm_display_mode *mode = NULL;
2767f453ba04SDave Airlie 	struct drm_mode_set set;
2768f453ba04SDave Airlie 	uint32_t __user *set_connectors_ptr;
27694a1b0714SLaurent Pinchart 	int ret;
2770f453ba04SDave Airlie 	int i;
2771f453ba04SDave Airlie 
2772fb3b06c8SDave Airlie 	if (!drm_core_check_feature(dev, DRIVER_MODESET))
2773fb3b06c8SDave Airlie 		return -EINVAL;
2774fb3b06c8SDave Airlie 
277501447e9fSZhao Junwang 	/*
277601447e9fSZhao Junwang 	 * Universal plane src offsets are only 16.16, prevent havoc for
277701447e9fSZhao Junwang 	 * drivers using universal plane code internally.
277801447e9fSZhao Junwang 	 */
277901447e9fSZhao Junwang 	if (crtc_req->x & 0xffff0000 || crtc_req->y & 0xffff0000)
27801d97e915SVille Syrjälä 		return -ERANGE;
27811d97e915SVille Syrjälä 
278284849903SDaniel Vetter 	drm_modeset_lock_all(dev);
2783a2b34e22SRob Clark 	crtc = drm_crtc_find(dev, crtc_req->crtc_id);
2784a2b34e22SRob Clark 	if (!crtc) {
278558367ed6SZhao Yakui 		DRM_DEBUG_KMS("Unknown CRTC ID %d\n", crtc_req->crtc_id);
2786f27657f2SVille Syrjälä 		ret = -ENOENT;
2787f453ba04SDave Airlie 		goto out;
2788f453ba04SDave Airlie 	}
2789fa3ab4c2SVille Syrjälä 	DRM_DEBUG_KMS("[CRTC:%d:%s]\n", crtc->base.id, crtc->name);
2790f453ba04SDave Airlie 
2791f453ba04SDave Airlie 	if (crtc_req->mode_valid) {
2792f453ba04SDave Airlie 		/* If we have a mode we need a framebuffer. */
2793f453ba04SDave Airlie 		/* If we pass -1, set the mode with the currently bound fb */
2794f453ba04SDave Airlie 		if (crtc_req->fb_id == -1) {
2795f4510a27SMatt Roper 			if (!crtc->primary->fb) {
27966653cc8dSVille Syrjälä 				DRM_DEBUG_KMS("CRTC doesn't have current FB\n");
27976653cc8dSVille Syrjälä 				ret = -EINVAL;
27986653cc8dSVille Syrjälä 				goto out;
27996653cc8dSVille Syrjälä 			}
2800f4510a27SMatt Roper 			fb = crtc->primary->fb;
2801b0d12325SDaniel Vetter 			/* Make refcounting symmetric with the lookup path. */
2802b0d12325SDaniel Vetter 			drm_framebuffer_reference(fb);
2803f453ba04SDave Airlie 		} else {
2804786b99edSDaniel Vetter 			fb = drm_framebuffer_lookup(dev, crtc_req->fb_id);
2805786b99edSDaniel Vetter 			if (!fb) {
280658367ed6SZhao Yakui 				DRM_DEBUG_KMS("Unknown FB ID%d\n",
280758367ed6SZhao Yakui 						crtc_req->fb_id);
280837c4e705SVille Syrjälä 				ret = -ENOENT;
2809f453ba04SDave Airlie 				goto out;
2810f453ba04SDave Airlie 			}
2811f453ba04SDave Airlie 		}
2812f453ba04SDave Airlie 
2813f453ba04SDave Airlie 		mode = drm_mode_create(dev);
2814ee34ab5bSVille Syrjälä 		if (!mode) {
2815ee34ab5bSVille Syrjälä 			ret = -ENOMEM;
2816ee34ab5bSVille Syrjälä 			goto out;
2817ee34ab5bSVille Syrjälä 		}
2818ee34ab5bSVille Syrjälä 
2819934a8a89SDaniel Stone 		ret = drm_mode_convert_umode(mode, &crtc_req->mode);
282090367bf6SVille Syrjälä 		if (ret) {
282190367bf6SVille Syrjälä 			DRM_DEBUG_KMS("Invalid mode\n");
282290367bf6SVille Syrjälä 			goto out;
282390367bf6SVille Syrjälä 		}
282490367bf6SVille Syrjälä 
2825f453ba04SDave Airlie 		drm_mode_set_crtcinfo(mode, CRTC_INTERLACE_HALVE_V);
28265f61bb42SVille Syrjälä 
28277eb5f302SLaurent Pinchart 		/*
28287eb5f302SLaurent Pinchart 		 * Check whether the primary plane supports the fb pixel format.
28297eb5f302SLaurent Pinchart 		 * Drivers not implementing the universal planes API use a
28307eb5f302SLaurent Pinchart 		 * default formats list provided by the DRM core which doesn't
28317eb5f302SLaurent Pinchart 		 * match real hardware capabilities. Skip the check in that
28327eb5f302SLaurent Pinchart 		 * case.
28337eb5f302SLaurent Pinchart 		 */
28347eb5f302SLaurent Pinchart 		if (!crtc->primary->format_default) {
28357eb5f302SLaurent Pinchart 			ret = drm_plane_check_pixel_format(crtc->primary,
28367eb5f302SLaurent Pinchart 							   fb->pixel_format);
28377eb5f302SLaurent Pinchart 			if (ret) {
28387eb5f302SLaurent Pinchart 				DRM_DEBUG_KMS("Invalid pixel format %s\n",
28397eb5f302SLaurent Pinchart 					drm_get_format_name(fb->pixel_format));
28407eb5f302SLaurent Pinchart 				goto out;
28417eb5f302SLaurent Pinchart 			}
28427eb5f302SLaurent Pinchart 		}
28437eb5f302SLaurent Pinchart 
2844c11e9283SDamien Lespiau 		ret = drm_crtc_check_viewport(crtc, crtc_req->x, crtc_req->y,
2845c11e9283SDamien Lespiau 					      mode, fb);
2846c11e9283SDamien Lespiau 		if (ret)
28475f61bb42SVille Syrjälä 			goto out;
2848c11e9283SDamien Lespiau 
2849f453ba04SDave Airlie 	}
2850f453ba04SDave Airlie 
2851f453ba04SDave Airlie 	if (crtc_req->count_connectors == 0 && mode) {
285258367ed6SZhao Yakui 		DRM_DEBUG_KMS("Count connectors is 0 but mode set\n");
2853f453ba04SDave Airlie 		ret = -EINVAL;
2854f453ba04SDave Airlie 		goto out;
2855f453ba04SDave Airlie 	}
2856f453ba04SDave Airlie 
28577781de74SJakob Bornecrantz 	if (crtc_req->count_connectors > 0 && (!mode || !fb)) {
285858367ed6SZhao Yakui 		DRM_DEBUG_KMS("Count connectors is %d but no mode or fb set\n",
2859f453ba04SDave Airlie 			  crtc_req->count_connectors);
2860f453ba04SDave Airlie 		ret = -EINVAL;
2861f453ba04SDave Airlie 		goto out;
2862f453ba04SDave Airlie 	}
2863f453ba04SDave Airlie 
2864f453ba04SDave Airlie 	if (crtc_req->count_connectors > 0) {
2865f453ba04SDave Airlie 		u32 out_id;
2866f453ba04SDave Airlie 
2867f453ba04SDave Airlie 		/* Avoid unbounded kernel memory allocation */
2868f453ba04SDave Airlie 		if (crtc_req->count_connectors > config->num_connector) {
2869f453ba04SDave Airlie 			ret = -EINVAL;
2870f453ba04SDave Airlie 			goto out;
2871f453ba04SDave Airlie 		}
2872f453ba04SDave Airlie 
28732f6c5389SThierry Reding 		connector_set = kmalloc_array(crtc_req->count_connectors,
2874f453ba04SDave Airlie 					      sizeof(struct drm_connector *),
2875f453ba04SDave Airlie 					      GFP_KERNEL);
2876f453ba04SDave Airlie 		if (!connector_set) {
2877f453ba04SDave Airlie 			ret = -ENOMEM;
2878f453ba04SDave Airlie 			goto out;
2879f453ba04SDave Airlie 		}
2880f453ba04SDave Airlie 
2881f453ba04SDave Airlie 		for (i = 0; i < crtc_req->count_connectors; i++) {
288281f6c7f8SVille Syrjälä 			set_connectors_ptr = (uint32_t __user *)(unsigned long)crtc_req->set_connectors_ptr;
2883f453ba04SDave Airlie 			if (get_user(out_id, &set_connectors_ptr[i])) {
2884f453ba04SDave Airlie 				ret = -EFAULT;
2885f453ba04SDave Airlie 				goto out;
2886f453ba04SDave Airlie 			}
2887f453ba04SDave Airlie 
2888a2b34e22SRob Clark 			connector = drm_connector_find(dev, out_id);
2889a2b34e22SRob Clark 			if (!connector) {
289058367ed6SZhao Yakui 				DRM_DEBUG_KMS("Connector id %d unknown\n",
289158367ed6SZhao Yakui 						out_id);
2892f27657f2SVille Syrjälä 				ret = -ENOENT;
2893f453ba04SDave Airlie 				goto out;
2894f453ba04SDave Airlie 			}
28959440106bSJerome Glisse 			DRM_DEBUG_KMS("[CONNECTOR:%d:%s]\n",
28969440106bSJerome Glisse 					connector->base.id,
289725933820SJani Nikula 					connector->name);
2898f453ba04SDave Airlie 
2899f453ba04SDave Airlie 			connector_set[i] = connector;
2900f453ba04SDave Airlie 		}
2901f453ba04SDave Airlie 	}
2902f453ba04SDave Airlie 
2903f453ba04SDave Airlie 	set.crtc = crtc;
2904f453ba04SDave Airlie 	set.x = crtc_req->x;
2905f453ba04SDave Airlie 	set.y = crtc_req->y;
2906f453ba04SDave Airlie 	set.mode = mode;
2907f453ba04SDave Airlie 	set.connectors = connector_set;
2908f453ba04SDave Airlie 	set.num_connectors = crtc_req->count_connectors;
2909f453ba04SDave Airlie 	set.fb = fb;
29102d13b679SDaniel Vetter 	ret = drm_mode_set_config_internal(&set);
2911f453ba04SDave Airlie 
2912f453ba04SDave Airlie out:
2913b0d12325SDaniel Vetter 	if (fb)
2914b0d12325SDaniel Vetter 		drm_framebuffer_unreference(fb);
2915b0d12325SDaniel Vetter 
2916f453ba04SDave Airlie 	kfree(connector_set);
2917ee34ab5bSVille Syrjälä 	drm_mode_destroy(dev, mode);
291884849903SDaniel Vetter 	drm_modeset_unlock_all(dev);
2919f453ba04SDave Airlie 	return ret;
2920f453ba04SDave Airlie }
2921f453ba04SDave Airlie 
2922161d0dc1SMatt Roper /**
2923161d0dc1SMatt Roper  * drm_mode_cursor_universal - translate legacy cursor ioctl call into a
2924161d0dc1SMatt Roper  *     universal plane handler call
2925161d0dc1SMatt Roper  * @crtc: crtc to update cursor for
2926161d0dc1SMatt Roper  * @req: data pointer for the ioctl
2927161d0dc1SMatt Roper  * @file_priv: drm file for the ioctl call
2928161d0dc1SMatt Roper  *
2929161d0dc1SMatt Roper  * Legacy cursor ioctl's work directly with driver buffer handles.  To
2930161d0dc1SMatt Roper  * translate legacy ioctl calls into universal plane handler calls, we need to
2931161d0dc1SMatt Roper  * wrap the native buffer handle in a drm_framebuffer.
2932161d0dc1SMatt Roper  *
2933161d0dc1SMatt Roper  * Note that we assume any handle passed to the legacy ioctls was a 32-bit ARGB
2934161d0dc1SMatt Roper  * buffer with a pitch of 4*width; the universal plane interface should be used
2935161d0dc1SMatt Roper  * directly in cases where the hardware can support other buffer settings and
2936161d0dc1SMatt Roper  * userspace wants to make use of these capabilities.
2937161d0dc1SMatt Roper  *
2938161d0dc1SMatt Roper  * Returns:
29391a498633SDaniel Vetter  * Zero on success, negative errno on failure.
2940161d0dc1SMatt Roper  */
2941161d0dc1SMatt Roper static int drm_mode_cursor_universal(struct drm_crtc *crtc,
2942161d0dc1SMatt Roper 				     struct drm_mode_cursor2 *req,
2943161d0dc1SMatt Roper 				     struct drm_file *file_priv)
2944161d0dc1SMatt Roper {
2945161d0dc1SMatt Roper 	struct drm_device *dev = crtc->dev;
2946161d0dc1SMatt Roper 	struct drm_framebuffer *fb = NULL;
2947161d0dc1SMatt Roper 	struct drm_mode_fb_cmd2 fbreq = {
2948161d0dc1SMatt Roper 		.width = req->width,
2949161d0dc1SMatt Roper 		.height = req->height,
2950161d0dc1SMatt Roper 		.pixel_format = DRM_FORMAT_ARGB8888,
2951161d0dc1SMatt Roper 		.pitches = { req->width * 4 },
2952161d0dc1SMatt Roper 		.handles = { req->handle },
2953161d0dc1SMatt Roper 	};
2954161d0dc1SMatt Roper 	int32_t crtc_x, crtc_y;
2955161d0dc1SMatt Roper 	uint32_t crtc_w = 0, crtc_h = 0;
2956161d0dc1SMatt Roper 	uint32_t src_w = 0, src_h = 0;
2957161d0dc1SMatt Roper 	int ret = 0;
2958161d0dc1SMatt Roper 
2959161d0dc1SMatt Roper 	BUG_ON(!crtc->cursor);
2960f2b50c11SDaniel Vetter 	WARN_ON(crtc->cursor->crtc != crtc && crtc->cursor->crtc != NULL);
2961161d0dc1SMatt Roper 
2962161d0dc1SMatt Roper 	/*
2963161d0dc1SMatt Roper 	 * Obtain fb we'll be using (either new or existing) and take an extra
2964161d0dc1SMatt Roper 	 * reference to it if fb != null.  setplane will take care of dropping
2965161d0dc1SMatt Roper 	 * the reference if the plane update fails.
2966161d0dc1SMatt Roper 	 */
2967161d0dc1SMatt Roper 	if (req->flags & DRM_MODE_CURSOR_BO) {
2968161d0dc1SMatt Roper 		if (req->handle) {
29699a6f5130SChris Wilson 			fb = internal_framebuffer_create(dev, &fbreq, file_priv);
2970161d0dc1SMatt Roper 			if (IS_ERR(fb)) {
2971161d0dc1SMatt Roper 				DRM_DEBUG_KMS("failed to wrap cursor buffer in drm framebuffer\n");
2972161d0dc1SMatt Roper 				return PTR_ERR(fb);
2973161d0dc1SMatt Roper 			}
2974161d0dc1SMatt Roper 		} else {
2975161d0dc1SMatt Roper 			fb = NULL;
2976161d0dc1SMatt Roper 		}
2977161d0dc1SMatt Roper 	} else {
2978161d0dc1SMatt Roper 		fb = crtc->cursor->fb;
2979161d0dc1SMatt Roper 		if (fb)
2980161d0dc1SMatt Roper 			drm_framebuffer_reference(fb);
2981161d0dc1SMatt Roper 	}
2982161d0dc1SMatt Roper 
2983161d0dc1SMatt Roper 	if (req->flags & DRM_MODE_CURSOR_MOVE) {
2984161d0dc1SMatt Roper 		crtc_x = req->x;
2985161d0dc1SMatt Roper 		crtc_y = req->y;
2986161d0dc1SMatt Roper 	} else {
2987161d0dc1SMatt Roper 		crtc_x = crtc->cursor_x;
2988161d0dc1SMatt Roper 		crtc_y = crtc->cursor_y;
2989161d0dc1SMatt Roper 	}
2990161d0dc1SMatt Roper 
2991161d0dc1SMatt Roper 	if (fb) {
2992161d0dc1SMatt Roper 		crtc_w = fb->width;
2993161d0dc1SMatt Roper 		crtc_h = fb->height;
2994161d0dc1SMatt Roper 		src_w = fb->width << 16;
2995161d0dc1SMatt Roper 		src_h = fb->height << 16;
2996161d0dc1SMatt Roper 	}
2997161d0dc1SMatt Roper 
2998161d0dc1SMatt Roper 	/*
2999161d0dc1SMatt Roper 	 * setplane_internal will take care of deref'ing either the old or new
3000161d0dc1SMatt Roper 	 * framebuffer depending on success.
3001161d0dc1SMatt Roper 	 */
3002f2b50c11SDaniel Vetter 	ret = __setplane_internal(crtc->cursor, crtc, fb,
3003161d0dc1SMatt Roper 				crtc_x, crtc_y, crtc_w, crtc_h,
3004161d0dc1SMatt Roper 				0, 0, src_w, src_h);
3005161d0dc1SMatt Roper 
3006161d0dc1SMatt Roper 	/* Update successful; save new cursor position, if necessary */
3007161d0dc1SMatt Roper 	if (ret == 0 && req->flags & DRM_MODE_CURSOR_MOVE) {
3008161d0dc1SMatt Roper 		crtc->cursor_x = req->x;
3009161d0dc1SMatt Roper 		crtc->cursor_y = req->y;
3010161d0dc1SMatt Roper 	}
3011161d0dc1SMatt Roper 
3012161d0dc1SMatt Roper 	return ret;
3013161d0dc1SMatt Roper }
3014161d0dc1SMatt Roper 
30154c813d4dSDave Airlie static int drm_mode_cursor_common(struct drm_device *dev,
30164c813d4dSDave Airlie 				  struct drm_mode_cursor2 *req,
30174c813d4dSDave Airlie 				  struct drm_file *file_priv)
3018f453ba04SDave Airlie {
3019f453ba04SDave Airlie 	struct drm_crtc *crtc;
3020f453ba04SDave Airlie 	int ret = 0;
3021f453ba04SDave Airlie 
3022fb3b06c8SDave Airlie 	if (!drm_core_check_feature(dev, DRIVER_MODESET))
3023fb3b06c8SDave Airlie 		return -EINVAL;
3024fb3b06c8SDave Airlie 
30257c4eaca4SJakob Bornecrantz 	if (!req->flags || (~DRM_MODE_CURSOR_FLAGS & req->flags))
3026f453ba04SDave Airlie 		return -EINVAL;
3027f453ba04SDave Airlie 
3028a2b34e22SRob Clark 	crtc = drm_crtc_find(dev, req->crtc_id);
3029a2b34e22SRob Clark 	if (!crtc) {
303058367ed6SZhao Yakui 		DRM_DEBUG_KMS("Unknown CRTC ID %d\n", req->crtc_id);
3031f27657f2SVille Syrjälä 		return -ENOENT;
3032f453ba04SDave Airlie 	}
3033f453ba04SDave Airlie 
3034161d0dc1SMatt Roper 	/*
3035161d0dc1SMatt Roper 	 * If this crtc has a universal cursor plane, call that plane's update
3036161d0dc1SMatt Roper 	 * handler rather than using legacy cursor handlers.
3037161d0dc1SMatt Roper 	 */
30384d02e2deSDaniel Vetter 	drm_modeset_lock_crtc(crtc, crtc->cursor);
3039f2b50c11SDaniel Vetter 	if (crtc->cursor) {
3040f2b50c11SDaniel Vetter 		ret = drm_mode_cursor_universal(crtc, req, file_priv);
3041f2b50c11SDaniel Vetter 		goto out;
3042f2b50c11SDaniel Vetter 	}
3043f2b50c11SDaniel Vetter 
3044f453ba04SDave Airlie 	if (req->flags & DRM_MODE_CURSOR_BO) {
30454c813d4dSDave Airlie 		if (!crtc->funcs->cursor_set && !crtc->funcs->cursor_set2) {
3046f453ba04SDave Airlie 			ret = -ENXIO;
3047f453ba04SDave Airlie 			goto out;
3048f453ba04SDave Airlie 		}
3049f453ba04SDave Airlie 		/* Turns off the cursor if handle is 0 */
30504c813d4dSDave Airlie 		if (crtc->funcs->cursor_set2)
30514c813d4dSDave Airlie 			ret = crtc->funcs->cursor_set2(crtc, file_priv, req->handle,
30524c813d4dSDave Airlie 						      req->width, req->height, req->hot_x, req->hot_y);
30534c813d4dSDave Airlie 		else
3054f453ba04SDave Airlie 			ret = crtc->funcs->cursor_set(crtc, file_priv, req->handle,
3055f453ba04SDave Airlie 						      req->width, req->height);
3056f453ba04SDave Airlie 	}
3057f453ba04SDave Airlie 
3058f453ba04SDave Airlie 	if (req->flags & DRM_MODE_CURSOR_MOVE) {
3059f453ba04SDave Airlie 		if (crtc->funcs->cursor_move) {
3060f453ba04SDave Airlie 			ret = crtc->funcs->cursor_move(crtc, req->x, req->y);
3061f453ba04SDave Airlie 		} else {
3062f453ba04SDave Airlie 			ret = -EFAULT;
3063f453ba04SDave Airlie 			goto out;
3064f453ba04SDave Airlie 		}
3065f453ba04SDave Airlie 	}
3066f453ba04SDave Airlie out:
3067d059f652SDaniel Vetter 	drm_modeset_unlock_crtc(crtc);
3068dac35663SDaniel Vetter 
3069f453ba04SDave Airlie 	return ret;
30704c813d4dSDave Airlie 
30714c813d4dSDave Airlie }
3072c8e32cc1SDaniel Vetter 
3073c8e32cc1SDaniel Vetter 
3074c8e32cc1SDaniel Vetter /**
3075c8e32cc1SDaniel Vetter  * drm_mode_cursor_ioctl - set CRTC's cursor configuration
3076c8e32cc1SDaniel Vetter  * @dev: drm device for the ioctl
3077c8e32cc1SDaniel Vetter  * @data: data pointer for the ioctl
3078c8e32cc1SDaniel Vetter  * @file_priv: drm file for the ioctl call
3079c8e32cc1SDaniel Vetter  *
3080c8e32cc1SDaniel Vetter  * Set the cursor configuration based on user request.
3081c8e32cc1SDaniel Vetter  *
3082c8e32cc1SDaniel Vetter  * Called by the user via ioctl.
3083c8e32cc1SDaniel Vetter  *
3084c8e32cc1SDaniel Vetter  * Returns:
30851a498633SDaniel Vetter  * Zero on success, negative errno on failure.
3086c8e32cc1SDaniel Vetter  */
30874c813d4dSDave Airlie int drm_mode_cursor_ioctl(struct drm_device *dev,
30884c813d4dSDave Airlie 			  void *data, struct drm_file *file_priv)
30894c813d4dSDave Airlie {
30904c813d4dSDave Airlie 	struct drm_mode_cursor *req = data;
30914c813d4dSDave Airlie 	struct drm_mode_cursor2 new_req;
30924c813d4dSDave Airlie 
30934c813d4dSDave Airlie 	memcpy(&new_req, req, sizeof(struct drm_mode_cursor));
30944c813d4dSDave Airlie 	new_req.hot_x = new_req.hot_y = 0;
30954c813d4dSDave Airlie 
30964c813d4dSDave Airlie 	return drm_mode_cursor_common(dev, &new_req, file_priv);
30974c813d4dSDave Airlie }
30984c813d4dSDave Airlie 
3099c8e32cc1SDaniel Vetter /**
3100c8e32cc1SDaniel Vetter  * drm_mode_cursor2_ioctl - set CRTC's cursor configuration
3101c8e32cc1SDaniel Vetter  * @dev: drm device for the ioctl
3102c8e32cc1SDaniel Vetter  * @data: data pointer for the ioctl
3103c8e32cc1SDaniel Vetter  * @file_priv: drm file for the ioctl call
3104c8e32cc1SDaniel Vetter  *
3105c8e32cc1SDaniel Vetter  * Set the cursor configuration based on user request. This implements the 2nd
3106c8e32cc1SDaniel Vetter  * version of the cursor ioctl, which allows userspace to additionally specify
3107c8e32cc1SDaniel Vetter  * the hotspot of the pointer.
3108c8e32cc1SDaniel Vetter  *
3109c8e32cc1SDaniel Vetter  * Called by the user via ioctl.
3110c8e32cc1SDaniel Vetter  *
3111c8e32cc1SDaniel Vetter  * Returns:
31121a498633SDaniel Vetter  * Zero on success, negative errno on failure.
3113c8e32cc1SDaniel Vetter  */
31144c813d4dSDave Airlie int drm_mode_cursor2_ioctl(struct drm_device *dev,
31154c813d4dSDave Airlie 			   void *data, struct drm_file *file_priv)
31164c813d4dSDave Airlie {
31174c813d4dSDave Airlie 	struct drm_mode_cursor2 *req = data;
31184dfd909fSThierry Reding 
31194c813d4dSDave Airlie 	return drm_mode_cursor_common(dev, req, file_priv);
3120f453ba04SDave Airlie }
3121f453ba04SDave Airlie 
3122c8e32cc1SDaniel Vetter /**
3123c8e32cc1SDaniel Vetter  * drm_mode_legacy_fb_format - compute drm fourcc code from legacy description
3124c8e32cc1SDaniel Vetter  * @bpp: bits per pixels
3125c8e32cc1SDaniel Vetter  * @depth: bit depth per pixel
3126c8e32cc1SDaniel Vetter  *
3127c8e32cc1SDaniel Vetter  * Computes a drm fourcc pixel format code for the given @bpp/@depth values.
3128c8e32cc1SDaniel Vetter  * Useful in fbdev emulation code, since that deals in those values.
3129c8e32cc1SDaniel Vetter  */
3130308e5bcbSJesse Barnes uint32_t drm_mode_legacy_fb_format(uint32_t bpp, uint32_t depth)
3131308e5bcbSJesse Barnes {
3132308e5bcbSJesse Barnes 	uint32_t fmt;
3133308e5bcbSJesse Barnes 
3134308e5bcbSJesse Barnes 	switch (bpp) {
3135308e5bcbSJesse Barnes 	case 8:
3136d84f031bSVille Syrjälä 		fmt = DRM_FORMAT_C8;
3137308e5bcbSJesse Barnes 		break;
3138308e5bcbSJesse Barnes 	case 16:
3139308e5bcbSJesse Barnes 		if (depth == 15)
314004b3924dSVille Syrjälä 			fmt = DRM_FORMAT_XRGB1555;
3141308e5bcbSJesse Barnes 		else
314204b3924dSVille Syrjälä 			fmt = DRM_FORMAT_RGB565;
3143308e5bcbSJesse Barnes 		break;
3144308e5bcbSJesse Barnes 	case 24:
314504b3924dSVille Syrjälä 		fmt = DRM_FORMAT_RGB888;
3146308e5bcbSJesse Barnes 		break;
3147308e5bcbSJesse Barnes 	case 32:
3148308e5bcbSJesse Barnes 		if (depth == 24)
314904b3924dSVille Syrjälä 			fmt = DRM_FORMAT_XRGB8888;
3150308e5bcbSJesse Barnes 		else if (depth == 30)
315104b3924dSVille Syrjälä 			fmt = DRM_FORMAT_XRGB2101010;
3152308e5bcbSJesse Barnes 		else
315304b3924dSVille Syrjälä 			fmt = DRM_FORMAT_ARGB8888;
3154308e5bcbSJesse Barnes 		break;
3155308e5bcbSJesse Barnes 	default:
315604b3924dSVille Syrjälä 		DRM_ERROR("bad bpp, assuming x8r8g8b8 pixel format\n");
315704b3924dSVille Syrjälä 		fmt = DRM_FORMAT_XRGB8888;
3158308e5bcbSJesse Barnes 		break;
3159308e5bcbSJesse Barnes 	}
3160308e5bcbSJesse Barnes 
3161308e5bcbSJesse Barnes 	return fmt;
3162308e5bcbSJesse Barnes }
3163308e5bcbSJesse Barnes EXPORT_SYMBOL(drm_mode_legacy_fb_format);
3164308e5bcbSJesse Barnes 
3165f453ba04SDave Airlie /**
3166f453ba04SDave Airlie  * drm_mode_addfb - add an FB to the graphics configuration
3167065a50edSDaniel Vetter  * @dev: drm device for the ioctl
3168065a50edSDaniel Vetter  * @data: data pointer for the ioctl
3169065a50edSDaniel Vetter  * @file_priv: drm file for the ioctl call
3170f453ba04SDave Airlie  *
3171c8e32cc1SDaniel Vetter  * Add a new FB to the specified CRTC, given a user request. This is the
3172209f5527SChuck Ebbert  * original addfb ioctl which only supported RGB formats.
3173f453ba04SDave Airlie  *
3174f453ba04SDave Airlie  * Called by the user via ioctl.
3175f453ba04SDave Airlie  *
3176c8e32cc1SDaniel Vetter  * Returns:
31771a498633SDaniel Vetter  * Zero on success, negative errno on failure.
3178f453ba04SDave Airlie  */
3179f453ba04SDave Airlie int drm_mode_addfb(struct drm_device *dev,
3180f453ba04SDave Airlie 		   void *data, struct drm_file *file_priv)
3181f453ba04SDave Airlie {
3182308e5bcbSJesse Barnes 	struct drm_mode_fb_cmd *or = data;
3183308e5bcbSJesse Barnes 	struct drm_mode_fb_cmd2 r = {};
3184228f2cb3SChuck Ebbert 	int ret;
3185308e5bcbSJesse Barnes 
3186228f2cb3SChuck Ebbert 	/* convert to new format and call new ioctl */
3187308e5bcbSJesse Barnes 	r.fb_id = or->fb_id;
3188308e5bcbSJesse Barnes 	r.width = or->width;
3189308e5bcbSJesse Barnes 	r.height = or->height;
3190308e5bcbSJesse Barnes 	r.pitches[0] = or->pitch;
3191308e5bcbSJesse Barnes 	r.pixel_format = drm_mode_legacy_fb_format(or->bpp, or->depth);
3192308e5bcbSJesse Barnes 	r.handles[0] = or->handle;
3193308e5bcbSJesse Barnes 
3194228f2cb3SChuck Ebbert 	ret = drm_mode_addfb2(dev, &r, file_priv);
3195228f2cb3SChuck Ebbert 	if (ret)
3196228f2cb3SChuck Ebbert 		return ret;
3197308e5bcbSJesse Barnes 
3198228f2cb3SChuck Ebbert 	or->fb_id = r.fb_id;
31994b096ac1SDaniel Vetter 
3200baf698b0SDaniel Vetter 	return 0;
3201308e5bcbSJesse Barnes }
3202308e5bcbSJesse Barnes 
3203cff91b62SVille Syrjälä static int format_check(const struct drm_mode_fb_cmd2 *r)
3204935b5977SVille Syrjälä {
3205935b5977SVille Syrjälä 	uint32_t format = r->pixel_format & ~DRM_FORMAT_BIG_ENDIAN;
3206935b5977SVille Syrjälä 
3207935b5977SVille Syrjälä 	switch (format) {
3208935b5977SVille Syrjälä 	case DRM_FORMAT_C8:
3209935b5977SVille Syrjälä 	case DRM_FORMAT_RGB332:
3210935b5977SVille Syrjälä 	case DRM_FORMAT_BGR233:
3211935b5977SVille Syrjälä 	case DRM_FORMAT_XRGB4444:
3212935b5977SVille Syrjälä 	case DRM_FORMAT_XBGR4444:
3213935b5977SVille Syrjälä 	case DRM_FORMAT_RGBX4444:
3214935b5977SVille Syrjälä 	case DRM_FORMAT_BGRX4444:
3215935b5977SVille Syrjälä 	case DRM_FORMAT_ARGB4444:
3216935b5977SVille Syrjälä 	case DRM_FORMAT_ABGR4444:
3217935b5977SVille Syrjälä 	case DRM_FORMAT_RGBA4444:
3218935b5977SVille Syrjälä 	case DRM_FORMAT_BGRA4444:
3219935b5977SVille Syrjälä 	case DRM_FORMAT_XRGB1555:
3220935b5977SVille Syrjälä 	case DRM_FORMAT_XBGR1555:
3221935b5977SVille Syrjälä 	case DRM_FORMAT_RGBX5551:
3222935b5977SVille Syrjälä 	case DRM_FORMAT_BGRX5551:
3223935b5977SVille Syrjälä 	case DRM_FORMAT_ARGB1555:
3224935b5977SVille Syrjälä 	case DRM_FORMAT_ABGR1555:
3225935b5977SVille Syrjälä 	case DRM_FORMAT_RGBA5551:
3226935b5977SVille Syrjälä 	case DRM_FORMAT_BGRA5551:
3227935b5977SVille Syrjälä 	case DRM_FORMAT_RGB565:
3228935b5977SVille Syrjälä 	case DRM_FORMAT_BGR565:
3229935b5977SVille Syrjälä 	case DRM_FORMAT_RGB888:
3230935b5977SVille Syrjälä 	case DRM_FORMAT_BGR888:
3231935b5977SVille Syrjälä 	case DRM_FORMAT_XRGB8888:
3232935b5977SVille Syrjälä 	case DRM_FORMAT_XBGR8888:
3233935b5977SVille Syrjälä 	case DRM_FORMAT_RGBX8888:
3234935b5977SVille Syrjälä 	case DRM_FORMAT_BGRX8888:
3235935b5977SVille Syrjälä 	case DRM_FORMAT_ARGB8888:
3236935b5977SVille Syrjälä 	case DRM_FORMAT_ABGR8888:
3237935b5977SVille Syrjälä 	case DRM_FORMAT_RGBA8888:
3238935b5977SVille Syrjälä 	case DRM_FORMAT_BGRA8888:
3239935b5977SVille Syrjälä 	case DRM_FORMAT_XRGB2101010:
3240935b5977SVille Syrjälä 	case DRM_FORMAT_XBGR2101010:
3241935b5977SVille Syrjälä 	case DRM_FORMAT_RGBX1010102:
3242935b5977SVille Syrjälä 	case DRM_FORMAT_BGRX1010102:
3243935b5977SVille Syrjälä 	case DRM_FORMAT_ARGB2101010:
3244935b5977SVille Syrjälä 	case DRM_FORMAT_ABGR2101010:
3245935b5977SVille Syrjälä 	case DRM_FORMAT_RGBA1010102:
3246935b5977SVille Syrjälä 	case DRM_FORMAT_BGRA1010102:
3247935b5977SVille Syrjälä 	case DRM_FORMAT_YUYV:
3248935b5977SVille Syrjälä 	case DRM_FORMAT_YVYU:
3249935b5977SVille Syrjälä 	case DRM_FORMAT_UYVY:
3250935b5977SVille Syrjälä 	case DRM_FORMAT_VYUY:
3251935b5977SVille Syrjälä 	case DRM_FORMAT_AYUV:
3252935b5977SVille Syrjälä 	case DRM_FORMAT_NV12:
3253935b5977SVille Syrjälä 	case DRM_FORMAT_NV21:
3254935b5977SVille Syrjälä 	case DRM_FORMAT_NV16:
3255935b5977SVille Syrjälä 	case DRM_FORMAT_NV61:
3256ba623f6aSLaurent Pinchart 	case DRM_FORMAT_NV24:
3257ba623f6aSLaurent Pinchart 	case DRM_FORMAT_NV42:
3258935b5977SVille Syrjälä 	case DRM_FORMAT_YUV410:
3259935b5977SVille Syrjälä 	case DRM_FORMAT_YVU410:
3260935b5977SVille Syrjälä 	case DRM_FORMAT_YUV411:
3261935b5977SVille Syrjälä 	case DRM_FORMAT_YVU411:
3262935b5977SVille Syrjälä 	case DRM_FORMAT_YUV420:
3263935b5977SVille Syrjälä 	case DRM_FORMAT_YVU420:
3264935b5977SVille Syrjälä 	case DRM_FORMAT_YUV422:
3265935b5977SVille Syrjälä 	case DRM_FORMAT_YVU422:
3266935b5977SVille Syrjälä 	case DRM_FORMAT_YUV444:
3267935b5977SVille Syrjälä 	case DRM_FORMAT_YVU444:
3268935b5977SVille Syrjälä 		return 0;
3269935b5977SVille Syrjälä 	default:
327023c453a4SVille Syrjälä 		DRM_DEBUG_KMS("invalid pixel format %s\n",
327123c453a4SVille Syrjälä 			      drm_get_format_name(r->pixel_format));
3272935b5977SVille Syrjälä 		return -EINVAL;
3273935b5977SVille Syrjälä 	}
3274935b5977SVille Syrjälä }
3275935b5977SVille Syrjälä 
3276cff91b62SVille Syrjälä static int framebuffer_check(const struct drm_mode_fb_cmd2 *r)
3277d1b45d5fSVille Syrjälä {
3278d1b45d5fSVille Syrjälä 	int ret, hsub, vsub, num_planes, i;
3279d1b45d5fSVille Syrjälä 
3280d1b45d5fSVille Syrjälä 	ret = format_check(r);
3281d1b45d5fSVille Syrjälä 	if (ret) {
32826ba6d03eSVille Syrjälä 		DRM_DEBUG_KMS("bad framebuffer format %s\n",
32836ba6d03eSVille Syrjälä 			      drm_get_format_name(r->pixel_format));
3284d1b45d5fSVille Syrjälä 		return ret;
3285d1b45d5fSVille Syrjälä 	}
3286d1b45d5fSVille Syrjälä 
3287d1b45d5fSVille Syrjälä 	hsub = drm_format_horz_chroma_subsampling(r->pixel_format);
3288d1b45d5fSVille Syrjälä 	vsub = drm_format_vert_chroma_subsampling(r->pixel_format);
3289d1b45d5fSVille Syrjälä 	num_planes = drm_format_num_planes(r->pixel_format);
3290d1b45d5fSVille Syrjälä 
3291d1b45d5fSVille Syrjälä 	if (r->width == 0 || r->width % hsub) {
3292209f5527SChuck Ebbert 		DRM_DEBUG_KMS("bad framebuffer width %u\n", r->width);
3293d1b45d5fSVille Syrjälä 		return -EINVAL;
3294d1b45d5fSVille Syrjälä 	}
3295d1b45d5fSVille Syrjälä 
3296d1b45d5fSVille Syrjälä 	if (r->height == 0 || r->height % vsub) {
32971aa1b11cSDave Airlie 		DRM_DEBUG_KMS("bad framebuffer height %u\n", r->height);
3298d1b45d5fSVille Syrjälä 		return -EINVAL;
3299d1b45d5fSVille Syrjälä 	}
3300d1b45d5fSVille Syrjälä 
3301d1b45d5fSVille Syrjälä 	for (i = 0; i < num_planes; i++) {
3302d1b45d5fSVille Syrjälä 		unsigned int width = r->width / (i != 0 ? hsub : 1);
3303b180b5d1SVille Syrjälä 		unsigned int height = r->height / (i != 0 ? vsub : 1);
3304b180b5d1SVille Syrjälä 		unsigned int cpp = drm_format_plane_cpp(r->pixel_format, i);
3305d1b45d5fSVille Syrjälä 
3306d1b45d5fSVille Syrjälä 		if (!r->handles[i]) {
33071aa1b11cSDave Airlie 			DRM_DEBUG_KMS("no buffer object handle for plane %d\n", i);
3308d1b45d5fSVille Syrjälä 			return -EINVAL;
3309d1b45d5fSVille Syrjälä 		}
3310d1b45d5fSVille Syrjälä 
3311b180b5d1SVille Syrjälä 		if ((uint64_t) width * cpp > UINT_MAX)
3312b180b5d1SVille Syrjälä 			return -ERANGE;
3313b180b5d1SVille Syrjälä 
3314b180b5d1SVille Syrjälä 		if ((uint64_t) height * r->pitches[i] + r->offsets[i] > UINT_MAX)
3315b180b5d1SVille Syrjälä 			return -ERANGE;
3316b180b5d1SVille Syrjälä 
3317b180b5d1SVille Syrjälä 		if (r->pitches[i] < width * cpp) {
33181aa1b11cSDave Airlie 			DRM_DEBUG_KMS("bad pitch %u for plane %d\n", r->pitches[i], i);
3319d1b45d5fSVille Syrjälä 			return -EINVAL;
3320d1b45d5fSVille Syrjälä 		}
3321e3eb3250SRob Clark 
3322e3eb3250SRob Clark 		if (r->modifier[i] && !(r->flags & DRM_MODE_FB_MODIFIERS)) {
3323e3eb3250SRob Clark 			DRM_DEBUG_KMS("bad fb modifier %llu for plane %d\n",
3324e3eb3250SRob Clark 				      r->modifier[i], i);
3325e3eb3250SRob Clark 			return -EINVAL;
3326e3eb3250SRob Clark 		}
3327570655b0SRob Clark 
3328570655b0SRob Clark 		/* modifier specific checks: */
3329570655b0SRob Clark 		switch (r->modifier[i]) {
3330570655b0SRob Clark 		case DRM_FORMAT_MOD_SAMSUNG_64_32_TILE:
3331570655b0SRob Clark 			/* NOTE: the pitch restriction may be lifted later if it turns
3332570655b0SRob Clark 			 * out that no hw has this restriction:
3333570655b0SRob Clark 			 */
3334570655b0SRob Clark 			if (r->pixel_format != DRM_FORMAT_NV12 ||
3335570655b0SRob Clark 					width % 128 || height % 32 ||
3336570655b0SRob Clark 					r->pitches[i] % 128) {
3337570655b0SRob Clark 				DRM_DEBUG_KMS("bad modifier data for plane %d\n", i);
3338570655b0SRob Clark 				return -EINVAL;
3339570655b0SRob Clark 			}
3340570655b0SRob Clark 			break;
3341570655b0SRob Clark 
3342570655b0SRob Clark 		default:
3343570655b0SRob Clark 			break;
3344570655b0SRob Clark 		}
3345d1b45d5fSVille Syrjälä 	}
3346d1b45d5fSVille Syrjälä 
3347bbe16a40SDaniel Vetter 	for (i = num_planes; i < 4; i++) {
3348bbe16a40SDaniel Vetter 		if (r->modifier[i]) {
3349bbe16a40SDaniel Vetter 			DRM_DEBUG_KMS("non-zero modifier for unused plane %d\n", i);
3350bbe16a40SDaniel Vetter 			return -EINVAL;
3351bbe16a40SDaniel Vetter 		}
3352bbe16a40SDaniel Vetter 
3353bbe16a40SDaniel Vetter 		/* Pre-FB_MODIFIERS userspace didn't clear the structs properly. */
3354bbe16a40SDaniel Vetter 		if (!(r->flags & DRM_MODE_FB_MODIFIERS))
3355bbe16a40SDaniel Vetter 			continue;
3356bbe16a40SDaniel Vetter 
3357bbe16a40SDaniel Vetter 		if (r->handles[i]) {
3358bbe16a40SDaniel Vetter 			DRM_DEBUG_KMS("buffer object handle for unused plane %d\n", i);
3359bbe16a40SDaniel Vetter 			return -EINVAL;
3360bbe16a40SDaniel Vetter 		}
3361bbe16a40SDaniel Vetter 
3362bbe16a40SDaniel Vetter 		if (r->pitches[i]) {
3363bbe16a40SDaniel Vetter 			DRM_DEBUG_KMS("non-zero pitch for unused plane %d\n", i);
3364bbe16a40SDaniel Vetter 			return -EINVAL;
3365bbe16a40SDaniel Vetter 		}
3366bbe16a40SDaniel Vetter 
3367bbe16a40SDaniel Vetter 		if (r->offsets[i]) {
3368bbe16a40SDaniel Vetter 			DRM_DEBUG_KMS("non-zero offset for unused plane %d\n", i);
3369bbe16a40SDaniel Vetter 			return -EINVAL;
3370bbe16a40SDaniel Vetter 		}
3371bbe16a40SDaniel Vetter 	}
3372bbe16a40SDaniel Vetter 
3373d1b45d5fSVille Syrjälä 	return 0;
3374d1b45d5fSVille Syrjälä }
3375d1b45d5fSVille Syrjälä 
33769a6f5130SChris Wilson static struct drm_framebuffer *
33779a6f5130SChris Wilson internal_framebuffer_create(struct drm_device *dev,
33781eb83451SVille Syrjälä 			    const struct drm_mode_fb_cmd2 *r,
3379c394c2b0SMatt Roper 			    struct drm_file *file_priv)
3380c394c2b0SMatt Roper {
3381c394c2b0SMatt Roper 	struct drm_mode_config *config = &dev->mode_config;
3382c394c2b0SMatt Roper 	struct drm_framebuffer *fb;
3383c394c2b0SMatt Roper 	int ret;
3384c394c2b0SMatt Roper 
3385e3eb3250SRob Clark 	if (r->flags & ~(DRM_MODE_FB_INTERLACED | DRM_MODE_FB_MODIFIERS)) {
3386c394c2b0SMatt Roper 		DRM_DEBUG_KMS("bad framebuffer flags 0x%08x\n", r->flags);
3387c394c2b0SMatt Roper 		return ERR_PTR(-EINVAL);
3388c394c2b0SMatt Roper 	}
3389c394c2b0SMatt Roper 
3390c394c2b0SMatt Roper 	if ((config->min_width > r->width) || (r->width > config->max_width)) {
3391c394c2b0SMatt Roper 		DRM_DEBUG_KMS("bad framebuffer width %d, should be >= %d && <= %d\n",
3392c394c2b0SMatt Roper 			  r->width, config->min_width, config->max_width);
3393c394c2b0SMatt Roper 		return ERR_PTR(-EINVAL);
3394c394c2b0SMatt Roper 	}
3395c394c2b0SMatt Roper 	if ((config->min_height > r->height) || (r->height > config->max_height)) {
3396c394c2b0SMatt Roper 		DRM_DEBUG_KMS("bad framebuffer height %d, should be >= %d && <= %d\n",
3397c394c2b0SMatt Roper 			  r->height, config->min_height, config->max_height);
3398c394c2b0SMatt Roper 		return ERR_PTR(-EINVAL);
3399c394c2b0SMatt Roper 	}
3400c394c2b0SMatt Roper 
3401e3eb3250SRob Clark 	if (r->flags & DRM_MODE_FB_MODIFIERS &&
3402e3eb3250SRob Clark 	    !dev->mode_config.allow_fb_modifiers) {
3403e3eb3250SRob Clark 		DRM_DEBUG_KMS("driver does not support fb modifiers\n");
3404e3eb3250SRob Clark 		return ERR_PTR(-EINVAL);
3405e3eb3250SRob Clark 	}
3406e3eb3250SRob Clark 
3407c394c2b0SMatt Roper 	ret = framebuffer_check(r);
3408c394c2b0SMatt Roper 	if (ret)
3409c394c2b0SMatt Roper 		return ERR_PTR(ret);
3410c394c2b0SMatt Roper 
3411c394c2b0SMatt Roper 	fb = dev->mode_config.funcs->fb_create(dev, file_priv, r);
3412c394c2b0SMatt Roper 	if (IS_ERR(fb)) {
3413c394c2b0SMatt Roper 		DRM_DEBUG_KMS("could not create framebuffer\n");
3414c394c2b0SMatt Roper 		return fb;
3415c394c2b0SMatt Roper 	}
3416c394c2b0SMatt Roper 
3417c394c2b0SMatt Roper 	return fb;
3418c394c2b0SMatt Roper }
3419c394c2b0SMatt Roper 
3420308e5bcbSJesse Barnes /**
3421308e5bcbSJesse Barnes  * drm_mode_addfb2 - add an FB to the graphics configuration
3422065a50edSDaniel Vetter  * @dev: drm device for the ioctl
3423065a50edSDaniel Vetter  * @data: data pointer for the ioctl
3424065a50edSDaniel Vetter  * @file_priv: drm file for the ioctl call
3425308e5bcbSJesse Barnes  *
3426c8e32cc1SDaniel Vetter  * Add a new FB to the specified CRTC, given a user request with format. This is
3427c8e32cc1SDaniel Vetter  * the 2nd version of the addfb ioctl, which supports multi-planar framebuffers
3428c8e32cc1SDaniel Vetter  * and uses fourcc codes as pixel format specifiers.
3429308e5bcbSJesse Barnes  *
3430308e5bcbSJesse Barnes  * Called by the user via ioctl.
3431308e5bcbSJesse Barnes  *
3432c8e32cc1SDaniel Vetter  * Returns:
34331a498633SDaniel Vetter  * Zero on success, negative errno on failure.
3434308e5bcbSJesse Barnes  */
3435308e5bcbSJesse Barnes int drm_mode_addfb2(struct drm_device *dev,
3436308e5bcbSJesse Barnes 		    void *data, struct drm_file *file_priv)
3437308e5bcbSJesse Barnes {
34389a6f5130SChris Wilson 	struct drm_mode_fb_cmd2 *r = data;
3439f453ba04SDave Airlie 	struct drm_framebuffer *fb;
3440f453ba04SDave Airlie 
3441fb3b06c8SDave Airlie 	if (!drm_core_check_feature(dev, DRIVER_MODESET))
3442fb3b06c8SDave Airlie 		return -EINVAL;
3443fb3b06c8SDave Airlie 
34449a6f5130SChris Wilson 	fb = internal_framebuffer_create(dev, r, file_priv);
3445c394c2b0SMatt Roper 	if (IS_ERR(fb))
34464b096ac1SDaniel Vetter 		return PTR_ERR(fb);
3447f453ba04SDave Airlie 
34489a6f5130SChris Wilson 	DRM_DEBUG_KMS("[FB:%d]\n", fb->base.id);
34499a6f5130SChris Wilson 	r->fb_id = fb->base.id;
3450c7e1c59aSDave Airlie 
3451c7e1c59aSDave Airlie 	/* Transfer ownership to the filp for reaping on close */
3452c7e1c59aSDave Airlie 	mutex_lock(&file_priv->fbs_lock);
34539a6f5130SChris Wilson 	list_add(&fb->filp_head, &file_priv->fbs);
34549a6f5130SChris Wilson 	mutex_unlock(&file_priv->fbs_lock);
34559a6f5130SChris Wilson 
3456c394c2b0SMatt Roper 	return 0;
3457f453ba04SDave Airlie }
3458f453ba04SDave Airlie 
3459f453ba04SDave Airlie /**
3460f453ba04SDave Airlie  * drm_mode_rmfb - remove an FB from the configuration
3461065a50edSDaniel Vetter  * @dev: drm device for the ioctl
3462065a50edSDaniel Vetter  * @data: data pointer for the ioctl
3463065a50edSDaniel Vetter  * @file_priv: drm file for the ioctl call
3464f453ba04SDave Airlie  *
3465f453ba04SDave Airlie  * Remove the FB specified by the user.
3466f453ba04SDave Airlie  *
3467f453ba04SDave Airlie  * Called by the user via ioctl.
3468f453ba04SDave Airlie  *
3469c8e32cc1SDaniel Vetter  * Returns:
34701a498633SDaniel Vetter  * Zero on success, negative errno on failure.
3471f453ba04SDave Airlie  */
3472f453ba04SDave Airlie int drm_mode_rmfb(struct drm_device *dev,
3473f453ba04SDave Airlie 		   void *data, struct drm_file *file_priv)
3474f453ba04SDave Airlie {
3475f453ba04SDave Airlie 	struct drm_framebuffer *fb = NULL;
3476f453ba04SDave Airlie 	struct drm_framebuffer *fbl = NULL;
3477cee26ac4SDave Airlie 	struct drm_mode_object *obj;
3478f453ba04SDave Airlie 	uint32_t *id = data;
3479f453ba04SDave Airlie 	int found = 0;
3480f453ba04SDave Airlie 
3481fb3b06c8SDave Airlie 	if (!drm_core_check_feature(dev, DRIVER_MODESET))
3482fb3b06c8SDave Airlie 		return -EINVAL;
3483fb3b06c8SDave Airlie 
34844b096ac1SDaniel Vetter 	mutex_lock(&file_priv->fbs_lock);
34852b677e8cSDaniel Vetter 	mutex_lock(&dev->mode_config.fb_lock);
3486cee26ac4SDave Airlie 	obj = _object_find(dev, *id, DRM_MODE_OBJECT_FB);
3487cee26ac4SDave Airlie 	if (!obj)
34882b677e8cSDaniel Vetter 		goto fail_lookup;
3489cee26ac4SDave Airlie 	fb = obj_to_fb(obj);
3490f453ba04SDave Airlie 	list_for_each_entry(fbl, &file_priv->fbs, filp_head)
3491f453ba04SDave Airlie 		if (fb == fbl)
3492f453ba04SDave Airlie 			found = 1;
34932b677e8cSDaniel Vetter 	if (!found)
34942b677e8cSDaniel Vetter 		goto fail_lookup;
34952b677e8cSDaniel Vetter 
34964b096ac1SDaniel Vetter 	list_del_init(&fb->filp_head);
34972b677e8cSDaniel Vetter 	mutex_unlock(&dev->mode_config.fb_lock);
34984b096ac1SDaniel Vetter 	mutex_unlock(&file_priv->fbs_lock);
3499f453ba04SDave Airlie 
350013803132SMaarten Lankhorst 	drm_framebuffer_unreference(fb);
35014b096ac1SDaniel Vetter 
35022b677e8cSDaniel Vetter 	return 0;
35032b677e8cSDaniel Vetter 
35042b677e8cSDaniel Vetter fail_lookup:
35052b677e8cSDaniel Vetter 	mutex_unlock(&dev->mode_config.fb_lock);
35062b677e8cSDaniel Vetter 	mutex_unlock(&file_priv->fbs_lock);
35072b677e8cSDaniel Vetter 
350837c4e705SVille Syrjälä 	return -ENOENT;
3509f453ba04SDave Airlie }
3510f453ba04SDave Airlie 
3511f453ba04SDave Airlie /**
3512f453ba04SDave Airlie  * drm_mode_getfb - get FB info
3513065a50edSDaniel Vetter  * @dev: drm device for the ioctl
3514065a50edSDaniel Vetter  * @data: data pointer for the ioctl
3515065a50edSDaniel Vetter  * @file_priv: drm file for the ioctl call
3516f453ba04SDave Airlie  *
3517f453ba04SDave Airlie  * Lookup the FB given its ID and return info about it.
3518f453ba04SDave Airlie  *
3519f453ba04SDave Airlie  * Called by the user via ioctl.
3520f453ba04SDave Airlie  *
3521c8e32cc1SDaniel Vetter  * Returns:
35221a498633SDaniel Vetter  * Zero on success, negative errno on failure.
3523f453ba04SDave Airlie  */
3524f453ba04SDave Airlie int drm_mode_getfb(struct drm_device *dev,
3525f453ba04SDave Airlie 		   void *data, struct drm_file *file_priv)
3526f453ba04SDave Airlie {
3527f453ba04SDave Airlie 	struct drm_mode_fb_cmd *r = data;
3528f453ba04SDave Airlie 	struct drm_framebuffer *fb;
352958c0dca1SDaniel Vetter 	int ret;
3530f453ba04SDave Airlie 
3531fb3b06c8SDave Airlie 	if (!drm_core_check_feature(dev, DRIVER_MODESET))
3532fb3b06c8SDave Airlie 		return -EINVAL;
3533fb3b06c8SDave Airlie 
3534786b99edSDaniel Vetter 	fb = drm_framebuffer_lookup(dev, r->fb_id);
353558c0dca1SDaniel Vetter 	if (!fb)
353637c4e705SVille Syrjälä 		return -ENOENT;
3537f453ba04SDave Airlie 
3538f453ba04SDave Airlie 	r->height = fb->height;
3539f453ba04SDave Airlie 	r->width = fb->width;
3540f453ba04SDave Airlie 	r->depth = fb->depth;
3541f453ba04SDave Airlie 	r->bpp = fb->bits_per_pixel;
354201f2c773SVille Syrjälä 	r->pitch = fb->pitches[0];
3543101b96f3SDavid Herrmann 	if (fb->funcs->create_handle) {
354409f308f7SThomas Hellstrom 		if (file_priv->is_master || capable(CAP_SYS_ADMIN) ||
354543683057SThomas Hellstrom 		    drm_is_control_client(file_priv)) {
3546101b96f3SDavid Herrmann 			ret = fb->funcs->create_handle(fb, file_priv,
3547101b96f3SDavid Herrmann 						       &r->handle);
3548101b96f3SDavid Herrmann 		} else {
3549101b96f3SDavid Herrmann 			/* GET_FB() is an unprivileged ioctl so we must not
3550101b96f3SDavid Herrmann 			 * return a buffer-handle to non-master processes! For
3551101b96f3SDavid Herrmann 			 * backwards-compatibility reasons, we cannot make
3552101b96f3SDavid Herrmann 			 * GET_FB() privileged, so just return an invalid handle
3553101b96f3SDavid Herrmann 			 * for non-masters. */
3554101b96f3SDavid Herrmann 			r->handle = 0;
3555101b96f3SDavid Herrmann 			ret = 0;
3556101b96f3SDavid Herrmann 		}
3557101b96f3SDavid Herrmann 	} else {
3558af26ef3bSDaniel Vetter 		ret = -ENODEV;
3559101b96f3SDavid Herrmann 	}
3560f453ba04SDave Airlie 
356158c0dca1SDaniel Vetter 	drm_framebuffer_unreference(fb);
356258c0dca1SDaniel Vetter 
3563f453ba04SDave Airlie 	return ret;
3564f453ba04SDave Airlie }
3565f453ba04SDave Airlie 
3566c8e32cc1SDaniel Vetter /**
3567c8e32cc1SDaniel Vetter  * drm_mode_dirtyfb_ioctl - flush frontbuffer rendering on an FB
3568c8e32cc1SDaniel Vetter  * @dev: drm device for the ioctl
3569c8e32cc1SDaniel Vetter  * @data: data pointer for the ioctl
3570c8e32cc1SDaniel Vetter  * @file_priv: drm file for the ioctl call
3571c8e32cc1SDaniel Vetter  *
3572c8e32cc1SDaniel Vetter  * Lookup the FB and flush out the damaged area supplied by userspace as a clip
3573c8e32cc1SDaniel Vetter  * rectangle list. Generic userspace which does frontbuffer rendering must call
3574c8e32cc1SDaniel Vetter  * this ioctl to flush out the changes on manual-update display outputs, e.g.
3575c8e32cc1SDaniel Vetter  * usb display-link, mipi manual update panels or edp panel self refresh modes.
3576c8e32cc1SDaniel Vetter  *
3577c8e32cc1SDaniel Vetter  * Modesetting drivers which always update the frontbuffer do not need to
3578c8e32cc1SDaniel Vetter  * implement the corresponding ->dirty framebuffer callback.
3579c8e32cc1SDaniel Vetter  *
3580c8e32cc1SDaniel Vetter  * Called by the user via ioctl.
3581c8e32cc1SDaniel Vetter  *
3582c8e32cc1SDaniel Vetter  * Returns:
35831a498633SDaniel Vetter  * Zero on success, negative errno on failure.
3584c8e32cc1SDaniel Vetter  */
3585884840aaSJakob Bornecrantz int drm_mode_dirtyfb_ioctl(struct drm_device *dev,
3586884840aaSJakob Bornecrantz 			   void *data, struct drm_file *file_priv)
3587884840aaSJakob Bornecrantz {
3588884840aaSJakob Bornecrantz 	struct drm_clip_rect __user *clips_ptr;
3589884840aaSJakob Bornecrantz 	struct drm_clip_rect *clips = NULL;
3590884840aaSJakob Bornecrantz 	struct drm_mode_fb_dirty_cmd *r = data;
3591884840aaSJakob Bornecrantz 	struct drm_framebuffer *fb;
3592884840aaSJakob Bornecrantz 	unsigned flags;
3593884840aaSJakob Bornecrantz 	int num_clips;
35944a1b0714SLaurent Pinchart 	int ret;
3595884840aaSJakob Bornecrantz 
3596fb3b06c8SDave Airlie 	if (!drm_core_check_feature(dev, DRIVER_MODESET))
3597fb3b06c8SDave Airlie 		return -EINVAL;
3598fb3b06c8SDave Airlie 
3599786b99edSDaniel Vetter 	fb = drm_framebuffer_lookup(dev, r->fb_id);
36004ccf097fSDaniel Vetter 	if (!fb)
360137c4e705SVille Syrjälä 		return -ENOENT;
3602884840aaSJakob Bornecrantz 
3603884840aaSJakob Bornecrantz 	num_clips = r->num_clips;
360481f6c7f8SVille Syrjälä 	clips_ptr = (struct drm_clip_rect __user *)(unsigned long)r->clips_ptr;
3605884840aaSJakob Bornecrantz 
3606884840aaSJakob Bornecrantz 	if (!num_clips != !clips_ptr) {
3607884840aaSJakob Bornecrantz 		ret = -EINVAL;
3608884840aaSJakob Bornecrantz 		goto out_err1;
3609884840aaSJakob Bornecrantz 	}
3610884840aaSJakob Bornecrantz 
3611884840aaSJakob Bornecrantz 	flags = DRM_MODE_FB_DIRTY_FLAGS & r->flags;
3612884840aaSJakob Bornecrantz 
3613884840aaSJakob Bornecrantz 	/* If userspace annotates copy, clips must come in pairs */
3614884840aaSJakob Bornecrantz 	if (flags & DRM_MODE_FB_DIRTY_ANNOTATE_COPY && (num_clips % 2)) {
3615884840aaSJakob Bornecrantz 		ret = -EINVAL;
3616884840aaSJakob Bornecrantz 		goto out_err1;
3617884840aaSJakob Bornecrantz 	}
3618884840aaSJakob Bornecrantz 
3619884840aaSJakob Bornecrantz 	if (num_clips && clips_ptr) {
3620a5cd3351SXi Wang 		if (num_clips < 0 || num_clips > DRM_MODE_FB_DIRTY_MAX_CLIPS) {
3621a5cd3351SXi Wang 			ret = -EINVAL;
3622a5cd3351SXi Wang 			goto out_err1;
3623a5cd3351SXi Wang 		}
3624bd3f0ff9SThierry Reding 		clips = kcalloc(num_clips, sizeof(*clips), GFP_KERNEL);
3625884840aaSJakob Bornecrantz 		if (!clips) {
3626884840aaSJakob Bornecrantz 			ret = -ENOMEM;
3627884840aaSJakob Bornecrantz 			goto out_err1;
3628884840aaSJakob Bornecrantz 		}
3629884840aaSJakob Bornecrantz 
3630884840aaSJakob Bornecrantz 		ret = copy_from_user(clips, clips_ptr,
3631884840aaSJakob Bornecrantz 				     num_clips * sizeof(*clips));
3632e902a358SDan Carpenter 		if (ret) {
3633e902a358SDan Carpenter 			ret = -EFAULT;
3634884840aaSJakob Bornecrantz 			goto out_err2;
3635884840aaSJakob Bornecrantz 		}
3636e902a358SDan Carpenter 	}
3637884840aaSJakob Bornecrantz 
3638884840aaSJakob Bornecrantz 	if (fb->funcs->dirty) {
363902b00162SThomas Hellstrom 		ret = fb->funcs->dirty(fb, file_priv, flags, r->color,
364002b00162SThomas Hellstrom 				       clips, num_clips);
3641884840aaSJakob Bornecrantz 	} else {
3642884840aaSJakob Bornecrantz 		ret = -ENOSYS;
3643884840aaSJakob Bornecrantz 	}
3644884840aaSJakob Bornecrantz 
3645884840aaSJakob Bornecrantz out_err2:
3646884840aaSJakob Bornecrantz 	kfree(clips);
3647884840aaSJakob Bornecrantz out_err1:
36484ccf097fSDaniel Vetter 	drm_framebuffer_unreference(fb);
36494ccf097fSDaniel Vetter 
3650884840aaSJakob Bornecrantz 	return ret;
3651884840aaSJakob Bornecrantz }
3652884840aaSJakob Bornecrantz 
3653884840aaSJakob Bornecrantz 
3654f453ba04SDave Airlie /**
3655f453ba04SDave Airlie  * drm_fb_release - remove and free the FBs on this file
3656065a50edSDaniel Vetter  * @priv: drm file for the ioctl
3657f453ba04SDave Airlie  *
3658f453ba04SDave Airlie  * Destroy all the FBs associated with @filp.
3659f453ba04SDave Airlie  *
3660f453ba04SDave Airlie  * Called by the user via ioctl.
3661f453ba04SDave Airlie  *
3662c8e32cc1SDaniel Vetter  * Returns:
36631a498633SDaniel Vetter  * Zero on success, negative errno on failure.
3664f453ba04SDave Airlie  */
3665ea39f835SKristian Høgsberg void drm_fb_release(struct drm_file *priv)
3666f453ba04SDave Airlie {
3667f453ba04SDave Airlie 	struct drm_framebuffer *fb, *tfb;
3668f453ba04SDave Airlie 
36691b116297SDaniel Vetter 	/*
36701b116297SDaniel Vetter 	 * When the file gets released that means no one else can access the fb
3671e2db726bSMartin Peres 	 * list any more, so no need to grab fpriv->fbs_lock. And we need to
36721b116297SDaniel Vetter 	 * avoid upsetting lockdep since the universal cursor code adds a
36731b116297SDaniel Vetter 	 * framebuffer while holding mutex locks.
36741b116297SDaniel Vetter 	 *
36751b116297SDaniel Vetter 	 * Note that a real deadlock between fpriv->fbs_lock and the modeset
36761b116297SDaniel Vetter 	 * locks is impossible here since no one else but this function can get
36771b116297SDaniel Vetter 	 * at it any more.
36781b116297SDaniel Vetter 	 */
3679f453ba04SDave Airlie 	list_for_each_entry_safe(fb, tfb, &priv->fbs, filp_head) {
36804b096ac1SDaniel Vetter 		list_del_init(&fb->filp_head);
36812b677e8cSDaniel Vetter 
368273f7570bSMaarten Lankhorst 		/* This drops the fpriv->fbs reference. */
368313803132SMaarten Lankhorst 		drm_framebuffer_unreference(fb);
3684f453ba04SDave Airlie 	}
3685f453ba04SDave Airlie }
3686f453ba04SDave Airlie 
3687c8e32cc1SDaniel Vetter /**
3688c8e32cc1SDaniel Vetter  * drm_property_create - create a new property type
3689c8e32cc1SDaniel Vetter  * @dev: drm device
3690c8e32cc1SDaniel Vetter  * @flags: flags specifying the property type
3691c8e32cc1SDaniel Vetter  * @name: name of the property
3692c8e32cc1SDaniel Vetter  * @num_values: number of pre-defined values
3693c8e32cc1SDaniel Vetter  *
3694c8e32cc1SDaniel Vetter  * This creates a new generic drm property which can then be attached to a drm
3695c8e32cc1SDaniel Vetter  * object with drm_object_attach_property. The returned property object must be
3696c8e32cc1SDaniel Vetter  * freed with drm_property_destroy.
3697c8e32cc1SDaniel Vetter  *
36983b5b9932SDamien Lespiau  * Note that the DRM core keeps a per-device list of properties and that, if
36993b5b9932SDamien Lespiau  * drm_mode_config_cleanup() is called, it will destroy all properties created
37003b5b9932SDamien Lespiau  * by the driver.
37013b5b9932SDamien Lespiau  *
3702c8e32cc1SDaniel Vetter  * Returns:
3703c8e32cc1SDaniel Vetter  * A pointer to the newly created property on success, NULL on failure.
3704c8e32cc1SDaniel Vetter  */
3705f453ba04SDave Airlie struct drm_property *drm_property_create(struct drm_device *dev, int flags,
3706f453ba04SDave Airlie 					 const char *name, int num_values)
3707f453ba04SDave Airlie {
3708f453ba04SDave Airlie 	struct drm_property *property = NULL;
37096bfc56aaSVille Syrjälä 	int ret;
3710f453ba04SDave Airlie 
3711f453ba04SDave Airlie 	property = kzalloc(sizeof(struct drm_property), GFP_KERNEL);
3712f453ba04SDave Airlie 	if (!property)
3713f453ba04SDave Airlie 		return NULL;
3714f453ba04SDave Airlie 
371598f75de4SRob Clark 	property->dev = dev;
371698f75de4SRob Clark 
3717f453ba04SDave Airlie 	if (num_values) {
3718bd3f0ff9SThierry Reding 		property->values = kcalloc(num_values, sizeof(uint64_t),
3719bd3f0ff9SThierry Reding 					   GFP_KERNEL);
3720f453ba04SDave Airlie 		if (!property->values)
3721f453ba04SDave Airlie 			goto fail;
3722f453ba04SDave Airlie 	}
3723f453ba04SDave Airlie 
37246bfc56aaSVille Syrjälä 	ret = drm_mode_object_get(dev, &property->base, DRM_MODE_OBJECT_PROPERTY);
37256bfc56aaSVille Syrjälä 	if (ret)
37266bfc56aaSVille Syrjälä 		goto fail;
37276bfc56aaSVille Syrjälä 
3728f453ba04SDave Airlie 	property->flags = flags;
3729f453ba04SDave Airlie 	property->num_values = num_values;
37303758b341SDaniel Vetter 	INIT_LIST_HEAD(&property->enum_list);
3731f453ba04SDave Airlie 
3732471dd2efSVinson Lee 	if (name) {
3733f453ba04SDave Airlie 		strncpy(property->name, name, DRM_PROP_NAME_LEN);
3734471dd2efSVinson Lee 		property->name[DRM_PROP_NAME_LEN-1] = '\0';
3735471dd2efSVinson Lee 	}
3736f453ba04SDave Airlie 
3737f453ba04SDave Airlie 	list_add_tail(&property->head, &dev->mode_config.property_list);
37385ea22f24SRob Clark 
37395ea22f24SRob Clark 	WARN_ON(!drm_property_type_valid(property));
37405ea22f24SRob Clark 
3741f453ba04SDave Airlie 	return property;
3742f453ba04SDave Airlie fail:
37436bfc56aaSVille Syrjälä 	kfree(property->values);
3744f453ba04SDave Airlie 	kfree(property);
3745f453ba04SDave Airlie 	return NULL;
3746f453ba04SDave Airlie }
3747f453ba04SDave Airlie EXPORT_SYMBOL(drm_property_create);
3748f453ba04SDave Airlie 
3749c8e32cc1SDaniel Vetter /**
37502aa9d2bcSThierry Reding  * drm_property_create_enum - create a new enumeration property type
3751c8e32cc1SDaniel Vetter  * @dev: drm device
3752c8e32cc1SDaniel Vetter  * @flags: flags specifying the property type
3753c8e32cc1SDaniel Vetter  * @name: name of the property
3754c8e32cc1SDaniel Vetter  * @props: enumeration lists with property values
3755c8e32cc1SDaniel Vetter  * @num_values: number of pre-defined values
3756c8e32cc1SDaniel Vetter  *
3757c8e32cc1SDaniel Vetter  * This creates a new generic drm property which can then be attached to a drm
3758c8e32cc1SDaniel Vetter  * object with drm_object_attach_property. The returned property object must be
3759c8e32cc1SDaniel Vetter  * freed with drm_property_destroy.
3760c8e32cc1SDaniel Vetter  *
3761c8e32cc1SDaniel Vetter  * Userspace is only allowed to set one of the predefined values for enumeration
3762c8e32cc1SDaniel Vetter  * properties.
3763c8e32cc1SDaniel Vetter  *
3764c8e32cc1SDaniel Vetter  * Returns:
3765c8e32cc1SDaniel Vetter  * A pointer to the newly created property on success, NULL on failure.
3766c8e32cc1SDaniel Vetter  */
37674a67d391SSascha Hauer struct drm_property *drm_property_create_enum(struct drm_device *dev, int flags,
37684a67d391SSascha Hauer 					 const char *name,
37694a67d391SSascha Hauer 					 const struct drm_prop_enum_list *props,
37704a67d391SSascha Hauer 					 int num_values)
37714a67d391SSascha Hauer {
37724a67d391SSascha Hauer 	struct drm_property *property;
37734a67d391SSascha Hauer 	int i, ret;
37744a67d391SSascha Hauer 
37754a67d391SSascha Hauer 	flags |= DRM_MODE_PROP_ENUM;
37764a67d391SSascha Hauer 
37774a67d391SSascha Hauer 	property = drm_property_create(dev, flags, name, num_values);
37784a67d391SSascha Hauer 	if (!property)
37794a67d391SSascha Hauer 		return NULL;
37804a67d391SSascha Hauer 
37814a67d391SSascha Hauer 	for (i = 0; i < num_values; i++) {
37824a67d391SSascha Hauer 		ret = drm_property_add_enum(property, i,
37834a67d391SSascha Hauer 				      props[i].type,
37844a67d391SSascha Hauer 				      props[i].name);
37854a67d391SSascha Hauer 		if (ret) {
37864a67d391SSascha Hauer 			drm_property_destroy(dev, property);
37874a67d391SSascha Hauer 			return NULL;
37884a67d391SSascha Hauer 		}
37894a67d391SSascha Hauer 	}
37904a67d391SSascha Hauer 
37914a67d391SSascha Hauer 	return property;
37924a67d391SSascha Hauer }
37934a67d391SSascha Hauer EXPORT_SYMBOL(drm_property_create_enum);
37944a67d391SSascha Hauer 
3795c8e32cc1SDaniel Vetter /**
37962aa9d2bcSThierry Reding  * drm_property_create_bitmask - create a new bitmask property type
3797c8e32cc1SDaniel Vetter  * @dev: drm device
3798c8e32cc1SDaniel Vetter  * @flags: flags specifying the property type
3799c8e32cc1SDaniel Vetter  * @name: name of the property
3800c8e32cc1SDaniel Vetter  * @props: enumeration lists with property bitflags
3801295ee853SDaniel Vetter  * @num_props: size of the @props array
3802295ee853SDaniel Vetter  * @supported_bits: bitmask of all supported enumeration values
3803c8e32cc1SDaniel Vetter  *
3804295ee853SDaniel Vetter  * This creates a new bitmask drm property which can then be attached to a drm
3805c8e32cc1SDaniel Vetter  * object with drm_object_attach_property. The returned property object must be
3806c8e32cc1SDaniel Vetter  * freed with drm_property_destroy.
3807c8e32cc1SDaniel Vetter  *
3808c8e32cc1SDaniel Vetter  * Compared to plain enumeration properties userspace is allowed to set any
3809c8e32cc1SDaniel Vetter  * or'ed together combination of the predefined property bitflag values
3810c8e32cc1SDaniel Vetter  *
3811c8e32cc1SDaniel Vetter  * Returns:
3812c8e32cc1SDaniel Vetter  * A pointer to the newly created property on success, NULL on failure.
3813c8e32cc1SDaniel Vetter  */
381449e27545SRob Clark struct drm_property *drm_property_create_bitmask(struct drm_device *dev,
381549e27545SRob Clark 					 int flags, const char *name,
381649e27545SRob Clark 					 const struct drm_prop_enum_list *props,
38177689ffb3SVille Syrjälä 					 int num_props,
38187689ffb3SVille Syrjälä 					 uint64_t supported_bits)
381949e27545SRob Clark {
382049e27545SRob Clark 	struct drm_property *property;
38217689ffb3SVille Syrjälä 	int i, ret, index = 0;
38227689ffb3SVille Syrjälä 	int num_values = hweight64(supported_bits);
382349e27545SRob Clark 
382449e27545SRob Clark 	flags |= DRM_MODE_PROP_BITMASK;
382549e27545SRob Clark 
382649e27545SRob Clark 	property = drm_property_create(dev, flags, name, num_values);
382749e27545SRob Clark 	if (!property)
382849e27545SRob Clark 		return NULL;
38297689ffb3SVille Syrjälä 	for (i = 0; i < num_props; i++) {
38307689ffb3SVille Syrjälä 		if (!(supported_bits & (1ULL << props[i].type)))
38317689ffb3SVille Syrjälä 			continue;
383249e27545SRob Clark 
38337689ffb3SVille Syrjälä 		if (WARN_ON(index >= num_values)) {
38347689ffb3SVille Syrjälä 			drm_property_destroy(dev, property);
38357689ffb3SVille Syrjälä 			return NULL;
38367689ffb3SVille Syrjälä 		}
38377689ffb3SVille Syrjälä 
38387689ffb3SVille Syrjälä 		ret = drm_property_add_enum(property, index++,
383949e27545SRob Clark 				      props[i].type,
384049e27545SRob Clark 				      props[i].name);
384149e27545SRob Clark 		if (ret) {
384249e27545SRob Clark 			drm_property_destroy(dev, property);
384349e27545SRob Clark 			return NULL;
384449e27545SRob Clark 		}
384549e27545SRob Clark 	}
384649e27545SRob Clark 
384749e27545SRob Clark 	return property;
384849e27545SRob Clark }
384949e27545SRob Clark EXPORT_SYMBOL(drm_property_create_bitmask);
385049e27545SRob Clark 
3851ebc44cf3SRob Clark static struct drm_property *property_create_range(struct drm_device *dev,
3852ebc44cf3SRob Clark 					 int flags, const char *name,
3853ebc44cf3SRob Clark 					 uint64_t min, uint64_t max)
3854ebc44cf3SRob Clark {
3855ebc44cf3SRob Clark 	struct drm_property *property;
3856ebc44cf3SRob Clark 
3857ebc44cf3SRob Clark 	property = drm_property_create(dev, flags, name, 2);
3858ebc44cf3SRob Clark 	if (!property)
3859ebc44cf3SRob Clark 		return NULL;
3860ebc44cf3SRob Clark 
3861ebc44cf3SRob Clark 	property->values[0] = min;
3862ebc44cf3SRob Clark 	property->values[1] = max;
3863ebc44cf3SRob Clark 
3864ebc44cf3SRob Clark 	return property;
3865ebc44cf3SRob Clark }
3866ebc44cf3SRob Clark 
3867c8e32cc1SDaniel Vetter /**
3868960cd9d4SDaniel Vetter  * drm_property_create_range - create a new unsigned ranged property type
3869c8e32cc1SDaniel Vetter  * @dev: drm device
3870c8e32cc1SDaniel Vetter  * @flags: flags specifying the property type
3871c8e32cc1SDaniel Vetter  * @name: name of the property
3872c8e32cc1SDaniel Vetter  * @min: minimum value of the property
3873c8e32cc1SDaniel Vetter  * @max: maximum value of the property
3874c8e32cc1SDaniel Vetter  *
3875c8e32cc1SDaniel Vetter  * This creates a new generic drm property which can then be attached to a drm
3876c8e32cc1SDaniel Vetter  * object with drm_object_attach_property. The returned property object must be
3877c8e32cc1SDaniel Vetter  * freed with drm_property_destroy.
3878c8e32cc1SDaniel Vetter  *
3879960cd9d4SDaniel Vetter  * Userspace is allowed to set any unsigned integer value in the (min, max)
3880960cd9d4SDaniel Vetter  * range inclusive.
3881c8e32cc1SDaniel Vetter  *
3882c8e32cc1SDaniel Vetter  * Returns:
3883c8e32cc1SDaniel Vetter  * A pointer to the newly created property on success, NULL on failure.
3884c8e32cc1SDaniel Vetter  */
3885d9bc3c02SSascha Hauer struct drm_property *drm_property_create_range(struct drm_device *dev, int flags,
3886d9bc3c02SSascha Hauer 					 const char *name,
3887d9bc3c02SSascha Hauer 					 uint64_t min, uint64_t max)
3888d9bc3c02SSascha Hauer {
3889ebc44cf3SRob Clark 	return property_create_range(dev, DRM_MODE_PROP_RANGE | flags,
3890ebc44cf3SRob Clark 			name, min, max);
3891d9bc3c02SSascha Hauer }
3892d9bc3c02SSascha Hauer EXPORT_SYMBOL(drm_property_create_range);
3893d9bc3c02SSascha Hauer 
3894960cd9d4SDaniel Vetter /**
3895960cd9d4SDaniel Vetter  * drm_property_create_signed_range - create a new signed ranged property type
3896960cd9d4SDaniel Vetter  * @dev: drm device
3897960cd9d4SDaniel Vetter  * @flags: flags specifying the property type
3898960cd9d4SDaniel Vetter  * @name: name of the property
3899960cd9d4SDaniel Vetter  * @min: minimum value of the property
3900960cd9d4SDaniel Vetter  * @max: maximum value of the property
3901960cd9d4SDaniel Vetter  *
3902960cd9d4SDaniel Vetter  * This creates a new generic drm property which can then be attached to a drm
3903960cd9d4SDaniel Vetter  * object with drm_object_attach_property. The returned property object must be
3904960cd9d4SDaniel Vetter  * freed with drm_property_destroy.
3905960cd9d4SDaniel Vetter  *
3906960cd9d4SDaniel Vetter  * Userspace is allowed to set any signed integer value in the (min, max)
3907960cd9d4SDaniel Vetter  * range inclusive.
3908960cd9d4SDaniel Vetter  *
3909960cd9d4SDaniel Vetter  * Returns:
3910960cd9d4SDaniel Vetter  * A pointer to the newly created property on success, NULL on failure.
3911960cd9d4SDaniel Vetter  */
3912ebc44cf3SRob Clark struct drm_property *drm_property_create_signed_range(struct drm_device *dev,
3913ebc44cf3SRob Clark 					 int flags, const char *name,
3914ebc44cf3SRob Clark 					 int64_t min, int64_t max)
3915ebc44cf3SRob Clark {
3916ebc44cf3SRob Clark 	return property_create_range(dev, DRM_MODE_PROP_SIGNED_RANGE | flags,
3917ebc44cf3SRob Clark 			name, I642U64(min), I642U64(max));
3918ebc44cf3SRob Clark }
3919ebc44cf3SRob Clark EXPORT_SYMBOL(drm_property_create_signed_range);
3920ebc44cf3SRob Clark 
3921960cd9d4SDaniel Vetter /**
3922960cd9d4SDaniel Vetter  * drm_property_create_object - create a new object property type
3923960cd9d4SDaniel Vetter  * @dev: drm device
3924960cd9d4SDaniel Vetter  * @flags: flags specifying the property type
3925960cd9d4SDaniel Vetter  * @name: name of the property
3926960cd9d4SDaniel Vetter  * @type: object type from DRM_MODE_OBJECT_* defines
3927960cd9d4SDaniel Vetter  *
3928960cd9d4SDaniel Vetter  * This creates a new generic drm property which can then be attached to a drm
3929960cd9d4SDaniel Vetter  * object with drm_object_attach_property. The returned property object must be
3930960cd9d4SDaniel Vetter  * freed with drm_property_destroy.
3931960cd9d4SDaniel Vetter  *
3932960cd9d4SDaniel Vetter  * Userspace is only allowed to set this to any property value of the given
3933960cd9d4SDaniel Vetter  * @type. Only useful for atomic properties, which is enforced.
3934960cd9d4SDaniel Vetter  *
3935960cd9d4SDaniel Vetter  * Returns:
3936960cd9d4SDaniel Vetter  * A pointer to the newly created property on success, NULL on failure.
3937960cd9d4SDaniel Vetter  */
393898f75de4SRob Clark struct drm_property *drm_property_create_object(struct drm_device *dev,
393998f75de4SRob Clark 					 int flags, const char *name, uint32_t type)
394098f75de4SRob Clark {
394198f75de4SRob Clark 	struct drm_property *property;
394298f75de4SRob Clark 
394398f75de4SRob Clark 	flags |= DRM_MODE_PROP_OBJECT;
394498f75de4SRob Clark 
3945960cd9d4SDaniel Vetter 	if (WARN_ON(!(flags & DRM_MODE_PROP_ATOMIC)))
3946960cd9d4SDaniel Vetter 		return NULL;
3947960cd9d4SDaniel Vetter 
394898f75de4SRob Clark 	property = drm_property_create(dev, flags, name, 1);
394998f75de4SRob Clark 	if (!property)
395098f75de4SRob Clark 		return NULL;
395198f75de4SRob Clark 
395298f75de4SRob Clark 	property->values[0] = type;
395398f75de4SRob Clark 
395498f75de4SRob Clark 	return property;
395598f75de4SRob Clark }
395698f75de4SRob Clark EXPORT_SYMBOL(drm_property_create_object);
395798f75de4SRob Clark 
3958c8e32cc1SDaniel Vetter /**
3959960cd9d4SDaniel Vetter  * drm_property_create_bool - create a new boolean property type
3960960cd9d4SDaniel Vetter  * @dev: drm device
3961960cd9d4SDaniel Vetter  * @flags: flags specifying the property type
3962960cd9d4SDaniel Vetter  * @name: name of the property
3963960cd9d4SDaniel Vetter  *
3964960cd9d4SDaniel Vetter  * This creates a new generic drm property which can then be attached to a drm
3965960cd9d4SDaniel Vetter  * object with drm_object_attach_property. The returned property object must be
3966960cd9d4SDaniel Vetter  * freed with drm_property_destroy.
3967960cd9d4SDaniel Vetter  *
3968960cd9d4SDaniel Vetter  * This is implemented as a ranged property with only {0, 1} as valid values.
3969960cd9d4SDaniel Vetter  *
3970960cd9d4SDaniel Vetter  * Returns:
3971960cd9d4SDaniel Vetter  * A pointer to the newly created property on success, NULL on failure.
3972960cd9d4SDaniel Vetter  */
3973960cd9d4SDaniel Vetter struct drm_property *drm_property_create_bool(struct drm_device *dev, int flags,
3974960cd9d4SDaniel Vetter 					 const char *name)
3975960cd9d4SDaniel Vetter {
3976960cd9d4SDaniel Vetter 	return drm_property_create_range(dev, flags, name, 0, 1);
3977960cd9d4SDaniel Vetter }
3978960cd9d4SDaniel Vetter EXPORT_SYMBOL(drm_property_create_bool);
3979960cd9d4SDaniel Vetter 
3980960cd9d4SDaniel Vetter /**
3981c8e32cc1SDaniel Vetter  * drm_property_add_enum - add a possible value to an enumeration property
3982c8e32cc1SDaniel Vetter  * @property: enumeration property to change
3983c8e32cc1SDaniel Vetter  * @index: index of the new enumeration
3984c8e32cc1SDaniel Vetter  * @value: value of the new enumeration
3985c8e32cc1SDaniel Vetter  * @name: symbolic name of the new enumeration
3986c8e32cc1SDaniel Vetter  *
3987c8e32cc1SDaniel Vetter  * This functions adds enumerations to a property.
3988c8e32cc1SDaniel Vetter  *
3989c8e32cc1SDaniel Vetter  * It's use is deprecated, drivers should use one of the more specific helpers
3990c8e32cc1SDaniel Vetter  * to directly create the property with all enumerations already attached.
3991c8e32cc1SDaniel Vetter  *
3992c8e32cc1SDaniel Vetter  * Returns:
3993c8e32cc1SDaniel Vetter  * Zero on success, error code on failure.
3994c8e32cc1SDaniel Vetter  */
3995f453ba04SDave Airlie int drm_property_add_enum(struct drm_property *property, int index,
3996f453ba04SDave Airlie 			  uint64_t value, const char *name)
3997f453ba04SDave Airlie {
3998f453ba04SDave Airlie 	struct drm_property_enum *prop_enum;
3999f453ba04SDave Airlie 
40005ea22f24SRob Clark 	if (!(drm_property_type_is(property, DRM_MODE_PROP_ENUM) ||
40015ea22f24SRob Clark 			drm_property_type_is(property, DRM_MODE_PROP_BITMASK)))
400249e27545SRob Clark 		return -EINVAL;
400349e27545SRob Clark 
400449e27545SRob Clark 	/*
400549e27545SRob Clark 	 * Bitmask enum properties have the additional constraint of values
400649e27545SRob Clark 	 * from 0 to 63
400749e27545SRob Clark 	 */
40085ea22f24SRob Clark 	if (drm_property_type_is(property, DRM_MODE_PROP_BITMASK) &&
40095ea22f24SRob Clark 			(value > 63))
4010f453ba04SDave Airlie 		return -EINVAL;
4011f453ba04SDave Airlie 
40123758b341SDaniel Vetter 	if (!list_empty(&property->enum_list)) {
40133758b341SDaniel Vetter 		list_for_each_entry(prop_enum, &property->enum_list, head) {
4014f453ba04SDave Airlie 			if (prop_enum->value == value) {
4015f453ba04SDave Airlie 				strncpy(prop_enum->name, name, DRM_PROP_NAME_LEN);
4016f453ba04SDave Airlie 				prop_enum->name[DRM_PROP_NAME_LEN-1] = '\0';
4017f453ba04SDave Airlie 				return 0;
4018f453ba04SDave Airlie 			}
4019f453ba04SDave Airlie 		}
4020f453ba04SDave Airlie 	}
4021f453ba04SDave Airlie 
4022f453ba04SDave Airlie 	prop_enum = kzalloc(sizeof(struct drm_property_enum), GFP_KERNEL);
4023f453ba04SDave Airlie 	if (!prop_enum)
4024f453ba04SDave Airlie 		return -ENOMEM;
4025f453ba04SDave Airlie 
4026f453ba04SDave Airlie 	strncpy(prop_enum->name, name, DRM_PROP_NAME_LEN);
4027f453ba04SDave Airlie 	prop_enum->name[DRM_PROP_NAME_LEN-1] = '\0';
4028f453ba04SDave Airlie 	prop_enum->value = value;
4029f453ba04SDave Airlie 
4030f453ba04SDave Airlie 	property->values[index] = value;
40313758b341SDaniel Vetter 	list_add_tail(&prop_enum->head, &property->enum_list);
4032f453ba04SDave Airlie 	return 0;
4033f453ba04SDave Airlie }
4034f453ba04SDave Airlie EXPORT_SYMBOL(drm_property_add_enum);
4035f453ba04SDave Airlie 
4036c8e32cc1SDaniel Vetter /**
4037c8e32cc1SDaniel Vetter  * drm_property_destroy - destroy a drm property
4038c8e32cc1SDaniel Vetter  * @dev: drm device
4039c8e32cc1SDaniel Vetter  * @property: property to destry
4040c8e32cc1SDaniel Vetter  *
4041c8e32cc1SDaniel Vetter  * This function frees a property including any attached resources like
4042c8e32cc1SDaniel Vetter  * enumeration values.
4043c8e32cc1SDaniel Vetter  */
4044f453ba04SDave Airlie void drm_property_destroy(struct drm_device *dev, struct drm_property *property)
4045f453ba04SDave Airlie {
4046f453ba04SDave Airlie 	struct drm_property_enum *prop_enum, *pt;
4047f453ba04SDave Airlie 
40483758b341SDaniel Vetter 	list_for_each_entry_safe(prop_enum, pt, &property->enum_list, head) {
4049f453ba04SDave Airlie 		list_del(&prop_enum->head);
4050f453ba04SDave Airlie 		kfree(prop_enum);
4051f453ba04SDave Airlie 	}
4052f453ba04SDave Airlie 
4053f453ba04SDave Airlie 	if (property->num_values)
4054f453ba04SDave Airlie 		kfree(property->values);
40557c8f6d25SDave Airlie 	drm_mode_object_unregister(dev, &property->base);
4056f453ba04SDave Airlie 	list_del(&property->head);
4057f453ba04SDave Airlie 	kfree(property);
4058f453ba04SDave Airlie }
4059f453ba04SDave Airlie EXPORT_SYMBOL(drm_property_destroy);
4060f453ba04SDave Airlie 
4061c8e32cc1SDaniel Vetter /**
4062c8e32cc1SDaniel Vetter  * drm_object_attach_property - attach a property to a modeset object
4063c8e32cc1SDaniel Vetter  * @obj: drm modeset object
4064c8e32cc1SDaniel Vetter  * @property: property to attach
4065c8e32cc1SDaniel Vetter  * @init_val: initial value of the property
4066c8e32cc1SDaniel Vetter  *
4067c8e32cc1SDaniel Vetter  * This attaches the given property to the modeset object with the given initial
4068c8e32cc1SDaniel Vetter  * value. Currently this function cannot fail since the properties are stored in
4069c8e32cc1SDaniel Vetter  * a statically sized array.
4070c8e32cc1SDaniel Vetter  */
4071c543188aSPaulo Zanoni void drm_object_attach_property(struct drm_mode_object *obj,
4072c543188aSPaulo Zanoni 				struct drm_property *property,
4073c543188aSPaulo Zanoni 				uint64_t init_val)
4074c543188aSPaulo Zanoni {
40757f88a9beSPaulo Zanoni 	int count = obj->properties->count;
4076c543188aSPaulo Zanoni 
40777f88a9beSPaulo Zanoni 	if (count == DRM_OBJECT_MAX_PROPERTY) {
40787f88a9beSPaulo Zanoni 		WARN(1, "Failed to attach object property (type: 0x%x). Please "
40797f88a9beSPaulo Zanoni 			"increase DRM_OBJECT_MAX_PROPERTY by 1 for each time "
40807f88a9beSPaulo Zanoni 			"you see this message on the same object type.\n",
40817f88a9beSPaulo Zanoni 			obj->type);
4082c543188aSPaulo Zanoni 		return;
4083c543188aSPaulo Zanoni 	}
4084c543188aSPaulo Zanoni 
4085b17cd757SRob Clark 	obj->properties->properties[count] = property;
40867f88a9beSPaulo Zanoni 	obj->properties->values[count] = init_val;
40877f88a9beSPaulo Zanoni 	obj->properties->count++;
408888a48e29SRob Clark 	if (property->flags & DRM_MODE_PROP_ATOMIC)
408988a48e29SRob Clark 		obj->properties->atomic_count++;
4090c543188aSPaulo Zanoni }
4091c543188aSPaulo Zanoni EXPORT_SYMBOL(drm_object_attach_property);
4092c543188aSPaulo Zanoni 
4093c8e32cc1SDaniel Vetter /**
4094c8e32cc1SDaniel Vetter  * drm_object_property_set_value - set the value of a property
4095c8e32cc1SDaniel Vetter  * @obj: drm mode object to set property value for
4096c8e32cc1SDaniel Vetter  * @property: property to set
4097c8e32cc1SDaniel Vetter  * @val: value the property should be set to
4098c8e32cc1SDaniel Vetter  *
4099c8e32cc1SDaniel Vetter  * This functions sets a given property on a given object. This function only
4100c8e32cc1SDaniel Vetter  * changes the software state of the property, it does not call into the
4101c8e32cc1SDaniel Vetter  * driver's ->set_property callback.
4102c8e32cc1SDaniel Vetter  *
4103c8e32cc1SDaniel Vetter  * Returns:
4104c8e32cc1SDaniel Vetter  * Zero on success, error code on failure.
4105c8e32cc1SDaniel Vetter  */
4106c543188aSPaulo Zanoni int drm_object_property_set_value(struct drm_mode_object *obj,
4107c543188aSPaulo Zanoni 				  struct drm_property *property, uint64_t val)
4108c543188aSPaulo Zanoni {
4109c543188aSPaulo Zanoni 	int i;
4110c543188aSPaulo Zanoni 
41117f88a9beSPaulo Zanoni 	for (i = 0; i < obj->properties->count; i++) {
4112b17cd757SRob Clark 		if (obj->properties->properties[i] == property) {
4113c543188aSPaulo Zanoni 			obj->properties->values[i] = val;
4114c543188aSPaulo Zanoni 			return 0;
4115c543188aSPaulo Zanoni 		}
4116c543188aSPaulo Zanoni 	}
4117c543188aSPaulo Zanoni 
4118c543188aSPaulo Zanoni 	return -EINVAL;
4119c543188aSPaulo Zanoni }
4120c543188aSPaulo Zanoni EXPORT_SYMBOL(drm_object_property_set_value);
4121c543188aSPaulo Zanoni 
4122c8e32cc1SDaniel Vetter /**
4123c8e32cc1SDaniel Vetter  * drm_object_property_get_value - retrieve the value of a property
4124c8e32cc1SDaniel Vetter  * @obj: drm mode object to get property value from
4125c8e32cc1SDaniel Vetter  * @property: property to retrieve
4126c8e32cc1SDaniel Vetter  * @val: storage for the property value
4127c8e32cc1SDaniel Vetter  *
4128c8e32cc1SDaniel Vetter  * This function retrieves the softare state of the given property for the given
4129c8e32cc1SDaniel Vetter  * property. Since there is no driver callback to retrieve the current property
4130c8e32cc1SDaniel Vetter  * value this might be out of sync with the hardware, depending upon the driver
4131c8e32cc1SDaniel Vetter  * and property.
4132c8e32cc1SDaniel Vetter  *
4133c8e32cc1SDaniel Vetter  * Returns:
4134c8e32cc1SDaniel Vetter  * Zero on success, error code on failure.
4135c8e32cc1SDaniel Vetter  */
4136c543188aSPaulo Zanoni int drm_object_property_get_value(struct drm_mode_object *obj,
4137c543188aSPaulo Zanoni 				  struct drm_property *property, uint64_t *val)
4138c543188aSPaulo Zanoni {
4139c543188aSPaulo Zanoni 	int i;
4140c543188aSPaulo Zanoni 
414188a48e29SRob Clark 	/* read-only properties bypass atomic mechanism and still store
414288a48e29SRob Clark 	 * their value in obj->properties->values[].. mostly to avoid
414388a48e29SRob Clark 	 * having to deal w/ EDID and similar props in atomic paths:
414488a48e29SRob Clark 	 */
414588a48e29SRob Clark 	if (drm_core_check_feature(property->dev, DRIVER_ATOMIC) &&
414688a48e29SRob Clark 			!(property->flags & DRM_MODE_PROP_IMMUTABLE))
414788a48e29SRob Clark 		return drm_atomic_get_property(obj, property, val);
414888a48e29SRob Clark 
41497f88a9beSPaulo Zanoni 	for (i = 0; i < obj->properties->count; i++) {
4150b17cd757SRob Clark 		if (obj->properties->properties[i] == property) {
4151c543188aSPaulo Zanoni 			*val = obj->properties->values[i];
4152c543188aSPaulo Zanoni 			return 0;
4153c543188aSPaulo Zanoni 		}
4154c543188aSPaulo Zanoni 	}
4155c543188aSPaulo Zanoni 
4156c543188aSPaulo Zanoni 	return -EINVAL;
4157c543188aSPaulo Zanoni }
4158c543188aSPaulo Zanoni EXPORT_SYMBOL(drm_object_property_get_value);
4159c543188aSPaulo Zanoni 
4160c8e32cc1SDaniel Vetter /**
41611a498633SDaniel Vetter  * drm_mode_getproperty_ioctl - get the property metadata
4162c8e32cc1SDaniel Vetter  * @dev: DRM device
4163c8e32cc1SDaniel Vetter  * @data: ioctl data
4164c8e32cc1SDaniel Vetter  * @file_priv: DRM file info
4165c8e32cc1SDaniel Vetter  *
41661a498633SDaniel Vetter  * This function retrieves the metadata for a given property, like the different
41671a498633SDaniel Vetter  * possible values for an enum property or the limits for a range property.
41681a498633SDaniel Vetter  *
41691a498633SDaniel Vetter  * Blob properties are special
4170c8e32cc1SDaniel Vetter  *
4171c8e32cc1SDaniel Vetter  * Called by the user via ioctl.
4172c8e32cc1SDaniel Vetter  *
4173c8e32cc1SDaniel Vetter  * Returns:
41741a498633SDaniel Vetter  * Zero on success, negative errno on failure.
4175c8e32cc1SDaniel Vetter  */
4176f453ba04SDave Airlie int drm_mode_getproperty_ioctl(struct drm_device *dev,
4177f453ba04SDave Airlie 			       void *data, struct drm_file *file_priv)
4178f453ba04SDave Airlie {
4179f453ba04SDave Airlie 	struct drm_mode_get_property *out_resp = data;
4180f453ba04SDave Airlie 	struct drm_property *property;
4181f453ba04SDave Airlie 	int enum_count = 0;
4182f453ba04SDave Airlie 	int value_count = 0;
4183f453ba04SDave Airlie 	int ret = 0, i;
4184f453ba04SDave Airlie 	int copied;
4185f453ba04SDave Airlie 	struct drm_property_enum *prop_enum;
4186f453ba04SDave Airlie 	struct drm_mode_property_enum __user *enum_ptr;
4187f453ba04SDave Airlie 	uint64_t __user *values_ptr;
4188f453ba04SDave Airlie 
4189fb3b06c8SDave Airlie 	if (!drm_core_check_feature(dev, DRIVER_MODESET))
4190fb3b06c8SDave Airlie 		return -EINVAL;
4191fb3b06c8SDave Airlie 
419284849903SDaniel Vetter 	drm_modeset_lock_all(dev);
4193a2b34e22SRob Clark 	property = drm_property_find(dev, out_resp->prop_id);
4194a2b34e22SRob Clark 	if (!property) {
4195f27657f2SVille Syrjälä 		ret = -ENOENT;
4196f453ba04SDave Airlie 		goto done;
4197f453ba04SDave Airlie 	}
4198f453ba04SDave Airlie 
41995ea22f24SRob Clark 	if (drm_property_type_is(property, DRM_MODE_PROP_ENUM) ||
42005ea22f24SRob Clark 			drm_property_type_is(property, DRM_MODE_PROP_BITMASK)) {
42013758b341SDaniel Vetter 		list_for_each_entry(prop_enum, &property->enum_list, head)
4202f453ba04SDave Airlie 			enum_count++;
4203f453ba04SDave Airlie 	}
4204f453ba04SDave Airlie 
4205f453ba04SDave Airlie 	value_count = property->num_values;
4206f453ba04SDave Airlie 
4207f453ba04SDave Airlie 	strncpy(out_resp->name, property->name, DRM_PROP_NAME_LEN);
4208f453ba04SDave Airlie 	out_resp->name[DRM_PROP_NAME_LEN-1] = 0;
4209f453ba04SDave Airlie 	out_resp->flags = property->flags;
4210f453ba04SDave Airlie 
4211f453ba04SDave Airlie 	if ((out_resp->count_values >= value_count) && value_count) {
421281f6c7f8SVille Syrjälä 		values_ptr = (uint64_t __user *)(unsigned long)out_resp->values_ptr;
4213f453ba04SDave Airlie 		for (i = 0; i < value_count; i++) {
4214f453ba04SDave Airlie 			if (copy_to_user(values_ptr + i, &property->values[i], sizeof(uint64_t))) {
4215f453ba04SDave Airlie 				ret = -EFAULT;
4216f453ba04SDave Airlie 				goto done;
4217f453ba04SDave Airlie 			}
4218f453ba04SDave Airlie 		}
4219f453ba04SDave Airlie 	}
4220f453ba04SDave Airlie 	out_resp->count_values = value_count;
4221f453ba04SDave Airlie 
42225ea22f24SRob Clark 	if (drm_property_type_is(property, DRM_MODE_PROP_ENUM) ||
42235ea22f24SRob Clark 			drm_property_type_is(property, DRM_MODE_PROP_BITMASK)) {
4224f453ba04SDave Airlie 		if ((out_resp->count_enum_blobs >= enum_count) && enum_count) {
4225f453ba04SDave Airlie 			copied = 0;
422681f6c7f8SVille Syrjälä 			enum_ptr = (struct drm_mode_property_enum __user *)(unsigned long)out_resp->enum_blob_ptr;
42273758b341SDaniel Vetter 			list_for_each_entry(prop_enum, &property->enum_list, head) {
4228f453ba04SDave Airlie 
4229f453ba04SDave Airlie 				if (copy_to_user(&enum_ptr[copied].value, &prop_enum->value, sizeof(uint64_t))) {
4230f453ba04SDave Airlie 					ret = -EFAULT;
4231f453ba04SDave Airlie 					goto done;
4232f453ba04SDave Airlie 				}
4233f453ba04SDave Airlie 
4234f453ba04SDave Airlie 				if (copy_to_user(&enum_ptr[copied].name,
4235f453ba04SDave Airlie 						 &prop_enum->name, DRM_PROP_NAME_LEN)) {
4236f453ba04SDave Airlie 					ret = -EFAULT;
4237f453ba04SDave Airlie 					goto done;
4238f453ba04SDave Airlie 				}
4239f453ba04SDave Airlie 				copied++;
4240f453ba04SDave Airlie 			}
4241f453ba04SDave Airlie 		}
4242f453ba04SDave Airlie 		out_resp->count_enum_blobs = enum_count;
4243f453ba04SDave Airlie 	}
4244f453ba04SDave Airlie 
42453758b341SDaniel Vetter 	/*
42463758b341SDaniel Vetter 	 * NOTE: The idea seems to have been to use this to read all the blob
42473758b341SDaniel Vetter 	 * property values. But nothing ever added them to the corresponding
42483758b341SDaniel Vetter 	 * list, userspace always used the special-purpose get_blob ioctl to
42493758b341SDaniel Vetter 	 * read the value for a blob property. It also doesn't make a lot of
42503758b341SDaniel Vetter 	 * sense to return values here when everything else is just metadata for
42513758b341SDaniel Vetter 	 * the property itself.
42523758b341SDaniel Vetter 	 */
42533758b341SDaniel Vetter 	if (drm_property_type_is(property, DRM_MODE_PROP_BLOB))
42543758b341SDaniel Vetter 		out_resp->count_enum_blobs = 0;
4255f453ba04SDave Airlie done:
425684849903SDaniel Vetter 	drm_modeset_unlock_all(dev);
4257f453ba04SDave Airlie 	return ret;
4258f453ba04SDave Airlie }
4259f453ba04SDave Airlie 
426099531d9bSDaniel Stone /**
426199531d9bSDaniel Stone  * drm_property_create_blob - Create new blob property
426299531d9bSDaniel Stone  *
426399531d9bSDaniel Stone  * Creates a new blob property for a specified DRM device, optionally
426499531d9bSDaniel Stone  * copying data.
426599531d9bSDaniel Stone  *
426699531d9bSDaniel Stone  * @dev: DRM device to create property for
426799531d9bSDaniel Stone  * @length: Length to allocate for blob data
426899531d9bSDaniel Stone  * @data: If specified, copies data into blob
426910e8cb7eSDaniel Stone  *
427010e8cb7eSDaniel Stone  * Returns:
427110e8cb7eSDaniel Stone  * New blob property with a single reference on success, or an ERR_PTR
427210e8cb7eSDaniel Stone  * value on failure.
427399531d9bSDaniel Stone  */
42746bcacf51SDaniel Stone struct drm_property_blob *
4275ecbbe59bSThierry Reding drm_property_create_blob(struct drm_device *dev, size_t length,
427612e6cecdSThierry Reding 			 const void *data)
4277f453ba04SDave Airlie {
4278f453ba04SDave Airlie 	struct drm_property_blob *blob;
42796bfc56aaSVille Syrjälä 	int ret;
4280f453ba04SDave Airlie 
42819ac0934bSDan Carpenter 	if (!length || length > ULONG_MAX - sizeof(struct drm_property_blob))
428210e8cb7eSDaniel Stone 		return ERR_PTR(-EINVAL);
4283f453ba04SDave Airlie 
4284f453ba04SDave Airlie 	blob = kzalloc(sizeof(struct drm_property_blob)+length, GFP_KERNEL);
4285f453ba04SDave Airlie 	if (!blob)
428610e8cb7eSDaniel Stone 		return ERR_PTR(-ENOMEM);
4287f453ba04SDave Airlie 
4288e2f5d2eaSDaniel Stone 	/* This must be explicitly initialised, so we can safely call list_del
4289e2f5d2eaSDaniel Stone 	 * on it in the removal handler, even if it isn't in a file list. */
4290e2f5d2eaSDaniel Stone 	INIT_LIST_HEAD(&blob->head_file);
4291f453ba04SDave Airlie 	blob->length = length;
42926bcacf51SDaniel Stone 	blob->dev = dev;
4293f453ba04SDave Airlie 
429499531d9bSDaniel Stone 	if (data)
4295f453ba04SDave Airlie 		memcpy(blob->data, data, length);
4296f453ba04SDave Airlie 
42978fb6e7a5SDaniel Stone 	mutex_lock(&dev->mode_config.blob_lock);
42988fb6e7a5SDaniel Stone 
42998fb6e7a5SDaniel Stone 	ret = drm_mode_object_get(dev, &blob->base, DRM_MODE_OBJECT_BLOB);
43008fb6e7a5SDaniel Stone 	if (ret) {
43018fb6e7a5SDaniel Stone 		kfree(blob);
43028fb6e7a5SDaniel Stone 		mutex_unlock(&dev->mode_config.blob_lock);
430310e8cb7eSDaniel Stone 		return ERR_PTR(-EINVAL);
43048fb6e7a5SDaniel Stone 	}
43058fb6e7a5SDaniel Stone 
43066bcacf51SDaniel Stone 	kref_init(&blob->refcount);
43076bcacf51SDaniel Stone 
4308e2f5d2eaSDaniel Stone 	list_add_tail(&blob->head_global,
4309e2f5d2eaSDaniel Stone 	              &dev->mode_config.property_blob_list);
43108fb6e7a5SDaniel Stone 
43118fb6e7a5SDaniel Stone 	mutex_unlock(&dev->mode_config.blob_lock);
43128fb6e7a5SDaniel Stone 
4313f453ba04SDave Airlie 	return blob;
4314f453ba04SDave Airlie }
43156bcacf51SDaniel Stone EXPORT_SYMBOL(drm_property_create_blob);
4316f453ba04SDave Airlie 
43176bcacf51SDaniel Stone /**
43186bcacf51SDaniel Stone  * drm_property_free_blob - Blob property destructor
43196bcacf51SDaniel Stone  *
43206bcacf51SDaniel Stone  * Internal free function for blob properties; must not be used directly.
43216bcacf51SDaniel Stone  *
4322f102c16eSDaniel Stone  * @kref: Reference
43236bcacf51SDaniel Stone  */
43246bcacf51SDaniel Stone static void drm_property_free_blob(struct kref *kref)
4325f453ba04SDave Airlie {
43266bcacf51SDaniel Stone 	struct drm_property_blob *blob =
43276bcacf51SDaniel Stone 		container_of(kref, struct drm_property_blob, refcount);
43286bcacf51SDaniel Stone 
43296bcacf51SDaniel Stone 	WARN_ON(!mutex_is_locked(&blob->dev->mode_config.blob_lock));
43306bcacf51SDaniel Stone 
4331e2f5d2eaSDaniel Stone 	list_del(&blob->head_global);
4332e2f5d2eaSDaniel Stone 	list_del(&blob->head_file);
43337c8f6d25SDave Airlie 	drm_mode_object_unregister(blob->dev, &blob->base);
43348fb6e7a5SDaniel Stone 
4335f453ba04SDave Airlie 	kfree(blob);
4336f453ba04SDave Airlie }
4337f453ba04SDave Airlie 
4338c8e32cc1SDaniel Vetter /**
43396bcacf51SDaniel Stone  * drm_property_unreference_blob - Unreference a blob property
43406bcacf51SDaniel Stone  *
43416bcacf51SDaniel Stone  * Drop a reference on a blob property. May free the object.
43426bcacf51SDaniel Stone  *
4343f102c16eSDaniel Stone  * @blob: Pointer to blob property
43446bcacf51SDaniel Stone  */
43456bcacf51SDaniel Stone void drm_property_unreference_blob(struct drm_property_blob *blob)
43466bcacf51SDaniel Stone {
43476bcacf51SDaniel Stone 	struct drm_device *dev;
43486bcacf51SDaniel Stone 
43496bcacf51SDaniel Stone 	if (!blob)
43506bcacf51SDaniel Stone 		return;
43516bcacf51SDaniel Stone 
43526bcacf51SDaniel Stone 	dev = blob->dev;
43536bcacf51SDaniel Stone 
43546bcacf51SDaniel Stone 	DRM_DEBUG("%p: blob ID: %d (%d)\n", blob, blob->base.id, atomic_read(&blob->refcount.refcount));
43556bcacf51SDaniel Stone 
43566bcacf51SDaniel Stone 	if (kref_put_mutex(&blob->refcount, drm_property_free_blob,
43576bcacf51SDaniel Stone 			   &dev->mode_config.blob_lock))
43586bcacf51SDaniel Stone 		mutex_unlock(&dev->mode_config.blob_lock);
43596bcacf51SDaniel Stone 	else
43606bcacf51SDaniel Stone 		might_lock(&dev->mode_config.blob_lock);
43616bcacf51SDaniel Stone }
43626bcacf51SDaniel Stone EXPORT_SYMBOL(drm_property_unreference_blob);
43636bcacf51SDaniel Stone 
43646bcacf51SDaniel Stone /**
43656bcacf51SDaniel Stone  * drm_property_unreference_blob_locked - Unreference a blob property with blob_lock held
43666bcacf51SDaniel Stone  *
43676bcacf51SDaniel Stone  * Drop a reference on a blob property. May free the object. This must be
43686bcacf51SDaniel Stone  * called with blob_lock held.
43696bcacf51SDaniel Stone  *
4370f102c16eSDaniel Stone  * @blob: Pointer to blob property
43716bcacf51SDaniel Stone  */
43726bcacf51SDaniel Stone static void drm_property_unreference_blob_locked(struct drm_property_blob *blob)
43736bcacf51SDaniel Stone {
43746bcacf51SDaniel Stone 	if (!blob)
43756bcacf51SDaniel Stone 		return;
43766bcacf51SDaniel Stone 
43776bcacf51SDaniel Stone 	DRM_DEBUG("%p: blob ID: %d (%d)\n", blob, blob->base.id, atomic_read(&blob->refcount.refcount));
43786bcacf51SDaniel Stone 
43796bcacf51SDaniel Stone 	kref_put(&blob->refcount, drm_property_free_blob);
43806bcacf51SDaniel Stone }
43816bcacf51SDaniel Stone 
43826bcacf51SDaniel Stone /**
4383e2f5d2eaSDaniel Stone  * drm_property_destroy_user_blobs - destroy all blobs created by this client
4384e2f5d2eaSDaniel Stone  * @dev:       DRM device
4385e2f5d2eaSDaniel Stone  * @file_priv: destroy all blobs owned by this file handle
4386e2f5d2eaSDaniel Stone  */
4387e2f5d2eaSDaniel Stone void drm_property_destroy_user_blobs(struct drm_device *dev,
4388e2f5d2eaSDaniel Stone 				     struct drm_file *file_priv)
4389e2f5d2eaSDaniel Stone {
4390e2f5d2eaSDaniel Stone 	struct drm_property_blob *blob, *bt;
4391e2f5d2eaSDaniel Stone 
4392e2f5d2eaSDaniel Stone 	mutex_lock(&dev->mode_config.blob_lock);
4393e2f5d2eaSDaniel Stone 
4394e2f5d2eaSDaniel Stone 	list_for_each_entry_safe(blob, bt, &file_priv->blobs, head_file) {
4395e2f5d2eaSDaniel Stone 		list_del_init(&blob->head_file);
4396e2f5d2eaSDaniel Stone 		drm_property_unreference_blob_locked(blob);
4397e2f5d2eaSDaniel Stone 	}
4398e2f5d2eaSDaniel Stone 
4399e2f5d2eaSDaniel Stone 	mutex_unlock(&dev->mode_config.blob_lock);
4400e2f5d2eaSDaniel Stone }
4401e2f5d2eaSDaniel Stone 
4402e2f5d2eaSDaniel Stone /**
44036bcacf51SDaniel Stone  * drm_property_reference_blob - Take a reference on an existing property
44046bcacf51SDaniel Stone  *
44056bcacf51SDaniel Stone  * Take a new reference on an existing blob property.
44066bcacf51SDaniel Stone  *
4407f102c16eSDaniel Stone  * @blob: Pointer to blob property
44086bcacf51SDaniel Stone  */
44096bcacf51SDaniel Stone struct drm_property_blob *drm_property_reference_blob(struct drm_property_blob *blob)
44106bcacf51SDaniel Stone {
44116bcacf51SDaniel Stone 	DRM_DEBUG("%p: blob ID: %d (%d)\n", blob, blob->base.id, atomic_read(&blob->refcount.refcount));
44126bcacf51SDaniel Stone 	kref_get(&blob->refcount);
44136bcacf51SDaniel Stone 	return blob;
44146bcacf51SDaniel Stone }
44156bcacf51SDaniel Stone EXPORT_SYMBOL(drm_property_reference_blob);
44166bcacf51SDaniel Stone 
44176bcacf51SDaniel Stone /*
44186bcacf51SDaniel Stone  * Like drm_property_lookup_blob, but does not return an additional reference.
44196bcacf51SDaniel Stone  * Must be called with blob_lock held.
44206bcacf51SDaniel Stone  */
44216bcacf51SDaniel Stone static struct drm_property_blob *__drm_property_lookup_blob(struct drm_device *dev,
44226bcacf51SDaniel Stone 							    uint32_t id)
44236bcacf51SDaniel Stone {
44246bcacf51SDaniel Stone 	struct drm_mode_object *obj = NULL;
44256bcacf51SDaniel Stone 	struct drm_property_blob *blob;
44266bcacf51SDaniel Stone 
44276bcacf51SDaniel Stone 	WARN_ON(!mutex_is_locked(&dev->mode_config.blob_lock));
44286bcacf51SDaniel Stone 
44296bcacf51SDaniel Stone 	mutex_lock(&dev->mode_config.idr_mutex);
44306bcacf51SDaniel Stone 	obj = idr_find(&dev->mode_config.crtc_idr, id);
44316bcacf51SDaniel Stone 	if (!obj || (obj->type != DRM_MODE_OBJECT_BLOB) || (obj->id != id))
44326bcacf51SDaniel Stone 		blob = NULL;
44336bcacf51SDaniel Stone 	else
44346bcacf51SDaniel Stone 		blob = obj_to_blob(obj);
44356bcacf51SDaniel Stone 	mutex_unlock(&dev->mode_config.idr_mutex);
44366bcacf51SDaniel Stone 
4437f453ba04SDave Airlie 	return blob;
4438f453ba04SDave Airlie }
4439f453ba04SDave Airlie 
44406bcacf51SDaniel Stone /**
44416bcacf51SDaniel Stone  * drm_property_lookup_blob - look up a blob property and take a reference
44426bcacf51SDaniel Stone  * @dev: drm device
44436bcacf51SDaniel Stone  * @id: id of the blob property
44446bcacf51SDaniel Stone  *
44456bcacf51SDaniel Stone  * If successful, this takes an additional reference to the blob property.
44466bcacf51SDaniel Stone  * callers need to make sure to eventually unreference the returned property
44476bcacf51SDaniel Stone  * again, using @drm_property_unreference_blob.
44486bcacf51SDaniel Stone  */
44496bcacf51SDaniel Stone struct drm_property_blob *drm_property_lookup_blob(struct drm_device *dev,
44506bcacf51SDaniel Stone 					           uint32_t id)
4451f453ba04SDave Airlie {
44526bcacf51SDaniel Stone 	struct drm_property_blob *blob;
44536bcacf51SDaniel Stone 
44546bcacf51SDaniel Stone 	mutex_lock(&dev->mode_config.blob_lock);
44556bcacf51SDaniel Stone 	blob = __drm_property_lookup_blob(dev, id);
44566bcacf51SDaniel Stone 	if (blob) {
44576bcacf51SDaniel Stone 		if (!kref_get_unless_zero(&blob->refcount))
44586bcacf51SDaniel Stone 			blob = NULL;
44596bcacf51SDaniel Stone 	}
44606bcacf51SDaniel Stone 	mutex_unlock(&dev->mode_config.blob_lock);
44616bcacf51SDaniel Stone 
44626bcacf51SDaniel Stone 	return blob;
44636bcacf51SDaniel Stone }
44646bcacf51SDaniel Stone EXPORT_SYMBOL(drm_property_lookup_blob);
44656bcacf51SDaniel Stone 
44666bcacf51SDaniel Stone /**
4467d2ed3436SDaniel Stone  * drm_property_replace_global_blob - atomically replace existing blob property
4468d2ed3436SDaniel Stone  * @dev: drm device
4469d2ed3436SDaniel Stone  * @replace: location of blob property pointer to be replaced
4470d2ed3436SDaniel Stone  * @length: length of data for new blob, or 0 for no data
4471d2ed3436SDaniel Stone  * @data: content for new blob, or NULL for no data
4472d2ed3436SDaniel Stone  * @obj_holds_id: optional object for property holding blob ID
4473d2ed3436SDaniel Stone  * @prop_holds_id: optional property holding blob ID
4474d2ed3436SDaniel Stone  * @return 0 on success or error on failure
4475d2ed3436SDaniel Stone  *
4476d2ed3436SDaniel Stone  * This function will atomically replace a global property in the blob list,
4477d2ed3436SDaniel Stone  * optionally updating a property which holds the ID of that property. It is
4478d2ed3436SDaniel Stone  * guaranteed to be atomic: no caller will be allowed to see intermediate
4479d2ed3436SDaniel Stone  * results, and either the entire operation will succeed and clean up the
4480d2ed3436SDaniel Stone  * previous property, or it will fail and the state will be unchanged.
4481d2ed3436SDaniel Stone  *
4482d2ed3436SDaniel Stone  * If length is 0 or data is NULL, no new blob will be created, and the holding
4483d2ed3436SDaniel Stone  * property, if specified, will be set to 0.
4484d2ed3436SDaniel Stone  *
4485d2ed3436SDaniel Stone  * Access to the replace pointer is assumed to be protected by the caller, e.g.
4486d2ed3436SDaniel Stone  * by holding the relevant modesetting object lock for its parent.
4487d2ed3436SDaniel Stone  *
4488d2ed3436SDaniel Stone  * For example, a drm_connector has a 'PATH' property, which contains the ID
4489d2ed3436SDaniel Stone  * of a blob property with the value of the MST path information. Calling this
4490d2ed3436SDaniel Stone  * function with replace pointing to the connector's path_blob_ptr, length and
4491d2ed3436SDaniel Stone  * data set for the new path information, obj_holds_id set to the connector's
4492d2ed3436SDaniel Stone  * base object, and prop_holds_id set to the path property name, will perform
4493d2ed3436SDaniel Stone  * a completely atomic update. The access to path_blob_ptr is protected by the
4494d2ed3436SDaniel Stone  * caller holding a lock on the connector.
4495d2ed3436SDaniel Stone  */
4496d2ed3436SDaniel Stone static int drm_property_replace_global_blob(struct drm_device *dev,
4497d2ed3436SDaniel Stone                                             struct drm_property_blob **replace,
4498d2ed3436SDaniel Stone                                             size_t length,
4499d2ed3436SDaniel Stone                                             const void *data,
4500d2ed3436SDaniel Stone                                             struct drm_mode_object *obj_holds_id,
4501d2ed3436SDaniel Stone                                             struct drm_property *prop_holds_id)
4502d2ed3436SDaniel Stone {
4503d2ed3436SDaniel Stone 	struct drm_property_blob *new_blob = NULL;
4504d2ed3436SDaniel Stone 	struct drm_property_blob *old_blob = NULL;
4505d2ed3436SDaniel Stone 	int ret;
4506d2ed3436SDaniel Stone 
4507d2ed3436SDaniel Stone 	WARN_ON(replace == NULL);
4508d2ed3436SDaniel Stone 
4509d2ed3436SDaniel Stone 	old_blob = *replace;
4510d2ed3436SDaniel Stone 
4511d2ed3436SDaniel Stone 	if (length && data) {
4512d2ed3436SDaniel Stone 		new_blob = drm_property_create_blob(dev, length, data);
451310e8cb7eSDaniel Stone 		if (IS_ERR(new_blob))
451410e8cb7eSDaniel Stone 			return PTR_ERR(new_blob);
4515d2ed3436SDaniel Stone 	}
4516d2ed3436SDaniel Stone 
4517d2ed3436SDaniel Stone 	/* This does not need to be synchronised with blob_lock, as the
4518d2ed3436SDaniel Stone 	 * get_properties ioctl locks all modesetting objects, and
4519d2ed3436SDaniel Stone 	 * obj_holds_id must be locked before calling here, so we cannot
4520d2ed3436SDaniel Stone 	 * have its value out of sync with the list membership modified
4521d2ed3436SDaniel Stone 	 * below under blob_lock. */
4522d2ed3436SDaniel Stone 	if (obj_holds_id) {
4523d2ed3436SDaniel Stone 		ret = drm_object_property_set_value(obj_holds_id,
4524d2ed3436SDaniel Stone 						    prop_holds_id,
4525d2ed3436SDaniel Stone 						    new_blob ?
4526d2ed3436SDaniel Stone 						        new_blob->base.id : 0);
4527d2ed3436SDaniel Stone 		if (ret != 0)
4528d2ed3436SDaniel Stone 			goto err_created;
4529d2ed3436SDaniel Stone 	}
4530d2ed3436SDaniel Stone 
45316bcacf51SDaniel Stone 	drm_property_unreference_blob(old_blob);
4532d2ed3436SDaniel Stone 	*replace = new_blob;
4533d2ed3436SDaniel Stone 
4534d2ed3436SDaniel Stone 	return 0;
4535d2ed3436SDaniel Stone 
4536d2ed3436SDaniel Stone err_created:
45376bcacf51SDaniel Stone 	drm_property_unreference_blob(new_blob);
4538d2ed3436SDaniel Stone 	return ret;
4539f453ba04SDave Airlie }
4540f453ba04SDave Airlie 
4541c8e32cc1SDaniel Vetter /**
4542c8e32cc1SDaniel Vetter  * drm_mode_getblob_ioctl - get the contents of a blob property value
4543c8e32cc1SDaniel Vetter  * @dev: DRM device
4544c8e32cc1SDaniel Vetter  * @data: ioctl data
4545c8e32cc1SDaniel Vetter  * @file_priv: DRM file info
4546c8e32cc1SDaniel Vetter  *
4547c8e32cc1SDaniel Vetter  * This function retrieves the contents of a blob property. The value stored in
4548c8e32cc1SDaniel Vetter  * an object's blob property is just a normal modeset object id.
4549c8e32cc1SDaniel Vetter  *
4550c8e32cc1SDaniel Vetter  * Called by the user via ioctl.
4551c8e32cc1SDaniel Vetter  *
4552c8e32cc1SDaniel Vetter  * Returns:
45531a498633SDaniel Vetter  * Zero on success, negative errno on failure.
4554c8e32cc1SDaniel Vetter  */
4555f453ba04SDave Airlie int drm_mode_getblob_ioctl(struct drm_device *dev,
4556f453ba04SDave Airlie 			   void *data, struct drm_file *file_priv)
4557f453ba04SDave Airlie {
4558f453ba04SDave Airlie 	struct drm_mode_get_blob *out_resp = data;
4559f453ba04SDave Airlie 	struct drm_property_blob *blob;
4560f453ba04SDave Airlie 	int ret = 0;
456181f6c7f8SVille Syrjälä 	void __user *blob_ptr;
4562f453ba04SDave Airlie 
4563fb3b06c8SDave Airlie 	if (!drm_core_check_feature(dev, DRIVER_MODESET))
4564fb3b06c8SDave Airlie 		return -EINVAL;
4565fb3b06c8SDave Airlie 
456684849903SDaniel Vetter 	drm_modeset_lock_all(dev);
45678fb6e7a5SDaniel Stone 	mutex_lock(&dev->mode_config.blob_lock);
45686bcacf51SDaniel Stone 	blob = __drm_property_lookup_blob(dev, out_resp->blob_id);
4569a2b34e22SRob Clark 	if (!blob) {
4570f27657f2SVille Syrjälä 		ret = -ENOENT;
4571f453ba04SDave Airlie 		goto done;
4572f453ba04SDave Airlie 	}
4573f453ba04SDave Airlie 
4574f453ba04SDave Airlie 	if (out_resp->length == blob->length) {
457581f6c7f8SVille Syrjälä 		blob_ptr = (void __user *)(unsigned long)out_resp->data;
4576f453ba04SDave Airlie 		if (copy_to_user(blob_ptr, blob->data, blob->length)) {
4577f453ba04SDave Airlie 			ret = -EFAULT;
4578f453ba04SDave Airlie 			goto done;
4579f453ba04SDave Airlie 		}
4580f453ba04SDave Airlie 	}
4581f453ba04SDave Airlie 	out_resp->length = blob->length;
4582f453ba04SDave Airlie 
4583f453ba04SDave Airlie done:
45848fb6e7a5SDaniel Stone 	mutex_unlock(&dev->mode_config.blob_lock);
458584849903SDaniel Vetter 	drm_modeset_unlock_all(dev);
4586f453ba04SDave Airlie 	return ret;
4587f453ba04SDave Airlie }
4588f453ba04SDave Airlie 
4589cc7096fbSDave Airlie /**
4590e2f5d2eaSDaniel Stone  * drm_mode_createblob_ioctl - create a new blob property
4591e2f5d2eaSDaniel Stone  * @dev: DRM device
4592e2f5d2eaSDaniel Stone  * @data: ioctl data
4593e2f5d2eaSDaniel Stone  * @file_priv: DRM file info
4594e2f5d2eaSDaniel Stone  *
4595e2f5d2eaSDaniel Stone  * This function creates a new blob property with user-defined values. In order
4596e2f5d2eaSDaniel Stone  * to give us sensible validation and checking when creating, rather than at
4597e2f5d2eaSDaniel Stone  * every potential use, we also require a type to be provided upfront.
4598e2f5d2eaSDaniel Stone  *
4599e2f5d2eaSDaniel Stone  * Called by the user via ioctl.
4600e2f5d2eaSDaniel Stone  *
4601e2f5d2eaSDaniel Stone  * Returns:
4602e2f5d2eaSDaniel Stone  * Zero on success, negative errno on failure.
4603e2f5d2eaSDaniel Stone  */
4604e2f5d2eaSDaniel Stone int drm_mode_createblob_ioctl(struct drm_device *dev,
4605e2f5d2eaSDaniel Stone 			      void *data, struct drm_file *file_priv)
4606e2f5d2eaSDaniel Stone {
4607e2f5d2eaSDaniel Stone 	struct drm_mode_create_blob *out_resp = data;
4608e2f5d2eaSDaniel Stone 	struct drm_property_blob *blob;
4609e2f5d2eaSDaniel Stone 	void __user *blob_ptr;
4610e2f5d2eaSDaniel Stone 	int ret = 0;
4611e2f5d2eaSDaniel Stone 
4612e2f5d2eaSDaniel Stone 	if (!drm_core_check_feature(dev, DRIVER_MODESET))
4613e2f5d2eaSDaniel Stone 		return -EINVAL;
4614e2f5d2eaSDaniel Stone 
4615e2f5d2eaSDaniel Stone 	blob = drm_property_create_blob(dev, out_resp->length, NULL);
4616e2f5d2eaSDaniel Stone 	if (IS_ERR(blob))
4617e2f5d2eaSDaniel Stone 		return PTR_ERR(blob);
4618e2f5d2eaSDaniel Stone 
4619e2f5d2eaSDaniel Stone 	blob_ptr = (void __user *)(unsigned long)out_resp->data;
4620e2f5d2eaSDaniel Stone 	if (copy_from_user(blob->data, blob_ptr, out_resp->length)) {
4621e2f5d2eaSDaniel Stone 		ret = -EFAULT;
4622e2f5d2eaSDaniel Stone 		goto out_blob;
4623e2f5d2eaSDaniel Stone 	}
4624e2f5d2eaSDaniel Stone 
4625e2f5d2eaSDaniel Stone 	/* Dropping the lock between create_blob and our access here is safe
4626e2f5d2eaSDaniel Stone 	 * as only the same file_priv can remove the blob; at this point, it is
4627e2f5d2eaSDaniel Stone 	 * not associated with any file_priv. */
4628e2f5d2eaSDaniel Stone 	mutex_lock(&dev->mode_config.blob_lock);
4629e2f5d2eaSDaniel Stone 	out_resp->blob_id = blob->base.id;
46308731b269SManeet Singh 	list_add_tail(&blob->head_file, &file_priv->blobs);
4631e2f5d2eaSDaniel Stone 	mutex_unlock(&dev->mode_config.blob_lock);
4632e2f5d2eaSDaniel Stone 
4633e2f5d2eaSDaniel Stone 	return 0;
4634e2f5d2eaSDaniel Stone 
4635e2f5d2eaSDaniel Stone out_blob:
4636e2f5d2eaSDaniel Stone 	drm_property_unreference_blob(blob);
4637e2f5d2eaSDaniel Stone 	return ret;
4638e2f5d2eaSDaniel Stone }
4639e2f5d2eaSDaniel Stone 
4640e2f5d2eaSDaniel Stone /**
4641e2f5d2eaSDaniel Stone  * drm_mode_destroyblob_ioctl - destroy a user blob property
4642e2f5d2eaSDaniel Stone  * @dev: DRM device
4643e2f5d2eaSDaniel Stone  * @data: ioctl data
4644e2f5d2eaSDaniel Stone  * @file_priv: DRM file info
4645e2f5d2eaSDaniel Stone  *
4646e2f5d2eaSDaniel Stone  * Destroy an existing user-defined blob property.
4647e2f5d2eaSDaniel Stone  *
4648e2f5d2eaSDaniel Stone  * Called by the user via ioctl.
4649e2f5d2eaSDaniel Stone  *
4650e2f5d2eaSDaniel Stone  * Returns:
4651e2f5d2eaSDaniel Stone  * Zero on success, negative errno on failure.
4652e2f5d2eaSDaniel Stone  */
4653e2f5d2eaSDaniel Stone int drm_mode_destroyblob_ioctl(struct drm_device *dev,
4654e2f5d2eaSDaniel Stone 			       void *data, struct drm_file *file_priv)
4655e2f5d2eaSDaniel Stone {
4656e2f5d2eaSDaniel Stone 	struct drm_mode_destroy_blob *out_resp = data;
4657e2f5d2eaSDaniel Stone 	struct drm_property_blob *blob = NULL, *bt;
4658e2f5d2eaSDaniel Stone 	bool found = false;
4659e2f5d2eaSDaniel Stone 	int ret = 0;
4660e2f5d2eaSDaniel Stone 
4661e2f5d2eaSDaniel Stone 	if (!drm_core_check_feature(dev, DRIVER_MODESET))
4662e2f5d2eaSDaniel Stone 		return -EINVAL;
4663e2f5d2eaSDaniel Stone 
4664e2f5d2eaSDaniel Stone 	mutex_lock(&dev->mode_config.blob_lock);
4665e2f5d2eaSDaniel Stone 	blob = __drm_property_lookup_blob(dev, out_resp->blob_id);
4666e2f5d2eaSDaniel Stone 	if (!blob) {
4667e2f5d2eaSDaniel Stone 		ret = -ENOENT;
4668e2f5d2eaSDaniel Stone 		goto err;
4669e2f5d2eaSDaniel Stone 	}
4670e2f5d2eaSDaniel Stone 
4671e2f5d2eaSDaniel Stone 	/* Ensure the property was actually created by this user. */
4672e2f5d2eaSDaniel Stone 	list_for_each_entry(bt, &file_priv->blobs, head_file) {
4673e2f5d2eaSDaniel Stone 		if (bt == blob) {
4674e2f5d2eaSDaniel Stone 			found = true;
4675e2f5d2eaSDaniel Stone 			break;
4676e2f5d2eaSDaniel Stone 		}
4677e2f5d2eaSDaniel Stone 	}
4678e2f5d2eaSDaniel Stone 
4679e2f5d2eaSDaniel Stone 	if (!found) {
4680e2f5d2eaSDaniel Stone 		ret = -EPERM;
4681e2f5d2eaSDaniel Stone 		goto err;
4682e2f5d2eaSDaniel Stone 	}
4683e2f5d2eaSDaniel Stone 
4684e2f5d2eaSDaniel Stone 	/* We must drop head_file here, because we may not be the last
4685e2f5d2eaSDaniel Stone 	 * reference on the blob. */
4686e2f5d2eaSDaniel Stone 	list_del_init(&blob->head_file);
4687e2f5d2eaSDaniel Stone 	drm_property_unreference_blob_locked(blob);
4688e2f5d2eaSDaniel Stone 	mutex_unlock(&dev->mode_config.blob_lock);
4689e2f5d2eaSDaniel Stone 
4690e2f5d2eaSDaniel Stone 	return 0;
4691e2f5d2eaSDaniel Stone 
4692e2f5d2eaSDaniel Stone err:
4693e2f5d2eaSDaniel Stone 	mutex_unlock(&dev->mode_config.blob_lock);
4694e2f5d2eaSDaniel Stone 	return ret;
4695e2f5d2eaSDaniel Stone }
4696e2f5d2eaSDaniel Stone 
4697e2f5d2eaSDaniel Stone /**
4698cc7096fbSDave Airlie  * drm_mode_connector_set_path_property - set tile property on connector
4699cc7096fbSDave Airlie  * @connector: connector to set property on.
4700d2ed3436SDaniel Stone  * @path: path to use for property; must not be NULL.
4701cc7096fbSDave Airlie  *
4702cc7096fbSDave Airlie  * This creates a property to expose to userspace to specify a
4703cc7096fbSDave Airlie  * connector path. This is mainly used for DisplayPort MST where
4704cc7096fbSDave Airlie  * connectors have a topology and we want to allow userspace to give
4705cc7096fbSDave Airlie  * them more meaningful names.
4706cc7096fbSDave Airlie  *
4707cc7096fbSDave Airlie  * Returns:
47081a498633SDaniel Vetter  * Zero on success, negative errno on failure.
4709cc7096fbSDave Airlie  */
471043aba7ebSDave Airlie int drm_mode_connector_set_path_property(struct drm_connector *connector,
471112e6cecdSThierry Reding 					 const char *path)
471243aba7ebSDave Airlie {
471343aba7ebSDave Airlie 	struct drm_device *dev = connector->dev;
4714ecbbe59bSThierry Reding 	int ret;
471543aba7ebSDave Airlie 
4716d2ed3436SDaniel Stone 	ret = drm_property_replace_global_blob(dev,
4717d2ed3436SDaniel Stone 	                                       &connector->path_blob_ptr,
4718d2ed3436SDaniel Stone 	                                       strlen(path) + 1,
4719d2ed3436SDaniel Stone 	                                       path,
4720d2ed3436SDaniel Stone 	                                       &connector->base,
4721d2ed3436SDaniel Stone 	                                       dev->mode_config.path_property);
472243aba7ebSDave Airlie 	return ret;
472343aba7ebSDave Airlie }
472443aba7ebSDave Airlie EXPORT_SYMBOL(drm_mode_connector_set_path_property);
472543aba7ebSDave Airlie 
4726c8e32cc1SDaniel Vetter /**
47276f134d7bSDave Airlie  * drm_mode_connector_set_tile_property - set tile property on connector
47286f134d7bSDave Airlie  * @connector: connector to set property on.
47296f134d7bSDave Airlie  *
47306f134d7bSDave Airlie  * This looks up the tile information for a connector, and creates a
47316f134d7bSDave Airlie  * property for userspace to parse if it exists. The property is of
47326f134d7bSDave Airlie  * the form of 8 integers using ':' as a separator.
47336f134d7bSDave Airlie  *
47346f134d7bSDave Airlie  * Returns:
47356f134d7bSDave Airlie  * Zero on success, errno on failure.
47366f134d7bSDave Airlie  */
47376f134d7bSDave Airlie int drm_mode_connector_set_tile_property(struct drm_connector *connector)
47386f134d7bSDave Airlie {
47396f134d7bSDave Airlie 	struct drm_device *dev = connector->dev;
47406f134d7bSDave Airlie 	char tile[256];
4741d2ed3436SDaniel Stone 	int ret;
47426f134d7bSDave Airlie 
47436f134d7bSDave Airlie 	if (!connector->has_tile) {
4744d2ed3436SDaniel Stone 		ret  = drm_property_replace_global_blob(dev,
4745d2ed3436SDaniel Stone 		                                        &connector->tile_blob_ptr,
4746d2ed3436SDaniel Stone 		                                        0,
4747d2ed3436SDaniel Stone 		                                        NULL,
4748d2ed3436SDaniel Stone 		                                        &connector->base,
4749d2ed3436SDaniel Stone 		                                        dev->mode_config.tile_property);
47506f134d7bSDave Airlie 		return ret;
47516f134d7bSDave Airlie 	}
47526f134d7bSDave Airlie 
47536f134d7bSDave Airlie 	snprintf(tile, 256, "%d:%d:%d:%d:%d:%d:%d:%d",
47546f134d7bSDave Airlie 		 connector->tile_group->id, connector->tile_is_single_monitor,
47556f134d7bSDave Airlie 		 connector->num_h_tile, connector->num_v_tile,
47566f134d7bSDave Airlie 		 connector->tile_h_loc, connector->tile_v_loc,
47576f134d7bSDave Airlie 		 connector->tile_h_size, connector->tile_v_size);
47586f134d7bSDave Airlie 
4759d2ed3436SDaniel Stone 	ret = drm_property_replace_global_blob(dev,
4760d2ed3436SDaniel Stone 	                                       &connector->tile_blob_ptr,
4761d2ed3436SDaniel Stone 	                                       strlen(tile) + 1,
4762d2ed3436SDaniel Stone 	                                       tile,
4763d2ed3436SDaniel Stone 	                                       &connector->base,
4764d2ed3436SDaniel Stone 	                                       dev->mode_config.tile_property);
47656f134d7bSDave Airlie 	return ret;
47666f134d7bSDave Airlie }
47676f134d7bSDave Airlie EXPORT_SYMBOL(drm_mode_connector_set_tile_property);
47686f134d7bSDave Airlie 
47696f134d7bSDave Airlie /**
4770c8e32cc1SDaniel Vetter  * drm_mode_connector_update_edid_property - update the edid property of a connector
4771c8e32cc1SDaniel Vetter  * @connector: drm connector
4772c8e32cc1SDaniel Vetter  * @edid: new value of the edid property
4773c8e32cc1SDaniel Vetter  *
4774c8e32cc1SDaniel Vetter  * This function creates a new blob modeset object and assigns its id to the
4775c8e32cc1SDaniel Vetter  * connector's edid property.
4776c8e32cc1SDaniel Vetter  *
4777c8e32cc1SDaniel Vetter  * Returns:
47781a498633SDaniel Vetter  * Zero on success, negative errno on failure.
4779c8e32cc1SDaniel Vetter  */
4780f453ba04SDave Airlie int drm_mode_connector_update_edid_property(struct drm_connector *connector,
478112e6cecdSThierry Reding 					    const struct edid *edid)
4782f453ba04SDave Airlie {
4783f453ba04SDave Airlie 	struct drm_device *dev = connector->dev;
4784d2ed3436SDaniel Stone 	size_t size = 0;
4785ecbbe59bSThierry Reding 	int ret;
4786f453ba04SDave Airlie 
47874cf2b281SThomas Wood 	/* ignore requests to set edid when overridden */
47884cf2b281SThomas Wood 	if (connector->override_edid)
47894cf2b281SThomas Wood 		return 0;
47904cf2b281SThomas Wood 
4791d2ed3436SDaniel Stone 	if (edid)
4792e24ff467SShixin Zeng 		size = EDID_LENGTH * (1 + edid->extensions);
4793f453ba04SDave Airlie 
4794d2ed3436SDaniel Stone 	ret = drm_property_replace_global_blob(dev,
4795d2ed3436SDaniel Stone 					       &connector->edid_blob_ptr,
4796d2ed3436SDaniel Stone 	                                       size,
4797d2ed3436SDaniel Stone 	                                       edid,
4798d2ed3436SDaniel Stone 	                                       &connector->base,
4799d2ed3436SDaniel Stone 	                                       dev->mode_config.edid_property);
4800f453ba04SDave Airlie 	return ret;
4801f453ba04SDave Airlie }
4802f453ba04SDave Airlie EXPORT_SYMBOL(drm_mode_connector_update_edid_property);
4803f453ba04SDave Airlie 
48043843e71fSRob Clark /* Some properties could refer to dynamic refcnt'd objects, or things that
48053843e71fSRob Clark  * need special locking to handle lifetime issues (ie. to ensure the prop
48063843e71fSRob Clark  * value doesn't become invalid part way through the property update due to
48073843e71fSRob Clark  * race).  The value returned by reference via 'obj' should be passed back
48083843e71fSRob Clark  * to drm_property_change_valid_put() after the property is set (and the
48093843e71fSRob Clark  * object to which the property is attached has a chance to take it's own
48103843e71fSRob Clark  * reference).
48113843e71fSRob Clark  */
4812d34f20d6SRob Clark bool drm_property_change_valid_get(struct drm_property *property,
48133843e71fSRob Clark 					 uint64_t value, struct drm_mode_object **ref)
481426a34815SPaulo Zanoni {
48152ca651d1SThierry Reding 	int i;
48162ca651d1SThierry Reding 
481726a34815SPaulo Zanoni 	if (property->flags & DRM_MODE_PROP_IMMUTABLE)
481826a34815SPaulo Zanoni 		return false;
48195ea22f24SRob Clark 
48203843e71fSRob Clark 	*ref = NULL;
48213843e71fSRob Clark 
48225ea22f24SRob Clark 	if (drm_property_type_is(property, DRM_MODE_PROP_RANGE)) {
482326a34815SPaulo Zanoni 		if (value < property->values[0] || value > property->values[1])
482426a34815SPaulo Zanoni 			return false;
482526a34815SPaulo Zanoni 		return true;
4826ebc44cf3SRob Clark 	} else if (drm_property_type_is(property, DRM_MODE_PROP_SIGNED_RANGE)) {
4827ebc44cf3SRob Clark 		int64_t svalue = U642I64(value);
48284dfd909fSThierry Reding 
4829ebc44cf3SRob Clark 		if (svalue < U642I64(property->values[0]) ||
4830ebc44cf3SRob Clark 				svalue > U642I64(property->values[1]))
4831ebc44cf3SRob Clark 			return false;
4832ebc44cf3SRob Clark 		return true;
48335ea22f24SRob Clark 	} else if (drm_property_type_is(property, DRM_MODE_PROP_BITMASK)) {
4834592c20eeSVille Syrjälä 		uint64_t valid_mask = 0;
48354dfd909fSThierry Reding 
483649e27545SRob Clark 		for (i = 0; i < property->num_values; i++)
483749e27545SRob Clark 			valid_mask |= (1ULL << property->values[i]);
483849e27545SRob Clark 		return !(value & ~valid_mask);
48395ea22f24SRob Clark 	} else if (drm_property_type_is(property, DRM_MODE_PROP_BLOB)) {
48406bcacf51SDaniel Stone 		struct drm_property_blob *blob;
48416bcacf51SDaniel Stone 
48426bcacf51SDaniel Stone 		if (value == 0)
4843c4a56750SVille Syrjälä 			return true;
48446bcacf51SDaniel Stone 
48456bcacf51SDaniel Stone 		blob = drm_property_lookup_blob(property->dev, value);
48466bcacf51SDaniel Stone 		if (blob) {
48476bcacf51SDaniel Stone 			*ref = &blob->base;
48486bcacf51SDaniel Stone 			return true;
48496bcacf51SDaniel Stone 		} else {
48506bcacf51SDaniel Stone 			return false;
48516bcacf51SDaniel Stone 		}
485298f75de4SRob Clark 	} else if (drm_property_type_is(property, DRM_MODE_PROP_OBJECT)) {
485398f75de4SRob Clark 		/* a zero value for an object property translates to null: */
485498f75de4SRob Clark 		if (value == 0)
485598f75de4SRob Clark 			return true;
48563843e71fSRob Clark 
48573843e71fSRob Clark 		/* handle refcnt'd objects specially: */
48583843e71fSRob Clark 		if (property->values[0] == DRM_MODE_OBJECT_FB) {
48593843e71fSRob Clark 			struct drm_framebuffer *fb;
48603843e71fSRob Clark 			fb = drm_framebuffer_lookup(property->dev, value);
48613843e71fSRob Clark 			if (fb) {
48623843e71fSRob Clark 				*ref = &fb->base;
48633843e71fSRob Clark 				return true;
48643843e71fSRob Clark 			} else {
48653843e71fSRob Clark 				return false;
48663843e71fSRob Clark 			}
48673843e71fSRob Clark 		} else {
48683843e71fSRob Clark 			return _object_find(property->dev, value, property->values[0]) != NULL;
48693843e71fSRob Clark 		}
48702ca651d1SThierry Reding 	}
48712ca651d1SThierry Reding 
487226a34815SPaulo Zanoni 	for (i = 0; i < property->num_values; i++)
487326a34815SPaulo Zanoni 		if (property->values[i] == value)
487426a34815SPaulo Zanoni 			return true;
487526a34815SPaulo Zanoni 	return false;
487626a34815SPaulo Zanoni }
487726a34815SPaulo Zanoni 
4878d34f20d6SRob Clark void drm_property_change_valid_put(struct drm_property *property,
48793843e71fSRob Clark 		struct drm_mode_object *ref)
48803843e71fSRob Clark {
48813843e71fSRob Clark 	if (!ref)
48823843e71fSRob Clark 		return;
48833843e71fSRob Clark 
48843843e71fSRob Clark 	if (drm_property_type_is(property, DRM_MODE_PROP_OBJECT)) {
48853843e71fSRob Clark 		if (property->values[0] == DRM_MODE_OBJECT_FB)
48863843e71fSRob Clark 			drm_framebuffer_unreference(obj_to_fb(ref));
4887da9b2a38SDaniel Stone 	} else if (drm_property_type_is(property, DRM_MODE_PROP_BLOB))
4888da9b2a38SDaniel Stone 		drm_property_unreference_blob(obj_to_blob(ref));
48893843e71fSRob Clark }
48903843e71fSRob Clark 
4891c8e32cc1SDaniel Vetter /**
4892c8e32cc1SDaniel Vetter  * drm_mode_connector_property_set_ioctl - set the current value of a connector property
4893c8e32cc1SDaniel Vetter  * @dev: DRM device
4894c8e32cc1SDaniel Vetter  * @data: ioctl data
4895c8e32cc1SDaniel Vetter  * @file_priv: DRM file info
4896c8e32cc1SDaniel Vetter  *
4897c8e32cc1SDaniel Vetter  * This function sets the current value for a connectors's property. It also
4898c8e32cc1SDaniel Vetter  * calls into a driver's ->set_property callback to update the hardware state
4899c8e32cc1SDaniel Vetter  *
4900c8e32cc1SDaniel Vetter  * Called by the user via ioctl.
4901c8e32cc1SDaniel Vetter  *
4902c8e32cc1SDaniel Vetter  * Returns:
49031a498633SDaniel Vetter  * Zero on success, negative errno on failure.
4904c8e32cc1SDaniel Vetter  */
4905f453ba04SDave Airlie int drm_mode_connector_property_set_ioctl(struct drm_device *dev,
4906f453ba04SDave Airlie 				       void *data, struct drm_file *file_priv)
4907f453ba04SDave Airlie {
49080057d8ddSPaulo Zanoni 	struct drm_mode_connector_set_property *conn_set_prop = data;
49090057d8ddSPaulo Zanoni 	struct drm_mode_obj_set_property obj_set_prop = {
49100057d8ddSPaulo Zanoni 		.value = conn_set_prop->value,
49110057d8ddSPaulo Zanoni 		.prop_id = conn_set_prop->prop_id,
49120057d8ddSPaulo Zanoni 		.obj_id = conn_set_prop->connector_id,
49130057d8ddSPaulo Zanoni 		.obj_type = DRM_MODE_OBJECT_CONNECTOR
49140057d8ddSPaulo Zanoni 	};
4915f453ba04SDave Airlie 
49160057d8ddSPaulo Zanoni 	/* It does all the locking and checking we need */
49170057d8ddSPaulo Zanoni 	return drm_mode_obj_set_property_ioctl(dev, &obj_set_prop, file_priv);
4918f453ba04SDave Airlie }
4919f453ba04SDave Airlie 
4920c543188aSPaulo Zanoni static int drm_mode_connector_set_obj_prop(struct drm_mode_object *obj,
4921c543188aSPaulo Zanoni 					   struct drm_property *property,
4922c543188aSPaulo Zanoni 					   uint64_t value)
4923c543188aSPaulo Zanoni {
4924c543188aSPaulo Zanoni 	int ret = -EINVAL;
4925c543188aSPaulo Zanoni 	struct drm_connector *connector = obj_to_connector(obj);
4926c543188aSPaulo Zanoni 
4927c543188aSPaulo Zanoni 	/* Do DPMS ourselves */
4928c543188aSPaulo Zanoni 	if (property == connector->dev->mode_config.dpms_property) {
49299a69a9acSMaarten Lankhorst 		ret = (*connector->funcs->dpms)(connector, (int)value);
4930c543188aSPaulo Zanoni 	} else if (connector->funcs->set_property)
4931c543188aSPaulo Zanoni 		ret = connector->funcs->set_property(connector, property, value);
4932c543188aSPaulo Zanoni 
4933c543188aSPaulo Zanoni 	/* store the property value if successful */
4934c543188aSPaulo Zanoni 	if (!ret)
493558495563SRob Clark 		drm_object_property_set_value(&connector->base, property, value);
4936c543188aSPaulo Zanoni 	return ret;
4937c543188aSPaulo Zanoni }
4938c543188aSPaulo Zanoni 
4939bffd9de0SPaulo Zanoni static int drm_mode_crtc_set_obj_prop(struct drm_mode_object *obj,
4940bffd9de0SPaulo Zanoni 				      struct drm_property *property,
4941bffd9de0SPaulo Zanoni 				      uint64_t value)
4942bffd9de0SPaulo Zanoni {
4943bffd9de0SPaulo Zanoni 	int ret = -EINVAL;
4944bffd9de0SPaulo Zanoni 	struct drm_crtc *crtc = obj_to_crtc(obj);
4945bffd9de0SPaulo Zanoni 
4946bffd9de0SPaulo Zanoni 	if (crtc->funcs->set_property)
4947bffd9de0SPaulo Zanoni 		ret = crtc->funcs->set_property(crtc, property, value);
4948bffd9de0SPaulo Zanoni 	if (!ret)
4949bffd9de0SPaulo Zanoni 		drm_object_property_set_value(obj, property, value);
4950bffd9de0SPaulo Zanoni 
4951bffd9de0SPaulo Zanoni 	return ret;
4952bffd9de0SPaulo Zanoni }
4953bffd9de0SPaulo Zanoni 
49543a5f87c2SThomas Wood /**
49553a5f87c2SThomas Wood  * drm_mode_plane_set_obj_prop - set the value of a property
49563a5f87c2SThomas Wood  * @plane: drm plane object to set property value for
49573a5f87c2SThomas Wood  * @property: property to set
49583a5f87c2SThomas Wood  * @value: value the property should be set to
49593a5f87c2SThomas Wood  *
49603a5f87c2SThomas Wood  * This functions sets a given property on a given plane object. This function
49613a5f87c2SThomas Wood  * calls the driver's ->set_property callback and changes the software state of
49623a5f87c2SThomas Wood  * the property if the callback succeeds.
49633a5f87c2SThomas Wood  *
49643a5f87c2SThomas Wood  * Returns:
49653a5f87c2SThomas Wood  * Zero on success, error code on failure.
49663a5f87c2SThomas Wood  */
49673a5f87c2SThomas Wood int drm_mode_plane_set_obj_prop(struct drm_plane *plane,
49684d93914aSRob Clark 				struct drm_property *property,
49694d93914aSRob Clark 				uint64_t value)
49704d93914aSRob Clark {
49714d93914aSRob Clark 	int ret = -EINVAL;
49723a5f87c2SThomas Wood 	struct drm_mode_object *obj = &plane->base;
49734d93914aSRob Clark 
49744d93914aSRob Clark 	if (plane->funcs->set_property)
49754d93914aSRob Clark 		ret = plane->funcs->set_property(plane, property, value);
49764d93914aSRob Clark 	if (!ret)
49774d93914aSRob Clark 		drm_object_property_set_value(obj, property, value);
49784d93914aSRob Clark 
49794d93914aSRob Clark 	return ret;
49804d93914aSRob Clark }
49813a5f87c2SThomas Wood EXPORT_SYMBOL(drm_mode_plane_set_obj_prop);
49824d93914aSRob Clark 
4983c8e32cc1SDaniel Vetter /**
49841a498633SDaniel Vetter  * drm_mode_obj_get_properties_ioctl - get the current value of a object's property
4985c8e32cc1SDaniel Vetter  * @dev: DRM device
4986c8e32cc1SDaniel Vetter  * @data: ioctl data
4987c8e32cc1SDaniel Vetter  * @file_priv: DRM file info
4988c8e32cc1SDaniel Vetter  *
4989c8e32cc1SDaniel Vetter  * This function retrieves the current value for an object's property. Compared
4990c8e32cc1SDaniel Vetter  * to the connector specific ioctl this one is extended to also work on crtc and
4991c8e32cc1SDaniel Vetter  * plane objects.
4992c8e32cc1SDaniel Vetter  *
4993c8e32cc1SDaniel Vetter  * Called by the user via ioctl.
4994c8e32cc1SDaniel Vetter  *
4995c8e32cc1SDaniel Vetter  * Returns:
49961a498633SDaniel Vetter  * Zero on success, negative errno on failure.
4997c8e32cc1SDaniel Vetter  */
4998c543188aSPaulo Zanoni int drm_mode_obj_get_properties_ioctl(struct drm_device *dev, void *data,
4999c543188aSPaulo Zanoni 				      struct drm_file *file_priv)
5000c543188aSPaulo Zanoni {
5001c543188aSPaulo Zanoni 	struct drm_mode_obj_get_properties *arg = data;
5002c543188aSPaulo Zanoni 	struct drm_mode_object *obj;
5003c543188aSPaulo Zanoni 	int ret = 0;
5004c543188aSPaulo Zanoni 
5005c543188aSPaulo Zanoni 	if (!drm_core_check_feature(dev, DRIVER_MODESET))
5006c543188aSPaulo Zanoni 		return -EINVAL;
5007c543188aSPaulo Zanoni 
500884849903SDaniel Vetter 	drm_modeset_lock_all(dev);
5009c543188aSPaulo Zanoni 
5010c543188aSPaulo Zanoni 	obj = drm_mode_object_find(dev, arg->obj_id, arg->obj_type);
5011c543188aSPaulo Zanoni 	if (!obj) {
5012f27657f2SVille Syrjälä 		ret = -ENOENT;
5013c543188aSPaulo Zanoni 		goto out;
5014c543188aSPaulo Zanoni 	}
5015c543188aSPaulo Zanoni 	if (!obj->properties) {
5016c543188aSPaulo Zanoni 		ret = -EINVAL;
5017c543188aSPaulo Zanoni 		goto out;
5018c543188aSPaulo Zanoni 	}
5019c543188aSPaulo Zanoni 
502088a48e29SRob Clark 	ret = get_properties(obj, file_priv->atomic,
502195cbf110SRob Clark 			(uint32_t __user *)(unsigned long)(arg->props_ptr),
502295cbf110SRob Clark 			(uint64_t __user *)(unsigned long)(arg->prop_values_ptr),
502395cbf110SRob Clark 			&arg->count_props);
5024c543188aSPaulo Zanoni 
5025c543188aSPaulo Zanoni out:
502684849903SDaniel Vetter 	drm_modeset_unlock_all(dev);
5027c543188aSPaulo Zanoni 	return ret;
5028c543188aSPaulo Zanoni }
5029c543188aSPaulo Zanoni 
5030c8e32cc1SDaniel Vetter /**
5031c8e32cc1SDaniel Vetter  * drm_mode_obj_set_property_ioctl - set the current value of an object's property
5032c8e32cc1SDaniel Vetter  * @dev: DRM device
5033c8e32cc1SDaniel Vetter  * @data: ioctl data
5034c8e32cc1SDaniel Vetter  * @file_priv: DRM file info
5035c8e32cc1SDaniel Vetter  *
5036c8e32cc1SDaniel Vetter  * This function sets the current value for an object's property. It also calls
5037c8e32cc1SDaniel Vetter  * into a driver's ->set_property callback to update the hardware state.
5038c8e32cc1SDaniel Vetter  * Compared to the connector specific ioctl this one is extended to also work on
5039c8e32cc1SDaniel Vetter  * crtc and plane objects.
5040c8e32cc1SDaniel Vetter  *
5041c8e32cc1SDaniel Vetter  * Called by the user via ioctl.
5042c8e32cc1SDaniel Vetter  *
5043c8e32cc1SDaniel Vetter  * Returns:
50441a498633SDaniel Vetter  * Zero on success, negative errno on failure.
5045c8e32cc1SDaniel Vetter  */
5046c543188aSPaulo Zanoni int drm_mode_obj_set_property_ioctl(struct drm_device *dev, void *data,
5047c543188aSPaulo Zanoni 				    struct drm_file *file_priv)
5048c543188aSPaulo Zanoni {
5049c543188aSPaulo Zanoni 	struct drm_mode_obj_set_property *arg = data;
5050c543188aSPaulo Zanoni 	struct drm_mode_object *arg_obj;
5051c543188aSPaulo Zanoni 	struct drm_mode_object *prop_obj;
5052c543188aSPaulo Zanoni 	struct drm_property *property;
50533843e71fSRob Clark 	int i, ret = -EINVAL;
50543843e71fSRob Clark 	struct drm_mode_object *ref;
5055c543188aSPaulo Zanoni 
5056c543188aSPaulo Zanoni 	if (!drm_core_check_feature(dev, DRIVER_MODESET))
5057c543188aSPaulo Zanoni 		return -EINVAL;
5058c543188aSPaulo Zanoni 
505984849903SDaniel Vetter 	drm_modeset_lock_all(dev);
5060c543188aSPaulo Zanoni 
5061c543188aSPaulo Zanoni 	arg_obj = drm_mode_object_find(dev, arg->obj_id, arg->obj_type);
5062f27657f2SVille Syrjälä 	if (!arg_obj) {
5063f27657f2SVille Syrjälä 		ret = -ENOENT;
5064c543188aSPaulo Zanoni 		goto out;
5065f27657f2SVille Syrjälä 	}
5066c543188aSPaulo Zanoni 	if (!arg_obj->properties)
5067c543188aSPaulo Zanoni 		goto out;
5068c543188aSPaulo Zanoni 
50697f88a9beSPaulo Zanoni 	for (i = 0; i < arg_obj->properties->count; i++)
5070b17cd757SRob Clark 		if (arg_obj->properties->properties[i]->base.id == arg->prop_id)
5071c543188aSPaulo Zanoni 			break;
5072c543188aSPaulo Zanoni 
50737f88a9beSPaulo Zanoni 	if (i == arg_obj->properties->count)
5074c543188aSPaulo Zanoni 		goto out;
5075c543188aSPaulo Zanoni 
5076c543188aSPaulo Zanoni 	prop_obj = drm_mode_object_find(dev, arg->prop_id,
5077c543188aSPaulo Zanoni 					DRM_MODE_OBJECT_PROPERTY);
5078f27657f2SVille Syrjälä 	if (!prop_obj) {
5079f27657f2SVille Syrjälä 		ret = -ENOENT;
5080c543188aSPaulo Zanoni 		goto out;
5081f27657f2SVille Syrjälä 	}
5082c543188aSPaulo Zanoni 	property = obj_to_property(prop_obj);
5083c543188aSPaulo Zanoni 
50843843e71fSRob Clark 	if (!drm_property_change_valid_get(property, arg->value, &ref))
5085c543188aSPaulo Zanoni 		goto out;
5086c543188aSPaulo Zanoni 
5087c543188aSPaulo Zanoni 	switch (arg_obj->type) {
5088c543188aSPaulo Zanoni 	case DRM_MODE_OBJECT_CONNECTOR:
5089c543188aSPaulo Zanoni 		ret = drm_mode_connector_set_obj_prop(arg_obj, property,
5090c543188aSPaulo Zanoni 						      arg->value);
5091c543188aSPaulo Zanoni 		break;
5092bffd9de0SPaulo Zanoni 	case DRM_MODE_OBJECT_CRTC:
5093bffd9de0SPaulo Zanoni 		ret = drm_mode_crtc_set_obj_prop(arg_obj, property, arg->value);
5094bffd9de0SPaulo Zanoni 		break;
50954d93914aSRob Clark 	case DRM_MODE_OBJECT_PLANE:
50963a5f87c2SThomas Wood 		ret = drm_mode_plane_set_obj_prop(obj_to_plane(arg_obj),
50973a5f87c2SThomas Wood 						  property, arg->value);
50984d93914aSRob Clark 		break;
5099c543188aSPaulo Zanoni 	}
5100c543188aSPaulo Zanoni 
51013843e71fSRob Clark 	drm_property_change_valid_put(property, ref);
51023843e71fSRob Clark 
5103c543188aSPaulo Zanoni out:
510484849903SDaniel Vetter 	drm_modeset_unlock_all(dev);
5105c543188aSPaulo Zanoni 	return ret;
5106c543188aSPaulo Zanoni }
5107c543188aSPaulo Zanoni 
5108c8e32cc1SDaniel Vetter /**
5109c8e32cc1SDaniel Vetter  * drm_mode_connector_attach_encoder - attach a connector to an encoder
5110c8e32cc1SDaniel Vetter  * @connector: connector to attach
5111c8e32cc1SDaniel Vetter  * @encoder: encoder to attach @connector to
5112c8e32cc1SDaniel Vetter  *
5113c8e32cc1SDaniel Vetter  * This function links up a connector to an encoder. Note that the routing
5114c8e32cc1SDaniel Vetter  * restrictions between encoders and crtcs are exposed to userspace through the
5115c8e32cc1SDaniel Vetter  * possible_clones and possible_crtcs bitmasks.
5116c8e32cc1SDaniel Vetter  *
5117c8e32cc1SDaniel Vetter  * Returns:
51181a498633SDaniel Vetter  * Zero on success, negative errno on failure.
5119c8e32cc1SDaniel Vetter  */
5120f453ba04SDave Airlie int drm_mode_connector_attach_encoder(struct drm_connector *connector,
5121f453ba04SDave Airlie 				      struct drm_encoder *encoder)
5122f453ba04SDave Airlie {
5123f453ba04SDave Airlie 	int i;
5124f453ba04SDave Airlie 
5125eb47fe80SThierry Reding 	/*
5126eb47fe80SThierry Reding 	 * In the past, drivers have attempted to model the static association
5127eb47fe80SThierry Reding 	 * of connector to encoder in simple connector/encoder devices using a
5128eb47fe80SThierry Reding 	 * direct assignment of connector->encoder = encoder. This connection
5129eb47fe80SThierry Reding 	 * is a logical one and the responsibility of the core, so drivers are
5130eb47fe80SThierry Reding 	 * expected not to mess with this.
5131eb47fe80SThierry Reding 	 *
5132eb47fe80SThierry Reding 	 * Note that the error return should've been enough here, but a large
5133eb47fe80SThierry Reding 	 * majority of drivers ignores the return value, so add in a big WARN
5134eb47fe80SThierry Reding 	 * to get people's attention.
5135eb47fe80SThierry Reding 	 */
5136eb47fe80SThierry Reding 	if (WARN_ON(connector->encoder))
5137eb47fe80SThierry Reding 		return -EINVAL;
5138eb47fe80SThierry Reding 
5139f453ba04SDave Airlie 	for (i = 0; i < DRM_CONNECTOR_MAX_ENCODER; i++) {
5140f453ba04SDave Airlie 		if (connector->encoder_ids[i] == 0) {
5141f453ba04SDave Airlie 			connector->encoder_ids[i] = encoder->base.id;
5142f453ba04SDave Airlie 			return 0;
5143f453ba04SDave Airlie 		}
5144f453ba04SDave Airlie 	}
5145f453ba04SDave Airlie 	return -ENOMEM;
5146f453ba04SDave Airlie }
5147f453ba04SDave Airlie EXPORT_SYMBOL(drm_mode_connector_attach_encoder);
5148f453ba04SDave Airlie 
5149c8e32cc1SDaniel Vetter /**
5150c8e32cc1SDaniel Vetter  * drm_mode_crtc_set_gamma_size - set the gamma table size
5151c8e32cc1SDaniel Vetter  * @crtc: CRTC to set the gamma table size for
5152c8e32cc1SDaniel Vetter  * @gamma_size: size of the gamma table
5153c8e32cc1SDaniel Vetter  *
5154c8e32cc1SDaniel Vetter  * Drivers which support gamma tables should set this to the supported gamma
5155c8e32cc1SDaniel Vetter  * table size when initializing the CRTC. Currently the drm core only supports a
5156c8e32cc1SDaniel Vetter  * fixed gamma table size.
5157c8e32cc1SDaniel Vetter  *
5158c8e32cc1SDaniel Vetter  * Returns:
51591a498633SDaniel Vetter  * Zero on success, negative errno on failure.
5160c8e32cc1SDaniel Vetter  */
51614cae5b84SSascha Hauer int drm_mode_crtc_set_gamma_size(struct drm_crtc *crtc,
5162f453ba04SDave Airlie 				 int gamma_size)
5163f453ba04SDave Airlie {
5164f453ba04SDave Airlie 	crtc->gamma_size = gamma_size;
5165f453ba04SDave Airlie 
5166bd3f0ff9SThierry Reding 	crtc->gamma_store = kcalloc(gamma_size, sizeof(uint16_t) * 3,
5167bd3f0ff9SThierry Reding 				    GFP_KERNEL);
5168f453ba04SDave Airlie 	if (!crtc->gamma_store) {
5169f453ba04SDave Airlie 		crtc->gamma_size = 0;
51704cae5b84SSascha Hauer 		return -ENOMEM;
5171f453ba04SDave Airlie 	}
5172f453ba04SDave Airlie 
51734cae5b84SSascha Hauer 	return 0;
5174f453ba04SDave Airlie }
5175f453ba04SDave Airlie EXPORT_SYMBOL(drm_mode_crtc_set_gamma_size);
5176f453ba04SDave Airlie 
5177c8e32cc1SDaniel Vetter /**
5178c8e32cc1SDaniel Vetter  * drm_mode_gamma_set_ioctl - set the gamma table
5179c8e32cc1SDaniel Vetter  * @dev: DRM device
5180c8e32cc1SDaniel Vetter  * @data: ioctl data
5181c8e32cc1SDaniel Vetter  * @file_priv: DRM file info
5182c8e32cc1SDaniel Vetter  *
5183c8e32cc1SDaniel Vetter  * Set the gamma table of a CRTC to the one passed in by the user. Userspace can
5184c8e32cc1SDaniel Vetter  * inquire the required gamma table size through drm_mode_gamma_get_ioctl.
5185c8e32cc1SDaniel Vetter  *
5186c8e32cc1SDaniel Vetter  * Called by the user via ioctl.
5187c8e32cc1SDaniel Vetter  *
5188c8e32cc1SDaniel Vetter  * Returns:
51891a498633SDaniel Vetter  * Zero on success, negative errno on failure.
5190c8e32cc1SDaniel Vetter  */
5191f453ba04SDave Airlie int drm_mode_gamma_set_ioctl(struct drm_device *dev,
5192f453ba04SDave Airlie 			     void *data, struct drm_file *file_priv)
5193f453ba04SDave Airlie {
5194f453ba04SDave Airlie 	struct drm_mode_crtc_lut *crtc_lut = data;
5195f453ba04SDave Airlie 	struct drm_crtc *crtc;
5196f453ba04SDave Airlie 	void *r_base, *g_base, *b_base;
5197f453ba04SDave Airlie 	int size;
5198f453ba04SDave Airlie 	int ret = 0;
5199f453ba04SDave Airlie 
5200fb3b06c8SDave Airlie 	if (!drm_core_check_feature(dev, DRIVER_MODESET))
5201fb3b06c8SDave Airlie 		return -EINVAL;
5202fb3b06c8SDave Airlie 
520384849903SDaniel Vetter 	drm_modeset_lock_all(dev);
5204a2b34e22SRob Clark 	crtc = drm_crtc_find(dev, crtc_lut->crtc_id);
5205a2b34e22SRob Clark 	if (!crtc) {
5206f27657f2SVille Syrjälä 		ret = -ENOENT;
5207f453ba04SDave Airlie 		goto out;
5208f453ba04SDave Airlie 	}
5209f453ba04SDave Airlie 
5210ebe0f244SLaurent Pinchart 	if (crtc->funcs->gamma_set == NULL) {
5211ebe0f244SLaurent Pinchart 		ret = -ENOSYS;
5212ebe0f244SLaurent Pinchart 		goto out;
5213ebe0f244SLaurent Pinchart 	}
5214ebe0f244SLaurent Pinchart 
5215f453ba04SDave Airlie 	/* memcpy into gamma store */
5216f453ba04SDave Airlie 	if (crtc_lut->gamma_size != crtc->gamma_size) {
5217f453ba04SDave Airlie 		ret = -EINVAL;
5218f453ba04SDave Airlie 		goto out;
5219f453ba04SDave Airlie 	}
5220f453ba04SDave Airlie 
5221f453ba04SDave Airlie 	size = crtc_lut->gamma_size * (sizeof(uint16_t));
5222f453ba04SDave Airlie 	r_base = crtc->gamma_store;
5223f453ba04SDave Airlie 	if (copy_from_user(r_base, (void __user *)(unsigned long)crtc_lut->red, size)) {
5224f453ba04SDave Airlie 		ret = -EFAULT;
5225f453ba04SDave Airlie 		goto out;
5226f453ba04SDave Airlie 	}
5227f453ba04SDave Airlie 
5228f453ba04SDave Airlie 	g_base = r_base + size;
5229f453ba04SDave Airlie 	if (copy_from_user(g_base, (void __user *)(unsigned long)crtc_lut->green, size)) {
5230f453ba04SDave Airlie 		ret = -EFAULT;
5231f453ba04SDave Airlie 		goto out;
5232f453ba04SDave Airlie 	}
5233f453ba04SDave Airlie 
5234f453ba04SDave Airlie 	b_base = g_base + size;
5235f453ba04SDave Airlie 	if (copy_from_user(b_base, (void __user *)(unsigned long)crtc_lut->blue, size)) {
5236f453ba04SDave Airlie 		ret = -EFAULT;
5237f453ba04SDave Airlie 		goto out;
5238f453ba04SDave Airlie 	}
5239f453ba04SDave Airlie 
52407203425aSJames Simmons 	crtc->funcs->gamma_set(crtc, r_base, g_base, b_base, 0, crtc->gamma_size);
5241f453ba04SDave Airlie 
5242f453ba04SDave Airlie out:
524384849903SDaniel Vetter 	drm_modeset_unlock_all(dev);
5244f453ba04SDave Airlie 	return ret;
5245f453ba04SDave Airlie 
5246f453ba04SDave Airlie }
5247f453ba04SDave Airlie 
5248c8e32cc1SDaniel Vetter /**
5249c8e32cc1SDaniel Vetter  * drm_mode_gamma_get_ioctl - get the gamma table
5250c8e32cc1SDaniel Vetter  * @dev: DRM device
5251c8e32cc1SDaniel Vetter  * @data: ioctl data
5252c8e32cc1SDaniel Vetter  * @file_priv: DRM file info
5253c8e32cc1SDaniel Vetter  *
5254c8e32cc1SDaniel Vetter  * Copy the current gamma table into the storage provided. This also provides
5255c8e32cc1SDaniel Vetter  * the gamma table size the driver expects, which can be used to size the
5256c8e32cc1SDaniel Vetter  * allocated storage.
5257c8e32cc1SDaniel Vetter  *
5258c8e32cc1SDaniel Vetter  * Called by the user via ioctl.
5259c8e32cc1SDaniel Vetter  *
5260c8e32cc1SDaniel Vetter  * Returns:
52611a498633SDaniel Vetter  * Zero on success, negative errno on failure.
5262c8e32cc1SDaniel Vetter  */
5263f453ba04SDave Airlie int drm_mode_gamma_get_ioctl(struct drm_device *dev,
5264f453ba04SDave Airlie 			     void *data, struct drm_file *file_priv)
5265f453ba04SDave Airlie {
5266f453ba04SDave Airlie 	struct drm_mode_crtc_lut *crtc_lut = data;
5267f453ba04SDave Airlie 	struct drm_crtc *crtc;
5268f453ba04SDave Airlie 	void *r_base, *g_base, *b_base;
5269f453ba04SDave Airlie 	int size;
5270f453ba04SDave Airlie 	int ret = 0;
5271f453ba04SDave Airlie 
5272fb3b06c8SDave Airlie 	if (!drm_core_check_feature(dev, DRIVER_MODESET))
5273fb3b06c8SDave Airlie 		return -EINVAL;
5274fb3b06c8SDave Airlie 
527584849903SDaniel Vetter 	drm_modeset_lock_all(dev);
5276a2b34e22SRob Clark 	crtc = drm_crtc_find(dev, crtc_lut->crtc_id);
5277a2b34e22SRob Clark 	if (!crtc) {
5278f27657f2SVille Syrjälä 		ret = -ENOENT;
5279f453ba04SDave Airlie 		goto out;
5280f453ba04SDave Airlie 	}
5281f453ba04SDave Airlie 
5282f453ba04SDave Airlie 	/* memcpy into gamma store */
5283f453ba04SDave Airlie 	if (crtc_lut->gamma_size != crtc->gamma_size) {
5284f453ba04SDave Airlie 		ret = -EINVAL;
5285f453ba04SDave Airlie 		goto out;
5286f453ba04SDave Airlie 	}
5287f453ba04SDave Airlie 
5288f453ba04SDave Airlie 	size = crtc_lut->gamma_size * (sizeof(uint16_t));
5289f453ba04SDave Airlie 	r_base = crtc->gamma_store;
5290f453ba04SDave Airlie 	if (copy_to_user((void __user *)(unsigned long)crtc_lut->red, r_base, size)) {
5291f453ba04SDave Airlie 		ret = -EFAULT;
5292f453ba04SDave Airlie 		goto out;
5293f453ba04SDave Airlie 	}
5294f453ba04SDave Airlie 
5295f453ba04SDave Airlie 	g_base = r_base + size;
5296f453ba04SDave Airlie 	if (copy_to_user((void __user *)(unsigned long)crtc_lut->green, g_base, size)) {
5297f453ba04SDave Airlie 		ret = -EFAULT;
5298f453ba04SDave Airlie 		goto out;
5299f453ba04SDave Airlie 	}
5300f453ba04SDave Airlie 
5301f453ba04SDave Airlie 	b_base = g_base + size;
5302f453ba04SDave Airlie 	if (copy_to_user((void __user *)(unsigned long)crtc_lut->blue, b_base, size)) {
5303f453ba04SDave Airlie 		ret = -EFAULT;
5304f453ba04SDave Airlie 		goto out;
5305f453ba04SDave Airlie 	}
5306f453ba04SDave Airlie out:
530784849903SDaniel Vetter 	drm_modeset_unlock_all(dev);
5308f453ba04SDave Airlie 	return ret;
5309f453ba04SDave Airlie }
5310d91d8a3fSKristian Høgsberg 
5311c8e32cc1SDaniel Vetter /**
5312c8e32cc1SDaniel Vetter  * drm_mode_page_flip_ioctl - schedule an asynchronous fb update
5313c8e32cc1SDaniel Vetter  * @dev: DRM device
5314c8e32cc1SDaniel Vetter  * @data: ioctl data
5315c8e32cc1SDaniel Vetter  * @file_priv: DRM file info
5316c8e32cc1SDaniel Vetter  *
5317c8e32cc1SDaniel Vetter  * This schedules an asynchronous update on a given CRTC, called page flip.
5318c8e32cc1SDaniel Vetter  * Optionally a drm event is generated to signal the completion of the event.
5319c8e32cc1SDaniel Vetter  * Generic drivers cannot assume that a pageflip with changed framebuffer
5320c8e32cc1SDaniel Vetter  * properties (including driver specific metadata like tiling layout) will work,
5321c8e32cc1SDaniel Vetter  * but some drivers support e.g. pixel format changes through the pageflip
5322c8e32cc1SDaniel Vetter  * ioctl.
5323c8e32cc1SDaniel Vetter  *
5324c8e32cc1SDaniel Vetter  * Called by the user via ioctl.
5325c8e32cc1SDaniel Vetter  *
5326c8e32cc1SDaniel Vetter  * Returns:
53271a498633SDaniel Vetter  * Zero on success, negative errno on failure.
5328c8e32cc1SDaniel Vetter  */
5329d91d8a3fSKristian Høgsberg int drm_mode_page_flip_ioctl(struct drm_device *dev,
5330d91d8a3fSKristian Høgsberg 			     void *data, struct drm_file *file_priv)
5331d91d8a3fSKristian Høgsberg {
5332d91d8a3fSKristian Høgsberg 	struct drm_mode_crtc_page_flip *page_flip = data;
5333d91d8a3fSKristian Høgsberg 	struct drm_crtc *crtc;
53343d30a59bSDaniel Vetter 	struct drm_framebuffer *fb = NULL;
5335d91d8a3fSKristian Høgsberg 	struct drm_pending_vblank_event *e = NULL;
5336d91d8a3fSKristian Høgsberg 	int ret = -EINVAL;
5337d91d8a3fSKristian Høgsberg 
5338d91d8a3fSKristian Høgsberg 	if (page_flip->flags & ~DRM_MODE_PAGE_FLIP_FLAGS ||
5339d91d8a3fSKristian Høgsberg 	    page_flip->reserved != 0)
5340d91d8a3fSKristian Høgsberg 		return -EINVAL;
5341d91d8a3fSKristian Høgsberg 
534262f2104fSKeith Packard 	if ((page_flip->flags & DRM_MODE_PAGE_FLIP_ASYNC) && !dev->mode_config.async_page_flip)
534362f2104fSKeith Packard 		return -EINVAL;
534462f2104fSKeith Packard 
5345a2b34e22SRob Clark 	crtc = drm_crtc_find(dev, page_flip->crtc_id);
5346a2b34e22SRob Clark 	if (!crtc)
5347f27657f2SVille Syrjälä 		return -ENOENT;
5348d91d8a3fSKristian Høgsberg 
53494d02e2deSDaniel Vetter 	drm_modeset_lock_crtc(crtc, crtc->primary);
5350f4510a27SMatt Roper 	if (crtc->primary->fb == NULL) {
535190c1efddSChris Wilson 		/* The framebuffer is currently unbound, presumably
535290c1efddSChris Wilson 		 * due to a hotplug event, that userspace has not
535390c1efddSChris Wilson 		 * yet discovered.
535490c1efddSChris Wilson 		 */
535590c1efddSChris Wilson 		ret = -EBUSY;
535690c1efddSChris Wilson 		goto out;
535790c1efddSChris Wilson 	}
535890c1efddSChris Wilson 
5359d91d8a3fSKristian Høgsberg 	if (crtc->funcs->page_flip == NULL)
5360d91d8a3fSKristian Høgsberg 		goto out;
5361d91d8a3fSKristian Høgsberg 
5362786b99edSDaniel Vetter 	fb = drm_framebuffer_lookup(dev, page_flip->fb_id);
536337c4e705SVille Syrjälä 	if (!fb) {
536437c4e705SVille Syrjälä 		ret = -ENOENT;
5365d91d8a3fSKristian Høgsberg 		goto out;
536637c4e705SVille Syrjälä 	}
5367d91d8a3fSKristian Høgsberg 
53682afa701dSVille Syrjälä 	if (crtc->state) {
53692afa701dSVille Syrjälä 		const struct drm_plane_state *state = crtc->primary->state;
53702afa701dSVille Syrjälä 
53712afa701dSVille Syrjälä 		ret = check_src_coords(state->src_x, state->src_y,
53722afa701dSVille Syrjälä 				       state->src_w, state->src_h, fb);
53732afa701dSVille Syrjälä 	} else {
5374c11e9283SDamien Lespiau 		ret = drm_crtc_check_viewport(crtc, crtc->x, crtc->y, &crtc->mode, fb);
53752afa701dSVille Syrjälä 	}
5376c11e9283SDamien Lespiau 	if (ret)
53775f61bb42SVille Syrjälä 		goto out;
53785f61bb42SVille Syrjälä 
5379f4510a27SMatt Roper 	if (crtc->primary->fb->pixel_format != fb->pixel_format) {
5380909d9cdaSLaurent Pinchart 		DRM_DEBUG_KMS("Page flip is not allowed to change frame buffer format.\n");
5381909d9cdaSLaurent Pinchart 		ret = -EINVAL;
5382909d9cdaSLaurent Pinchart 		goto out;
5383909d9cdaSLaurent Pinchart 	}
5384909d9cdaSLaurent Pinchart 
5385d91d8a3fSKristian Høgsberg 	if (page_flip->flags & DRM_MODE_PAGE_FLIP_EVENT) {
53862dd500f1SDaniel Vetter 		e = kzalloc(sizeof *e, GFP_KERNEL);
53872dd500f1SDaniel Vetter 		if (!e) {
5388d91d8a3fSKristian Høgsberg 			ret = -ENOMEM;
5389d91d8a3fSKristian Høgsberg 			goto out;
5390d91d8a3fSKristian Høgsberg 		}
53917bd4d7beSJesse Barnes 		e->event.base.type = DRM_EVENT_FLIP_COMPLETE;
5392f76511b9SThierry Reding 		e->event.base.length = sizeof(e->event);
5393d91d8a3fSKristian Høgsberg 		e->event.user_data = page_flip->user_data;
53942dd500f1SDaniel Vetter 		ret = drm_event_reserve_init(dev, file_priv, &e->base, &e->event.base);
53952dd500f1SDaniel Vetter 		if (ret) {
53962dd500f1SDaniel Vetter 			kfree(e);
53972dd500f1SDaniel Vetter 			goto out;
53982dd500f1SDaniel Vetter 		}
5399d91d8a3fSKristian Høgsberg 	}
5400d91d8a3fSKristian Høgsberg 
54013d30a59bSDaniel Vetter 	crtc->primary->old_fb = crtc->primary->fb;
5402ed8d1975SKeith Packard 	ret = crtc->funcs->page_flip(crtc, fb, e, page_flip->flags);
5403d91d8a3fSKristian Høgsberg 	if (ret) {
54042dd500f1SDaniel Vetter 		if (page_flip->flags & DRM_MODE_PAGE_FLIP_EVENT)
54052dd500f1SDaniel Vetter 			drm_event_cancel_free(dev, &e->base);
5406b0d12325SDaniel Vetter 		/* Keep the old fb, don't unref it. */
54073d30a59bSDaniel Vetter 		crtc->primary->old_fb = NULL;
5408b0d12325SDaniel Vetter 	} else {
54093cb43cc0SDaniel Vetter 		crtc->primary->fb = fb;
5410b0d12325SDaniel Vetter 		/* Unref only the old framebuffer. */
5411b0d12325SDaniel Vetter 		fb = NULL;
5412aef6a7eeSJoonyoung Shim 	}
5413d91d8a3fSKristian Høgsberg 
5414d91d8a3fSKristian Høgsberg out:
5415b0d12325SDaniel Vetter 	if (fb)
5416b0d12325SDaniel Vetter 		drm_framebuffer_unreference(fb);
54173d30a59bSDaniel Vetter 	if (crtc->primary->old_fb)
54183d30a59bSDaniel Vetter 		drm_framebuffer_unreference(crtc->primary->old_fb);
54193d30a59bSDaniel Vetter 	crtc->primary->old_fb = NULL;
5420d059f652SDaniel Vetter 	drm_modeset_unlock_crtc(crtc);
5421b4d5e7d1SDaniel Vetter 
5422d91d8a3fSKristian Høgsberg 	return ret;
5423d91d8a3fSKristian Høgsberg }
5424eb033556SChris Wilson 
5425c8e32cc1SDaniel Vetter /**
5426c8e32cc1SDaniel Vetter  * drm_mode_config_reset - call ->reset callbacks
5427c8e32cc1SDaniel Vetter  * @dev: drm device
5428c8e32cc1SDaniel Vetter  *
5429c8e32cc1SDaniel Vetter  * This functions calls all the crtc's, encoder's and connector's ->reset
5430c8e32cc1SDaniel Vetter  * callback. Drivers can use this in e.g. their driver load or resume code to
5431c8e32cc1SDaniel Vetter  * reset hardware and software state.
5432c8e32cc1SDaniel Vetter  */
5433eb033556SChris Wilson void drm_mode_config_reset(struct drm_device *dev)
5434eb033556SChris Wilson {
5435eb033556SChris Wilson 	struct drm_crtc *crtc;
54362a0d7cfdSDaniel Vetter 	struct drm_plane *plane;
5437eb033556SChris Wilson 	struct drm_encoder *encoder;
5438eb033556SChris Wilson 	struct drm_connector *connector;
5439eb033556SChris Wilson 
5440e4f62546SDaniel Vetter 	drm_for_each_plane(plane, dev)
54412a0d7cfdSDaniel Vetter 		if (plane->funcs->reset)
54422a0d7cfdSDaniel Vetter 			plane->funcs->reset(plane);
54432a0d7cfdSDaniel Vetter 
5444e4f62546SDaniel Vetter 	drm_for_each_crtc(crtc, dev)
5445eb033556SChris Wilson 		if (crtc->funcs->reset)
5446eb033556SChris Wilson 			crtc->funcs->reset(crtc);
5447eb033556SChris Wilson 
5448e4f62546SDaniel Vetter 	drm_for_each_encoder(encoder, dev)
5449eb033556SChris Wilson 		if (encoder->funcs->reset)
5450eb033556SChris Wilson 			encoder->funcs->reset(encoder);
5451eb033556SChris Wilson 
5452f8c2ba31SDaniel Vetter 	mutex_lock(&dev->mode_config.mutex);
54534eebf60bSDave Airlie 	drm_for_each_connector(connector, dev)
5454eb033556SChris Wilson 		if (connector->funcs->reset)
5455eb033556SChris Wilson 			connector->funcs->reset(connector);
5456f8c2ba31SDaniel Vetter 	mutex_unlock(&dev->mode_config.mutex);
54575e2cb2f6SDaniel Vetter }
5458eb033556SChris Wilson EXPORT_SYMBOL(drm_mode_config_reset);
5459ff72145bSDave Airlie 
5460c8e32cc1SDaniel Vetter /**
5461c8e32cc1SDaniel Vetter  * drm_mode_create_dumb_ioctl - create a dumb backing storage buffer
5462c8e32cc1SDaniel Vetter  * @dev: DRM device
5463c8e32cc1SDaniel Vetter  * @data: ioctl data
5464c8e32cc1SDaniel Vetter  * @file_priv: DRM file info
5465c8e32cc1SDaniel Vetter  *
5466c8e32cc1SDaniel Vetter  * This creates a new dumb buffer in the driver's backing storage manager (GEM,
5467c8e32cc1SDaniel Vetter  * TTM or something else entirely) and returns the resulting buffer handle. This
5468c8e32cc1SDaniel Vetter  * handle can then be wrapped up into a framebuffer modeset object.
5469c8e32cc1SDaniel Vetter  *
5470c8e32cc1SDaniel Vetter  * Note that userspace is not allowed to use such objects for render
5471c8e32cc1SDaniel Vetter  * acceleration - drivers must create their own private ioctls for such a use
5472c8e32cc1SDaniel Vetter  * case.
5473c8e32cc1SDaniel Vetter  *
5474c8e32cc1SDaniel Vetter  * Called by the user via ioctl.
5475c8e32cc1SDaniel Vetter  *
5476c8e32cc1SDaniel Vetter  * Returns:
54771a498633SDaniel Vetter  * Zero on success, negative errno on failure.
5478c8e32cc1SDaniel Vetter  */
5479ff72145bSDave Airlie int drm_mode_create_dumb_ioctl(struct drm_device *dev,
5480ff72145bSDave Airlie 			       void *data, struct drm_file *file_priv)
5481ff72145bSDave Airlie {
5482ff72145bSDave Airlie 	struct drm_mode_create_dumb *args = data;
5483b28cd41fSDavid Herrmann 	u32 cpp, stride, size;
5484ff72145bSDave Airlie 
5485ff72145bSDave Airlie 	if (!dev->driver->dumb_create)
5486ff72145bSDave Airlie 		return -ENOSYS;
5487b28cd41fSDavid Herrmann 	if (!args->width || !args->height || !args->bpp)
5488b28cd41fSDavid Herrmann 		return -EINVAL;
5489b28cd41fSDavid Herrmann 
5490b28cd41fSDavid Herrmann 	/* overflow checks for 32bit size calculations */
549100e72089SDavid Herrmann 	/* NOTE: DIV_ROUND_UP() can overflow */
5492b28cd41fSDavid Herrmann 	cpp = DIV_ROUND_UP(args->bpp, 8);
549300e72089SDavid Herrmann 	if (!cpp || cpp > 0xffffffffU / args->width)
5494b28cd41fSDavid Herrmann 		return -EINVAL;
5495b28cd41fSDavid Herrmann 	stride = cpp * args->width;
5496b28cd41fSDavid Herrmann 	if (args->height > 0xffffffffU / stride)
5497b28cd41fSDavid Herrmann 		return -EINVAL;
5498b28cd41fSDavid Herrmann 
5499b28cd41fSDavid Herrmann 	/* test for wrap-around */
5500b28cd41fSDavid Herrmann 	size = args->height * stride;
5501b28cd41fSDavid Herrmann 	if (PAGE_ALIGN(size) == 0)
5502b28cd41fSDavid Herrmann 		return -EINVAL;
5503b28cd41fSDavid Herrmann 
5504f6085952SThierry Reding 	/*
5505f6085952SThierry Reding 	 * handle, pitch and size are output parameters. Zero them out to
5506f6085952SThierry Reding 	 * prevent drivers from accidentally using uninitialized data. Since
5507f6085952SThierry Reding 	 * not all existing userspace is clearing these fields properly we
5508f6085952SThierry Reding 	 * cannot reject IOCTL with garbage in them.
5509f6085952SThierry Reding 	 */
5510f6085952SThierry Reding 	args->handle = 0;
5511f6085952SThierry Reding 	args->pitch = 0;
5512f6085952SThierry Reding 	args->size = 0;
5513f6085952SThierry Reding 
5514ff72145bSDave Airlie 	return dev->driver->dumb_create(file_priv, dev, args);
5515ff72145bSDave Airlie }
5516ff72145bSDave Airlie 
5517c8e32cc1SDaniel Vetter /**
5518c8e32cc1SDaniel Vetter  * drm_mode_mmap_dumb_ioctl - create an mmap offset for a dumb backing storage buffer
5519c8e32cc1SDaniel Vetter  * @dev: DRM device
5520c8e32cc1SDaniel Vetter  * @data: ioctl data
5521c8e32cc1SDaniel Vetter  * @file_priv: DRM file info
5522c8e32cc1SDaniel Vetter  *
5523c8e32cc1SDaniel Vetter  * Allocate an offset in the drm device node's address space to be able to
5524c8e32cc1SDaniel Vetter  * memory map a dumb buffer.
5525c8e32cc1SDaniel Vetter  *
5526c8e32cc1SDaniel Vetter  * Called by the user via ioctl.
5527c8e32cc1SDaniel Vetter  *
5528c8e32cc1SDaniel Vetter  * Returns:
55291a498633SDaniel Vetter  * Zero on success, negative errno on failure.
5530c8e32cc1SDaniel Vetter  */
5531ff72145bSDave Airlie int drm_mode_mmap_dumb_ioctl(struct drm_device *dev,
5532ff72145bSDave Airlie 			     void *data, struct drm_file *file_priv)
5533ff72145bSDave Airlie {
5534ff72145bSDave Airlie 	struct drm_mode_map_dumb *args = data;
5535ff72145bSDave Airlie 
5536ff72145bSDave Airlie 	/* call driver ioctl to get mmap offset */
5537ff72145bSDave Airlie 	if (!dev->driver->dumb_map_offset)
5538ff72145bSDave Airlie 		return -ENOSYS;
5539ff72145bSDave Airlie 
5540ff72145bSDave Airlie 	return dev->driver->dumb_map_offset(file_priv, dev, args->handle, &args->offset);
5541ff72145bSDave Airlie }
5542ff72145bSDave Airlie 
5543c8e32cc1SDaniel Vetter /**
5544c8e32cc1SDaniel Vetter  * drm_mode_destroy_dumb_ioctl - destroy a dumb backing strage buffer
5545c8e32cc1SDaniel Vetter  * @dev: DRM device
5546c8e32cc1SDaniel Vetter  * @data: ioctl data
5547c8e32cc1SDaniel Vetter  * @file_priv: DRM file info
5548c8e32cc1SDaniel Vetter  *
5549c8e32cc1SDaniel Vetter  * This destroys the userspace handle for the given dumb backing storage buffer.
5550c8e32cc1SDaniel Vetter  * Since buffer objects must be reference counted in the kernel a buffer object
5551c8e32cc1SDaniel Vetter  * won't be immediately freed if a framebuffer modeset object still uses it.
5552c8e32cc1SDaniel Vetter  *
5553c8e32cc1SDaniel Vetter  * Called by the user via ioctl.
5554c8e32cc1SDaniel Vetter  *
5555c8e32cc1SDaniel Vetter  * Returns:
55561a498633SDaniel Vetter  * Zero on success, negative errno on failure.
5557c8e32cc1SDaniel Vetter  */
5558ff72145bSDave Airlie int drm_mode_destroy_dumb_ioctl(struct drm_device *dev,
5559ff72145bSDave Airlie 				void *data, struct drm_file *file_priv)
5560ff72145bSDave Airlie {
5561ff72145bSDave Airlie 	struct drm_mode_destroy_dumb *args = data;
5562ff72145bSDave Airlie 
5563ff72145bSDave Airlie 	if (!dev->driver->dumb_destroy)
5564ff72145bSDave Airlie 		return -ENOSYS;
5565ff72145bSDave Airlie 
5566ff72145bSDave Airlie 	return dev->driver->dumb_destroy(file_priv, dev, args->handle);
5567ff72145bSDave Airlie }
5568248dbc23SDave Airlie 
5569c8e32cc1SDaniel Vetter /**
5570c8e32cc1SDaniel Vetter  * drm_fb_get_bpp_depth - get the bpp/depth values for format
5571c8e32cc1SDaniel Vetter  * @format: pixel format (DRM_FORMAT_*)
5572c8e32cc1SDaniel Vetter  * @depth: storage for the depth value
5573c8e32cc1SDaniel Vetter  * @bpp: storage for the bpp value
5574c8e32cc1SDaniel Vetter  *
5575c8e32cc1SDaniel Vetter  * This only supports RGB formats here for compat with code that doesn't use
5576c8e32cc1SDaniel Vetter  * pixel formats directly yet.
5577248dbc23SDave Airlie  */
5578248dbc23SDave Airlie void drm_fb_get_bpp_depth(uint32_t format, unsigned int *depth,
5579248dbc23SDave Airlie 			  int *bpp)
5580248dbc23SDave Airlie {
5581248dbc23SDave Airlie 	switch (format) {
5582c51a6bc5SVille Syrjälä 	case DRM_FORMAT_C8:
558304b3924dSVille Syrjälä 	case DRM_FORMAT_RGB332:
558404b3924dSVille Syrjälä 	case DRM_FORMAT_BGR233:
5585248dbc23SDave Airlie 		*depth = 8;
5586248dbc23SDave Airlie 		*bpp = 8;
5587248dbc23SDave Airlie 		break;
558804b3924dSVille Syrjälä 	case DRM_FORMAT_XRGB1555:
558904b3924dSVille Syrjälä 	case DRM_FORMAT_XBGR1555:
559004b3924dSVille Syrjälä 	case DRM_FORMAT_RGBX5551:
559104b3924dSVille Syrjälä 	case DRM_FORMAT_BGRX5551:
559204b3924dSVille Syrjälä 	case DRM_FORMAT_ARGB1555:
559304b3924dSVille Syrjälä 	case DRM_FORMAT_ABGR1555:
559404b3924dSVille Syrjälä 	case DRM_FORMAT_RGBA5551:
559504b3924dSVille Syrjälä 	case DRM_FORMAT_BGRA5551:
5596248dbc23SDave Airlie 		*depth = 15;
5597248dbc23SDave Airlie 		*bpp = 16;
5598248dbc23SDave Airlie 		break;
559904b3924dSVille Syrjälä 	case DRM_FORMAT_RGB565:
560004b3924dSVille Syrjälä 	case DRM_FORMAT_BGR565:
5601248dbc23SDave Airlie 		*depth = 16;
5602248dbc23SDave Airlie 		*bpp = 16;
5603248dbc23SDave Airlie 		break;
560404b3924dSVille Syrjälä 	case DRM_FORMAT_RGB888:
560504b3924dSVille Syrjälä 	case DRM_FORMAT_BGR888:
560604b3924dSVille Syrjälä 		*depth = 24;
560704b3924dSVille Syrjälä 		*bpp = 24;
560804b3924dSVille Syrjälä 		break;
560904b3924dSVille Syrjälä 	case DRM_FORMAT_XRGB8888:
561004b3924dSVille Syrjälä 	case DRM_FORMAT_XBGR8888:
561104b3924dSVille Syrjälä 	case DRM_FORMAT_RGBX8888:
561204b3924dSVille Syrjälä 	case DRM_FORMAT_BGRX8888:
5613248dbc23SDave Airlie 		*depth = 24;
5614248dbc23SDave Airlie 		*bpp = 32;
5615248dbc23SDave Airlie 		break;
561604b3924dSVille Syrjälä 	case DRM_FORMAT_XRGB2101010:
561704b3924dSVille Syrjälä 	case DRM_FORMAT_XBGR2101010:
561804b3924dSVille Syrjälä 	case DRM_FORMAT_RGBX1010102:
561904b3924dSVille Syrjälä 	case DRM_FORMAT_BGRX1010102:
562004b3924dSVille Syrjälä 	case DRM_FORMAT_ARGB2101010:
562104b3924dSVille Syrjälä 	case DRM_FORMAT_ABGR2101010:
562204b3924dSVille Syrjälä 	case DRM_FORMAT_RGBA1010102:
562304b3924dSVille Syrjälä 	case DRM_FORMAT_BGRA1010102:
5624248dbc23SDave Airlie 		*depth = 30;
5625248dbc23SDave Airlie 		*bpp = 32;
5626248dbc23SDave Airlie 		break;
562704b3924dSVille Syrjälä 	case DRM_FORMAT_ARGB8888:
562804b3924dSVille Syrjälä 	case DRM_FORMAT_ABGR8888:
562904b3924dSVille Syrjälä 	case DRM_FORMAT_RGBA8888:
563004b3924dSVille Syrjälä 	case DRM_FORMAT_BGRA8888:
5631248dbc23SDave Airlie 		*depth = 32;
5632248dbc23SDave Airlie 		*bpp = 32;
5633248dbc23SDave Airlie 		break;
5634248dbc23SDave Airlie 	default:
563523c453a4SVille Syrjälä 		DRM_DEBUG_KMS("unsupported pixel format %s\n",
563623c453a4SVille Syrjälä 			      drm_get_format_name(format));
5637248dbc23SDave Airlie 		*depth = 0;
5638248dbc23SDave Airlie 		*bpp = 0;
5639248dbc23SDave Airlie 		break;
5640248dbc23SDave Airlie 	}
5641248dbc23SDave Airlie }
5642248dbc23SDave Airlie EXPORT_SYMBOL(drm_fb_get_bpp_depth);
5643141670e9SVille Syrjälä 
5644141670e9SVille Syrjälä /**
5645141670e9SVille Syrjälä  * drm_format_num_planes - get the number of planes for format
5646141670e9SVille Syrjälä  * @format: pixel format (DRM_FORMAT_*)
5647141670e9SVille Syrjälä  *
5648c8e32cc1SDaniel Vetter  * Returns:
5649141670e9SVille Syrjälä  * The number of planes used by the specified pixel format.
5650141670e9SVille Syrjälä  */
5651141670e9SVille Syrjälä int drm_format_num_planes(uint32_t format)
5652141670e9SVille Syrjälä {
5653141670e9SVille Syrjälä 	switch (format) {
5654141670e9SVille Syrjälä 	case DRM_FORMAT_YUV410:
5655141670e9SVille Syrjälä 	case DRM_FORMAT_YVU410:
5656141670e9SVille Syrjälä 	case DRM_FORMAT_YUV411:
5657141670e9SVille Syrjälä 	case DRM_FORMAT_YVU411:
5658141670e9SVille Syrjälä 	case DRM_FORMAT_YUV420:
5659141670e9SVille Syrjälä 	case DRM_FORMAT_YVU420:
5660141670e9SVille Syrjälä 	case DRM_FORMAT_YUV422:
5661141670e9SVille Syrjälä 	case DRM_FORMAT_YVU422:
5662141670e9SVille Syrjälä 	case DRM_FORMAT_YUV444:
5663141670e9SVille Syrjälä 	case DRM_FORMAT_YVU444:
5664141670e9SVille Syrjälä 		return 3;
5665141670e9SVille Syrjälä 	case DRM_FORMAT_NV12:
5666141670e9SVille Syrjälä 	case DRM_FORMAT_NV21:
5667141670e9SVille Syrjälä 	case DRM_FORMAT_NV16:
5668141670e9SVille Syrjälä 	case DRM_FORMAT_NV61:
5669ba623f6aSLaurent Pinchart 	case DRM_FORMAT_NV24:
5670ba623f6aSLaurent Pinchart 	case DRM_FORMAT_NV42:
5671141670e9SVille Syrjälä 		return 2;
5672141670e9SVille Syrjälä 	default:
5673141670e9SVille Syrjälä 		return 1;
5674141670e9SVille Syrjälä 	}
5675141670e9SVille Syrjälä }
5676141670e9SVille Syrjälä EXPORT_SYMBOL(drm_format_num_planes);
56775a86bd55SVille Syrjälä 
56785a86bd55SVille Syrjälä /**
56795a86bd55SVille Syrjälä  * drm_format_plane_cpp - determine the bytes per pixel value
56805a86bd55SVille Syrjälä  * @format: pixel format (DRM_FORMAT_*)
56815a86bd55SVille Syrjälä  * @plane: plane index
56825a86bd55SVille Syrjälä  *
5683c8e32cc1SDaniel Vetter  * Returns:
56845a86bd55SVille Syrjälä  * The bytes per pixel value for the specified plane.
56855a86bd55SVille Syrjälä  */
56865a86bd55SVille Syrjälä int drm_format_plane_cpp(uint32_t format, int plane)
56875a86bd55SVille Syrjälä {
56885a86bd55SVille Syrjälä 	unsigned int depth;
56895a86bd55SVille Syrjälä 	int bpp;
56905a86bd55SVille Syrjälä 
56915a86bd55SVille Syrjälä 	if (plane >= drm_format_num_planes(format))
56925a86bd55SVille Syrjälä 		return 0;
56935a86bd55SVille Syrjälä 
56945a86bd55SVille Syrjälä 	switch (format) {
56955a86bd55SVille Syrjälä 	case DRM_FORMAT_YUYV:
56965a86bd55SVille Syrjälä 	case DRM_FORMAT_YVYU:
56975a86bd55SVille Syrjälä 	case DRM_FORMAT_UYVY:
56985a86bd55SVille Syrjälä 	case DRM_FORMAT_VYUY:
56995a86bd55SVille Syrjälä 		return 2;
57005a86bd55SVille Syrjälä 	case DRM_FORMAT_NV12:
57015a86bd55SVille Syrjälä 	case DRM_FORMAT_NV21:
57025a86bd55SVille Syrjälä 	case DRM_FORMAT_NV16:
57035a86bd55SVille Syrjälä 	case DRM_FORMAT_NV61:
5704ba623f6aSLaurent Pinchart 	case DRM_FORMAT_NV24:
5705ba623f6aSLaurent Pinchart 	case DRM_FORMAT_NV42:
57065a86bd55SVille Syrjälä 		return plane ? 2 : 1;
57075a86bd55SVille Syrjälä 	case DRM_FORMAT_YUV410:
57085a86bd55SVille Syrjälä 	case DRM_FORMAT_YVU410:
57095a86bd55SVille Syrjälä 	case DRM_FORMAT_YUV411:
57105a86bd55SVille Syrjälä 	case DRM_FORMAT_YVU411:
57115a86bd55SVille Syrjälä 	case DRM_FORMAT_YUV420:
57125a86bd55SVille Syrjälä 	case DRM_FORMAT_YVU420:
57135a86bd55SVille Syrjälä 	case DRM_FORMAT_YUV422:
57145a86bd55SVille Syrjälä 	case DRM_FORMAT_YVU422:
57155a86bd55SVille Syrjälä 	case DRM_FORMAT_YUV444:
57165a86bd55SVille Syrjälä 	case DRM_FORMAT_YVU444:
57175a86bd55SVille Syrjälä 		return 1;
57185a86bd55SVille Syrjälä 	default:
57195a86bd55SVille Syrjälä 		drm_fb_get_bpp_depth(format, &depth, &bpp);
57205a86bd55SVille Syrjälä 		return bpp >> 3;
57215a86bd55SVille Syrjälä 	}
57225a86bd55SVille Syrjälä }
57235a86bd55SVille Syrjälä EXPORT_SYMBOL(drm_format_plane_cpp);
572401b68b04SVille Syrjälä 
572501b68b04SVille Syrjälä /**
572601b68b04SVille Syrjälä  * drm_format_horz_chroma_subsampling - get the horizontal chroma subsampling factor
572701b68b04SVille Syrjälä  * @format: pixel format (DRM_FORMAT_*)
572801b68b04SVille Syrjälä  *
5729c8e32cc1SDaniel Vetter  * Returns:
573001b68b04SVille Syrjälä  * The horizontal chroma subsampling factor for the
573101b68b04SVille Syrjälä  * specified pixel format.
573201b68b04SVille Syrjälä  */
573301b68b04SVille Syrjälä int drm_format_horz_chroma_subsampling(uint32_t format)
573401b68b04SVille Syrjälä {
573501b68b04SVille Syrjälä 	switch (format) {
573601b68b04SVille Syrjälä 	case DRM_FORMAT_YUV411:
573701b68b04SVille Syrjälä 	case DRM_FORMAT_YVU411:
573801b68b04SVille Syrjälä 	case DRM_FORMAT_YUV410:
573901b68b04SVille Syrjälä 	case DRM_FORMAT_YVU410:
574001b68b04SVille Syrjälä 		return 4;
574101b68b04SVille Syrjälä 	case DRM_FORMAT_YUYV:
574201b68b04SVille Syrjälä 	case DRM_FORMAT_YVYU:
574301b68b04SVille Syrjälä 	case DRM_FORMAT_UYVY:
574401b68b04SVille Syrjälä 	case DRM_FORMAT_VYUY:
574501b68b04SVille Syrjälä 	case DRM_FORMAT_NV12:
574601b68b04SVille Syrjälä 	case DRM_FORMAT_NV21:
574701b68b04SVille Syrjälä 	case DRM_FORMAT_NV16:
574801b68b04SVille Syrjälä 	case DRM_FORMAT_NV61:
574901b68b04SVille Syrjälä 	case DRM_FORMAT_YUV422:
575001b68b04SVille Syrjälä 	case DRM_FORMAT_YVU422:
575101b68b04SVille Syrjälä 	case DRM_FORMAT_YUV420:
575201b68b04SVille Syrjälä 	case DRM_FORMAT_YVU420:
575301b68b04SVille Syrjälä 		return 2;
575401b68b04SVille Syrjälä 	default:
575501b68b04SVille Syrjälä 		return 1;
575601b68b04SVille Syrjälä 	}
575701b68b04SVille Syrjälä }
575801b68b04SVille Syrjälä EXPORT_SYMBOL(drm_format_horz_chroma_subsampling);
575901b68b04SVille Syrjälä 
576001b68b04SVille Syrjälä /**
576101b68b04SVille Syrjälä  * drm_format_vert_chroma_subsampling - get the vertical chroma subsampling factor
576201b68b04SVille Syrjälä  * @format: pixel format (DRM_FORMAT_*)
576301b68b04SVille Syrjälä  *
5764c8e32cc1SDaniel Vetter  * Returns:
576501b68b04SVille Syrjälä  * The vertical chroma subsampling factor for the
576601b68b04SVille Syrjälä  * specified pixel format.
576701b68b04SVille Syrjälä  */
576801b68b04SVille Syrjälä int drm_format_vert_chroma_subsampling(uint32_t format)
576901b68b04SVille Syrjälä {
577001b68b04SVille Syrjälä 	switch (format) {
577101b68b04SVille Syrjälä 	case DRM_FORMAT_YUV410:
577201b68b04SVille Syrjälä 	case DRM_FORMAT_YVU410:
577301b68b04SVille Syrjälä 		return 4;
577401b68b04SVille Syrjälä 	case DRM_FORMAT_YUV420:
577501b68b04SVille Syrjälä 	case DRM_FORMAT_YVU420:
577601b68b04SVille Syrjälä 	case DRM_FORMAT_NV12:
577701b68b04SVille Syrjälä 	case DRM_FORMAT_NV21:
577801b68b04SVille Syrjälä 		return 2;
577901b68b04SVille Syrjälä 	default:
578001b68b04SVille Syrjälä 		return 1;
578101b68b04SVille Syrjälä 	}
578201b68b04SVille Syrjälä }
578301b68b04SVille Syrjälä EXPORT_SYMBOL(drm_format_vert_chroma_subsampling);
578487d24fc3SLaurent Pinchart 
578587d24fc3SLaurent Pinchart /**
57864c61716cSVille Syrjälä  * drm_format_plane_width - width of the plane given the first plane
57874c61716cSVille Syrjälä  * @width: width of the first plane
57884c61716cSVille Syrjälä  * @format: pixel format
57894c61716cSVille Syrjälä  * @plane: plane index
57904c61716cSVille Syrjälä  *
57914c61716cSVille Syrjälä  * Returns:
57924c61716cSVille Syrjälä  * The width of @plane, given that the width of the first plane is @width.
57934c61716cSVille Syrjälä  */
57944c61716cSVille Syrjälä int drm_format_plane_width(int width, uint32_t format, int plane)
57954c61716cSVille Syrjälä {
57964c61716cSVille Syrjälä 	if (plane >= drm_format_num_planes(format))
57974c61716cSVille Syrjälä 		return 0;
57984c61716cSVille Syrjälä 
57994c61716cSVille Syrjälä 	if (plane == 0)
58004c61716cSVille Syrjälä 		return width;
58014c61716cSVille Syrjälä 
58024c61716cSVille Syrjälä 	return width / drm_format_horz_chroma_subsampling(format);
58034c61716cSVille Syrjälä }
58044c61716cSVille Syrjälä EXPORT_SYMBOL(drm_format_plane_width);
58054c61716cSVille Syrjälä 
58064c61716cSVille Syrjälä /**
58074c61716cSVille Syrjälä  * drm_format_plane_height - height of the plane given the first plane
58084c61716cSVille Syrjälä  * @height: height of the first plane
58094c61716cSVille Syrjälä  * @format: pixel format
58104c61716cSVille Syrjälä  * @plane: plane index
58114c61716cSVille Syrjälä  *
58124c61716cSVille Syrjälä  * Returns:
58134c61716cSVille Syrjälä  * The height of @plane, given that the height of the first plane is @height.
58144c61716cSVille Syrjälä  */
58154c61716cSVille Syrjälä int drm_format_plane_height(int height, uint32_t format, int plane)
58164c61716cSVille Syrjälä {
58174c61716cSVille Syrjälä 	if (plane >= drm_format_num_planes(format))
58184c61716cSVille Syrjälä 		return 0;
58194c61716cSVille Syrjälä 
58204c61716cSVille Syrjälä 	if (plane == 0)
58214c61716cSVille Syrjälä 		return height;
58224c61716cSVille Syrjälä 
58234c61716cSVille Syrjälä 	return height / drm_format_vert_chroma_subsampling(format);
58244c61716cSVille Syrjälä }
58254c61716cSVille Syrjälä EXPORT_SYMBOL(drm_format_plane_height);
58264c61716cSVille Syrjälä 
58274c61716cSVille Syrjälä /**
58283c9855f6SVille Syrjälä  * drm_rotation_simplify() - Try to simplify the rotation
58293c9855f6SVille Syrjälä  * @rotation: Rotation to be simplified
58303c9855f6SVille Syrjälä  * @supported_rotations: Supported rotations
58313c9855f6SVille Syrjälä  *
58323c9855f6SVille Syrjälä  * Attempt to simplify the rotation to a form that is supported.
58333c9855f6SVille Syrjälä  * Eg. if the hardware supports everything except DRM_REFLECT_X
58343c9855f6SVille Syrjälä  * one could call this function like this:
58353c9855f6SVille Syrjälä  *
58363c9855f6SVille Syrjälä  * drm_rotation_simplify(rotation, BIT(DRM_ROTATE_0) |
58373c9855f6SVille Syrjälä  *                       BIT(DRM_ROTATE_90) | BIT(DRM_ROTATE_180) |
58383c9855f6SVille Syrjälä  *                       BIT(DRM_ROTATE_270) | BIT(DRM_REFLECT_Y));
58393c9855f6SVille Syrjälä  *
58403c9855f6SVille Syrjälä  * to eliminate the DRM_ROTATE_X flag. Depending on what kind of
58413c9855f6SVille Syrjälä  * transforms the hardware supports, this function may not
58423c9855f6SVille Syrjälä  * be able to produce a supported transform, so the caller should
58433c9855f6SVille Syrjälä  * check the result afterwards.
58443c9855f6SVille Syrjälä  */
58453c9855f6SVille Syrjälä unsigned int drm_rotation_simplify(unsigned int rotation,
58463c9855f6SVille Syrjälä 				   unsigned int supported_rotations)
58473c9855f6SVille Syrjälä {
58483c9855f6SVille Syrjälä 	if (rotation & ~supported_rotations) {
58493c9855f6SVille Syrjälä 		rotation ^= BIT(DRM_REFLECT_X) | BIT(DRM_REFLECT_Y);
585014152c8dSJoonas Lahtinen 		rotation = (rotation & DRM_REFLECT_MASK) |
585114152c8dSJoonas Lahtinen 		           BIT((ffs(rotation & DRM_ROTATE_MASK) + 1) % 4);
58523c9855f6SVille Syrjälä 	}
58533c9855f6SVille Syrjälä 
58543c9855f6SVille Syrjälä 	return rotation;
58553c9855f6SVille Syrjälä }
58563c9855f6SVille Syrjälä EXPORT_SYMBOL(drm_rotation_simplify);
58573c9855f6SVille Syrjälä 
58583c9855f6SVille Syrjälä /**
585987d24fc3SLaurent Pinchart  * drm_mode_config_init - initialize DRM mode_configuration structure
586087d24fc3SLaurent Pinchart  * @dev: DRM device
586187d24fc3SLaurent Pinchart  *
586287d24fc3SLaurent Pinchart  * Initialize @dev's mode_config structure, used for tracking the graphics
586387d24fc3SLaurent Pinchart  * configuration of @dev.
586487d24fc3SLaurent Pinchart  *
586587d24fc3SLaurent Pinchart  * Since this initializes the modeset locks, no locking is possible. Which is no
586687d24fc3SLaurent Pinchart  * problem, since this should happen single threaded at init time. It is the
586787d24fc3SLaurent Pinchart  * driver's problem to ensure this guarantee.
586887d24fc3SLaurent Pinchart  *
586987d24fc3SLaurent Pinchart  */
587087d24fc3SLaurent Pinchart void drm_mode_config_init(struct drm_device *dev)
587187d24fc3SLaurent Pinchart {
587287d24fc3SLaurent Pinchart 	mutex_init(&dev->mode_config.mutex);
587351fd371bSRob Clark 	drm_modeset_lock_init(&dev->mode_config.connection_mutex);
587487d24fc3SLaurent Pinchart 	mutex_init(&dev->mode_config.idr_mutex);
587587d24fc3SLaurent Pinchart 	mutex_init(&dev->mode_config.fb_lock);
58768fb6e7a5SDaniel Stone 	mutex_init(&dev->mode_config.blob_lock);
587787d24fc3SLaurent Pinchart 	INIT_LIST_HEAD(&dev->mode_config.fb_list);
587887d24fc3SLaurent Pinchart 	INIT_LIST_HEAD(&dev->mode_config.crtc_list);
587987d24fc3SLaurent Pinchart 	INIT_LIST_HEAD(&dev->mode_config.connector_list);
588087d24fc3SLaurent Pinchart 	INIT_LIST_HEAD(&dev->mode_config.encoder_list);
588187d24fc3SLaurent Pinchart 	INIT_LIST_HEAD(&dev->mode_config.property_list);
588287d24fc3SLaurent Pinchart 	INIT_LIST_HEAD(&dev->mode_config.property_blob_list);
588387d24fc3SLaurent Pinchart 	INIT_LIST_HEAD(&dev->mode_config.plane_list);
588487d24fc3SLaurent Pinchart 	idr_init(&dev->mode_config.crtc_idr);
5885138f9ebbSDave Airlie 	idr_init(&dev->mode_config.tile_idr);
58865fff80bbSMaarten Lankhorst 	ida_init(&dev->mode_config.connector_ida);
588787d24fc3SLaurent Pinchart 
588887d24fc3SLaurent Pinchart 	drm_modeset_lock_all(dev);
58896b4959f4SRob Clark 	drm_mode_create_standard_properties(dev);
589087d24fc3SLaurent Pinchart 	drm_modeset_unlock_all(dev);
589187d24fc3SLaurent Pinchart 
589287d24fc3SLaurent Pinchart 	/* Just to be sure */
589387d24fc3SLaurent Pinchart 	dev->mode_config.num_fb = 0;
589487d24fc3SLaurent Pinchart 	dev->mode_config.num_connector = 0;
589587d24fc3SLaurent Pinchart 	dev->mode_config.num_crtc = 0;
589687d24fc3SLaurent Pinchart 	dev->mode_config.num_encoder = 0;
5897e27dde3eSMatt Roper 	dev->mode_config.num_overlay_plane = 0;
5898e27dde3eSMatt Roper 	dev->mode_config.num_total_plane = 0;
589987d24fc3SLaurent Pinchart }
590087d24fc3SLaurent Pinchart EXPORT_SYMBOL(drm_mode_config_init);
590187d24fc3SLaurent Pinchart 
590287d24fc3SLaurent Pinchart /**
590387d24fc3SLaurent Pinchart  * drm_mode_config_cleanup - free up DRM mode_config info
590487d24fc3SLaurent Pinchart  * @dev: DRM device
590587d24fc3SLaurent Pinchart  *
590687d24fc3SLaurent Pinchart  * Free up all the connectors and CRTCs associated with this DRM device, then
590787d24fc3SLaurent Pinchart  * free up the framebuffers and associated buffer objects.
590887d24fc3SLaurent Pinchart  *
590987d24fc3SLaurent Pinchart  * Note that since this /should/ happen single-threaded at driver/device
591087d24fc3SLaurent Pinchart  * teardown time, no locking is required. It's the driver's job to ensure that
591187d24fc3SLaurent Pinchart  * this guarantee actually holds true.
591287d24fc3SLaurent Pinchart  *
591387d24fc3SLaurent Pinchart  * FIXME: cleanup any dangling user buffer objects too
591487d24fc3SLaurent Pinchart  */
591587d24fc3SLaurent Pinchart void drm_mode_config_cleanup(struct drm_device *dev)
591687d24fc3SLaurent Pinchart {
591787d24fc3SLaurent Pinchart 	struct drm_connector *connector, *ot;
591887d24fc3SLaurent Pinchart 	struct drm_crtc *crtc, *ct;
591987d24fc3SLaurent Pinchart 	struct drm_encoder *encoder, *enct;
592087d24fc3SLaurent Pinchart 	struct drm_framebuffer *fb, *fbt;
592187d24fc3SLaurent Pinchart 	struct drm_property *property, *pt;
592287d24fc3SLaurent Pinchart 	struct drm_property_blob *blob, *bt;
592387d24fc3SLaurent Pinchart 	struct drm_plane *plane, *plt;
592487d24fc3SLaurent Pinchart 
592587d24fc3SLaurent Pinchart 	list_for_each_entry_safe(encoder, enct, &dev->mode_config.encoder_list,
592687d24fc3SLaurent Pinchart 				 head) {
592787d24fc3SLaurent Pinchart 		encoder->funcs->destroy(encoder);
592887d24fc3SLaurent Pinchart 	}
592987d24fc3SLaurent Pinchart 
593087d24fc3SLaurent Pinchart 	list_for_each_entry_safe(connector, ot,
593187d24fc3SLaurent Pinchart 				 &dev->mode_config.connector_list, head) {
593287d24fc3SLaurent Pinchart 		connector->funcs->destroy(connector);
593387d24fc3SLaurent Pinchart 	}
593487d24fc3SLaurent Pinchart 
593587d24fc3SLaurent Pinchart 	list_for_each_entry_safe(property, pt, &dev->mode_config.property_list,
593687d24fc3SLaurent Pinchart 				 head) {
593787d24fc3SLaurent Pinchart 		drm_property_destroy(dev, property);
593887d24fc3SLaurent Pinchart 	}
593987d24fc3SLaurent Pinchart 
5940f35034f8SMaarten Lankhorst 	list_for_each_entry_safe(plane, plt, &dev->mode_config.plane_list,
5941f35034f8SMaarten Lankhorst 				 head) {
5942f35034f8SMaarten Lankhorst 		plane->funcs->destroy(plane);
5943f35034f8SMaarten Lankhorst 	}
5944f35034f8SMaarten Lankhorst 
5945f35034f8SMaarten Lankhorst 	list_for_each_entry_safe(crtc, ct, &dev->mode_config.crtc_list, head) {
5946f35034f8SMaarten Lankhorst 		crtc->funcs->destroy(crtc);
5947f35034f8SMaarten Lankhorst 	}
5948f35034f8SMaarten Lankhorst 
594987d24fc3SLaurent Pinchart 	list_for_each_entry_safe(blob, bt, &dev->mode_config.property_blob_list,
5950e2f5d2eaSDaniel Stone 				 head_global) {
59516bcacf51SDaniel Stone 		drm_property_unreference_blob(blob);
595287d24fc3SLaurent Pinchart 	}
595387d24fc3SLaurent Pinchart 
595487d24fc3SLaurent Pinchart 	/*
595587d24fc3SLaurent Pinchart 	 * Single-threaded teardown context, so it's not required to grab the
595687d24fc3SLaurent Pinchart 	 * fb_lock to protect against concurrent fb_list access. Contrary, it
595787d24fc3SLaurent Pinchart 	 * would actually deadlock with the drm_framebuffer_cleanup function.
595887d24fc3SLaurent Pinchart 	 *
595987d24fc3SLaurent Pinchart 	 * Also, if there are any framebuffers left, that's a driver leak now,
596087d24fc3SLaurent Pinchart 	 * so politely WARN about this.
596187d24fc3SLaurent Pinchart 	 */
596287d24fc3SLaurent Pinchart 	WARN_ON(!list_empty(&dev->mode_config.fb_list));
596387d24fc3SLaurent Pinchart 	list_for_each_entry_safe(fb, fbt, &dev->mode_config.fb_list, head) {
5964d0f37cf6SDave Airlie 		drm_framebuffer_free(&fb->base.refcount);
596587d24fc3SLaurent Pinchart 	}
596687d24fc3SLaurent Pinchart 
59675fff80bbSMaarten Lankhorst 	ida_destroy(&dev->mode_config.connector_ida);
5968138f9ebbSDave Airlie 	idr_destroy(&dev->mode_config.tile_idr);
596987d24fc3SLaurent Pinchart 	idr_destroy(&dev->mode_config.crtc_idr);
597051fd371bSRob Clark 	drm_modeset_lock_fini(&dev->mode_config.connection_mutex);
597187d24fc3SLaurent Pinchart }
597287d24fc3SLaurent Pinchart EXPORT_SYMBOL(drm_mode_config_cleanup);
5973c1df5f3cSVille Syrjälä 
5974c1df5f3cSVille Syrjälä struct drm_property *drm_mode_create_rotation_property(struct drm_device *dev,
5975c1df5f3cSVille Syrjälä 						       unsigned int supported_rotations)
5976c1df5f3cSVille Syrjälä {
5977c1df5f3cSVille Syrjälä 	static const struct drm_prop_enum_list props[] = {
5978c1df5f3cSVille Syrjälä 		{ DRM_ROTATE_0,   "rotate-0" },
5979c1df5f3cSVille Syrjälä 		{ DRM_ROTATE_90,  "rotate-90" },
5980c1df5f3cSVille Syrjälä 		{ DRM_ROTATE_180, "rotate-180" },
5981c1df5f3cSVille Syrjälä 		{ DRM_ROTATE_270, "rotate-270" },
5982c1df5f3cSVille Syrjälä 		{ DRM_REFLECT_X,  "reflect-x" },
5983c1df5f3cSVille Syrjälä 		{ DRM_REFLECT_Y,  "reflect-y" },
5984c1df5f3cSVille Syrjälä 	};
5985c1df5f3cSVille Syrjälä 
5986c1df5f3cSVille Syrjälä 	return drm_property_create_bitmask(dev, 0, "rotation",
5987c1df5f3cSVille Syrjälä 					   props, ARRAY_SIZE(props),
5988c1df5f3cSVille Syrjälä 					   supported_rotations);
5989c1df5f3cSVille Syrjälä }
5990c1df5f3cSVille Syrjälä EXPORT_SYMBOL(drm_mode_create_rotation_property);
5991138f9ebbSDave Airlie 
5992138f9ebbSDave Airlie /**
5993138f9ebbSDave Airlie  * DOC: Tile group
5994138f9ebbSDave Airlie  *
5995138f9ebbSDave Airlie  * Tile groups are used to represent tiled monitors with a unique
5996138f9ebbSDave Airlie  * integer identifier. Tiled monitors using DisplayID v1.3 have
5997138f9ebbSDave Airlie  * a unique 8-byte handle, we store this in a tile group, so we
5998138f9ebbSDave Airlie  * have a common identifier for all tiles in a monitor group.
5999138f9ebbSDave Airlie  */
6000138f9ebbSDave Airlie static void drm_tile_group_free(struct kref *kref)
6001138f9ebbSDave Airlie {
6002138f9ebbSDave Airlie 	struct drm_tile_group *tg = container_of(kref, struct drm_tile_group, refcount);
6003138f9ebbSDave Airlie 	struct drm_device *dev = tg->dev;
6004138f9ebbSDave Airlie 	mutex_lock(&dev->mode_config.idr_mutex);
6005138f9ebbSDave Airlie 	idr_remove(&dev->mode_config.tile_idr, tg->id);
6006138f9ebbSDave Airlie 	mutex_unlock(&dev->mode_config.idr_mutex);
6007138f9ebbSDave Airlie 	kfree(tg);
6008138f9ebbSDave Airlie }
6009138f9ebbSDave Airlie 
6010138f9ebbSDave Airlie /**
6011138f9ebbSDave Airlie  * drm_mode_put_tile_group - drop a reference to a tile group.
6012138f9ebbSDave Airlie  * @dev: DRM device
6013138f9ebbSDave Airlie  * @tg: tile group to drop reference to.
6014138f9ebbSDave Airlie  *
6015138f9ebbSDave Airlie  * drop reference to tile group and free if 0.
6016138f9ebbSDave Airlie  */
6017138f9ebbSDave Airlie void drm_mode_put_tile_group(struct drm_device *dev,
6018138f9ebbSDave Airlie 			     struct drm_tile_group *tg)
6019138f9ebbSDave Airlie {
6020138f9ebbSDave Airlie 	kref_put(&tg->refcount, drm_tile_group_free);
6021138f9ebbSDave Airlie }
6022138f9ebbSDave Airlie 
6023138f9ebbSDave Airlie /**
6024138f9ebbSDave Airlie  * drm_mode_get_tile_group - get a reference to an existing tile group
6025138f9ebbSDave Airlie  * @dev: DRM device
6026138f9ebbSDave Airlie  * @topology: 8-bytes unique per monitor.
6027138f9ebbSDave Airlie  *
6028138f9ebbSDave Airlie  * Use the unique bytes to get a reference to an existing tile group.
6029138f9ebbSDave Airlie  *
6030138f9ebbSDave Airlie  * RETURNS:
6031138f9ebbSDave Airlie  * tile group or NULL if not found.
6032138f9ebbSDave Airlie  */
6033138f9ebbSDave Airlie struct drm_tile_group *drm_mode_get_tile_group(struct drm_device *dev,
6034138f9ebbSDave Airlie 					       char topology[8])
6035138f9ebbSDave Airlie {
6036138f9ebbSDave Airlie 	struct drm_tile_group *tg;
6037138f9ebbSDave Airlie 	int id;
6038138f9ebbSDave Airlie 	mutex_lock(&dev->mode_config.idr_mutex);
6039138f9ebbSDave Airlie 	idr_for_each_entry(&dev->mode_config.tile_idr, tg, id) {
6040138f9ebbSDave Airlie 		if (!memcmp(tg->group_data, topology, 8)) {
6041138f9ebbSDave Airlie 			if (!kref_get_unless_zero(&tg->refcount))
6042138f9ebbSDave Airlie 				tg = NULL;
6043138f9ebbSDave Airlie 			mutex_unlock(&dev->mode_config.idr_mutex);
6044138f9ebbSDave Airlie 			return tg;
6045138f9ebbSDave Airlie 		}
6046138f9ebbSDave Airlie 	}
6047138f9ebbSDave Airlie 	mutex_unlock(&dev->mode_config.idr_mutex);
6048138f9ebbSDave Airlie 	return NULL;
6049138f9ebbSDave Airlie }
605081ddd1bcSRob Clark EXPORT_SYMBOL(drm_mode_get_tile_group);
6051138f9ebbSDave Airlie 
6052138f9ebbSDave Airlie /**
6053138f9ebbSDave Airlie  * drm_mode_create_tile_group - create a tile group from a displayid description
6054138f9ebbSDave Airlie  * @dev: DRM device
6055138f9ebbSDave Airlie  * @topology: 8-bytes unique per monitor.
6056138f9ebbSDave Airlie  *
6057138f9ebbSDave Airlie  * Create a tile group for the unique monitor, and get a unique
6058138f9ebbSDave Airlie  * identifier for the tile group.
6059138f9ebbSDave Airlie  *
6060138f9ebbSDave Airlie  * RETURNS:
6061138f9ebbSDave Airlie  * new tile group or error.
6062138f9ebbSDave Airlie  */
6063138f9ebbSDave Airlie struct drm_tile_group *drm_mode_create_tile_group(struct drm_device *dev,
6064138f9ebbSDave Airlie 						  char topology[8])
6065138f9ebbSDave Airlie {
6066138f9ebbSDave Airlie 	struct drm_tile_group *tg;
6067138f9ebbSDave Airlie 	int ret;
6068138f9ebbSDave Airlie 
6069138f9ebbSDave Airlie 	tg = kzalloc(sizeof(*tg), GFP_KERNEL);
6070138f9ebbSDave Airlie 	if (!tg)
6071138f9ebbSDave Airlie 		return ERR_PTR(-ENOMEM);
6072138f9ebbSDave Airlie 
6073138f9ebbSDave Airlie 	kref_init(&tg->refcount);
6074138f9ebbSDave Airlie 	memcpy(tg->group_data, topology, 8);
6075138f9ebbSDave Airlie 	tg->dev = dev;
6076138f9ebbSDave Airlie 
6077138f9ebbSDave Airlie 	mutex_lock(&dev->mode_config.idr_mutex);
6078138f9ebbSDave Airlie 	ret = idr_alloc(&dev->mode_config.tile_idr, tg, 1, 0, GFP_KERNEL);
6079138f9ebbSDave Airlie 	if (ret >= 0) {
6080138f9ebbSDave Airlie 		tg->id = ret;
6081138f9ebbSDave Airlie 	} else {
6082138f9ebbSDave Airlie 		kfree(tg);
6083138f9ebbSDave Airlie 		tg = ERR_PTR(ret);
6084138f9ebbSDave Airlie 	}
6085138f9ebbSDave Airlie 
6086138f9ebbSDave Airlie 	mutex_unlock(&dev->mode_config.idr_mutex);
6087138f9ebbSDave Airlie 	return tg;
6088138f9ebbSDave Airlie }
608981ddd1bcSRob Clark EXPORT_SYMBOL(drm_mode_create_tile_group);
6090