xref: /openbmc/linux/drivers/gpu/drm/drm_crtc.c (revision ad222799)
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>
40f453ba04SDave Airlie 
418bd441b2SDaniel Vetter #include "drm_crtc_internal.h"
428bd441b2SDaniel Vetter 
4384849903SDaniel Vetter /**
4484849903SDaniel Vetter  * drm_modeset_lock_all - take all modeset locks
4584849903SDaniel Vetter  * @dev: drm device
4684849903SDaniel Vetter  *
4784849903SDaniel Vetter  * This function takes all modeset locks, suitable where a more fine-grained
48c8e32cc1SDaniel Vetter  * scheme isn't (yet) implemented. Locks must be dropped with
49c8e32cc1SDaniel Vetter  * drm_modeset_unlock_all.
5084849903SDaniel Vetter  */
5184849903SDaniel Vetter void drm_modeset_lock_all(struct drm_device *dev)
5284849903SDaniel Vetter {
5329494c17SDaniel Vetter 	struct drm_crtc *crtc;
5429494c17SDaniel Vetter 
5584849903SDaniel Vetter 	mutex_lock(&dev->mode_config.mutex);
5629494c17SDaniel Vetter 
5729494c17SDaniel Vetter 	list_for_each_entry(crtc, &dev->mode_config.crtc_list, head)
5829494c17SDaniel Vetter 		mutex_lock_nest_lock(&crtc->mutex, &dev->mode_config.mutex);
5984849903SDaniel Vetter }
6084849903SDaniel Vetter EXPORT_SYMBOL(drm_modeset_lock_all);
6184849903SDaniel Vetter 
6284849903SDaniel Vetter /**
6384849903SDaniel Vetter  * drm_modeset_unlock_all - drop all modeset locks
6484849903SDaniel Vetter  * @dev: device
65c8e32cc1SDaniel Vetter  *
66c8e32cc1SDaniel Vetter  * This function drop all modeset locks taken by drm_modeset_lock_all.
6784849903SDaniel Vetter  */
6884849903SDaniel Vetter void drm_modeset_unlock_all(struct drm_device *dev)
6984849903SDaniel Vetter {
7029494c17SDaniel Vetter 	struct drm_crtc *crtc;
7129494c17SDaniel Vetter 
7229494c17SDaniel Vetter 	list_for_each_entry(crtc, &dev->mode_config.crtc_list, head)
7329494c17SDaniel Vetter 		mutex_unlock(&crtc->mutex);
7429494c17SDaniel Vetter 
7584849903SDaniel Vetter 	mutex_unlock(&dev->mode_config.mutex);
7684849903SDaniel Vetter }
7784849903SDaniel Vetter EXPORT_SYMBOL(drm_modeset_unlock_all);
7884849903SDaniel Vetter 
796aed8ec3SDaniel Vetter /**
806aed8ec3SDaniel Vetter  * drm_warn_on_modeset_not_all_locked - check that all modeset locks are locked
816aed8ec3SDaniel Vetter  * @dev: device
82c8e32cc1SDaniel Vetter  *
83c8e32cc1SDaniel Vetter  * Useful as a debug assert.
846aed8ec3SDaniel Vetter  */
856aed8ec3SDaniel Vetter void drm_warn_on_modeset_not_all_locked(struct drm_device *dev)
866aed8ec3SDaniel Vetter {
876aed8ec3SDaniel Vetter 	struct drm_crtc *crtc;
886aed8ec3SDaniel Vetter 
89a9b054e8SDaniel Vetter 	/* Locking is currently fubar in the panic handler. */
90a9b054e8SDaniel Vetter 	if (oops_in_progress)
91a9b054e8SDaniel Vetter 		return;
92a9b054e8SDaniel Vetter 
936aed8ec3SDaniel Vetter 	list_for_each_entry(crtc, &dev->mode_config.crtc_list, head)
946aed8ec3SDaniel Vetter 		WARN_ON(!mutex_is_locked(&crtc->mutex));
956aed8ec3SDaniel Vetter 
966aed8ec3SDaniel Vetter 	WARN_ON(!mutex_is_locked(&dev->mode_config.mutex));
976aed8ec3SDaniel Vetter }
986aed8ec3SDaniel Vetter EXPORT_SYMBOL(drm_warn_on_modeset_not_all_locked);
996aed8ec3SDaniel Vetter 
100f453ba04SDave Airlie /* Avoid boilerplate.  I'm tired of typing. */
101f453ba04SDave Airlie #define DRM_ENUM_NAME_FN(fnname, list)				\
102d20d3174SVille Syrjälä 	const char *fnname(int val)				\
103f453ba04SDave Airlie 	{							\
104f453ba04SDave Airlie 		int i;						\
105f453ba04SDave Airlie 		for (i = 0; i < ARRAY_SIZE(list); i++) {	\
106f453ba04SDave Airlie 			if (list[i].type == val)		\
107f453ba04SDave Airlie 				return list[i].name;		\
108f453ba04SDave Airlie 		}						\
109f453ba04SDave Airlie 		return "(unknown)";				\
110f453ba04SDave Airlie 	}
111f453ba04SDave Airlie 
112f453ba04SDave Airlie /*
113f453ba04SDave Airlie  * Global properties
114f453ba04SDave Airlie  */
115d20d3174SVille Syrjälä static const struct drm_prop_enum_list drm_dpms_enum_list[] =
116f453ba04SDave Airlie {	{ DRM_MODE_DPMS_ON, "On" },
117f453ba04SDave Airlie 	{ DRM_MODE_DPMS_STANDBY, "Standby" },
118f453ba04SDave Airlie 	{ DRM_MODE_DPMS_SUSPEND, "Suspend" },
119f453ba04SDave Airlie 	{ DRM_MODE_DPMS_OFF, "Off" }
120f453ba04SDave Airlie };
121f453ba04SDave Airlie 
122f453ba04SDave Airlie DRM_ENUM_NAME_FN(drm_get_dpms_name, drm_dpms_enum_list)
123f453ba04SDave Airlie 
1249922ab5aSRob Clark static const struct drm_prop_enum_list drm_plane_type_enum_list[] =
1259922ab5aSRob Clark {
1269922ab5aSRob Clark 	{ DRM_PLANE_TYPE_OVERLAY, "Overlay" },
1279922ab5aSRob Clark 	{ DRM_PLANE_TYPE_PRIMARY, "Primary" },
1289922ab5aSRob Clark 	{ DRM_PLANE_TYPE_CURSOR, "Cursor" },
1299922ab5aSRob Clark };
1309922ab5aSRob Clark 
131f453ba04SDave Airlie /*
132f453ba04SDave Airlie  * Optional properties
133f453ba04SDave Airlie  */
134d20d3174SVille Syrjälä static const struct drm_prop_enum_list drm_scaling_mode_enum_list[] =
135f453ba04SDave Airlie {
13653bd8389SJesse Barnes 	{ DRM_MODE_SCALE_NONE, "None" },
13753bd8389SJesse Barnes 	{ DRM_MODE_SCALE_FULLSCREEN, "Full" },
13853bd8389SJesse Barnes 	{ DRM_MODE_SCALE_CENTER, "Center" },
13953bd8389SJesse Barnes 	{ DRM_MODE_SCALE_ASPECT, "Full aspect" },
140f453ba04SDave Airlie };
141f453ba04SDave Airlie 
142f453ba04SDave Airlie /*
143f453ba04SDave Airlie  * Non-global properties, but "required" for certain connectors.
144f453ba04SDave Airlie  */
145d20d3174SVille Syrjälä static const struct drm_prop_enum_list drm_dvi_i_select_enum_list[] =
146f453ba04SDave Airlie {
147f453ba04SDave Airlie 	{ DRM_MODE_SUBCONNECTOR_Automatic, "Automatic" }, /* DVI-I and TV-out */
148f453ba04SDave Airlie 	{ DRM_MODE_SUBCONNECTOR_DVID,      "DVI-D"     }, /* DVI-I  */
149f453ba04SDave Airlie 	{ DRM_MODE_SUBCONNECTOR_DVIA,      "DVI-A"     }, /* DVI-I  */
150f453ba04SDave Airlie };
151f453ba04SDave Airlie 
152f453ba04SDave Airlie DRM_ENUM_NAME_FN(drm_get_dvi_i_select_name, drm_dvi_i_select_enum_list)
153f453ba04SDave Airlie 
154d20d3174SVille Syrjälä static const struct drm_prop_enum_list drm_dvi_i_subconnector_enum_list[] =
155f453ba04SDave Airlie {
156f453ba04SDave Airlie 	{ DRM_MODE_SUBCONNECTOR_Unknown,   "Unknown"   }, /* DVI-I and TV-out */
157f453ba04SDave Airlie 	{ DRM_MODE_SUBCONNECTOR_DVID,      "DVI-D"     }, /* DVI-I  */
158f453ba04SDave Airlie 	{ DRM_MODE_SUBCONNECTOR_DVIA,      "DVI-A"     }, /* DVI-I  */
159f453ba04SDave Airlie };
160f453ba04SDave Airlie 
161f453ba04SDave Airlie DRM_ENUM_NAME_FN(drm_get_dvi_i_subconnector_name,
162f453ba04SDave Airlie 		 drm_dvi_i_subconnector_enum_list)
163f453ba04SDave Airlie 
164d20d3174SVille Syrjälä static const struct drm_prop_enum_list drm_tv_select_enum_list[] =
165f453ba04SDave Airlie {
166f453ba04SDave Airlie 	{ DRM_MODE_SUBCONNECTOR_Automatic, "Automatic" }, /* DVI-I and TV-out */
167f453ba04SDave Airlie 	{ DRM_MODE_SUBCONNECTOR_Composite, "Composite" }, /* TV-out */
168f453ba04SDave Airlie 	{ DRM_MODE_SUBCONNECTOR_SVIDEO,    "SVIDEO"    }, /* TV-out */
169f453ba04SDave Airlie 	{ DRM_MODE_SUBCONNECTOR_Component, "Component" }, /* TV-out */
170aeaa1ad3SFrancisco Jerez 	{ DRM_MODE_SUBCONNECTOR_SCART,     "SCART"     }, /* TV-out */
171f453ba04SDave Airlie };
172f453ba04SDave Airlie 
173f453ba04SDave Airlie DRM_ENUM_NAME_FN(drm_get_tv_select_name, drm_tv_select_enum_list)
174f453ba04SDave Airlie 
175d20d3174SVille Syrjälä static const struct drm_prop_enum_list drm_tv_subconnector_enum_list[] =
176f453ba04SDave Airlie {
177f453ba04SDave Airlie 	{ DRM_MODE_SUBCONNECTOR_Unknown,   "Unknown"   }, /* DVI-I and TV-out */
178f453ba04SDave Airlie 	{ DRM_MODE_SUBCONNECTOR_Composite, "Composite" }, /* TV-out */
179f453ba04SDave Airlie 	{ DRM_MODE_SUBCONNECTOR_SVIDEO,    "SVIDEO"    }, /* TV-out */
180f453ba04SDave Airlie 	{ DRM_MODE_SUBCONNECTOR_Component, "Component" }, /* TV-out */
181aeaa1ad3SFrancisco Jerez 	{ DRM_MODE_SUBCONNECTOR_SCART,     "SCART"     }, /* TV-out */
182f453ba04SDave Airlie };
183f453ba04SDave Airlie 
184f453ba04SDave Airlie DRM_ENUM_NAME_FN(drm_get_tv_subconnector_name,
185f453ba04SDave Airlie 		 drm_tv_subconnector_enum_list)
186f453ba04SDave Airlie 
187d20d3174SVille Syrjälä static const struct drm_prop_enum_list drm_dirty_info_enum_list[] = {
188884840aaSJakob Bornecrantz 	{ DRM_MODE_DIRTY_OFF,      "Off"      },
189884840aaSJakob Bornecrantz 	{ DRM_MODE_DIRTY_ON,       "On"       },
190884840aaSJakob Bornecrantz 	{ DRM_MODE_DIRTY_ANNOTATE, "Annotate" },
191884840aaSJakob Bornecrantz };
192884840aaSJakob Bornecrantz 
193f453ba04SDave Airlie struct drm_conn_prop_enum_list {
194f453ba04SDave Airlie 	int type;
195d20d3174SVille Syrjälä 	const char *name;
196b21e3afeSIlia Mirkin 	struct ida ida;
197f453ba04SDave Airlie };
198f453ba04SDave Airlie 
199f453ba04SDave Airlie /*
200f453ba04SDave Airlie  * Connector and encoder types.
201f453ba04SDave Airlie  */
202f453ba04SDave Airlie static struct drm_conn_prop_enum_list drm_connector_enum_list[] =
203b21e3afeSIlia Mirkin {	{ DRM_MODE_CONNECTOR_Unknown, "Unknown" },
204b21e3afeSIlia Mirkin 	{ DRM_MODE_CONNECTOR_VGA, "VGA" },
205b21e3afeSIlia Mirkin 	{ DRM_MODE_CONNECTOR_DVII, "DVI-I" },
206b21e3afeSIlia Mirkin 	{ DRM_MODE_CONNECTOR_DVID, "DVI-D" },
207b21e3afeSIlia Mirkin 	{ DRM_MODE_CONNECTOR_DVIA, "DVI-A" },
208b21e3afeSIlia Mirkin 	{ DRM_MODE_CONNECTOR_Composite, "Composite" },
209b21e3afeSIlia Mirkin 	{ DRM_MODE_CONNECTOR_SVIDEO, "SVIDEO" },
210b21e3afeSIlia Mirkin 	{ DRM_MODE_CONNECTOR_LVDS, "LVDS" },
211b21e3afeSIlia Mirkin 	{ DRM_MODE_CONNECTOR_Component, "Component" },
212b21e3afeSIlia Mirkin 	{ DRM_MODE_CONNECTOR_9PinDIN, "DIN" },
213b21e3afeSIlia Mirkin 	{ DRM_MODE_CONNECTOR_DisplayPort, "DP" },
214b21e3afeSIlia Mirkin 	{ DRM_MODE_CONNECTOR_HDMIA, "HDMI-A" },
215b21e3afeSIlia Mirkin 	{ DRM_MODE_CONNECTOR_HDMIB, "HDMI-B" },
216b21e3afeSIlia Mirkin 	{ DRM_MODE_CONNECTOR_TV, "TV" },
217b21e3afeSIlia Mirkin 	{ DRM_MODE_CONNECTOR_eDP, "eDP" },
218b21e3afeSIlia Mirkin 	{ DRM_MODE_CONNECTOR_VIRTUAL, "Virtual" },
219b8923273SShobhit Kumar 	{ DRM_MODE_CONNECTOR_DSI, "DSI" },
220f453ba04SDave Airlie };
221f453ba04SDave Airlie 
222d20d3174SVille Syrjälä static const struct drm_prop_enum_list drm_encoder_enum_list[] =
223f453ba04SDave Airlie {	{ DRM_MODE_ENCODER_NONE, "None" },
224f453ba04SDave Airlie 	{ DRM_MODE_ENCODER_DAC, "DAC" },
225f453ba04SDave Airlie 	{ DRM_MODE_ENCODER_TMDS, "TMDS" },
226f453ba04SDave Airlie 	{ DRM_MODE_ENCODER_LVDS, "LVDS" },
227f453ba04SDave Airlie 	{ DRM_MODE_ENCODER_TVDAC, "TV" },
228a7331e5cSThomas Hellstrom 	{ DRM_MODE_ENCODER_VIRTUAL, "Virtual" },
229b8923273SShobhit Kumar 	{ DRM_MODE_ENCODER_DSI, "DSI" },
230f453ba04SDave Airlie };
231f453ba04SDave Airlie 
232ac1bb36cSJesse Barnes static const struct drm_prop_enum_list drm_subpixel_enum_list[] =
233ac1bb36cSJesse Barnes {
234ac1bb36cSJesse Barnes 	{ SubPixelUnknown, "Unknown" },
235ac1bb36cSJesse Barnes 	{ SubPixelHorizontalRGB, "Horizontal RGB" },
236ac1bb36cSJesse Barnes 	{ SubPixelHorizontalBGR, "Horizontal BGR" },
237ac1bb36cSJesse Barnes 	{ SubPixelVerticalRGB, "Vertical RGB" },
238ac1bb36cSJesse Barnes 	{ SubPixelVerticalBGR, "Vertical BGR" },
239ac1bb36cSJesse Barnes 	{ SubPixelNone, "None" },
240ac1bb36cSJesse Barnes };
241ac1bb36cSJesse Barnes 
242b21e3afeSIlia Mirkin void drm_connector_ida_init(void)
243b21e3afeSIlia Mirkin {
244b21e3afeSIlia Mirkin 	int i;
245b21e3afeSIlia Mirkin 
246b21e3afeSIlia Mirkin 	for (i = 0; i < ARRAY_SIZE(drm_connector_enum_list); i++)
247b21e3afeSIlia Mirkin 		ida_init(&drm_connector_enum_list[i].ida);
248b21e3afeSIlia Mirkin }
249b21e3afeSIlia Mirkin 
250b21e3afeSIlia Mirkin void drm_connector_ida_destroy(void)
251b21e3afeSIlia Mirkin {
252b21e3afeSIlia Mirkin 	int i;
253b21e3afeSIlia Mirkin 
254b21e3afeSIlia Mirkin 	for (i = 0; i < ARRAY_SIZE(drm_connector_enum_list); i++)
255b21e3afeSIlia Mirkin 		ida_destroy(&drm_connector_enum_list[i].ida);
256b21e3afeSIlia Mirkin }
257b21e3afeSIlia Mirkin 
258c8e32cc1SDaniel Vetter /**
259c8e32cc1SDaniel Vetter  * drm_get_encoder_name - return a string for encoder
260c8e32cc1SDaniel Vetter  * @encoder: encoder to compute name of
261c8e32cc1SDaniel Vetter  *
262c8e32cc1SDaniel Vetter  * Note that the buffer used by this function is globally shared and owned by
263c8e32cc1SDaniel Vetter  * the function itself.
264c8e32cc1SDaniel Vetter  *
265c8e32cc1SDaniel Vetter  * FIXME: This isn't really multithreading safe.
266c8e32cc1SDaniel Vetter  */
267d20d3174SVille Syrjälä const char *drm_get_encoder_name(const struct drm_encoder *encoder)
268f453ba04SDave Airlie {
269f453ba04SDave Airlie 	static char buf[32];
270f453ba04SDave Airlie 
271f453ba04SDave Airlie 	snprintf(buf, 32, "%s-%d",
272f453ba04SDave Airlie 		 drm_encoder_enum_list[encoder->encoder_type].name,
273f453ba04SDave Airlie 		 encoder->base.id);
274f453ba04SDave Airlie 	return buf;
275f453ba04SDave Airlie }
27613a8195bSDave Airlie EXPORT_SYMBOL(drm_get_encoder_name);
277f453ba04SDave Airlie 
278c8e32cc1SDaniel Vetter /**
279c8e32cc1SDaniel Vetter  * drm_get_connector_name - return a string for connector
280c8e32cc1SDaniel Vetter  * @connector: connector to compute name of
281c8e32cc1SDaniel Vetter  *
282c8e32cc1SDaniel Vetter  * Note that the buffer used by this function is globally shared and owned by
283c8e32cc1SDaniel Vetter  * the function itself.
284c8e32cc1SDaniel Vetter  *
285c8e32cc1SDaniel Vetter  * FIXME: This isn't really multithreading safe.
286c8e32cc1SDaniel Vetter  */
287d20d3174SVille Syrjälä const char *drm_get_connector_name(const struct drm_connector *connector)
288f453ba04SDave Airlie {
289f453ba04SDave Airlie 	static char buf[32];
290f453ba04SDave Airlie 
291f453ba04SDave Airlie 	snprintf(buf, 32, "%s-%d",
292f453ba04SDave Airlie 		 drm_connector_enum_list[connector->connector_type].name,
293f453ba04SDave Airlie 		 connector->connector_type_id);
294f453ba04SDave Airlie 	return buf;
295f453ba04SDave Airlie }
296f453ba04SDave Airlie EXPORT_SYMBOL(drm_get_connector_name);
297f453ba04SDave Airlie 
298c8e32cc1SDaniel Vetter /**
299c8e32cc1SDaniel Vetter  * drm_get_connector_status_name - return a string for connector status
300c8e32cc1SDaniel Vetter  * @status: connector status to compute name of
301c8e32cc1SDaniel Vetter  *
302c8e32cc1SDaniel Vetter  * In contrast to the other drm_get_*_name functions this one here returns a
303c8e32cc1SDaniel Vetter  * const pointer and hence is threadsafe.
304c8e32cc1SDaniel Vetter  */
305d20d3174SVille Syrjälä const char *drm_get_connector_status_name(enum drm_connector_status status)
306f453ba04SDave Airlie {
307f453ba04SDave Airlie 	if (status == connector_status_connected)
308f453ba04SDave Airlie 		return "connected";
309f453ba04SDave Airlie 	else if (status == connector_status_disconnected)
310f453ba04SDave Airlie 		return "disconnected";
311f453ba04SDave Airlie 	else
312f453ba04SDave Airlie 		return "unknown";
313f453ba04SDave Airlie }
314ed7951dcSLespiau, Damien EXPORT_SYMBOL(drm_get_connector_status_name);
315f453ba04SDave Airlie 
316ac1bb36cSJesse Barnes /**
317ac1bb36cSJesse Barnes  * drm_get_subpixel_order_name - return a string for a given subpixel enum
318ac1bb36cSJesse Barnes  * @order: enum of subpixel_order
319ac1bb36cSJesse Barnes  *
320ac1bb36cSJesse Barnes  * Note you could abuse this and return something out of bounds, but that
321ac1bb36cSJesse Barnes  * would be a caller error.  No unscrubbed user data should make it here.
322ac1bb36cSJesse Barnes  */
323ac1bb36cSJesse Barnes const char *drm_get_subpixel_order_name(enum subpixel_order order)
324ac1bb36cSJesse Barnes {
325ac1bb36cSJesse Barnes 	return drm_subpixel_enum_list[order].name;
326ac1bb36cSJesse Barnes }
327ac1bb36cSJesse Barnes EXPORT_SYMBOL(drm_get_subpixel_order_name);
328ac1bb36cSJesse Barnes 
3296ba6d03eSVille Syrjälä static char printable_char(int c)
3306ba6d03eSVille Syrjälä {
3316ba6d03eSVille Syrjälä 	return isascii(c) && isprint(c) ? c : '?';
3326ba6d03eSVille Syrjälä }
3336ba6d03eSVille Syrjälä 
334c8e32cc1SDaniel Vetter /**
335c8e32cc1SDaniel Vetter  * drm_get_format_name - return a string for drm fourcc format
336c8e32cc1SDaniel Vetter  * @format: format to compute name of
337c8e32cc1SDaniel Vetter  *
338c8e32cc1SDaniel Vetter  * Note that the buffer used by this function is globally shared and owned by
339c8e32cc1SDaniel Vetter  * the function itself.
340c8e32cc1SDaniel Vetter  *
341c8e32cc1SDaniel Vetter  * FIXME: This isn't really multithreading safe.
342c8e32cc1SDaniel Vetter  */
343d20d3174SVille Syrjälä const char *drm_get_format_name(uint32_t format)
3446ba6d03eSVille Syrjälä {
3456ba6d03eSVille Syrjälä 	static char buf[32];
3466ba6d03eSVille Syrjälä 
3476ba6d03eSVille Syrjälä 	snprintf(buf, sizeof(buf),
3486ba6d03eSVille Syrjälä 		 "%c%c%c%c %s-endian (0x%08x)",
3496ba6d03eSVille Syrjälä 		 printable_char(format & 0xff),
3506ba6d03eSVille Syrjälä 		 printable_char((format >> 8) & 0xff),
3516ba6d03eSVille Syrjälä 		 printable_char((format >> 16) & 0xff),
3526ba6d03eSVille Syrjälä 		 printable_char((format >> 24) & 0x7f),
3536ba6d03eSVille Syrjälä 		 format & DRM_FORMAT_BIG_ENDIAN ? "big" : "little",
3546ba6d03eSVille Syrjälä 		 format);
3556ba6d03eSVille Syrjälä 
3566ba6d03eSVille Syrjälä 	return buf;
3576ba6d03eSVille Syrjälä }
3586ba6d03eSVille Syrjälä EXPORT_SYMBOL(drm_get_format_name);
3596ba6d03eSVille Syrjälä 
360f453ba04SDave Airlie /**
361065a50edSDaniel Vetter  * drm_mode_object_get - allocate a new modeset identifier
362f453ba04SDave Airlie  * @dev: DRM device
363065a50edSDaniel Vetter  * @obj: object pointer, used to generate unique ID
364065a50edSDaniel Vetter  * @obj_type: object type
365f453ba04SDave Airlie  *
366f453ba04SDave Airlie  * Create a unique identifier based on @ptr in @dev's identifier space.  Used
367c8e32cc1SDaniel Vetter  * for tracking modes, CRTCs and connectors. Note that despite the _get postfix
368c8e32cc1SDaniel Vetter  * modeset identifiers are _not_ reference counted. Hence don't use this for
369c8e32cc1SDaniel Vetter  * reference counted modeset objects like framebuffers.
370f453ba04SDave Airlie  *
371c8e32cc1SDaniel Vetter  * Returns:
372f453ba04SDave Airlie  * New unique (relative to other objects in @dev) integer identifier for the
373f453ba04SDave Airlie  * object.
374f453ba04SDave Airlie  */
3758bd441b2SDaniel Vetter int drm_mode_object_get(struct drm_device *dev,
376f453ba04SDave Airlie 			struct drm_mode_object *obj, uint32_t obj_type)
377f453ba04SDave Airlie {
378f453ba04SDave Airlie 	int ret;
379f453ba04SDave Airlie 
380ad2563c2SJesse Barnes 	mutex_lock(&dev->mode_config.idr_mutex);
3812e928815STejun Heo 	ret = idr_alloc(&dev->mode_config.crtc_idr, obj, 1, 0, GFP_KERNEL);
3822e928815STejun Heo 	if (ret >= 0) {
3834b096ac1SDaniel Vetter 		/*
3844b096ac1SDaniel Vetter 		 * Set up the object linking under the protection of the idr
3854b096ac1SDaniel Vetter 		 * lock so that other users can't see inconsistent state.
3864b096ac1SDaniel Vetter 		 */
3872e928815STejun Heo 		obj->id = ret;
388f453ba04SDave Airlie 		obj->type = obj_type;
3894b096ac1SDaniel Vetter 	}
3904b096ac1SDaniel Vetter 	mutex_unlock(&dev->mode_config.idr_mutex);
3914b096ac1SDaniel Vetter 
3922e928815STejun Heo 	return ret < 0 ? ret : 0;
393f453ba04SDave Airlie }
394f453ba04SDave Airlie 
395f453ba04SDave Airlie /**
396065a50edSDaniel Vetter  * drm_mode_object_put - free a modeset identifer
397f453ba04SDave Airlie  * @dev: DRM device
398065a50edSDaniel Vetter  * @object: object to free
399f453ba04SDave Airlie  *
400c8e32cc1SDaniel Vetter  * Free @id from @dev's unique identifier pool. Note that despite the _get
401c8e32cc1SDaniel Vetter  * postfix modeset identifiers are _not_ reference counted. Hence don't use this
402c8e32cc1SDaniel Vetter  * for reference counted modeset objects like framebuffers.
403f453ba04SDave Airlie  */
4048bd441b2SDaniel Vetter void drm_mode_object_put(struct drm_device *dev,
405f453ba04SDave Airlie 			 struct drm_mode_object *object)
406f453ba04SDave Airlie {
407ad2563c2SJesse Barnes 	mutex_lock(&dev->mode_config.idr_mutex);
408f453ba04SDave Airlie 	idr_remove(&dev->mode_config.crtc_idr, object->id);
409ad2563c2SJesse Barnes 	mutex_unlock(&dev->mode_config.idr_mutex);
410f453ba04SDave Airlie }
411f453ba04SDave Airlie 
412786b99edSDaniel Vetter /**
413786b99edSDaniel Vetter  * drm_mode_object_find - look up a drm object with static lifetime
414786b99edSDaniel Vetter  * @dev: drm device
415786b99edSDaniel Vetter  * @id: id of the mode object
416786b99edSDaniel Vetter  * @type: type of the mode object
417786b99edSDaniel Vetter  *
418786b99edSDaniel Vetter  * Note that framebuffers cannot be looked up with this functions - since those
419786b99edSDaniel Vetter  * are reference counted, they need special treatment.
420786b99edSDaniel Vetter  */
4217a9c9060SDaniel Vetter struct drm_mode_object *drm_mode_object_find(struct drm_device *dev,
4227a9c9060SDaniel Vetter 		uint32_t id, uint32_t type)
423f453ba04SDave Airlie {
424ad2563c2SJesse Barnes 	struct drm_mode_object *obj = NULL;
425f453ba04SDave Airlie 
426786b99edSDaniel Vetter 	/* Framebuffers are reference counted and need their own lookup
427786b99edSDaniel Vetter 	 * function.*/
428786b99edSDaniel Vetter 	WARN_ON(type == DRM_MODE_OBJECT_FB);
429786b99edSDaniel Vetter 
430ad2563c2SJesse Barnes 	mutex_lock(&dev->mode_config.idr_mutex);
431f453ba04SDave Airlie 	obj = idr_find(&dev->mode_config.crtc_idr, id);
432f453ba04SDave Airlie 	if (!obj || (obj->type != type) || (obj->id != id))
433ad2563c2SJesse Barnes 		obj = NULL;
434ad2563c2SJesse Barnes 	mutex_unlock(&dev->mode_config.idr_mutex);
435f453ba04SDave Airlie 
436f453ba04SDave Airlie 	return obj;
437f453ba04SDave Airlie }
438f453ba04SDave Airlie EXPORT_SYMBOL(drm_mode_object_find);
439f453ba04SDave Airlie 
440f453ba04SDave Airlie /**
441f453ba04SDave Airlie  * drm_framebuffer_init - initialize a framebuffer
442f453ba04SDave Airlie  * @dev: DRM device
443065a50edSDaniel Vetter  * @fb: framebuffer to be initialized
444065a50edSDaniel Vetter  * @funcs: ... with these functions
445f453ba04SDave Airlie  *
446f453ba04SDave Airlie  * Allocates an ID for the framebuffer's parent mode object, sets its mode
447f453ba04SDave Airlie  * functions & device file and adds it to the master fd list.
448f453ba04SDave Airlie  *
4494b096ac1SDaniel Vetter  * IMPORTANT:
4504b096ac1SDaniel Vetter  * This functions publishes the fb and makes it available for concurrent access
4514b096ac1SDaniel Vetter  * by other users. Which means by this point the fb _must_ be fully set up -
4524b096ac1SDaniel Vetter  * since all the fb attributes are invariant over its lifetime, no further
4534b096ac1SDaniel Vetter  * locking but only correct reference counting is required.
4544b096ac1SDaniel Vetter  *
455c8e32cc1SDaniel Vetter  * Returns:
456af901ca1SAndré Goddard Rosa  * Zero on success, error code on failure.
457f453ba04SDave Airlie  */
458f453ba04SDave Airlie int drm_framebuffer_init(struct drm_device *dev, struct drm_framebuffer *fb,
459f453ba04SDave Airlie 			 const struct drm_framebuffer_funcs *funcs)
460f453ba04SDave Airlie {
461f453ba04SDave Airlie 	int ret;
462f453ba04SDave Airlie 
4634b096ac1SDaniel Vetter 	mutex_lock(&dev->mode_config.fb_lock);
464f7eff60eSRob Clark 	kref_init(&fb->refcount);
4654b096ac1SDaniel Vetter 	INIT_LIST_HEAD(&fb->filp_head);
4664b096ac1SDaniel Vetter 	fb->dev = dev;
4674b096ac1SDaniel Vetter 	fb->funcs = funcs;
468f7eff60eSRob Clark 
469f453ba04SDave Airlie 	ret = drm_mode_object_get(dev, &fb->base, DRM_MODE_OBJECT_FB);
4706bfc56aaSVille Syrjälä 	if (ret)
4714b096ac1SDaniel Vetter 		goto out;
472f453ba04SDave Airlie 
4732b677e8cSDaniel Vetter 	/* Grab the idr reference. */
4742b677e8cSDaniel Vetter 	drm_framebuffer_reference(fb);
4752b677e8cSDaniel Vetter 
476f453ba04SDave Airlie 	dev->mode_config.num_fb++;
477f453ba04SDave Airlie 	list_add(&fb->head, &dev->mode_config.fb_list);
4784b096ac1SDaniel Vetter out:
4794b096ac1SDaniel Vetter 	mutex_unlock(&dev->mode_config.fb_lock);
480f453ba04SDave Airlie 
481f453ba04SDave Airlie 	return 0;
482f453ba04SDave Airlie }
483f453ba04SDave Airlie EXPORT_SYMBOL(drm_framebuffer_init);
484f453ba04SDave Airlie 
485f7eff60eSRob Clark static void drm_framebuffer_free(struct kref *kref)
486f7eff60eSRob Clark {
487f7eff60eSRob Clark 	struct drm_framebuffer *fb =
488f7eff60eSRob Clark 			container_of(kref, struct drm_framebuffer, refcount);
489f7eff60eSRob Clark 	fb->funcs->destroy(fb);
490f7eff60eSRob Clark }
491f7eff60eSRob Clark 
4922b677e8cSDaniel Vetter static struct drm_framebuffer *__drm_framebuffer_lookup(struct drm_device *dev,
4932b677e8cSDaniel Vetter 							uint32_t id)
4942b677e8cSDaniel Vetter {
4952b677e8cSDaniel Vetter 	struct drm_mode_object *obj = NULL;
4962b677e8cSDaniel Vetter 	struct drm_framebuffer *fb;
4972b677e8cSDaniel Vetter 
4982b677e8cSDaniel Vetter 	mutex_lock(&dev->mode_config.idr_mutex);
4992b677e8cSDaniel Vetter 	obj = idr_find(&dev->mode_config.crtc_idr, id);
5002b677e8cSDaniel Vetter 	if (!obj || (obj->type != DRM_MODE_OBJECT_FB) || (obj->id != id))
5012b677e8cSDaniel Vetter 		fb = NULL;
5022b677e8cSDaniel Vetter 	else
5032b677e8cSDaniel Vetter 		fb = obj_to_fb(obj);
5042b677e8cSDaniel Vetter 	mutex_unlock(&dev->mode_config.idr_mutex);
5052b677e8cSDaniel Vetter 
5062b677e8cSDaniel Vetter 	return fb;
5072b677e8cSDaniel Vetter }
5082b677e8cSDaniel Vetter 
509f7eff60eSRob Clark /**
510786b99edSDaniel Vetter  * drm_framebuffer_lookup - look up a drm framebuffer and grab a reference
511786b99edSDaniel Vetter  * @dev: drm device
512786b99edSDaniel Vetter  * @id: id of the fb object
513786b99edSDaniel Vetter  *
514786b99edSDaniel Vetter  * If successful, this grabs an additional reference to the framebuffer -
515786b99edSDaniel Vetter  * callers need to make sure to eventually unreference the returned framebuffer
516c8e32cc1SDaniel Vetter  * again, using @drm_framebuffer_unreference.
517786b99edSDaniel Vetter  */
518786b99edSDaniel Vetter struct drm_framebuffer *drm_framebuffer_lookup(struct drm_device *dev,
519786b99edSDaniel Vetter 					       uint32_t id)
520786b99edSDaniel Vetter {
521786b99edSDaniel Vetter 	struct drm_framebuffer *fb;
522786b99edSDaniel Vetter 
523786b99edSDaniel Vetter 	mutex_lock(&dev->mode_config.fb_lock);
5242b677e8cSDaniel Vetter 	fb = __drm_framebuffer_lookup(dev, id);
525786b99edSDaniel Vetter 	if (fb)
5269131d3d8Sarchit taneja 		drm_framebuffer_reference(fb);
527786b99edSDaniel Vetter 	mutex_unlock(&dev->mode_config.fb_lock);
528786b99edSDaniel Vetter 
529786b99edSDaniel Vetter 	return fb;
530786b99edSDaniel Vetter }
531786b99edSDaniel Vetter EXPORT_SYMBOL(drm_framebuffer_lookup);
532786b99edSDaniel Vetter 
533786b99edSDaniel Vetter /**
534f7eff60eSRob Clark  * drm_framebuffer_unreference - unref a framebuffer
535065a50edSDaniel Vetter  * @fb: framebuffer to unref
536065a50edSDaniel Vetter  *
537065a50edSDaniel Vetter  * This functions decrements the fb's refcount and frees it if it drops to zero.
538f7eff60eSRob Clark  */
539f7eff60eSRob Clark void drm_framebuffer_unreference(struct drm_framebuffer *fb)
540f7eff60eSRob Clark {
541f7eff60eSRob Clark 	DRM_DEBUG("FB ID: %d\n", fb->base.id);
542f7eff60eSRob Clark 	kref_put(&fb->refcount, drm_framebuffer_free);
543f7eff60eSRob Clark }
544f7eff60eSRob Clark EXPORT_SYMBOL(drm_framebuffer_unreference);
545f7eff60eSRob Clark 
546f7eff60eSRob Clark /**
547f7eff60eSRob Clark  * drm_framebuffer_reference - incr the fb refcnt
548065a50edSDaniel Vetter  * @fb: framebuffer
549c8e32cc1SDaniel Vetter  *
550c8e32cc1SDaniel Vetter  * This functions increments the fb's refcount.
551f7eff60eSRob Clark  */
552f7eff60eSRob Clark void drm_framebuffer_reference(struct drm_framebuffer *fb)
553f7eff60eSRob Clark {
554f7eff60eSRob Clark 	DRM_DEBUG("FB ID: %d\n", fb->base.id);
555f7eff60eSRob Clark 	kref_get(&fb->refcount);
556f7eff60eSRob Clark }
557f7eff60eSRob Clark EXPORT_SYMBOL(drm_framebuffer_reference);
558f7eff60eSRob Clark 
5592b677e8cSDaniel Vetter static void drm_framebuffer_free_bug(struct kref *kref)
5602b677e8cSDaniel Vetter {
5612b677e8cSDaniel Vetter 	BUG();
5622b677e8cSDaniel Vetter }
5632b677e8cSDaniel Vetter 
5646c2a7532SDaniel Vetter static void __drm_framebuffer_unreference(struct drm_framebuffer *fb)
5656c2a7532SDaniel Vetter {
5666c2a7532SDaniel Vetter 	DRM_DEBUG("FB ID: %d\n", fb->base.id);
5676c2a7532SDaniel Vetter 	kref_put(&fb->refcount, drm_framebuffer_free_bug);
5686c2a7532SDaniel Vetter }
5696c2a7532SDaniel Vetter 
5702b677e8cSDaniel Vetter /* dev->mode_config.fb_lock must be held! */
5712b677e8cSDaniel Vetter static void __drm_framebuffer_unregister(struct drm_device *dev,
5722b677e8cSDaniel Vetter 					 struct drm_framebuffer *fb)
5732b677e8cSDaniel Vetter {
5742b677e8cSDaniel Vetter 	mutex_lock(&dev->mode_config.idr_mutex);
5752b677e8cSDaniel Vetter 	idr_remove(&dev->mode_config.crtc_idr, fb->base.id);
5762b677e8cSDaniel Vetter 	mutex_unlock(&dev->mode_config.idr_mutex);
5772b677e8cSDaniel Vetter 
5782b677e8cSDaniel Vetter 	fb->base.id = 0;
5792b677e8cSDaniel Vetter 
5806c2a7532SDaniel Vetter 	__drm_framebuffer_unreference(fb);
5812b677e8cSDaniel Vetter }
5822b677e8cSDaniel Vetter 
583f453ba04SDave Airlie /**
58436206361SDaniel Vetter  * drm_framebuffer_unregister_private - unregister a private fb from the lookup idr
58536206361SDaniel Vetter  * @fb: fb to unregister
58636206361SDaniel Vetter  *
58736206361SDaniel Vetter  * Drivers need to call this when cleaning up driver-private framebuffers, e.g.
58836206361SDaniel Vetter  * those used for fbdev. Note that the caller must hold a reference of it's own,
58936206361SDaniel Vetter  * i.e. the object may not be destroyed through this call (since it'll lead to a
59036206361SDaniel Vetter  * locking inversion).
59136206361SDaniel Vetter  */
59236206361SDaniel Vetter void drm_framebuffer_unregister_private(struct drm_framebuffer *fb)
59336206361SDaniel Vetter {
5942b677e8cSDaniel Vetter 	struct drm_device *dev = fb->dev;
5952b677e8cSDaniel Vetter 
5962b677e8cSDaniel Vetter 	mutex_lock(&dev->mode_config.fb_lock);
5972b677e8cSDaniel Vetter 	/* Mark fb as reaped and drop idr ref. */
5982b677e8cSDaniel Vetter 	__drm_framebuffer_unregister(dev, fb);
5992b677e8cSDaniel Vetter 	mutex_unlock(&dev->mode_config.fb_lock);
60036206361SDaniel Vetter }
60136206361SDaniel Vetter EXPORT_SYMBOL(drm_framebuffer_unregister_private);
60236206361SDaniel Vetter 
60336206361SDaniel Vetter /**
604f453ba04SDave Airlie  * drm_framebuffer_cleanup - remove a framebuffer object
605f453ba04SDave Airlie  * @fb: framebuffer to remove
606f453ba04SDave Airlie  *
607c8e32cc1SDaniel Vetter  * Cleanup framebuffer. This function is intended to be used from the drivers
608c8e32cc1SDaniel Vetter  * ->destroy callback. It can also be used to clean up driver private
609c8e32cc1SDaniel Vetter  *  framebuffers embedded into a larger structure.
61036206361SDaniel Vetter  *
61136206361SDaniel Vetter  * Note that this function does not remove the fb from active usuage - if it is
61236206361SDaniel Vetter  * still used anywhere, hilarity can ensue since userspace could call getfb on
61336206361SDaniel Vetter  * the id and get back -EINVAL. Obviously no concern at driver unload time.
61436206361SDaniel Vetter  *
61536206361SDaniel Vetter  * Also, the framebuffer will not be removed from the lookup idr - for
61636206361SDaniel Vetter  * user-created framebuffers this will happen in in the rmfb ioctl. For
61736206361SDaniel Vetter  * driver-private objects (e.g. for fbdev) drivers need to explicitly call
61836206361SDaniel Vetter  * drm_framebuffer_unregister_private.
619f453ba04SDave Airlie  */
620f453ba04SDave Airlie void drm_framebuffer_cleanup(struct drm_framebuffer *fb)
621f453ba04SDave Airlie {
622f453ba04SDave Airlie 	struct drm_device *dev = fb->dev;
6238faf6b18SDaniel Vetter 
6244b096ac1SDaniel Vetter 	mutex_lock(&dev->mode_config.fb_lock);
625f7eff60eSRob Clark 	list_del(&fb->head);
626f7eff60eSRob Clark 	dev->mode_config.num_fb--;
6274b096ac1SDaniel Vetter 	mutex_unlock(&dev->mode_config.fb_lock);
628f7eff60eSRob Clark }
629f7eff60eSRob Clark EXPORT_SYMBOL(drm_framebuffer_cleanup);
630f7eff60eSRob Clark 
631f7eff60eSRob Clark /**
632f7eff60eSRob Clark  * drm_framebuffer_remove - remove and unreference a framebuffer object
633f7eff60eSRob Clark  * @fb: framebuffer to remove
634f7eff60eSRob Clark  *
635f7eff60eSRob Clark  * Scans all the CRTCs and planes in @dev's mode_config.  If they're
63636206361SDaniel Vetter  * using @fb, removes it, setting it to NULL. Then drops the reference to the
637b62584e3SDaniel Vetter  * passed-in framebuffer. Might take the modeset locks.
638b62584e3SDaniel Vetter  *
639b62584e3SDaniel Vetter  * Note that this function optimizes the cleanup away if the caller holds the
640b62584e3SDaniel Vetter  * last reference to the framebuffer. It is also guaranteed to not take the
641b62584e3SDaniel Vetter  * modeset locks in this case.
642f7eff60eSRob Clark  */
643f7eff60eSRob Clark void drm_framebuffer_remove(struct drm_framebuffer *fb)
644f7eff60eSRob Clark {
645f7eff60eSRob Clark 	struct drm_device *dev = fb->dev;
646f453ba04SDave Airlie 	struct drm_crtc *crtc;
6478cf5c917SJesse Barnes 	struct drm_plane *plane;
6485ef5f72fSDave Airlie 	struct drm_mode_set set;
6495ef5f72fSDave Airlie 	int ret;
650f453ba04SDave Airlie 
6514b096ac1SDaniel Vetter 	WARN_ON(!list_empty(&fb->filp_head));
6528faf6b18SDaniel Vetter 
653b62584e3SDaniel Vetter 	/*
654b62584e3SDaniel Vetter 	 * drm ABI mandates that we remove any deleted framebuffers from active
655b62584e3SDaniel Vetter 	 * useage. But since most sane clients only remove framebuffers they no
656b62584e3SDaniel Vetter 	 * longer need, try to optimize this away.
657b62584e3SDaniel Vetter 	 *
658b62584e3SDaniel Vetter 	 * Since we're holding a reference ourselves, observing a refcount of 1
659b62584e3SDaniel Vetter 	 * means that we're the last holder and can skip it. Also, the refcount
660b62584e3SDaniel Vetter 	 * can never increase from 1 again, so we don't need any barriers or
661b62584e3SDaniel Vetter 	 * locks.
662b62584e3SDaniel Vetter 	 *
663b62584e3SDaniel Vetter 	 * Note that userspace could try to race with use and instate a new
664b62584e3SDaniel Vetter 	 * usage _after_ we've cleared all current ones. End result will be an
665b62584e3SDaniel Vetter 	 * in-use fb with fb-id == 0. Userspace is allowed to shoot its own foot
666b62584e3SDaniel Vetter 	 * in this manner.
667b62584e3SDaniel Vetter 	 */
668b62584e3SDaniel Vetter 	if (atomic_read(&fb->refcount.refcount) > 1) {
669b62584e3SDaniel Vetter 		drm_modeset_lock_all(dev);
670f453ba04SDave Airlie 		/* remove from any CRTC */
671f453ba04SDave Airlie 		list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
672f4510a27SMatt Roper 			if (crtc->primary->fb == fb) {
6735ef5f72fSDave Airlie 				/* should turn off the crtc */
6745ef5f72fSDave Airlie 				memset(&set, 0, sizeof(struct drm_mode_set));
6755ef5f72fSDave Airlie 				set.crtc = crtc;
6765ef5f72fSDave Airlie 				set.fb = NULL;
6772d13b679SDaniel Vetter 				ret = drm_mode_set_config_internal(&set);
6785ef5f72fSDave Airlie 				if (ret)
6795ef5f72fSDave Airlie 					DRM_ERROR("failed to reset crtc %p when fb was deleted\n", crtc);
6805ef5f72fSDave Airlie 			}
681f453ba04SDave Airlie 		}
682f453ba04SDave Airlie 
6838cf5c917SJesse Barnes 		list_for_each_entry(plane, &dev->mode_config.plane_list, head) {
6849125e618SVille Syrjälä 			if (plane->fb == fb)
6859125e618SVille Syrjälä 				drm_plane_force_disable(plane);
6868cf5c917SJesse Barnes 		}
687b62584e3SDaniel Vetter 		drm_modeset_unlock_all(dev);
688b62584e3SDaniel Vetter 	}
6898cf5c917SJesse Barnes 
690f7eff60eSRob Clark 	drm_framebuffer_unreference(fb);
691f453ba04SDave Airlie }
692f7eff60eSRob Clark EXPORT_SYMBOL(drm_framebuffer_remove);
693f453ba04SDave Airlie 
694f453ba04SDave Airlie /**
695e13161afSMatt Roper  * drm_crtc_init_with_planes - Initialise a new CRTC object with
696e13161afSMatt Roper  *    specified primary and cursor planes.
697f453ba04SDave Airlie  * @dev: DRM device
698f453ba04SDave Airlie  * @crtc: CRTC object to init
699e13161afSMatt Roper  * @primary: Primary plane for CRTC
700e13161afSMatt Roper  * @cursor: Cursor plane for CRTC
701f453ba04SDave Airlie  * @funcs: callbacks for the new CRTC
702f453ba04SDave Airlie  *
703ad6f5c34SVille Syrjälä  * Inits a new object created as base part of a driver crtc object.
7046bfc56aaSVille Syrjälä  *
705c8e32cc1SDaniel Vetter  * Returns:
7066bfc56aaSVille Syrjälä  * Zero on success, error code on failure.
707f453ba04SDave Airlie  */
708e13161afSMatt Roper int drm_crtc_init_with_planes(struct drm_device *dev, struct drm_crtc *crtc,
709e13161afSMatt Roper 			      struct drm_plane *primary,
710e13161afSMatt Roper 			      void *cursor,
711f453ba04SDave Airlie 			      const struct drm_crtc_funcs *funcs)
712f453ba04SDave Airlie {
7136bfc56aaSVille Syrjälä 	int ret;
7146bfc56aaSVille Syrjälä 
715f453ba04SDave Airlie 	crtc->dev = dev;
716f453ba04SDave Airlie 	crtc->funcs = funcs;
7177c80e128SRob Clark 	crtc->invert_dimensions = false;
718f453ba04SDave Airlie 
71984849903SDaniel Vetter 	drm_modeset_lock_all(dev);
72029494c17SDaniel Vetter 	mutex_init(&crtc->mutex);
72129494c17SDaniel Vetter 	mutex_lock_nest_lock(&crtc->mutex, &dev->mode_config.mutex);
7226bfc56aaSVille Syrjälä 
7236bfc56aaSVille Syrjälä 	ret = drm_mode_object_get(dev, &crtc->base, DRM_MODE_OBJECT_CRTC);
7246bfc56aaSVille Syrjälä 	if (ret)
7256bfc56aaSVille Syrjälä 		goto out;
726f453ba04SDave Airlie 
727bffd9de0SPaulo Zanoni 	crtc->base.properties = &crtc->properties;
728bffd9de0SPaulo Zanoni 
729f453ba04SDave Airlie 	list_add_tail(&crtc->head, &dev->mode_config.crtc_list);
730f453ba04SDave Airlie 	dev->mode_config.num_crtc++;
7316bfc56aaSVille Syrjälä 
732e13161afSMatt Roper 	crtc->primary = primary;
733e13161afSMatt Roper 	if (primary)
734e13161afSMatt Roper 		primary->possible_crtcs = 1 << drm_crtc_index(crtc);
735e13161afSMatt Roper 
7366bfc56aaSVille Syrjälä  out:
73784849903SDaniel Vetter 	drm_modeset_unlock_all(dev);
7386bfc56aaSVille Syrjälä 
7396bfc56aaSVille Syrjälä 	return ret;
740f453ba04SDave Airlie }
741e13161afSMatt Roper EXPORT_SYMBOL(drm_crtc_init_with_planes);
742f453ba04SDave Airlie 
743f453ba04SDave Airlie /**
744ad6f5c34SVille Syrjälä  * drm_crtc_cleanup - Clean up the core crtc usage
745f453ba04SDave Airlie  * @crtc: CRTC to cleanup
746f453ba04SDave Airlie  *
747ad6f5c34SVille Syrjälä  * This function cleans up @crtc and removes it from the DRM mode setting
748ad6f5c34SVille Syrjälä  * core. Note that the function does *not* free the crtc structure itself,
749ad6f5c34SVille Syrjälä  * this is the responsibility of the caller.
750f453ba04SDave Airlie  */
751f453ba04SDave Airlie void drm_crtc_cleanup(struct drm_crtc *crtc)
752f453ba04SDave Airlie {
753f453ba04SDave Airlie 	struct drm_device *dev = crtc->dev;
754f453ba04SDave Airlie 
755f453ba04SDave Airlie 	kfree(crtc->gamma_store);
756f453ba04SDave Airlie 	crtc->gamma_store = NULL;
757f453ba04SDave Airlie 
758f453ba04SDave Airlie 	drm_mode_object_put(dev, &crtc->base);
759f453ba04SDave Airlie 	list_del(&crtc->head);
760f453ba04SDave Airlie 	dev->mode_config.num_crtc--;
761f453ba04SDave Airlie }
762f453ba04SDave Airlie EXPORT_SYMBOL(drm_crtc_cleanup);
763f453ba04SDave Airlie 
764f453ba04SDave Airlie /**
765db5f7a6eSRussell King  * drm_crtc_index - find the index of a registered CRTC
766db5f7a6eSRussell King  * @crtc: CRTC to find index for
767db5f7a6eSRussell King  *
768db5f7a6eSRussell King  * Given a registered CRTC, return the index of that CRTC within a DRM
769db5f7a6eSRussell King  * device's list of CRTCs.
770db5f7a6eSRussell King  */
771db5f7a6eSRussell King unsigned int drm_crtc_index(struct drm_crtc *crtc)
772db5f7a6eSRussell King {
773db5f7a6eSRussell King 	unsigned int index = 0;
774db5f7a6eSRussell King 	struct drm_crtc *tmp;
775db5f7a6eSRussell King 
776db5f7a6eSRussell King 	list_for_each_entry(tmp, &crtc->dev->mode_config.crtc_list, head) {
777db5f7a6eSRussell King 		if (tmp == crtc)
778db5f7a6eSRussell King 			return index;
779db5f7a6eSRussell King 
780db5f7a6eSRussell King 		index++;
781db5f7a6eSRussell King 	}
782db5f7a6eSRussell King 
783db5f7a6eSRussell King 	BUG();
784db5f7a6eSRussell King }
785db5f7a6eSRussell King EXPORT_SYMBOL(drm_crtc_index);
786db5f7a6eSRussell King 
78786f422d5SLespiau, Damien /*
788f453ba04SDave Airlie  * drm_mode_remove - remove and free a mode
789f453ba04SDave Airlie  * @connector: connector list to modify
790f453ba04SDave Airlie  * @mode: mode to remove
791f453ba04SDave Airlie  *
792f453ba04SDave Airlie  * Remove @mode from @connector's mode list, then free it.
793f453ba04SDave Airlie  */
79486f422d5SLespiau, Damien static void drm_mode_remove(struct drm_connector *connector,
795f453ba04SDave Airlie 			    struct drm_display_mode *mode)
796f453ba04SDave Airlie {
797f453ba04SDave Airlie 	list_del(&mode->head);
798554f1d78SSascha Hauer 	drm_mode_destroy(connector->dev, mode);
799f453ba04SDave Airlie }
800f453ba04SDave Airlie 
801f453ba04SDave Airlie /**
802f453ba04SDave Airlie  * drm_connector_init - Init a preallocated connector
803f453ba04SDave Airlie  * @dev: DRM device
804f453ba04SDave Airlie  * @connector: the connector to init
805f453ba04SDave Airlie  * @funcs: callbacks for this connector
806065a50edSDaniel Vetter  * @connector_type: user visible type of the connector
807f453ba04SDave Airlie  *
808f453ba04SDave Airlie  * Initialises a preallocated connector. Connectors should be
809f453ba04SDave Airlie  * subclassed as part of driver connector objects.
8106bfc56aaSVille Syrjälä  *
811c8e32cc1SDaniel Vetter  * Returns:
8126bfc56aaSVille Syrjälä  * Zero on success, error code on failure.
813f453ba04SDave Airlie  */
8146bfc56aaSVille Syrjälä int drm_connector_init(struct drm_device *dev,
815f453ba04SDave Airlie 		       struct drm_connector *connector,
816f453ba04SDave Airlie 		       const struct drm_connector_funcs *funcs,
817f453ba04SDave Airlie 		       int connector_type)
818f453ba04SDave Airlie {
8196bfc56aaSVille Syrjälä 	int ret;
820b21e3afeSIlia Mirkin 	struct ida *connector_ida =
821b21e3afeSIlia Mirkin 		&drm_connector_enum_list[connector_type].ida;
8226bfc56aaSVille Syrjälä 
82384849903SDaniel Vetter 	drm_modeset_lock_all(dev);
824f453ba04SDave Airlie 
8256bfc56aaSVille Syrjälä 	ret = drm_mode_object_get(dev, &connector->base, DRM_MODE_OBJECT_CONNECTOR);
8266bfc56aaSVille Syrjälä 	if (ret)
8276bfc56aaSVille Syrjälä 		goto out;
8286bfc56aaSVille Syrjälä 
8297e3bdf4aSPaulo Zanoni 	connector->base.properties = &connector->properties;
830f453ba04SDave Airlie 	connector->dev = dev;
831f453ba04SDave Airlie 	connector->funcs = funcs;
832f453ba04SDave Airlie 	connector->connector_type = connector_type;
833f453ba04SDave Airlie 	connector->connector_type_id =
834b21e3afeSIlia Mirkin 		ida_simple_get(connector_ida, 1, 0, GFP_KERNEL);
835b21e3afeSIlia Mirkin 	if (connector->connector_type_id < 0) {
836b21e3afeSIlia Mirkin 		ret = connector->connector_type_id;
837b21e3afeSIlia Mirkin 		drm_mode_object_put(dev, &connector->base);
838b21e3afeSIlia Mirkin 		goto out;
839b21e3afeSIlia Mirkin 	}
840f453ba04SDave Airlie 	INIT_LIST_HEAD(&connector->probed_modes);
841f453ba04SDave Airlie 	INIT_LIST_HEAD(&connector->modes);
842f453ba04SDave Airlie 	connector->edid_blob_ptr = NULL;
8435e2cb2f6SDaniel Vetter 	connector->status = connector_status_unknown;
844f453ba04SDave Airlie 
845f453ba04SDave Airlie 	list_add_tail(&connector->head, &dev->mode_config.connector_list);
846f453ba04SDave Airlie 	dev->mode_config.num_connector++;
847f453ba04SDave Airlie 
848a7331e5cSThomas Hellstrom 	if (connector_type != DRM_MODE_CONNECTOR_VIRTUAL)
84958495563SRob Clark 		drm_object_attach_property(&connector->base,
850a7331e5cSThomas Hellstrom 					      dev->mode_config.edid_property,
851a7331e5cSThomas Hellstrom 					      0);
852f453ba04SDave Airlie 
85358495563SRob Clark 	drm_object_attach_property(&connector->base,
854f453ba04SDave Airlie 				      dev->mode_config.dpms_property, 0);
855f453ba04SDave Airlie 
8566bfc56aaSVille Syrjälä  out:
85784849903SDaniel Vetter 	drm_modeset_unlock_all(dev);
8586bfc56aaSVille Syrjälä 
8596bfc56aaSVille Syrjälä 	return ret;
860f453ba04SDave Airlie }
861f453ba04SDave Airlie EXPORT_SYMBOL(drm_connector_init);
862f453ba04SDave Airlie 
863f453ba04SDave Airlie /**
864f453ba04SDave Airlie  * drm_connector_cleanup - cleans up an initialised connector
865f453ba04SDave Airlie  * @connector: connector to cleanup
866f453ba04SDave Airlie  *
867f453ba04SDave Airlie  * Cleans up the connector but doesn't free the object.
868f453ba04SDave Airlie  */
869f453ba04SDave Airlie void drm_connector_cleanup(struct drm_connector *connector)
870f453ba04SDave Airlie {
871f453ba04SDave Airlie 	struct drm_device *dev = connector->dev;
872f453ba04SDave Airlie 	struct drm_display_mode *mode, *t;
873f453ba04SDave Airlie 
874f453ba04SDave Airlie 	list_for_each_entry_safe(mode, t, &connector->probed_modes, head)
875f453ba04SDave Airlie 		drm_mode_remove(connector, mode);
876f453ba04SDave Airlie 
877f453ba04SDave Airlie 	list_for_each_entry_safe(mode, t, &connector->modes, head)
878f453ba04SDave Airlie 		drm_mode_remove(connector, mode);
879f453ba04SDave Airlie 
880b21e3afeSIlia Mirkin 	ida_remove(&drm_connector_enum_list[connector->connector_type].ida,
881b21e3afeSIlia Mirkin 		   connector->connector_type_id);
882b21e3afeSIlia Mirkin 
883f453ba04SDave Airlie 	drm_mode_object_put(dev, &connector->base);
884f453ba04SDave Airlie 	list_del(&connector->head);
8856380c509SJoonyoung Shim 	dev->mode_config.num_connector--;
886f453ba04SDave Airlie }
887f453ba04SDave Airlie EXPORT_SYMBOL(drm_connector_cleanup);
888f453ba04SDave Airlie 
889c8e32cc1SDaniel Vetter /**
890c8e32cc1SDaniel Vetter  * drm_connector_unplug_all - unregister connector userspace interfaces
891c8e32cc1SDaniel Vetter  * @dev: drm device
892c8e32cc1SDaniel Vetter  *
893c8e32cc1SDaniel Vetter  * This function unregisters all connector userspace interfaces in sysfs. Should
894c8e32cc1SDaniel Vetter  * be call when the device is disconnected, e.g. from an usb driver's
895c8e32cc1SDaniel Vetter  * ->disconnect callback.
896c8e32cc1SDaniel Vetter  */
897cbc7e221SDave Airlie void drm_connector_unplug_all(struct drm_device *dev)
898cbc7e221SDave Airlie {
899cbc7e221SDave Airlie 	struct drm_connector *connector;
900cbc7e221SDave Airlie 
901cbc7e221SDave Airlie 	/* taking the mode config mutex ends up in a clash with sysfs */
902cbc7e221SDave Airlie 	list_for_each_entry(connector, &dev->mode_config.connector_list, head)
903cbc7e221SDave Airlie 		drm_sysfs_connector_remove(connector);
904cbc7e221SDave Airlie 
905cbc7e221SDave Airlie }
906cbc7e221SDave Airlie EXPORT_SYMBOL(drm_connector_unplug_all);
907cbc7e221SDave Airlie 
908c8e32cc1SDaniel Vetter /**
909c8e32cc1SDaniel Vetter  * drm_bridge_init - initialize a drm transcoder/bridge
910c8e32cc1SDaniel Vetter  * @dev: drm device
911c8e32cc1SDaniel Vetter  * @bridge: transcoder/bridge to set up
912c8e32cc1SDaniel Vetter  * @funcs: bridge function table
913c8e32cc1SDaniel Vetter  *
914c8e32cc1SDaniel Vetter  * Initialises a preallocated bridge. Bridges should be
915c8e32cc1SDaniel Vetter  * subclassed as part of driver connector objects.
916c8e32cc1SDaniel Vetter  *
917c8e32cc1SDaniel Vetter  * Returns:
918c8e32cc1SDaniel Vetter  * Zero on success, error code on failure.
919c8e32cc1SDaniel Vetter  */
9203b336ec4SSean Paul int drm_bridge_init(struct drm_device *dev, struct drm_bridge *bridge,
9213b336ec4SSean Paul 		const struct drm_bridge_funcs *funcs)
9223b336ec4SSean Paul {
9233b336ec4SSean Paul 	int ret;
9243b336ec4SSean Paul 
9253b336ec4SSean Paul 	drm_modeset_lock_all(dev);
9263b336ec4SSean Paul 
9273b336ec4SSean Paul 	ret = drm_mode_object_get(dev, &bridge->base, DRM_MODE_OBJECT_BRIDGE);
9283b336ec4SSean Paul 	if (ret)
9293b336ec4SSean Paul 		goto out;
9303b336ec4SSean Paul 
9313b336ec4SSean Paul 	bridge->dev = dev;
9323b336ec4SSean Paul 	bridge->funcs = funcs;
9333b336ec4SSean Paul 
9343b336ec4SSean Paul 	list_add_tail(&bridge->head, &dev->mode_config.bridge_list);
9353b336ec4SSean Paul 	dev->mode_config.num_bridge++;
9363b336ec4SSean Paul 
9373b336ec4SSean Paul  out:
9383b336ec4SSean Paul 	drm_modeset_unlock_all(dev);
9393b336ec4SSean Paul 	return ret;
9403b336ec4SSean Paul }
9413b336ec4SSean Paul EXPORT_SYMBOL(drm_bridge_init);
9423b336ec4SSean Paul 
943c8e32cc1SDaniel Vetter /**
944c8e32cc1SDaniel Vetter  * drm_bridge_cleanup - cleans up an initialised bridge
945c8e32cc1SDaniel Vetter  * @bridge: bridge to cleanup
946c8e32cc1SDaniel Vetter  *
947c8e32cc1SDaniel Vetter  * Cleans up the bridge but doesn't free the object.
948c8e32cc1SDaniel Vetter  */
9493b336ec4SSean Paul void drm_bridge_cleanup(struct drm_bridge *bridge)
9503b336ec4SSean Paul {
9513b336ec4SSean Paul 	struct drm_device *dev = bridge->dev;
9523b336ec4SSean Paul 
9533b336ec4SSean Paul 	drm_modeset_lock_all(dev);
9543b336ec4SSean Paul 	drm_mode_object_put(dev, &bridge->base);
9553b336ec4SSean Paul 	list_del(&bridge->head);
9563b336ec4SSean Paul 	dev->mode_config.num_bridge--;
9573b336ec4SSean Paul 	drm_modeset_unlock_all(dev);
9583b336ec4SSean Paul }
9593b336ec4SSean Paul EXPORT_SYMBOL(drm_bridge_cleanup);
9603b336ec4SSean Paul 
961c8e32cc1SDaniel Vetter /**
962c8e32cc1SDaniel Vetter  * drm_encoder_init - Init a preallocated encoder
963c8e32cc1SDaniel Vetter  * @dev: drm device
964c8e32cc1SDaniel Vetter  * @encoder: the encoder to init
965c8e32cc1SDaniel Vetter  * @funcs: callbacks for this encoder
966c8e32cc1SDaniel Vetter  * @encoder_type: user visible type of the encoder
967c8e32cc1SDaniel Vetter  *
968c8e32cc1SDaniel Vetter  * Initialises a preallocated encoder. Encoder should be
969c8e32cc1SDaniel Vetter  * subclassed as part of driver encoder objects.
970c8e32cc1SDaniel Vetter  *
971c8e32cc1SDaniel Vetter  * Returns:
972c8e32cc1SDaniel Vetter  * Zero on success, error code on failure.
973c8e32cc1SDaniel Vetter  */
9746bfc56aaSVille Syrjälä int drm_encoder_init(struct drm_device *dev,
975f453ba04SDave Airlie 		      struct drm_encoder *encoder,
976f453ba04SDave Airlie 		      const struct drm_encoder_funcs *funcs,
977f453ba04SDave Airlie 		      int encoder_type)
978f453ba04SDave Airlie {
9796bfc56aaSVille Syrjälä 	int ret;
9806bfc56aaSVille Syrjälä 
98184849903SDaniel Vetter 	drm_modeset_lock_all(dev);
982f453ba04SDave Airlie 
9836bfc56aaSVille Syrjälä 	ret = drm_mode_object_get(dev, &encoder->base, DRM_MODE_OBJECT_ENCODER);
9846bfc56aaSVille Syrjälä 	if (ret)
9856bfc56aaSVille Syrjälä 		goto out;
986f453ba04SDave Airlie 
9876bfc56aaSVille Syrjälä 	encoder->dev = dev;
988f453ba04SDave Airlie 	encoder->encoder_type = encoder_type;
989f453ba04SDave Airlie 	encoder->funcs = funcs;
990f453ba04SDave Airlie 
991f453ba04SDave Airlie 	list_add_tail(&encoder->head, &dev->mode_config.encoder_list);
992f453ba04SDave Airlie 	dev->mode_config.num_encoder++;
993f453ba04SDave Airlie 
9946bfc56aaSVille Syrjälä  out:
99584849903SDaniel Vetter 	drm_modeset_unlock_all(dev);
9966bfc56aaSVille Syrjälä 
9976bfc56aaSVille Syrjälä 	return ret;
998f453ba04SDave Airlie }
999f453ba04SDave Airlie EXPORT_SYMBOL(drm_encoder_init);
1000f453ba04SDave Airlie 
1001c8e32cc1SDaniel Vetter /**
1002c8e32cc1SDaniel Vetter  * drm_encoder_cleanup - cleans up an initialised encoder
1003c8e32cc1SDaniel Vetter  * @encoder: encoder to cleanup
1004c8e32cc1SDaniel Vetter  *
1005c8e32cc1SDaniel Vetter  * Cleans up the encoder but doesn't free the object.
1006c8e32cc1SDaniel Vetter  */
1007f453ba04SDave Airlie void drm_encoder_cleanup(struct drm_encoder *encoder)
1008f453ba04SDave Airlie {
1009f453ba04SDave Airlie 	struct drm_device *dev = encoder->dev;
101084849903SDaniel Vetter 	drm_modeset_lock_all(dev);
1011f453ba04SDave Airlie 	drm_mode_object_put(dev, &encoder->base);
1012f453ba04SDave Airlie 	list_del(&encoder->head);
10136380c509SJoonyoung Shim 	dev->mode_config.num_encoder--;
101484849903SDaniel Vetter 	drm_modeset_unlock_all(dev);
1015f453ba04SDave Airlie }
1016f453ba04SDave Airlie EXPORT_SYMBOL(drm_encoder_cleanup);
1017f453ba04SDave Airlie 
101835f2c3aeSVille Syrjälä /**
1019dc415ff9SMatt Roper  * drm_universal_plane_init - Initialize a new universal plane object
102035f2c3aeSVille Syrjälä  * @dev: DRM device
102135f2c3aeSVille Syrjälä  * @plane: plane object to init
102235f2c3aeSVille Syrjälä  * @possible_crtcs: bitmask of possible CRTCs
102335f2c3aeSVille Syrjälä  * @funcs: callbacks for the new plane
102435f2c3aeSVille Syrjälä  * @formats: array of supported formats (%DRM_FORMAT_*)
102535f2c3aeSVille Syrjälä  * @format_count: number of elements in @formats
1026dc415ff9SMatt Roper  * @type: type of plane (overlay, primary, cursor)
102735f2c3aeSVille Syrjälä  *
1028dc415ff9SMatt Roper  * Initializes a plane object of type @type.
102935f2c3aeSVille Syrjälä  *
1030c8e32cc1SDaniel Vetter  * Returns:
103135f2c3aeSVille Syrjälä  * Zero on success, error code on failure.
103235f2c3aeSVille Syrjälä  */
1033dc415ff9SMatt Roper int drm_universal_plane_init(struct drm_device *dev, struct drm_plane *plane,
10348cf5c917SJesse Barnes 			     unsigned long possible_crtcs,
10358cf5c917SJesse Barnes 			     const struct drm_plane_funcs *funcs,
10360a7eb243SRob Clark 			     const uint32_t *formats, uint32_t format_count,
1037dc415ff9SMatt Roper 			     enum drm_plane_type type)
10388cf5c917SJesse Barnes {
10396bfc56aaSVille Syrjälä 	int ret;
10406bfc56aaSVille Syrjälä 
104184849903SDaniel Vetter 	drm_modeset_lock_all(dev);
10428cf5c917SJesse Barnes 
10436bfc56aaSVille Syrjälä 	ret = drm_mode_object_get(dev, &plane->base, DRM_MODE_OBJECT_PLANE);
10446bfc56aaSVille Syrjälä 	if (ret)
10456bfc56aaSVille Syrjälä 		goto out;
10466bfc56aaSVille Syrjälä 
10474d93914aSRob Clark 	plane->base.properties = &plane->properties;
10488cf5c917SJesse Barnes 	plane->dev = dev;
10498cf5c917SJesse Barnes 	plane->funcs = funcs;
10508cf5c917SJesse Barnes 	plane->format_types = kmalloc(sizeof(uint32_t) * format_count,
10518cf5c917SJesse Barnes 				      GFP_KERNEL);
10528cf5c917SJesse Barnes 	if (!plane->format_types) {
10538cf5c917SJesse Barnes 		DRM_DEBUG_KMS("out of memory when allocating plane\n");
10548cf5c917SJesse Barnes 		drm_mode_object_put(dev, &plane->base);
10556bfc56aaSVille Syrjälä 		ret = -ENOMEM;
10566bfc56aaSVille Syrjälä 		goto out;
10578cf5c917SJesse Barnes 	}
10588cf5c917SJesse Barnes 
1059308e5bcbSJesse Barnes 	memcpy(plane->format_types, formats, format_count * sizeof(uint32_t));
10608cf5c917SJesse Barnes 	plane->format_count = format_count;
10618cf5c917SJesse Barnes 	plane->possible_crtcs = possible_crtcs;
1062dc415ff9SMatt Roper 	plane->type = type;
10638cf5c917SJesse Barnes 
10648cf5c917SJesse Barnes 	list_add_tail(&plane->head, &dev->mode_config.plane_list);
1065e27dde3eSMatt Roper 	dev->mode_config.num_total_plane++;
1066e27dde3eSMatt Roper 	if (plane->type == DRM_PLANE_TYPE_OVERLAY)
1067e27dde3eSMatt Roper 		dev->mode_config.num_overlay_plane++;
10688cf5c917SJesse Barnes 
10699922ab5aSRob Clark 	drm_object_attach_property(&plane->base,
10709922ab5aSRob Clark 				   dev->mode_config.plane_type_property,
10719922ab5aSRob Clark 				   plane->type);
10729922ab5aSRob Clark 
10736bfc56aaSVille Syrjälä  out:
107484849903SDaniel Vetter 	drm_modeset_unlock_all(dev);
10758cf5c917SJesse Barnes 
10766bfc56aaSVille Syrjälä 	return ret;
10778cf5c917SJesse Barnes }
1078dc415ff9SMatt Roper EXPORT_SYMBOL(drm_universal_plane_init);
1079dc415ff9SMatt Roper 
1080dc415ff9SMatt Roper /**
1081dc415ff9SMatt Roper  * drm_plane_init - Initialize a legacy plane
1082dc415ff9SMatt Roper  * @dev: DRM device
1083dc415ff9SMatt Roper  * @plane: plane object to init
1084dc415ff9SMatt Roper  * @possible_crtcs: bitmask of possible CRTCs
1085dc415ff9SMatt Roper  * @funcs: callbacks for the new plane
1086dc415ff9SMatt Roper  * @formats: array of supported formats (%DRM_FORMAT_*)
1087dc415ff9SMatt Roper  * @format_count: number of elements in @formats
1088dc415ff9SMatt Roper  * @is_primary: plane type (primary vs overlay)
1089dc415ff9SMatt Roper  *
1090dc415ff9SMatt Roper  * Legacy API to initialize a DRM plane.
1091dc415ff9SMatt Roper  *
1092dc415ff9SMatt Roper  * New drivers should call drm_universal_plane_init() instead.
1093dc415ff9SMatt Roper  *
1094dc415ff9SMatt Roper  * Returns:
1095dc415ff9SMatt Roper  * Zero on success, error code on failure.
1096dc415ff9SMatt Roper  */
1097dc415ff9SMatt Roper int drm_plane_init(struct drm_device *dev, struct drm_plane *plane,
1098dc415ff9SMatt Roper 		   unsigned long possible_crtcs,
1099dc415ff9SMatt Roper 		   const struct drm_plane_funcs *funcs,
1100dc415ff9SMatt Roper 		   const uint32_t *formats, uint32_t format_count,
1101dc415ff9SMatt Roper 		   bool is_primary)
1102dc415ff9SMatt Roper {
1103dc415ff9SMatt Roper 	enum drm_plane_type type;
1104dc415ff9SMatt Roper 
1105dc415ff9SMatt Roper 	type = is_primary ? DRM_PLANE_TYPE_PRIMARY : DRM_PLANE_TYPE_OVERLAY;
1106dc415ff9SMatt Roper 	return drm_universal_plane_init(dev, plane, possible_crtcs, funcs,
1107dc415ff9SMatt Roper 					formats, format_count, type);
1108dc415ff9SMatt Roper }
11098cf5c917SJesse Barnes EXPORT_SYMBOL(drm_plane_init);
11108cf5c917SJesse Barnes 
111135f2c3aeSVille Syrjälä /**
111235f2c3aeSVille Syrjälä  * drm_plane_cleanup - Clean up the core plane usage
111335f2c3aeSVille Syrjälä  * @plane: plane to cleanup
111435f2c3aeSVille Syrjälä  *
111535f2c3aeSVille Syrjälä  * This function cleans up @plane and removes it from the DRM mode setting
111635f2c3aeSVille Syrjälä  * core. Note that the function does *not* free the plane structure itself,
111735f2c3aeSVille Syrjälä  * this is the responsibility of the caller.
111835f2c3aeSVille Syrjälä  */
11198cf5c917SJesse Barnes void drm_plane_cleanup(struct drm_plane *plane)
11208cf5c917SJesse Barnes {
11218cf5c917SJesse Barnes 	struct drm_device *dev = plane->dev;
11228cf5c917SJesse Barnes 
112384849903SDaniel Vetter 	drm_modeset_lock_all(dev);
11248cf5c917SJesse Barnes 	kfree(plane->format_types);
11258cf5c917SJesse Barnes 	drm_mode_object_put(dev, &plane->base);
1126dc415ff9SMatt Roper 
1127dc415ff9SMatt Roper 	BUG_ON(list_empty(&plane->head));
1128dc415ff9SMatt Roper 
11298cf5c917SJesse Barnes 	list_del(&plane->head);
1130e27dde3eSMatt Roper 	dev->mode_config.num_total_plane--;
1131e27dde3eSMatt Roper 	if (plane->type == DRM_PLANE_TYPE_OVERLAY)
1132e27dde3eSMatt Roper 		dev->mode_config.num_overlay_plane--;
113384849903SDaniel Vetter 	drm_modeset_unlock_all(dev);
11348cf5c917SJesse Barnes }
11358cf5c917SJesse Barnes EXPORT_SYMBOL(drm_plane_cleanup);
11368cf5c917SJesse Barnes 
113735f2c3aeSVille Syrjälä /**
113835f2c3aeSVille Syrjälä  * drm_plane_force_disable - Forcibly disable a plane
113935f2c3aeSVille Syrjälä  * @plane: plane to disable
114035f2c3aeSVille Syrjälä  *
114135f2c3aeSVille Syrjälä  * Forces the plane to be disabled.
114235f2c3aeSVille Syrjälä  *
114335f2c3aeSVille Syrjälä  * Used when the plane's current framebuffer is destroyed,
114435f2c3aeSVille Syrjälä  * and when restoring fbdev mode.
114535f2c3aeSVille Syrjälä  */
11469125e618SVille Syrjälä void drm_plane_force_disable(struct drm_plane *plane)
11479125e618SVille Syrjälä {
11489125e618SVille Syrjälä 	int ret;
11499125e618SVille Syrjälä 
11509125e618SVille Syrjälä 	if (!plane->fb)
11519125e618SVille Syrjälä 		return;
11529125e618SVille Syrjälä 
11539125e618SVille Syrjälä 	ret = plane->funcs->disable_plane(plane);
11549125e618SVille Syrjälä 	if (ret)
11559125e618SVille Syrjälä 		DRM_ERROR("failed to disable plane with busy fb\n");
11569125e618SVille Syrjälä 	/* disconnect the plane from the fb and crtc: */
11579125e618SVille Syrjälä 	__drm_framebuffer_unreference(plane->fb);
11589125e618SVille Syrjälä 	plane->fb = NULL;
11599125e618SVille Syrjälä 	plane->crtc = NULL;
11609125e618SVille Syrjälä }
11619125e618SVille Syrjälä EXPORT_SYMBOL(drm_plane_force_disable);
11629125e618SVille Syrjälä 
1163f453ba04SDave Airlie static int drm_mode_create_standard_connector_properties(struct drm_device *dev)
1164f453ba04SDave Airlie {
1165f453ba04SDave Airlie 	struct drm_property *edid;
1166f453ba04SDave Airlie 	struct drm_property *dpms;
1167f453ba04SDave Airlie 
1168f453ba04SDave Airlie 	/*
1169f453ba04SDave Airlie 	 * Standard properties (apply to all connectors)
1170f453ba04SDave Airlie 	 */
1171f453ba04SDave Airlie 	edid = drm_property_create(dev, DRM_MODE_PROP_BLOB |
1172f453ba04SDave Airlie 				   DRM_MODE_PROP_IMMUTABLE,
1173f453ba04SDave Airlie 				   "EDID", 0);
1174f453ba04SDave Airlie 	dev->mode_config.edid_property = edid;
1175f453ba04SDave Airlie 
11764a67d391SSascha Hauer 	dpms = drm_property_create_enum(dev, 0,
11774a67d391SSascha Hauer 				   "DPMS", drm_dpms_enum_list,
11784a67d391SSascha Hauer 				   ARRAY_SIZE(drm_dpms_enum_list));
1179f453ba04SDave Airlie 	dev->mode_config.dpms_property = dpms;
1180f453ba04SDave Airlie 
1181f453ba04SDave Airlie 	return 0;
1182f453ba04SDave Airlie }
1183f453ba04SDave Airlie 
11849922ab5aSRob Clark static int drm_mode_create_standard_plane_properties(struct drm_device *dev)
11859922ab5aSRob Clark {
11869922ab5aSRob Clark 	struct drm_property *type;
11879922ab5aSRob Clark 
11889922ab5aSRob Clark 	/*
11899922ab5aSRob Clark 	 * Standard properties (apply to all planes)
11909922ab5aSRob Clark 	 */
11919922ab5aSRob Clark 	type = drm_property_create_enum(dev, DRM_MODE_PROP_IMMUTABLE,
11929922ab5aSRob Clark 					"type", drm_plane_type_enum_list,
11939922ab5aSRob Clark 					ARRAY_SIZE(drm_plane_type_enum_list));
11949922ab5aSRob Clark 	dev->mode_config.plane_type_property = type;
11959922ab5aSRob Clark 
11969922ab5aSRob Clark 	return 0;
11979922ab5aSRob Clark }
11989922ab5aSRob Clark 
1199f453ba04SDave Airlie /**
1200f453ba04SDave Airlie  * drm_mode_create_dvi_i_properties - create DVI-I specific connector properties
1201f453ba04SDave Airlie  * @dev: DRM device
1202f453ba04SDave Airlie  *
1203f453ba04SDave Airlie  * Called by a driver the first time a DVI-I connector is made.
1204f453ba04SDave Airlie  */
1205f453ba04SDave Airlie int drm_mode_create_dvi_i_properties(struct drm_device *dev)
1206f453ba04SDave Airlie {
1207f453ba04SDave Airlie 	struct drm_property *dvi_i_selector;
1208f453ba04SDave Airlie 	struct drm_property *dvi_i_subconnector;
1209f453ba04SDave Airlie 
1210f453ba04SDave Airlie 	if (dev->mode_config.dvi_i_select_subconnector_property)
1211f453ba04SDave Airlie 		return 0;
1212f453ba04SDave Airlie 
1213f453ba04SDave Airlie 	dvi_i_selector =
12144a67d391SSascha Hauer 		drm_property_create_enum(dev, 0,
1215f453ba04SDave Airlie 				    "select subconnector",
12164a67d391SSascha Hauer 				    drm_dvi_i_select_enum_list,
1217f453ba04SDave Airlie 				    ARRAY_SIZE(drm_dvi_i_select_enum_list));
1218f453ba04SDave Airlie 	dev->mode_config.dvi_i_select_subconnector_property = dvi_i_selector;
1219f453ba04SDave Airlie 
12204a67d391SSascha Hauer 	dvi_i_subconnector = drm_property_create_enum(dev, DRM_MODE_PROP_IMMUTABLE,
1221f453ba04SDave Airlie 				    "subconnector",
12224a67d391SSascha Hauer 				    drm_dvi_i_subconnector_enum_list,
1223f453ba04SDave Airlie 				    ARRAY_SIZE(drm_dvi_i_subconnector_enum_list));
1224f453ba04SDave Airlie 	dev->mode_config.dvi_i_subconnector_property = dvi_i_subconnector;
1225f453ba04SDave Airlie 
1226f453ba04SDave Airlie 	return 0;
1227f453ba04SDave Airlie }
1228f453ba04SDave Airlie EXPORT_SYMBOL(drm_mode_create_dvi_i_properties);
1229f453ba04SDave Airlie 
1230f453ba04SDave Airlie /**
1231f453ba04SDave Airlie  * drm_create_tv_properties - create TV specific connector properties
1232f453ba04SDave Airlie  * @dev: DRM device
1233f453ba04SDave Airlie  * @num_modes: number of different TV formats (modes) supported
1234f453ba04SDave Airlie  * @modes: array of pointers to strings containing name of each format
1235f453ba04SDave Airlie  *
1236f453ba04SDave Airlie  * Called by a driver's TV initialization routine, this function creates
1237f453ba04SDave Airlie  * the TV specific connector properties for a given device.  Caller is
1238f453ba04SDave Airlie  * responsible for allocating a list of format names and passing them to
1239f453ba04SDave Airlie  * this routine.
1240f453ba04SDave Airlie  */
1241f453ba04SDave Airlie int drm_mode_create_tv_properties(struct drm_device *dev, int num_modes,
1242f453ba04SDave Airlie 				  char *modes[])
1243f453ba04SDave Airlie {
1244f453ba04SDave Airlie 	struct drm_property *tv_selector;
1245f453ba04SDave Airlie 	struct drm_property *tv_subconnector;
1246f453ba04SDave Airlie 	int i;
1247f453ba04SDave Airlie 
1248f453ba04SDave Airlie 	if (dev->mode_config.tv_select_subconnector_property)
1249f453ba04SDave Airlie 		return 0;
1250f453ba04SDave Airlie 
1251f453ba04SDave Airlie 	/*
1252f453ba04SDave Airlie 	 * Basic connector properties
1253f453ba04SDave Airlie 	 */
12544a67d391SSascha Hauer 	tv_selector = drm_property_create_enum(dev, 0,
1255f453ba04SDave Airlie 					  "select subconnector",
12564a67d391SSascha Hauer 					  drm_tv_select_enum_list,
1257f453ba04SDave Airlie 					  ARRAY_SIZE(drm_tv_select_enum_list));
1258f453ba04SDave Airlie 	dev->mode_config.tv_select_subconnector_property = tv_selector;
1259f453ba04SDave Airlie 
1260f453ba04SDave Airlie 	tv_subconnector =
12614a67d391SSascha Hauer 		drm_property_create_enum(dev, DRM_MODE_PROP_IMMUTABLE,
12624a67d391SSascha Hauer 				    "subconnector",
12634a67d391SSascha Hauer 				    drm_tv_subconnector_enum_list,
1264f453ba04SDave Airlie 				    ARRAY_SIZE(drm_tv_subconnector_enum_list));
1265f453ba04SDave Airlie 	dev->mode_config.tv_subconnector_property = tv_subconnector;
1266f453ba04SDave Airlie 
1267f453ba04SDave Airlie 	/*
1268f453ba04SDave Airlie 	 * Other, TV specific properties: margins & TV modes.
1269f453ba04SDave Airlie 	 */
1270f453ba04SDave Airlie 	dev->mode_config.tv_left_margin_property =
1271d9bc3c02SSascha Hauer 		drm_property_create_range(dev, 0, "left margin", 0, 100);
1272f453ba04SDave Airlie 
1273f453ba04SDave Airlie 	dev->mode_config.tv_right_margin_property =
1274d9bc3c02SSascha Hauer 		drm_property_create_range(dev, 0, "right margin", 0, 100);
1275f453ba04SDave Airlie 
1276f453ba04SDave Airlie 	dev->mode_config.tv_top_margin_property =
1277d9bc3c02SSascha Hauer 		drm_property_create_range(dev, 0, "top margin", 0, 100);
1278f453ba04SDave Airlie 
1279f453ba04SDave Airlie 	dev->mode_config.tv_bottom_margin_property =
1280d9bc3c02SSascha Hauer 		drm_property_create_range(dev, 0, "bottom margin", 0, 100);
1281f453ba04SDave Airlie 
1282f453ba04SDave Airlie 	dev->mode_config.tv_mode_property =
1283f453ba04SDave Airlie 		drm_property_create(dev, DRM_MODE_PROP_ENUM,
1284f453ba04SDave Airlie 				    "mode", num_modes);
1285f453ba04SDave Airlie 	for (i = 0; i < num_modes; i++)
1286f453ba04SDave Airlie 		drm_property_add_enum(dev->mode_config.tv_mode_property, i,
1287f453ba04SDave Airlie 				      i, modes[i]);
1288f453ba04SDave Airlie 
1289b6b7902eSFrancisco Jerez 	dev->mode_config.tv_brightness_property =
1290d9bc3c02SSascha Hauer 		drm_property_create_range(dev, 0, "brightness", 0, 100);
1291b6b7902eSFrancisco Jerez 
1292b6b7902eSFrancisco Jerez 	dev->mode_config.tv_contrast_property =
1293d9bc3c02SSascha Hauer 		drm_property_create_range(dev, 0, "contrast", 0, 100);
1294b6b7902eSFrancisco Jerez 
1295b6b7902eSFrancisco Jerez 	dev->mode_config.tv_flicker_reduction_property =
1296d9bc3c02SSascha Hauer 		drm_property_create_range(dev, 0, "flicker reduction", 0, 100);
1297b6b7902eSFrancisco Jerez 
1298a75f0236SFrancisco Jerez 	dev->mode_config.tv_overscan_property =
1299d9bc3c02SSascha Hauer 		drm_property_create_range(dev, 0, "overscan", 0, 100);
1300a75f0236SFrancisco Jerez 
1301a75f0236SFrancisco Jerez 	dev->mode_config.tv_saturation_property =
1302d9bc3c02SSascha Hauer 		drm_property_create_range(dev, 0, "saturation", 0, 100);
1303a75f0236SFrancisco Jerez 
1304a75f0236SFrancisco Jerez 	dev->mode_config.tv_hue_property =
1305d9bc3c02SSascha Hauer 		drm_property_create_range(dev, 0, "hue", 0, 100);
1306a75f0236SFrancisco Jerez 
1307f453ba04SDave Airlie 	return 0;
1308f453ba04SDave Airlie }
1309f453ba04SDave Airlie EXPORT_SYMBOL(drm_mode_create_tv_properties);
1310f453ba04SDave Airlie 
1311f453ba04SDave Airlie /**
1312f453ba04SDave Airlie  * drm_mode_create_scaling_mode_property - create scaling mode property
1313f453ba04SDave Airlie  * @dev: DRM device
1314f453ba04SDave Airlie  *
1315f453ba04SDave Airlie  * Called by a driver the first time it's needed, must be attached to desired
1316f453ba04SDave Airlie  * connectors.
1317f453ba04SDave Airlie  */
1318f453ba04SDave Airlie int drm_mode_create_scaling_mode_property(struct drm_device *dev)
1319f453ba04SDave Airlie {
1320f453ba04SDave Airlie 	struct drm_property *scaling_mode;
1321f453ba04SDave Airlie 
1322f453ba04SDave Airlie 	if (dev->mode_config.scaling_mode_property)
1323f453ba04SDave Airlie 		return 0;
1324f453ba04SDave Airlie 
1325f453ba04SDave Airlie 	scaling_mode =
13264a67d391SSascha Hauer 		drm_property_create_enum(dev, 0, "scaling mode",
13274a67d391SSascha Hauer 				drm_scaling_mode_enum_list,
1328f453ba04SDave Airlie 				    ARRAY_SIZE(drm_scaling_mode_enum_list));
1329f453ba04SDave Airlie 
1330f453ba04SDave Airlie 	dev->mode_config.scaling_mode_property = scaling_mode;
1331f453ba04SDave Airlie 
1332f453ba04SDave Airlie 	return 0;
1333f453ba04SDave Airlie }
1334f453ba04SDave Airlie EXPORT_SYMBOL(drm_mode_create_scaling_mode_property);
1335f453ba04SDave Airlie 
1336f453ba04SDave Airlie /**
1337884840aaSJakob Bornecrantz  * drm_mode_create_dirty_property - create dirty property
1338884840aaSJakob Bornecrantz  * @dev: DRM device
1339884840aaSJakob Bornecrantz  *
1340884840aaSJakob Bornecrantz  * Called by a driver the first time it's needed, must be attached to desired
1341884840aaSJakob Bornecrantz  * connectors.
1342884840aaSJakob Bornecrantz  */
1343884840aaSJakob Bornecrantz int drm_mode_create_dirty_info_property(struct drm_device *dev)
1344884840aaSJakob Bornecrantz {
1345884840aaSJakob Bornecrantz 	struct drm_property *dirty_info;
1346884840aaSJakob Bornecrantz 
1347884840aaSJakob Bornecrantz 	if (dev->mode_config.dirty_info_property)
1348884840aaSJakob Bornecrantz 		return 0;
1349884840aaSJakob Bornecrantz 
1350884840aaSJakob Bornecrantz 	dirty_info =
13514a67d391SSascha Hauer 		drm_property_create_enum(dev, DRM_MODE_PROP_IMMUTABLE,
1352884840aaSJakob Bornecrantz 				    "dirty",
13534a67d391SSascha Hauer 				    drm_dirty_info_enum_list,
1354884840aaSJakob Bornecrantz 				    ARRAY_SIZE(drm_dirty_info_enum_list));
1355884840aaSJakob Bornecrantz 	dev->mode_config.dirty_info_property = dirty_info;
1356884840aaSJakob Bornecrantz 
1357884840aaSJakob Bornecrantz 	return 0;
1358884840aaSJakob Bornecrantz }
1359884840aaSJakob Bornecrantz EXPORT_SYMBOL(drm_mode_create_dirty_info_property);
1360884840aaSJakob Bornecrantz 
1361ea9cbb06SVille Syrjälä static int drm_mode_group_init(struct drm_device *dev, struct drm_mode_group *group)
1362f453ba04SDave Airlie {
1363f453ba04SDave Airlie 	uint32_t total_objects = 0;
1364f453ba04SDave Airlie 
1365f453ba04SDave Airlie 	total_objects += dev->mode_config.num_crtc;
1366f453ba04SDave Airlie 	total_objects += dev->mode_config.num_connector;
1367f453ba04SDave Airlie 	total_objects += dev->mode_config.num_encoder;
13683b336ec4SSean Paul 	total_objects += dev->mode_config.num_bridge;
1369f453ba04SDave Airlie 
1370f453ba04SDave Airlie 	group->id_list = kzalloc(total_objects * sizeof(uint32_t), GFP_KERNEL);
1371f453ba04SDave Airlie 	if (!group->id_list)
1372f453ba04SDave Airlie 		return -ENOMEM;
1373f453ba04SDave Airlie 
1374f453ba04SDave Airlie 	group->num_crtcs = 0;
1375f453ba04SDave Airlie 	group->num_connectors = 0;
1376f453ba04SDave Airlie 	group->num_encoders = 0;
13773b336ec4SSean Paul 	group->num_bridges = 0;
1378f453ba04SDave Airlie 	return 0;
1379f453ba04SDave Airlie }
1380f453ba04SDave Airlie 
1381ad222799SDave Airlie void drm_mode_group_destroy(struct drm_mode_group *group)
1382ad222799SDave Airlie {
1383ad222799SDave Airlie 	kfree(group->id_list);
1384ad222799SDave Airlie 	group->id_list = NULL;
1385ad222799SDave Airlie }
1386ad222799SDave Airlie 
1387c8e32cc1SDaniel Vetter /*
1388c8e32cc1SDaniel Vetter  * NOTE: Driver's shouldn't ever call drm_mode_group_init_legacy_group - it is
1389c8e32cc1SDaniel Vetter  * the drm core's responsibility to set up mode control groups.
1390c8e32cc1SDaniel Vetter  */
1391f453ba04SDave Airlie int drm_mode_group_init_legacy_group(struct drm_device *dev,
1392f453ba04SDave Airlie 				     struct drm_mode_group *group)
1393f453ba04SDave Airlie {
1394f453ba04SDave Airlie 	struct drm_crtc *crtc;
1395f453ba04SDave Airlie 	struct drm_encoder *encoder;
1396f453ba04SDave Airlie 	struct drm_connector *connector;
13973b336ec4SSean Paul 	struct drm_bridge *bridge;
1398f453ba04SDave Airlie 	int ret;
1399f453ba04SDave Airlie 
1400f453ba04SDave Airlie 	if ((ret = drm_mode_group_init(dev, group)))
1401f453ba04SDave Airlie 		return ret;
1402f453ba04SDave Airlie 
1403f453ba04SDave Airlie 	list_for_each_entry(crtc, &dev->mode_config.crtc_list, head)
1404f453ba04SDave Airlie 		group->id_list[group->num_crtcs++] = crtc->base.id;
1405f453ba04SDave Airlie 
1406f453ba04SDave Airlie 	list_for_each_entry(encoder, &dev->mode_config.encoder_list, head)
1407f453ba04SDave Airlie 		group->id_list[group->num_crtcs + group->num_encoders++] =
1408f453ba04SDave Airlie 		encoder->base.id;
1409f453ba04SDave Airlie 
1410f453ba04SDave Airlie 	list_for_each_entry(connector, &dev->mode_config.connector_list, head)
1411f453ba04SDave Airlie 		group->id_list[group->num_crtcs + group->num_encoders +
1412f453ba04SDave Airlie 			       group->num_connectors++] = connector->base.id;
1413f453ba04SDave Airlie 
14143b336ec4SSean Paul 	list_for_each_entry(bridge, &dev->mode_config.bridge_list, head)
14153b336ec4SSean Paul 		group->id_list[group->num_crtcs + group->num_encoders +
14163b336ec4SSean Paul 			       group->num_connectors + group->num_bridges++] =
14173b336ec4SSean Paul 					bridge->base.id;
14183b336ec4SSean Paul 
1419f453ba04SDave Airlie 	return 0;
1420f453ba04SDave Airlie }
14219c1dfc55SDave Airlie EXPORT_SYMBOL(drm_mode_group_init_legacy_group);
1422f453ba04SDave Airlie 
1423f453ba04SDave Airlie /**
1424f453ba04SDave Airlie  * drm_crtc_convert_to_umode - convert a drm_display_mode into a modeinfo
1425f453ba04SDave Airlie  * @out: drm_mode_modeinfo struct to return to the user
1426f453ba04SDave Airlie  * @in: drm_display_mode to use
1427f453ba04SDave Airlie  *
1428f453ba04SDave Airlie  * Convert a drm_display_mode into a drm_mode_modeinfo structure to return to
1429f453ba04SDave Airlie  * the user.
1430f453ba04SDave Airlie  */
143193bbf6dbSVille Syrjälä static void drm_crtc_convert_to_umode(struct drm_mode_modeinfo *out,
143293bbf6dbSVille Syrjälä 				      const struct drm_display_mode *in)
1433f453ba04SDave Airlie {
1434e36fae38SVille Syrjälä 	WARN(in->hdisplay > USHRT_MAX || in->hsync_start > USHRT_MAX ||
1435e36fae38SVille Syrjälä 	     in->hsync_end > USHRT_MAX || in->htotal > USHRT_MAX ||
1436e36fae38SVille Syrjälä 	     in->hskew > USHRT_MAX || in->vdisplay > USHRT_MAX ||
1437e36fae38SVille Syrjälä 	     in->vsync_start > USHRT_MAX || in->vsync_end > USHRT_MAX ||
1438e36fae38SVille Syrjälä 	     in->vtotal > USHRT_MAX || in->vscan > USHRT_MAX,
1439e36fae38SVille Syrjälä 	     "timing values too large for mode info\n");
1440e36fae38SVille Syrjälä 
1441f453ba04SDave Airlie 	out->clock = in->clock;
1442f453ba04SDave Airlie 	out->hdisplay = in->hdisplay;
1443f453ba04SDave Airlie 	out->hsync_start = in->hsync_start;
1444f453ba04SDave Airlie 	out->hsync_end = in->hsync_end;
1445f453ba04SDave Airlie 	out->htotal = in->htotal;
1446f453ba04SDave Airlie 	out->hskew = in->hskew;
1447f453ba04SDave Airlie 	out->vdisplay = in->vdisplay;
1448f453ba04SDave Airlie 	out->vsync_start = in->vsync_start;
1449f453ba04SDave Airlie 	out->vsync_end = in->vsync_end;
1450f453ba04SDave Airlie 	out->vtotal = in->vtotal;
1451f453ba04SDave Airlie 	out->vscan = in->vscan;
1452f453ba04SDave Airlie 	out->vrefresh = in->vrefresh;
1453f453ba04SDave Airlie 	out->flags = in->flags;
1454f453ba04SDave Airlie 	out->type = in->type;
1455f453ba04SDave Airlie 	strncpy(out->name, in->name, DRM_DISPLAY_MODE_LEN);
1456f453ba04SDave Airlie 	out->name[DRM_DISPLAY_MODE_LEN-1] = 0;
1457f453ba04SDave Airlie }
1458f453ba04SDave Airlie 
1459f453ba04SDave Airlie /**
146074afee7dSMarc-André Lureau  * drm_crtc_convert_umode - convert a modeinfo into a drm_display_mode
1461f453ba04SDave Airlie  * @out: drm_display_mode to return to the user
1462f453ba04SDave Airlie  * @in: drm_mode_modeinfo to use
1463f453ba04SDave Airlie  *
1464f453ba04SDave Airlie  * Convert a drm_mode_modeinfo into a drm_display_mode structure to return to
1465f453ba04SDave Airlie  * the caller.
146690367bf6SVille Syrjälä  *
1467c8e32cc1SDaniel Vetter  * Returns:
146890367bf6SVille Syrjälä  * Zero on success, errno on failure.
1469f453ba04SDave Airlie  */
147093bbf6dbSVille Syrjälä static int drm_crtc_convert_umode(struct drm_display_mode *out,
147193bbf6dbSVille Syrjälä 				  const struct drm_mode_modeinfo *in)
1472f453ba04SDave Airlie {
147390367bf6SVille Syrjälä 	if (in->clock > INT_MAX || in->vrefresh > INT_MAX)
147490367bf6SVille Syrjälä 		return -ERANGE;
147590367bf6SVille Syrjälä 
14765848ad40SDamien Lespiau 	if ((in->flags & DRM_MODE_FLAG_3D_MASK) > DRM_MODE_FLAG_3D_MAX)
14775848ad40SDamien Lespiau 		return -EINVAL;
14785848ad40SDamien Lespiau 
1479f453ba04SDave Airlie 	out->clock = in->clock;
1480f453ba04SDave Airlie 	out->hdisplay = in->hdisplay;
1481f453ba04SDave Airlie 	out->hsync_start = in->hsync_start;
1482f453ba04SDave Airlie 	out->hsync_end = in->hsync_end;
1483f453ba04SDave Airlie 	out->htotal = in->htotal;
1484f453ba04SDave Airlie 	out->hskew = in->hskew;
1485f453ba04SDave Airlie 	out->vdisplay = in->vdisplay;
1486f453ba04SDave Airlie 	out->vsync_start = in->vsync_start;
1487f453ba04SDave Airlie 	out->vsync_end = in->vsync_end;
1488f453ba04SDave Airlie 	out->vtotal = in->vtotal;
1489f453ba04SDave Airlie 	out->vscan = in->vscan;
1490f453ba04SDave Airlie 	out->vrefresh = in->vrefresh;
1491f453ba04SDave Airlie 	out->flags = in->flags;
1492f453ba04SDave Airlie 	out->type = in->type;
1493f453ba04SDave Airlie 	strncpy(out->name, in->name, DRM_DISPLAY_MODE_LEN);
1494f453ba04SDave Airlie 	out->name[DRM_DISPLAY_MODE_LEN-1] = 0;
149590367bf6SVille Syrjälä 
149690367bf6SVille Syrjälä 	return 0;
1497f453ba04SDave Airlie }
1498f453ba04SDave Airlie 
1499f453ba04SDave Airlie /**
1500f453ba04SDave Airlie  * drm_mode_getresources - get graphics configuration
1501065a50edSDaniel Vetter  * @dev: drm device for the ioctl
1502065a50edSDaniel Vetter  * @data: data pointer for the ioctl
1503065a50edSDaniel Vetter  * @file_priv: drm file for the ioctl call
1504f453ba04SDave Airlie  *
1505f453ba04SDave Airlie  * Construct a set of configuration description structures and return
1506f453ba04SDave Airlie  * them to the user, including CRTC, connector and framebuffer configuration.
1507f453ba04SDave Airlie  *
1508f453ba04SDave Airlie  * Called by the user via ioctl.
1509f453ba04SDave Airlie  *
1510c8e32cc1SDaniel Vetter  * Returns:
1511f453ba04SDave Airlie  * Zero on success, errno on failure.
1512f453ba04SDave Airlie  */
1513f453ba04SDave Airlie int drm_mode_getresources(struct drm_device *dev, void *data,
1514f453ba04SDave Airlie 			  struct drm_file *file_priv)
1515f453ba04SDave Airlie {
1516f453ba04SDave Airlie 	struct drm_mode_card_res *card_res = data;
1517f453ba04SDave Airlie 	struct list_head *lh;
1518f453ba04SDave Airlie 	struct drm_framebuffer *fb;
1519f453ba04SDave Airlie 	struct drm_connector *connector;
1520f453ba04SDave Airlie 	struct drm_crtc *crtc;
1521f453ba04SDave Airlie 	struct drm_encoder *encoder;
1522f453ba04SDave Airlie 	int ret = 0;
1523f453ba04SDave Airlie 	int connector_count = 0;
1524f453ba04SDave Airlie 	int crtc_count = 0;
1525f453ba04SDave Airlie 	int fb_count = 0;
1526f453ba04SDave Airlie 	int encoder_count = 0;
1527f453ba04SDave Airlie 	int copied = 0, i;
1528f453ba04SDave Airlie 	uint32_t __user *fb_id;
1529f453ba04SDave Airlie 	uint32_t __user *crtc_id;
1530f453ba04SDave Airlie 	uint32_t __user *connector_id;
1531f453ba04SDave Airlie 	uint32_t __user *encoder_id;
1532f453ba04SDave Airlie 	struct drm_mode_group *mode_group;
1533f453ba04SDave Airlie 
1534fb3b06c8SDave Airlie 	if (!drm_core_check_feature(dev, DRIVER_MODESET))
1535fb3b06c8SDave Airlie 		return -EINVAL;
1536fb3b06c8SDave Airlie 
1537f453ba04SDave Airlie 
15384b096ac1SDaniel Vetter 	mutex_lock(&file_priv->fbs_lock);
1539f453ba04SDave Airlie 	/*
1540f453ba04SDave Airlie 	 * For the non-control nodes we need to limit the list of resources
1541f453ba04SDave Airlie 	 * by IDs in the group list for this node
1542f453ba04SDave Airlie 	 */
1543f453ba04SDave Airlie 	list_for_each(lh, &file_priv->fbs)
1544f453ba04SDave Airlie 		fb_count++;
1545f453ba04SDave Airlie 
15464b096ac1SDaniel Vetter 	/* handle this in 4 parts */
15474b096ac1SDaniel Vetter 	/* FBs */
15484b096ac1SDaniel Vetter 	if (card_res->count_fbs >= fb_count) {
15494b096ac1SDaniel Vetter 		copied = 0;
15504b096ac1SDaniel Vetter 		fb_id = (uint32_t __user *)(unsigned long)card_res->fb_id_ptr;
15514b096ac1SDaniel Vetter 		list_for_each_entry(fb, &file_priv->fbs, filp_head) {
15524b096ac1SDaniel Vetter 			if (put_user(fb->base.id, fb_id + copied)) {
15534b096ac1SDaniel Vetter 				mutex_unlock(&file_priv->fbs_lock);
15544b096ac1SDaniel Vetter 				return -EFAULT;
15554b096ac1SDaniel Vetter 			}
15564b096ac1SDaniel Vetter 			copied++;
15574b096ac1SDaniel Vetter 		}
15584b096ac1SDaniel Vetter 	}
15594b096ac1SDaniel Vetter 	card_res->count_fbs = fb_count;
15604b096ac1SDaniel Vetter 	mutex_unlock(&file_priv->fbs_lock);
15614b096ac1SDaniel Vetter 
15624b096ac1SDaniel Vetter 	drm_modeset_lock_all(dev);
156343683057SThomas Hellstrom 	if (!drm_is_primary_client(file_priv)) {
1564f453ba04SDave Airlie 
156509f308f7SThomas Hellstrom 		mode_group = NULL;
1566f453ba04SDave Airlie 		list_for_each(lh, &dev->mode_config.crtc_list)
1567f453ba04SDave Airlie 			crtc_count++;
1568f453ba04SDave Airlie 
1569f453ba04SDave Airlie 		list_for_each(lh, &dev->mode_config.connector_list)
1570f453ba04SDave Airlie 			connector_count++;
1571f453ba04SDave Airlie 
1572f453ba04SDave Airlie 		list_for_each(lh, &dev->mode_config.encoder_list)
1573f453ba04SDave Airlie 			encoder_count++;
1574f453ba04SDave Airlie 	} else {
1575f453ba04SDave Airlie 
157609f308f7SThomas Hellstrom 		mode_group = &file_priv->master->minor->mode_group;
1577f453ba04SDave Airlie 		crtc_count = mode_group->num_crtcs;
1578f453ba04SDave Airlie 		connector_count = mode_group->num_connectors;
1579f453ba04SDave Airlie 		encoder_count = mode_group->num_encoders;
1580f453ba04SDave Airlie 	}
1581f453ba04SDave Airlie 
1582f453ba04SDave Airlie 	card_res->max_height = dev->mode_config.max_height;
1583f453ba04SDave Airlie 	card_res->min_height = dev->mode_config.min_height;
1584f453ba04SDave Airlie 	card_res->max_width = dev->mode_config.max_width;
1585f453ba04SDave Airlie 	card_res->min_width = dev->mode_config.min_width;
1586f453ba04SDave Airlie 
1587f453ba04SDave Airlie 	/* CRTCs */
1588f453ba04SDave Airlie 	if (card_res->count_crtcs >= crtc_count) {
1589f453ba04SDave Airlie 		copied = 0;
1590f453ba04SDave Airlie 		crtc_id = (uint32_t __user *)(unsigned long)card_res->crtc_id_ptr;
159109f308f7SThomas Hellstrom 		if (!mode_group) {
1592f453ba04SDave Airlie 			list_for_each_entry(crtc, &dev->mode_config.crtc_list,
1593f453ba04SDave Airlie 					    head) {
15949440106bSJerome Glisse 				DRM_DEBUG_KMS("[CRTC:%d]\n", crtc->base.id);
1595f453ba04SDave Airlie 				if (put_user(crtc->base.id, crtc_id + copied)) {
1596f453ba04SDave Airlie 					ret = -EFAULT;
1597f453ba04SDave Airlie 					goto out;
1598f453ba04SDave Airlie 				}
1599f453ba04SDave Airlie 				copied++;
1600f453ba04SDave Airlie 			}
1601f453ba04SDave Airlie 		} else {
1602f453ba04SDave Airlie 			for (i = 0; i < mode_group->num_crtcs; i++) {
1603f453ba04SDave Airlie 				if (put_user(mode_group->id_list[i],
1604f453ba04SDave Airlie 					     crtc_id + copied)) {
1605f453ba04SDave Airlie 					ret = -EFAULT;
1606f453ba04SDave Airlie 					goto out;
1607f453ba04SDave Airlie 				}
1608f453ba04SDave Airlie 				copied++;
1609f453ba04SDave Airlie 			}
1610f453ba04SDave Airlie 		}
1611f453ba04SDave Airlie 	}
1612f453ba04SDave Airlie 	card_res->count_crtcs = crtc_count;
1613f453ba04SDave Airlie 
1614f453ba04SDave Airlie 	/* Encoders */
1615f453ba04SDave Airlie 	if (card_res->count_encoders >= encoder_count) {
1616f453ba04SDave Airlie 		copied = 0;
1617f453ba04SDave Airlie 		encoder_id = (uint32_t __user *)(unsigned long)card_res->encoder_id_ptr;
161809f308f7SThomas Hellstrom 		if (!mode_group) {
1619f453ba04SDave Airlie 			list_for_each_entry(encoder,
1620f453ba04SDave Airlie 					    &dev->mode_config.encoder_list,
1621f453ba04SDave Airlie 					    head) {
16229440106bSJerome Glisse 				DRM_DEBUG_KMS("[ENCODER:%d:%s]\n", encoder->base.id,
16239440106bSJerome Glisse 						drm_get_encoder_name(encoder));
1624f453ba04SDave Airlie 				if (put_user(encoder->base.id, encoder_id +
1625f453ba04SDave Airlie 					     copied)) {
1626f453ba04SDave Airlie 					ret = -EFAULT;
1627f453ba04SDave Airlie 					goto out;
1628f453ba04SDave Airlie 				}
1629f453ba04SDave Airlie 				copied++;
1630f453ba04SDave Airlie 			}
1631f453ba04SDave Airlie 		} else {
1632f453ba04SDave Airlie 			for (i = mode_group->num_crtcs; i < mode_group->num_crtcs + mode_group->num_encoders; i++) {
1633f453ba04SDave Airlie 				if (put_user(mode_group->id_list[i],
1634f453ba04SDave Airlie 					     encoder_id + copied)) {
1635f453ba04SDave Airlie 					ret = -EFAULT;
1636f453ba04SDave Airlie 					goto out;
1637f453ba04SDave Airlie 				}
1638f453ba04SDave Airlie 				copied++;
1639f453ba04SDave Airlie 			}
1640f453ba04SDave Airlie 
1641f453ba04SDave Airlie 		}
1642f453ba04SDave Airlie 	}
1643f453ba04SDave Airlie 	card_res->count_encoders = encoder_count;
1644f453ba04SDave Airlie 
1645f453ba04SDave Airlie 	/* Connectors */
1646f453ba04SDave Airlie 	if (card_res->count_connectors >= connector_count) {
1647f453ba04SDave Airlie 		copied = 0;
1648f453ba04SDave Airlie 		connector_id = (uint32_t __user *)(unsigned long)card_res->connector_id_ptr;
164909f308f7SThomas Hellstrom 		if (!mode_group) {
1650f453ba04SDave Airlie 			list_for_each_entry(connector,
1651f453ba04SDave Airlie 					    &dev->mode_config.connector_list,
1652f453ba04SDave Airlie 					    head) {
16539440106bSJerome Glisse 				DRM_DEBUG_KMS("[CONNECTOR:%d:%s]\n",
16549440106bSJerome Glisse 					connector->base.id,
16559440106bSJerome Glisse 					drm_get_connector_name(connector));
1656f453ba04SDave Airlie 				if (put_user(connector->base.id,
1657f453ba04SDave Airlie 					     connector_id + copied)) {
1658f453ba04SDave Airlie 					ret = -EFAULT;
1659f453ba04SDave Airlie 					goto out;
1660f453ba04SDave Airlie 				}
1661f453ba04SDave Airlie 				copied++;
1662f453ba04SDave Airlie 			}
1663f453ba04SDave Airlie 		} else {
1664f453ba04SDave Airlie 			int start = mode_group->num_crtcs +
1665f453ba04SDave Airlie 				mode_group->num_encoders;
1666f453ba04SDave Airlie 			for (i = start; i < start + mode_group->num_connectors; i++) {
1667f453ba04SDave Airlie 				if (put_user(mode_group->id_list[i],
1668f453ba04SDave Airlie 					     connector_id + copied)) {
1669f453ba04SDave Airlie 					ret = -EFAULT;
1670f453ba04SDave Airlie 					goto out;
1671f453ba04SDave Airlie 				}
1672f453ba04SDave Airlie 				copied++;
1673f453ba04SDave Airlie 			}
1674f453ba04SDave Airlie 		}
1675f453ba04SDave Airlie 	}
1676f453ba04SDave Airlie 	card_res->count_connectors = connector_count;
1677f453ba04SDave Airlie 
16789440106bSJerome Glisse 	DRM_DEBUG_KMS("CRTC[%d] CONNECTORS[%d] ENCODERS[%d]\n", card_res->count_crtcs,
1679f453ba04SDave Airlie 		  card_res->count_connectors, card_res->count_encoders);
1680f453ba04SDave Airlie 
1681f453ba04SDave Airlie out:
168284849903SDaniel Vetter 	drm_modeset_unlock_all(dev);
1683f453ba04SDave Airlie 	return ret;
1684f453ba04SDave Airlie }
1685f453ba04SDave Airlie 
1686f453ba04SDave Airlie /**
1687f453ba04SDave Airlie  * drm_mode_getcrtc - get CRTC configuration
1688065a50edSDaniel Vetter  * @dev: drm device for the ioctl
1689065a50edSDaniel Vetter  * @data: data pointer for the ioctl
1690065a50edSDaniel Vetter  * @file_priv: drm file for the ioctl call
1691f453ba04SDave Airlie  *
1692f453ba04SDave Airlie  * Construct a CRTC configuration structure to return to the user.
1693f453ba04SDave Airlie  *
1694f453ba04SDave Airlie  * Called by the user via ioctl.
1695f453ba04SDave Airlie  *
1696c8e32cc1SDaniel Vetter  * Returns:
1697f453ba04SDave Airlie  * Zero on success, errno on failure.
1698f453ba04SDave Airlie  */
1699f453ba04SDave Airlie int drm_mode_getcrtc(struct drm_device *dev,
1700f453ba04SDave Airlie 		     void *data, struct drm_file *file_priv)
1701f453ba04SDave Airlie {
1702f453ba04SDave Airlie 	struct drm_mode_crtc *crtc_resp = data;
1703f453ba04SDave Airlie 	struct drm_crtc *crtc;
1704f453ba04SDave Airlie 	struct drm_mode_object *obj;
1705f453ba04SDave Airlie 	int ret = 0;
1706f453ba04SDave Airlie 
1707fb3b06c8SDave Airlie 	if (!drm_core_check_feature(dev, DRIVER_MODESET))
1708fb3b06c8SDave Airlie 		return -EINVAL;
1709fb3b06c8SDave Airlie 
171084849903SDaniel Vetter 	drm_modeset_lock_all(dev);
1711f453ba04SDave Airlie 
1712f453ba04SDave Airlie 	obj = drm_mode_object_find(dev, crtc_resp->crtc_id,
1713f453ba04SDave Airlie 				   DRM_MODE_OBJECT_CRTC);
1714f453ba04SDave Airlie 	if (!obj) {
1715f27657f2SVille Syrjälä 		ret = -ENOENT;
1716f453ba04SDave Airlie 		goto out;
1717f453ba04SDave Airlie 	}
1718f453ba04SDave Airlie 	crtc = obj_to_crtc(obj);
1719f453ba04SDave Airlie 
1720f453ba04SDave Airlie 	crtc_resp->x = crtc->x;
1721f453ba04SDave Airlie 	crtc_resp->y = crtc->y;
1722f453ba04SDave Airlie 	crtc_resp->gamma_size = crtc->gamma_size;
1723f4510a27SMatt Roper 	if (crtc->primary->fb)
1724f4510a27SMatt Roper 		crtc_resp->fb_id = crtc->primary->fb->base.id;
1725f453ba04SDave Airlie 	else
1726f453ba04SDave Airlie 		crtc_resp->fb_id = 0;
1727f453ba04SDave Airlie 
1728f453ba04SDave Airlie 	if (crtc->enabled) {
1729f453ba04SDave Airlie 
1730f453ba04SDave Airlie 		drm_crtc_convert_to_umode(&crtc_resp->mode, &crtc->mode);
1731f453ba04SDave Airlie 		crtc_resp->mode_valid = 1;
1732f453ba04SDave Airlie 
1733f453ba04SDave Airlie 	} else {
1734f453ba04SDave Airlie 		crtc_resp->mode_valid = 0;
1735f453ba04SDave Airlie 	}
1736f453ba04SDave Airlie 
1737f453ba04SDave Airlie out:
173884849903SDaniel Vetter 	drm_modeset_unlock_all(dev);
1739f453ba04SDave Airlie 	return ret;
1740f453ba04SDave Airlie }
1741f453ba04SDave Airlie 
174261d8e328SDamien Lespiau static bool drm_mode_expose_to_userspace(const struct drm_display_mode *mode,
174361d8e328SDamien Lespiau 					 const struct drm_file *file_priv)
174461d8e328SDamien Lespiau {
174561d8e328SDamien Lespiau 	/*
174661d8e328SDamien Lespiau 	 * If user-space hasn't configured the driver to expose the stereo 3D
174761d8e328SDamien Lespiau 	 * modes, don't expose them.
174861d8e328SDamien Lespiau 	 */
174961d8e328SDamien Lespiau 	if (!file_priv->stereo_allowed && drm_mode_is_stereo(mode))
175061d8e328SDamien Lespiau 		return false;
175161d8e328SDamien Lespiau 
175261d8e328SDamien Lespiau 	return true;
175361d8e328SDamien Lespiau }
175461d8e328SDamien Lespiau 
1755f453ba04SDave Airlie /**
1756f453ba04SDave Airlie  * drm_mode_getconnector - get connector configuration
1757065a50edSDaniel Vetter  * @dev: drm device for the ioctl
1758065a50edSDaniel Vetter  * @data: data pointer for the ioctl
1759065a50edSDaniel Vetter  * @file_priv: drm file for the ioctl call
1760f453ba04SDave Airlie  *
1761f453ba04SDave Airlie  * Construct a connector configuration structure to return to the user.
1762f453ba04SDave Airlie  *
1763f453ba04SDave Airlie  * Called by the user via ioctl.
1764f453ba04SDave Airlie  *
1765c8e32cc1SDaniel Vetter  * Returns:
1766f453ba04SDave Airlie  * Zero on success, errno on failure.
1767f453ba04SDave Airlie  */
1768f453ba04SDave Airlie int drm_mode_getconnector(struct drm_device *dev, void *data,
1769f453ba04SDave Airlie 			  struct drm_file *file_priv)
1770f453ba04SDave Airlie {
1771f453ba04SDave Airlie 	struct drm_mode_get_connector *out_resp = data;
1772f453ba04SDave Airlie 	struct drm_mode_object *obj;
1773f453ba04SDave Airlie 	struct drm_connector *connector;
1774f453ba04SDave Airlie 	struct drm_display_mode *mode;
1775f453ba04SDave Airlie 	int mode_count = 0;
1776f453ba04SDave Airlie 	int props_count = 0;
1777f453ba04SDave Airlie 	int encoders_count = 0;
1778f453ba04SDave Airlie 	int ret = 0;
1779f453ba04SDave Airlie 	int copied = 0;
1780f453ba04SDave Airlie 	int i;
1781f453ba04SDave Airlie 	struct drm_mode_modeinfo u_mode;
1782f453ba04SDave Airlie 	struct drm_mode_modeinfo __user *mode_ptr;
1783f453ba04SDave Airlie 	uint32_t __user *prop_ptr;
1784f453ba04SDave Airlie 	uint64_t __user *prop_values;
1785f453ba04SDave Airlie 	uint32_t __user *encoder_ptr;
1786f453ba04SDave Airlie 
1787fb3b06c8SDave Airlie 	if (!drm_core_check_feature(dev, DRIVER_MODESET))
1788fb3b06c8SDave Airlie 		return -EINVAL;
1789fb3b06c8SDave Airlie 
1790f453ba04SDave Airlie 	memset(&u_mode, 0, sizeof(struct drm_mode_modeinfo));
1791f453ba04SDave Airlie 
17929440106bSJerome Glisse 	DRM_DEBUG_KMS("[CONNECTOR:%d:?]\n", out_resp->connector_id);
1793f453ba04SDave Airlie 
17947b24056bSDaniel Vetter 	mutex_lock(&dev->mode_config.mutex);
1795f453ba04SDave Airlie 
1796f453ba04SDave Airlie 	obj = drm_mode_object_find(dev, out_resp->connector_id,
1797f453ba04SDave Airlie 				   DRM_MODE_OBJECT_CONNECTOR);
1798f453ba04SDave Airlie 	if (!obj) {
1799f27657f2SVille Syrjälä 		ret = -ENOENT;
1800f453ba04SDave Airlie 		goto out;
1801f453ba04SDave Airlie 	}
1802f453ba04SDave Airlie 	connector = obj_to_connector(obj);
1803f453ba04SDave Airlie 
18047f88a9beSPaulo Zanoni 	props_count = connector->properties.count;
1805f453ba04SDave Airlie 
1806f453ba04SDave Airlie 	for (i = 0; i < DRM_CONNECTOR_MAX_ENCODER; i++) {
1807f453ba04SDave Airlie 		if (connector->encoder_ids[i] != 0) {
1808f453ba04SDave Airlie 			encoders_count++;
1809f453ba04SDave Airlie 		}
1810f453ba04SDave Airlie 	}
1811f453ba04SDave Airlie 
1812f453ba04SDave Airlie 	if (out_resp->count_modes == 0) {
1813f453ba04SDave Airlie 		connector->funcs->fill_modes(connector,
1814f453ba04SDave Airlie 					     dev->mode_config.max_width,
1815f453ba04SDave Airlie 					     dev->mode_config.max_height);
1816f453ba04SDave Airlie 	}
1817f453ba04SDave Airlie 
1818f453ba04SDave Airlie 	/* delayed so we get modes regardless of pre-fill_modes state */
1819f453ba04SDave Airlie 	list_for_each_entry(mode, &connector->modes, head)
182061d8e328SDamien Lespiau 		if (drm_mode_expose_to_userspace(mode, file_priv))
1821f453ba04SDave Airlie 			mode_count++;
1822f453ba04SDave Airlie 
1823f453ba04SDave Airlie 	out_resp->connector_id = connector->base.id;
1824f453ba04SDave Airlie 	out_resp->connector_type = connector->connector_type;
1825f453ba04SDave Airlie 	out_resp->connector_type_id = connector->connector_type_id;
1826f453ba04SDave Airlie 	out_resp->mm_width = connector->display_info.width_mm;
1827f453ba04SDave Airlie 	out_resp->mm_height = connector->display_info.height_mm;
1828f453ba04SDave Airlie 	out_resp->subpixel = connector->display_info.subpixel_order;
1829f453ba04SDave Airlie 	out_resp->connection = connector->status;
1830f453ba04SDave Airlie 	if (connector->encoder)
1831f453ba04SDave Airlie 		out_resp->encoder_id = connector->encoder->base.id;
1832f453ba04SDave Airlie 	else
1833f453ba04SDave Airlie 		out_resp->encoder_id = 0;
1834f453ba04SDave Airlie 
1835f453ba04SDave Airlie 	/*
1836f453ba04SDave Airlie 	 * This ioctl is called twice, once to determine how much space is
1837f453ba04SDave Airlie 	 * needed, and the 2nd time to fill it.
1838f453ba04SDave Airlie 	 */
1839f453ba04SDave Airlie 	if ((out_resp->count_modes >= mode_count) && mode_count) {
1840f453ba04SDave Airlie 		copied = 0;
184181f6c7f8SVille Syrjälä 		mode_ptr = (struct drm_mode_modeinfo __user *)(unsigned long)out_resp->modes_ptr;
1842f453ba04SDave Airlie 		list_for_each_entry(mode, &connector->modes, head) {
184361d8e328SDamien Lespiau 			if (!drm_mode_expose_to_userspace(mode, file_priv))
184461d8e328SDamien Lespiau 				continue;
184561d8e328SDamien Lespiau 
1846f453ba04SDave Airlie 			drm_crtc_convert_to_umode(&u_mode, mode);
1847f453ba04SDave Airlie 			if (copy_to_user(mode_ptr + copied,
1848f453ba04SDave Airlie 					 &u_mode, sizeof(u_mode))) {
1849f453ba04SDave Airlie 				ret = -EFAULT;
1850f453ba04SDave Airlie 				goto out;
1851f453ba04SDave Airlie 			}
1852f453ba04SDave Airlie 			copied++;
1853f453ba04SDave Airlie 		}
1854f453ba04SDave Airlie 	}
1855f453ba04SDave Airlie 	out_resp->count_modes = mode_count;
1856f453ba04SDave Airlie 
1857f453ba04SDave Airlie 	if ((out_resp->count_props >= props_count) && props_count) {
1858f453ba04SDave Airlie 		copied = 0;
185981f6c7f8SVille Syrjälä 		prop_ptr = (uint32_t __user *)(unsigned long)(out_resp->props_ptr);
186081f6c7f8SVille Syrjälä 		prop_values = (uint64_t __user *)(unsigned long)(out_resp->prop_values_ptr);
18617f88a9beSPaulo Zanoni 		for (i = 0; i < connector->properties.count; i++) {
18627e3bdf4aSPaulo Zanoni 			if (put_user(connector->properties.ids[i],
1863f453ba04SDave Airlie 				     prop_ptr + copied)) {
1864f453ba04SDave Airlie 				ret = -EFAULT;
1865f453ba04SDave Airlie 				goto out;
1866f453ba04SDave Airlie 			}
1867f453ba04SDave Airlie 
18687e3bdf4aSPaulo Zanoni 			if (put_user(connector->properties.values[i],
1869f453ba04SDave Airlie 				     prop_values + copied)) {
1870f453ba04SDave Airlie 				ret = -EFAULT;
1871f453ba04SDave Airlie 				goto out;
1872f453ba04SDave Airlie 			}
1873f453ba04SDave Airlie 			copied++;
1874f453ba04SDave Airlie 		}
1875f453ba04SDave Airlie 	}
1876f453ba04SDave Airlie 	out_resp->count_props = props_count;
1877f453ba04SDave Airlie 
1878f453ba04SDave Airlie 	if ((out_resp->count_encoders >= encoders_count) && encoders_count) {
1879f453ba04SDave Airlie 		copied = 0;
188081f6c7f8SVille Syrjälä 		encoder_ptr = (uint32_t __user *)(unsigned long)(out_resp->encoders_ptr);
1881f453ba04SDave Airlie 		for (i = 0; i < DRM_CONNECTOR_MAX_ENCODER; i++) {
1882f453ba04SDave Airlie 			if (connector->encoder_ids[i] != 0) {
1883f453ba04SDave Airlie 				if (put_user(connector->encoder_ids[i],
1884f453ba04SDave Airlie 					     encoder_ptr + copied)) {
1885f453ba04SDave Airlie 					ret = -EFAULT;
1886f453ba04SDave Airlie 					goto out;
1887f453ba04SDave Airlie 				}
1888f453ba04SDave Airlie 				copied++;
1889f453ba04SDave Airlie 			}
1890f453ba04SDave Airlie 		}
1891f453ba04SDave Airlie 	}
1892f453ba04SDave Airlie 	out_resp->count_encoders = encoders_count;
1893f453ba04SDave Airlie 
1894f453ba04SDave Airlie out:
18957b24056bSDaniel Vetter 	mutex_unlock(&dev->mode_config.mutex);
18967b24056bSDaniel Vetter 
1897f453ba04SDave Airlie 	return ret;
1898f453ba04SDave Airlie }
1899f453ba04SDave Airlie 
1900c8e32cc1SDaniel Vetter /**
1901c8e32cc1SDaniel Vetter  * drm_mode_getencoder - get encoder configuration
1902c8e32cc1SDaniel Vetter  * @dev: drm device for the ioctl
1903c8e32cc1SDaniel Vetter  * @data: data pointer for the ioctl
1904c8e32cc1SDaniel Vetter  * @file_priv: drm file for the ioctl call
1905c8e32cc1SDaniel Vetter  *
1906c8e32cc1SDaniel Vetter  * Construct a encoder configuration structure to return to the user.
1907c8e32cc1SDaniel Vetter  *
1908c8e32cc1SDaniel Vetter  * Called by the user via ioctl.
1909c8e32cc1SDaniel Vetter  *
1910c8e32cc1SDaniel Vetter  * Returns:
1911c8e32cc1SDaniel Vetter  * Zero on success, errno on failure.
1912c8e32cc1SDaniel Vetter  */
1913f453ba04SDave Airlie int drm_mode_getencoder(struct drm_device *dev, void *data,
1914f453ba04SDave Airlie 			struct drm_file *file_priv)
1915f453ba04SDave Airlie {
1916f453ba04SDave Airlie 	struct drm_mode_get_encoder *enc_resp = data;
1917f453ba04SDave Airlie 	struct drm_mode_object *obj;
1918f453ba04SDave Airlie 	struct drm_encoder *encoder;
1919f453ba04SDave Airlie 	int ret = 0;
1920f453ba04SDave Airlie 
1921fb3b06c8SDave Airlie 	if (!drm_core_check_feature(dev, DRIVER_MODESET))
1922fb3b06c8SDave Airlie 		return -EINVAL;
1923fb3b06c8SDave Airlie 
192484849903SDaniel Vetter 	drm_modeset_lock_all(dev);
1925f453ba04SDave Airlie 	obj = drm_mode_object_find(dev, enc_resp->encoder_id,
1926f453ba04SDave Airlie 				   DRM_MODE_OBJECT_ENCODER);
1927f453ba04SDave Airlie 	if (!obj) {
1928f27657f2SVille Syrjälä 		ret = -ENOENT;
1929f453ba04SDave Airlie 		goto out;
1930f453ba04SDave Airlie 	}
1931f453ba04SDave Airlie 	encoder = obj_to_encoder(obj);
1932f453ba04SDave Airlie 
1933f453ba04SDave Airlie 	if (encoder->crtc)
1934f453ba04SDave Airlie 		enc_resp->crtc_id = encoder->crtc->base.id;
1935f453ba04SDave Airlie 	else
1936f453ba04SDave Airlie 		enc_resp->crtc_id = 0;
1937f453ba04SDave Airlie 	enc_resp->encoder_type = encoder->encoder_type;
1938f453ba04SDave Airlie 	enc_resp->encoder_id = encoder->base.id;
1939f453ba04SDave Airlie 	enc_resp->possible_crtcs = encoder->possible_crtcs;
1940f453ba04SDave Airlie 	enc_resp->possible_clones = encoder->possible_clones;
1941f453ba04SDave Airlie 
1942f453ba04SDave Airlie out:
194384849903SDaniel Vetter 	drm_modeset_unlock_all(dev);
1944f453ba04SDave Airlie 	return ret;
1945f453ba04SDave Airlie }
1946f453ba04SDave Airlie 
1947f453ba04SDave Airlie /**
1948c8e32cc1SDaniel Vetter  * drm_mode_getplane_res - enumerate all plane resources
19498cf5c917SJesse Barnes  * @dev: DRM device
19508cf5c917SJesse Barnes  * @data: ioctl data
19518cf5c917SJesse Barnes  * @file_priv: DRM file info
19528cf5c917SJesse Barnes  *
1953c8e32cc1SDaniel Vetter  * Construct a list of plane ids to return to the user.
1954c8e32cc1SDaniel Vetter  *
1955c8e32cc1SDaniel Vetter  * Called by the user via ioctl.
1956c8e32cc1SDaniel Vetter  *
1957c8e32cc1SDaniel Vetter  * Returns:
1958c8e32cc1SDaniel Vetter  * Zero on success, errno on failure.
19598cf5c917SJesse Barnes  */
19608cf5c917SJesse Barnes int drm_mode_getplane_res(struct drm_device *dev, void *data,
19618cf5c917SJesse Barnes 			  struct drm_file *file_priv)
19628cf5c917SJesse Barnes {
19638cf5c917SJesse Barnes 	struct drm_mode_get_plane_res *plane_resp = data;
19648cf5c917SJesse Barnes 	struct drm_mode_config *config;
19658cf5c917SJesse Barnes 	struct drm_plane *plane;
19668cf5c917SJesse Barnes 	uint32_t __user *plane_ptr;
19678cf5c917SJesse Barnes 	int copied = 0, ret = 0;
1968681e7ec7SMatt Roper 	unsigned num_planes;
19698cf5c917SJesse Barnes 
19708cf5c917SJesse Barnes 	if (!drm_core_check_feature(dev, DRIVER_MODESET))
19718cf5c917SJesse Barnes 		return -EINVAL;
19728cf5c917SJesse Barnes 
197384849903SDaniel Vetter 	drm_modeset_lock_all(dev);
19748cf5c917SJesse Barnes 	config = &dev->mode_config;
19758cf5c917SJesse Barnes 
1976681e7ec7SMatt Roper 	if (file_priv->universal_planes)
1977681e7ec7SMatt Roper 		num_planes = config->num_total_plane;
1978681e7ec7SMatt Roper 	else
1979681e7ec7SMatt Roper 		num_planes = config->num_overlay_plane;
1980681e7ec7SMatt Roper 
19818cf5c917SJesse Barnes 	/*
19828cf5c917SJesse Barnes 	 * This ioctl is called twice, once to determine how much space is
19838cf5c917SJesse Barnes 	 * needed, and the 2nd time to fill it.
19848cf5c917SJesse Barnes 	 */
1985681e7ec7SMatt Roper 	if (num_planes &&
1986681e7ec7SMatt Roper 	    (plane_resp->count_planes >= num_planes)) {
198781f6c7f8SVille Syrjälä 		plane_ptr = (uint32_t __user *)(unsigned long)plane_resp->plane_id_ptr;
19888cf5c917SJesse Barnes 
19898cf5c917SJesse Barnes 		list_for_each_entry(plane, &config->plane_list, head) {
1990681e7ec7SMatt Roper 			/*
1991681e7ec7SMatt Roper 			 * Unless userspace set the 'universal planes'
1992681e7ec7SMatt Roper 			 * capability bit, only advertise overlays.
1993681e7ec7SMatt Roper 			 */
1994681e7ec7SMatt Roper 			if (plane->type != DRM_PLANE_TYPE_OVERLAY &&
1995681e7ec7SMatt Roper 			    !file_priv->universal_planes)
1996e27dde3eSMatt Roper 				continue;
1997e27dde3eSMatt Roper 
19988cf5c917SJesse Barnes 			if (put_user(plane->base.id, plane_ptr + copied)) {
19998cf5c917SJesse Barnes 				ret = -EFAULT;
20008cf5c917SJesse Barnes 				goto out;
20018cf5c917SJesse Barnes 			}
20028cf5c917SJesse Barnes 			copied++;
20038cf5c917SJesse Barnes 		}
20048cf5c917SJesse Barnes 	}
2005681e7ec7SMatt Roper 	plane_resp->count_planes = num_planes;
20068cf5c917SJesse Barnes 
20078cf5c917SJesse Barnes out:
200884849903SDaniel Vetter 	drm_modeset_unlock_all(dev);
20098cf5c917SJesse Barnes 	return ret;
20108cf5c917SJesse Barnes }
20118cf5c917SJesse Barnes 
20128cf5c917SJesse Barnes /**
2013c8e32cc1SDaniel Vetter  * drm_mode_getplane - get plane configuration
20148cf5c917SJesse Barnes  * @dev: DRM device
20158cf5c917SJesse Barnes  * @data: ioctl data
20168cf5c917SJesse Barnes  * @file_priv: DRM file info
20178cf5c917SJesse Barnes  *
2018c8e32cc1SDaniel Vetter  * Construct a plane configuration structure to return to the user.
2019c8e32cc1SDaniel Vetter  *
2020c8e32cc1SDaniel Vetter  * Called by the user via ioctl.
2021c8e32cc1SDaniel Vetter  *
2022c8e32cc1SDaniel Vetter  * Returns:
2023c8e32cc1SDaniel Vetter  * Zero on success, errno on failure.
20248cf5c917SJesse Barnes  */
20258cf5c917SJesse Barnes int drm_mode_getplane(struct drm_device *dev, void *data,
20268cf5c917SJesse Barnes 		      struct drm_file *file_priv)
20278cf5c917SJesse Barnes {
20288cf5c917SJesse Barnes 	struct drm_mode_get_plane *plane_resp = data;
20298cf5c917SJesse Barnes 	struct drm_mode_object *obj;
20308cf5c917SJesse Barnes 	struct drm_plane *plane;
20318cf5c917SJesse Barnes 	uint32_t __user *format_ptr;
20328cf5c917SJesse Barnes 	int ret = 0;
20338cf5c917SJesse Barnes 
20348cf5c917SJesse Barnes 	if (!drm_core_check_feature(dev, DRIVER_MODESET))
20358cf5c917SJesse Barnes 		return -EINVAL;
20368cf5c917SJesse Barnes 
203784849903SDaniel Vetter 	drm_modeset_lock_all(dev);
20388cf5c917SJesse Barnes 	obj = drm_mode_object_find(dev, plane_resp->plane_id,
20398cf5c917SJesse Barnes 				   DRM_MODE_OBJECT_PLANE);
20408cf5c917SJesse Barnes 	if (!obj) {
20418cf5c917SJesse Barnes 		ret = -ENOENT;
20428cf5c917SJesse Barnes 		goto out;
20438cf5c917SJesse Barnes 	}
20448cf5c917SJesse Barnes 	plane = obj_to_plane(obj);
20458cf5c917SJesse Barnes 
20468cf5c917SJesse Barnes 	if (plane->crtc)
20478cf5c917SJesse Barnes 		plane_resp->crtc_id = plane->crtc->base.id;
20488cf5c917SJesse Barnes 	else
20498cf5c917SJesse Barnes 		plane_resp->crtc_id = 0;
20508cf5c917SJesse Barnes 
20518cf5c917SJesse Barnes 	if (plane->fb)
20528cf5c917SJesse Barnes 		plane_resp->fb_id = plane->fb->base.id;
20538cf5c917SJesse Barnes 	else
20548cf5c917SJesse Barnes 		plane_resp->fb_id = 0;
20558cf5c917SJesse Barnes 
20568cf5c917SJesse Barnes 	plane_resp->plane_id = plane->base.id;
20578cf5c917SJesse Barnes 	plane_resp->possible_crtcs = plane->possible_crtcs;
2058778ad903SVille Syrjälä 	plane_resp->gamma_size = 0;
20598cf5c917SJesse Barnes 
20608cf5c917SJesse Barnes 	/*
20618cf5c917SJesse Barnes 	 * This ioctl is called twice, once to determine how much space is
20628cf5c917SJesse Barnes 	 * needed, and the 2nd time to fill it.
20638cf5c917SJesse Barnes 	 */
20648cf5c917SJesse Barnes 	if (plane->format_count &&
20658cf5c917SJesse Barnes 	    (plane_resp->count_format_types >= plane->format_count)) {
206681f6c7f8SVille Syrjälä 		format_ptr = (uint32_t __user *)(unsigned long)plane_resp->format_type_ptr;
20678cf5c917SJesse Barnes 		if (copy_to_user(format_ptr,
20688cf5c917SJesse Barnes 				 plane->format_types,
20698cf5c917SJesse Barnes 				 sizeof(uint32_t) * plane->format_count)) {
20708cf5c917SJesse Barnes 			ret = -EFAULT;
20718cf5c917SJesse Barnes 			goto out;
20728cf5c917SJesse Barnes 		}
20738cf5c917SJesse Barnes 	}
20748cf5c917SJesse Barnes 	plane_resp->count_format_types = plane->format_count;
20758cf5c917SJesse Barnes 
20768cf5c917SJesse Barnes out:
207784849903SDaniel Vetter 	drm_modeset_unlock_all(dev);
20788cf5c917SJesse Barnes 	return ret;
20798cf5c917SJesse Barnes }
20808cf5c917SJesse Barnes 
20818cf5c917SJesse Barnes /**
2082c8e32cc1SDaniel Vetter  * drm_mode_setplane - configure a plane's configuration
20838cf5c917SJesse Barnes  * @dev: DRM device
20848cf5c917SJesse Barnes  * @data: ioctl data*
2085065a50edSDaniel Vetter  * @file_priv: DRM file info
20868cf5c917SJesse Barnes  *
2087c8e32cc1SDaniel Vetter  * Set plane configuration, including placement, fb, scaling, and other factors.
20888cf5c917SJesse Barnes  * Or pass a NULL fb to disable.
2089c8e32cc1SDaniel Vetter  *
2090c8e32cc1SDaniel Vetter  * Returns:
2091c8e32cc1SDaniel Vetter  * Zero on success, errno on failure.
20928cf5c917SJesse Barnes  */
20938cf5c917SJesse Barnes int drm_mode_setplane(struct drm_device *dev, void *data,
20948cf5c917SJesse Barnes 		      struct drm_file *file_priv)
20958cf5c917SJesse Barnes {
20968cf5c917SJesse Barnes 	struct drm_mode_set_plane *plane_req = data;
20978cf5c917SJesse Barnes 	struct drm_mode_object *obj;
20988cf5c917SJesse Barnes 	struct drm_plane *plane;
20998cf5c917SJesse Barnes 	struct drm_crtc *crtc;
21006c2a7532SDaniel Vetter 	struct drm_framebuffer *fb = NULL, *old_fb = NULL;
21018cf5c917SJesse Barnes 	int ret = 0;
210242ef8789SVille Syrjälä 	unsigned int fb_width, fb_height;
210362443be6SVille Syrjälä 	int i;
21048cf5c917SJesse Barnes 
21058cf5c917SJesse Barnes 	if (!drm_core_check_feature(dev, DRIVER_MODESET))
21068cf5c917SJesse Barnes 		return -EINVAL;
21078cf5c917SJesse Barnes 
21088cf5c917SJesse Barnes 	/*
21098cf5c917SJesse Barnes 	 * First, find the plane, crtc, and fb objects.  If not available,
21108cf5c917SJesse Barnes 	 * we don't bother to call the driver.
21118cf5c917SJesse Barnes 	 */
21128cf5c917SJesse Barnes 	obj = drm_mode_object_find(dev, plane_req->plane_id,
21138cf5c917SJesse Barnes 				   DRM_MODE_OBJECT_PLANE);
21148cf5c917SJesse Barnes 	if (!obj) {
21158cf5c917SJesse Barnes 		DRM_DEBUG_KMS("Unknown plane ID %d\n",
21168cf5c917SJesse Barnes 			      plane_req->plane_id);
21176c2a7532SDaniel Vetter 		return -ENOENT;
21188cf5c917SJesse Barnes 	}
21198cf5c917SJesse Barnes 	plane = obj_to_plane(obj);
21208cf5c917SJesse Barnes 
21218cf5c917SJesse Barnes 	/* No fb means shut it down */
21228cf5c917SJesse Barnes 	if (!plane_req->fb_id) {
21236c2a7532SDaniel Vetter 		drm_modeset_lock_all(dev);
21246c2a7532SDaniel Vetter 		old_fb = plane->fb;
21258cf5c917SJesse Barnes 		plane->funcs->disable_plane(plane);
2126e5e3b44cSVille Syrjälä 		plane->crtc = NULL;
2127e5e3b44cSVille Syrjälä 		plane->fb = NULL;
21286c2a7532SDaniel Vetter 		drm_modeset_unlock_all(dev);
21298cf5c917SJesse Barnes 		goto out;
21308cf5c917SJesse Barnes 	}
21318cf5c917SJesse Barnes 
21328cf5c917SJesse Barnes 	obj = drm_mode_object_find(dev, plane_req->crtc_id,
21338cf5c917SJesse Barnes 				   DRM_MODE_OBJECT_CRTC);
21348cf5c917SJesse Barnes 	if (!obj) {
21358cf5c917SJesse Barnes 		DRM_DEBUG_KMS("Unknown crtc ID %d\n",
21368cf5c917SJesse Barnes 			      plane_req->crtc_id);
21378cf5c917SJesse Barnes 		ret = -ENOENT;
21388cf5c917SJesse Barnes 		goto out;
21398cf5c917SJesse Barnes 	}
21408cf5c917SJesse Barnes 	crtc = obj_to_crtc(obj);
21418cf5c917SJesse Barnes 
2142786b99edSDaniel Vetter 	fb = drm_framebuffer_lookup(dev, plane_req->fb_id);
2143786b99edSDaniel Vetter 	if (!fb) {
21448cf5c917SJesse Barnes 		DRM_DEBUG_KMS("Unknown framebuffer ID %d\n",
21458cf5c917SJesse Barnes 			      plane_req->fb_id);
21468cf5c917SJesse Barnes 		ret = -ENOENT;
21478cf5c917SJesse Barnes 		goto out;
21488cf5c917SJesse Barnes 	}
21498cf5c917SJesse Barnes 
215062443be6SVille Syrjälä 	/* Check whether this plane supports the fb pixel format. */
215162443be6SVille Syrjälä 	for (i = 0; i < plane->format_count; i++)
215262443be6SVille Syrjälä 		if (fb->pixel_format == plane->format_types[i])
215362443be6SVille Syrjälä 			break;
215462443be6SVille Syrjälä 	if (i == plane->format_count) {
21556ba6d03eSVille Syrjälä 		DRM_DEBUG_KMS("Invalid pixel format %s\n",
21566ba6d03eSVille Syrjälä 			      drm_get_format_name(fb->pixel_format));
215762443be6SVille Syrjälä 		ret = -EINVAL;
215862443be6SVille Syrjälä 		goto out;
215962443be6SVille Syrjälä 	}
216062443be6SVille Syrjälä 
216142ef8789SVille Syrjälä 	fb_width = fb->width << 16;
216242ef8789SVille Syrjälä 	fb_height = fb->height << 16;
216342ef8789SVille Syrjälä 
216442ef8789SVille Syrjälä 	/* Make sure source coordinates are inside the fb. */
216542ef8789SVille Syrjälä 	if (plane_req->src_w > fb_width ||
216642ef8789SVille Syrjälä 	    plane_req->src_x > fb_width - plane_req->src_w ||
216742ef8789SVille Syrjälä 	    plane_req->src_h > fb_height ||
216842ef8789SVille Syrjälä 	    plane_req->src_y > fb_height - plane_req->src_h) {
216942ef8789SVille Syrjälä 		DRM_DEBUG_KMS("Invalid source coordinates "
217042ef8789SVille Syrjälä 			      "%u.%06ux%u.%06u+%u.%06u+%u.%06u\n",
217142ef8789SVille Syrjälä 			      plane_req->src_w >> 16,
217242ef8789SVille Syrjälä 			      ((plane_req->src_w & 0xffff) * 15625) >> 10,
217342ef8789SVille Syrjälä 			      plane_req->src_h >> 16,
217442ef8789SVille Syrjälä 			      ((plane_req->src_h & 0xffff) * 15625) >> 10,
217542ef8789SVille Syrjälä 			      plane_req->src_x >> 16,
217642ef8789SVille Syrjälä 			      ((plane_req->src_x & 0xffff) * 15625) >> 10,
217742ef8789SVille Syrjälä 			      plane_req->src_y >> 16,
217842ef8789SVille Syrjälä 			      ((plane_req->src_y & 0xffff) * 15625) >> 10);
217942ef8789SVille Syrjälä 		ret = -ENOSPC;
218042ef8789SVille Syrjälä 		goto out;
218142ef8789SVille Syrjälä 	}
218242ef8789SVille Syrjälä 
2183687a0400SVille Syrjälä 	/* Give drivers some help against integer overflows */
2184687a0400SVille Syrjälä 	if (plane_req->crtc_w > INT_MAX ||
2185687a0400SVille Syrjälä 	    plane_req->crtc_x > INT_MAX - (int32_t) plane_req->crtc_w ||
2186687a0400SVille Syrjälä 	    plane_req->crtc_h > INT_MAX ||
2187687a0400SVille Syrjälä 	    plane_req->crtc_y > INT_MAX - (int32_t) plane_req->crtc_h) {
2188687a0400SVille Syrjälä 		DRM_DEBUG_KMS("Invalid CRTC coordinates %ux%u+%d+%d\n",
2189687a0400SVille Syrjälä 			      plane_req->crtc_w, plane_req->crtc_h,
2190687a0400SVille Syrjälä 			      plane_req->crtc_x, plane_req->crtc_y);
2191687a0400SVille Syrjälä 		ret = -ERANGE;
2192687a0400SVille Syrjälä 		goto out;
2193687a0400SVille Syrjälä 	}
2194687a0400SVille Syrjälä 
21956c2a7532SDaniel Vetter 	drm_modeset_lock_all(dev);
21968cf5c917SJesse Barnes 	ret = plane->funcs->update_plane(plane, crtc, fb,
21978cf5c917SJesse Barnes 					 plane_req->crtc_x, plane_req->crtc_y,
21988cf5c917SJesse Barnes 					 plane_req->crtc_w, plane_req->crtc_h,
21998cf5c917SJesse Barnes 					 plane_req->src_x, plane_req->src_y,
22008cf5c917SJesse Barnes 					 plane_req->src_w, plane_req->src_h);
22018cf5c917SJesse Barnes 	if (!ret) {
22026c2a7532SDaniel Vetter 		old_fb = plane->fb;
22038cf5c917SJesse Barnes 		plane->crtc = crtc;
22048cf5c917SJesse Barnes 		plane->fb = fb;
220535f8badcSDaniel Vetter 		fb = NULL;
22068cf5c917SJesse Barnes 	}
22076c2a7532SDaniel Vetter 	drm_modeset_unlock_all(dev);
22088cf5c917SJesse Barnes 
22098cf5c917SJesse Barnes out:
22106c2a7532SDaniel Vetter 	if (fb)
22116c2a7532SDaniel Vetter 		drm_framebuffer_unreference(fb);
22126c2a7532SDaniel Vetter 	if (old_fb)
22136c2a7532SDaniel Vetter 		drm_framebuffer_unreference(old_fb);
22148cf5c917SJesse Barnes 
22158cf5c917SJesse Barnes 	return ret;
22168cf5c917SJesse Barnes }
22178cf5c917SJesse Barnes 
22188cf5c917SJesse Barnes /**
22192d13b679SDaniel Vetter  * drm_mode_set_config_internal - helper to call ->set_config
22202d13b679SDaniel Vetter  * @set: modeset config to set
22212d13b679SDaniel Vetter  *
22222d13b679SDaniel Vetter  * This is a little helper to wrap internal calls to the ->set_config driver
22232d13b679SDaniel Vetter  * interface. The only thing it adds is correct refcounting dance.
2224c8e32cc1SDaniel Vetter  *
2225c8e32cc1SDaniel Vetter  * Returns:
2226c8e32cc1SDaniel Vetter  * Zero on success, errno on failure.
22272d13b679SDaniel Vetter  */
22282d13b679SDaniel Vetter int drm_mode_set_config_internal(struct drm_mode_set *set)
22292d13b679SDaniel Vetter {
22302d13b679SDaniel Vetter 	struct drm_crtc *crtc = set->crtc;
22315cef29aaSDaniel Vetter 	struct drm_framebuffer *fb;
22325cef29aaSDaniel Vetter 	struct drm_crtc *tmp;
2233b0d12325SDaniel Vetter 	int ret;
22342d13b679SDaniel Vetter 
22355cef29aaSDaniel Vetter 	/*
22365cef29aaSDaniel Vetter 	 * NOTE: ->set_config can also disable other crtcs (if we steal all
22375cef29aaSDaniel Vetter 	 * connectors from it), hence we need to refcount the fbs across all
22385cef29aaSDaniel Vetter 	 * crtcs. Atomic modeset will have saner semantics ...
22395cef29aaSDaniel Vetter 	 */
22405cef29aaSDaniel Vetter 	list_for_each_entry(tmp, &crtc->dev->mode_config.crtc_list, head)
2241f4510a27SMatt Roper 		tmp->old_fb = tmp->primary->fb;
22425cef29aaSDaniel Vetter 
2243b0d12325SDaniel Vetter 	fb = set->fb;
2244b0d12325SDaniel Vetter 
2245b0d12325SDaniel Vetter 	ret = crtc->funcs->set_config(set);
2246b0d12325SDaniel Vetter 	if (ret == 0) {
2247e13161afSMatt Roper 		crtc->primary->crtc = crtc;
2248e13161afSMatt Roper 
2249cc85e121SDaniel Vetter 		/* crtc->fb must be updated by ->set_config, enforces this. */
2250f4510a27SMatt Roper 		WARN_ON(fb != crtc->primary->fb);
22515cef29aaSDaniel Vetter 	}
2252cc85e121SDaniel Vetter 
22535cef29aaSDaniel Vetter 	list_for_each_entry(tmp, &crtc->dev->mode_config.crtc_list, head) {
2254f4510a27SMatt Roper 		if (tmp->primary->fb)
2255f4510a27SMatt Roper 			drm_framebuffer_reference(tmp->primary->fb);
22565cef29aaSDaniel Vetter 		if (tmp->old_fb)
22575cef29aaSDaniel Vetter 			drm_framebuffer_unreference(tmp->old_fb);
2258b0d12325SDaniel Vetter 	}
2259b0d12325SDaniel Vetter 
2260b0d12325SDaniel Vetter 	return ret;
22612d13b679SDaniel Vetter }
22622d13b679SDaniel Vetter EXPORT_SYMBOL(drm_mode_set_config_internal);
22632d13b679SDaniel Vetter 
2264af93629dSMatt Roper /**
2265af93629dSMatt Roper  * drm_crtc_check_viewport - Checks that a framebuffer is big enough for the
2266af93629dSMatt Roper  *     CRTC viewport
2267af93629dSMatt Roper  * @crtc: CRTC that framebuffer will be displayed on
2268af93629dSMatt Roper  * @x: x panning
2269af93629dSMatt Roper  * @y: y panning
2270af93629dSMatt Roper  * @mode: mode that framebuffer will be displayed under
2271af93629dSMatt Roper  * @fb: framebuffer to check size of
2272c11e9283SDamien Lespiau  */
2273af93629dSMatt Roper int drm_crtc_check_viewport(const struct drm_crtc *crtc,
2274c11e9283SDamien Lespiau 			    int x, int y,
2275c11e9283SDamien Lespiau 			    const struct drm_display_mode *mode,
2276c11e9283SDamien Lespiau 			    const struct drm_framebuffer *fb)
2277c11e9283SDamien Lespiau 
2278c11e9283SDamien Lespiau {
2279c11e9283SDamien Lespiau 	int hdisplay, vdisplay;
2280c11e9283SDamien Lespiau 
2281c11e9283SDamien Lespiau 	hdisplay = mode->hdisplay;
2282c11e9283SDamien Lespiau 	vdisplay = mode->vdisplay;
2283c11e9283SDamien Lespiau 
2284a0c1bbb0SDamien Lespiau 	if (drm_mode_is_stereo(mode)) {
2285a0c1bbb0SDamien Lespiau 		struct drm_display_mode adjusted = *mode;
2286a0c1bbb0SDamien Lespiau 
2287a0c1bbb0SDamien Lespiau 		drm_mode_set_crtcinfo(&adjusted, CRTC_STEREO_DOUBLE);
2288a0c1bbb0SDamien Lespiau 		hdisplay = adjusted.crtc_hdisplay;
2289a0c1bbb0SDamien Lespiau 		vdisplay = adjusted.crtc_vdisplay;
2290a0c1bbb0SDamien Lespiau 	}
2291a0c1bbb0SDamien Lespiau 
2292c11e9283SDamien Lespiau 	if (crtc->invert_dimensions)
2293c11e9283SDamien Lespiau 		swap(hdisplay, vdisplay);
2294c11e9283SDamien Lespiau 
2295c11e9283SDamien Lespiau 	if (hdisplay > fb->width ||
2296c11e9283SDamien Lespiau 	    vdisplay > fb->height ||
2297c11e9283SDamien Lespiau 	    x > fb->width - hdisplay ||
2298c11e9283SDamien Lespiau 	    y > fb->height - vdisplay) {
2299c11e9283SDamien Lespiau 		DRM_DEBUG_KMS("Invalid fb size %ux%u for CRTC viewport %ux%u+%d+%d%s.\n",
2300c11e9283SDamien Lespiau 			      fb->width, fb->height, hdisplay, vdisplay, x, y,
2301c11e9283SDamien Lespiau 			      crtc->invert_dimensions ? " (inverted)" : "");
2302c11e9283SDamien Lespiau 		return -ENOSPC;
2303c11e9283SDamien Lespiau 	}
2304c11e9283SDamien Lespiau 
2305c11e9283SDamien Lespiau 	return 0;
2306c11e9283SDamien Lespiau }
2307af93629dSMatt Roper EXPORT_SYMBOL(drm_crtc_check_viewport);
2308c11e9283SDamien Lespiau 
23092d13b679SDaniel Vetter /**
2310f453ba04SDave Airlie  * drm_mode_setcrtc - set CRTC configuration
2311065a50edSDaniel Vetter  * @dev: drm device for the ioctl
2312065a50edSDaniel Vetter  * @data: data pointer for the ioctl
2313065a50edSDaniel Vetter  * @file_priv: drm file for the ioctl call
2314f453ba04SDave Airlie  *
2315f453ba04SDave Airlie  * Build a new CRTC configuration based on user request.
2316f453ba04SDave Airlie  *
2317f453ba04SDave Airlie  * Called by the user via ioctl.
2318f453ba04SDave Airlie  *
2319c8e32cc1SDaniel Vetter  * Returns:
2320f453ba04SDave Airlie  * Zero on success, errno on failure.
2321f453ba04SDave Airlie  */
2322f453ba04SDave Airlie int drm_mode_setcrtc(struct drm_device *dev, void *data,
2323f453ba04SDave Airlie 		     struct drm_file *file_priv)
2324f453ba04SDave Airlie {
2325f453ba04SDave Airlie 	struct drm_mode_config *config = &dev->mode_config;
2326f453ba04SDave Airlie 	struct drm_mode_crtc *crtc_req = data;
2327f453ba04SDave Airlie 	struct drm_mode_object *obj;
23286653cc8dSVille Syrjälä 	struct drm_crtc *crtc;
2329f453ba04SDave Airlie 	struct drm_connector **connector_set = NULL, *connector;
2330f453ba04SDave Airlie 	struct drm_framebuffer *fb = NULL;
2331f453ba04SDave Airlie 	struct drm_display_mode *mode = NULL;
2332f453ba04SDave Airlie 	struct drm_mode_set set;
2333f453ba04SDave Airlie 	uint32_t __user *set_connectors_ptr;
23344a1b0714SLaurent Pinchart 	int ret;
2335f453ba04SDave Airlie 	int i;
2336f453ba04SDave Airlie 
2337fb3b06c8SDave Airlie 	if (!drm_core_check_feature(dev, DRIVER_MODESET))
2338fb3b06c8SDave Airlie 		return -EINVAL;
2339fb3b06c8SDave Airlie 
23401d97e915SVille Syrjälä 	/* For some reason crtc x/y offsets are signed internally. */
23411d97e915SVille Syrjälä 	if (crtc_req->x > INT_MAX || crtc_req->y > INT_MAX)
23421d97e915SVille Syrjälä 		return -ERANGE;
23431d97e915SVille Syrjälä 
234484849903SDaniel Vetter 	drm_modeset_lock_all(dev);
2345f453ba04SDave Airlie 	obj = drm_mode_object_find(dev, crtc_req->crtc_id,
2346f453ba04SDave Airlie 				   DRM_MODE_OBJECT_CRTC);
2347f453ba04SDave Airlie 	if (!obj) {
234858367ed6SZhao Yakui 		DRM_DEBUG_KMS("Unknown CRTC ID %d\n", crtc_req->crtc_id);
2349f27657f2SVille Syrjälä 		ret = -ENOENT;
2350f453ba04SDave Airlie 		goto out;
2351f453ba04SDave Airlie 	}
2352f453ba04SDave Airlie 	crtc = obj_to_crtc(obj);
23539440106bSJerome Glisse 	DRM_DEBUG_KMS("[CRTC:%d]\n", crtc->base.id);
2354f453ba04SDave Airlie 
2355f453ba04SDave Airlie 	if (crtc_req->mode_valid) {
2356f453ba04SDave Airlie 		/* If we have a mode we need a framebuffer. */
2357f453ba04SDave Airlie 		/* If we pass -1, set the mode with the currently bound fb */
2358f453ba04SDave Airlie 		if (crtc_req->fb_id == -1) {
2359f4510a27SMatt Roper 			if (!crtc->primary->fb) {
23606653cc8dSVille Syrjälä 				DRM_DEBUG_KMS("CRTC doesn't have current FB\n");
23616653cc8dSVille Syrjälä 				ret = -EINVAL;
23626653cc8dSVille Syrjälä 				goto out;
23636653cc8dSVille Syrjälä 			}
2364f4510a27SMatt Roper 			fb = crtc->primary->fb;
2365b0d12325SDaniel Vetter 			/* Make refcounting symmetric with the lookup path. */
2366b0d12325SDaniel Vetter 			drm_framebuffer_reference(fb);
2367f453ba04SDave Airlie 		} else {
2368786b99edSDaniel Vetter 			fb = drm_framebuffer_lookup(dev, crtc_req->fb_id);
2369786b99edSDaniel Vetter 			if (!fb) {
237058367ed6SZhao Yakui 				DRM_DEBUG_KMS("Unknown FB ID%d\n",
237158367ed6SZhao Yakui 						crtc_req->fb_id);
237237c4e705SVille Syrjälä 				ret = -ENOENT;
2373f453ba04SDave Airlie 				goto out;
2374f453ba04SDave Airlie 			}
2375f453ba04SDave Airlie 		}
2376f453ba04SDave Airlie 
2377f453ba04SDave Airlie 		mode = drm_mode_create(dev);
2378ee34ab5bSVille Syrjälä 		if (!mode) {
2379ee34ab5bSVille Syrjälä 			ret = -ENOMEM;
2380ee34ab5bSVille Syrjälä 			goto out;
2381ee34ab5bSVille Syrjälä 		}
2382ee34ab5bSVille Syrjälä 
238390367bf6SVille Syrjälä 		ret = drm_crtc_convert_umode(mode, &crtc_req->mode);
238490367bf6SVille Syrjälä 		if (ret) {
238590367bf6SVille Syrjälä 			DRM_DEBUG_KMS("Invalid mode\n");
238690367bf6SVille Syrjälä 			goto out;
238790367bf6SVille Syrjälä 		}
238890367bf6SVille Syrjälä 
2389f453ba04SDave Airlie 		drm_mode_set_crtcinfo(mode, CRTC_INTERLACE_HALVE_V);
23905f61bb42SVille Syrjälä 
2391c11e9283SDamien Lespiau 		ret = drm_crtc_check_viewport(crtc, crtc_req->x, crtc_req->y,
2392c11e9283SDamien Lespiau 					      mode, fb);
2393c11e9283SDamien Lespiau 		if (ret)
23945f61bb42SVille Syrjälä 			goto out;
2395c11e9283SDamien Lespiau 
2396f453ba04SDave Airlie 	}
2397f453ba04SDave Airlie 
2398f453ba04SDave Airlie 	if (crtc_req->count_connectors == 0 && mode) {
239958367ed6SZhao Yakui 		DRM_DEBUG_KMS("Count connectors is 0 but mode set\n");
2400f453ba04SDave Airlie 		ret = -EINVAL;
2401f453ba04SDave Airlie 		goto out;
2402f453ba04SDave Airlie 	}
2403f453ba04SDave Airlie 
24047781de74SJakob Bornecrantz 	if (crtc_req->count_connectors > 0 && (!mode || !fb)) {
240558367ed6SZhao Yakui 		DRM_DEBUG_KMS("Count connectors is %d but no mode or fb set\n",
2406f453ba04SDave Airlie 			  crtc_req->count_connectors);
2407f453ba04SDave Airlie 		ret = -EINVAL;
2408f453ba04SDave Airlie 		goto out;
2409f453ba04SDave Airlie 	}
2410f453ba04SDave Airlie 
2411f453ba04SDave Airlie 	if (crtc_req->count_connectors > 0) {
2412f453ba04SDave Airlie 		u32 out_id;
2413f453ba04SDave Airlie 
2414f453ba04SDave Airlie 		/* Avoid unbounded kernel memory allocation */
2415f453ba04SDave Airlie 		if (crtc_req->count_connectors > config->num_connector) {
2416f453ba04SDave Airlie 			ret = -EINVAL;
2417f453ba04SDave Airlie 			goto out;
2418f453ba04SDave Airlie 		}
2419f453ba04SDave Airlie 
2420f453ba04SDave Airlie 		connector_set = kmalloc(crtc_req->count_connectors *
2421f453ba04SDave Airlie 					sizeof(struct drm_connector *),
2422f453ba04SDave Airlie 					GFP_KERNEL);
2423f453ba04SDave Airlie 		if (!connector_set) {
2424f453ba04SDave Airlie 			ret = -ENOMEM;
2425f453ba04SDave Airlie 			goto out;
2426f453ba04SDave Airlie 		}
2427f453ba04SDave Airlie 
2428f453ba04SDave Airlie 		for (i = 0; i < crtc_req->count_connectors; i++) {
242981f6c7f8SVille Syrjälä 			set_connectors_ptr = (uint32_t __user *)(unsigned long)crtc_req->set_connectors_ptr;
2430f453ba04SDave Airlie 			if (get_user(out_id, &set_connectors_ptr[i])) {
2431f453ba04SDave Airlie 				ret = -EFAULT;
2432f453ba04SDave Airlie 				goto out;
2433f453ba04SDave Airlie 			}
2434f453ba04SDave Airlie 
2435f453ba04SDave Airlie 			obj = drm_mode_object_find(dev, out_id,
2436f453ba04SDave Airlie 						   DRM_MODE_OBJECT_CONNECTOR);
2437f453ba04SDave Airlie 			if (!obj) {
243858367ed6SZhao Yakui 				DRM_DEBUG_KMS("Connector id %d unknown\n",
243958367ed6SZhao Yakui 						out_id);
2440f27657f2SVille Syrjälä 				ret = -ENOENT;
2441f453ba04SDave Airlie 				goto out;
2442f453ba04SDave Airlie 			}
2443f453ba04SDave Airlie 			connector = obj_to_connector(obj);
24449440106bSJerome Glisse 			DRM_DEBUG_KMS("[CONNECTOR:%d:%s]\n",
24459440106bSJerome Glisse 					connector->base.id,
24469440106bSJerome Glisse 					drm_get_connector_name(connector));
2447f453ba04SDave Airlie 
2448f453ba04SDave Airlie 			connector_set[i] = connector;
2449f453ba04SDave Airlie 		}
2450f453ba04SDave Airlie 	}
2451f453ba04SDave Airlie 
2452f453ba04SDave Airlie 	set.crtc = crtc;
2453f453ba04SDave Airlie 	set.x = crtc_req->x;
2454f453ba04SDave Airlie 	set.y = crtc_req->y;
2455f453ba04SDave Airlie 	set.mode = mode;
2456f453ba04SDave Airlie 	set.connectors = connector_set;
2457f453ba04SDave Airlie 	set.num_connectors = crtc_req->count_connectors;
2458f453ba04SDave Airlie 	set.fb = fb;
24592d13b679SDaniel Vetter 	ret = drm_mode_set_config_internal(&set);
2460f453ba04SDave Airlie 
2461f453ba04SDave Airlie out:
2462b0d12325SDaniel Vetter 	if (fb)
2463b0d12325SDaniel Vetter 		drm_framebuffer_unreference(fb);
2464b0d12325SDaniel Vetter 
2465f453ba04SDave Airlie 	kfree(connector_set);
2466ee34ab5bSVille Syrjälä 	drm_mode_destroy(dev, mode);
246784849903SDaniel Vetter 	drm_modeset_unlock_all(dev);
2468f453ba04SDave Airlie 	return ret;
2469f453ba04SDave Airlie }
2470f453ba04SDave Airlie 
24714c813d4dSDave Airlie static int drm_mode_cursor_common(struct drm_device *dev,
24724c813d4dSDave Airlie 				  struct drm_mode_cursor2 *req,
24734c813d4dSDave Airlie 				  struct drm_file *file_priv)
2474f453ba04SDave Airlie {
2475f453ba04SDave Airlie 	struct drm_mode_object *obj;
2476f453ba04SDave Airlie 	struct drm_crtc *crtc;
2477f453ba04SDave Airlie 	int ret = 0;
2478f453ba04SDave Airlie 
2479fb3b06c8SDave Airlie 	if (!drm_core_check_feature(dev, DRIVER_MODESET))
2480fb3b06c8SDave Airlie 		return -EINVAL;
2481fb3b06c8SDave Airlie 
24827c4eaca4SJakob Bornecrantz 	if (!req->flags || (~DRM_MODE_CURSOR_FLAGS & req->flags))
2483f453ba04SDave Airlie 		return -EINVAL;
2484f453ba04SDave Airlie 
2485e0c8463aSJakob Bornecrantz 	obj = drm_mode_object_find(dev, req->crtc_id, DRM_MODE_OBJECT_CRTC);
2486f453ba04SDave Airlie 	if (!obj) {
248758367ed6SZhao Yakui 		DRM_DEBUG_KMS("Unknown CRTC ID %d\n", req->crtc_id);
2488f27657f2SVille Syrjälä 		return -ENOENT;
2489f453ba04SDave Airlie 	}
2490f453ba04SDave Airlie 	crtc = obj_to_crtc(obj);
2491f453ba04SDave Airlie 
2492dac35663SDaniel Vetter 	mutex_lock(&crtc->mutex);
2493f453ba04SDave Airlie 	if (req->flags & DRM_MODE_CURSOR_BO) {
24944c813d4dSDave Airlie 		if (!crtc->funcs->cursor_set && !crtc->funcs->cursor_set2) {
2495f453ba04SDave Airlie 			ret = -ENXIO;
2496f453ba04SDave Airlie 			goto out;
2497f453ba04SDave Airlie 		}
2498f453ba04SDave Airlie 		/* Turns off the cursor if handle is 0 */
24994c813d4dSDave Airlie 		if (crtc->funcs->cursor_set2)
25004c813d4dSDave Airlie 			ret = crtc->funcs->cursor_set2(crtc, file_priv, req->handle,
25014c813d4dSDave Airlie 						      req->width, req->height, req->hot_x, req->hot_y);
25024c813d4dSDave Airlie 		else
2503f453ba04SDave Airlie 			ret = crtc->funcs->cursor_set(crtc, file_priv, req->handle,
2504f453ba04SDave Airlie 						      req->width, req->height);
2505f453ba04SDave Airlie 	}
2506f453ba04SDave Airlie 
2507f453ba04SDave Airlie 	if (req->flags & DRM_MODE_CURSOR_MOVE) {
2508f453ba04SDave Airlie 		if (crtc->funcs->cursor_move) {
2509f453ba04SDave Airlie 			ret = crtc->funcs->cursor_move(crtc, req->x, req->y);
2510f453ba04SDave Airlie 		} else {
2511f453ba04SDave Airlie 			ret = -EFAULT;
2512f453ba04SDave Airlie 			goto out;
2513f453ba04SDave Airlie 		}
2514f453ba04SDave Airlie 	}
2515f453ba04SDave Airlie out:
2516dac35663SDaniel Vetter 	mutex_unlock(&crtc->mutex);
2517dac35663SDaniel Vetter 
2518f453ba04SDave Airlie 	return ret;
25194c813d4dSDave Airlie 
25204c813d4dSDave Airlie }
2521c8e32cc1SDaniel Vetter 
2522c8e32cc1SDaniel Vetter 
2523c8e32cc1SDaniel Vetter /**
2524c8e32cc1SDaniel Vetter  * drm_mode_cursor_ioctl - set CRTC's cursor configuration
2525c8e32cc1SDaniel Vetter  * @dev: drm device for the ioctl
2526c8e32cc1SDaniel Vetter  * @data: data pointer for the ioctl
2527c8e32cc1SDaniel Vetter  * @file_priv: drm file for the ioctl call
2528c8e32cc1SDaniel Vetter  *
2529c8e32cc1SDaniel Vetter  * Set the cursor configuration based on user request.
2530c8e32cc1SDaniel Vetter  *
2531c8e32cc1SDaniel Vetter  * Called by the user via ioctl.
2532c8e32cc1SDaniel Vetter  *
2533c8e32cc1SDaniel Vetter  * Returns:
2534c8e32cc1SDaniel Vetter  * Zero on success, errno on failure.
2535c8e32cc1SDaniel Vetter  */
25364c813d4dSDave Airlie int drm_mode_cursor_ioctl(struct drm_device *dev,
25374c813d4dSDave Airlie 			  void *data, struct drm_file *file_priv)
25384c813d4dSDave Airlie {
25394c813d4dSDave Airlie 	struct drm_mode_cursor *req = data;
25404c813d4dSDave Airlie 	struct drm_mode_cursor2 new_req;
25414c813d4dSDave Airlie 
25424c813d4dSDave Airlie 	memcpy(&new_req, req, sizeof(struct drm_mode_cursor));
25434c813d4dSDave Airlie 	new_req.hot_x = new_req.hot_y = 0;
25444c813d4dSDave Airlie 
25454c813d4dSDave Airlie 	return drm_mode_cursor_common(dev, &new_req, file_priv);
25464c813d4dSDave Airlie }
25474c813d4dSDave Airlie 
2548c8e32cc1SDaniel Vetter /**
2549c8e32cc1SDaniel Vetter  * drm_mode_cursor2_ioctl - set CRTC's cursor configuration
2550c8e32cc1SDaniel Vetter  * @dev: drm device for the ioctl
2551c8e32cc1SDaniel Vetter  * @data: data pointer for the ioctl
2552c8e32cc1SDaniel Vetter  * @file_priv: drm file for the ioctl call
2553c8e32cc1SDaniel Vetter  *
2554c8e32cc1SDaniel Vetter  * Set the cursor configuration based on user request. This implements the 2nd
2555c8e32cc1SDaniel Vetter  * version of the cursor ioctl, which allows userspace to additionally specify
2556c8e32cc1SDaniel Vetter  * the hotspot of the pointer.
2557c8e32cc1SDaniel Vetter  *
2558c8e32cc1SDaniel Vetter  * Called by the user via ioctl.
2559c8e32cc1SDaniel Vetter  *
2560c8e32cc1SDaniel Vetter  * Returns:
2561c8e32cc1SDaniel Vetter  * Zero on success, errno on failure.
2562c8e32cc1SDaniel Vetter  */
25634c813d4dSDave Airlie int drm_mode_cursor2_ioctl(struct drm_device *dev,
25644c813d4dSDave Airlie 			   void *data, struct drm_file *file_priv)
25654c813d4dSDave Airlie {
25664c813d4dSDave Airlie 	struct drm_mode_cursor2 *req = data;
25674c813d4dSDave Airlie 	return drm_mode_cursor_common(dev, req, file_priv);
2568f453ba04SDave Airlie }
2569f453ba04SDave Airlie 
2570c8e32cc1SDaniel Vetter /**
2571c8e32cc1SDaniel Vetter  * drm_mode_legacy_fb_format - compute drm fourcc code from legacy description
2572c8e32cc1SDaniel Vetter  * @bpp: bits per pixels
2573c8e32cc1SDaniel Vetter  * @depth: bit depth per pixel
2574c8e32cc1SDaniel Vetter  *
2575c8e32cc1SDaniel Vetter  * Computes a drm fourcc pixel format code for the given @bpp/@depth values.
2576c8e32cc1SDaniel Vetter  * Useful in fbdev emulation code, since that deals in those values.
2577c8e32cc1SDaniel Vetter  */
2578308e5bcbSJesse Barnes uint32_t drm_mode_legacy_fb_format(uint32_t bpp, uint32_t depth)
2579308e5bcbSJesse Barnes {
2580308e5bcbSJesse Barnes 	uint32_t fmt;
2581308e5bcbSJesse Barnes 
2582308e5bcbSJesse Barnes 	switch (bpp) {
2583308e5bcbSJesse Barnes 	case 8:
2584d84f031bSVille Syrjälä 		fmt = DRM_FORMAT_C8;
2585308e5bcbSJesse Barnes 		break;
2586308e5bcbSJesse Barnes 	case 16:
2587308e5bcbSJesse Barnes 		if (depth == 15)
258804b3924dSVille Syrjälä 			fmt = DRM_FORMAT_XRGB1555;
2589308e5bcbSJesse Barnes 		else
259004b3924dSVille Syrjälä 			fmt = DRM_FORMAT_RGB565;
2591308e5bcbSJesse Barnes 		break;
2592308e5bcbSJesse Barnes 	case 24:
259304b3924dSVille Syrjälä 		fmt = DRM_FORMAT_RGB888;
2594308e5bcbSJesse Barnes 		break;
2595308e5bcbSJesse Barnes 	case 32:
2596308e5bcbSJesse Barnes 		if (depth == 24)
259704b3924dSVille Syrjälä 			fmt = DRM_FORMAT_XRGB8888;
2598308e5bcbSJesse Barnes 		else if (depth == 30)
259904b3924dSVille Syrjälä 			fmt = DRM_FORMAT_XRGB2101010;
2600308e5bcbSJesse Barnes 		else
260104b3924dSVille Syrjälä 			fmt = DRM_FORMAT_ARGB8888;
2602308e5bcbSJesse Barnes 		break;
2603308e5bcbSJesse Barnes 	default:
260404b3924dSVille Syrjälä 		DRM_ERROR("bad bpp, assuming x8r8g8b8 pixel format\n");
260504b3924dSVille Syrjälä 		fmt = DRM_FORMAT_XRGB8888;
2606308e5bcbSJesse Barnes 		break;
2607308e5bcbSJesse Barnes 	}
2608308e5bcbSJesse Barnes 
2609308e5bcbSJesse Barnes 	return fmt;
2610308e5bcbSJesse Barnes }
2611308e5bcbSJesse Barnes EXPORT_SYMBOL(drm_mode_legacy_fb_format);
2612308e5bcbSJesse Barnes 
2613f453ba04SDave Airlie /**
2614f453ba04SDave Airlie  * drm_mode_addfb - add an FB to the graphics configuration
2615065a50edSDaniel Vetter  * @dev: drm device for the ioctl
2616065a50edSDaniel Vetter  * @data: data pointer for the ioctl
2617065a50edSDaniel Vetter  * @file_priv: drm file for the ioctl call
2618f453ba04SDave Airlie  *
2619c8e32cc1SDaniel Vetter  * Add a new FB to the specified CRTC, given a user request. This is the
2620c8e32cc1SDaniel Vetter  * original addfb ioclt which only supported RGB formats.
2621f453ba04SDave Airlie  *
2622f453ba04SDave Airlie  * Called by the user via ioctl.
2623f453ba04SDave Airlie  *
2624c8e32cc1SDaniel Vetter  * Returns:
2625f453ba04SDave Airlie  * Zero on success, errno on failure.
2626f453ba04SDave Airlie  */
2627f453ba04SDave Airlie int drm_mode_addfb(struct drm_device *dev,
2628f453ba04SDave Airlie 		   void *data, struct drm_file *file_priv)
2629f453ba04SDave Airlie {
2630308e5bcbSJesse Barnes 	struct drm_mode_fb_cmd *or = data;
2631308e5bcbSJesse Barnes 	struct drm_mode_fb_cmd2 r = {};
2632308e5bcbSJesse Barnes 	struct drm_mode_config *config = &dev->mode_config;
2633308e5bcbSJesse Barnes 	struct drm_framebuffer *fb;
2634308e5bcbSJesse Barnes 	int ret = 0;
2635308e5bcbSJesse Barnes 
2636308e5bcbSJesse Barnes 	/* Use new struct with format internally */
2637308e5bcbSJesse Barnes 	r.fb_id = or->fb_id;
2638308e5bcbSJesse Barnes 	r.width = or->width;
2639308e5bcbSJesse Barnes 	r.height = or->height;
2640308e5bcbSJesse Barnes 	r.pitches[0] = or->pitch;
2641308e5bcbSJesse Barnes 	r.pixel_format = drm_mode_legacy_fb_format(or->bpp, or->depth);
2642308e5bcbSJesse Barnes 	r.handles[0] = or->handle;
2643308e5bcbSJesse Barnes 
2644308e5bcbSJesse Barnes 	if (!drm_core_check_feature(dev, DRIVER_MODESET))
2645308e5bcbSJesse Barnes 		return -EINVAL;
2646308e5bcbSJesse Barnes 
2647acb4b992SJesse Barnes 	if ((config->min_width > r.width) || (r.width > config->max_width))
2648308e5bcbSJesse Barnes 		return -EINVAL;
2649acb4b992SJesse Barnes 
2650acb4b992SJesse Barnes 	if ((config->min_height > r.height) || (r.height > config->max_height))
2651308e5bcbSJesse Barnes 		return -EINVAL;
2652308e5bcbSJesse Barnes 
2653308e5bcbSJesse Barnes 	fb = dev->mode_config.funcs->fb_create(dev, file_priv, &r);
2654308e5bcbSJesse Barnes 	if (IS_ERR(fb)) {
26551aa1b11cSDave Airlie 		DRM_DEBUG_KMS("could not create framebuffer\n");
26564b096ac1SDaniel Vetter 		return PTR_ERR(fb);
2657308e5bcbSJesse Barnes 	}
2658308e5bcbSJesse Barnes 
26594b096ac1SDaniel Vetter 	mutex_lock(&file_priv->fbs_lock);
2660308e5bcbSJesse Barnes 	or->fb_id = fb->base.id;
2661308e5bcbSJesse Barnes 	list_add(&fb->filp_head, &file_priv->fbs);
2662308e5bcbSJesse Barnes 	DRM_DEBUG_KMS("[FB:%d]\n", fb->base.id);
26634b096ac1SDaniel Vetter 	mutex_unlock(&file_priv->fbs_lock);
26644b096ac1SDaniel Vetter 
2665308e5bcbSJesse Barnes 	return ret;
2666308e5bcbSJesse Barnes }
2667308e5bcbSJesse Barnes 
2668cff91b62SVille Syrjälä static int format_check(const struct drm_mode_fb_cmd2 *r)
2669935b5977SVille Syrjälä {
2670935b5977SVille Syrjälä 	uint32_t format = r->pixel_format & ~DRM_FORMAT_BIG_ENDIAN;
2671935b5977SVille Syrjälä 
2672935b5977SVille Syrjälä 	switch (format) {
2673935b5977SVille Syrjälä 	case DRM_FORMAT_C8:
2674935b5977SVille Syrjälä 	case DRM_FORMAT_RGB332:
2675935b5977SVille Syrjälä 	case DRM_FORMAT_BGR233:
2676935b5977SVille Syrjälä 	case DRM_FORMAT_XRGB4444:
2677935b5977SVille Syrjälä 	case DRM_FORMAT_XBGR4444:
2678935b5977SVille Syrjälä 	case DRM_FORMAT_RGBX4444:
2679935b5977SVille Syrjälä 	case DRM_FORMAT_BGRX4444:
2680935b5977SVille Syrjälä 	case DRM_FORMAT_ARGB4444:
2681935b5977SVille Syrjälä 	case DRM_FORMAT_ABGR4444:
2682935b5977SVille Syrjälä 	case DRM_FORMAT_RGBA4444:
2683935b5977SVille Syrjälä 	case DRM_FORMAT_BGRA4444:
2684935b5977SVille Syrjälä 	case DRM_FORMAT_XRGB1555:
2685935b5977SVille Syrjälä 	case DRM_FORMAT_XBGR1555:
2686935b5977SVille Syrjälä 	case DRM_FORMAT_RGBX5551:
2687935b5977SVille Syrjälä 	case DRM_FORMAT_BGRX5551:
2688935b5977SVille Syrjälä 	case DRM_FORMAT_ARGB1555:
2689935b5977SVille Syrjälä 	case DRM_FORMAT_ABGR1555:
2690935b5977SVille Syrjälä 	case DRM_FORMAT_RGBA5551:
2691935b5977SVille Syrjälä 	case DRM_FORMAT_BGRA5551:
2692935b5977SVille Syrjälä 	case DRM_FORMAT_RGB565:
2693935b5977SVille Syrjälä 	case DRM_FORMAT_BGR565:
2694935b5977SVille Syrjälä 	case DRM_FORMAT_RGB888:
2695935b5977SVille Syrjälä 	case DRM_FORMAT_BGR888:
2696935b5977SVille Syrjälä 	case DRM_FORMAT_XRGB8888:
2697935b5977SVille Syrjälä 	case DRM_FORMAT_XBGR8888:
2698935b5977SVille Syrjälä 	case DRM_FORMAT_RGBX8888:
2699935b5977SVille Syrjälä 	case DRM_FORMAT_BGRX8888:
2700935b5977SVille Syrjälä 	case DRM_FORMAT_ARGB8888:
2701935b5977SVille Syrjälä 	case DRM_FORMAT_ABGR8888:
2702935b5977SVille Syrjälä 	case DRM_FORMAT_RGBA8888:
2703935b5977SVille Syrjälä 	case DRM_FORMAT_BGRA8888:
2704935b5977SVille Syrjälä 	case DRM_FORMAT_XRGB2101010:
2705935b5977SVille Syrjälä 	case DRM_FORMAT_XBGR2101010:
2706935b5977SVille Syrjälä 	case DRM_FORMAT_RGBX1010102:
2707935b5977SVille Syrjälä 	case DRM_FORMAT_BGRX1010102:
2708935b5977SVille Syrjälä 	case DRM_FORMAT_ARGB2101010:
2709935b5977SVille Syrjälä 	case DRM_FORMAT_ABGR2101010:
2710935b5977SVille Syrjälä 	case DRM_FORMAT_RGBA1010102:
2711935b5977SVille Syrjälä 	case DRM_FORMAT_BGRA1010102:
2712935b5977SVille Syrjälä 	case DRM_FORMAT_YUYV:
2713935b5977SVille Syrjälä 	case DRM_FORMAT_YVYU:
2714935b5977SVille Syrjälä 	case DRM_FORMAT_UYVY:
2715935b5977SVille Syrjälä 	case DRM_FORMAT_VYUY:
2716935b5977SVille Syrjälä 	case DRM_FORMAT_AYUV:
2717935b5977SVille Syrjälä 	case DRM_FORMAT_NV12:
2718935b5977SVille Syrjälä 	case DRM_FORMAT_NV21:
2719935b5977SVille Syrjälä 	case DRM_FORMAT_NV16:
2720935b5977SVille Syrjälä 	case DRM_FORMAT_NV61:
2721ba623f6aSLaurent Pinchart 	case DRM_FORMAT_NV24:
2722ba623f6aSLaurent Pinchart 	case DRM_FORMAT_NV42:
2723935b5977SVille Syrjälä 	case DRM_FORMAT_YUV410:
2724935b5977SVille Syrjälä 	case DRM_FORMAT_YVU410:
2725935b5977SVille Syrjälä 	case DRM_FORMAT_YUV411:
2726935b5977SVille Syrjälä 	case DRM_FORMAT_YVU411:
2727935b5977SVille Syrjälä 	case DRM_FORMAT_YUV420:
2728935b5977SVille Syrjälä 	case DRM_FORMAT_YVU420:
2729935b5977SVille Syrjälä 	case DRM_FORMAT_YUV422:
2730935b5977SVille Syrjälä 	case DRM_FORMAT_YVU422:
2731935b5977SVille Syrjälä 	case DRM_FORMAT_YUV444:
2732935b5977SVille Syrjälä 	case DRM_FORMAT_YVU444:
2733935b5977SVille Syrjälä 		return 0;
2734935b5977SVille Syrjälä 	default:
273523c453a4SVille Syrjälä 		DRM_DEBUG_KMS("invalid pixel format %s\n",
273623c453a4SVille Syrjälä 			      drm_get_format_name(r->pixel_format));
2737935b5977SVille Syrjälä 		return -EINVAL;
2738935b5977SVille Syrjälä 	}
2739935b5977SVille Syrjälä }
2740935b5977SVille Syrjälä 
2741cff91b62SVille Syrjälä static int framebuffer_check(const struct drm_mode_fb_cmd2 *r)
2742d1b45d5fSVille Syrjälä {
2743d1b45d5fSVille Syrjälä 	int ret, hsub, vsub, num_planes, i;
2744d1b45d5fSVille Syrjälä 
2745d1b45d5fSVille Syrjälä 	ret = format_check(r);
2746d1b45d5fSVille Syrjälä 	if (ret) {
27476ba6d03eSVille Syrjälä 		DRM_DEBUG_KMS("bad framebuffer format %s\n",
27486ba6d03eSVille Syrjälä 			      drm_get_format_name(r->pixel_format));
2749d1b45d5fSVille Syrjälä 		return ret;
2750d1b45d5fSVille Syrjälä 	}
2751d1b45d5fSVille Syrjälä 
2752d1b45d5fSVille Syrjälä 	hsub = drm_format_horz_chroma_subsampling(r->pixel_format);
2753d1b45d5fSVille Syrjälä 	vsub = drm_format_vert_chroma_subsampling(r->pixel_format);
2754d1b45d5fSVille Syrjälä 	num_planes = drm_format_num_planes(r->pixel_format);
2755d1b45d5fSVille Syrjälä 
2756d1b45d5fSVille Syrjälä 	if (r->width == 0 || r->width % hsub) {
27571aa1b11cSDave Airlie 		DRM_DEBUG_KMS("bad framebuffer width %u\n", r->height);
2758d1b45d5fSVille Syrjälä 		return -EINVAL;
2759d1b45d5fSVille Syrjälä 	}
2760d1b45d5fSVille Syrjälä 
2761d1b45d5fSVille Syrjälä 	if (r->height == 0 || r->height % vsub) {
27621aa1b11cSDave Airlie 		DRM_DEBUG_KMS("bad framebuffer height %u\n", r->height);
2763d1b45d5fSVille Syrjälä 		return -EINVAL;
2764d1b45d5fSVille Syrjälä 	}
2765d1b45d5fSVille Syrjälä 
2766d1b45d5fSVille Syrjälä 	for (i = 0; i < num_planes; i++) {
2767d1b45d5fSVille Syrjälä 		unsigned int width = r->width / (i != 0 ? hsub : 1);
2768b180b5d1SVille Syrjälä 		unsigned int height = r->height / (i != 0 ? vsub : 1);
2769b180b5d1SVille Syrjälä 		unsigned int cpp = drm_format_plane_cpp(r->pixel_format, i);
2770d1b45d5fSVille Syrjälä 
2771d1b45d5fSVille Syrjälä 		if (!r->handles[i]) {
27721aa1b11cSDave Airlie 			DRM_DEBUG_KMS("no buffer object handle for plane %d\n", i);
2773d1b45d5fSVille Syrjälä 			return -EINVAL;
2774d1b45d5fSVille Syrjälä 		}
2775d1b45d5fSVille Syrjälä 
2776b180b5d1SVille Syrjälä 		if ((uint64_t) width * cpp > UINT_MAX)
2777b180b5d1SVille Syrjälä 			return -ERANGE;
2778b180b5d1SVille Syrjälä 
2779b180b5d1SVille Syrjälä 		if ((uint64_t) height * r->pitches[i] + r->offsets[i] > UINT_MAX)
2780b180b5d1SVille Syrjälä 			return -ERANGE;
2781b180b5d1SVille Syrjälä 
2782b180b5d1SVille Syrjälä 		if (r->pitches[i] < width * cpp) {
27831aa1b11cSDave Airlie 			DRM_DEBUG_KMS("bad pitch %u for plane %d\n", r->pitches[i], i);
2784d1b45d5fSVille Syrjälä 			return -EINVAL;
2785d1b45d5fSVille Syrjälä 		}
2786d1b45d5fSVille Syrjälä 	}
2787d1b45d5fSVille Syrjälä 
2788d1b45d5fSVille Syrjälä 	return 0;
2789d1b45d5fSVille Syrjälä }
2790d1b45d5fSVille Syrjälä 
2791308e5bcbSJesse Barnes /**
2792308e5bcbSJesse Barnes  * drm_mode_addfb2 - add an FB to the graphics configuration
2793065a50edSDaniel Vetter  * @dev: drm device for the ioctl
2794065a50edSDaniel Vetter  * @data: data pointer for the ioctl
2795065a50edSDaniel Vetter  * @file_priv: drm file for the ioctl call
2796308e5bcbSJesse Barnes  *
2797c8e32cc1SDaniel Vetter  * Add a new FB to the specified CRTC, given a user request with format. This is
2798c8e32cc1SDaniel Vetter  * the 2nd version of the addfb ioctl, which supports multi-planar framebuffers
2799c8e32cc1SDaniel Vetter  * and uses fourcc codes as pixel format specifiers.
2800308e5bcbSJesse Barnes  *
2801308e5bcbSJesse Barnes  * Called by the user via ioctl.
2802308e5bcbSJesse Barnes  *
2803c8e32cc1SDaniel Vetter  * Returns:
2804308e5bcbSJesse Barnes  * Zero on success, errno on failure.
2805308e5bcbSJesse Barnes  */
2806308e5bcbSJesse Barnes int drm_mode_addfb2(struct drm_device *dev,
2807308e5bcbSJesse Barnes 		    void *data, struct drm_file *file_priv)
2808308e5bcbSJesse Barnes {
2809308e5bcbSJesse Barnes 	struct drm_mode_fb_cmd2 *r = data;
2810f453ba04SDave Airlie 	struct drm_mode_config *config = &dev->mode_config;
2811f453ba04SDave Airlie 	struct drm_framebuffer *fb;
28124a1b0714SLaurent Pinchart 	int ret;
2813f453ba04SDave Airlie 
2814fb3b06c8SDave Airlie 	if (!drm_core_check_feature(dev, DRIVER_MODESET))
2815fb3b06c8SDave Airlie 		return -EINVAL;
2816fb3b06c8SDave Airlie 
2817e3cc3520SVille Syrjälä 	if (r->flags & ~DRM_MODE_FB_INTERLACED) {
2818e3cc3520SVille Syrjälä 		DRM_DEBUG_KMS("bad framebuffer flags 0x%08x\n", r->flags);
2819e3cc3520SVille Syrjälä 		return -EINVAL;
2820e3cc3520SVille Syrjälä 	}
2821e3cc3520SVille Syrjälä 
2822f453ba04SDave Airlie 	if ((config->min_width > r->width) || (r->width > config->max_width)) {
28231aa1b11cSDave Airlie 		DRM_DEBUG_KMS("bad framebuffer width %d, should be >= %d && <= %d\n",
28248cf5c917SJesse Barnes 			  r->width, config->min_width, config->max_width);
2825f453ba04SDave Airlie 		return -EINVAL;
2826f453ba04SDave Airlie 	}
2827f453ba04SDave Airlie 	if ((config->min_height > r->height) || (r->height > config->max_height)) {
28281aa1b11cSDave Airlie 		DRM_DEBUG_KMS("bad framebuffer height %d, should be >= %d && <= %d\n",
28298cf5c917SJesse Barnes 			  r->height, config->min_height, config->max_height);
2830f453ba04SDave Airlie 		return -EINVAL;
2831f453ba04SDave Airlie 	}
2832f453ba04SDave Airlie 
2833d1b45d5fSVille Syrjälä 	ret = framebuffer_check(r);
2834d1b45d5fSVille Syrjälä 	if (ret)
2835935b5977SVille Syrjälä 		return ret;
2836935b5977SVille Syrjälä 
2837f453ba04SDave Airlie 	fb = dev->mode_config.funcs->fb_create(dev, file_priv, r);
2838cce13ff7SChris Wilson 	if (IS_ERR(fb)) {
28391aa1b11cSDave Airlie 		DRM_DEBUG_KMS("could not create framebuffer\n");
28404b096ac1SDaniel Vetter 		return PTR_ERR(fb);
2841f453ba04SDave Airlie 	}
2842f453ba04SDave Airlie 
28434b096ac1SDaniel Vetter 	mutex_lock(&file_priv->fbs_lock);
2844e0c8463aSJakob Bornecrantz 	r->fb_id = fb->base.id;
2845f453ba04SDave Airlie 	list_add(&fb->filp_head, &file_priv->fbs);
28469440106bSJerome Glisse 	DRM_DEBUG_KMS("[FB:%d]\n", fb->base.id);
28474b096ac1SDaniel Vetter 	mutex_unlock(&file_priv->fbs_lock);
2848f453ba04SDave Airlie 
28494b096ac1SDaniel Vetter 
2850f453ba04SDave Airlie 	return ret;
2851f453ba04SDave Airlie }
2852f453ba04SDave Airlie 
2853f453ba04SDave Airlie /**
2854f453ba04SDave Airlie  * drm_mode_rmfb - remove an FB from the configuration
2855065a50edSDaniel Vetter  * @dev: drm device for the ioctl
2856065a50edSDaniel Vetter  * @data: data pointer for the ioctl
2857065a50edSDaniel Vetter  * @file_priv: drm file for the ioctl call
2858f453ba04SDave Airlie  *
2859f453ba04SDave Airlie  * Remove the FB specified by the user.
2860f453ba04SDave Airlie  *
2861f453ba04SDave Airlie  * Called by the user via ioctl.
2862f453ba04SDave Airlie  *
2863c8e32cc1SDaniel Vetter  * Returns:
2864f453ba04SDave Airlie  * Zero on success, errno on failure.
2865f453ba04SDave Airlie  */
2866f453ba04SDave Airlie int drm_mode_rmfb(struct drm_device *dev,
2867f453ba04SDave Airlie 		   void *data, struct drm_file *file_priv)
2868f453ba04SDave Airlie {
2869f453ba04SDave Airlie 	struct drm_framebuffer *fb = NULL;
2870f453ba04SDave Airlie 	struct drm_framebuffer *fbl = NULL;
2871f453ba04SDave Airlie 	uint32_t *id = data;
2872f453ba04SDave Airlie 	int found = 0;
2873f453ba04SDave Airlie 
2874fb3b06c8SDave Airlie 	if (!drm_core_check_feature(dev, DRIVER_MODESET))
2875fb3b06c8SDave Airlie 		return -EINVAL;
2876fb3b06c8SDave Airlie 
28774b096ac1SDaniel Vetter 	mutex_lock(&file_priv->fbs_lock);
28782b677e8cSDaniel Vetter 	mutex_lock(&dev->mode_config.fb_lock);
28792b677e8cSDaniel Vetter 	fb = __drm_framebuffer_lookup(dev, *id);
28802b677e8cSDaniel Vetter 	if (!fb)
28812b677e8cSDaniel Vetter 		goto fail_lookup;
28822b677e8cSDaniel Vetter 
2883f453ba04SDave Airlie 	list_for_each_entry(fbl, &file_priv->fbs, filp_head)
2884f453ba04SDave Airlie 		if (fb == fbl)
2885f453ba04SDave Airlie 			found = 1;
28862b677e8cSDaniel Vetter 	if (!found)
28872b677e8cSDaniel Vetter 		goto fail_lookup;
28882b677e8cSDaniel Vetter 
28892b677e8cSDaniel Vetter 	/* Mark fb as reaped, we still have a ref from fpriv->fbs. */
28902b677e8cSDaniel Vetter 	__drm_framebuffer_unregister(dev, fb);
2891f453ba04SDave Airlie 
28924b096ac1SDaniel Vetter 	list_del_init(&fb->filp_head);
28932b677e8cSDaniel Vetter 	mutex_unlock(&dev->mode_config.fb_lock);
28944b096ac1SDaniel Vetter 	mutex_unlock(&file_priv->fbs_lock);
2895f453ba04SDave Airlie 
28964b096ac1SDaniel Vetter 	drm_framebuffer_remove(fb);
28974b096ac1SDaniel Vetter 
28982b677e8cSDaniel Vetter 	return 0;
28992b677e8cSDaniel Vetter 
29002b677e8cSDaniel Vetter fail_lookup:
29012b677e8cSDaniel Vetter 	mutex_unlock(&dev->mode_config.fb_lock);
29022b677e8cSDaniel Vetter 	mutex_unlock(&file_priv->fbs_lock);
29032b677e8cSDaniel Vetter 
290437c4e705SVille Syrjälä 	return -ENOENT;
2905f453ba04SDave Airlie }
2906f453ba04SDave Airlie 
2907f453ba04SDave Airlie /**
2908f453ba04SDave Airlie  * drm_mode_getfb - get FB info
2909065a50edSDaniel Vetter  * @dev: drm device for the ioctl
2910065a50edSDaniel Vetter  * @data: data pointer for the ioctl
2911065a50edSDaniel Vetter  * @file_priv: drm file for the ioctl call
2912f453ba04SDave Airlie  *
2913f453ba04SDave Airlie  * Lookup the FB given its ID and return info about it.
2914f453ba04SDave Airlie  *
2915f453ba04SDave Airlie  * Called by the user via ioctl.
2916f453ba04SDave Airlie  *
2917c8e32cc1SDaniel Vetter  * Returns:
2918f453ba04SDave Airlie  * Zero on success, errno on failure.
2919f453ba04SDave Airlie  */
2920f453ba04SDave Airlie int drm_mode_getfb(struct drm_device *dev,
2921f453ba04SDave Airlie 		   void *data, struct drm_file *file_priv)
2922f453ba04SDave Airlie {
2923f453ba04SDave Airlie 	struct drm_mode_fb_cmd *r = data;
2924f453ba04SDave Airlie 	struct drm_framebuffer *fb;
292558c0dca1SDaniel Vetter 	int ret;
2926f453ba04SDave Airlie 
2927fb3b06c8SDave Airlie 	if (!drm_core_check_feature(dev, DRIVER_MODESET))
2928fb3b06c8SDave Airlie 		return -EINVAL;
2929fb3b06c8SDave Airlie 
2930786b99edSDaniel Vetter 	fb = drm_framebuffer_lookup(dev, r->fb_id);
293158c0dca1SDaniel Vetter 	if (!fb)
293237c4e705SVille Syrjälä 		return -ENOENT;
2933f453ba04SDave Airlie 
2934f453ba04SDave Airlie 	r->height = fb->height;
2935f453ba04SDave Airlie 	r->width = fb->width;
2936f453ba04SDave Airlie 	r->depth = fb->depth;
2937f453ba04SDave Airlie 	r->bpp = fb->bits_per_pixel;
293801f2c773SVille Syrjälä 	r->pitch = fb->pitches[0];
2939101b96f3SDavid Herrmann 	if (fb->funcs->create_handle) {
294009f308f7SThomas Hellstrom 		if (file_priv->is_master || capable(CAP_SYS_ADMIN) ||
294143683057SThomas Hellstrom 		    drm_is_control_client(file_priv)) {
2942101b96f3SDavid Herrmann 			ret = fb->funcs->create_handle(fb, file_priv,
2943101b96f3SDavid Herrmann 						       &r->handle);
2944101b96f3SDavid Herrmann 		} else {
2945101b96f3SDavid Herrmann 			/* GET_FB() is an unprivileged ioctl so we must not
2946101b96f3SDavid Herrmann 			 * return a buffer-handle to non-master processes! For
2947101b96f3SDavid Herrmann 			 * backwards-compatibility reasons, we cannot make
2948101b96f3SDavid Herrmann 			 * GET_FB() privileged, so just return an invalid handle
2949101b96f3SDavid Herrmann 			 * for non-masters. */
2950101b96f3SDavid Herrmann 			r->handle = 0;
2951101b96f3SDavid Herrmann 			ret = 0;
2952101b96f3SDavid Herrmann 		}
2953101b96f3SDavid Herrmann 	} else {
2954af26ef3bSDaniel Vetter 		ret = -ENODEV;
2955101b96f3SDavid Herrmann 	}
2956f453ba04SDave Airlie 
295758c0dca1SDaniel Vetter 	drm_framebuffer_unreference(fb);
295858c0dca1SDaniel Vetter 
2959f453ba04SDave Airlie 	return ret;
2960f453ba04SDave Airlie }
2961f453ba04SDave Airlie 
2962c8e32cc1SDaniel Vetter /**
2963c8e32cc1SDaniel Vetter  * drm_mode_dirtyfb_ioctl - flush frontbuffer rendering on an FB
2964c8e32cc1SDaniel Vetter  * @dev: drm device for the ioctl
2965c8e32cc1SDaniel Vetter  * @data: data pointer for the ioctl
2966c8e32cc1SDaniel Vetter  * @file_priv: drm file for the ioctl call
2967c8e32cc1SDaniel Vetter  *
2968c8e32cc1SDaniel Vetter  * Lookup the FB and flush out the damaged area supplied by userspace as a clip
2969c8e32cc1SDaniel Vetter  * rectangle list. Generic userspace which does frontbuffer rendering must call
2970c8e32cc1SDaniel Vetter  * this ioctl to flush out the changes on manual-update display outputs, e.g.
2971c8e32cc1SDaniel Vetter  * usb display-link, mipi manual update panels or edp panel self refresh modes.
2972c8e32cc1SDaniel Vetter  *
2973c8e32cc1SDaniel Vetter  * Modesetting drivers which always update the frontbuffer do not need to
2974c8e32cc1SDaniel Vetter  * implement the corresponding ->dirty framebuffer callback.
2975c8e32cc1SDaniel Vetter  *
2976c8e32cc1SDaniel Vetter  * Called by the user via ioctl.
2977c8e32cc1SDaniel Vetter  *
2978c8e32cc1SDaniel Vetter  * Returns:
2979c8e32cc1SDaniel Vetter  * Zero on success, errno on failure.
2980c8e32cc1SDaniel Vetter  */
2981884840aaSJakob Bornecrantz int drm_mode_dirtyfb_ioctl(struct drm_device *dev,
2982884840aaSJakob Bornecrantz 			   void *data, struct drm_file *file_priv)
2983884840aaSJakob Bornecrantz {
2984884840aaSJakob Bornecrantz 	struct drm_clip_rect __user *clips_ptr;
2985884840aaSJakob Bornecrantz 	struct drm_clip_rect *clips = NULL;
2986884840aaSJakob Bornecrantz 	struct drm_mode_fb_dirty_cmd *r = data;
2987884840aaSJakob Bornecrantz 	struct drm_framebuffer *fb;
2988884840aaSJakob Bornecrantz 	unsigned flags;
2989884840aaSJakob Bornecrantz 	int num_clips;
29904a1b0714SLaurent Pinchart 	int ret;
2991884840aaSJakob Bornecrantz 
2992fb3b06c8SDave Airlie 	if (!drm_core_check_feature(dev, DRIVER_MODESET))
2993fb3b06c8SDave Airlie 		return -EINVAL;
2994fb3b06c8SDave Airlie 
2995786b99edSDaniel Vetter 	fb = drm_framebuffer_lookup(dev, r->fb_id);
29964ccf097fSDaniel Vetter 	if (!fb)
299737c4e705SVille Syrjälä 		return -ENOENT;
2998884840aaSJakob Bornecrantz 
2999884840aaSJakob Bornecrantz 	num_clips = r->num_clips;
300081f6c7f8SVille Syrjälä 	clips_ptr = (struct drm_clip_rect __user *)(unsigned long)r->clips_ptr;
3001884840aaSJakob Bornecrantz 
3002884840aaSJakob Bornecrantz 	if (!num_clips != !clips_ptr) {
3003884840aaSJakob Bornecrantz 		ret = -EINVAL;
3004884840aaSJakob Bornecrantz 		goto out_err1;
3005884840aaSJakob Bornecrantz 	}
3006884840aaSJakob Bornecrantz 
3007884840aaSJakob Bornecrantz 	flags = DRM_MODE_FB_DIRTY_FLAGS & r->flags;
3008884840aaSJakob Bornecrantz 
3009884840aaSJakob Bornecrantz 	/* If userspace annotates copy, clips must come in pairs */
3010884840aaSJakob Bornecrantz 	if (flags & DRM_MODE_FB_DIRTY_ANNOTATE_COPY && (num_clips % 2)) {
3011884840aaSJakob Bornecrantz 		ret = -EINVAL;
3012884840aaSJakob Bornecrantz 		goto out_err1;
3013884840aaSJakob Bornecrantz 	}
3014884840aaSJakob Bornecrantz 
3015884840aaSJakob Bornecrantz 	if (num_clips && clips_ptr) {
3016a5cd3351SXi Wang 		if (num_clips < 0 || num_clips > DRM_MODE_FB_DIRTY_MAX_CLIPS) {
3017a5cd3351SXi Wang 			ret = -EINVAL;
3018a5cd3351SXi Wang 			goto out_err1;
3019a5cd3351SXi Wang 		}
3020884840aaSJakob Bornecrantz 		clips = kzalloc(num_clips * sizeof(*clips), GFP_KERNEL);
3021884840aaSJakob Bornecrantz 		if (!clips) {
3022884840aaSJakob Bornecrantz 			ret = -ENOMEM;
3023884840aaSJakob Bornecrantz 			goto out_err1;
3024884840aaSJakob Bornecrantz 		}
3025884840aaSJakob Bornecrantz 
3026884840aaSJakob Bornecrantz 		ret = copy_from_user(clips, clips_ptr,
3027884840aaSJakob Bornecrantz 				     num_clips * sizeof(*clips));
3028e902a358SDan Carpenter 		if (ret) {
3029e902a358SDan Carpenter 			ret = -EFAULT;
3030884840aaSJakob Bornecrantz 			goto out_err2;
3031884840aaSJakob Bornecrantz 		}
3032e902a358SDan Carpenter 	}
3033884840aaSJakob Bornecrantz 
3034884840aaSJakob Bornecrantz 	if (fb->funcs->dirty) {
303502b00162SThomas Hellstrom 		ret = fb->funcs->dirty(fb, file_priv, flags, r->color,
303602b00162SThomas Hellstrom 				       clips, num_clips);
3037884840aaSJakob Bornecrantz 	} else {
3038884840aaSJakob Bornecrantz 		ret = -ENOSYS;
3039884840aaSJakob Bornecrantz 	}
3040884840aaSJakob Bornecrantz 
3041884840aaSJakob Bornecrantz out_err2:
3042884840aaSJakob Bornecrantz 	kfree(clips);
3043884840aaSJakob Bornecrantz out_err1:
30444ccf097fSDaniel Vetter 	drm_framebuffer_unreference(fb);
30454ccf097fSDaniel Vetter 
3046884840aaSJakob Bornecrantz 	return ret;
3047884840aaSJakob Bornecrantz }
3048884840aaSJakob Bornecrantz 
3049884840aaSJakob Bornecrantz 
3050f453ba04SDave Airlie /**
3051f453ba04SDave Airlie  * drm_fb_release - remove and free the FBs on this file
3052065a50edSDaniel Vetter  * @priv: drm file for the ioctl
3053f453ba04SDave Airlie  *
3054f453ba04SDave Airlie  * Destroy all the FBs associated with @filp.
3055f453ba04SDave Airlie  *
3056f453ba04SDave Airlie  * Called by the user via ioctl.
3057f453ba04SDave Airlie  *
3058c8e32cc1SDaniel Vetter  * Returns:
3059f453ba04SDave Airlie  * Zero on success, errno on failure.
3060f453ba04SDave Airlie  */
3061ea39f835SKristian Høgsberg void drm_fb_release(struct drm_file *priv)
3062f453ba04SDave Airlie {
3063f453ba04SDave Airlie 	struct drm_device *dev = priv->minor->dev;
3064f453ba04SDave Airlie 	struct drm_framebuffer *fb, *tfb;
3065f453ba04SDave Airlie 
30664b096ac1SDaniel Vetter 	mutex_lock(&priv->fbs_lock);
3067f453ba04SDave Airlie 	list_for_each_entry_safe(fb, tfb, &priv->fbs, filp_head) {
30682b677e8cSDaniel Vetter 
30692b677e8cSDaniel Vetter 		mutex_lock(&dev->mode_config.fb_lock);
30702b677e8cSDaniel Vetter 		/* Mark fb as reaped, we still have a ref from fpriv->fbs. */
30712b677e8cSDaniel Vetter 		__drm_framebuffer_unregister(dev, fb);
30722b677e8cSDaniel Vetter 		mutex_unlock(&dev->mode_config.fb_lock);
30732b677e8cSDaniel Vetter 
30744b096ac1SDaniel Vetter 		list_del_init(&fb->filp_head);
30752b677e8cSDaniel Vetter 
30762b677e8cSDaniel Vetter 		/* This will also drop the fpriv->fbs reference. */
3077f7eff60eSRob Clark 		drm_framebuffer_remove(fb);
3078f453ba04SDave Airlie 	}
30794b096ac1SDaniel Vetter 	mutex_unlock(&priv->fbs_lock);
3080f453ba04SDave Airlie }
3081f453ba04SDave Airlie 
3082c8e32cc1SDaniel Vetter /**
3083c8e32cc1SDaniel Vetter  * drm_property_create - create a new property type
3084c8e32cc1SDaniel Vetter  * @dev: drm device
3085c8e32cc1SDaniel Vetter  * @flags: flags specifying the property type
3086c8e32cc1SDaniel Vetter  * @name: name of the property
3087c8e32cc1SDaniel Vetter  * @num_values: number of pre-defined values
3088c8e32cc1SDaniel Vetter  *
3089c8e32cc1SDaniel Vetter  * This creates a new generic drm property which can then be attached to a drm
3090c8e32cc1SDaniel Vetter  * object with drm_object_attach_property. The returned property object must be
3091c8e32cc1SDaniel Vetter  * freed with drm_property_destroy.
3092c8e32cc1SDaniel Vetter  *
3093c8e32cc1SDaniel Vetter  * Returns:
3094c8e32cc1SDaniel Vetter  * A pointer to the newly created property on success, NULL on failure.
3095c8e32cc1SDaniel Vetter  */
3096f453ba04SDave Airlie struct drm_property *drm_property_create(struct drm_device *dev, int flags,
3097f453ba04SDave Airlie 					 const char *name, int num_values)
3098f453ba04SDave Airlie {
3099f453ba04SDave Airlie 	struct drm_property *property = NULL;
31006bfc56aaSVille Syrjälä 	int ret;
3101f453ba04SDave Airlie 
3102f453ba04SDave Airlie 	property = kzalloc(sizeof(struct drm_property), GFP_KERNEL);
3103f453ba04SDave Airlie 	if (!property)
3104f453ba04SDave Airlie 		return NULL;
3105f453ba04SDave Airlie 
3106f453ba04SDave Airlie 	if (num_values) {
3107f453ba04SDave Airlie 		property->values = kzalloc(sizeof(uint64_t)*num_values, GFP_KERNEL);
3108f453ba04SDave Airlie 		if (!property->values)
3109f453ba04SDave Airlie 			goto fail;
3110f453ba04SDave Airlie 	}
3111f453ba04SDave Airlie 
31126bfc56aaSVille Syrjälä 	ret = drm_mode_object_get(dev, &property->base, DRM_MODE_OBJECT_PROPERTY);
31136bfc56aaSVille Syrjälä 	if (ret)
31146bfc56aaSVille Syrjälä 		goto fail;
31156bfc56aaSVille Syrjälä 
3116f453ba04SDave Airlie 	property->flags = flags;
3117f453ba04SDave Airlie 	property->num_values = num_values;
3118f453ba04SDave Airlie 	INIT_LIST_HEAD(&property->enum_blob_list);
3119f453ba04SDave Airlie 
3120471dd2efSVinson Lee 	if (name) {
3121f453ba04SDave Airlie 		strncpy(property->name, name, DRM_PROP_NAME_LEN);
3122471dd2efSVinson Lee 		property->name[DRM_PROP_NAME_LEN-1] = '\0';
3123471dd2efSVinson Lee 	}
3124f453ba04SDave Airlie 
3125f453ba04SDave Airlie 	list_add_tail(&property->head, &dev->mode_config.property_list);
3126f453ba04SDave Airlie 	return property;
3127f453ba04SDave Airlie fail:
31286bfc56aaSVille Syrjälä 	kfree(property->values);
3129f453ba04SDave Airlie 	kfree(property);
3130f453ba04SDave Airlie 	return NULL;
3131f453ba04SDave Airlie }
3132f453ba04SDave Airlie EXPORT_SYMBOL(drm_property_create);
3133f453ba04SDave Airlie 
3134c8e32cc1SDaniel Vetter /**
3135c8e32cc1SDaniel Vetter  * drm_property_create - create a new enumeration property type
3136c8e32cc1SDaniel Vetter  * @dev: drm device
3137c8e32cc1SDaniel Vetter  * @flags: flags specifying the property type
3138c8e32cc1SDaniel Vetter  * @name: name of the property
3139c8e32cc1SDaniel Vetter  * @props: enumeration lists with property values
3140c8e32cc1SDaniel Vetter  * @num_values: number of pre-defined values
3141c8e32cc1SDaniel Vetter  *
3142c8e32cc1SDaniel Vetter  * This creates a new generic drm property which can then be attached to a drm
3143c8e32cc1SDaniel Vetter  * object with drm_object_attach_property. The returned property object must be
3144c8e32cc1SDaniel Vetter  * freed with drm_property_destroy.
3145c8e32cc1SDaniel Vetter  *
3146c8e32cc1SDaniel Vetter  * Userspace is only allowed to set one of the predefined values for enumeration
3147c8e32cc1SDaniel Vetter  * properties.
3148c8e32cc1SDaniel Vetter  *
3149c8e32cc1SDaniel Vetter  * Returns:
3150c8e32cc1SDaniel Vetter  * A pointer to the newly created property on success, NULL on failure.
3151c8e32cc1SDaniel Vetter  */
31524a67d391SSascha Hauer struct drm_property *drm_property_create_enum(struct drm_device *dev, int flags,
31534a67d391SSascha Hauer 					 const char *name,
31544a67d391SSascha Hauer 					 const struct drm_prop_enum_list *props,
31554a67d391SSascha Hauer 					 int num_values)
31564a67d391SSascha Hauer {
31574a67d391SSascha Hauer 	struct drm_property *property;
31584a67d391SSascha Hauer 	int i, ret;
31594a67d391SSascha Hauer 
31604a67d391SSascha Hauer 	flags |= DRM_MODE_PROP_ENUM;
31614a67d391SSascha Hauer 
31624a67d391SSascha Hauer 	property = drm_property_create(dev, flags, name, num_values);
31634a67d391SSascha Hauer 	if (!property)
31644a67d391SSascha Hauer 		return NULL;
31654a67d391SSascha Hauer 
31664a67d391SSascha Hauer 	for (i = 0; i < num_values; i++) {
31674a67d391SSascha Hauer 		ret = drm_property_add_enum(property, i,
31684a67d391SSascha Hauer 				      props[i].type,
31694a67d391SSascha Hauer 				      props[i].name);
31704a67d391SSascha Hauer 		if (ret) {
31714a67d391SSascha Hauer 			drm_property_destroy(dev, property);
31724a67d391SSascha Hauer 			return NULL;
31734a67d391SSascha Hauer 		}
31744a67d391SSascha Hauer 	}
31754a67d391SSascha Hauer 
31764a67d391SSascha Hauer 	return property;
31774a67d391SSascha Hauer }
31784a67d391SSascha Hauer EXPORT_SYMBOL(drm_property_create_enum);
31794a67d391SSascha Hauer 
3180c8e32cc1SDaniel Vetter /**
3181c8e32cc1SDaniel Vetter  * drm_property_create - create a new bitmask property type
3182c8e32cc1SDaniel Vetter  * @dev: drm device
3183c8e32cc1SDaniel Vetter  * @flags: flags specifying the property type
3184c8e32cc1SDaniel Vetter  * @name: name of the property
3185c8e32cc1SDaniel Vetter  * @props: enumeration lists with property bitflags
3186c8e32cc1SDaniel Vetter  * @num_values: number of pre-defined values
3187c8e32cc1SDaniel Vetter  *
3188c8e32cc1SDaniel Vetter  * This creates a new generic drm property which can then be attached to a drm
3189c8e32cc1SDaniel Vetter  * object with drm_object_attach_property. The returned property object must be
3190c8e32cc1SDaniel Vetter  * freed with drm_property_destroy.
3191c8e32cc1SDaniel Vetter  *
3192c8e32cc1SDaniel Vetter  * Compared to plain enumeration properties userspace is allowed to set any
3193c8e32cc1SDaniel Vetter  * or'ed together combination of the predefined property bitflag values
3194c8e32cc1SDaniel Vetter  *
3195c8e32cc1SDaniel Vetter  * Returns:
3196c8e32cc1SDaniel Vetter  * A pointer to the newly created property on success, NULL on failure.
3197c8e32cc1SDaniel Vetter  */
319849e27545SRob Clark struct drm_property *drm_property_create_bitmask(struct drm_device *dev,
319949e27545SRob Clark 					 int flags, const char *name,
320049e27545SRob Clark 					 const struct drm_prop_enum_list *props,
320149e27545SRob Clark 					 int num_values)
320249e27545SRob Clark {
320349e27545SRob Clark 	struct drm_property *property;
320449e27545SRob Clark 	int i, ret;
320549e27545SRob Clark 
320649e27545SRob Clark 	flags |= DRM_MODE_PROP_BITMASK;
320749e27545SRob Clark 
320849e27545SRob Clark 	property = drm_property_create(dev, flags, name, num_values);
320949e27545SRob Clark 	if (!property)
321049e27545SRob Clark 		return NULL;
321149e27545SRob Clark 
321249e27545SRob Clark 	for (i = 0; i < num_values; i++) {
321349e27545SRob Clark 		ret = drm_property_add_enum(property, i,
321449e27545SRob Clark 				      props[i].type,
321549e27545SRob Clark 				      props[i].name);
321649e27545SRob Clark 		if (ret) {
321749e27545SRob Clark 			drm_property_destroy(dev, property);
321849e27545SRob Clark 			return NULL;
321949e27545SRob Clark 		}
322049e27545SRob Clark 	}
322149e27545SRob Clark 
322249e27545SRob Clark 	return property;
322349e27545SRob Clark }
322449e27545SRob Clark EXPORT_SYMBOL(drm_property_create_bitmask);
322549e27545SRob Clark 
3226c8e32cc1SDaniel Vetter /**
3227c8e32cc1SDaniel Vetter  * drm_property_create - create a new ranged property type
3228c8e32cc1SDaniel Vetter  * @dev: drm device
3229c8e32cc1SDaniel Vetter  * @flags: flags specifying the property type
3230c8e32cc1SDaniel Vetter  * @name: name of the property
3231c8e32cc1SDaniel Vetter  * @min: minimum value of the property
3232c8e32cc1SDaniel Vetter  * @max: maximum value of the property
3233c8e32cc1SDaniel Vetter  *
3234c8e32cc1SDaniel Vetter  * This creates a new generic drm property which can then be attached to a drm
3235c8e32cc1SDaniel Vetter  * object with drm_object_attach_property. The returned property object must be
3236c8e32cc1SDaniel Vetter  * freed with drm_property_destroy.
3237c8e32cc1SDaniel Vetter  *
3238c8e32cc1SDaniel Vetter  * Userspace is allowed to set any interger value in the (min, max) range
3239c8e32cc1SDaniel Vetter  * inclusive.
3240c8e32cc1SDaniel Vetter  *
3241c8e32cc1SDaniel Vetter  * Returns:
3242c8e32cc1SDaniel Vetter  * A pointer to the newly created property on success, NULL on failure.
3243c8e32cc1SDaniel Vetter  */
3244d9bc3c02SSascha Hauer struct drm_property *drm_property_create_range(struct drm_device *dev, int flags,
3245d9bc3c02SSascha Hauer 					 const char *name,
3246d9bc3c02SSascha Hauer 					 uint64_t min, uint64_t max)
3247d9bc3c02SSascha Hauer {
3248d9bc3c02SSascha Hauer 	struct drm_property *property;
3249d9bc3c02SSascha Hauer 
3250d9bc3c02SSascha Hauer 	flags |= DRM_MODE_PROP_RANGE;
3251d9bc3c02SSascha Hauer 
3252d9bc3c02SSascha Hauer 	property = drm_property_create(dev, flags, name, 2);
3253d9bc3c02SSascha Hauer 	if (!property)
3254d9bc3c02SSascha Hauer 		return NULL;
3255d9bc3c02SSascha Hauer 
3256d9bc3c02SSascha Hauer 	property->values[0] = min;
3257d9bc3c02SSascha Hauer 	property->values[1] = max;
3258d9bc3c02SSascha Hauer 
3259d9bc3c02SSascha Hauer 	return property;
3260d9bc3c02SSascha Hauer }
3261d9bc3c02SSascha Hauer EXPORT_SYMBOL(drm_property_create_range);
3262d9bc3c02SSascha Hauer 
3263c8e32cc1SDaniel Vetter /**
3264c8e32cc1SDaniel Vetter  * drm_property_add_enum - add a possible value to an enumeration property
3265c8e32cc1SDaniel Vetter  * @property: enumeration property to change
3266c8e32cc1SDaniel Vetter  * @index: index of the new enumeration
3267c8e32cc1SDaniel Vetter  * @value: value of the new enumeration
3268c8e32cc1SDaniel Vetter  * @name: symbolic name of the new enumeration
3269c8e32cc1SDaniel Vetter  *
3270c8e32cc1SDaniel Vetter  * This functions adds enumerations to a property.
3271c8e32cc1SDaniel Vetter  *
3272c8e32cc1SDaniel Vetter  * It's use is deprecated, drivers should use one of the more specific helpers
3273c8e32cc1SDaniel Vetter  * to directly create the property with all enumerations already attached.
3274c8e32cc1SDaniel Vetter  *
3275c8e32cc1SDaniel Vetter  * Returns:
3276c8e32cc1SDaniel Vetter  * Zero on success, error code on failure.
3277c8e32cc1SDaniel Vetter  */
3278f453ba04SDave Airlie int drm_property_add_enum(struct drm_property *property, int index,
3279f453ba04SDave Airlie 			  uint64_t value, const char *name)
3280f453ba04SDave Airlie {
3281f453ba04SDave Airlie 	struct drm_property_enum *prop_enum;
3282f453ba04SDave Airlie 
328349e27545SRob Clark 	if (!(property->flags & (DRM_MODE_PROP_ENUM | DRM_MODE_PROP_BITMASK)))
328449e27545SRob Clark 		return -EINVAL;
328549e27545SRob Clark 
328649e27545SRob Clark 	/*
328749e27545SRob Clark 	 * Bitmask enum properties have the additional constraint of values
328849e27545SRob Clark 	 * from 0 to 63
328949e27545SRob Clark 	 */
329049e27545SRob Clark 	if ((property->flags & DRM_MODE_PROP_BITMASK) && (value > 63))
3291f453ba04SDave Airlie 		return -EINVAL;
3292f453ba04SDave Airlie 
3293f453ba04SDave Airlie 	if (!list_empty(&property->enum_blob_list)) {
3294f453ba04SDave Airlie 		list_for_each_entry(prop_enum, &property->enum_blob_list, head) {
3295f453ba04SDave Airlie 			if (prop_enum->value == value) {
3296f453ba04SDave Airlie 				strncpy(prop_enum->name, name, DRM_PROP_NAME_LEN);
3297f453ba04SDave Airlie 				prop_enum->name[DRM_PROP_NAME_LEN-1] = '\0';
3298f453ba04SDave Airlie 				return 0;
3299f453ba04SDave Airlie 			}
3300f453ba04SDave Airlie 		}
3301f453ba04SDave Airlie 	}
3302f453ba04SDave Airlie 
3303f453ba04SDave Airlie 	prop_enum = kzalloc(sizeof(struct drm_property_enum), GFP_KERNEL);
3304f453ba04SDave Airlie 	if (!prop_enum)
3305f453ba04SDave Airlie 		return -ENOMEM;
3306f453ba04SDave Airlie 
3307f453ba04SDave Airlie 	strncpy(prop_enum->name, name, DRM_PROP_NAME_LEN);
3308f453ba04SDave Airlie 	prop_enum->name[DRM_PROP_NAME_LEN-1] = '\0';
3309f453ba04SDave Airlie 	prop_enum->value = value;
3310f453ba04SDave Airlie 
3311f453ba04SDave Airlie 	property->values[index] = value;
3312f453ba04SDave Airlie 	list_add_tail(&prop_enum->head, &property->enum_blob_list);
3313f453ba04SDave Airlie 	return 0;
3314f453ba04SDave Airlie }
3315f453ba04SDave Airlie EXPORT_SYMBOL(drm_property_add_enum);
3316f453ba04SDave Airlie 
3317c8e32cc1SDaniel Vetter /**
3318c8e32cc1SDaniel Vetter  * drm_property_destroy - destroy a drm property
3319c8e32cc1SDaniel Vetter  * @dev: drm device
3320c8e32cc1SDaniel Vetter  * @property: property to destry
3321c8e32cc1SDaniel Vetter  *
3322c8e32cc1SDaniel Vetter  * This function frees a property including any attached resources like
3323c8e32cc1SDaniel Vetter  * enumeration values.
3324c8e32cc1SDaniel Vetter  */
3325f453ba04SDave Airlie void drm_property_destroy(struct drm_device *dev, struct drm_property *property)
3326f453ba04SDave Airlie {
3327f453ba04SDave Airlie 	struct drm_property_enum *prop_enum, *pt;
3328f453ba04SDave Airlie 
3329f453ba04SDave Airlie 	list_for_each_entry_safe(prop_enum, pt, &property->enum_blob_list, head) {
3330f453ba04SDave Airlie 		list_del(&prop_enum->head);
3331f453ba04SDave Airlie 		kfree(prop_enum);
3332f453ba04SDave Airlie 	}
3333f453ba04SDave Airlie 
3334f453ba04SDave Airlie 	if (property->num_values)
3335f453ba04SDave Airlie 		kfree(property->values);
3336f453ba04SDave Airlie 	drm_mode_object_put(dev, &property->base);
3337f453ba04SDave Airlie 	list_del(&property->head);
3338f453ba04SDave Airlie 	kfree(property);
3339f453ba04SDave Airlie }
3340f453ba04SDave Airlie EXPORT_SYMBOL(drm_property_destroy);
3341f453ba04SDave Airlie 
3342c8e32cc1SDaniel Vetter /**
3343c8e32cc1SDaniel Vetter  * drm_object_attach_property - attach a property to a modeset object
3344c8e32cc1SDaniel Vetter  * @obj: drm modeset object
3345c8e32cc1SDaniel Vetter  * @property: property to attach
3346c8e32cc1SDaniel Vetter  * @init_val: initial value of the property
3347c8e32cc1SDaniel Vetter  *
3348c8e32cc1SDaniel Vetter  * This attaches the given property to the modeset object with the given initial
3349c8e32cc1SDaniel Vetter  * value. Currently this function cannot fail since the properties are stored in
3350c8e32cc1SDaniel Vetter  * a statically sized array.
3351c8e32cc1SDaniel Vetter  */
3352c543188aSPaulo Zanoni void drm_object_attach_property(struct drm_mode_object *obj,
3353c543188aSPaulo Zanoni 				struct drm_property *property,
3354c543188aSPaulo Zanoni 				uint64_t init_val)
3355c543188aSPaulo Zanoni {
33567f88a9beSPaulo Zanoni 	int count = obj->properties->count;
3357c543188aSPaulo Zanoni 
33587f88a9beSPaulo Zanoni 	if (count == DRM_OBJECT_MAX_PROPERTY) {
33597f88a9beSPaulo Zanoni 		WARN(1, "Failed to attach object property (type: 0x%x). Please "
33607f88a9beSPaulo Zanoni 			"increase DRM_OBJECT_MAX_PROPERTY by 1 for each time "
33617f88a9beSPaulo Zanoni 			"you see this message on the same object type.\n",
33627f88a9beSPaulo Zanoni 			obj->type);
3363c543188aSPaulo Zanoni 		return;
3364c543188aSPaulo Zanoni 	}
3365c543188aSPaulo Zanoni 
33667f88a9beSPaulo Zanoni 	obj->properties->ids[count] = property->base.id;
33677f88a9beSPaulo Zanoni 	obj->properties->values[count] = init_val;
33687f88a9beSPaulo Zanoni 	obj->properties->count++;
3369c543188aSPaulo Zanoni }
3370c543188aSPaulo Zanoni EXPORT_SYMBOL(drm_object_attach_property);
3371c543188aSPaulo Zanoni 
3372c8e32cc1SDaniel Vetter /**
3373c8e32cc1SDaniel Vetter  * drm_object_property_set_value - set the value of a property
3374c8e32cc1SDaniel Vetter  * @obj: drm mode object to set property value for
3375c8e32cc1SDaniel Vetter  * @property: property to set
3376c8e32cc1SDaniel Vetter  * @val: value the property should be set to
3377c8e32cc1SDaniel Vetter  *
3378c8e32cc1SDaniel Vetter  * This functions sets a given property on a given object. This function only
3379c8e32cc1SDaniel Vetter  * changes the software state of the property, it does not call into the
3380c8e32cc1SDaniel Vetter  * driver's ->set_property callback.
3381c8e32cc1SDaniel Vetter  *
3382c8e32cc1SDaniel Vetter  * Returns:
3383c8e32cc1SDaniel Vetter  * Zero on success, error code on failure.
3384c8e32cc1SDaniel Vetter  */
3385c543188aSPaulo Zanoni int drm_object_property_set_value(struct drm_mode_object *obj,
3386c543188aSPaulo Zanoni 				  struct drm_property *property, uint64_t val)
3387c543188aSPaulo Zanoni {
3388c543188aSPaulo Zanoni 	int i;
3389c543188aSPaulo Zanoni 
33907f88a9beSPaulo Zanoni 	for (i = 0; i < obj->properties->count; i++) {
3391c543188aSPaulo Zanoni 		if (obj->properties->ids[i] == property->base.id) {
3392c543188aSPaulo Zanoni 			obj->properties->values[i] = val;
3393c543188aSPaulo Zanoni 			return 0;
3394c543188aSPaulo Zanoni 		}
3395c543188aSPaulo Zanoni 	}
3396c543188aSPaulo Zanoni 
3397c543188aSPaulo Zanoni 	return -EINVAL;
3398c543188aSPaulo Zanoni }
3399c543188aSPaulo Zanoni EXPORT_SYMBOL(drm_object_property_set_value);
3400c543188aSPaulo Zanoni 
3401c8e32cc1SDaniel Vetter /**
3402c8e32cc1SDaniel Vetter  * drm_object_property_get_value - retrieve the value of a property
3403c8e32cc1SDaniel Vetter  * @obj: drm mode object to get property value from
3404c8e32cc1SDaniel Vetter  * @property: property to retrieve
3405c8e32cc1SDaniel Vetter  * @val: storage for the property value
3406c8e32cc1SDaniel Vetter  *
3407c8e32cc1SDaniel Vetter  * This function retrieves the softare state of the given property for the given
3408c8e32cc1SDaniel Vetter  * property. Since there is no driver callback to retrieve the current property
3409c8e32cc1SDaniel Vetter  * value this might be out of sync with the hardware, depending upon the driver
3410c8e32cc1SDaniel Vetter  * and property.
3411c8e32cc1SDaniel Vetter  *
3412c8e32cc1SDaniel Vetter  * Returns:
3413c8e32cc1SDaniel Vetter  * Zero on success, error code on failure.
3414c8e32cc1SDaniel Vetter  */
3415c543188aSPaulo Zanoni int drm_object_property_get_value(struct drm_mode_object *obj,
3416c543188aSPaulo Zanoni 				  struct drm_property *property, uint64_t *val)
3417c543188aSPaulo Zanoni {
3418c543188aSPaulo Zanoni 	int i;
3419c543188aSPaulo Zanoni 
34207f88a9beSPaulo Zanoni 	for (i = 0; i < obj->properties->count; i++) {
3421c543188aSPaulo Zanoni 		if (obj->properties->ids[i] == property->base.id) {
3422c543188aSPaulo Zanoni 			*val = obj->properties->values[i];
3423c543188aSPaulo Zanoni 			return 0;
3424c543188aSPaulo Zanoni 		}
3425c543188aSPaulo Zanoni 	}
3426c543188aSPaulo Zanoni 
3427c543188aSPaulo Zanoni 	return -EINVAL;
3428c543188aSPaulo Zanoni }
3429c543188aSPaulo Zanoni EXPORT_SYMBOL(drm_object_property_get_value);
3430c543188aSPaulo Zanoni 
3431c8e32cc1SDaniel Vetter /**
3432c8e32cc1SDaniel Vetter  * drm_mode_getproperty_ioctl - get the current value of a connector's property
3433c8e32cc1SDaniel Vetter  * @dev: DRM device
3434c8e32cc1SDaniel Vetter  * @data: ioctl data
3435c8e32cc1SDaniel Vetter  * @file_priv: DRM file info
3436c8e32cc1SDaniel Vetter  *
3437c8e32cc1SDaniel Vetter  * This function retrieves the current value for an connectors's property.
3438c8e32cc1SDaniel Vetter  *
3439c8e32cc1SDaniel Vetter  * Called by the user via ioctl.
3440c8e32cc1SDaniel Vetter  *
3441c8e32cc1SDaniel Vetter  * Returns:
3442c8e32cc1SDaniel Vetter  * Zero on success, errno on failure.
3443c8e32cc1SDaniel Vetter  */
3444f453ba04SDave Airlie int drm_mode_getproperty_ioctl(struct drm_device *dev,
3445f453ba04SDave Airlie 			       void *data, struct drm_file *file_priv)
3446f453ba04SDave Airlie {
3447f453ba04SDave Airlie 	struct drm_mode_object *obj;
3448f453ba04SDave Airlie 	struct drm_mode_get_property *out_resp = data;
3449f453ba04SDave Airlie 	struct drm_property *property;
3450f453ba04SDave Airlie 	int enum_count = 0;
3451f453ba04SDave Airlie 	int blob_count = 0;
3452f453ba04SDave Airlie 	int value_count = 0;
3453f453ba04SDave Airlie 	int ret = 0, i;
3454f453ba04SDave Airlie 	int copied;
3455f453ba04SDave Airlie 	struct drm_property_enum *prop_enum;
3456f453ba04SDave Airlie 	struct drm_mode_property_enum __user *enum_ptr;
3457f453ba04SDave Airlie 	struct drm_property_blob *prop_blob;
345881f6c7f8SVille Syrjälä 	uint32_t __user *blob_id_ptr;
3459f453ba04SDave Airlie 	uint64_t __user *values_ptr;
3460f453ba04SDave Airlie 	uint32_t __user *blob_length_ptr;
3461f453ba04SDave Airlie 
3462fb3b06c8SDave Airlie 	if (!drm_core_check_feature(dev, DRIVER_MODESET))
3463fb3b06c8SDave Airlie 		return -EINVAL;
3464fb3b06c8SDave Airlie 
346584849903SDaniel Vetter 	drm_modeset_lock_all(dev);
3466f453ba04SDave Airlie 	obj = drm_mode_object_find(dev, out_resp->prop_id, DRM_MODE_OBJECT_PROPERTY);
3467f453ba04SDave Airlie 	if (!obj) {
3468f27657f2SVille Syrjälä 		ret = -ENOENT;
3469f453ba04SDave Airlie 		goto done;
3470f453ba04SDave Airlie 	}
3471f453ba04SDave Airlie 	property = obj_to_property(obj);
3472f453ba04SDave Airlie 
347349e27545SRob Clark 	if (property->flags & (DRM_MODE_PROP_ENUM | DRM_MODE_PROP_BITMASK)) {
3474f453ba04SDave Airlie 		list_for_each_entry(prop_enum, &property->enum_blob_list, head)
3475f453ba04SDave Airlie 			enum_count++;
3476f453ba04SDave Airlie 	} else if (property->flags & DRM_MODE_PROP_BLOB) {
3477f453ba04SDave Airlie 		list_for_each_entry(prop_blob, &property->enum_blob_list, head)
3478f453ba04SDave Airlie 			blob_count++;
3479f453ba04SDave Airlie 	}
3480f453ba04SDave Airlie 
3481f453ba04SDave Airlie 	value_count = property->num_values;
3482f453ba04SDave Airlie 
3483f453ba04SDave Airlie 	strncpy(out_resp->name, property->name, DRM_PROP_NAME_LEN);
3484f453ba04SDave Airlie 	out_resp->name[DRM_PROP_NAME_LEN-1] = 0;
3485f453ba04SDave Airlie 	out_resp->flags = property->flags;
3486f453ba04SDave Airlie 
3487f453ba04SDave Airlie 	if ((out_resp->count_values >= value_count) && value_count) {
348881f6c7f8SVille Syrjälä 		values_ptr = (uint64_t __user *)(unsigned long)out_resp->values_ptr;
3489f453ba04SDave Airlie 		for (i = 0; i < value_count; i++) {
3490f453ba04SDave Airlie 			if (copy_to_user(values_ptr + i, &property->values[i], sizeof(uint64_t))) {
3491f453ba04SDave Airlie 				ret = -EFAULT;
3492f453ba04SDave Airlie 				goto done;
3493f453ba04SDave Airlie 			}
3494f453ba04SDave Airlie 		}
3495f453ba04SDave Airlie 	}
3496f453ba04SDave Airlie 	out_resp->count_values = value_count;
3497f453ba04SDave Airlie 
349849e27545SRob Clark 	if (property->flags & (DRM_MODE_PROP_ENUM | DRM_MODE_PROP_BITMASK)) {
3499f453ba04SDave Airlie 		if ((out_resp->count_enum_blobs >= enum_count) && enum_count) {
3500f453ba04SDave Airlie 			copied = 0;
350181f6c7f8SVille Syrjälä 			enum_ptr = (struct drm_mode_property_enum __user *)(unsigned long)out_resp->enum_blob_ptr;
3502f453ba04SDave Airlie 			list_for_each_entry(prop_enum, &property->enum_blob_list, head) {
3503f453ba04SDave Airlie 
3504f453ba04SDave Airlie 				if (copy_to_user(&enum_ptr[copied].value, &prop_enum->value, sizeof(uint64_t))) {
3505f453ba04SDave Airlie 					ret = -EFAULT;
3506f453ba04SDave Airlie 					goto done;
3507f453ba04SDave Airlie 				}
3508f453ba04SDave Airlie 
3509f453ba04SDave Airlie 				if (copy_to_user(&enum_ptr[copied].name,
3510f453ba04SDave Airlie 						 &prop_enum->name, DRM_PROP_NAME_LEN)) {
3511f453ba04SDave Airlie 					ret = -EFAULT;
3512f453ba04SDave Airlie 					goto done;
3513f453ba04SDave Airlie 				}
3514f453ba04SDave Airlie 				copied++;
3515f453ba04SDave Airlie 			}
3516f453ba04SDave Airlie 		}
3517f453ba04SDave Airlie 		out_resp->count_enum_blobs = enum_count;
3518f453ba04SDave Airlie 	}
3519f453ba04SDave Airlie 
3520f453ba04SDave Airlie 	if (property->flags & DRM_MODE_PROP_BLOB) {
3521f453ba04SDave Airlie 		if ((out_resp->count_enum_blobs >= blob_count) && blob_count) {
3522f453ba04SDave Airlie 			copied = 0;
352381f6c7f8SVille Syrjälä 			blob_id_ptr = (uint32_t __user *)(unsigned long)out_resp->enum_blob_ptr;
352481f6c7f8SVille Syrjälä 			blob_length_ptr = (uint32_t __user *)(unsigned long)out_resp->values_ptr;
3525f453ba04SDave Airlie 
3526f453ba04SDave Airlie 			list_for_each_entry(prop_blob, &property->enum_blob_list, head) {
3527f453ba04SDave Airlie 				if (put_user(prop_blob->base.id, blob_id_ptr + copied)) {
3528f453ba04SDave Airlie 					ret = -EFAULT;
3529f453ba04SDave Airlie 					goto done;
3530f453ba04SDave Airlie 				}
3531f453ba04SDave Airlie 
3532f453ba04SDave Airlie 				if (put_user(prop_blob->length, blob_length_ptr + copied)) {
3533f453ba04SDave Airlie 					ret = -EFAULT;
3534f453ba04SDave Airlie 					goto done;
3535f453ba04SDave Airlie 				}
3536f453ba04SDave Airlie 
3537f453ba04SDave Airlie 				copied++;
3538f453ba04SDave Airlie 			}
3539f453ba04SDave Airlie 		}
3540f453ba04SDave Airlie 		out_resp->count_enum_blobs = blob_count;
3541f453ba04SDave Airlie 	}
3542f453ba04SDave Airlie done:
354384849903SDaniel Vetter 	drm_modeset_unlock_all(dev);
3544f453ba04SDave Airlie 	return ret;
3545f453ba04SDave Airlie }
3546f453ba04SDave Airlie 
3547f453ba04SDave Airlie static struct drm_property_blob *drm_property_create_blob(struct drm_device *dev, int length,
3548f453ba04SDave Airlie 							  void *data)
3549f453ba04SDave Airlie {
3550f453ba04SDave Airlie 	struct drm_property_blob *blob;
35516bfc56aaSVille Syrjälä 	int ret;
3552f453ba04SDave Airlie 
3553f453ba04SDave Airlie 	if (!length || !data)
3554f453ba04SDave Airlie 		return NULL;
3555f453ba04SDave Airlie 
3556f453ba04SDave Airlie 	blob = kzalloc(sizeof(struct drm_property_blob)+length, GFP_KERNEL);
3557f453ba04SDave Airlie 	if (!blob)
3558f453ba04SDave Airlie 		return NULL;
3559f453ba04SDave Airlie 
35606bfc56aaSVille Syrjälä 	ret = drm_mode_object_get(dev, &blob->base, DRM_MODE_OBJECT_BLOB);
35616bfc56aaSVille Syrjälä 	if (ret) {
35626bfc56aaSVille Syrjälä 		kfree(blob);
35636bfc56aaSVille Syrjälä 		return NULL;
35646bfc56aaSVille Syrjälä 	}
35656bfc56aaSVille Syrjälä 
3566f453ba04SDave Airlie 	blob->length = length;
3567f453ba04SDave Airlie 
3568f453ba04SDave Airlie 	memcpy(blob->data, data, length);
3569f453ba04SDave Airlie 
3570f453ba04SDave Airlie 	list_add_tail(&blob->head, &dev->mode_config.property_blob_list);
3571f453ba04SDave Airlie 	return blob;
3572f453ba04SDave Airlie }
3573f453ba04SDave Airlie 
3574f453ba04SDave Airlie static void drm_property_destroy_blob(struct drm_device *dev,
3575f453ba04SDave Airlie 			       struct drm_property_blob *blob)
3576f453ba04SDave Airlie {
3577f453ba04SDave Airlie 	drm_mode_object_put(dev, &blob->base);
3578f453ba04SDave Airlie 	list_del(&blob->head);
3579f453ba04SDave Airlie 	kfree(blob);
3580f453ba04SDave Airlie }
3581f453ba04SDave Airlie 
3582c8e32cc1SDaniel Vetter /**
3583c8e32cc1SDaniel Vetter  * drm_mode_getblob_ioctl - get the contents of a blob property value
3584c8e32cc1SDaniel Vetter  * @dev: DRM device
3585c8e32cc1SDaniel Vetter  * @data: ioctl data
3586c8e32cc1SDaniel Vetter  * @file_priv: DRM file info
3587c8e32cc1SDaniel Vetter  *
3588c8e32cc1SDaniel Vetter  * This function retrieves the contents of a blob property. The value stored in
3589c8e32cc1SDaniel Vetter  * an object's blob property is just a normal modeset object id.
3590c8e32cc1SDaniel Vetter  *
3591c8e32cc1SDaniel Vetter  * Called by the user via ioctl.
3592c8e32cc1SDaniel Vetter  *
3593c8e32cc1SDaniel Vetter  * Returns:
3594c8e32cc1SDaniel Vetter  * Zero on success, errno on failure.
3595c8e32cc1SDaniel Vetter  */
3596f453ba04SDave Airlie int drm_mode_getblob_ioctl(struct drm_device *dev,
3597f453ba04SDave Airlie 			   void *data, struct drm_file *file_priv)
3598f453ba04SDave Airlie {
3599f453ba04SDave Airlie 	struct drm_mode_object *obj;
3600f453ba04SDave Airlie 	struct drm_mode_get_blob *out_resp = data;
3601f453ba04SDave Airlie 	struct drm_property_blob *blob;
3602f453ba04SDave Airlie 	int ret = 0;
360381f6c7f8SVille Syrjälä 	void __user *blob_ptr;
3604f453ba04SDave Airlie 
3605fb3b06c8SDave Airlie 	if (!drm_core_check_feature(dev, DRIVER_MODESET))
3606fb3b06c8SDave Airlie 		return -EINVAL;
3607fb3b06c8SDave Airlie 
360884849903SDaniel Vetter 	drm_modeset_lock_all(dev);
3609f453ba04SDave Airlie 	obj = drm_mode_object_find(dev, out_resp->blob_id, DRM_MODE_OBJECT_BLOB);
3610f453ba04SDave Airlie 	if (!obj) {
3611f27657f2SVille Syrjälä 		ret = -ENOENT;
3612f453ba04SDave Airlie 		goto done;
3613f453ba04SDave Airlie 	}
3614f453ba04SDave Airlie 	blob = obj_to_blob(obj);
3615f453ba04SDave Airlie 
3616f453ba04SDave Airlie 	if (out_resp->length == blob->length) {
361781f6c7f8SVille Syrjälä 		blob_ptr = (void __user *)(unsigned long)out_resp->data;
3618f453ba04SDave Airlie 		if (copy_to_user(blob_ptr, blob->data, blob->length)){
3619f453ba04SDave Airlie 			ret = -EFAULT;
3620f453ba04SDave Airlie 			goto done;
3621f453ba04SDave Airlie 		}
3622f453ba04SDave Airlie 	}
3623f453ba04SDave Airlie 	out_resp->length = blob->length;
3624f453ba04SDave Airlie 
3625f453ba04SDave Airlie done:
362684849903SDaniel Vetter 	drm_modeset_unlock_all(dev);
3627f453ba04SDave Airlie 	return ret;
3628f453ba04SDave Airlie }
3629f453ba04SDave Airlie 
3630c8e32cc1SDaniel Vetter /**
3631c8e32cc1SDaniel Vetter  * drm_mode_connector_update_edid_property - update the edid property of a connector
3632c8e32cc1SDaniel Vetter  * @connector: drm connector
3633c8e32cc1SDaniel Vetter  * @edid: new value of the edid property
3634c8e32cc1SDaniel Vetter  *
3635c8e32cc1SDaniel Vetter  * This function creates a new blob modeset object and assigns its id to the
3636c8e32cc1SDaniel Vetter  * connector's edid property.
3637c8e32cc1SDaniel Vetter  *
3638c8e32cc1SDaniel Vetter  * Returns:
3639c8e32cc1SDaniel Vetter  * Zero on success, errno on failure.
3640c8e32cc1SDaniel Vetter  */
3641f453ba04SDave Airlie int drm_mode_connector_update_edid_property(struct drm_connector *connector,
3642f453ba04SDave Airlie 					    struct edid *edid)
3643f453ba04SDave Airlie {
3644f453ba04SDave Airlie 	struct drm_device *dev = connector->dev;
36454a1b0714SLaurent Pinchart 	int ret, size;
3646f453ba04SDave Airlie 
3647f453ba04SDave Airlie 	if (connector->edid_blob_ptr)
3648f453ba04SDave Airlie 		drm_property_destroy_blob(dev, connector->edid_blob_ptr);
3649f453ba04SDave Airlie 
3650f453ba04SDave Airlie 	/* Delete edid, when there is none. */
3651f453ba04SDave Airlie 	if (!edid) {
3652f453ba04SDave Airlie 		connector->edid_blob_ptr = NULL;
365358495563SRob Clark 		ret = drm_object_property_set_value(&connector->base, dev->mode_config.edid_property, 0);
3654f453ba04SDave Airlie 		return ret;
3655f453ba04SDave Airlie 	}
3656f453ba04SDave Airlie 
36577466f4ccSAdam Jackson 	size = EDID_LENGTH * (1 + edid->extensions);
36587466f4ccSAdam Jackson 	connector->edid_blob_ptr = drm_property_create_blob(connector->dev,
36597466f4ccSAdam Jackson 							    size, edid);
3660e655d122SSachin Kamat 	if (!connector->edid_blob_ptr)
3661e655d122SSachin Kamat 		return -EINVAL;
3662f453ba04SDave Airlie 
366358495563SRob Clark 	ret = drm_object_property_set_value(&connector->base,
3664f453ba04SDave Airlie 					       dev->mode_config.edid_property,
3665f453ba04SDave Airlie 					       connector->edid_blob_ptr->base.id);
3666f453ba04SDave Airlie 
3667f453ba04SDave Airlie 	return ret;
3668f453ba04SDave Airlie }
3669f453ba04SDave Airlie EXPORT_SYMBOL(drm_mode_connector_update_edid_property);
3670f453ba04SDave Airlie 
367126a34815SPaulo Zanoni static bool drm_property_change_is_valid(struct drm_property *property,
3672592c20eeSVille Syrjälä 					 uint64_t value)
367326a34815SPaulo Zanoni {
367426a34815SPaulo Zanoni 	if (property->flags & DRM_MODE_PROP_IMMUTABLE)
367526a34815SPaulo Zanoni 		return false;
367626a34815SPaulo Zanoni 	if (property->flags & DRM_MODE_PROP_RANGE) {
367726a34815SPaulo Zanoni 		if (value < property->values[0] || value > property->values[1])
367826a34815SPaulo Zanoni 			return false;
367926a34815SPaulo Zanoni 		return true;
368049e27545SRob Clark 	} else if (property->flags & DRM_MODE_PROP_BITMASK) {
368149e27545SRob Clark 		int i;
3682592c20eeSVille Syrjälä 		uint64_t valid_mask = 0;
368349e27545SRob Clark 		for (i = 0; i < property->num_values; i++)
368449e27545SRob Clark 			valid_mask |= (1ULL << property->values[i]);
368549e27545SRob Clark 		return !(value & ~valid_mask);
3686c4a56750SVille Syrjälä 	} else if (property->flags & DRM_MODE_PROP_BLOB) {
3687c4a56750SVille Syrjälä 		/* Only the driver knows */
3688c4a56750SVille Syrjälä 		return true;
368926a34815SPaulo Zanoni 	} else {
369026a34815SPaulo Zanoni 		int i;
369126a34815SPaulo Zanoni 		for (i = 0; i < property->num_values; i++)
369226a34815SPaulo Zanoni 			if (property->values[i] == value)
369326a34815SPaulo Zanoni 				return true;
369426a34815SPaulo Zanoni 		return false;
369526a34815SPaulo Zanoni 	}
369626a34815SPaulo Zanoni }
369726a34815SPaulo Zanoni 
3698c8e32cc1SDaniel Vetter /**
3699c8e32cc1SDaniel Vetter  * drm_mode_connector_property_set_ioctl - set the current value of a connector property
3700c8e32cc1SDaniel Vetter  * @dev: DRM device
3701c8e32cc1SDaniel Vetter  * @data: ioctl data
3702c8e32cc1SDaniel Vetter  * @file_priv: DRM file info
3703c8e32cc1SDaniel Vetter  *
3704c8e32cc1SDaniel Vetter  * This function sets the current value for a connectors's property. It also
3705c8e32cc1SDaniel Vetter  * calls into a driver's ->set_property callback to update the hardware state
3706c8e32cc1SDaniel Vetter  *
3707c8e32cc1SDaniel Vetter  * Called by the user via ioctl.
3708c8e32cc1SDaniel Vetter  *
3709c8e32cc1SDaniel Vetter  * Returns:
3710c8e32cc1SDaniel Vetter  * Zero on success, errno on failure.
3711c8e32cc1SDaniel Vetter  */
3712f453ba04SDave Airlie int drm_mode_connector_property_set_ioctl(struct drm_device *dev,
3713f453ba04SDave Airlie 				       void *data, struct drm_file *file_priv)
3714f453ba04SDave Airlie {
37150057d8ddSPaulo Zanoni 	struct drm_mode_connector_set_property *conn_set_prop = data;
37160057d8ddSPaulo Zanoni 	struct drm_mode_obj_set_property obj_set_prop = {
37170057d8ddSPaulo Zanoni 		.value = conn_set_prop->value,
37180057d8ddSPaulo Zanoni 		.prop_id = conn_set_prop->prop_id,
37190057d8ddSPaulo Zanoni 		.obj_id = conn_set_prop->connector_id,
37200057d8ddSPaulo Zanoni 		.obj_type = DRM_MODE_OBJECT_CONNECTOR
37210057d8ddSPaulo Zanoni 	};
3722f453ba04SDave Airlie 
37230057d8ddSPaulo Zanoni 	/* It does all the locking and checking we need */
37240057d8ddSPaulo Zanoni 	return drm_mode_obj_set_property_ioctl(dev, &obj_set_prop, file_priv);
3725f453ba04SDave Airlie }
3726f453ba04SDave Airlie 
3727c543188aSPaulo Zanoni static int drm_mode_connector_set_obj_prop(struct drm_mode_object *obj,
3728c543188aSPaulo Zanoni 					   struct drm_property *property,
3729c543188aSPaulo Zanoni 					   uint64_t value)
3730c543188aSPaulo Zanoni {
3731c543188aSPaulo Zanoni 	int ret = -EINVAL;
3732c543188aSPaulo Zanoni 	struct drm_connector *connector = obj_to_connector(obj);
3733c543188aSPaulo Zanoni 
3734c543188aSPaulo Zanoni 	/* Do DPMS ourselves */
3735c543188aSPaulo Zanoni 	if (property == connector->dev->mode_config.dpms_property) {
3736c543188aSPaulo Zanoni 		if (connector->funcs->dpms)
3737c543188aSPaulo Zanoni 			(*connector->funcs->dpms)(connector, (int)value);
3738c543188aSPaulo Zanoni 		ret = 0;
3739c543188aSPaulo Zanoni 	} else if (connector->funcs->set_property)
3740c543188aSPaulo Zanoni 		ret = connector->funcs->set_property(connector, property, value);
3741c543188aSPaulo Zanoni 
3742c543188aSPaulo Zanoni 	/* store the property value if successful */
3743c543188aSPaulo Zanoni 	if (!ret)
374458495563SRob Clark 		drm_object_property_set_value(&connector->base, property, value);
3745c543188aSPaulo Zanoni 	return ret;
3746c543188aSPaulo Zanoni }
3747c543188aSPaulo Zanoni 
3748bffd9de0SPaulo Zanoni static int drm_mode_crtc_set_obj_prop(struct drm_mode_object *obj,
3749bffd9de0SPaulo Zanoni 				      struct drm_property *property,
3750bffd9de0SPaulo Zanoni 				      uint64_t value)
3751bffd9de0SPaulo Zanoni {
3752bffd9de0SPaulo Zanoni 	int ret = -EINVAL;
3753bffd9de0SPaulo Zanoni 	struct drm_crtc *crtc = obj_to_crtc(obj);
3754bffd9de0SPaulo Zanoni 
3755bffd9de0SPaulo Zanoni 	if (crtc->funcs->set_property)
3756bffd9de0SPaulo Zanoni 		ret = crtc->funcs->set_property(crtc, property, value);
3757bffd9de0SPaulo Zanoni 	if (!ret)
3758bffd9de0SPaulo Zanoni 		drm_object_property_set_value(obj, property, value);
3759bffd9de0SPaulo Zanoni 
3760bffd9de0SPaulo Zanoni 	return ret;
3761bffd9de0SPaulo Zanoni }
3762bffd9de0SPaulo Zanoni 
37634d93914aSRob Clark static int drm_mode_plane_set_obj_prop(struct drm_mode_object *obj,
37644d93914aSRob Clark 				      struct drm_property *property,
37654d93914aSRob Clark 				      uint64_t value)
37664d93914aSRob Clark {
37674d93914aSRob Clark 	int ret = -EINVAL;
37684d93914aSRob Clark 	struct drm_plane *plane = obj_to_plane(obj);
37694d93914aSRob Clark 
37704d93914aSRob Clark 	if (plane->funcs->set_property)
37714d93914aSRob Clark 		ret = plane->funcs->set_property(plane, property, value);
37724d93914aSRob Clark 	if (!ret)
37734d93914aSRob Clark 		drm_object_property_set_value(obj, property, value);
37744d93914aSRob Clark 
37754d93914aSRob Clark 	return ret;
37764d93914aSRob Clark }
37774d93914aSRob Clark 
3778c8e32cc1SDaniel Vetter /**
3779c8e32cc1SDaniel Vetter  * drm_mode_getproperty_ioctl - get the current value of a object's property
3780c8e32cc1SDaniel Vetter  * @dev: DRM device
3781c8e32cc1SDaniel Vetter  * @data: ioctl data
3782c8e32cc1SDaniel Vetter  * @file_priv: DRM file info
3783c8e32cc1SDaniel Vetter  *
3784c8e32cc1SDaniel Vetter  * This function retrieves the current value for an object's property. Compared
3785c8e32cc1SDaniel Vetter  * to the connector specific ioctl this one is extended to also work on crtc and
3786c8e32cc1SDaniel Vetter  * plane objects.
3787c8e32cc1SDaniel Vetter  *
3788c8e32cc1SDaniel Vetter  * Called by the user via ioctl.
3789c8e32cc1SDaniel Vetter  *
3790c8e32cc1SDaniel Vetter  * Returns:
3791c8e32cc1SDaniel Vetter  * Zero on success, errno on failure.
3792c8e32cc1SDaniel Vetter  */
3793c543188aSPaulo Zanoni int drm_mode_obj_get_properties_ioctl(struct drm_device *dev, void *data,
3794c543188aSPaulo Zanoni 				      struct drm_file *file_priv)
3795c543188aSPaulo Zanoni {
3796c543188aSPaulo Zanoni 	struct drm_mode_obj_get_properties *arg = data;
3797c543188aSPaulo Zanoni 	struct drm_mode_object *obj;
3798c543188aSPaulo Zanoni 	int ret = 0;
3799c543188aSPaulo Zanoni 	int i;
3800c543188aSPaulo Zanoni 	int copied = 0;
3801c543188aSPaulo Zanoni 	int props_count = 0;
3802c543188aSPaulo Zanoni 	uint32_t __user *props_ptr;
3803c543188aSPaulo Zanoni 	uint64_t __user *prop_values_ptr;
3804c543188aSPaulo Zanoni 
3805c543188aSPaulo Zanoni 	if (!drm_core_check_feature(dev, DRIVER_MODESET))
3806c543188aSPaulo Zanoni 		return -EINVAL;
3807c543188aSPaulo Zanoni 
380884849903SDaniel Vetter 	drm_modeset_lock_all(dev);
3809c543188aSPaulo Zanoni 
3810c543188aSPaulo Zanoni 	obj = drm_mode_object_find(dev, arg->obj_id, arg->obj_type);
3811c543188aSPaulo Zanoni 	if (!obj) {
3812f27657f2SVille Syrjälä 		ret = -ENOENT;
3813c543188aSPaulo Zanoni 		goto out;
3814c543188aSPaulo Zanoni 	}
3815c543188aSPaulo Zanoni 	if (!obj->properties) {
3816c543188aSPaulo Zanoni 		ret = -EINVAL;
3817c543188aSPaulo Zanoni 		goto out;
3818c543188aSPaulo Zanoni 	}
3819c543188aSPaulo Zanoni 
38207f88a9beSPaulo Zanoni 	props_count = obj->properties->count;
3821c543188aSPaulo Zanoni 
3822c543188aSPaulo Zanoni 	/* This ioctl is called twice, once to determine how much space is
3823c543188aSPaulo Zanoni 	 * needed, and the 2nd time to fill it. */
3824c543188aSPaulo Zanoni 	if ((arg->count_props >= props_count) && props_count) {
3825c543188aSPaulo Zanoni 		copied = 0;
3826c543188aSPaulo Zanoni 		props_ptr = (uint32_t __user *)(unsigned long)(arg->props_ptr);
3827c543188aSPaulo Zanoni 		prop_values_ptr = (uint64_t __user *)(unsigned long)
3828c543188aSPaulo Zanoni 				  (arg->prop_values_ptr);
3829c543188aSPaulo Zanoni 		for (i = 0; i < props_count; i++) {
3830c543188aSPaulo Zanoni 			if (put_user(obj->properties->ids[i],
3831c543188aSPaulo Zanoni 				     props_ptr + copied)) {
3832c543188aSPaulo Zanoni 				ret = -EFAULT;
3833c543188aSPaulo Zanoni 				goto out;
3834c543188aSPaulo Zanoni 			}
3835c543188aSPaulo Zanoni 			if (put_user(obj->properties->values[i],
3836c543188aSPaulo Zanoni 				     prop_values_ptr + copied)) {
3837c543188aSPaulo Zanoni 				ret = -EFAULT;
3838c543188aSPaulo Zanoni 				goto out;
3839c543188aSPaulo Zanoni 			}
3840c543188aSPaulo Zanoni 			copied++;
3841c543188aSPaulo Zanoni 		}
3842c543188aSPaulo Zanoni 	}
3843c543188aSPaulo Zanoni 	arg->count_props = props_count;
3844c543188aSPaulo Zanoni out:
384584849903SDaniel Vetter 	drm_modeset_unlock_all(dev);
3846c543188aSPaulo Zanoni 	return ret;
3847c543188aSPaulo Zanoni }
3848c543188aSPaulo Zanoni 
3849c8e32cc1SDaniel Vetter /**
3850c8e32cc1SDaniel Vetter  * drm_mode_obj_set_property_ioctl - set the current value of an object's property
3851c8e32cc1SDaniel Vetter  * @dev: DRM device
3852c8e32cc1SDaniel Vetter  * @data: ioctl data
3853c8e32cc1SDaniel Vetter  * @file_priv: DRM file info
3854c8e32cc1SDaniel Vetter  *
3855c8e32cc1SDaniel Vetter  * This function sets the current value for an object's property. It also calls
3856c8e32cc1SDaniel Vetter  * into a driver's ->set_property callback to update the hardware state.
3857c8e32cc1SDaniel Vetter  * Compared to the connector specific ioctl this one is extended to also work on
3858c8e32cc1SDaniel Vetter  * crtc and plane objects.
3859c8e32cc1SDaniel Vetter  *
3860c8e32cc1SDaniel Vetter  * Called by the user via ioctl.
3861c8e32cc1SDaniel Vetter  *
3862c8e32cc1SDaniel Vetter  * Returns:
3863c8e32cc1SDaniel Vetter  * Zero on success, errno on failure.
3864c8e32cc1SDaniel Vetter  */
3865c543188aSPaulo Zanoni int drm_mode_obj_set_property_ioctl(struct drm_device *dev, void *data,
3866c543188aSPaulo Zanoni 				    struct drm_file *file_priv)
3867c543188aSPaulo Zanoni {
3868c543188aSPaulo Zanoni 	struct drm_mode_obj_set_property *arg = data;
3869c543188aSPaulo Zanoni 	struct drm_mode_object *arg_obj;
3870c543188aSPaulo Zanoni 	struct drm_mode_object *prop_obj;
3871c543188aSPaulo Zanoni 	struct drm_property *property;
3872c543188aSPaulo Zanoni 	int ret = -EINVAL;
3873c543188aSPaulo Zanoni 	int i;
3874c543188aSPaulo Zanoni 
3875c543188aSPaulo Zanoni 	if (!drm_core_check_feature(dev, DRIVER_MODESET))
3876c543188aSPaulo Zanoni 		return -EINVAL;
3877c543188aSPaulo Zanoni 
387884849903SDaniel Vetter 	drm_modeset_lock_all(dev);
3879c543188aSPaulo Zanoni 
3880c543188aSPaulo Zanoni 	arg_obj = drm_mode_object_find(dev, arg->obj_id, arg->obj_type);
3881f27657f2SVille Syrjälä 	if (!arg_obj) {
3882f27657f2SVille Syrjälä 		ret = -ENOENT;
3883c543188aSPaulo Zanoni 		goto out;
3884f27657f2SVille Syrjälä 	}
3885c543188aSPaulo Zanoni 	if (!arg_obj->properties)
3886c543188aSPaulo Zanoni 		goto out;
3887c543188aSPaulo Zanoni 
38887f88a9beSPaulo Zanoni 	for (i = 0; i < arg_obj->properties->count; i++)
3889c543188aSPaulo Zanoni 		if (arg_obj->properties->ids[i] == arg->prop_id)
3890c543188aSPaulo Zanoni 			break;
3891c543188aSPaulo Zanoni 
38927f88a9beSPaulo Zanoni 	if (i == arg_obj->properties->count)
3893c543188aSPaulo Zanoni 		goto out;
3894c543188aSPaulo Zanoni 
3895c543188aSPaulo Zanoni 	prop_obj = drm_mode_object_find(dev, arg->prop_id,
3896c543188aSPaulo Zanoni 					DRM_MODE_OBJECT_PROPERTY);
3897f27657f2SVille Syrjälä 	if (!prop_obj) {
3898f27657f2SVille Syrjälä 		ret = -ENOENT;
3899c543188aSPaulo Zanoni 		goto out;
3900f27657f2SVille Syrjälä 	}
3901c543188aSPaulo Zanoni 	property = obj_to_property(prop_obj);
3902c543188aSPaulo Zanoni 
3903c543188aSPaulo Zanoni 	if (!drm_property_change_is_valid(property, arg->value))
3904c543188aSPaulo Zanoni 		goto out;
3905c543188aSPaulo Zanoni 
3906c543188aSPaulo Zanoni 	switch (arg_obj->type) {
3907c543188aSPaulo Zanoni 	case DRM_MODE_OBJECT_CONNECTOR:
3908c543188aSPaulo Zanoni 		ret = drm_mode_connector_set_obj_prop(arg_obj, property,
3909c543188aSPaulo Zanoni 						      arg->value);
3910c543188aSPaulo Zanoni 		break;
3911bffd9de0SPaulo Zanoni 	case DRM_MODE_OBJECT_CRTC:
3912bffd9de0SPaulo Zanoni 		ret = drm_mode_crtc_set_obj_prop(arg_obj, property, arg->value);
3913bffd9de0SPaulo Zanoni 		break;
39144d93914aSRob Clark 	case DRM_MODE_OBJECT_PLANE:
39154d93914aSRob Clark 		ret = drm_mode_plane_set_obj_prop(arg_obj, property, arg->value);
39164d93914aSRob Clark 		break;
3917c543188aSPaulo Zanoni 	}
3918c543188aSPaulo Zanoni 
3919c543188aSPaulo Zanoni out:
392084849903SDaniel Vetter 	drm_modeset_unlock_all(dev);
3921c543188aSPaulo Zanoni 	return ret;
3922c543188aSPaulo Zanoni }
3923c543188aSPaulo Zanoni 
3924c8e32cc1SDaniel Vetter /**
3925c8e32cc1SDaniel Vetter  * drm_mode_connector_attach_encoder - attach a connector to an encoder
3926c8e32cc1SDaniel Vetter  * @connector: connector to attach
3927c8e32cc1SDaniel Vetter  * @encoder: encoder to attach @connector to
3928c8e32cc1SDaniel Vetter  *
3929c8e32cc1SDaniel Vetter  * This function links up a connector to an encoder. Note that the routing
3930c8e32cc1SDaniel Vetter  * restrictions between encoders and crtcs are exposed to userspace through the
3931c8e32cc1SDaniel Vetter  * possible_clones and possible_crtcs bitmasks.
3932c8e32cc1SDaniel Vetter  *
3933c8e32cc1SDaniel Vetter  * Returns:
3934c8e32cc1SDaniel Vetter  * Zero on success, errno on failure.
3935c8e32cc1SDaniel Vetter  */
3936f453ba04SDave Airlie int drm_mode_connector_attach_encoder(struct drm_connector *connector,
3937f453ba04SDave Airlie 				      struct drm_encoder *encoder)
3938f453ba04SDave Airlie {
3939f453ba04SDave Airlie 	int i;
3940f453ba04SDave Airlie 
3941f453ba04SDave Airlie 	for (i = 0; i < DRM_CONNECTOR_MAX_ENCODER; i++) {
3942f453ba04SDave Airlie 		if (connector->encoder_ids[i] == 0) {
3943f453ba04SDave Airlie 			connector->encoder_ids[i] = encoder->base.id;
3944f453ba04SDave Airlie 			return 0;
3945f453ba04SDave Airlie 		}
3946f453ba04SDave Airlie 	}
3947f453ba04SDave Airlie 	return -ENOMEM;
3948f453ba04SDave Airlie }
3949f453ba04SDave Airlie EXPORT_SYMBOL(drm_mode_connector_attach_encoder);
3950f453ba04SDave Airlie 
3951c8e32cc1SDaniel Vetter /**
3952c8e32cc1SDaniel Vetter  * drm_mode_crtc_set_gamma_size - set the gamma table size
3953c8e32cc1SDaniel Vetter  * @crtc: CRTC to set the gamma table size for
3954c8e32cc1SDaniel Vetter  * @gamma_size: size of the gamma table
3955c8e32cc1SDaniel Vetter  *
3956c8e32cc1SDaniel Vetter  * Drivers which support gamma tables should set this to the supported gamma
3957c8e32cc1SDaniel Vetter  * table size when initializing the CRTC. Currently the drm core only supports a
3958c8e32cc1SDaniel Vetter  * fixed gamma table size.
3959c8e32cc1SDaniel Vetter  *
3960c8e32cc1SDaniel Vetter  * Returns:
3961c8e32cc1SDaniel Vetter  * Zero on success, errno on failure.
3962c8e32cc1SDaniel Vetter  */
39634cae5b84SSascha Hauer int drm_mode_crtc_set_gamma_size(struct drm_crtc *crtc,
3964f453ba04SDave Airlie 				 int gamma_size)
3965f453ba04SDave Airlie {
3966f453ba04SDave Airlie 	crtc->gamma_size = gamma_size;
3967f453ba04SDave Airlie 
3968f453ba04SDave Airlie 	crtc->gamma_store = kzalloc(gamma_size * sizeof(uint16_t) * 3, GFP_KERNEL);
3969f453ba04SDave Airlie 	if (!crtc->gamma_store) {
3970f453ba04SDave Airlie 		crtc->gamma_size = 0;
39714cae5b84SSascha Hauer 		return -ENOMEM;
3972f453ba04SDave Airlie 	}
3973f453ba04SDave Airlie 
39744cae5b84SSascha Hauer 	return 0;
3975f453ba04SDave Airlie }
3976f453ba04SDave Airlie EXPORT_SYMBOL(drm_mode_crtc_set_gamma_size);
3977f453ba04SDave Airlie 
3978c8e32cc1SDaniel Vetter /**
3979c8e32cc1SDaniel Vetter  * drm_mode_gamma_set_ioctl - set the gamma table
3980c8e32cc1SDaniel Vetter  * @dev: DRM device
3981c8e32cc1SDaniel Vetter  * @data: ioctl data
3982c8e32cc1SDaniel Vetter  * @file_priv: DRM file info
3983c8e32cc1SDaniel Vetter  *
3984c8e32cc1SDaniel Vetter  * Set the gamma table of a CRTC to the one passed in by the user. Userspace can
3985c8e32cc1SDaniel Vetter  * inquire the required gamma table size through drm_mode_gamma_get_ioctl.
3986c8e32cc1SDaniel Vetter  *
3987c8e32cc1SDaniel Vetter  * Called by the user via ioctl.
3988c8e32cc1SDaniel Vetter  *
3989c8e32cc1SDaniel Vetter  * Returns:
3990c8e32cc1SDaniel Vetter  * Zero on success, errno on failure.
3991c8e32cc1SDaniel Vetter  */
3992f453ba04SDave Airlie int drm_mode_gamma_set_ioctl(struct drm_device *dev,
3993f453ba04SDave Airlie 			     void *data, struct drm_file *file_priv)
3994f453ba04SDave Airlie {
3995f453ba04SDave Airlie 	struct drm_mode_crtc_lut *crtc_lut = data;
3996f453ba04SDave Airlie 	struct drm_mode_object *obj;
3997f453ba04SDave Airlie 	struct drm_crtc *crtc;
3998f453ba04SDave Airlie 	void *r_base, *g_base, *b_base;
3999f453ba04SDave Airlie 	int size;
4000f453ba04SDave Airlie 	int ret = 0;
4001f453ba04SDave Airlie 
4002fb3b06c8SDave Airlie 	if (!drm_core_check_feature(dev, DRIVER_MODESET))
4003fb3b06c8SDave Airlie 		return -EINVAL;
4004fb3b06c8SDave Airlie 
400584849903SDaniel Vetter 	drm_modeset_lock_all(dev);
4006f453ba04SDave Airlie 	obj = drm_mode_object_find(dev, crtc_lut->crtc_id, DRM_MODE_OBJECT_CRTC);
4007f453ba04SDave Airlie 	if (!obj) {
4008f27657f2SVille Syrjälä 		ret = -ENOENT;
4009f453ba04SDave Airlie 		goto out;
4010f453ba04SDave Airlie 	}
4011f453ba04SDave Airlie 	crtc = obj_to_crtc(obj);
4012f453ba04SDave Airlie 
4013ebe0f244SLaurent Pinchart 	if (crtc->funcs->gamma_set == NULL) {
4014ebe0f244SLaurent Pinchart 		ret = -ENOSYS;
4015ebe0f244SLaurent Pinchart 		goto out;
4016ebe0f244SLaurent Pinchart 	}
4017ebe0f244SLaurent Pinchart 
4018f453ba04SDave Airlie 	/* memcpy into gamma store */
4019f453ba04SDave Airlie 	if (crtc_lut->gamma_size != crtc->gamma_size) {
4020f453ba04SDave Airlie 		ret = -EINVAL;
4021f453ba04SDave Airlie 		goto out;
4022f453ba04SDave Airlie 	}
4023f453ba04SDave Airlie 
4024f453ba04SDave Airlie 	size = crtc_lut->gamma_size * (sizeof(uint16_t));
4025f453ba04SDave Airlie 	r_base = crtc->gamma_store;
4026f453ba04SDave Airlie 	if (copy_from_user(r_base, (void __user *)(unsigned long)crtc_lut->red, size)) {
4027f453ba04SDave Airlie 		ret = -EFAULT;
4028f453ba04SDave Airlie 		goto out;
4029f453ba04SDave Airlie 	}
4030f453ba04SDave Airlie 
4031f453ba04SDave Airlie 	g_base = r_base + size;
4032f453ba04SDave Airlie 	if (copy_from_user(g_base, (void __user *)(unsigned long)crtc_lut->green, size)) {
4033f453ba04SDave Airlie 		ret = -EFAULT;
4034f453ba04SDave Airlie 		goto out;
4035f453ba04SDave Airlie 	}
4036f453ba04SDave Airlie 
4037f453ba04SDave Airlie 	b_base = g_base + size;
4038f453ba04SDave Airlie 	if (copy_from_user(b_base, (void __user *)(unsigned long)crtc_lut->blue, size)) {
4039f453ba04SDave Airlie 		ret = -EFAULT;
4040f453ba04SDave Airlie 		goto out;
4041f453ba04SDave Airlie 	}
4042f453ba04SDave Airlie 
40437203425aSJames Simmons 	crtc->funcs->gamma_set(crtc, r_base, g_base, b_base, 0, crtc->gamma_size);
4044f453ba04SDave Airlie 
4045f453ba04SDave Airlie out:
404684849903SDaniel Vetter 	drm_modeset_unlock_all(dev);
4047f453ba04SDave Airlie 	return ret;
4048f453ba04SDave Airlie 
4049f453ba04SDave Airlie }
4050f453ba04SDave Airlie 
4051c8e32cc1SDaniel Vetter /**
4052c8e32cc1SDaniel Vetter  * drm_mode_gamma_get_ioctl - get the gamma table
4053c8e32cc1SDaniel Vetter  * @dev: DRM device
4054c8e32cc1SDaniel Vetter  * @data: ioctl data
4055c8e32cc1SDaniel Vetter  * @file_priv: DRM file info
4056c8e32cc1SDaniel Vetter  *
4057c8e32cc1SDaniel Vetter  * Copy the current gamma table into the storage provided. This also provides
4058c8e32cc1SDaniel Vetter  * the gamma table size the driver expects, which can be used to size the
4059c8e32cc1SDaniel Vetter  * allocated storage.
4060c8e32cc1SDaniel Vetter  *
4061c8e32cc1SDaniel Vetter  * Called by the user via ioctl.
4062c8e32cc1SDaniel Vetter  *
4063c8e32cc1SDaniel Vetter  * Returns:
4064c8e32cc1SDaniel Vetter  * Zero on success, errno on failure.
4065c8e32cc1SDaniel Vetter  */
4066f453ba04SDave Airlie int drm_mode_gamma_get_ioctl(struct drm_device *dev,
4067f453ba04SDave Airlie 			     void *data, struct drm_file *file_priv)
4068f453ba04SDave Airlie {
4069f453ba04SDave Airlie 	struct drm_mode_crtc_lut *crtc_lut = data;
4070f453ba04SDave Airlie 	struct drm_mode_object *obj;
4071f453ba04SDave Airlie 	struct drm_crtc *crtc;
4072f453ba04SDave Airlie 	void *r_base, *g_base, *b_base;
4073f453ba04SDave Airlie 	int size;
4074f453ba04SDave Airlie 	int ret = 0;
4075f453ba04SDave Airlie 
4076fb3b06c8SDave Airlie 	if (!drm_core_check_feature(dev, DRIVER_MODESET))
4077fb3b06c8SDave Airlie 		return -EINVAL;
4078fb3b06c8SDave Airlie 
407984849903SDaniel Vetter 	drm_modeset_lock_all(dev);
4080f453ba04SDave Airlie 	obj = drm_mode_object_find(dev, crtc_lut->crtc_id, DRM_MODE_OBJECT_CRTC);
4081f453ba04SDave Airlie 	if (!obj) {
4082f27657f2SVille Syrjälä 		ret = -ENOENT;
4083f453ba04SDave Airlie 		goto out;
4084f453ba04SDave Airlie 	}
4085f453ba04SDave Airlie 	crtc = obj_to_crtc(obj);
4086f453ba04SDave Airlie 
4087f453ba04SDave Airlie 	/* memcpy into gamma store */
4088f453ba04SDave Airlie 	if (crtc_lut->gamma_size != crtc->gamma_size) {
4089f453ba04SDave Airlie 		ret = -EINVAL;
4090f453ba04SDave Airlie 		goto out;
4091f453ba04SDave Airlie 	}
4092f453ba04SDave Airlie 
4093f453ba04SDave Airlie 	size = crtc_lut->gamma_size * (sizeof(uint16_t));
4094f453ba04SDave Airlie 	r_base = crtc->gamma_store;
4095f453ba04SDave Airlie 	if (copy_to_user((void __user *)(unsigned long)crtc_lut->red, r_base, size)) {
4096f453ba04SDave Airlie 		ret = -EFAULT;
4097f453ba04SDave Airlie 		goto out;
4098f453ba04SDave Airlie 	}
4099f453ba04SDave Airlie 
4100f453ba04SDave Airlie 	g_base = r_base + size;
4101f453ba04SDave Airlie 	if (copy_to_user((void __user *)(unsigned long)crtc_lut->green, g_base, size)) {
4102f453ba04SDave Airlie 		ret = -EFAULT;
4103f453ba04SDave Airlie 		goto out;
4104f453ba04SDave Airlie 	}
4105f453ba04SDave Airlie 
4106f453ba04SDave Airlie 	b_base = g_base + size;
4107f453ba04SDave Airlie 	if (copy_to_user((void __user *)(unsigned long)crtc_lut->blue, b_base, size)) {
4108f453ba04SDave Airlie 		ret = -EFAULT;
4109f453ba04SDave Airlie 		goto out;
4110f453ba04SDave Airlie 	}
4111f453ba04SDave Airlie out:
411284849903SDaniel Vetter 	drm_modeset_unlock_all(dev);
4113f453ba04SDave Airlie 	return ret;
4114f453ba04SDave Airlie }
4115d91d8a3fSKristian Høgsberg 
4116c8e32cc1SDaniel Vetter /**
4117c8e32cc1SDaniel Vetter  * drm_mode_page_flip_ioctl - schedule an asynchronous fb update
4118c8e32cc1SDaniel Vetter  * @dev: DRM device
4119c8e32cc1SDaniel Vetter  * @data: ioctl data
4120c8e32cc1SDaniel Vetter  * @file_priv: DRM file info
4121c8e32cc1SDaniel Vetter  *
4122c8e32cc1SDaniel Vetter  * This schedules an asynchronous update on a given CRTC, called page flip.
4123c8e32cc1SDaniel Vetter  * Optionally a drm event is generated to signal the completion of the event.
4124c8e32cc1SDaniel Vetter  * Generic drivers cannot assume that a pageflip with changed framebuffer
4125c8e32cc1SDaniel Vetter  * properties (including driver specific metadata like tiling layout) will work,
4126c8e32cc1SDaniel Vetter  * but some drivers support e.g. pixel format changes through the pageflip
4127c8e32cc1SDaniel Vetter  * ioctl.
4128c8e32cc1SDaniel Vetter  *
4129c8e32cc1SDaniel Vetter  * Called by the user via ioctl.
4130c8e32cc1SDaniel Vetter  *
4131c8e32cc1SDaniel Vetter  * Returns:
4132c8e32cc1SDaniel Vetter  * Zero on success, errno on failure.
4133c8e32cc1SDaniel Vetter  */
4134d91d8a3fSKristian Høgsberg int drm_mode_page_flip_ioctl(struct drm_device *dev,
4135d91d8a3fSKristian Høgsberg 			     void *data, struct drm_file *file_priv)
4136d91d8a3fSKristian Høgsberg {
4137d91d8a3fSKristian Høgsberg 	struct drm_mode_crtc_page_flip *page_flip = data;
4138d91d8a3fSKristian Høgsberg 	struct drm_mode_object *obj;
4139d91d8a3fSKristian Høgsberg 	struct drm_crtc *crtc;
4140b0d12325SDaniel Vetter 	struct drm_framebuffer *fb = NULL, *old_fb = NULL;
4141d91d8a3fSKristian Høgsberg 	struct drm_pending_vblank_event *e = NULL;
4142d91d8a3fSKristian Høgsberg 	unsigned long flags;
4143d91d8a3fSKristian Høgsberg 	int ret = -EINVAL;
4144d91d8a3fSKristian Høgsberg 
4145d91d8a3fSKristian Høgsberg 	if (page_flip->flags & ~DRM_MODE_PAGE_FLIP_FLAGS ||
4146d91d8a3fSKristian Høgsberg 	    page_flip->reserved != 0)
4147d91d8a3fSKristian Høgsberg 		return -EINVAL;
4148d91d8a3fSKristian Høgsberg 
414962f2104fSKeith Packard 	if ((page_flip->flags & DRM_MODE_PAGE_FLIP_ASYNC) && !dev->mode_config.async_page_flip)
415062f2104fSKeith Packard 		return -EINVAL;
415162f2104fSKeith Packard 
4152d91d8a3fSKristian Høgsberg 	obj = drm_mode_object_find(dev, page_flip->crtc_id, DRM_MODE_OBJECT_CRTC);
4153d91d8a3fSKristian Høgsberg 	if (!obj)
4154f27657f2SVille Syrjälä 		return -ENOENT;
4155d91d8a3fSKristian Høgsberg 	crtc = obj_to_crtc(obj);
4156d91d8a3fSKristian Høgsberg 
4157b4d5e7d1SDaniel Vetter 	mutex_lock(&crtc->mutex);
4158f4510a27SMatt Roper 	if (crtc->primary->fb == NULL) {
415990c1efddSChris Wilson 		/* The framebuffer is currently unbound, presumably
416090c1efddSChris Wilson 		 * due to a hotplug event, that userspace has not
416190c1efddSChris Wilson 		 * yet discovered.
416290c1efddSChris Wilson 		 */
416390c1efddSChris Wilson 		ret = -EBUSY;
416490c1efddSChris Wilson 		goto out;
416590c1efddSChris Wilson 	}
416690c1efddSChris Wilson 
4167d91d8a3fSKristian Høgsberg 	if (crtc->funcs->page_flip == NULL)
4168d91d8a3fSKristian Høgsberg 		goto out;
4169d91d8a3fSKristian Høgsberg 
4170786b99edSDaniel Vetter 	fb = drm_framebuffer_lookup(dev, page_flip->fb_id);
417137c4e705SVille Syrjälä 	if (!fb) {
417237c4e705SVille Syrjälä 		ret = -ENOENT;
4173d91d8a3fSKristian Høgsberg 		goto out;
417437c4e705SVille Syrjälä 	}
4175d91d8a3fSKristian Høgsberg 
4176c11e9283SDamien Lespiau 	ret = drm_crtc_check_viewport(crtc, crtc->x, crtc->y, &crtc->mode, fb);
4177c11e9283SDamien Lespiau 	if (ret)
41785f61bb42SVille Syrjälä 		goto out;
41795f61bb42SVille Syrjälä 
4180f4510a27SMatt Roper 	if (crtc->primary->fb->pixel_format != fb->pixel_format) {
4181909d9cdaSLaurent Pinchart 		DRM_DEBUG_KMS("Page flip is not allowed to change frame buffer format.\n");
4182909d9cdaSLaurent Pinchart 		ret = -EINVAL;
4183909d9cdaSLaurent Pinchart 		goto out;
4184909d9cdaSLaurent Pinchart 	}
4185909d9cdaSLaurent Pinchart 
4186d91d8a3fSKristian Høgsberg 	if (page_flip->flags & DRM_MODE_PAGE_FLIP_EVENT) {
4187d91d8a3fSKristian Høgsberg 		ret = -ENOMEM;
4188d91d8a3fSKristian Høgsberg 		spin_lock_irqsave(&dev->event_lock, flags);
4189d91d8a3fSKristian Høgsberg 		if (file_priv->event_space < sizeof e->event) {
4190d91d8a3fSKristian Høgsberg 			spin_unlock_irqrestore(&dev->event_lock, flags);
4191d91d8a3fSKristian Høgsberg 			goto out;
4192d91d8a3fSKristian Høgsberg 		}
4193d91d8a3fSKristian Høgsberg 		file_priv->event_space -= sizeof e->event;
4194d91d8a3fSKristian Høgsberg 		spin_unlock_irqrestore(&dev->event_lock, flags);
4195d91d8a3fSKristian Høgsberg 
4196d91d8a3fSKristian Høgsberg 		e = kzalloc(sizeof *e, GFP_KERNEL);
4197d91d8a3fSKristian Høgsberg 		if (e == NULL) {
4198d91d8a3fSKristian Høgsberg 			spin_lock_irqsave(&dev->event_lock, flags);
4199d91d8a3fSKristian Høgsberg 			file_priv->event_space += sizeof e->event;
4200d91d8a3fSKristian Høgsberg 			spin_unlock_irqrestore(&dev->event_lock, flags);
4201d91d8a3fSKristian Høgsberg 			goto out;
4202d91d8a3fSKristian Høgsberg 		}
4203d91d8a3fSKristian Høgsberg 
42047bd4d7beSJesse Barnes 		e->event.base.type = DRM_EVENT_FLIP_COMPLETE;
4205d91d8a3fSKristian Høgsberg 		e->event.base.length = sizeof e->event;
4206d91d8a3fSKristian Høgsberg 		e->event.user_data = page_flip->user_data;
4207d91d8a3fSKristian Høgsberg 		e->base.event = &e->event.base;
4208d91d8a3fSKristian Høgsberg 		e->base.file_priv = file_priv;
4209d91d8a3fSKristian Høgsberg 		e->base.destroy =
4210d91d8a3fSKristian Høgsberg 			(void (*) (struct drm_pending_event *)) kfree;
4211d91d8a3fSKristian Høgsberg 	}
4212d91d8a3fSKristian Høgsberg 
4213f4510a27SMatt Roper 	old_fb = crtc->primary->fb;
4214ed8d1975SKeith Packard 	ret = crtc->funcs->page_flip(crtc, fb, e, page_flip->flags);
4215d91d8a3fSKristian Høgsberg 	if (ret) {
4216aef6a7eeSJoonyoung Shim 		if (page_flip->flags & DRM_MODE_PAGE_FLIP_EVENT) {
4217d91d8a3fSKristian Høgsberg 			spin_lock_irqsave(&dev->event_lock, flags);
4218d91d8a3fSKristian Høgsberg 			file_priv->event_space += sizeof e->event;
4219d91d8a3fSKristian Høgsberg 			spin_unlock_irqrestore(&dev->event_lock, flags);
4220d91d8a3fSKristian Høgsberg 			kfree(e);
4221d91d8a3fSKristian Høgsberg 		}
4222b0d12325SDaniel Vetter 		/* Keep the old fb, don't unref it. */
4223b0d12325SDaniel Vetter 		old_fb = NULL;
4224b0d12325SDaniel Vetter 	} else {
42258cf1e981SThierry Reding 		/*
42268cf1e981SThierry Reding 		 * Warn if the driver hasn't properly updated the crtc->fb
42278cf1e981SThierry Reding 		 * field to reflect that the new framebuffer is now used.
42288cf1e981SThierry Reding 		 * Failing to do so will screw with the reference counting
42298cf1e981SThierry Reding 		 * on framebuffers.
42308cf1e981SThierry Reding 		 */
4231f4510a27SMatt Roper 		WARN_ON(crtc->primary->fb != fb);
4232b0d12325SDaniel Vetter 		/* Unref only the old framebuffer. */
4233b0d12325SDaniel Vetter 		fb = NULL;
4234aef6a7eeSJoonyoung Shim 	}
4235d91d8a3fSKristian Høgsberg 
4236d91d8a3fSKristian Høgsberg out:
4237b0d12325SDaniel Vetter 	if (fb)
4238b0d12325SDaniel Vetter 		drm_framebuffer_unreference(fb);
4239b0d12325SDaniel Vetter 	if (old_fb)
4240b0d12325SDaniel Vetter 		drm_framebuffer_unreference(old_fb);
4241b4d5e7d1SDaniel Vetter 	mutex_unlock(&crtc->mutex);
4242b4d5e7d1SDaniel Vetter 
4243d91d8a3fSKristian Høgsberg 	return ret;
4244d91d8a3fSKristian Høgsberg }
4245eb033556SChris Wilson 
4246c8e32cc1SDaniel Vetter /**
4247c8e32cc1SDaniel Vetter  * drm_mode_config_reset - call ->reset callbacks
4248c8e32cc1SDaniel Vetter  * @dev: drm device
4249c8e32cc1SDaniel Vetter  *
4250c8e32cc1SDaniel Vetter  * This functions calls all the crtc's, encoder's and connector's ->reset
4251c8e32cc1SDaniel Vetter  * callback. Drivers can use this in e.g. their driver load or resume code to
4252c8e32cc1SDaniel Vetter  * reset hardware and software state.
4253c8e32cc1SDaniel Vetter  */
4254eb033556SChris Wilson void drm_mode_config_reset(struct drm_device *dev)
4255eb033556SChris Wilson {
4256eb033556SChris Wilson 	struct drm_crtc *crtc;
4257eb033556SChris Wilson 	struct drm_encoder *encoder;
4258eb033556SChris Wilson 	struct drm_connector *connector;
4259eb033556SChris Wilson 
4260eb033556SChris Wilson 	list_for_each_entry(crtc, &dev->mode_config.crtc_list, head)
4261eb033556SChris Wilson 		if (crtc->funcs->reset)
4262eb033556SChris Wilson 			crtc->funcs->reset(crtc);
4263eb033556SChris Wilson 
4264eb033556SChris Wilson 	list_for_each_entry(encoder, &dev->mode_config.encoder_list, head)
4265eb033556SChris Wilson 		if (encoder->funcs->reset)
4266eb033556SChris Wilson 			encoder->funcs->reset(encoder);
4267eb033556SChris Wilson 
42685e2cb2f6SDaniel Vetter 	list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
42695e2cb2f6SDaniel Vetter 		connector->status = connector_status_unknown;
42705e2cb2f6SDaniel Vetter 
4271eb033556SChris Wilson 		if (connector->funcs->reset)
4272eb033556SChris Wilson 			connector->funcs->reset(connector);
4273eb033556SChris Wilson 	}
42745e2cb2f6SDaniel Vetter }
4275eb033556SChris Wilson EXPORT_SYMBOL(drm_mode_config_reset);
4276ff72145bSDave Airlie 
4277c8e32cc1SDaniel Vetter /**
4278c8e32cc1SDaniel Vetter  * drm_mode_create_dumb_ioctl - create a dumb backing storage buffer
4279c8e32cc1SDaniel Vetter  * @dev: DRM device
4280c8e32cc1SDaniel Vetter  * @data: ioctl data
4281c8e32cc1SDaniel Vetter  * @file_priv: DRM file info
4282c8e32cc1SDaniel Vetter  *
4283c8e32cc1SDaniel Vetter  * This creates a new dumb buffer in the driver's backing storage manager (GEM,
4284c8e32cc1SDaniel Vetter  * TTM or something else entirely) and returns the resulting buffer handle. This
4285c8e32cc1SDaniel Vetter  * handle can then be wrapped up into a framebuffer modeset object.
4286c8e32cc1SDaniel Vetter  *
4287c8e32cc1SDaniel Vetter  * Note that userspace is not allowed to use such objects for render
4288c8e32cc1SDaniel Vetter  * acceleration - drivers must create their own private ioctls for such a use
4289c8e32cc1SDaniel Vetter  * case.
4290c8e32cc1SDaniel Vetter  *
4291c8e32cc1SDaniel Vetter  * Called by the user via ioctl.
4292c8e32cc1SDaniel Vetter  *
4293c8e32cc1SDaniel Vetter  * Returns:
4294c8e32cc1SDaniel Vetter  * Zero on success, errno on failure.
4295c8e32cc1SDaniel Vetter  */
4296ff72145bSDave Airlie int drm_mode_create_dumb_ioctl(struct drm_device *dev,
4297ff72145bSDave Airlie 			       void *data, struct drm_file *file_priv)
4298ff72145bSDave Airlie {
4299ff72145bSDave Airlie 	struct drm_mode_create_dumb *args = data;
4300b28cd41fSDavid Herrmann 	u32 cpp, stride, size;
4301ff72145bSDave Airlie 
4302ff72145bSDave Airlie 	if (!dev->driver->dumb_create)
4303ff72145bSDave Airlie 		return -ENOSYS;
4304b28cd41fSDavid Herrmann 	if (!args->width || !args->height || !args->bpp)
4305b28cd41fSDavid Herrmann 		return -EINVAL;
4306b28cd41fSDavid Herrmann 
4307b28cd41fSDavid Herrmann 	/* overflow checks for 32bit size calculations */
4308b28cd41fSDavid Herrmann 	cpp = DIV_ROUND_UP(args->bpp, 8);
4309b28cd41fSDavid Herrmann 	if (cpp > 0xffffffffU / args->width)
4310b28cd41fSDavid Herrmann 		return -EINVAL;
4311b28cd41fSDavid Herrmann 	stride = cpp * args->width;
4312b28cd41fSDavid Herrmann 	if (args->height > 0xffffffffU / stride)
4313b28cd41fSDavid Herrmann 		return -EINVAL;
4314b28cd41fSDavid Herrmann 
4315b28cd41fSDavid Herrmann 	/* test for wrap-around */
4316b28cd41fSDavid Herrmann 	size = args->height * stride;
4317b28cd41fSDavid Herrmann 	if (PAGE_ALIGN(size) == 0)
4318b28cd41fSDavid Herrmann 		return -EINVAL;
4319b28cd41fSDavid Herrmann 
4320ff72145bSDave Airlie 	return dev->driver->dumb_create(file_priv, dev, args);
4321ff72145bSDave Airlie }
4322ff72145bSDave Airlie 
4323c8e32cc1SDaniel Vetter /**
4324c8e32cc1SDaniel Vetter  * drm_mode_mmap_dumb_ioctl - create an mmap offset for a dumb backing storage buffer
4325c8e32cc1SDaniel Vetter  * @dev: DRM device
4326c8e32cc1SDaniel Vetter  * @data: ioctl data
4327c8e32cc1SDaniel Vetter  * @file_priv: DRM file info
4328c8e32cc1SDaniel Vetter  *
4329c8e32cc1SDaniel Vetter  * Allocate an offset in the drm device node's address space to be able to
4330c8e32cc1SDaniel Vetter  * memory map a dumb buffer.
4331c8e32cc1SDaniel Vetter  *
4332c8e32cc1SDaniel Vetter  * Called by the user via ioctl.
4333c8e32cc1SDaniel Vetter  *
4334c8e32cc1SDaniel Vetter  * Returns:
4335c8e32cc1SDaniel Vetter  * Zero on success, errno on failure.
4336c8e32cc1SDaniel Vetter  */
4337ff72145bSDave Airlie int drm_mode_mmap_dumb_ioctl(struct drm_device *dev,
4338ff72145bSDave Airlie 			     void *data, struct drm_file *file_priv)
4339ff72145bSDave Airlie {
4340ff72145bSDave Airlie 	struct drm_mode_map_dumb *args = data;
4341ff72145bSDave Airlie 
4342ff72145bSDave Airlie 	/* call driver ioctl to get mmap offset */
4343ff72145bSDave Airlie 	if (!dev->driver->dumb_map_offset)
4344ff72145bSDave Airlie 		return -ENOSYS;
4345ff72145bSDave Airlie 
4346ff72145bSDave Airlie 	return dev->driver->dumb_map_offset(file_priv, dev, args->handle, &args->offset);
4347ff72145bSDave Airlie }
4348ff72145bSDave Airlie 
4349c8e32cc1SDaniel Vetter /**
4350c8e32cc1SDaniel Vetter  * drm_mode_destroy_dumb_ioctl - destroy a dumb backing strage buffer
4351c8e32cc1SDaniel Vetter  * @dev: DRM device
4352c8e32cc1SDaniel Vetter  * @data: ioctl data
4353c8e32cc1SDaniel Vetter  * @file_priv: DRM file info
4354c8e32cc1SDaniel Vetter  *
4355c8e32cc1SDaniel Vetter  * This destroys the userspace handle for the given dumb backing storage buffer.
4356c8e32cc1SDaniel Vetter  * Since buffer objects must be reference counted in the kernel a buffer object
4357c8e32cc1SDaniel Vetter  * won't be immediately freed if a framebuffer modeset object still uses it.
4358c8e32cc1SDaniel Vetter  *
4359c8e32cc1SDaniel Vetter  * Called by the user via ioctl.
4360c8e32cc1SDaniel Vetter  *
4361c8e32cc1SDaniel Vetter  * Returns:
4362c8e32cc1SDaniel Vetter  * Zero on success, errno on failure.
4363c8e32cc1SDaniel Vetter  */
4364ff72145bSDave Airlie int drm_mode_destroy_dumb_ioctl(struct drm_device *dev,
4365ff72145bSDave Airlie 				void *data, struct drm_file *file_priv)
4366ff72145bSDave Airlie {
4367ff72145bSDave Airlie 	struct drm_mode_destroy_dumb *args = data;
4368ff72145bSDave Airlie 
4369ff72145bSDave Airlie 	if (!dev->driver->dumb_destroy)
4370ff72145bSDave Airlie 		return -ENOSYS;
4371ff72145bSDave Airlie 
4372ff72145bSDave Airlie 	return dev->driver->dumb_destroy(file_priv, dev, args->handle);
4373ff72145bSDave Airlie }
4374248dbc23SDave Airlie 
4375c8e32cc1SDaniel Vetter /**
4376c8e32cc1SDaniel Vetter  * drm_fb_get_bpp_depth - get the bpp/depth values for format
4377c8e32cc1SDaniel Vetter  * @format: pixel format (DRM_FORMAT_*)
4378c8e32cc1SDaniel Vetter  * @depth: storage for the depth value
4379c8e32cc1SDaniel Vetter  * @bpp: storage for the bpp value
4380c8e32cc1SDaniel Vetter  *
4381c8e32cc1SDaniel Vetter  * This only supports RGB formats here for compat with code that doesn't use
4382c8e32cc1SDaniel Vetter  * pixel formats directly yet.
4383248dbc23SDave Airlie  */
4384248dbc23SDave Airlie void drm_fb_get_bpp_depth(uint32_t format, unsigned int *depth,
4385248dbc23SDave Airlie 			  int *bpp)
4386248dbc23SDave Airlie {
4387248dbc23SDave Airlie 	switch (format) {
4388c51a6bc5SVille Syrjälä 	case DRM_FORMAT_C8:
438904b3924dSVille Syrjälä 	case DRM_FORMAT_RGB332:
439004b3924dSVille Syrjälä 	case DRM_FORMAT_BGR233:
4391248dbc23SDave Airlie 		*depth = 8;
4392248dbc23SDave Airlie 		*bpp = 8;
4393248dbc23SDave Airlie 		break;
439404b3924dSVille Syrjälä 	case DRM_FORMAT_XRGB1555:
439504b3924dSVille Syrjälä 	case DRM_FORMAT_XBGR1555:
439604b3924dSVille Syrjälä 	case DRM_FORMAT_RGBX5551:
439704b3924dSVille Syrjälä 	case DRM_FORMAT_BGRX5551:
439804b3924dSVille Syrjälä 	case DRM_FORMAT_ARGB1555:
439904b3924dSVille Syrjälä 	case DRM_FORMAT_ABGR1555:
440004b3924dSVille Syrjälä 	case DRM_FORMAT_RGBA5551:
440104b3924dSVille Syrjälä 	case DRM_FORMAT_BGRA5551:
4402248dbc23SDave Airlie 		*depth = 15;
4403248dbc23SDave Airlie 		*bpp = 16;
4404248dbc23SDave Airlie 		break;
440504b3924dSVille Syrjälä 	case DRM_FORMAT_RGB565:
440604b3924dSVille Syrjälä 	case DRM_FORMAT_BGR565:
4407248dbc23SDave Airlie 		*depth = 16;
4408248dbc23SDave Airlie 		*bpp = 16;
4409248dbc23SDave Airlie 		break;
441004b3924dSVille Syrjälä 	case DRM_FORMAT_RGB888:
441104b3924dSVille Syrjälä 	case DRM_FORMAT_BGR888:
441204b3924dSVille Syrjälä 		*depth = 24;
441304b3924dSVille Syrjälä 		*bpp = 24;
441404b3924dSVille Syrjälä 		break;
441504b3924dSVille Syrjälä 	case DRM_FORMAT_XRGB8888:
441604b3924dSVille Syrjälä 	case DRM_FORMAT_XBGR8888:
441704b3924dSVille Syrjälä 	case DRM_FORMAT_RGBX8888:
441804b3924dSVille Syrjälä 	case DRM_FORMAT_BGRX8888:
4419248dbc23SDave Airlie 		*depth = 24;
4420248dbc23SDave Airlie 		*bpp = 32;
4421248dbc23SDave Airlie 		break;
442204b3924dSVille Syrjälä 	case DRM_FORMAT_XRGB2101010:
442304b3924dSVille Syrjälä 	case DRM_FORMAT_XBGR2101010:
442404b3924dSVille Syrjälä 	case DRM_FORMAT_RGBX1010102:
442504b3924dSVille Syrjälä 	case DRM_FORMAT_BGRX1010102:
442604b3924dSVille Syrjälä 	case DRM_FORMAT_ARGB2101010:
442704b3924dSVille Syrjälä 	case DRM_FORMAT_ABGR2101010:
442804b3924dSVille Syrjälä 	case DRM_FORMAT_RGBA1010102:
442904b3924dSVille Syrjälä 	case DRM_FORMAT_BGRA1010102:
4430248dbc23SDave Airlie 		*depth = 30;
4431248dbc23SDave Airlie 		*bpp = 32;
4432248dbc23SDave Airlie 		break;
443304b3924dSVille Syrjälä 	case DRM_FORMAT_ARGB8888:
443404b3924dSVille Syrjälä 	case DRM_FORMAT_ABGR8888:
443504b3924dSVille Syrjälä 	case DRM_FORMAT_RGBA8888:
443604b3924dSVille Syrjälä 	case DRM_FORMAT_BGRA8888:
4437248dbc23SDave Airlie 		*depth = 32;
4438248dbc23SDave Airlie 		*bpp = 32;
4439248dbc23SDave Airlie 		break;
4440248dbc23SDave Airlie 	default:
444123c453a4SVille Syrjälä 		DRM_DEBUG_KMS("unsupported pixel format %s\n",
444223c453a4SVille Syrjälä 			      drm_get_format_name(format));
4443248dbc23SDave Airlie 		*depth = 0;
4444248dbc23SDave Airlie 		*bpp = 0;
4445248dbc23SDave Airlie 		break;
4446248dbc23SDave Airlie 	}
4447248dbc23SDave Airlie }
4448248dbc23SDave Airlie EXPORT_SYMBOL(drm_fb_get_bpp_depth);
4449141670e9SVille Syrjälä 
4450141670e9SVille Syrjälä /**
4451141670e9SVille Syrjälä  * drm_format_num_planes - get the number of planes for format
4452141670e9SVille Syrjälä  * @format: pixel format (DRM_FORMAT_*)
4453141670e9SVille Syrjälä  *
4454c8e32cc1SDaniel Vetter  * Returns:
4455141670e9SVille Syrjälä  * The number of planes used by the specified pixel format.
4456141670e9SVille Syrjälä  */
4457141670e9SVille Syrjälä int drm_format_num_planes(uint32_t format)
4458141670e9SVille Syrjälä {
4459141670e9SVille Syrjälä 	switch (format) {
4460141670e9SVille Syrjälä 	case DRM_FORMAT_YUV410:
4461141670e9SVille Syrjälä 	case DRM_FORMAT_YVU410:
4462141670e9SVille Syrjälä 	case DRM_FORMAT_YUV411:
4463141670e9SVille Syrjälä 	case DRM_FORMAT_YVU411:
4464141670e9SVille Syrjälä 	case DRM_FORMAT_YUV420:
4465141670e9SVille Syrjälä 	case DRM_FORMAT_YVU420:
4466141670e9SVille Syrjälä 	case DRM_FORMAT_YUV422:
4467141670e9SVille Syrjälä 	case DRM_FORMAT_YVU422:
4468141670e9SVille Syrjälä 	case DRM_FORMAT_YUV444:
4469141670e9SVille Syrjälä 	case DRM_FORMAT_YVU444:
4470141670e9SVille Syrjälä 		return 3;
4471141670e9SVille Syrjälä 	case DRM_FORMAT_NV12:
4472141670e9SVille Syrjälä 	case DRM_FORMAT_NV21:
4473141670e9SVille Syrjälä 	case DRM_FORMAT_NV16:
4474141670e9SVille Syrjälä 	case DRM_FORMAT_NV61:
4475ba623f6aSLaurent Pinchart 	case DRM_FORMAT_NV24:
4476ba623f6aSLaurent Pinchart 	case DRM_FORMAT_NV42:
4477141670e9SVille Syrjälä 		return 2;
4478141670e9SVille Syrjälä 	default:
4479141670e9SVille Syrjälä 		return 1;
4480141670e9SVille Syrjälä 	}
4481141670e9SVille Syrjälä }
4482141670e9SVille Syrjälä EXPORT_SYMBOL(drm_format_num_planes);
44835a86bd55SVille Syrjälä 
44845a86bd55SVille Syrjälä /**
44855a86bd55SVille Syrjälä  * drm_format_plane_cpp - determine the bytes per pixel value
44865a86bd55SVille Syrjälä  * @format: pixel format (DRM_FORMAT_*)
44875a86bd55SVille Syrjälä  * @plane: plane index
44885a86bd55SVille Syrjälä  *
4489c8e32cc1SDaniel Vetter  * Returns:
44905a86bd55SVille Syrjälä  * The bytes per pixel value for the specified plane.
44915a86bd55SVille Syrjälä  */
44925a86bd55SVille Syrjälä int drm_format_plane_cpp(uint32_t format, int plane)
44935a86bd55SVille Syrjälä {
44945a86bd55SVille Syrjälä 	unsigned int depth;
44955a86bd55SVille Syrjälä 	int bpp;
44965a86bd55SVille Syrjälä 
44975a86bd55SVille Syrjälä 	if (plane >= drm_format_num_planes(format))
44985a86bd55SVille Syrjälä 		return 0;
44995a86bd55SVille Syrjälä 
45005a86bd55SVille Syrjälä 	switch (format) {
45015a86bd55SVille Syrjälä 	case DRM_FORMAT_YUYV:
45025a86bd55SVille Syrjälä 	case DRM_FORMAT_YVYU:
45035a86bd55SVille Syrjälä 	case DRM_FORMAT_UYVY:
45045a86bd55SVille Syrjälä 	case DRM_FORMAT_VYUY:
45055a86bd55SVille Syrjälä 		return 2;
45065a86bd55SVille Syrjälä 	case DRM_FORMAT_NV12:
45075a86bd55SVille Syrjälä 	case DRM_FORMAT_NV21:
45085a86bd55SVille Syrjälä 	case DRM_FORMAT_NV16:
45095a86bd55SVille Syrjälä 	case DRM_FORMAT_NV61:
4510ba623f6aSLaurent Pinchart 	case DRM_FORMAT_NV24:
4511ba623f6aSLaurent Pinchart 	case DRM_FORMAT_NV42:
45125a86bd55SVille Syrjälä 		return plane ? 2 : 1;
45135a86bd55SVille Syrjälä 	case DRM_FORMAT_YUV410:
45145a86bd55SVille Syrjälä 	case DRM_FORMAT_YVU410:
45155a86bd55SVille Syrjälä 	case DRM_FORMAT_YUV411:
45165a86bd55SVille Syrjälä 	case DRM_FORMAT_YVU411:
45175a86bd55SVille Syrjälä 	case DRM_FORMAT_YUV420:
45185a86bd55SVille Syrjälä 	case DRM_FORMAT_YVU420:
45195a86bd55SVille Syrjälä 	case DRM_FORMAT_YUV422:
45205a86bd55SVille Syrjälä 	case DRM_FORMAT_YVU422:
45215a86bd55SVille Syrjälä 	case DRM_FORMAT_YUV444:
45225a86bd55SVille Syrjälä 	case DRM_FORMAT_YVU444:
45235a86bd55SVille Syrjälä 		return 1;
45245a86bd55SVille Syrjälä 	default:
45255a86bd55SVille Syrjälä 		drm_fb_get_bpp_depth(format, &depth, &bpp);
45265a86bd55SVille Syrjälä 		return bpp >> 3;
45275a86bd55SVille Syrjälä 	}
45285a86bd55SVille Syrjälä }
45295a86bd55SVille Syrjälä EXPORT_SYMBOL(drm_format_plane_cpp);
453001b68b04SVille Syrjälä 
453101b68b04SVille Syrjälä /**
453201b68b04SVille Syrjälä  * drm_format_horz_chroma_subsampling - get the horizontal chroma subsampling factor
453301b68b04SVille Syrjälä  * @format: pixel format (DRM_FORMAT_*)
453401b68b04SVille Syrjälä  *
4535c8e32cc1SDaniel Vetter  * Returns:
453601b68b04SVille Syrjälä  * The horizontal chroma subsampling factor for the
453701b68b04SVille Syrjälä  * specified pixel format.
453801b68b04SVille Syrjälä  */
453901b68b04SVille Syrjälä int drm_format_horz_chroma_subsampling(uint32_t format)
454001b68b04SVille Syrjälä {
454101b68b04SVille Syrjälä 	switch (format) {
454201b68b04SVille Syrjälä 	case DRM_FORMAT_YUV411:
454301b68b04SVille Syrjälä 	case DRM_FORMAT_YVU411:
454401b68b04SVille Syrjälä 	case DRM_FORMAT_YUV410:
454501b68b04SVille Syrjälä 	case DRM_FORMAT_YVU410:
454601b68b04SVille Syrjälä 		return 4;
454701b68b04SVille Syrjälä 	case DRM_FORMAT_YUYV:
454801b68b04SVille Syrjälä 	case DRM_FORMAT_YVYU:
454901b68b04SVille Syrjälä 	case DRM_FORMAT_UYVY:
455001b68b04SVille Syrjälä 	case DRM_FORMAT_VYUY:
455101b68b04SVille Syrjälä 	case DRM_FORMAT_NV12:
455201b68b04SVille Syrjälä 	case DRM_FORMAT_NV21:
455301b68b04SVille Syrjälä 	case DRM_FORMAT_NV16:
455401b68b04SVille Syrjälä 	case DRM_FORMAT_NV61:
455501b68b04SVille Syrjälä 	case DRM_FORMAT_YUV422:
455601b68b04SVille Syrjälä 	case DRM_FORMAT_YVU422:
455701b68b04SVille Syrjälä 	case DRM_FORMAT_YUV420:
455801b68b04SVille Syrjälä 	case DRM_FORMAT_YVU420:
455901b68b04SVille Syrjälä 		return 2;
456001b68b04SVille Syrjälä 	default:
456101b68b04SVille Syrjälä 		return 1;
456201b68b04SVille Syrjälä 	}
456301b68b04SVille Syrjälä }
456401b68b04SVille Syrjälä EXPORT_SYMBOL(drm_format_horz_chroma_subsampling);
456501b68b04SVille Syrjälä 
456601b68b04SVille Syrjälä /**
456701b68b04SVille Syrjälä  * drm_format_vert_chroma_subsampling - get the vertical chroma subsampling factor
456801b68b04SVille Syrjälä  * @format: pixel format (DRM_FORMAT_*)
456901b68b04SVille Syrjälä  *
4570c8e32cc1SDaniel Vetter  * Returns:
457101b68b04SVille Syrjälä  * The vertical chroma subsampling factor for the
457201b68b04SVille Syrjälä  * specified pixel format.
457301b68b04SVille Syrjälä  */
457401b68b04SVille Syrjälä int drm_format_vert_chroma_subsampling(uint32_t format)
457501b68b04SVille Syrjälä {
457601b68b04SVille Syrjälä 	switch (format) {
457701b68b04SVille Syrjälä 	case DRM_FORMAT_YUV410:
457801b68b04SVille Syrjälä 	case DRM_FORMAT_YVU410:
457901b68b04SVille Syrjälä 		return 4;
458001b68b04SVille Syrjälä 	case DRM_FORMAT_YUV420:
458101b68b04SVille Syrjälä 	case DRM_FORMAT_YVU420:
458201b68b04SVille Syrjälä 	case DRM_FORMAT_NV12:
458301b68b04SVille Syrjälä 	case DRM_FORMAT_NV21:
458401b68b04SVille Syrjälä 		return 2;
458501b68b04SVille Syrjälä 	default:
458601b68b04SVille Syrjälä 		return 1;
458701b68b04SVille Syrjälä 	}
458801b68b04SVille Syrjälä }
458901b68b04SVille Syrjälä EXPORT_SYMBOL(drm_format_vert_chroma_subsampling);
459087d24fc3SLaurent Pinchart 
459187d24fc3SLaurent Pinchart /**
459287d24fc3SLaurent Pinchart  * drm_mode_config_init - initialize DRM mode_configuration structure
459387d24fc3SLaurent Pinchart  * @dev: DRM device
459487d24fc3SLaurent Pinchart  *
459587d24fc3SLaurent Pinchart  * Initialize @dev's mode_config structure, used for tracking the graphics
459687d24fc3SLaurent Pinchart  * configuration of @dev.
459787d24fc3SLaurent Pinchart  *
459887d24fc3SLaurent Pinchart  * Since this initializes the modeset locks, no locking is possible. Which is no
459987d24fc3SLaurent Pinchart  * problem, since this should happen single threaded at init time. It is the
460087d24fc3SLaurent Pinchart  * driver's problem to ensure this guarantee.
460187d24fc3SLaurent Pinchart  *
460287d24fc3SLaurent Pinchart  */
460387d24fc3SLaurent Pinchart void drm_mode_config_init(struct drm_device *dev)
460487d24fc3SLaurent Pinchart {
460587d24fc3SLaurent Pinchart 	mutex_init(&dev->mode_config.mutex);
460687d24fc3SLaurent Pinchart 	mutex_init(&dev->mode_config.idr_mutex);
460787d24fc3SLaurent Pinchart 	mutex_init(&dev->mode_config.fb_lock);
460887d24fc3SLaurent Pinchart 	INIT_LIST_HEAD(&dev->mode_config.fb_list);
460987d24fc3SLaurent Pinchart 	INIT_LIST_HEAD(&dev->mode_config.crtc_list);
461087d24fc3SLaurent Pinchart 	INIT_LIST_HEAD(&dev->mode_config.connector_list);
46113b336ec4SSean Paul 	INIT_LIST_HEAD(&dev->mode_config.bridge_list);
461287d24fc3SLaurent Pinchart 	INIT_LIST_HEAD(&dev->mode_config.encoder_list);
461387d24fc3SLaurent Pinchart 	INIT_LIST_HEAD(&dev->mode_config.property_list);
461487d24fc3SLaurent Pinchart 	INIT_LIST_HEAD(&dev->mode_config.property_blob_list);
461587d24fc3SLaurent Pinchart 	INIT_LIST_HEAD(&dev->mode_config.plane_list);
461687d24fc3SLaurent Pinchart 	idr_init(&dev->mode_config.crtc_idr);
461787d24fc3SLaurent Pinchart 
461887d24fc3SLaurent Pinchart 	drm_modeset_lock_all(dev);
461987d24fc3SLaurent Pinchart 	drm_mode_create_standard_connector_properties(dev);
46209922ab5aSRob Clark 	drm_mode_create_standard_plane_properties(dev);
462187d24fc3SLaurent Pinchart 	drm_modeset_unlock_all(dev);
462287d24fc3SLaurent Pinchart 
462387d24fc3SLaurent Pinchart 	/* Just to be sure */
462487d24fc3SLaurent Pinchart 	dev->mode_config.num_fb = 0;
462587d24fc3SLaurent Pinchart 	dev->mode_config.num_connector = 0;
462687d24fc3SLaurent Pinchart 	dev->mode_config.num_crtc = 0;
462787d24fc3SLaurent Pinchart 	dev->mode_config.num_encoder = 0;
4628e27dde3eSMatt Roper 	dev->mode_config.num_overlay_plane = 0;
4629e27dde3eSMatt Roper 	dev->mode_config.num_total_plane = 0;
463087d24fc3SLaurent Pinchart }
463187d24fc3SLaurent Pinchart EXPORT_SYMBOL(drm_mode_config_init);
463287d24fc3SLaurent Pinchart 
463387d24fc3SLaurent Pinchart /**
463487d24fc3SLaurent Pinchart  * drm_mode_config_cleanup - free up DRM mode_config info
463587d24fc3SLaurent Pinchart  * @dev: DRM device
463687d24fc3SLaurent Pinchart  *
463787d24fc3SLaurent Pinchart  * Free up all the connectors and CRTCs associated with this DRM device, then
463887d24fc3SLaurent Pinchart  * free up the framebuffers and associated buffer objects.
463987d24fc3SLaurent Pinchart  *
464087d24fc3SLaurent Pinchart  * Note that since this /should/ happen single-threaded at driver/device
464187d24fc3SLaurent Pinchart  * teardown time, no locking is required. It's the driver's job to ensure that
464287d24fc3SLaurent Pinchart  * this guarantee actually holds true.
464387d24fc3SLaurent Pinchart  *
464487d24fc3SLaurent Pinchart  * FIXME: cleanup any dangling user buffer objects too
464587d24fc3SLaurent Pinchart  */
464687d24fc3SLaurent Pinchart void drm_mode_config_cleanup(struct drm_device *dev)
464787d24fc3SLaurent Pinchart {
464887d24fc3SLaurent Pinchart 	struct drm_connector *connector, *ot;
464987d24fc3SLaurent Pinchart 	struct drm_crtc *crtc, *ct;
465087d24fc3SLaurent Pinchart 	struct drm_encoder *encoder, *enct;
46513b336ec4SSean Paul 	struct drm_bridge *bridge, *brt;
465287d24fc3SLaurent Pinchart 	struct drm_framebuffer *fb, *fbt;
465387d24fc3SLaurent Pinchart 	struct drm_property *property, *pt;
465487d24fc3SLaurent Pinchart 	struct drm_property_blob *blob, *bt;
465587d24fc3SLaurent Pinchart 	struct drm_plane *plane, *plt;
465687d24fc3SLaurent Pinchart 
465787d24fc3SLaurent Pinchart 	list_for_each_entry_safe(encoder, enct, &dev->mode_config.encoder_list,
465887d24fc3SLaurent Pinchart 				 head) {
465987d24fc3SLaurent Pinchart 		encoder->funcs->destroy(encoder);
466087d24fc3SLaurent Pinchart 	}
466187d24fc3SLaurent Pinchart 
46623b336ec4SSean Paul 	list_for_each_entry_safe(bridge, brt,
46633b336ec4SSean Paul 				 &dev->mode_config.bridge_list, head) {
46643b336ec4SSean Paul 		bridge->funcs->destroy(bridge);
46653b336ec4SSean Paul 	}
46663b336ec4SSean Paul 
466787d24fc3SLaurent Pinchart 	list_for_each_entry_safe(connector, ot,
466887d24fc3SLaurent Pinchart 				 &dev->mode_config.connector_list, head) {
466987d24fc3SLaurent Pinchart 		connector->funcs->destroy(connector);
467087d24fc3SLaurent Pinchart 	}
467187d24fc3SLaurent Pinchart 
467287d24fc3SLaurent Pinchart 	list_for_each_entry_safe(property, pt, &dev->mode_config.property_list,
467387d24fc3SLaurent Pinchart 				 head) {
467487d24fc3SLaurent Pinchart 		drm_property_destroy(dev, property);
467587d24fc3SLaurent Pinchart 	}
467687d24fc3SLaurent Pinchart 
467787d24fc3SLaurent Pinchart 	list_for_each_entry_safe(blob, bt, &dev->mode_config.property_blob_list,
467887d24fc3SLaurent Pinchart 				 head) {
467987d24fc3SLaurent Pinchart 		drm_property_destroy_blob(dev, blob);
468087d24fc3SLaurent Pinchart 	}
468187d24fc3SLaurent Pinchart 
468287d24fc3SLaurent Pinchart 	/*
468387d24fc3SLaurent Pinchart 	 * Single-threaded teardown context, so it's not required to grab the
468487d24fc3SLaurent Pinchart 	 * fb_lock to protect against concurrent fb_list access. Contrary, it
468587d24fc3SLaurent Pinchart 	 * would actually deadlock with the drm_framebuffer_cleanup function.
468687d24fc3SLaurent Pinchart 	 *
468787d24fc3SLaurent Pinchart 	 * Also, if there are any framebuffers left, that's a driver leak now,
468887d24fc3SLaurent Pinchart 	 * so politely WARN about this.
468987d24fc3SLaurent Pinchart 	 */
469087d24fc3SLaurent Pinchart 	WARN_ON(!list_empty(&dev->mode_config.fb_list));
469187d24fc3SLaurent Pinchart 	list_for_each_entry_safe(fb, fbt, &dev->mode_config.fb_list, head) {
469287d24fc3SLaurent Pinchart 		drm_framebuffer_remove(fb);
469387d24fc3SLaurent Pinchart 	}
469487d24fc3SLaurent Pinchart 
469587d24fc3SLaurent Pinchart 	list_for_each_entry_safe(plane, plt, &dev->mode_config.plane_list,
469687d24fc3SLaurent Pinchart 				 head) {
469787d24fc3SLaurent Pinchart 		plane->funcs->destroy(plane);
469887d24fc3SLaurent Pinchart 	}
469987d24fc3SLaurent Pinchart 
470087d24fc3SLaurent Pinchart 	list_for_each_entry_safe(crtc, ct, &dev->mode_config.crtc_list, head) {
470187d24fc3SLaurent Pinchart 		crtc->funcs->destroy(crtc);
470287d24fc3SLaurent Pinchart 	}
470387d24fc3SLaurent Pinchart 
470487d24fc3SLaurent Pinchart 	idr_destroy(&dev->mode_config.crtc_idr);
470587d24fc3SLaurent Pinchart }
470687d24fc3SLaurent Pinchart EXPORT_SYMBOL(drm_mode_config_cleanup);
4707