1f453ba04SDave Airlie /* 2f453ba04SDave Airlie * Copyright (c) 2006-2008 Intel Corporation 3f453ba04SDave Airlie * Copyright (c) 2007 Dave Airlie <airlied@linux.ie> 4f453ba04SDave Airlie * Copyright (c) 2008 Red Hat Inc. 5f453ba04SDave Airlie * 6f453ba04SDave Airlie * DRM core CRTC related functions 7f453ba04SDave Airlie * 8f453ba04SDave Airlie * Permission to use, copy, modify, distribute, and sell this software and its 9f453ba04SDave Airlie * documentation for any purpose is hereby granted without fee, provided that 10f453ba04SDave Airlie * the above copyright notice appear in all copies and that both that copyright 11f453ba04SDave Airlie * notice and this permission notice appear in supporting documentation, and 12f453ba04SDave Airlie * that the name of the copyright holders not be used in advertising or 13f453ba04SDave Airlie * publicity pertaining to distribution of the software without specific, 14f453ba04SDave Airlie * written prior permission. The copyright holders make no representations 15f453ba04SDave Airlie * about the suitability of this software for any purpose. It is provided "as 16f453ba04SDave Airlie * is" without express or implied warranty. 17f453ba04SDave Airlie * 18f453ba04SDave Airlie * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, 19f453ba04SDave Airlie * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO 20f453ba04SDave Airlie * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR 21f453ba04SDave Airlie * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, 22f453ba04SDave Airlie * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER 23f453ba04SDave Airlie * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE 24f453ba04SDave Airlie * OF THIS SOFTWARE. 25f453ba04SDave Airlie * 26f453ba04SDave Airlie * Authors: 27f453ba04SDave Airlie * Keith Packard 28f453ba04SDave Airlie * Eric Anholt <eric@anholt.net> 29f453ba04SDave Airlie * Dave Airlie <airlied@linux.ie> 30f453ba04SDave Airlie * Jesse Barnes <jesse.barnes@intel.com> 31f453ba04SDave Airlie */ 326ba6d03eSVille Syrjälä #include <linux/ctype.h> 33f453ba04SDave Airlie #include <linux/list.h> 345a0e3ad6STejun Heo #include <linux/slab.h> 352d1a8a48SPaul Gortmaker #include <linux/export.h> 36760285e7SDavid Howells #include <drm/drmP.h> 37760285e7SDavid Howells #include <drm/drm_crtc.h> 38760285e7SDavid Howells #include <drm/drm_edid.h> 39760285e7SDavid Howells #include <drm/drm_fourcc.h> 4051fd371bSRob Clark #include <drm/drm_modeset_lock.h> 4188a48e29SRob Clark #include <drm/drm_atomic.h> 42f453ba04SDave Airlie 438bd441b2SDaniel Vetter #include "drm_crtc_internal.h" 4467d0ec4eSDaniel Vetter #include "drm_internal.h" 458bd441b2SDaniel Vetter 469a6f5130SChris Wilson static struct drm_framebuffer * 479a6f5130SChris Wilson internal_framebuffer_create(struct drm_device *dev, 48c394c2b0SMatt Roper struct drm_mode_fb_cmd2 *r, 49c394c2b0SMatt Roper struct drm_file *file_priv); 50c394c2b0SMatt Roper 51f453ba04SDave Airlie /* Avoid boilerplate. I'm tired of typing. */ 52f453ba04SDave Airlie #define DRM_ENUM_NAME_FN(fnname, list) \ 53d20d3174SVille Syrjälä const char *fnname(int val) \ 54f453ba04SDave Airlie { \ 55f453ba04SDave Airlie int i; \ 56f453ba04SDave Airlie for (i = 0; i < ARRAY_SIZE(list); i++) { \ 57f453ba04SDave Airlie if (list[i].type == val) \ 58f453ba04SDave Airlie return list[i].name; \ 59f453ba04SDave Airlie } \ 60f453ba04SDave Airlie return "(unknown)"; \ 61f453ba04SDave Airlie } 62f453ba04SDave Airlie 63f453ba04SDave Airlie /* 64f453ba04SDave Airlie * Global properties 65f453ba04SDave Airlie */ 664dfd909fSThierry Reding static const struct drm_prop_enum_list drm_dpms_enum_list[] = { 674dfd909fSThierry Reding { DRM_MODE_DPMS_ON, "On" }, 68f453ba04SDave Airlie { DRM_MODE_DPMS_STANDBY, "Standby" }, 69f453ba04SDave Airlie { DRM_MODE_DPMS_SUSPEND, "Suspend" }, 70f453ba04SDave Airlie { DRM_MODE_DPMS_OFF, "Off" } 71f453ba04SDave Airlie }; 72f453ba04SDave Airlie 73f453ba04SDave Airlie DRM_ENUM_NAME_FN(drm_get_dpms_name, drm_dpms_enum_list) 74f453ba04SDave Airlie 754dfd909fSThierry Reding static const struct drm_prop_enum_list drm_plane_type_enum_list[] = { 769922ab5aSRob Clark { DRM_PLANE_TYPE_OVERLAY, "Overlay" }, 779922ab5aSRob Clark { DRM_PLANE_TYPE_PRIMARY, "Primary" }, 789922ab5aSRob Clark { DRM_PLANE_TYPE_CURSOR, "Cursor" }, 799922ab5aSRob Clark }; 809922ab5aSRob Clark 81f453ba04SDave Airlie /* 82f453ba04SDave Airlie * Optional properties 83f453ba04SDave Airlie */ 844dfd909fSThierry Reding static const struct drm_prop_enum_list drm_scaling_mode_enum_list[] = { 8553bd8389SJesse Barnes { DRM_MODE_SCALE_NONE, "None" }, 8653bd8389SJesse Barnes { DRM_MODE_SCALE_FULLSCREEN, "Full" }, 8753bd8389SJesse Barnes { DRM_MODE_SCALE_CENTER, "Center" }, 8853bd8389SJesse Barnes { DRM_MODE_SCALE_ASPECT, "Full aspect" }, 89f453ba04SDave Airlie }; 90f453ba04SDave Airlie 91ff587e45SVandana Kannan static const struct drm_prop_enum_list drm_aspect_ratio_enum_list[] = { 92ff587e45SVandana Kannan { DRM_MODE_PICTURE_ASPECT_NONE, "Automatic" }, 93ff587e45SVandana Kannan { DRM_MODE_PICTURE_ASPECT_4_3, "4:3" }, 94ff587e45SVandana Kannan { DRM_MODE_PICTURE_ASPECT_16_9, "16:9" }, 95ff587e45SVandana Kannan }; 96ff587e45SVandana Kannan 97f453ba04SDave Airlie /* 98f453ba04SDave Airlie * Non-global properties, but "required" for certain connectors. 99f453ba04SDave Airlie */ 1004dfd909fSThierry Reding static const struct drm_prop_enum_list drm_dvi_i_select_enum_list[] = { 101f453ba04SDave Airlie { DRM_MODE_SUBCONNECTOR_Automatic, "Automatic" }, /* DVI-I and TV-out */ 102f453ba04SDave Airlie { DRM_MODE_SUBCONNECTOR_DVID, "DVI-D" }, /* DVI-I */ 103f453ba04SDave Airlie { DRM_MODE_SUBCONNECTOR_DVIA, "DVI-A" }, /* DVI-I */ 104f453ba04SDave Airlie }; 105f453ba04SDave Airlie 106f453ba04SDave Airlie DRM_ENUM_NAME_FN(drm_get_dvi_i_select_name, drm_dvi_i_select_enum_list) 107f453ba04SDave Airlie 1084dfd909fSThierry Reding static const struct drm_prop_enum_list drm_dvi_i_subconnector_enum_list[] = { 109f453ba04SDave Airlie { DRM_MODE_SUBCONNECTOR_Unknown, "Unknown" }, /* DVI-I and TV-out */ 110f453ba04SDave Airlie { DRM_MODE_SUBCONNECTOR_DVID, "DVI-D" }, /* DVI-I */ 111f453ba04SDave Airlie { DRM_MODE_SUBCONNECTOR_DVIA, "DVI-A" }, /* DVI-I */ 112f453ba04SDave Airlie }; 113f453ba04SDave Airlie 114f453ba04SDave Airlie DRM_ENUM_NAME_FN(drm_get_dvi_i_subconnector_name, 115f453ba04SDave Airlie drm_dvi_i_subconnector_enum_list) 116f453ba04SDave Airlie 1174dfd909fSThierry Reding static const struct drm_prop_enum_list drm_tv_select_enum_list[] = { 118f453ba04SDave Airlie { DRM_MODE_SUBCONNECTOR_Automatic, "Automatic" }, /* DVI-I and TV-out */ 119f453ba04SDave Airlie { DRM_MODE_SUBCONNECTOR_Composite, "Composite" }, /* TV-out */ 120f453ba04SDave Airlie { DRM_MODE_SUBCONNECTOR_SVIDEO, "SVIDEO" }, /* TV-out */ 121f453ba04SDave Airlie { DRM_MODE_SUBCONNECTOR_Component, "Component" }, /* TV-out */ 122aeaa1ad3SFrancisco Jerez { DRM_MODE_SUBCONNECTOR_SCART, "SCART" }, /* TV-out */ 123f453ba04SDave Airlie }; 124f453ba04SDave Airlie 125f453ba04SDave Airlie DRM_ENUM_NAME_FN(drm_get_tv_select_name, drm_tv_select_enum_list) 126f453ba04SDave Airlie 1274dfd909fSThierry Reding static const struct drm_prop_enum_list drm_tv_subconnector_enum_list[] = { 128f453ba04SDave Airlie { DRM_MODE_SUBCONNECTOR_Unknown, "Unknown" }, /* DVI-I and TV-out */ 129f453ba04SDave Airlie { DRM_MODE_SUBCONNECTOR_Composite, "Composite" }, /* TV-out */ 130f453ba04SDave Airlie { DRM_MODE_SUBCONNECTOR_SVIDEO, "SVIDEO" }, /* TV-out */ 131f453ba04SDave Airlie { DRM_MODE_SUBCONNECTOR_Component, "Component" }, /* TV-out */ 132aeaa1ad3SFrancisco Jerez { DRM_MODE_SUBCONNECTOR_SCART, "SCART" }, /* TV-out */ 133f453ba04SDave Airlie }; 134f453ba04SDave Airlie 135f453ba04SDave Airlie DRM_ENUM_NAME_FN(drm_get_tv_subconnector_name, 136f453ba04SDave Airlie drm_tv_subconnector_enum_list) 137f453ba04SDave Airlie 138d20d3174SVille Syrjälä static const struct drm_prop_enum_list drm_dirty_info_enum_list[] = { 139884840aaSJakob Bornecrantz { DRM_MODE_DIRTY_OFF, "Off" }, 140884840aaSJakob Bornecrantz { DRM_MODE_DIRTY_ON, "On" }, 141884840aaSJakob Bornecrantz { DRM_MODE_DIRTY_ANNOTATE, "Annotate" }, 142884840aaSJakob Bornecrantz }; 143884840aaSJakob Bornecrantz 144f453ba04SDave Airlie struct drm_conn_prop_enum_list { 145f453ba04SDave Airlie int type; 146d20d3174SVille Syrjälä const char *name; 147b21e3afeSIlia Mirkin struct ida ida; 148f453ba04SDave Airlie }; 149f453ba04SDave Airlie 150f453ba04SDave Airlie /* 151f453ba04SDave Airlie * Connector and encoder types. 152f453ba04SDave Airlie */ 1534dfd909fSThierry Reding static struct drm_conn_prop_enum_list drm_connector_enum_list[] = { 1544dfd909fSThierry Reding { DRM_MODE_CONNECTOR_Unknown, "Unknown" }, 155b21e3afeSIlia Mirkin { DRM_MODE_CONNECTOR_VGA, "VGA" }, 156b21e3afeSIlia Mirkin { DRM_MODE_CONNECTOR_DVII, "DVI-I" }, 157b21e3afeSIlia Mirkin { DRM_MODE_CONNECTOR_DVID, "DVI-D" }, 158b21e3afeSIlia Mirkin { DRM_MODE_CONNECTOR_DVIA, "DVI-A" }, 159b21e3afeSIlia Mirkin { DRM_MODE_CONNECTOR_Composite, "Composite" }, 160b21e3afeSIlia Mirkin { DRM_MODE_CONNECTOR_SVIDEO, "SVIDEO" }, 161b21e3afeSIlia Mirkin { DRM_MODE_CONNECTOR_LVDS, "LVDS" }, 162b21e3afeSIlia Mirkin { DRM_MODE_CONNECTOR_Component, "Component" }, 163b21e3afeSIlia Mirkin { DRM_MODE_CONNECTOR_9PinDIN, "DIN" }, 164b21e3afeSIlia Mirkin { DRM_MODE_CONNECTOR_DisplayPort, "DP" }, 165b21e3afeSIlia Mirkin { DRM_MODE_CONNECTOR_HDMIA, "HDMI-A" }, 166b21e3afeSIlia Mirkin { DRM_MODE_CONNECTOR_HDMIB, "HDMI-B" }, 167b21e3afeSIlia Mirkin { DRM_MODE_CONNECTOR_TV, "TV" }, 168b21e3afeSIlia Mirkin { DRM_MODE_CONNECTOR_eDP, "eDP" }, 169b21e3afeSIlia Mirkin { DRM_MODE_CONNECTOR_VIRTUAL, "Virtual" }, 170b8923273SShobhit Kumar { DRM_MODE_CONNECTOR_DSI, "DSI" }, 171f453ba04SDave Airlie }; 172f453ba04SDave Airlie 1734dfd909fSThierry Reding static const struct drm_prop_enum_list drm_encoder_enum_list[] = { 1744dfd909fSThierry Reding { DRM_MODE_ENCODER_NONE, "None" }, 175f453ba04SDave Airlie { DRM_MODE_ENCODER_DAC, "DAC" }, 176f453ba04SDave Airlie { DRM_MODE_ENCODER_TMDS, "TMDS" }, 177f453ba04SDave Airlie { DRM_MODE_ENCODER_LVDS, "LVDS" }, 178f453ba04SDave Airlie { DRM_MODE_ENCODER_TVDAC, "TV" }, 179a7331e5cSThomas Hellstrom { DRM_MODE_ENCODER_VIRTUAL, "Virtual" }, 180b8923273SShobhit Kumar { DRM_MODE_ENCODER_DSI, "DSI" }, 181182407a6SDave Airlie { DRM_MODE_ENCODER_DPMST, "DP MST" }, 182f453ba04SDave Airlie }; 183f453ba04SDave Airlie 1844dfd909fSThierry Reding static const struct drm_prop_enum_list drm_subpixel_enum_list[] = { 185ac1bb36cSJesse Barnes { SubPixelUnknown, "Unknown" }, 186ac1bb36cSJesse Barnes { SubPixelHorizontalRGB, "Horizontal RGB" }, 187ac1bb36cSJesse Barnes { SubPixelHorizontalBGR, "Horizontal BGR" }, 188ac1bb36cSJesse Barnes { SubPixelVerticalRGB, "Vertical RGB" }, 189ac1bb36cSJesse Barnes { SubPixelVerticalBGR, "Vertical BGR" }, 190ac1bb36cSJesse Barnes { SubPixelNone, "None" }, 191ac1bb36cSJesse Barnes }; 192ac1bb36cSJesse Barnes 193b21e3afeSIlia Mirkin void drm_connector_ida_init(void) 194b21e3afeSIlia Mirkin { 195b21e3afeSIlia Mirkin int i; 196b21e3afeSIlia Mirkin 197b21e3afeSIlia Mirkin for (i = 0; i < ARRAY_SIZE(drm_connector_enum_list); i++) 198b21e3afeSIlia Mirkin ida_init(&drm_connector_enum_list[i].ida); 199b21e3afeSIlia Mirkin } 200b21e3afeSIlia Mirkin 201b21e3afeSIlia Mirkin void drm_connector_ida_destroy(void) 202b21e3afeSIlia Mirkin { 203b21e3afeSIlia Mirkin int i; 204b21e3afeSIlia Mirkin 205b21e3afeSIlia Mirkin for (i = 0; i < ARRAY_SIZE(drm_connector_enum_list); i++) 206b21e3afeSIlia Mirkin ida_destroy(&drm_connector_enum_list[i].ida); 207b21e3afeSIlia Mirkin } 208b21e3afeSIlia Mirkin 209c8e32cc1SDaniel Vetter /** 210c8e32cc1SDaniel Vetter * drm_get_connector_status_name - return a string for connector status 211c8e32cc1SDaniel Vetter * @status: connector status to compute name of 212c8e32cc1SDaniel Vetter * 213c8e32cc1SDaniel Vetter * In contrast to the other drm_get_*_name functions this one here returns a 214c8e32cc1SDaniel Vetter * const pointer and hence is threadsafe. 215c8e32cc1SDaniel Vetter */ 216d20d3174SVille Syrjälä const char *drm_get_connector_status_name(enum drm_connector_status status) 217f453ba04SDave Airlie { 218f453ba04SDave Airlie if (status == connector_status_connected) 219f453ba04SDave Airlie return "connected"; 220f453ba04SDave Airlie else if (status == connector_status_disconnected) 221f453ba04SDave Airlie return "disconnected"; 222f453ba04SDave Airlie else 223f453ba04SDave Airlie return "unknown"; 224f453ba04SDave Airlie } 225ed7951dcSLespiau, Damien EXPORT_SYMBOL(drm_get_connector_status_name); 226f453ba04SDave Airlie 227ac1bb36cSJesse Barnes /** 228ac1bb36cSJesse Barnes * drm_get_subpixel_order_name - return a string for a given subpixel enum 229ac1bb36cSJesse Barnes * @order: enum of subpixel_order 230ac1bb36cSJesse Barnes * 231ac1bb36cSJesse Barnes * Note you could abuse this and return something out of bounds, but that 232ac1bb36cSJesse Barnes * would be a caller error. No unscrubbed user data should make it here. 233ac1bb36cSJesse Barnes */ 234ac1bb36cSJesse Barnes const char *drm_get_subpixel_order_name(enum subpixel_order order) 235ac1bb36cSJesse Barnes { 236ac1bb36cSJesse Barnes return drm_subpixel_enum_list[order].name; 237ac1bb36cSJesse Barnes } 238ac1bb36cSJesse Barnes EXPORT_SYMBOL(drm_get_subpixel_order_name); 239ac1bb36cSJesse Barnes 2406ba6d03eSVille Syrjälä static char printable_char(int c) 2416ba6d03eSVille Syrjälä { 2426ba6d03eSVille Syrjälä return isascii(c) && isprint(c) ? c : '?'; 2436ba6d03eSVille Syrjälä } 2446ba6d03eSVille Syrjälä 245c8e32cc1SDaniel Vetter /** 246c8e32cc1SDaniel Vetter * drm_get_format_name - return a string for drm fourcc format 247c8e32cc1SDaniel Vetter * @format: format to compute name of 248c8e32cc1SDaniel Vetter * 249c8e32cc1SDaniel Vetter * Note that the buffer used by this function is globally shared and owned by 250c8e32cc1SDaniel Vetter * the function itself. 251c8e32cc1SDaniel Vetter * 252c8e32cc1SDaniel Vetter * FIXME: This isn't really multithreading safe. 253c8e32cc1SDaniel Vetter */ 254d20d3174SVille Syrjälä const char *drm_get_format_name(uint32_t format) 2556ba6d03eSVille Syrjälä { 2566ba6d03eSVille Syrjälä static char buf[32]; 2576ba6d03eSVille Syrjälä 2586ba6d03eSVille Syrjälä snprintf(buf, sizeof(buf), 2596ba6d03eSVille Syrjälä "%c%c%c%c %s-endian (0x%08x)", 2606ba6d03eSVille Syrjälä printable_char(format & 0xff), 2616ba6d03eSVille Syrjälä printable_char((format >> 8) & 0xff), 2626ba6d03eSVille Syrjälä printable_char((format >> 16) & 0xff), 2636ba6d03eSVille Syrjälä printable_char((format >> 24) & 0x7f), 2646ba6d03eSVille Syrjälä format & DRM_FORMAT_BIG_ENDIAN ? "big" : "little", 2656ba6d03eSVille Syrjälä format); 2666ba6d03eSVille Syrjälä 2676ba6d03eSVille Syrjälä return buf; 2686ba6d03eSVille Syrjälä } 2696ba6d03eSVille Syrjälä EXPORT_SYMBOL(drm_get_format_name); 2706ba6d03eSVille Syrjälä 2712ee39452SDave Airlie /* 2722ee39452SDave Airlie * Internal function to assign a slot in the object idr and optionally 2732ee39452SDave Airlie * register the object into the idr. 2742ee39452SDave Airlie */ 2752ee39452SDave Airlie static int drm_mode_object_get_reg(struct drm_device *dev, 2762ee39452SDave Airlie struct drm_mode_object *obj, 2772ee39452SDave Airlie uint32_t obj_type, 2782ee39452SDave Airlie bool register_obj) 2792ee39452SDave Airlie { 2802ee39452SDave Airlie int ret; 2812ee39452SDave Airlie 2822ee39452SDave Airlie mutex_lock(&dev->mode_config.idr_mutex); 2832ee39452SDave Airlie ret = idr_alloc(&dev->mode_config.crtc_idr, register_obj ? obj : NULL, 1, 0, GFP_KERNEL); 2842ee39452SDave Airlie if (ret >= 0) { 2852ee39452SDave Airlie /* 2862ee39452SDave Airlie * Set up the object linking under the protection of the idr 2872ee39452SDave Airlie * lock so that other users can't see inconsistent state. 2882ee39452SDave Airlie */ 2892ee39452SDave Airlie obj->id = ret; 2902ee39452SDave Airlie obj->type = obj_type; 2912ee39452SDave Airlie } 2922ee39452SDave Airlie mutex_unlock(&dev->mode_config.idr_mutex); 2932ee39452SDave Airlie 2942ee39452SDave Airlie return ret < 0 ? ret : 0; 2952ee39452SDave Airlie } 2962ee39452SDave Airlie 297f453ba04SDave Airlie /** 298065a50edSDaniel Vetter * drm_mode_object_get - allocate a new modeset identifier 299f453ba04SDave Airlie * @dev: DRM device 300065a50edSDaniel Vetter * @obj: object pointer, used to generate unique ID 301065a50edSDaniel Vetter * @obj_type: object type 302f453ba04SDave Airlie * 303f453ba04SDave Airlie * Create a unique identifier based on @ptr in @dev's identifier space. Used 304c8e32cc1SDaniel Vetter * for tracking modes, CRTCs and connectors. Note that despite the _get postfix 305c8e32cc1SDaniel Vetter * modeset identifiers are _not_ reference counted. Hence don't use this for 306c8e32cc1SDaniel Vetter * reference counted modeset objects like framebuffers. 307f453ba04SDave Airlie * 308c8e32cc1SDaniel Vetter * Returns: 309f453ba04SDave Airlie * New unique (relative to other objects in @dev) integer identifier for the 310f453ba04SDave Airlie * object. 311f453ba04SDave Airlie */ 3128bd441b2SDaniel Vetter int drm_mode_object_get(struct drm_device *dev, 313f453ba04SDave Airlie struct drm_mode_object *obj, uint32_t obj_type) 314f453ba04SDave Airlie { 3152ee39452SDave Airlie return drm_mode_object_get_reg(dev, obj, obj_type, true); 3164b096ac1SDaniel Vetter } 3174b096ac1SDaniel Vetter 3182ee39452SDave Airlie static void drm_mode_object_register(struct drm_device *dev, 3192ee39452SDave Airlie struct drm_mode_object *obj) 3202ee39452SDave Airlie { 3212ee39452SDave Airlie mutex_lock(&dev->mode_config.idr_mutex); 3222ee39452SDave Airlie idr_replace(&dev->mode_config.crtc_idr, obj, obj->id); 3232ee39452SDave Airlie mutex_unlock(&dev->mode_config.idr_mutex); 324f453ba04SDave Airlie } 325f453ba04SDave Airlie 326f453ba04SDave Airlie /** 327065a50edSDaniel Vetter * drm_mode_object_put - free a modeset identifer 328f453ba04SDave Airlie * @dev: DRM device 329065a50edSDaniel Vetter * @object: object to free 330f453ba04SDave Airlie * 331c8e32cc1SDaniel Vetter * Free @id from @dev's unique identifier pool. Note that despite the _get 332c8e32cc1SDaniel Vetter * postfix modeset identifiers are _not_ reference counted. Hence don't use this 333c8e32cc1SDaniel Vetter * for reference counted modeset objects like framebuffers. 334f453ba04SDave Airlie */ 3358bd441b2SDaniel Vetter void drm_mode_object_put(struct drm_device *dev, 336f453ba04SDave Airlie struct drm_mode_object *object) 337f453ba04SDave Airlie { 338ad2563c2SJesse Barnes mutex_lock(&dev->mode_config.idr_mutex); 339f453ba04SDave Airlie idr_remove(&dev->mode_config.crtc_idr, object->id); 340ad2563c2SJesse Barnes mutex_unlock(&dev->mode_config.idr_mutex); 341f453ba04SDave Airlie } 342f453ba04SDave Airlie 34398f75de4SRob Clark static struct drm_mode_object *_object_find(struct drm_device *dev, 34498f75de4SRob Clark uint32_t id, uint32_t type) 34598f75de4SRob Clark { 34698f75de4SRob Clark struct drm_mode_object *obj = NULL; 34798f75de4SRob Clark 34898f75de4SRob Clark mutex_lock(&dev->mode_config.idr_mutex); 34998f75de4SRob Clark obj = idr_find(&dev->mode_config.crtc_idr, id); 350168c02ecSDaniel Vetter if (obj && type != DRM_MODE_OBJECT_ANY && obj->type != type) 351168c02ecSDaniel Vetter obj = NULL; 352168c02ecSDaniel Vetter if (obj && obj->id != id) 353168c02ecSDaniel Vetter obj = NULL; 354168c02ecSDaniel Vetter /* don't leak out unref'd fb's */ 3556bcacf51SDaniel Stone if (obj && 3566bcacf51SDaniel Stone (obj->type == DRM_MODE_OBJECT_FB || 3576bcacf51SDaniel Stone obj->type == DRM_MODE_OBJECT_BLOB)) 35898f75de4SRob Clark obj = NULL; 35998f75de4SRob Clark mutex_unlock(&dev->mode_config.idr_mutex); 36098f75de4SRob Clark 36198f75de4SRob Clark return obj; 36298f75de4SRob Clark } 36398f75de4SRob Clark 364786b99edSDaniel Vetter /** 365786b99edSDaniel Vetter * drm_mode_object_find - look up a drm object with static lifetime 366786b99edSDaniel Vetter * @dev: drm device 367786b99edSDaniel Vetter * @id: id of the mode object 368786b99edSDaniel Vetter * @type: type of the mode object 369786b99edSDaniel Vetter * 370786b99edSDaniel Vetter * Note that framebuffers cannot be looked up with this functions - since those 37198f75de4SRob Clark * are reference counted, they need special treatment. Even with 37298f75de4SRob Clark * DRM_MODE_OBJECT_ANY (although that will simply return NULL 37398f75de4SRob Clark * rather than WARN_ON()). 374786b99edSDaniel Vetter */ 3757a9c9060SDaniel Vetter struct drm_mode_object *drm_mode_object_find(struct drm_device *dev, 3767a9c9060SDaniel Vetter uint32_t id, uint32_t type) 377f453ba04SDave Airlie { 378ad2563c2SJesse Barnes struct drm_mode_object *obj = NULL; 379f453ba04SDave Airlie 380786b99edSDaniel Vetter /* Framebuffers are reference counted and need their own lookup 381786b99edSDaniel Vetter * function.*/ 3826bcacf51SDaniel Stone WARN_ON(type == DRM_MODE_OBJECT_FB || type == DRM_MODE_OBJECT_BLOB); 38398f75de4SRob Clark obj = _object_find(dev, id, type); 384f453ba04SDave Airlie return obj; 385f453ba04SDave Airlie } 386f453ba04SDave Airlie EXPORT_SYMBOL(drm_mode_object_find); 387f453ba04SDave Airlie 388f453ba04SDave Airlie /** 389f453ba04SDave Airlie * drm_framebuffer_init - initialize a framebuffer 390f453ba04SDave Airlie * @dev: DRM device 391065a50edSDaniel Vetter * @fb: framebuffer to be initialized 392065a50edSDaniel Vetter * @funcs: ... with these functions 393f453ba04SDave Airlie * 394f453ba04SDave Airlie * Allocates an ID for the framebuffer's parent mode object, sets its mode 395f453ba04SDave Airlie * functions & device file and adds it to the master fd list. 396f453ba04SDave Airlie * 3974b096ac1SDaniel Vetter * IMPORTANT: 3984b096ac1SDaniel Vetter * This functions publishes the fb and makes it available for concurrent access 3994b096ac1SDaniel Vetter * by other users. Which means by this point the fb _must_ be fully set up - 4004b096ac1SDaniel Vetter * since all the fb attributes are invariant over its lifetime, no further 4014b096ac1SDaniel Vetter * locking but only correct reference counting is required. 4024b096ac1SDaniel Vetter * 403c8e32cc1SDaniel Vetter * Returns: 404af901ca1SAndré Goddard Rosa * Zero on success, error code on failure. 405f453ba04SDave Airlie */ 406f453ba04SDave Airlie int drm_framebuffer_init(struct drm_device *dev, struct drm_framebuffer *fb, 407f453ba04SDave Airlie const struct drm_framebuffer_funcs *funcs) 408f453ba04SDave Airlie { 409f453ba04SDave Airlie int ret; 410f453ba04SDave Airlie 4114b096ac1SDaniel Vetter mutex_lock(&dev->mode_config.fb_lock); 412f7eff60eSRob Clark kref_init(&fb->refcount); 4134b096ac1SDaniel Vetter INIT_LIST_HEAD(&fb->filp_head); 4144b096ac1SDaniel Vetter fb->dev = dev; 4154b096ac1SDaniel Vetter fb->funcs = funcs; 416f7eff60eSRob Clark 417f453ba04SDave Airlie ret = drm_mode_object_get(dev, &fb->base, DRM_MODE_OBJECT_FB); 4186bfc56aaSVille Syrjälä if (ret) 4194b096ac1SDaniel Vetter goto out; 420f453ba04SDave Airlie 421f453ba04SDave Airlie dev->mode_config.num_fb++; 422f453ba04SDave Airlie list_add(&fb->head, &dev->mode_config.fb_list); 4234b096ac1SDaniel Vetter out: 4244b096ac1SDaniel Vetter mutex_unlock(&dev->mode_config.fb_lock); 425f453ba04SDave Airlie 426f453ba04SDave Airlie return 0; 427f453ba04SDave Airlie } 428f453ba04SDave Airlie EXPORT_SYMBOL(drm_framebuffer_init); 429f453ba04SDave Airlie 43083f45fc3SDaniel Vetter /* dev->mode_config.fb_lock must be held! */ 43183f45fc3SDaniel Vetter static void __drm_framebuffer_unregister(struct drm_device *dev, 43283f45fc3SDaniel Vetter struct drm_framebuffer *fb) 43383f45fc3SDaniel Vetter { 43483f45fc3SDaniel Vetter mutex_lock(&dev->mode_config.idr_mutex); 43583f45fc3SDaniel Vetter idr_remove(&dev->mode_config.crtc_idr, fb->base.id); 43683f45fc3SDaniel Vetter mutex_unlock(&dev->mode_config.idr_mutex); 43783f45fc3SDaniel Vetter 43883f45fc3SDaniel Vetter fb->base.id = 0; 43983f45fc3SDaniel Vetter } 44083f45fc3SDaniel Vetter 441f7eff60eSRob Clark static void drm_framebuffer_free(struct kref *kref) 442f7eff60eSRob Clark { 443f7eff60eSRob Clark struct drm_framebuffer *fb = 444f7eff60eSRob Clark container_of(kref, struct drm_framebuffer, refcount); 44583f45fc3SDaniel Vetter struct drm_device *dev = fb->dev; 44683f45fc3SDaniel Vetter 44783f45fc3SDaniel Vetter /* 44883f45fc3SDaniel Vetter * The lookup idr holds a weak reference, which has not necessarily been 44983f45fc3SDaniel Vetter * removed at this point. Check for that. 45083f45fc3SDaniel Vetter */ 45183f45fc3SDaniel Vetter mutex_lock(&dev->mode_config.fb_lock); 45283f45fc3SDaniel Vetter if (fb->base.id) { 45383f45fc3SDaniel Vetter /* Mark fb as reaped and drop idr ref. */ 45483f45fc3SDaniel Vetter __drm_framebuffer_unregister(dev, fb); 45583f45fc3SDaniel Vetter } 45683f45fc3SDaniel Vetter mutex_unlock(&dev->mode_config.fb_lock); 45783f45fc3SDaniel Vetter 458f7eff60eSRob Clark fb->funcs->destroy(fb); 459f7eff60eSRob Clark } 460f7eff60eSRob Clark 4612b677e8cSDaniel Vetter static struct drm_framebuffer *__drm_framebuffer_lookup(struct drm_device *dev, 4622b677e8cSDaniel Vetter uint32_t id) 4632b677e8cSDaniel Vetter { 4642b677e8cSDaniel Vetter struct drm_mode_object *obj = NULL; 4652b677e8cSDaniel Vetter struct drm_framebuffer *fb; 4662b677e8cSDaniel Vetter 4672b677e8cSDaniel Vetter mutex_lock(&dev->mode_config.idr_mutex); 4682b677e8cSDaniel Vetter obj = idr_find(&dev->mode_config.crtc_idr, id); 4692b677e8cSDaniel Vetter if (!obj || (obj->type != DRM_MODE_OBJECT_FB) || (obj->id != id)) 4702b677e8cSDaniel Vetter fb = NULL; 4712b677e8cSDaniel Vetter else 4722b677e8cSDaniel Vetter fb = obj_to_fb(obj); 4732b677e8cSDaniel Vetter mutex_unlock(&dev->mode_config.idr_mutex); 4742b677e8cSDaniel Vetter 4752b677e8cSDaniel Vetter return fb; 4762b677e8cSDaniel Vetter } 4772b677e8cSDaniel Vetter 478f7eff60eSRob Clark /** 479786b99edSDaniel Vetter * drm_framebuffer_lookup - look up a drm framebuffer and grab a reference 480786b99edSDaniel Vetter * @dev: drm device 481786b99edSDaniel Vetter * @id: id of the fb object 482786b99edSDaniel Vetter * 483786b99edSDaniel Vetter * If successful, this grabs an additional reference to the framebuffer - 484786b99edSDaniel Vetter * callers need to make sure to eventually unreference the returned framebuffer 485c8e32cc1SDaniel Vetter * again, using @drm_framebuffer_unreference. 486786b99edSDaniel Vetter */ 487786b99edSDaniel Vetter struct drm_framebuffer *drm_framebuffer_lookup(struct drm_device *dev, 488786b99edSDaniel Vetter uint32_t id) 489786b99edSDaniel Vetter { 490786b99edSDaniel Vetter struct drm_framebuffer *fb; 491786b99edSDaniel Vetter 492786b99edSDaniel Vetter mutex_lock(&dev->mode_config.fb_lock); 4932b677e8cSDaniel Vetter fb = __drm_framebuffer_lookup(dev, id); 49483f45fc3SDaniel Vetter if (fb) { 49583f45fc3SDaniel Vetter if (!kref_get_unless_zero(&fb->refcount)) 49683f45fc3SDaniel Vetter fb = NULL; 49783f45fc3SDaniel Vetter } 498786b99edSDaniel Vetter mutex_unlock(&dev->mode_config.fb_lock); 499786b99edSDaniel Vetter 500786b99edSDaniel Vetter return fb; 501786b99edSDaniel Vetter } 502786b99edSDaniel Vetter EXPORT_SYMBOL(drm_framebuffer_lookup); 503786b99edSDaniel Vetter 504786b99edSDaniel Vetter /** 505f7eff60eSRob Clark * drm_framebuffer_unreference - unref a framebuffer 506065a50edSDaniel Vetter * @fb: framebuffer to unref 507065a50edSDaniel Vetter * 508065a50edSDaniel Vetter * This functions decrements the fb's refcount and frees it if it drops to zero. 509f7eff60eSRob Clark */ 510f7eff60eSRob Clark void drm_framebuffer_unreference(struct drm_framebuffer *fb) 511f7eff60eSRob Clark { 5128291272aSRob Clark DRM_DEBUG("%p: FB ID: %d (%d)\n", fb, fb->base.id, atomic_read(&fb->refcount.refcount)); 513f7eff60eSRob Clark kref_put(&fb->refcount, drm_framebuffer_free); 514f7eff60eSRob Clark } 515f7eff60eSRob Clark EXPORT_SYMBOL(drm_framebuffer_unreference); 516f7eff60eSRob Clark 517f7eff60eSRob Clark /** 518f7eff60eSRob Clark * drm_framebuffer_reference - incr the fb refcnt 519065a50edSDaniel Vetter * @fb: framebuffer 520c8e32cc1SDaniel Vetter * 521c8e32cc1SDaniel Vetter * This functions increments the fb's refcount. 522f7eff60eSRob Clark */ 523f7eff60eSRob Clark void drm_framebuffer_reference(struct drm_framebuffer *fb) 524f7eff60eSRob Clark { 5258291272aSRob Clark DRM_DEBUG("%p: FB ID: %d (%d)\n", fb, fb->base.id, atomic_read(&fb->refcount.refcount)); 526f7eff60eSRob Clark kref_get(&fb->refcount); 527f7eff60eSRob Clark } 528f7eff60eSRob Clark EXPORT_SYMBOL(drm_framebuffer_reference); 529f7eff60eSRob Clark 530f453ba04SDave Airlie /** 53136206361SDaniel Vetter * drm_framebuffer_unregister_private - unregister a private fb from the lookup idr 53236206361SDaniel Vetter * @fb: fb to unregister 53336206361SDaniel Vetter * 53436206361SDaniel Vetter * Drivers need to call this when cleaning up driver-private framebuffers, e.g. 53536206361SDaniel Vetter * those used for fbdev. Note that the caller must hold a reference of it's own, 53636206361SDaniel Vetter * i.e. the object may not be destroyed through this call (since it'll lead to a 53736206361SDaniel Vetter * locking inversion). 53836206361SDaniel Vetter */ 53936206361SDaniel Vetter void drm_framebuffer_unregister_private(struct drm_framebuffer *fb) 54036206361SDaniel Vetter { 5412b677e8cSDaniel Vetter struct drm_device *dev = fb->dev; 5422b677e8cSDaniel Vetter 5432b677e8cSDaniel Vetter mutex_lock(&dev->mode_config.fb_lock); 5442b677e8cSDaniel Vetter /* Mark fb as reaped and drop idr ref. */ 5452b677e8cSDaniel Vetter __drm_framebuffer_unregister(dev, fb); 5462b677e8cSDaniel Vetter mutex_unlock(&dev->mode_config.fb_lock); 54736206361SDaniel Vetter } 54836206361SDaniel Vetter EXPORT_SYMBOL(drm_framebuffer_unregister_private); 54936206361SDaniel Vetter 55036206361SDaniel Vetter /** 551f453ba04SDave Airlie * drm_framebuffer_cleanup - remove a framebuffer object 552f453ba04SDave Airlie * @fb: framebuffer to remove 553f453ba04SDave Airlie * 554c8e32cc1SDaniel Vetter * Cleanup framebuffer. This function is intended to be used from the drivers 555c8e32cc1SDaniel Vetter * ->destroy callback. It can also be used to clean up driver private 556c8e32cc1SDaniel Vetter * framebuffers embedded into a larger structure. 55736206361SDaniel Vetter * 55836206361SDaniel Vetter * Note that this function does not remove the fb from active usuage - if it is 55936206361SDaniel Vetter * still used anywhere, hilarity can ensue since userspace could call getfb on 56036206361SDaniel Vetter * the id and get back -EINVAL. Obviously no concern at driver unload time. 56136206361SDaniel Vetter * 56236206361SDaniel Vetter * Also, the framebuffer will not be removed from the lookup idr - for 56336206361SDaniel Vetter * user-created framebuffers this will happen in in the rmfb ioctl. For 56436206361SDaniel Vetter * driver-private objects (e.g. for fbdev) drivers need to explicitly call 56536206361SDaniel Vetter * drm_framebuffer_unregister_private. 566f453ba04SDave Airlie */ 567f453ba04SDave Airlie void drm_framebuffer_cleanup(struct drm_framebuffer *fb) 568f453ba04SDave Airlie { 569f453ba04SDave Airlie struct drm_device *dev = fb->dev; 5708faf6b18SDaniel Vetter 5714b096ac1SDaniel Vetter mutex_lock(&dev->mode_config.fb_lock); 572f7eff60eSRob Clark list_del(&fb->head); 573f7eff60eSRob Clark dev->mode_config.num_fb--; 5744b096ac1SDaniel Vetter mutex_unlock(&dev->mode_config.fb_lock); 575f7eff60eSRob Clark } 576f7eff60eSRob Clark EXPORT_SYMBOL(drm_framebuffer_cleanup); 577f7eff60eSRob Clark 578f7eff60eSRob Clark /** 579f7eff60eSRob Clark * drm_framebuffer_remove - remove and unreference a framebuffer object 580f7eff60eSRob Clark * @fb: framebuffer to remove 581f7eff60eSRob Clark * 582f7eff60eSRob Clark * Scans all the CRTCs and planes in @dev's mode_config. If they're 58336206361SDaniel Vetter * using @fb, removes it, setting it to NULL. Then drops the reference to the 584b62584e3SDaniel Vetter * passed-in framebuffer. Might take the modeset locks. 585b62584e3SDaniel Vetter * 586b62584e3SDaniel Vetter * Note that this function optimizes the cleanup away if the caller holds the 587b62584e3SDaniel Vetter * last reference to the framebuffer. It is also guaranteed to not take the 588b62584e3SDaniel Vetter * modeset locks in this case. 589f7eff60eSRob Clark */ 590f7eff60eSRob Clark void drm_framebuffer_remove(struct drm_framebuffer *fb) 591f7eff60eSRob Clark { 592f7eff60eSRob Clark struct drm_device *dev = fb->dev; 593f453ba04SDave Airlie struct drm_crtc *crtc; 5948cf5c917SJesse Barnes struct drm_plane *plane; 5955ef5f72fSDave Airlie struct drm_mode_set set; 5965ef5f72fSDave Airlie int ret; 597f453ba04SDave Airlie 5984b096ac1SDaniel Vetter WARN_ON(!list_empty(&fb->filp_head)); 5998faf6b18SDaniel Vetter 600b62584e3SDaniel Vetter /* 601b62584e3SDaniel Vetter * drm ABI mandates that we remove any deleted framebuffers from active 602b62584e3SDaniel Vetter * useage. But since most sane clients only remove framebuffers they no 603b62584e3SDaniel Vetter * longer need, try to optimize this away. 604b62584e3SDaniel Vetter * 605b62584e3SDaniel Vetter * Since we're holding a reference ourselves, observing a refcount of 1 606b62584e3SDaniel Vetter * means that we're the last holder and can skip it. Also, the refcount 607b62584e3SDaniel Vetter * can never increase from 1 again, so we don't need any barriers or 608b62584e3SDaniel Vetter * locks. 609b62584e3SDaniel Vetter * 610b62584e3SDaniel Vetter * Note that userspace could try to race with use and instate a new 611b62584e3SDaniel Vetter * usage _after_ we've cleared all current ones. End result will be an 612b62584e3SDaniel Vetter * in-use fb with fb-id == 0. Userspace is allowed to shoot its own foot 613b62584e3SDaniel Vetter * in this manner. 614b62584e3SDaniel Vetter */ 615b62584e3SDaniel Vetter if (atomic_read(&fb->refcount.refcount) > 1) { 616b62584e3SDaniel Vetter drm_modeset_lock_all(dev); 617f453ba04SDave Airlie /* remove from any CRTC */ 618f453ba04SDave Airlie list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { 619f4510a27SMatt Roper if (crtc->primary->fb == fb) { 6205ef5f72fSDave Airlie /* should turn off the crtc */ 6215ef5f72fSDave Airlie memset(&set, 0, sizeof(struct drm_mode_set)); 6225ef5f72fSDave Airlie set.crtc = crtc; 6235ef5f72fSDave Airlie set.fb = NULL; 6242d13b679SDaniel Vetter ret = drm_mode_set_config_internal(&set); 6255ef5f72fSDave Airlie if (ret) 6265ef5f72fSDave Airlie DRM_ERROR("failed to reset crtc %p when fb was deleted\n", crtc); 6275ef5f72fSDave Airlie } 628f453ba04SDave Airlie } 629f453ba04SDave Airlie 6308cf5c917SJesse Barnes list_for_each_entry(plane, &dev->mode_config.plane_list, head) { 6319125e618SVille Syrjälä if (plane->fb == fb) 6329125e618SVille Syrjälä drm_plane_force_disable(plane); 6338cf5c917SJesse Barnes } 634b62584e3SDaniel Vetter drm_modeset_unlock_all(dev); 635b62584e3SDaniel Vetter } 6368cf5c917SJesse Barnes 637f7eff60eSRob Clark drm_framebuffer_unreference(fb); 638f453ba04SDave Airlie } 639f7eff60eSRob Clark EXPORT_SYMBOL(drm_framebuffer_remove); 640f453ba04SDave Airlie 64151fd371bSRob Clark DEFINE_WW_CLASS(crtc_ww_class); 64251fd371bSRob Clark 643f453ba04SDave Airlie /** 644e13161afSMatt Roper * drm_crtc_init_with_planes - Initialise a new CRTC object with 645e13161afSMatt Roper * specified primary and cursor planes. 646f453ba04SDave Airlie * @dev: DRM device 647f453ba04SDave Airlie * @crtc: CRTC object to init 648e13161afSMatt Roper * @primary: Primary plane for CRTC 649e13161afSMatt Roper * @cursor: Cursor plane for CRTC 650f453ba04SDave Airlie * @funcs: callbacks for the new CRTC 651f453ba04SDave Airlie * 652ad6f5c34SVille Syrjälä * Inits a new object created as base part of a driver crtc object. 6536bfc56aaSVille Syrjälä * 654c8e32cc1SDaniel Vetter * Returns: 6556bfc56aaSVille Syrjälä * Zero on success, error code on failure. 656f453ba04SDave Airlie */ 657e13161afSMatt Roper int drm_crtc_init_with_planes(struct drm_device *dev, struct drm_crtc *crtc, 658e13161afSMatt Roper struct drm_plane *primary, 659fc1d3e44SMatt Roper struct drm_plane *cursor, 660f453ba04SDave Airlie const struct drm_crtc_funcs *funcs) 661f453ba04SDave Airlie { 66251fd371bSRob Clark struct drm_mode_config *config = &dev->mode_config; 6636bfc56aaSVille Syrjälä int ret; 6646bfc56aaSVille Syrjälä 665522cf91fSBenjamin Gaignard WARN_ON(primary && primary->type != DRM_PLANE_TYPE_PRIMARY); 666522cf91fSBenjamin Gaignard WARN_ON(cursor && cursor->type != DRM_PLANE_TYPE_CURSOR); 667522cf91fSBenjamin Gaignard 668f453ba04SDave Airlie crtc->dev = dev; 669f453ba04SDave Airlie crtc->funcs = funcs; 6707c80e128SRob Clark crtc->invert_dimensions = false; 671f453ba04SDave Airlie 67251fd371bSRob Clark drm_modeset_lock_init(&crtc->mutex); 6736bfc56aaSVille Syrjälä ret = drm_mode_object_get(dev, &crtc->base, DRM_MODE_OBJECT_CRTC); 6746bfc56aaSVille Syrjälä if (ret) 675baf698b0SDaniel Vetter return ret; 676f453ba04SDave Airlie 677bffd9de0SPaulo Zanoni crtc->base.properties = &crtc->properties; 678bffd9de0SPaulo Zanoni 67951fd371bSRob Clark list_add_tail(&crtc->head, &config->crtc_list); 68051fd371bSRob Clark config->num_crtc++; 6816bfc56aaSVille Syrjälä 682e13161afSMatt Roper crtc->primary = primary; 683fc1d3e44SMatt Roper crtc->cursor = cursor; 684e13161afSMatt Roper if (primary) 685e13161afSMatt Roper primary->possible_crtcs = 1 << drm_crtc_index(crtc); 686fc1d3e44SMatt Roper if (cursor) 687fc1d3e44SMatt Roper cursor->possible_crtcs = 1 << drm_crtc_index(crtc); 688e13161afSMatt Roper 689eab3bbefSDaniel Vetter if (drm_core_check_feature(dev, DRIVER_ATOMIC)) { 690eab3bbefSDaniel Vetter drm_object_attach_property(&crtc->base, config->prop_active, 0); 691955f3c33SDaniel Stone drm_object_attach_property(&crtc->base, config->prop_mode_id, 0); 692eab3bbefSDaniel Vetter } 693eab3bbefSDaniel Vetter 694baf698b0SDaniel Vetter return 0; 695f453ba04SDave Airlie } 696e13161afSMatt Roper EXPORT_SYMBOL(drm_crtc_init_with_planes); 697f453ba04SDave Airlie 698f453ba04SDave Airlie /** 699ad6f5c34SVille Syrjälä * drm_crtc_cleanup - Clean up the core crtc usage 700f453ba04SDave Airlie * @crtc: CRTC to cleanup 701f453ba04SDave Airlie * 702ad6f5c34SVille Syrjälä * This function cleans up @crtc and removes it from the DRM mode setting 703ad6f5c34SVille Syrjälä * core. Note that the function does *not* free the crtc structure itself, 704ad6f5c34SVille Syrjälä * this is the responsibility of the caller. 705f453ba04SDave Airlie */ 706f453ba04SDave Airlie void drm_crtc_cleanup(struct drm_crtc *crtc) 707f453ba04SDave Airlie { 708f453ba04SDave Airlie struct drm_device *dev = crtc->dev; 709f453ba04SDave Airlie 710f453ba04SDave Airlie kfree(crtc->gamma_store); 711f453ba04SDave Airlie crtc->gamma_store = NULL; 712f453ba04SDave Airlie 71351fd371bSRob Clark drm_modeset_lock_fini(&crtc->mutex); 71451fd371bSRob Clark 715f453ba04SDave Airlie drm_mode_object_put(dev, &crtc->base); 716f453ba04SDave Airlie list_del(&crtc->head); 717f453ba04SDave Airlie dev->mode_config.num_crtc--; 7183009c037SThierry Reding 7193009c037SThierry Reding WARN_ON(crtc->state && !crtc->funcs->atomic_destroy_state); 7203009c037SThierry Reding if (crtc->state && crtc->funcs->atomic_destroy_state) 7213009c037SThierry Reding crtc->funcs->atomic_destroy_state(crtc, crtc->state); 722a18c0af1SThierry Reding 723a18c0af1SThierry Reding memset(crtc, 0, sizeof(*crtc)); 724f453ba04SDave Airlie } 725f453ba04SDave Airlie EXPORT_SYMBOL(drm_crtc_cleanup); 726f453ba04SDave Airlie 727f453ba04SDave Airlie /** 728db5f7a6eSRussell King * drm_crtc_index - find the index of a registered CRTC 729db5f7a6eSRussell King * @crtc: CRTC to find index for 730db5f7a6eSRussell King * 731db5f7a6eSRussell King * Given a registered CRTC, return the index of that CRTC within a DRM 732db5f7a6eSRussell King * device's list of CRTCs. 733db5f7a6eSRussell King */ 734db5f7a6eSRussell King unsigned int drm_crtc_index(struct drm_crtc *crtc) 735db5f7a6eSRussell King { 736db5f7a6eSRussell King unsigned int index = 0; 737db5f7a6eSRussell King struct drm_crtc *tmp; 738db5f7a6eSRussell King 739db5f7a6eSRussell King list_for_each_entry(tmp, &crtc->dev->mode_config.crtc_list, head) { 740db5f7a6eSRussell King if (tmp == crtc) 741db5f7a6eSRussell King return index; 742db5f7a6eSRussell King 743db5f7a6eSRussell King index++; 744db5f7a6eSRussell King } 745db5f7a6eSRussell King 746db5f7a6eSRussell King BUG(); 747db5f7a6eSRussell King } 748db5f7a6eSRussell King EXPORT_SYMBOL(drm_crtc_index); 749db5f7a6eSRussell King 75086f422d5SLespiau, Damien /* 751f453ba04SDave Airlie * drm_mode_remove - remove and free a mode 752f453ba04SDave Airlie * @connector: connector list to modify 753f453ba04SDave Airlie * @mode: mode to remove 754f453ba04SDave Airlie * 755f453ba04SDave Airlie * Remove @mode from @connector's mode list, then free it. 756f453ba04SDave Airlie */ 75786f422d5SLespiau, Damien static void drm_mode_remove(struct drm_connector *connector, 758f453ba04SDave Airlie struct drm_display_mode *mode) 759f453ba04SDave Airlie { 760f453ba04SDave Airlie list_del(&mode->head); 761554f1d78SSascha Hauer drm_mode_destroy(connector->dev, mode); 762f453ba04SDave Airlie } 763f453ba04SDave Airlie 764f453ba04SDave Airlie /** 765b5571e9dSBoris Brezillon * drm_display_info_set_bus_formats - set the supported bus formats 766b5571e9dSBoris Brezillon * @info: display info to store bus formats in 767e37bfa1aSBoris Brezillon * @formats: array containing the supported bus formats 768e37bfa1aSBoris Brezillon * @num_formats: the number of entries in the fmts array 769b5571e9dSBoris Brezillon * 770b5571e9dSBoris Brezillon * Store the supported bus formats in display info structure. 771b5571e9dSBoris Brezillon * See MEDIA_BUS_FMT_* definitions in include/uapi/linux/media-bus-format.h for 772b5571e9dSBoris Brezillon * a full list of available formats. 773b5571e9dSBoris Brezillon */ 774b5571e9dSBoris Brezillon int drm_display_info_set_bus_formats(struct drm_display_info *info, 775b5571e9dSBoris Brezillon const u32 *formats, 776b5571e9dSBoris Brezillon unsigned int num_formats) 777b5571e9dSBoris Brezillon { 778b5571e9dSBoris Brezillon u32 *fmts = NULL; 779b5571e9dSBoris Brezillon 780b5571e9dSBoris Brezillon if (!formats && num_formats) 781b5571e9dSBoris Brezillon return -EINVAL; 782b5571e9dSBoris Brezillon 783b5571e9dSBoris Brezillon if (formats && num_formats) { 784b5571e9dSBoris Brezillon fmts = kmemdup(formats, sizeof(*formats) * num_formats, 785b5571e9dSBoris Brezillon GFP_KERNEL); 786944579c5SDan Carpenter if (!fmts) 787b5571e9dSBoris Brezillon return -ENOMEM; 788b5571e9dSBoris Brezillon } 789b5571e9dSBoris Brezillon 790b5571e9dSBoris Brezillon kfree(info->bus_formats); 791b5571e9dSBoris Brezillon info->bus_formats = fmts; 792b5571e9dSBoris Brezillon info->num_bus_formats = num_formats; 793b5571e9dSBoris Brezillon 794b5571e9dSBoris Brezillon return 0; 795b5571e9dSBoris Brezillon } 796b5571e9dSBoris Brezillon EXPORT_SYMBOL(drm_display_info_set_bus_formats); 797b5571e9dSBoris Brezillon 798b5571e9dSBoris Brezillon /** 799eaf99c74SChris Wilson * drm_connector_get_cmdline_mode - reads the user's cmdline mode 800eaf99c74SChris Wilson * @connector: connector to quwery 801eaf99c74SChris Wilson * 802eaf99c74SChris Wilson * The kernel supports per-connector configration of its consoles through 803eaf99c74SChris Wilson * use of the video= parameter. This function parses that option and 804eaf99c74SChris Wilson * extracts the user's specified mode (or enable/disable status) for a 805eaf99c74SChris Wilson * particular connector. This is typically only used during the early fbdev 806eaf99c74SChris Wilson * setup. 807eaf99c74SChris Wilson */ 808eaf99c74SChris Wilson static void drm_connector_get_cmdline_mode(struct drm_connector *connector) 809eaf99c74SChris Wilson { 810eaf99c74SChris Wilson struct drm_cmdline_mode *mode = &connector->cmdline_mode; 811eaf99c74SChris Wilson char *option = NULL; 812eaf99c74SChris Wilson 813eaf99c74SChris Wilson if (fb_get_options(connector->name, &option)) 814eaf99c74SChris Wilson return; 815eaf99c74SChris Wilson 816eaf99c74SChris Wilson if (!drm_mode_parse_command_line_for_connector(option, 817eaf99c74SChris Wilson connector, 818eaf99c74SChris Wilson mode)) 819eaf99c74SChris Wilson return; 820eaf99c74SChris Wilson 821eaf99c74SChris Wilson if (mode->force) { 822eaf99c74SChris Wilson const char *s; 823eaf99c74SChris Wilson 824eaf99c74SChris Wilson switch (mode->force) { 825eaf99c74SChris Wilson case DRM_FORCE_OFF: 826eaf99c74SChris Wilson s = "OFF"; 827eaf99c74SChris Wilson break; 828eaf99c74SChris Wilson case DRM_FORCE_ON_DIGITAL: 829eaf99c74SChris Wilson s = "ON - dig"; 830eaf99c74SChris Wilson break; 831eaf99c74SChris Wilson default: 832eaf99c74SChris Wilson case DRM_FORCE_ON: 833eaf99c74SChris Wilson s = "ON"; 834eaf99c74SChris Wilson break; 835eaf99c74SChris Wilson } 836eaf99c74SChris Wilson 837eaf99c74SChris Wilson DRM_INFO("forcing %s connector %s\n", connector->name, s); 838eaf99c74SChris Wilson connector->force = mode->force; 839eaf99c74SChris Wilson } 840eaf99c74SChris Wilson 841eaf99c74SChris Wilson DRM_DEBUG_KMS("cmdline mode for connector %s %dx%d@%dHz%s%s%s\n", 842eaf99c74SChris Wilson connector->name, 843eaf99c74SChris Wilson mode->xres, mode->yres, 844eaf99c74SChris Wilson mode->refresh_specified ? mode->refresh : 60, 845eaf99c74SChris Wilson mode->rb ? " reduced blanking" : "", 846eaf99c74SChris Wilson mode->margins ? " with margins" : "", 847eaf99c74SChris Wilson mode->interlace ? " interlaced" : ""); 848eaf99c74SChris Wilson } 849eaf99c74SChris Wilson 850eaf99c74SChris Wilson /** 851f453ba04SDave Airlie * drm_connector_init - Init a preallocated connector 852f453ba04SDave Airlie * @dev: DRM device 853f453ba04SDave Airlie * @connector: the connector to init 854f453ba04SDave Airlie * @funcs: callbacks for this connector 855065a50edSDaniel Vetter * @connector_type: user visible type of the connector 856f453ba04SDave Airlie * 857f453ba04SDave Airlie * Initialises a preallocated connector. Connectors should be 858f453ba04SDave Airlie * subclassed as part of driver connector objects. 8596bfc56aaSVille Syrjälä * 860c8e32cc1SDaniel Vetter * Returns: 8616bfc56aaSVille Syrjälä * Zero on success, error code on failure. 862f453ba04SDave Airlie */ 8636bfc56aaSVille Syrjälä int drm_connector_init(struct drm_device *dev, 864f453ba04SDave Airlie struct drm_connector *connector, 865f453ba04SDave Airlie const struct drm_connector_funcs *funcs, 866f453ba04SDave Airlie int connector_type) 867f453ba04SDave Airlie { 868ae16c597SRob Clark struct drm_mode_config *config = &dev->mode_config; 8696bfc56aaSVille Syrjälä int ret; 870b21e3afeSIlia Mirkin struct ida *connector_ida = 871b21e3afeSIlia Mirkin &drm_connector_enum_list[connector_type].ida; 8726bfc56aaSVille Syrjälä 87384849903SDaniel Vetter drm_modeset_lock_all(dev); 874f453ba04SDave Airlie 8752ee39452SDave Airlie ret = drm_mode_object_get_reg(dev, &connector->base, DRM_MODE_OBJECT_CONNECTOR, false); 8766bfc56aaSVille Syrjälä if (ret) 8772abdd313SJani Nikula goto out_unlock; 8786bfc56aaSVille Syrjälä 8797e3bdf4aSPaulo Zanoni connector->base.properties = &connector->properties; 880f453ba04SDave Airlie connector->dev = dev; 881f453ba04SDave Airlie connector->funcs = funcs; 882f453ba04SDave Airlie connector->connector_type = connector_type; 883f453ba04SDave Airlie connector->connector_type_id = 884b21e3afeSIlia Mirkin ida_simple_get(connector_ida, 1, 0, GFP_KERNEL); 885b21e3afeSIlia Mirkin if (connector->connector_type_id < 0) { 886b21e3afeSIlia Mirkin ret = connector->connector_type_id; 8872abdd313SJani Nikula goto out_put; 888b21e3afeSIlia Mirkin } 8892abdd313SJani Nikula connector->name = 8902abdd313SJani Nikula kasprintf(GFP_KERNEL, "%s-%d", 8912abdd313SJani Nikula drm_connector_enum_list[connector_type].name, 8922abdd313SJani Nikula connector->connector_type_id); 8932abdd313SJani Nikula if (!connector->name) { 8942abdd313SJani Nikula ret = -ENOMEM; 8952abdd313SJani Nikula goto out_put; 8962abdd313SJani Nikula } 8972abdd313SJani Nikula 898f453ba04SDave Airlie INIT_LIST_HEAD(&connector->probed_modes); 899f453ba04SDave Airlie INIT_LIST_HEAD(&connector->modes); 900f453ba04SDave Airlie connector->edid_blob_ptr = NULL; 9015e2cb2f6SDaniel Vetter connector->status = connector_status_unknown; 902f453ba04SDave Airlie 903eaf99c74SChris Wilson drm_connector_get_cmdline_mode(connector); 904eaf99c74SChris Wilson 905c7eb76f4SDaniel Vetter /* We should add connectors at the end to avoid upsetting the connector 906c7eb76f4SDaniel Vetter * index too much. */ 907ae16c597SRob Clark list_add_tail(&connector->head, &config->connector_list); 908ae16c597SRob Clark config->num_connector++; 909f453ba04SDave Airlie 910a7331e5cSThomas Hellstrom if (connector_type != DRM_MODE_CONNECTOR_VIRTUAL) 91158495563SRob Clark drm_object_attach_property(&connector->base, 912ae16c597SRob Clark config->edid_property, 913a7331e5cSThomas Hellstrom 0); 914f453ba04SDave Airlie 91558495563SRob Clark drm_object_attach_property(&connector->base, 916ae16c597SRob Clark config->dpms_property, 0); 917ae16c597SRob Clark 918ae16c597SRob Clark if (drm_core_check_feature(dev, DRIVER_ATOMIC)) { 919ae16c597SRob Clark drm_object_attach_property(&connector->base, config->prop_crtc_id, 0); 920ae16c597SRob Clark } 921f453ba04SDave Airlie 92230f65707SThomas Wood connector->debugfs_entry = NULL; 92330f65707SThomas Wood 9242abdd313SJani Nikula out_put: 9252abdd313SJani Nikula if (ret) 9262abdd313SJani Nikula drm_mode_object_put(dev, &connector->base); 9272abdd313SJani Nikula 9282abdd313SJani Nikula out_unlock: 92984849903SDaniel Vetter drm_modeset_unlock_all(dev); 9306bfc56aaSVille Syrjälä 9316bfc56aaSVille Syrjälä return ret; 932f453ba04SDave Airlie } 933f453ba04SDave Airlie EXPORT_SYMBOL(drm_connector_init); 934f453ba04SDave Airlie 935f453ba04SDave Airlie /** 936f453ba04SDave Airlie * drm_connector_cleanup - cleans up an initialised connector 937f453ba04SDave Airlie * @connector: connector to cleanup 938f453ba04SDave Airlie * 939f453ba04SDave Airlie * Cleans up the connector but doesn't free the object. 940f453ba04SDave Airlie */ 941f453ba04SDave Airlie void drm_connector_cleanup(struct drm_connector *connector) 942f453ba04SDave Airlie { 943f453ba04SDave Airlie struct drm_device *dev = connector->dev; 944f453ba04SDave Airlie struct drm_display_mode *mode, *t; 945f453ba04SDave Airlie 94640d9b043SDave Airlie if (connector->tile_group) { 94740d9b043SDave Airlie drm_mode_put_tile_group(dev, connector->tile_group); 94840d9b043SDave Airlie connector->tile_group = NULL; 94940d9b043SDave Airlie } 95040d9b043SDave Airlie 951f453ba04SDave Airlie list_for_each_entry_safe(mode, t, &connector->probed_modes, head) 952f453ba04SDave Airlie drm_mode_remove(connector, mode); 953f453ba04SDave Airlie 954f453ba04SDave Airlie list_for_each_entry_safe(mode, t, &connector->modes, head) 955f453ba04SDave Airlie drm_mode_remove(connector, mode); 956f453ba04SDave Airlie 957b21e3afeSIlia Mirkin ida_remove(&drm_connector_enum_list[connector->connector_type].ida, 958b21e3afeSIlia Mirkin connector->connector_type_id); 959b21e3afeSIlia Mirkin 960b5571e9dSBoris Brezillon kfree(connector->display_info.bus_formats); 961f453ba04SDave Airlie drm_mode_object_put(dev, &connector->base); 9622abdd313SJani Nikula kfree(connector->name); 9632abdd313SJani Nikula connector->name = NULL; 964f453ba04SDave Airlie list_del(&connector->head); 9656380c509SJoonyoung Shim dev->mode_config.num_connector--; 9663009c037SThierry Reding 9673009c037SThierry Reding WARN_ON(connector->state && !connector->funcs->atomic_destroy_state); 9683009c037SThierry Reding if (connector->state && connector->funcs->atomic_destroy_state) 9693009c037SThierry Reding connector->funcs->atomic_destroy_state(connector, 9703009c037SThierry Reding connector->state); 971a18c0af1SThierry Reding 972a18c0af1SThierry Reding memset(connector, 0, sizeof(*connector)); 973f453ba04SDave Airlie } 974f453ba04SDave Airlie EXPORT_SYMBOL(drm_connector_cleanup); 975f453ba04SDave Airlie 976c8e32cc1SDaniel Vetter /** 97710f637bfSDaniel Vetter * drm_connector_index - find the index of a registered connector 97810f637bfSDaniel Vetter * @connector: connector to find index for 97910f637bfSDaniel Vetter * 98010f637bfSDaniel Vetter * Given a registered connector, return the index of that connector within a DRM 98110f637bfSDaniel Vetter * device's list of connectors. 98210f637bfSDaniel Vetter */ 98310f637bfSDaniel Vetter unsigned int drm_connector_index(struct drm_connector *connector) 98410f637bfSDaniel Vetter { 98510f637bfSDaniel Vetter unsigned int index = 0; 98610f637bfSDaniel Vetter struct drm_connector *tmp; 987c7eb76f4SDaniel Vetter struct drm_mode_config *config = &connector->dev->mode_config; 988c7eb76f4SDaniel Vetter 989c7eb76f4SDaniel Vetter WARN_ON(!drm_modeset_is_locked(&config->connection_mutex)); 99010f637bfSDaniel Vetter 99110f637bfSDaniel Vetter list_for_each_entry(tmp, &connector->dev->mode_config.connector_list, head) { 99210f637bfSDaniel Vetter if (tmp == connector) 99310f637bfSDaniel Vetter return index; 99410f637bfSDaniel Vetter 99510f637bfSDaniel Vetter index++; 99610f637bfSDaniel Vetter } 99710f637bfSDaniel Vetter 99810f637bfSDaniel Vetter BUG(); 99910f637bfSDaniel Vetter } 100010f637bfSDaniel Vetter EXPORT_SYMBOL(drm_connector_index); 100110f637bfSDaniel Vetter 100210f637bfSDaniel Vetter /** 100334ea3d38SThomas Wood * drm_connector_register - register a connector 100434ea3d38SThomas Wood * @connector: the connector to register 100534ea3d38SThomas Wood * 100634ea3d38SThomas Wood * Register userspace interfaces for a connector 100734ea3d38SThomas Wood * 100834ea3d38SThomas Wood * Returns: 100934ea3d38SThomas Wood * Zero on success, error code on failure. 101034ea3d38SThomas Wood */ 101134ea3d38SThomas Wood int drm_connector_register(struct drm_connector *connector) 101234ea3d38SThomas Wood { 101330f65707SThomas Wood int ret; 101430f65707SThomas Wood 10152ee39452SDave Airlie drm_mode_object_register(connector->dev, &connector->base); 10162ee39452SDave Airlie 101730f65707SThomas Wood ret = drm_sysfs_connector_add(connector); 101830f65707SThomas Wood if (ret) 101930f65707SThomas Wood return ret; 102030f65707SThomas Wood 102130f65707SThomas Wood ret = drm_debugfs_connector_add(connector); 102230f65707SThomas Wood if (ret) { 102330f65707SThomas Wood drm_sysfs_connector_remove(connector); 102430f65707SThomas Wood return ret; 102530f65707SThomas Wood } 102630f65707SThomas Wood 102730f65707SThomas Wood return 0; 102834ea3d38SThomas Wood } 102934ea3d38SThomas Wood EXPORT_SYMBOL(drm_connector_register); 103034ea3d38SThomas Wood 103134ea3d38SThomas Wood /** 103234ea3d38SThomas Wood * drm_connector_unregister - unregister a connector 103334ea3d38SThomas Wood * @connector: the connector to unregister 103434ea3d38SThomas Wood * 103534ea3d38SThomas Wood * Unregister userspace interfaces for a connector 103634ea3d38SThomas Wood */ 103734ea3d38SThomas Wood void drm_connector_unregister(struct drm_connector *connector) 103834ea3d38SThomas Wood { 103934ea3d38SThomas Wood drm_sysfs_connector_remove(connector); 104030f65707SThomas Wood drm_debugfs_connector_remove(connector); 104134ea3d38SThomas Wood } 104234ea3d38SThomas Wood EXPORT_SYMBOL(drm_connector_unregister); 104334ea3d38SThomas Wood 104434ea3d38SThomas Wood 104534ea3d38SThomas Wood /** 1046c8e32cc1SDaniel Vetter * drm_connector_unplug_all - unregister connector userspace interfaces 1047c8e32cc1SDaniel Vetter * @dev: drm device 1048c8e32cc1SDaniel Vetter * 1049c8e32cc1SDaniel Vetter * This function unregisters all connector userspace interfaces in sysfs. Should 1050c8e32cc1SDaniel Vetter * be call when the device is disconnected, e.g. from an usb driver's 1051c8e32cc1SDaniel Vetter * ->disconnect callback. 1052c8e32cc1SDaniel Vetter */ 1053cbc7e221SDave Airlie void drm_connector_unplug_all(struct drm_device *dev) 1054cbc7e221SDave Airlie { 1055cbc7e221SDave Airlie struct drm_connector *connector; 1056cbc7e221SDave Airlie 1057cbc7e221SDave Airlie /* taking the mode config mutex ends up in a clash with sysfs */ 1058cbc7e221SDave Airlie list_for_each_entry(connector, &dev->mode_config.connector_list, head) 105934ea3d38SThomas Wood drm_connector_unregister(connector); 1060cbc7e221SDave Airlie 1061cbc7e221SDave Airlie } 1062cbc7e221SDave Airlie EXPORT_SYMBOL(drm_connector_unplug_all); 1063cbc7e221SDave Airlie 1064c8e32cc1SDaniel Vetter /** 1065c8e32cc1SDaniel Vetter * drm_encoder_init - Init a preallocated encoder 1066c8e32cc1SDaniel Vetter * @dev: drm device 1067c8e32cc1SDaniel Vetter * @encoder: the encoder to init 1068c8e32cc1SDaniel Vetter * @funcs: callbacks for this encoder 1069c8e32cc1SDaniel Vetter * @encoder_type: user visible type of the encoder 1070c8e32cc1SDaniel Vetter * 1071c8e32cc1SDaniel Vetter * Initialises a preallocated encoder. Encoder should be 1072c8e32cc1SDaniel Vetter * subclassed as part of driver encoder objects. 1073c8e32cc1SDaniel Vetter * 1074c8e32cc1SDaniel Vetter * Returns: 1075c8e32cc1SDaniel Vetter * Zero on success, error code on failure. 1076c8e32cc1SDaniel Vetter */ 10776bfc56aaSVille Syrjälä int drm_encoder_init(struct drm_device *dev, 1078f453ba04SDave Airlie struct drm_encoder *encoder, 1079f453ba04SDave Airlie const struct drm_encoder_funcs *funcs, 1080f453ba04SDave Airlie int encoder_type) 1081f453ba04SDave Airlie { 10826bfc56aaSVille Syrjälä int ret; 10836bfc56aaSVille Syrjälä 108484849903SDaniel Vetter drm_modeset_lock_all(dev); 1085f453ba04SDave Airlie 10866bfc56aaSVille Syrjälä ret = drm_mode_object_get(dev, &encoder->base, DRM_MODE_OBJECT_ENCODER); 10876bfc56aaSVille Syrjälä if (ret) 1088e5748946SJani Nikula goto out_unlock; 1089f453ba04SDave Airlie 10906bfc56aaSVille Syrjälä encoder->dev = dev; 1091f453ba04SDave Airlie encoder->encoder_type = encoder_type; 1092f453ba04SDave Airlie encoder->funcs = funcs; 1093e5748946SJani Nikula encoder->name = kasprintf(GFP_KERNEL, "%s-%d", 1094e5748946SJani Nikula drm_encoder_enum_list[encoder_type].name, 1095e5748946SJani Nikula encoder->base.id); 1096e5748946SJani Nikula if (!encoder->name) { 1097e5748946SJani Nikula ret = -ENOMEM; 1098e5748946SJani Nikula goto out_put; 1099e5748946SJani Nikula } 1100f453ba04SDave Airlie 1101f453ba04SDave Airlie list_add_tail(&encoder->head, &dev->mode_config.encoder_list); 1102f453ba04SDave Airlie dev->mode_config.num_encoder++; 1103f453ba04SDave Airlie 1104e5748946SJani Nikula out_put: 1105e5748946SJani Nikula if (ret) 1106e5748946SJani Nikula drm_mode_object_put(dev, &encoder->base); 1107e5748946SJani Nikula 1108e5748946SJani Nikula out_unlock: 110984849903SDaniel Vetter drm_modeset_unlock_all(dev); 11106bfc56aaSVille Syrjälä 11116bfc56aaSVille Syrjälä return ret; 1112f453ba04SDave Airlie } 1113f453ba04SDave Airlie EXPORT_SYMBOL(drm_encoder_init); 1114f453ba04SDave Airlie 1115c8e32cc1SDaniel Vetter /** 1116c8e32cc1SDaniel Vetter * drm_encoder_cleanup - cleans up an initialised encoder 1117c8e32cc1SDaniel Vetter * @encoder: encoder to cleanup 1118c8e32cc1SDaniel Vetter * 1119c8e32cc1SDaniel Vetter * Cleans up the encoder but doesn't free the object. 1120c8e32cc1SDaniel Vetter */ 1121f453ba04SDave Airlie void drm_encoder_cleanup(struct drm_encoder *encoder) 1122f453ba04SDave Airlie { 1123f453ba04SDave Airlie struct drm_device *dev = encoder->dev; 11244dfd909fSThierry Reding 112584849903SDaniel Vetter drm_modeset_lock_all(dev); 1126f453ba04SDave Airlie drm_mode_object_put(dev, &encoder->base); 1127e5748946SJani Nikula kfree(encoder->name); 1128f453ba04SDave Airlie list_del(&encoder->head); 11296380c509SJoonyoung Shim dev->mode_config.num_encoder--; 113084849903SDaniel Vetter drm_modeset_unlock_all(dev); 1131a18c0af1SThierry Reding 1132a18c0af1SThierry Reding memset(encoder, 0, sizeof(*encoder)); 1133f453ba04SDave Airlie } 1134f453ba04SDave Airlie EXPORT_SYMBOL(drm_encoder_cleanup); 1135f453ba04SDave Airlie 113635f2c3aeSVille Syrjälä /** 1137dc415ff9SMatt Roper * drm_universal_plane_init - Initialize a new universal plane object 113835f2c3aeSVille Syrjälä * @dev: DRM device 113935f2c3aeSVille Syrjälä * @plane: plane object to init 114035f2c3aeSVille Syrjälä * @possible_crtcs: bitmask of possible CRTCs 114135f2c3aeSVille Syrjälä * @funcs: callbacks for the new plane 114235f2c3aeSVille Syrjälä * @formats: array of supported formats (%DRM_FORMAT_*) 114335f2c3aeSVille Syrjälä * @format_count: number of elements in @formats 1144dc415ff9SMatt Roper * @type: type of plane (overlay, primary, cursor) 114535f2c3aeSVille Syrjälä * 1146dc415ff9SMatt Roper * Initializes a plane object of type @type. 114735f2c3aeSVille Syrjälä * 1148c8e32cc1SDaniel Vetter * Returns: 114935f2c3aeSVille Syrjälä * Zero on success, error code on failure. 115035f2c3aeSVille Syrjälä */ 1151dc415ff9SMatt Roper int drm_universal_plane_init(struct drm_device *dev, struct drm_plane *plane, 11528cf5c917SJesse Barnes unsigned long possible_crtcs, 11538cf5c917SJesse Barnes const struct drm_plane_funcs *funcs, 11540a7eb243SRob Clark const uint32_t *formats, uint32_t format_count, 1155dc415ff9SMatt Roper enum drm_plane_type type) 11568cf5c917SJesse Barnes { 11576b4959f4SRob Clark struct drm_mode_config *config = &dev->mode_config; 11586bfc56aaSVille Syrjälä int ret; 11596bfc56aaSVille Syrjälä 11606bfc56aaSVille Syrjälä ret = drm_mode_object_get(dev, &plane->base, DRM_MODE_OBJECT_PLANE); 11616bfc56aaSVille Syrjälä if (ret) 1162baf698b0SDaniel Vetter return ret; 11636bfc56aaSVille Syrjälä 11644d02e2deSDaniel Vetter drm_modeset_lock_init(&plane->mutex); 11654d02e2deSDaniel Vetter 11664d93914aSRob Clark plane->base.properties = &plane->properties; 11678cf5c917SJesse Barnes plane->dev = dev; 11688cf5c917SJesse Barnes plane->funcs = funcs; 11692f6c5389SThierry Reding plane->format_types = kmalloc_array(format_count, sizeof(uint32_t), 11708cf5c917SJesse Barnes GFP_KERNEL); 11718cf5c917SJesse Barnes if (!plane->format_types) { 11728cf5c917SJesse Barnes DRM_DEBUG_KMS("out of memory when allocating plane\n"); 11738cf5c917SJesse Barnes drm_mode_object_put(dev, &plane->base); 1174baf698b0SDaniel Vetter return -ENOMEM; 11758cf5c917SJesse Barnes } 11768cf5c917SJesse Barnes 1177308e5bcbSJesse Barnes memcpy(plane->format_types, formats, format_count * sizeof(uint32_t)); 11788cf5c917SJesse Barnes plane->format_count = format_count; 11798cf5c917SJesse Barnes plane->possible_crtcs = possible_crtcs; 1180dc415ff9SMatt Roper plane->type = type; 11818cf5c917SJesse Barnes 11826b4959f4SRob Clark list_add_tail(&plane->head, &config->plane_list); 11836b4959f4SRob Clark config->num_total_plane++; 1184e27dde3eSMatt Roper if (plane->type == DRM_PLANE_TYPE_OVERLAY) 11856b4959f4SRob Clark config->num_overlay_plane++; 11868cf5c917SJesse Barnes 11879922ab5aSRob Clark drm_object_attach_property(&plane->base, 11886b4959f4SRob Clark config->plane_type_property, 11899922ab5aSRob Clark plane->type); 11909922ab5aSRob Clark 11916b4959f4SRob Clark if (drm_core_check_feature(dev, DRIVER_ATOMIC)) { 11926b4959f4SRob Clark drm_object_attach_property(&plane->base, config->prop_fb_id, 0); 11936b4959f4SRob Clark drm_object_attach_property(&plane->base, config->prop_crtc_id, 0); 11946b4959f4SRob Clark drm_object_attach_property(&plane->base, config->prop_crtc_x, 0); 11956b4959f4SRob Clark drm_object_attach_property(&plane->base, config->prop_crtc_y, 0); 11966b4959f4SRob Clark drm_object_attach_property(&plane->base, config->prop_crtc_w, 0); 11976b4959f4SRob Clark drm_object_attach_property(&plane->base, config->prop_crtc_h, 0); 11986b4959f4SRob Clark drm_object_attach_property(&plane->base, config->prop_src_x, 0); 11996b4959f4SRob Clark drm_object_attach_property(&plane->base, config->prop_src_y, 0); 12006b4959f4SRob Clark drm_object_attach_property(&plane->base, config->prop_src_w, 0); 12016b4959f4SRob Clark drm_object_attach_property(&plane->base, config->prop_src_h, 0); 12026b4959f4SRob Clark } 12036b4959f4SRob Clark 1204baf698b0SDaniel Vetter return 0; 12058cf5c917SJesse Barnes } 1206dc415ff9SMatt Roper EXPORT_SYMBOL(drm_universal_plane_init); 1207dc415ff9SMatt Roper 1208dc415ff9SMatt Roper /** 1209dc415ff9SMatt Roper * drm_plane_init - Initialize a legacy plane 1210dc415ff9SMatt Roper * @dev: DRM device 1211dc415ff9SMatt Roper * @plane: plane object to init 1212dc415ff9SMatt Roper * @possible_crtcs: bitmask of possible CRTCs 1213dc415ff9SMatt Roper * @funcs: callbacks for the new plane 1214dc415ff9SMatt Roper * @formats: array of supported formats (%DRM_FORMAT_*) 1215dc415ff9SMatt Roper * @format_count: number of elements in @formats 1216dc415ff9SMatt Roper * @is_primary: plane type (primary vs overlay) 1217dc415ff9SMatt Roper * 1218dc415ff9SMatt Roper * Legacy API to initialize a DRM plane. 1219dc415ff9SMatt Roper * 1220dc415ff9SMatt Roper * New drivers should call drm_universal_plane_init() instead. 1221dc415ff9SMatt Roper * 1222dc415ff9SMatt Roper * Returns: 1223dc415ff9SMatt Roper * Zero on success, error code on failure. 1224dc415ff9SMatt Roper */ 1225dc415ff9SMatt Roper int drm_plane_init(struct drm_device *dev, struct drm_plane *plane, 1226dc415ff9SMatt Roper unsigned long possible_crtcs, 1227dc415ff9SMatt Roper const struct drm_plane_funcs *funcs, 1228dc415ff9SMatt Roper const uint32_t *formats, uint32_t format_count, 1229dc415ff9SMatt Roper bool is_primary) 1230dc415ff9SMatt Roper { 1231dc415ff9SMatt Roper enum drm_plane_type type; 1232dc415ff9SMatt Roper 1233dc415ff9SMatt Roper type = is_primary ? DRM_PLANE_TYPE_PRIMARY : DRM_PLANE_TYPE_OVERLAY; 1234dc415ff9SMatt Roper return drm_universal_plane_init(dev, plane, possible_crtcs, funcs, 1235dc415ff9SMatt Roper formats, format_count, type); 1236dc415ff9SMatt Roper } 12378cf5c917SJesse Barnes EXPORT_SYMBOL(drm_plane_init); 12388cf5c917SJesse Barnes 123935f2c3aeSVille Syrjälä /** 124035f2c3aeSVille Syrjälä * drm_plane_cleanup - Clean up the core plane usage 124135f2c3aeSVille Syrjälä * @plane: plane to cleanup 124235f2c3aeSVille Syrjälä * 124335f2c3aeSVille Syrjälä * This function cleans up @plane and removes it from the DRM mode setting 124435f2c3aeSVille Syrjälä * core. Note that the function does *not* free the plane structure itself, 124535f2c3aeSVille Syrjälä * this is the responsibility of the caller. 124635f2c3aeSVille Syrjälä */ 12478cf5c917SJesse Barnes void drm_plane_cleanup(struct drm_plane *plane) 12488cf5c917SJesse Barnes { 12498cf5c917SJesse Barnes struct drm_device *dev = plane->dev; 12508cf5c917SJesse Barnes 125184849903SDaniel Vetter drm_modeset_lock_all(dev); 12528cf5c917SJesse Barnes kfree(plane->format_types); 12538cf5c917SJesse Barnes drm_mode_object_put(dev, &plane->base); 1254dc415ff9SMatt Roper 1255dc415ff9SMatt Roper BUG_ON(list_empty(&plane->head)); 1256dc415ff9SMatt Roper 12578cf5c917SJesse Barnes list_del(&plane->head); 1258e27dde3eSMatt Roper dev->mode_config.num_total_plane--; 1259e27dde3eSMatt Roper if (plane->type == DRM_PLANE_TYPE_OVERLAY) 1260e27dde3eSMatt Roper dev->mode_config.num_overlay_plane--; 126184849903SDaniel Vetter drm_modeset_unlock_all(dev); 12623009c037SThierry Reding 12633009c037SThierry Reding WARN_ON(plane->state && !plane->funcs->atomic_destroy_state); 12643009c037SThierry Reding if (plane->state && plane->funcs->atomic_destroy_state) 12653009c037SThierry Reding plane->funcs->atomic_destroy_state(plane, plane->state); 1266a18c0af1SThierry Reding 1267a18c0af1SThierry Reding memset(plane, 0, sizeof(*plane)); 12688cf5c917SJesse Barnes } 12698cf5c917SJesse Barnes EXPORT_SYMBOL(drm_plane_cleanup); 12708cf5c917SJesse Barnes 127135f2c3aeSVille Syrjälä /** 127210f637bfSDaniel Vetter * drm_plane_index - find the index of a registered plane 127310f637bfSDaniel Vetter * @plane: plane to find index for 127410f637bfSDaniel Vetter * 127510f637bfSDaniel Vetter * Given a registered plane, return the index of that CRTC within a DRM 127610f637bfSDaniel Vetter * device's list of planes. 127710f637bfSDaniel Vetter */ 127810f637bfSDaniel Vetter unsigned int drm_plane_index(struct drm_plane *plane) 127910f637bfSDaniel Vetter { 128010f637bfSDaniel Vetter unsigned int index = 0; 128110f637bfSDaniel Vetter struct drm_plane *tmp; 128210f637bfSDaniel Vetter 128310f637bfSDaniel Vetter list_for_each_entry(tmp, &plane->dev->mode_config.plane_list, head) { 128410f637bfSDaniel Vetter if (tmp == plane) 128510f637bfSDaniel Vetter return index; 128610f637bfSDaniel Vetter 128710f637bfSDaniel Vetter index++; 128810f637bfSDaniel Vetter } 128910f637bfSDaniel Vetter 129010f637bfSDaniel Vetter BUG(); 129110f637bfSDaniel Vetter } 129210f637bfSDaniel Vetter EXPORT_SYMBOL(drm_plane_index); 129310f637bfSDaniel Vetter 129410f637bfSDaniel Vetter /** 1295f81338a5SChandra Konduru * drm_plane_from_index - find the registered plane at an index 1296f81338a5SChandra Konduru * @dev: DRM device 1297f81338a5SChandra Konduru * @idx: index of registered plane to find for 1298f81338a5SChandra Konduru * 1299f81338a5SChandra Konduru * Given a plane index, return the registered plane from DRM device's 1300f81338a5SChandra Konduru * list of planes with matching index. 1301f81338a5SChandra Konduru */ 1302f81338a5SChandra Konduru struct drm_plane * 1303f81338a5SChandra Konduru drm_plane_from_index(struct drm_device *dev, int idx) 1304f81338a5SChandra Konduru { 1305f81338a5SChandra Konduru struct drm_plane *plane; 1306f81338a5SChandra Konduru unsigned int i = 0; 1307f81338a5SChandra Konduru 1308f81338a5SChandra Konduru list_for_each_entry(plane, &dev->mode_config.plane_list, head) { 1309f81338a5SChandra Konduru if (i == idx) 1310f81338a5SChandra Konduru return plane; 1311f81338a5SChandra Konduru i++; 1312f81338a5SChandra Konduru } 1313f81338a5SChandra Konduru return NULL; 1314f81338a5SChandra Konduru } 1315f81338a5SChandra Konduru EXPORT_SYMBOL(drm_plane_from_index); 1316f81338a5SChandra Konduru 1317f81338a5SChandra Konduru /** 131835f2c3aeSVille Syrjälä * drm_plane_force_disable - Forcibly disable a plane 131935f2c3aeSVille Syrjälä * @plane: plane to disable 132035f2c3aeSVille Syrjälä * 132135f2c3aeSVille Syrjälä * Forces the plane to be disabled. 132235f2c3aeSVille Syrjälä * 132335f2c3aeSVille Syrjälä * Used when the plane's current framebuffer is destroyed, 132435f2c3aeSVille Syrjälä * and when restoring fbdev mode. 132535f2c3aeSVille Syrjälä */ 13269125e618SVille Syrjälä void drm_plane_force_disable(struct drm_plane *plane) 13279125e618SVille Syrjälä { 13289125e618SVille Syrjälä int ret; 13299125e618SVille Syrjälä 13303d30a59bSDaniel Vetter if (!plane->fb) 13319125e618SVille Syrjälä return; 13329125e618SVille Syrjälä 13333d30a59bSDaniel Vetter plane->old_fb = plane->fb; 13349125e618SVille Syrjälä ret = plane->funcs->disable_plane(plane); 1335731cce48SDaniel Vetter if (ret) { 13369125e618SVille Syrjälä DRM_ERROR("failed to disable plane with busy fb\n"); 13373d30a59bSDaniel Vetter plane->old_fb = NULL; 1338731cce48SDaniel Vetter return; 1339731cce48SDaniel Vetter } 13409125e618SVille Syrjälä /* disconnect the plane from the fb and crtc: */ 1341220dd2bcSDaniel Vetter drm_framebuffer_unreference(plane->old_fb); 13423d30a59bSDaniel Vetter plane->old_fb = NULL; 13439125e618SVille Syrjälä plane->fb = NULL; 13449125e618SVille Syrjälä plane->crtc = NULL; 13459125e618SVille Syrjälä } 13469125e618SVille Syrjälä EXPORT_SYMBOL(drm_plane_force_disable); 13479125e618SVille Syrjälä 13486b4959f4SRob Clark static int drm_mode_create_standard_properties(struct drm_device *dev) 1349f453ba04SDave Airlie { 1350356af0e1SRob Clark struct drm_property *prop; 1351f453ba04SDave Airlie 1352f453ba04SDave Airlie /* 1353f453ba04SDave Airlie * Standard properties (apply to all connectors) 1354f453ba04SDave Airlie */ 1355356af0e1SRob Clark prop = drm_property_create(dev, DRM_MODE_PROP_BLOB | 1356f453ba04SDave Airlie DRM_MODE_PROP_IMMUTABLE, 1357f453ba04SDave Airlie "EDID", 0); 1358356af0e1SRob Clark if (!prop) 1359356af0e1SRob Clark return -ENOMEM; 1360356af0e1SRob Clark dev->mode_config.edid_property = prop; 1361f453ba04SDave Airlie 1362356af0e1SRob Clark prop = drm_property_create_enum(dev, 0, 13634a67d391SSascha Hauer "DPMS", drm_dpms_enum_list, 13644a67d391SSascha Hauer ARRAY_SIZE(drm_dpms_enum_list)); 1365356af0e1SRob Clark if (!prop) 1366356af0e1SRob Clark return -ENOMEM; 1367356af0e1SRob Clark dev->mode_config.dpms_property = prop; 1368f453ba04SDave Airlie 1369356af0e1SRob Clark prop = drm_property_create(dev, 137043aba7ebSDave Airlie DRM_MODE_PROP_BLOB | 137143aba7ebSDave Airlie DRM_MODE_PROP_IMMUTABLE, 137243aba7ebSDave Airlie "PATH", 0); 1373356af0e1SRob Clark if (!prop) 1374356af0e1SRob Clark return -ENOMEM; 1375356af0e1SRob Clark dev->mode_config.path_property = prop; 137643aba7ebSDave Airlie 1377356af0e1SRob Clark prop = drm_property_create(dev, 13786f134d7bSDave Airlie DRM_MODE_PROP_BLOB | 13796f134d7bSDave Airlie DRM_MODE_PROP_IMMUTABLE, 13806f134d7bSDave Airlie "TILE", 0); 1381356af0e1SRob Clark if (!prop) 1382356af0e1SRob Clark return -ENOMEM; 1383356af0e1SRob Clark dev->mode_config.tile_property = prop; 13846f134d7bSDave Airlie 13856b4959f4SRob Clark prop = drm_property_create_enum(dev, DRM_MODE_PROP_IMMUTABLE, 13869922ab5aSRob Clark "type", drm_plane_type_enum_list, 13879922ab5aSRob Clark ARRAY_SIZE(drm_plane_type_enum_list)); 13886b4959f4SRob Clark if (!prop) 13896b4959f4SRob Clark return -ENOMEM; 13906b4959f4SRob Clark dev->mode_config.plane_type_property = prop; 13916b4959f4SRob Clark 13926b4959f4SRob Clark prop = drm_property_create_range(dev, DRM_MODE_PROP_ATOMIC, 13936b4959f4SRob Clark "SRC_X", 0, UINT_MAX); 13946b4959f4SRob Clark if (!prop) 13956b4959f4SRob Clark return -ENOMEM; 13966b4959f4SRob Clark dev->mode_config.prop_src_x = prop; 13976b4959f4SRob Clark 13986b4959f4SRob Clark prop = drm_property_create_range(dev, DRM_MODE_PROP_ATOMIC, 13996b4959f4SRob Clark "SRC_Y", 0, UINT_MAX); 14006b4959f4SRob Clark if (!prop) 14016b4959f4SRob Clark return -ENOMEM; 14026b4959f4SRob Clark dev->mode_config.prop_src_y = prop; 14036b4959f4SRob Clark 14046b4959f4SRob Clark prop = drm_property_create_range(dev, DRM_MODE_PROP_ATOMIC, 14056b4959f4SRob Clark "SRC_W", 0, UINT_MAX); 14066b4959f4SRob Clark if (!prop) 14076b4959f4SRob Clark return -ENOMEM; 14086b4959f4SRob Clark dev->mode_config.prop_src_w = prop; 14096b4959f4SRob Clark 14106b4959f4SRob Clark prop = drm_property_create_range(dev, DRM_MODE_PROP_ATOMIC, 14116b4959f4SRob Clark "SRC_H", 0, UINT_MAX); 14126b4959f4SRob Clark if (!prop) 14136b4959f4SRob Clark return -ENOMEM; 14146b4959f4SRob Clark dev->mode_config.prop_src_h = prop; 14156b4959f4SRob Clark 14166b4959f4SRob Clark prop = drm_property_create_signed_range(dev, DRM_MODE_PROP_ATOMIC, 14176b4959f4SRob Clark "CRTC_X", INT_MIN, INT_MAX); 14186b4959f4SRob Clark if (!prop) 14196b4959f4SRob Clark return -ENOMEM; 14206b4959f4SRob Clark dev->mode_config.prop_crtc_x = prop; 14216b4959f4SRob Clark 14226b4959f4SRob Clark prop = drm_property_create_signed_range(dev, DRM_MODE_PROP_ATOMIC, 14236b4959f4SRob Clark "CRTC_Y", INT_MIN, INT_MAX); 14246b4959f4SRob Clark if (!prop) 14256b4959f4SRob Clark return -ENOMEM; 14266b4959f4SRob Clark dev->mode_config.prop_crtc_y = prop; 14276b4959f4SRob Clark 14286b4959f4SRob Clark prop = drm_property_create_range(dev, DRM_MODE_PROP_ATOMIC, 14296b4959f4SRob Clark "CRTC_W", 0, INT_MAX); 14306b4959f4SRob Clark if (!prop) 14316b4959f4SRob Clark return -ENOMEM; 14326b4959f4SRob Clark dev->mode_config.prop_crtc_w = prop; 14336b4959f4SRob Clark 14346b4959f4SRob Clark prop = drm_property_create_range(dev, DRM_MODE_PROP_ATOMIC, 14356b4959f4SRob Clark "CRTC_H", 0, INT_MAX); 14366b4959f4SRob Clark if (!prop) 14376b4959f4SRob Clark return -ENOMEM; 14386b4959f4SRob Clark dev->mode_config.prop_crtc_h = prop; 14396b4959f4SRob Clark 14406b4959f4SRob Clark prop = drm_property_create_object(dev, DRM_MODE_PROP_ATOMIC, 14416b4959f4SRob Clark "FB_ID", DRM_MODE_OBJECT_FB); 14426b4959f4SRob Clark if (!prop) 14436b4959f4SRob Clark return -ENOMEM; 14446b4959f4SRob Clark dev->mode_config.prop_fb_id = prop; 14456b4959f4SRob Clark 14466b4959f4SRob Clark prop = drm_property_create_object(dev, DRM_MODE_PROP_ATOMIC, 14476b4959f4SRob Clark "CRTC_ID", DRM_MODE_OBJECT_CRTC); 14486b4959f4SRob Clark if (!prop) 14496b4959f4SRob Clark return -ENOMEM; 14506b4959f4SRob Clark dev->mode_config.prop_crtc_id = prop; 14519922ab5aSRob Clark 1452eab3bbefSDaniel Vetter prop = drm_property_create_bool(dev, DRM_MODE_PROP_ATOMIC, 1453eab3bbefSDaniel Vetter "ACTIVE"); 1454eab3bbefSDaniel Vetter if (!prop) 1455eab3bbefSDaniel Vetter return -ENOMEM; 1456eab3bbefSDaniel Vetter dev->mode_config.prop_active = prop; 1457eab3bbefSDaniel Vetter 1458955f3c33SDaniel Stone prop = drm_property_create(dev, 1459955f3c33SDaniel Stone DRM_MODE_PROP_ATOMIC | DRM_MODE_PROP_BLOB, 1460955f3c33SDaniel Stone "MODE_ID", 0); 1461955f3c33SDaniel Stone if (!prop) 1462955f3c33SDaniel Stone return -ENOMEM; 1463955f3c33SDaniel Stone dev->mode_config.prop_mode_id = prop; 1464955f3c33SDaniel Stone 14659922ab5aSRob Clark return 0; 14669922ab5aSRob Clark } 14679922ab5aSRob Clark 1468f453ba04SDave Airlie /** 1469f453ba04SDave Airlie * drm_mode_create_dvi_i_properties - create DVI-I specific connector properties 1470f453ba04SDave Airlie * @dev: DRM device 1471f453ba04SDave Airlie * 1472f453ba04SDave Airlie * Called by a driver the first time a DVI-I connector is made. 1473f453ba04SDave Airlie */ 1474f453ba04SDave Airlie int drm_mode_create_dvi_i_properties(struct drm_device *dev) 1475f453ba04SDave Airlie { 1476f453ba04SDave Airlie struct drm_property *dvi_i_selector; 1477f453ba04SDave Airlie struct drm_property *dvi_i_subconnector; 1478f453ba04SDave Airlie 1479f453ba04SDave Airlie if (dev->mode_config.dvi_i_select_subconnector_property) 1480f453ba04SDave Airlie return 0; 1481f453ba04SDave Airlie 1482f453ba04SDave Airlie dvi_i_selector = 14834a67d391SSascha Hauer drm_property_create_enum(dev, 0, 1484f453ba04SDave Airlie "select subconnector", 14854a67d391SSascha Hauer drm_dvi_i_select_enum_list, 1486f453ba04SDave Airlie ARRAY_SIZE(drm_dvi_i_select_enum_list)); 1487f453ba04SDave Airlie dev->mode_config.dvi_i_select_subconnector_property = dvi_i_selector; 1488f453ba04SDave Airlie 14894a67d391SSascha Hauer dvi_i_subconnector = drm_property_create_enum(dev, DRM_MODE_PROP_IMMUTABLE, 1490f453ba04SDave Airlie "subconnector", 14914a67d391SSascha Hauer drm_dvi_i_subconnector_enum_list, 1492f453ba04SDave Airlie ARRAY_SIZE(drm_dvi_i_subconnector_enum_list)); 1493f453ba04SDave Airlie dev->mode_config.dvi_i_subconnector_property = dvi_i_subconnector; 1494f453ba04SDave Airlie 1495f453ba04SDave Airlie return 0; 1496f453ba04SDave Airlie } 1497f453ba04SDave Airlie EXPORT_SYMBOL(drm_mode_create_dvi_i_properties); 1498f453ba04SDave Airlie 1499f453ba04SDave Airlie /** 1500f453ba04SDave Airlie * drm_create_tv_properties - create TV specific connector properties 1501f453ba04SDave Airlie * @dev: DRM device 1502f453ba04SDave Airlie * @num_modes: number of different TV formats (modes) supported 1503f453ba04SDave Airlie * @modes: array of pointers to strings containing name of each format 1504f453ba04SDave Airlie * 1505f453ba04SDave Airlie * Called by a driver's TV initialization routine, this function creates 1506f453ba04SDave Airlie * the TV specific connector properties for a given device. Caller is 1507f453ba04SDave Airlie * responsible for allocating a list of format names and passing them to 1508f453ba04SDave Airlie * this routine. 1509f453ba04SDave Airlie */ 15102f763312SThierry Reding int drm_mode_create_tv_properties(struct drm_device *dev, 15112f763312SThierry Reding unsigned int num_modes, 1512f453ba04SDave Airlie char *modes[]) 1513f453ba04SDave Airlie { 1514f453ba04SDave Airlie struct drm_property *tv_selector; 1515f453ba04SDave Airlie struct drm_property *tv_subconnector; 15162f763312SThierry Reding unsigned int i; 1517f453ba04SDave Airlie 1518f453ba04SDave Airlie if (dev->mode_config.tv_select_subconnector_property) 1519f453ba04SDave Airlie return 0; 1520f453ba04SDave Airlie 1521f453ba04SDave Airlie /* 1522f453ba04SDave Airlie * Basic connector properties 1523f453ba04SDave Airlie */ 15244a67d391SSascha Hauer tv_selector = drm_property_create_enum(dev, 0, 1525f453ba04SDave Airlie "select subconnector", 15264a67d391SSascha Hauer drm_tv_select_enum_list, 1527f453ba04SDave Airlie ARRAY_SIZE(drm_tv_select_enum_list)); 1528f453ba04SDave Airlie dev->mode_config.tv_select_subconnector_property = tv_selector; 1529f453ba04SDave Airlie 1530f453ba04SDave Airlie tv_subconnector = 15314a67d391SSascha Hauer drm_property_create_enum(dev, DRM_MODE_PROP_IMMUTABLE, 15324a67d391SSascha Hauer "subconnector", 15334a67d391SSascha Hauer drm_tv_subconnector_enum_list, 1534f453ba04SDave Airlie ARRAY_SIZE(drm_tv_subconnector_enum_list)); 1535f453ba04SDave Airlie dev->mode_config.tv_subconnector_property = tv_subconnector; 1536f453ba04SDave Airlie 1537f453ba04SDave Airlie /* 1538f453ba04SDave Airlie * Other, TV specific properties: margins & TV modes. 1539f453ba04SDave Airlie */ 1540f453ba04SDave Airlie dev->mode_config.tv_left_margin_property = 1541d9bc3c02SSascha Hauer drm_property_create_range(dev, 0, "left margin", 0, 100); 1542f453ba04SDave Airlie 1543f453ba04SDave Airlie dev->mode_config.tv_right_margin_property = 1544d9bc3c02SSascha Hauer drm_property_create_range(dev, 0, "right margin", 0, 100); 1545f453ba04SDave Airlie 1546f453ba04SDave Airlie dev->mode_config.tv_top_margin_property = 1547d9bc3c02SSascha Hauer drm_property_create_range(dev, 0, "top margin", 0, 100); 1548f453ba04SDave Airlie 1549f453ba04SDave Airlie dev->mode_config.tv_bottom_margin_property = 1550d9bc3c02SSascha Hauer drm_property_create_range(dev, 0, "bottom margin", 0, 100); 1551f453ba04SDave Airlie 1552f453ba04SDave Airlie dev->mode_config.tv_mode_property = 1553f453ba04SDave Airlie drm_property_create(dev, DRM_MODE_PROP_ENUM, 1554f453ba04SDave Airlie "mode", num_modes); 1555f453ba04SDave Airlie for (i = 0; i < num_modes; i++) 1556f453ba04SDave Airlie drm_property_add_enum(dev->mode_config.tv_mode_property, i, 1557f453ba04SDave Airlie i, modes[i]); 1558f453ba04SDave Airlie 1559b6b7902eSFrancisco Jerez dev->mode_config.tv_brightness_property = 1560d9bc3c02SSascha Hauer drm_property_create_range(dev, 0, "brightness", 0, 100); 1561b6b7902eSFrancisco Jerez 1562b6b7902eSFrancisco Jerez dev->mode_config.tv_contrast_property = 1563d9bc3c02SSascha Hauer drm_property_create_range(dev, 0, "contrast", 0, 100); 1564b6b7902eSFrancisco Jerez 1565b6b7902eSFrancisco Jerez dev->mode_config.tv_flicker_reduction_property = 1566d9bc3c02SSascha Hauer drm_property_create_range(dev, 0, "flicker reduction", 0, 100); 1567b6b7902eSFrancisco Jerez 1568a75f0236SFrancisco Jerez dev->mode_config.tv_overscan_property = 1569d9bc3c02SSascha Hauer drm_property_create_range(dev, 0, "overscan", 0, 100); 1570a75f0236SFrancisco Jerez 1571a75f0236SFrancisco Jerez dev->mode_config.tv_saturation_property = 1572d9bc3c02SSascha Hauer drm_property_create_range(dev, 0, "saturation", 0, 100); 1573a75f0236SFrancisco Jerez 1574a75f0236SFrancisco Jerez dev->mode_config.tv_hue_property = 1575d9bc3c02SSascha Hauer drm_property_create_range(dev, 0, "hue", 0, 100); 1576a75f0236SFrancisco Jerez 1577f453ba04SDave Airlie return 0; 1578f453ba04SDave Airlie } 1579f453ba04SDave Airlie EXPORT_SYMBOL(drm_mode_create_tv_properties); 1580f453ba04SDave Airlie 1581f453ba04SDave Airlie /** 1582f453ba04SDave Airlie * drm_mode_create_scaling_mode_property - create scaling mode property 1583f453ba04SDave Airlie * @dev: DRM device 1584f453ba04SDave Airlie * 1585f453ba04SDave Airlie * Called by a driver the first time it's needed, must be attached to desired 1586f453ba04SDave Airlie * connectors. 1587f453ba04SDave Airlie */ 1588f453ba04SDave Airlie int drm_mode_create_scaling_mode_property(struct drm_device *dev) 1589f453ba04SDave Airlie { 1590f453ba04SDave Airlie struct drm_property *scaling_mode; 1591f453ba04SDave Airlie 1592f453ba04SDave Airlie if (dev->mode_config.scaling_mode_property) 1593f453ba04SDave Airlie return 0; 1594f453ba04SDave Airlie 1595f453ba04SDave Airlie scaling_mode = 15964a67d391SSascha Hauer drm_property_create_enum(dev, 0, "scaling mode", 15974a67d391SSascha Hauer drm_scaling_mode_enum_list, 1598f453ba04SDave Airlie ARRAY_SIZE(drm_scaling_mode_enum_list)); 1599f453ba04SDave Airlie 1600f453ba04SDave Airlie dev->mode_config.scaling_mode_property = scaling_mode; 1601f453ba04SDave Airlie 1602f453ba04SDave Airlie return 0; 1603f453ba04SDave Airlie } 1604f453ba04SDave Airlie EXPORT_SYMBOL(drm_mode_create_scaling_mode_property); 1605f453ba04SDave Airlie 1606f453ba04SDave Airlie /** 1607ff587e45SVandana Kannan * drm_mode_create_aspect_ratio_property - create aspect ratio property 1608ff587e45SVandana Kannan * @dev: DRM device 1609ff587e45SVandana Kannan * 1610ff587e45SVandana Kannan * Called by a driver the first time it's needed, must be attached to desired 1611ff587e45SVandana Kannan * connectors. 1612ff587e45SVandana Kannan * 1613ff587e45SVandana Kannan * Returns: 16141a498633SDaniel Vetter * Zero on success, negative errno on failure. 1615ff587e45SVandana Kannan */ 1616ff587e45SVandana Kannan int drm_mode_create_aspect_ratio_property(struct drm_device *dev) 1617ff587e45SVandana Kannan { 1618ff587e45SVandana Kannan if (dev->mode_config.aspect_ratio_property) 1619ff587e45SVandana Kannan return 0; 1620ff587e45SVandana Kannan 1621ff587e45SVandana Kannan dev->mode_config.aspect_ratio_property = 1622ff587e45SVandana Kannan drm_property_create_enum(dev, 0, "aspect ratio", 1623ff587e45SVandana Kannan drm_aspect_ratio_enum_list, 1624ff587e45SVandana Kannan ARRAY_SIZE(drm_aspect_ratio_enum_list)); 1625ff587e45SVandana Kannan 1626ff587e45SVandana Kannan if (dev->mode_config.aspect_ratio_property == NULL) 1627ff587e45SVandana Kannan return -ENOMEM; 1628ff587e45SVandana Kannan 1629ff587e45SVandana Kannan return 0; 1630ff587e45SVandana Kannan } 1631ff587e45SVandana Kannan EXPORT_SYMBOL(drm_mode_create_aspect_ratio_property); 1632ff587e45SVandana Kannan 1633ff587e45SVandana Kannan /** 1634884840aaSJakob Bornecrantz * drm_mode_create_dirty_property - create dirty property 1635884840aaSJakob Bornecrantz * @dev: DRM device 1636884840aaSJakob Bornecrantz * 1637884840aaSJakob Bornecrantz * Called by a driver the first time it's needed, must be attached to desired 1638884840aaSJakob Bornecrantz * connectors. 1639884840aaSJakob Bornecrantz */ 1640884840aaSJakob Bornecrantz int drm_mode_create_dirty_info_property(struct drm_device *dev) 1641884840aaSJakob Bornecrantz { 1642884840aaSJakob Bornecrantz struct drm_property *dirty_info; 1643884840aaSJakob Bornecrantz 1644884840aaSJakob Bornecrantz if (dev->mode_config.dirty_info_property) 1645884840aaSJakob Bornecrantz return 0; 1646884840aaSJakob Bornecrantz 1647884840aaSJakob Bornecrantz dirty_info = 16484a67d391SSascha Hauer drm_property_create_enum(dev, DRM_MODE_PROP_IMMUTABLE, 1649884840aaSJakob Bornecrantz "dirty", 16504a67d391SSascha Hauer drm_dirty_info_enum_list, 1651884840aaSJakob Bornecrantz ARRAY_SIZE(drm_dirty_info_enum_list)); 1652884840aaSJakob Bornecrantz dev->mode_config.dirty_info_property = dirty_info; 1653884840aaSJakob Bornecrantz 1654884840aaSJakob Bornecrantz return 0; 1655884840aaSJakob Bornecrantz } 1656884840aaSJakob Bornecrantz EXPORT_SYMBOL(drm_mode_create_dirty_info_property); 1657884840aaSJakob Bornecrantz 16585bb2bbf5SDave Airlie /** 16595bb2bbf5SDave Airlie * drm_mode_create_suggested_offset_properties - create suggests offset properties 16605bb2bbf5SDave Airlie * @dev: DRM device 16615bb2bbf5SDave Airlie * 16625bb2bbf5SDave Airlie * Create the the suggested x/y offset property for connectors. 16635bb2bbf5SDave Airlie */ 16645bb2bbf5SDave Airlie int drm_mode_create_suggested_offset_properties(struct drm_device *dev) 16655bb2bbf5SDave Airlie { 16665bb2bbf5SDave Airlie if (dev->mode_config.suggested_x_property && dev->mode_config.suggested_y_property) 16675bb2bbf5SDave Airlie return 0; 16685bb2bbf5SDave Airlie 16695bb2bbf5SDave Airlie dev->mode_config.suggested_x_property = 16705bb2bbf5SDave Airlie drm_property_create_range(dev, DRM_MODE_PROP_IMMUTABLE, "suggested X", 0, 0xffffffff); 16715bb2bbf5SDave Airlie 16725bb2bbf5SDave Airlie dev->mode_config.suggested_y_property = 16735bb2bbf5SDave Airlie drm_property_create_range(dev, DRM_MODE_PROP_IMMUTABLE, "suggested Y", 0, 0xffffffff); 16745bb2bbf5SDave Airlie 16755bb2bbf5SDave Airlie if (dev->mode_config.suggested_x_property == NULL || 16765bb2bbf5SDave Airlie dev->mode_config.suggested_y_property == NULL) 16775bb2bbf5SDave Airlie return -ENOMEM; 16785bb2bbf5SDave Airlie return 0; 16795bb2bbf5SDave Airlie } 16805bb2bbf5SDave Airlie EXPORT_SYMBOL(drm_mode_create_suggested_offset_properties); 16815bb2bbf5SDave Airlie 1682ea9cbb06SVille Syrjälä static int drm_mode_group_init(struct drm_device *dev, struct drm_mode_group *group) 1683f453ba04SDave Airlie { 1684f453ba04SDave Airlie uint32_t total_objects = 0; 1685f453ba04SDave Airlie 1686f453ba04SDave Airlie total_objects += dev->mode_config.num_crtc; 1687f453ba04SDave Airlie total_objects += dev->mode_config.num_connector; 1688f453ba04SDave Airlie total_objects += dev->mode_config.num_encoder; 1689f453ba04SDave Airlie 1690bd3f0ff9SThierry Reding group->id_list = kcalloc(total_objects, sizeof(uint32_t), GFP_KERNEL); 1691f453ba04SDave Airlie if (!group->id_list) 1692f453ba04SDave Airlie return -ENOMEM; 1693f453ba04SDave Airlie 1694f453ba04SDave Airlie group->num_crtcs = 0; 1695f453ba04SDave Airlie group->num_connectors = 0; 1696f453ba04SDave Airlie group->num_encoders = 0; 1697f453ba04SDave Airlie return 0; 1698f453ba04SDave Airlie } 1699f453ba04SDave Airlie 1700ad222799SDave Airlie void drm_mode_group_destroy(struct drm_mode_group *group) 1701ad222799SDave Airlie { 1702ad222799SDave Airlie kfree(group->id_list); 1703ad222799SDave Airlie group->id_list = NULL; 1704ad222799SDave Airlie } 1705ad222799SDave Airlie 1706c8e32cc1SDaniel Vetter /* 1707c8e32cc1SDaniel Vetter * NOTE: Driver's shouldn't ever call drm_mode_group_init_legacy_group - it is 1708c8e32cc1SDaniel Vetter * the drm core's responsibility to set up mode control groups. 1709c8e32cc1SDaniel Vetter */ 1710f453ba04SDave Airlie int drm_mode_group_init_legacy_group(struct drm_device *dev, 1711f453ba04SDave Airlie struct drm_mode_group *group) 1712f453ba04SDave Airlie { 1713f453ba04SDave Airlie struct drm_crtc *crtc; 1714f453ba04SDave Airlie struct drm_encoder *encoder; 1715f453ba04SDave Airlie struct drm_connector *connector; 1716f453ba04SDave Airlie int ret; 1717f453ba04SDave Airlie 17180cc0b223SThierry Reding ret = drm_mode_group_init(dev, group); 17190cc0b223SThierry Reding if (ret) 1720f453ba04SDave Airlie return ret; 1721f453ba04SDave Airlie 1722f453ba04SDave Airlie list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) 1723f453ba04SDave Airlie group->id_list[group->num_crtcs++] = crtc->base.id; 1724f453ba04SDave Airlie 1725f453ba04SDave Airlie list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) 1726f453ba04SDave Airlie group->id_list[group->num_crtcs + group->num_encoders++] = 1727f453ba04SDave Airlie encoder->base.id; 1728f453ba04SDave Airlie 1729f453ba04SDave Airlie list_for_each_entry(connector, &dev->mode_config.connector_list, head) 1730f453ba04SDave Airlie group->id_list[group->num_crtcs + group->num_encoders + 1731f453ba04SDave Airlie group->num_connectors++] = connector->base.id; 1732f453ba04SDave Airlie 1733f453ba04SDave Airlie return 0; 1734f453ba04SDave Airlie } 17359c1dfc55SDave Airlie EXPORT_SYMBOL(drm_mode_group_init_legacy_group); 1736f453ba04SDave Airlie 17372390cd11SDave Airlie void drm_reinit_primary_mode_group(struct drm_device *dev) 17382390cd11SDave Airlie { 17392390cd11SDave Airlie drm_modeset_lock_all(dev); 17402390cd11SDave Airlie drm_mode_group_destroy(&dev->primary->mode_group); 17412390cd11SDave Airlie drm_mode_group_init_legacy_group(dev, &dev->primary->mode_group); 17422390cd11SDave Airlie drm_modeset_unlock_all(dev); 17432390cd11SDave Airlie } 17442390cd11SDave Airlie EXPORT_SYMBOL(drm_reinit_primary_mode_group); 17452390cd11SDave Airlie 1746f453ba04SDave Airlie /** 1747f453ba04SDave Airlie * drm_mode_getresources - get graphics configuration 1748065a50edSDaniel Vetter * @dev: drm device for the ioctl 1749065a50edSDaniel Vetter * @data: data pointer for the ioctl 1750065a50edSDaniel Vetter * @file_priv: drm file for the ioctl call 1751f453ba04SDave Airlie * 1752f453ba04SDave Airlie * Construct a set of configuration description structures and return 1753f453ba04SDave Airlie * them to the user, including CRTC, connector and framebuffer configuration. 1754f453ba04SDave Airlie * 1755f453ba04SDave Airlie * Called by the user via ioctl. 1756f453ba04SDave Airlie * 1757c8e32cc1SDaniel Vetter * Returns: 17581a498633SDaniel Vetter * Zero on success, negative errno on failure. 1759f453ba04SDave Airlie */ 1760f453ba04SDave Airlie int drm_mode_getresources(struct drm_device *dev, void *data, 1761f453ba04SDave Airlie struct drm_file *file_priv) 1762f453ba04SDave Airlie { 1763f453ba04SDave Airlie struct drm_mode_card_res *card_res = data; 1764f453ba04SDave Airlie struct list_head *lh; 1765f453ba04SDave Airlie struct drm_framebuffer *fb; 1766f453ba04SDave Airlie struct drm_connector *connector; 1767f453ba04SDave Airlie struct drm_crtc *crtc; 1768f453ba04SDave Airlie struct drm_encoder *encoder; 1769f453ba04SDave Airlie int ret = 0; 1770f453ba04SDave Airlie int connector_count = 0; 1771f453ba04SDave Airlie int crtc_count = 0; 1772f453ba04SDave Airlie int fb_count = 0; 1773f453ba04SDave Airlie int encoder_count = 0; 1774f453ba04SDave Airlie int copied = 0, i; 1775f453ba04SDave Airlie uint32_t __user *fb_id; 1776f453ba04SDave Airlie uint32_t __user *crtc_id; 1777f453ba04SDave Airlie uint32_t __user *connector_id; 1778f453ba04SDave Airlie uint32_t __user *encoder_id; 1779f453ba04SDave Airlie struct drm_mode_group *mode_group; 1780f453ba04SDave Airlie 1781fb3b06c8SDave Airlie if (!drm_core_check_feature(dev, DRIVER_MODESET)) 1782fb3b06c8SDave Airlie return -EINVAL; 1783fb3b06c8SDave Airlie 1784f453ba04SDave Airlie 17854b096ac1SDaniel Vetter mutex_lock(&file_priv->fbs_lock); 1786f453ba04SDave Airlie /* 1787f453ba04SDave Airlie * For the non-control nodes we need to limit the list of resources 1788f453ba04SDave Airlie * by IDs in the group list for this node 1789f453ba04SDave Airlie */ 1790f453ba04SDave Airlie list_for_each(lh, &file_priv->fbs) 1791f453ba04SDave Airlie fb_count++; 1792f453ba04SDave Airlie 17934b096ac1SDaniel Vetter /* handle this in 4 parts */ 17944b096ac1SDaniel Vetter /* FBs */ 17954b096ac1SDaniel Vetter if (card_res->count_fbs >= fb_count) { 17964b096ac1SDaniel Vetter copied = 0; 17974b096ac1SDaniel Vetter fb_id = (uint32_t __user *)(unsigned long)card_res->fb_id_ptr; 17984b096ac1SDaniel Vetter list_for_each_entry(fb, &file_priv->fbs, filp_head) { 17994b096ac1SDaniel Vetter if (put_user(fb->base.id, fb_id + copied)) { 18004b096ac1SDaniel Vetter mutex_unlock(&file_priv->fbs_lock); 18014b096ac1SDaniel Vetter return -EFAULT; 18024b096ac1SDaniel Vetter } 18034b096ac1SDaniel Vetter copied++; 18044b096ac1SDaniel Vetter } 18054b096ac1SDaniel Vetter } 18064b096ac1SDaniel Vetter card_res->count_fbs = fb_count; 18074b096ac1SDaniel Vetter mutex_unlock(&file_priv->fbs_lock); 18084b096ac1SDaniel Vetter 1809fcf93f69SDaniel Vetter /* mode_config.mutex protects the connector list against e.g. DP MST 1810fcf93f69SDaniel Vetter * connector hot-adding. CRTC/Plane lists are invariant. */ 1811fcf93f69SDaniel Vetter mutex_lock(&dev->mode_config.mutex); 181243683057SThomas Hellstrom if (!drm_is_primary_client(file_priv)) { 1813f453ba04SDave Airlie 181409f308f7SThomas Hellstrom mode_group = NULL; 1815f453ba04SDave Airlie list_for_each(lh, &dev->mode_config.crtc_list) 1816f453ba04SDave Airlie crtc_count++; 1817f453ba04SDave Airlie 1818f453ba04SDave Airlie list_for_each(lh, &dev->mode_config.connector_list) 1819f453ba04SDave Airlie connector_count++; 1820f453ba04SDave Airlie 1821f453ba04SDave Airlie list_for_each(lh, &dev->mode_config.encoder_list) 1822f453ba04SDave Airlie encoder_count++; 1823f453ba04SDave Airlie } else { 1824f453ba04SDave Airlie 182509f308f7SThomas Hellstrom mode_group = &file_priv->master->minor->mode_group; 1826f453ba04SDave Airlie crtc_count = mode_group->num_crtcs; 1827f453ba04SDave Airlie connector_count = mode_group->num_connectors; 1828f453ba04SDave Airlie encoder_count = mode_group->num_encoders; 1829f453ba04SDave Airlie } 1830f453ba04SDave Airlie 1831f453ba04SDave Airlie card_res->max_height = dev->mode_config.max_height; 1832f453ba04SDave Airlie card_res->min_height = dev->mode_config.min_height; 1833f453ba04SDave Airlie card_res->max_width = dev->mode_config.max_width; 1834f453ba04SDave Airlie card_res->min_width = dev->mode_config.min_width; 1835f453ba04SDave Airlie 1836f453ba04SDave Airlie /* CRTCs */ 1837f453ba04SDave Airlie if (card_res->count_crtcs >= crtc_count) { 1838f453ba04SDave Airlie copied = 0; 1839f453ba04SDave Airlie crtc_id = (uint32_t __user *)(unsigned long)card_res->crtc_id_ptr; 184009f308f7SThomas Hellstrom if (!mode_group) { 1841f453ba04SDave Airlie list_for_each_entry(crtc, &dev->mode_config.crtc_list, 1842f453ba04SDave Airlie head) { 18439440106bSJerome Glisse DRM_DEBUG_KMS("[CRTC:%d]\n", crtc->base.id); 1844f453ba04SDave Airlie if (put_user(crtc->base.id, crtc_id + copied)) { 1845f453ba04SDave Airlie ret = -EFAULT; 1846f453ba04SDave Airlie goto out; 1847f453ba04SDave Airlie } 1848f453ba04SDave Airlie copied++; 1849f453ba04SDave Airlie } 1850f453ba04SDave Airlie } else { 1851f453ba04SDave Airlie for (i = 0; i < mode_group->num_crtcs; i++) { 1852f453ba04SDave Airlie if (put_user(mode_group->id_list[i], 1853f453ba04SDave Airlie crtc_id + copied)) { 1854f453ba04SDave Airlie ret = -EFAULT; 1855f453ba04SDave Airlie goto out; 1856f453ba04SDave Airlie } 1857f453ba04SDave Airlie copied++; 1858f453ba04SDave Airlie } 1859f453ba04SDave Airlie } 1860f453ba04SDave Airlie } 1861f453ba04SDave Airlie card_res->count_crtcs = crtc_count; 1862f453ba04SDave Airlie 1863f453ba04SDave Airlie /* Encoders */ 1864f453ba04SDave Airlie if (card_res->count_encoders >= encoder_count) { 1865f453ba04SDave Airlie copied = 0; 1866f453ba04SDave Airlie encoder_id = (uint32_t __user *)(unsigned long)card_res->encoder_id_ptr; 186709f308f7SThomas Hellstrom if (!mode_group) { 1868f453ba04SDave Airlie list_for_each_entry(encoder, 1869f453ba04SDave Airlie &dev->mode_config.encoder_list, 1870f453ba04SDave Airlie head) { 18719440106bSJerome Glisse DRM_DEBUG_KMS("[ENCODER:%d:%s]\n", encoder->base.id, 187283a8cfd3SJani Nikula encoder->name); 1873f453ba04SDave Airlie if (put_user(encoder->base.id, encoder_id + 1874f453ba04SDave Airlie copied)) { 1875f453ba04SDave Airlie ret = -EFAULT; 1876f453ba04SDave Airlie goto out; 1877f453ba04SDave Airlie } 1878f453ba04SDave Airlie copied++; 1879f453ba04SDave Airlie } 1880f453ba04SDave Airlie } else { 1881f453ba04SDave Airlie for (i = mode_group->num_crtcs; i < mode_group->num_crtcs + mode_group->num_encoders; i++) { 1882f453ba04SDave Airlie if (put_user(mode_group->id_list[i], 1883f453ba04SDave Airlie encoder_id + copied)) { 1884f453ba04SDave Airlie ret = -EFAULT; 1885f453ba04SDave Airlie goto out; 1886f453ba04SDave Airlie } 1887f453ba04SDave Airlie copied++; 1888f453ba04SDave Airlie } 1889f453ba04SDave Airlie 1890f453ba04SDave Airlie } 1891f453ba04SDave Airlie } 1892f453ba04SDave Airlie card_res->count_encoders = encoder_count; 1893f453ba04SDave Airlie 1894f453ba04SDave Airlie /* Connectors */ 1895f453ba04SDave Airlie if (card_res->count_connectors >= connector_count) { 1896f453ba04SDave Airlie copied = 0; 1897f453ba04SDave Airlie connector_id = (uint32_t __user *)(unsigned long)card_res->connector_id_ptr; 189809f308f7SThomas Hellstrom if (!mode_group) { 1899f453ba04SDave Airlie list_for_each_entry(connector, 1900f453ba04SDave Airlie &dev->mode_config.connector_list, 1901f453ba04SDave Airlie head) { 19029440106bSJerome Glisse DRM_DEBUG_KMS("[CONNECTOR:%d:%s]\n", 19039440106bSJerome Glisse connector->base.id, 190425933820SJani Nikula connector->name); 1905f453ba04SDave Airlie if (put_user(connector->base.id, 1906f453ba04SDave Airlie connector_id + copied)) { 1907f453ba04SDave Airlie ret = -EFAULT; 1908f453ba04SDave Airlie goto out; 1909f453ba04SDave Airlie } 1910f453ba04SDave Airlie copied++; 1911f453ba04SDave Airlie } 1912f453ba04SDave Airlie } else { 1913f453ba04SDave Airlie int start = mode_group->num_crtcs + 1914f453ba04SDave Airlie mode_group->num_encoders; 1915f453ba04SDave Airlie for (i = start; i < start + mode_group->num_connectors; i++) { 1916f453ba04SDave Airlie if (put_user(mode_group->id_list[i], 1917f453ba04SDave Airlie connector_id + copied)) { 1918f453ba04SDave Airlie ret = -EFAULT; 1919f453ba04SDave Airlie goto out; 1920f453ba04SDave Airlie } 1921f453ba04SDave Airlie copied++; 1922f453ba04SDave Airlie } 1923f453ba04SDave Airlie } 1924f453ba04SDave Airlie } 1925f453ba04SDave Airlie card_res->count_connectors = connector_count; 1926f453ba04SDave Airlie 19279440106bSJerome Glisse DRM_DEBUG_KMS("CRTC[%d] CONNECTORS[%d] ENCODERS[%d]\n", card_res->count_crtcs, 1928f453ba04SDave Airlie card_res->count_connectors, card_res->count_encoders); 1929f453ba04SDave Airlie 1930f453ba04SDave Airlie out: 1931fcf93f69SDaniel Vetter mutex_unlock(&dev->mode_config.mutex); 1932f453ba04SDave Airlie return ret; 1933f453ba04SDave Airlie } 1934f453ba04SDave Airlie 1935f453ba04SDave Airlie /** 1936f453ba04SDave Airlie * drm_mode_getcrtc - get CRTC configuration 1937065a50edSDaniel Vetter * @dev: drm device for the ioctl 1938065a50edSDaniel Vetter * @data: data pointer for the ioctl 1939065a50edSDaniel Vetter * @file_priv: drm file for the ioctl call 1940f453ba04SDave Airlie * 1941f453ba04SDave Airlie * Construct a CRTC configuration structure to return to the user. 1942f453ba04SDave Airlie * 1943f453ba04SDave Airlie * Called by the user via ioctl. 1944f453ba04SDave Airlie * 1945c8e32cc1SDaniel Vetter * Returns: 19461a498633SDaniel Vetter * Zero on success, negative errno on failure. 1947f453ba04SDave Airlie */ 1948f453ba04SDave Airlie int drm_mode_getcrtc(struct drm_device *dev, 1949f453ba04SDave Airlie void *data, struct drm_file *file_priv) 1950f453ba04SDave Airlie { 1951f453ba04SDave Airlie struct drm_mode_crtc *crtc_resp = data; 1952f453ba04SDave Airlie struct drm_crtc *crtc; 1953f453ba04SDave Airlie 1954fb3b06c8SDave Airlie if (!drm_core_check_feature(dev, DRIVER_MODESET)) 1955fb3b06c8SDave Airlie return -EINVAL; 1956fb3b06c8SDave Airlie 1957a2b34e22SRob Clark crtc = drm_crtc_find(dev, crtc_resp->crtc_id); 1958fcf93f69SDaniel Vetter if (!crtc) 1959fcf93f69SDaniel Vetter return -ENOENT; 1960f453ba04SDave Airlie 1961fcf93f69SDaniel Vetter drm_modeset_lock_crtc(crtc, crtc->primary); 1962f453ba04SDave Airlie crtc_resp->gamma_size = crtc->gamma_size; 1963f4510a27SMatt Roper if (crtc->primary->fb) 1964f4510a27SMatt Roper crtc_resp->fb_id = crtc->primary->fb->base.id; 1965f453ba04SDave Airlie else 1966f453ba04SDave Airlie crtc_resp->fb_id = 0; 1967f453ba04SDave Airlie 196831c946e8SDaniel Vetter if (crtc->state) { 196931c946e8SDaniel Vetter crtc_resp->x = crtc->primary->state->src_x >> 16; 197031c946e8SDaniel Vetter crtc_resp->y = crtc->primary->state->src_y >> 16; 197131c946e8SDaniel Vetter if (crtc->state->enable) { 1972934a8a89SDaniel Stone drm_mode_convert_to_umode(&crtc_resp->mode, &crtc->state->mode); 197331c946e8SDaniel Vetter crtc_resp->mode_valid = 1; 1974f453ba04SDave Airlie 197531c946e8SDaniel Vetter } else { 197631c946e8SDaniel Vetter crtc_resp->mode_valid = 0; 197731c946e8SDaniel Vetter } 197831c946e8SDaniel Vetter } else { 197931c946e8SDaniel Vetter crtc_resp->x = crtc->x; 198031c946e8SDaniel Vetter crtc_resp->y = crtc->y; 198131c946e8SDaniel Vetter if (crtc->enabled) { 1982934a8a89SDaniel Stone drm_mode_convert_to_umode(&crtc_resp->mode, &crtc->mode); 1983f453ba04SDave Airlie crtc_resp->mode_valid = 1; 1984f453ba04SDave Airlie 1985f453ba04SDave Airlie } else { 1986f453ba04SDave Airlie crtc_resp->mode_valid = 0; 1987f453ba04SDave Airlie } 198831c946e8SDaniel Vetter } 1989fcf93f69SDaniel Vetter drm_modeset_unlock_crtc(crtc); 1990f453ba04SDave Airlie 1991baf698b0SDaniel Vetter return 0; 1992f453ba04SDave Airlie } 1993f453ba04SDave Airlie 199461d8e328SDamien Lespiau static bool drm_mode_expose_to_userspace(const struct drm_display_mode *mode, 199561d8e328SDamien Lespiau const struct drm_file *file_priv) 199661d8e328SDamien Lespiau { 199761d8e328SDamien Lespiau /* 199861d8e328SDamien Lespiau * If user-space hasn't configured the driver to expose the stereo 3D 199961d8e328SDamien Lespiau * modes, don't expose them. 200061d8e328SDamien Lespiau */ 200161d8e328SDamien Lespiau if (!file_priv->stereo_allowed && drm_mode_is_stereo(mode)) 200261d8e328SDamien Lespiau return false; 200361d8e328SDamien Lespiau 200461d8e328SDamien Lespiau return true; 200561d8e328SDamien Lespiau } 200661d8e328SDamien Lespiau 2007abd69c55SDaniel Vetter static struct drm_encoder *drm_connector_get_encoder(struct drm_connector *connector) 2008abd69c55SDaniel Vetter { 2009abd69c55SDaniel Vetter /* For atomic drivers only state objects are synchronously updated and 2010abd69c55SDaniel Vetter * protected by modeset locks, so check those first. */ 2011abd69c55SDaniel Vetter if (connector->state) 2012abd69c55SDaniel Vetter return connector->state->best_encoder; 2013abd69c55SDaniel Vetter return connector->encoder; 2014abd69c55SDaniel Vetter } 2015abd69c55SDaniel Vetter 201695cbf110SRob Clark /* helper for getconnector and getproperties ioctls */ 201788a48e29SRob Clark static int get_properties(struct drm_mode_object *obj, bool atomic, 201895cbf110SRob Clark uint32_t __user *prop_ptr, uint64_t __user *prop_values, 201995cbf110SRob Clark uint32_t *arg_count_props) 202095cbf110SRob Clark { 202188a48e29SRob Clark int props_count; 202288a48e29SRob Clark int i, ret, copied; 202388a48e29SRob Clark 202488a48e29SRob Clark props_count = obj->properties->count; 202588a48e29SRob Clark if (!atomic) 202688a48e29SRob Clark props_count -= obj->properties->atomic_count; 202795cbf110SRob Clark 202895cbf110SRob Clark if ((*arg_count_props >= props_count) && props_count) { 202988a48e29SRob Clark for (i = 0, copied = 0; copied < props_count; i++) { 203095cbf110SRob Clark struct drm_property *prop = obj->properties->properties[i]; 203195cbf110SRob Clark uint64_t val; 203295cbf110SRob Clark 203388a48e29SRob Clark if ((prop->flags & DRM_MODE_PROP_ATOMIC) && !atomic) 203488a48e29SRob Clark continue; 203588a48e29SRob Clark 203695cbf110SRob Clark ret = drm_object_property_get_value(obj, prop, &val); 203795cbf110SRob Clark if (ret) 203895cbf110SRob Clark return ret; 203995cbf110SRob Clark 204095cbf110SRob Clark if (put_user(prop->base.id, prop_ptr + copied)) 204195cbf110SRob Clark return -EFAULT; 204295cbf110SRob Clark 204395cbf110SRob Clark if (put_user(val, prop_values + copied)) 204495cbf110SRob Clark return -EFAULT; 204595cbf110SRob Clark 204695cbf110SRob Clark copied++; 204795cbf110SRob Clark } 204895cbf110SRob Clark } 204995cbf110SRob Clark *arg_count_props = props_count; 205095cbf110SRob Clark 205195cbf110SRob Clark return 0; 205295cbf110SRob Clark } 205395cbf110SRob Clark 2054f453ba04SDave Airlie /** 2055f453ba04SDave Airlie * drm_mode_getconnector - get connector configuration 2056065a50edSDaniel Vetter * @dev: drm device for the ioctl 2057065a50edSDaniel Vetter * @data: data pointer for the ioctl 2058065a50edSDaniel Vetter * @file_priv: drm file for the ioctl call 2059f453ba04SDave Airlie * 2060f453ba04SDave Airlie * Construct a connector configuration structure to return to the user. 2061f453ba04SDave Airlie * 2062f453ba04SDave Airlie * Called by the user via ioctl. 2063f453ba04SDave Airlie * 2064c8e32cc1SDaniel Vetter * Returns: 20651a498633SDaniel Vetter * Zero on success, negative errno on failure. 2066f453ba04SDave Airlie */ 2067f453ba04SDave Airlie int drm_mode_getconnector(struct drm_device *dev, void *data, 2068f453ba04SDave Airlie struct drm_file *file_priv) 2069f453ba04SDave Airlie { 2070f453ba04SDave Airlie struct drm_mode_get_connector *out_resp = data; 2071f453ba04SDave Airlie struct drm_connector *connector; 2072abd69c55SDaniel Vetter struct drm_encoder *encoder; 2073f453ba04SDave Airlie struct drm_display_mode *mode; 2074f453ba04SDave Airlie int mode_count = 0; 2075f453ba04SDave Airlie int encoders_count = 0; 2076f453ba04SDave Airlie int ret = 0; 2077f453ba04SDave Airlie int copied = 0; 2078f453ba04SDave Airlie int i; 2079f453ba04SDave Airlie struct drm_mode_modeinfo u_mode; 2080f453ba04SDave Airlie struct drm_mode_modeinfo __user *mode_ptr; 2081f453ba04SDave Airlie uint32_t __user *encoder_ptr; 2082f453ba04SDave Airlie 2083fb3b06c8SDave Airlie if (!drm_core_check_feature(dev, DRIVER_MODESET)) 2084fb3b06c8SDave Airlie return -EINVAL; 2085fb3b06c8SDave Airlie 2086f453ba04SDave Airlie memset(&u_mode, 0, sizeof(struct drm_mode_modeinfo)); 2087f453ba04SDave Airlie 20889440106bSJerome Glisse DRM_DEBUG_KMS("[CONNECTOR:%d:?]\n", out_resp->connector_id); 2089f453ba04SDave Airlie 20907b24056bSDaniel Vetter mutex_lock(&dev->mode_config.mutex); 2091f453ba04SDave Airlie 2092a2b34e22SRob Clark connector = drm_connector_find(dev, out_resp->connector_id); 2093a2b34e22SRob Clark if (!connector) { 2094f27657f2SVille Syrjälä ret = -ENOENT; 209504bdf441STommi Rantala goto out_unlock; 2096f453ba04SDave Airlie } 2097f453ba04SDave Airlie 209801073b08SThierry Reding for (i = 0; i < DRM_CONNECTOR_MAX_ENCODER; i++) 209901073b08SThierry Reding if (connector->encoder_ids[i] != 0) 2100f453ba04SDave Airlie encoders_count++; 2101f453ba04SDave Airlie 2102f453ba04SDave Airlie if (out_resp->count_modes == 0) { 2103f453ba04SDave Airlie connector->funcs->fill_modes(connector, 2104f453ba04SDave Airlie dev->mode_config.max_width, 2105f453ba04SDave Airlie dev->mode_config.max_height); 2106f453ba04SDave Airlie } 2107f453ba04SDave Airlie 2108f453ba04SDave Airlie /* delayed so we get modes regardless of pre-fill_modes state */ 2109f453ba04SDave Airlie list_for_each_entry(mode, &connector->modes, head) 211061d8e328SDamien Lespiau if (drm_mode_expose_to_userspace(mode, file_priv)) 2111f453ba04SDave Airlie mode_count++; 2112f453ba04SDave Airlie 2113f453ba04SDave Airlie out_resp->connector_id = connector->base.id; 2114f453ba04SDave Airlie out_resp->connector_type = connector->connector_type; 2115f453ba04SDave Airlie out_resp->connector_type_id = connector->connector_type_id; 2116f453ba04SDave Airlie out_resp->mm_width = connector->display_info.width_mm; 2117f453ba04SDave Airlie out_resp->mm_height = connector->display_info.height_mm; 2118f453ba04SDave Airlie out_resp->subpixel = connector->display_info.subpixel_order; 2119f453ba04SDave Airlie out_resp->connection = connector->status; 21202caa80e7SDaniel Vetter 21212caa80e7SDaniel Vetter drm_modeset_lock(&dev->mode_config.connection_mutex, NULL); 2122abd69c55SDaniel Vetter encoder = drm_connector_get_encoder(connector); 2123abd69c55SDaniel Vetter if (encoder) 2124abd69c55SDaniel Vetter out_resp->encoder_id = encoder->base.id; 2125f453ba04SDave Airlie else 2126f453ba04SDave Airlie out_resp->encoder_id = 0; 2127f453ba04SDave Airlie 2128f453ba04SDave Airlie /* 2129f453ba04SDave Airlie * This ioctl is called twice, once to determine how much space is 2130f453ba04SDave Airlie * needed, and the 2nd time to fill it. 2131f453ba04SDave Airlie */ 2132f453ba04SDave Airlie if ((out_resp->count_modes >= mode_count) && mode_count) { 2133f453ba04SDave Airlie copied = 0; 213481f6c7f8SVille Syrjälä mode_ptr = (struct drm_mode_modeinfo __user *)(unsigned long)out_resp->modes_ptr; 2135f453ba04SDave Airlie list_for_each_entry(mode, &connector->modes, head) { 213661d8e328SDamien Lespiau if (!drm_mode_expose_to_userspace(mode, file_priv)) 213761d8e328SDamien Lespiau continue; 213861d8e328SDamien Lespiau 2139934a8a89SDaniel Stone drm_mode_convert_to_umode(&u_mode, mode); 2140f453ba04SDave Airlie if (copy_to_user(mode_ptr + copied, 2141f453ba04SDave Airlie &u_mode, sizeof(u_mode))) { 2142f453ba04SDave Airlie ret = -EFAULT; 2143f453ba04SDave Airlie goto out; 2144f453ba04SDave Airlie } 2145f453ba04SDave Airlie copied++; 2146f453ba04SDave Airlie } 2147f453ba04SDave Airlie } 2148f453ba04SDave Airlie out_resp->count_modes = mode_count; 2149f453ba04SDave Airlie 215088a48e29SRob Clark ret = get_properties(&connector->base, file_priv->atomic, 215195cbf110SRob Clark (uint32_t __user *)(unsigned long)(out_resp->props_ptr), 215295cbf110SRob Clark (uint64_t __user *)(unsigned long)(out_resp->prop_values_ptr), 215395cbf110SRob Clark &out_resp->count_props); 215422b8b13bSRob Clark if (ret) 2155f453ba04SDave Airlie goto out; 2156f453ba04SDave Airlie 2157f453ba04SDave Airlie if ((out_resp->count_encoders >= encoders_count) && encoders_count) { 2158f453ba04SDave Airlie copied = 0; 215981f6c7f8SVille Syrjälä encoder_ptr = (uint32_t __user *)(unsigned long)(out_resp->encoders_ptr); 2160f453ba04SDave Airlie for (i = 0; i < DRM_CONNECTOR_MAX_ENCODER; i++) { 2161f453ba04SDave Airlie if (connector->encoder_ids[i] != 0) { 2162f453ba04SDave Airlie if (put_user(connector->encoder_ids[i], 2163f453ba04SDave Airlie encoder_ptr + copied)) { 2164f453ba04SDave Airlie ret = -EFAULT; 2165f453ba04SDave Airlie goto out; 2166f453ba04SDave Airlie } 2167f453ba04SDave Airlie copied++; 2168f453ba04SDave Airlie } 2169f453ba04SDave Airlie } 2170f453ba04SDave Airlie } 2171f453ba04SDave Airlie out_resp->count_encoders = encoders_count; 2172f453ba04SDave Airlie 2173f453ba04SDave Airlie out: 2174ccfc0865SRob Clark drm_modeset_unlock(&dev->mode_config.connection_mutex); 217504bdf441STommi Rantala 217604bdf441STommi Rantala out_unlock: 21777b24056bSDaniel Vetter mutex_unlock(&dev->mode_config.mutex); 21787b24056bSDaniel Vetter 2179f453ba04SDave Airlie return ret; 2180f453ba04SDave Airlie } 2181f453ba04SDave Airlie 2182abd69c55SDaniel Vetter static struct drm_crtc *drm_encoder_get_crtc(struct drm_encoder *encoder) 2183abd69c55SDaniel Vetter { 2184abd69c55SDaniel Vetter struct drm_connector *connector; 2185abd69c55SDaniel Vetter struct drm_device *dev = encoder->dev; 2186abd69c55SDaniel Vetter bool uses_atomic = false; 2187abd69c55SDaniel Vetter 2188abd69c55SDaniel Vetter /* For atomic drivers only state objects are synchronously updated and 2189abd69c55SDaniel Vetter * protected by modeset locks, so check those first. */ 2190abd69c55SDaniel Vetter list_for_each_entry(connector, &dev->mode_config.connector_list, head) { 2191abd69c55SDaniel Vetter if (!connector->state) 2192abd69c55SDaniel Vetter continue; 2193abd69c55SDaniel Vetter 2194abd69c55SDaniel Vetter uses_atomic = true; 2195abd69c55SDaniel Vetter 2196abd69c55SDaniel Vetter if (connector->state->best_encoder != encoder) 2197abd69c55SDaniel Vetter continue; 2198abd69c55SDaniel Vetter 2199abd69c55SDaniel Vetter return connector->state->crtc; 2200abd69c55SDaniel Vetter } 2201abd69c55SDaniel Vetter 2202abd69c55SDaniel Vetter /* Don't return stale data (e.g. pending async disable). */ 2203abd69c55SDaniel Vetter if (uses_atomic) 2204abd69c55SDaniel Vetter return NULL; 2205abd69c55SDaniel Vetter 2206abd69c55SDaniel Vetter return encoder->crtc; 2207abd69c55SDaniel Vetter } 2208abd69c55SDaniel Vetter 2209c8e32cc1SDaniel Vetter /** 2210c8e32cc1SDaniel Vetter * drm_mode_getencoder - get encoder configuration 2211c8e32cc1SDaniel Vetter * @dev: drm device for the ioctl 2212c8e32cc1SDaniel Vetter * @data: data pointer for the ioctl 2213c8e32cc1SDaniel Vetter * @file_priv: drm file for the ioctl call 2214c8e32cc1SDaniel Vetter * 2215c8e32cc1SDaniel Vetter * Construct a encoder configuration structure to return to the user. 2216c8e32cc1SDaniel Vetter * 2217c8e32cc1SDaniel Vetter * Called by the user via ioctl. 2218c8e32cc1SDaniel Vetter * 2219c8e32cc1SDaniel Vetter * Returns: 22201a498633SDaniel Vetter * Zero on success, negative errno on failure. 2221c8e32cc1SDaniel Vetter */ 2222f453ba04SDave Airlie int drm_mode_getencoder(struct drm_device *dev, void *data, 2223f453ba04SDave Airlie struct drm_file *file_priv) 2224f453ba04SDave Airlie { 2225f453ba04SDave Airlie struct drm_mode_get_encoder *enc_resp = data; 2226f453ba04SDave Airlie struct drm_encoder *encoder; 2227abd69c55SDaniel Vetter struct drm_crtc *crtc; 2228f453ba04SDave Airlie 2229fb3b06c8SDave Airlie if (!drm_core_check_feature(dev, DRIVER_MODESET)) 2230fb3b06c8SDave Airlie return -EINVAL; 2231fb3b06c8SDave Airlie 2232a2b34e22SRob Clark encoder = drm_encoder_find(dev, enc_resp->encoder_id); 2233fcf93f69SDaniel Vetter if (!encoder) 2234fcf93f69SDaniel Vetter return -ENOENT; 2235f453ba04SDave Airlie 2236fcf93f69SDaniel Vetter drm_modeset_lock(&dev->mode_config.connection_mutex, NULL); 2237abd69c55SDaniel Vetter crtc = drm_encoder_get_crtc(encoder); 2238abd69c55SDaniel Vetter if (crtc) 2239abd69c55SDaniel Vetter enc_resp->crtc_id = crtc->base.id; 2240f453ba04SDave Airlie else 2241f453ba04SDave Airlie enc_resp->crtc_id = 0; 2242fcf93f69SDaniel Vetter drm_modeset_unlock(&dev->mode_config.connection_mutex); 2243fcf93f69SDaniel Vetter 2244f453ba04SDave Airlie enc_resp->encoder_type = encoder->encoder_type; 2245f453ba04SDave Airlie enc_resp->encoder_id = encoder->base.id; 2246f453ba04SDave Airlie enc_resp->possible_crtcs = encoder->possible_crtcs; 2247f453ba04SDave Airlie enc_resp->possible_clones = encoder->possible_clones; 2248f453ba04SDave Airlie 2249baf698b0SDaniel Vetter return 0; 2250f453ba04SDave Airlie } 2251f453ba04SDave Airlie 2252f453ba04SDave Airlie /** 2253c8e32cc1SDaniel Vetter * drm_mode_getplane_res - enumerate all plane resources 22548cf5c917SJesse Barnes * @dev: DRM device 22558cf5c917SJesse Barnes * @data: ioctl data 22568cf5c917SJesse Barnes * @file_priv: DRM file info 22578cf5c917SJesse Barnes * 2258c8e32cc1SDaniel Vetter * Construct a list of plane ids to return to the user. 2259c8e32cc1SDaniel Vetter * 2260c8e32cc1SDaniel Vetter * Called by the user via ioctl. 2261c8e32cc1SDaniel Vetter * 2262c8e32cc1SDaniel Vetter * Returns: 22631a498633SDaniel Vetter * Zero on success, negative errno on failure. 22648cf5c917SJesse Barnes */ 22658cf5c917SJesse Barnes int drm_mode_getplane_res(struct drm_device *dev, void *data, 22668cf5c917SJesse Barnes struct drm_file *file_priv) 22678cf5c917SJesse Barnes { 22688cf5c917SJesse Barnes struct drm_mode_get_plane_res *plane_resp = data; 22698cf5c917SJesse Barnes struct drm_mode_config *config; 22708cf5c917SJesse Barnes struct drm_plane *plane; 22718cf5c917SJesse Barnes uint32_t __user *plane_ptr; 2272fcf93f69SDaniel Vetter int copied = 0; 2273681e7ec7SMatt Roper unsigned num_planes; 22748cf5c917SJesse Barnes 22758cf5c917SJesse Barnes if (!drm_core_check_feature(dev, DRIVER_MODESET)) 22768cf5c917SJesse Barnes return -EINVAL; 22778cf5c917SJesse Barnes 22788cf5c917SJesse Barnes config = &dev->mode_config; 22798cf5c917SJesse Barnes 2280681e7ec7SMatt Roper if (file_priv->universal_planes) 2281681e7ec7SMatt Roper num_planes = config->num_total_plane; 2282681e7ec7SMatt Roper else 2283681e7ec7SMatt Roper num_planes = config->num_overlay_plane; 2284681e7ec7SMatt Roper 22858cf5c917SJesse Barnes /* 22868cf5c917SJesse Barnes * This ioctl is called twice, once to determine how much space is 22878cf5c917SJesse Barnes * needed, and the 2nd time to fill it. 22888cf5c917SJesse Barnes */ 2289681e7ec7SMatt Roper if (num_planes && 2290681e7ec7SMatt Roper (plane_resp->count_planes >= num_planes)) { 229181f6c7f8SVille Syrjälä plane_ptr = (uint32_t __user *)(unsigned long)plane_resp->plane_id_ptr; 22928cf5c917SJesse Barnes 2293fcf93f69SDaniel Vetter /* Plane lists are invariant, no locking needed. */ 22948cf5c917SJesse Barnes list_for_each_entry(plane, &config->plane_list, head) { 2295681e7ec7SMatt Roper /* 2296681e7ec7SMatt Roper * Unless userspace set the 'universal planes' 2297681e7ec7SMatt Roper * capability bit, only advertise overlays. 2298681e7ec7SMatt Roper */ 2299681e7ec7SMatt Roper if (plane->type != DRM_PLANE_TYPE_OVERLAY && 2300681e7ec7SMatt Roper !file_priv->universal_planes) 2301e27dde3eSMatt Roper continue; 2302e27dde3eSMatt Roper 2303fcf93f69SDaniel Vetter if (put_user(plane->base.id, plane_ptr + copied)) 2304fcf93f69SDaniel Vetter return -EFAULT; 23058cf5c917SJesse Barnes copied++; 23068cf5c917SJesse Barnes } 23078cf5c917SJesse Barnes } 2308681e7ec7SMatt Roper plane_resp->count_planes = num_planes; 23098cf5c917SJesse Barnes 2310fcf93f69SDaniel Vetter return 0; 23118cf5c917SJesse Barnes } 23128cf5c917SJesse Barnes 23138cf5c917SJesse Barnes /** 2314c8e32cc1SDaniel Vetter * drm_mode_getplane - get plane configuration 23158cf5c917SJesse Barnes * @dev: DRM device 23168cf5c917SJesse Barnes * @data: ioctl data 23178cf5c917SJesse Barnes * @file_priv: DRM file info 23188cf5c917SJesse Barnes * 2319c8e32cc1SDaniel Vetter * Construct a plane configuration structure to return to the user. 2320c8e32cc1SDaniel Vetter * 2321c8e32cc1SDaniel Vetter * Called by the user via ioctl. 2322c8e32cc1SDaniel Vetter * 2323c8e32cc1SDaniel Vetter * Returns: 23241a498633SDaniel Vetter * Zero on success, negative errno on failure. 23258cf5c917SJesse Barnes */ 23268cf5c917SJesse Barnes int drm_mode_getplane(struct drm_device *dev, void *data, 23278cf5c917SJesse Barnes struct drm_file *file_priv) 23288cf5c917SJesse Barnes { 23298cf5c917SJesse Barnes struct drm_mode_get_plane *plane_resp = data; 23308cf5c917SJesse Barnes struct drm_plane *plane; 23318cf5c917SJesse Barnes uint32_t __user *format_ptr; 23328cf5c917SJesse Barnes 23338cf5c917SJesse Barnes if (!drm_core_check_feature(dev, DRIVER_MODESET)) 23348cf5c917SJesse Barnes return -EINVAL; 23358cf5c917SJesse Barnes 2336a2b34e22SRob Clark plane = drm_plane_find(dev, plane_resp->plane_id); 2337fcf93f69SDaniel Vetter if (!plane) 2338fcf93f69SDaniel Vetter return -ENOENT; 23398cf5c917SJesse Barnes 2340fcf93f69SDaniel Vetter drm_modeset_lock(&plane->mutex, NULL); 23418cf5c917SJesse Barnes if (plane->crtc) 23428cf5c917SJesse Barnes plane_resp->crtc_id = plane->crtc->base.id; 23438cf5c917SJesse Barnes else 23448cf5c917SJesse Barnes plane_resp->crtc_id = 0; 23458cf5c917SJesse Barnes 23468cf5c917SJesse Barnes if (plane->fb) 23478cf5c917SJesse Barnes plane_resp->fb_id = plane->fb->base.id; 23488cf5c917SJesse Barnes else 23498cf5c917SJesse Barnes plane_resp->fb_id = 0; 2350fcf93f69SDaniel Vetter drm_modeset_unlock(&plane->mutex); 23518cf5c917SJesse Barnes 23528cf5c917SJesse Barnes plane_resp->plane_id = plane->base.id; 23538cf5c917SJesse Barnes plane_resp->possible_crtcs = plane->possible_crtcs; 2354778ad903SVille Syrjälä plane_resp->gamma_size = 0; 23558cf5c917SJesse Barnes 23568cf5c917SJesse Barnes /* 23578cf5c917SJesse Barnes * This ioctl is called twice, once to determine how much space is 23588cf5c917SJesse Barnes * needed, and the 2nd time to fill it. 23598cf5c917SJesse Barnes */ 23608cf5c917SJesse Barnes if (plane->format_count && 23618cf5c917SJesse Barnes (plane_resp->count_format_types >= plane->format_count)) { 236281f6c7f8SVille Syrjälä format_ptr = (uint32_t __user *)(unsigned long)plane_resp->format_type_ptr; 23638cf5c917SJesse Barnes if (copy_to_user(format_ptr, 23648cf5c917SJesse Barnes plane->format_types, 23658cf5c917SJesse Barnes sizeof(uint32_t) * plane->format_count)) { 2366fcf93f69SDaniel Vetter return -EFAULT; 23678cf5c917SJesse Barnes } 23688cf5c917SJesse Barnes } 23698cf5c917SJesse Barnes plane_resp->count_format_types = plane->format_count; 23708cf5c917SJesse Barnes 2371baf698b0SDaniel Vetter return 0; 23728cf5c917SJesse Barnes } 23738cf5c917SJesse Barnes 2374ead8610dSLaurent Pinchart /** 2375ead8610dSLaurent Pinchart * drm_plane_check_pixel_format - Check if the plane supports the pixel format 2376ead8610dSLaurent Pinchart * @plane: plane to check for format support 2377ead8610dSLaurent Pinchart * @format: the pixel format 2378ead8610dSLaurent Pinchart * 2379ead8610dSLaurent Pinchart * Returns: 2380ead8610dSLaurent Pinchart * Zero of @plane has @format in its list of supported pixel formats, -EINVAL 2381ead8610dSLaurent Pinchart * otherwise. 2382ead8610dSLaurent Pinchart */ 2383ead8610dSLaurent Pinchart int drm_plane_check_pixel_format(const struct drm_plane *plane, u32 format) 2384ead8610dSLaurent Pinchart { 2385ead8610dSLaurent Pinchart unsigned int i; 2386ead8610dSLaurent Pinchart 2387ead8610dSLaurent Pinchart for (i = 0; i < plane->format_count; i++) { 2388ead8610dSLaurent Pinchart if (format == plane->format_types[i]) 2389ead8610dSLaurent Pinchart return 0; 2390ead8610dSLaurent Pinchart } 2391ead8610dSLaurent Pinchart 2392ead8610dSLaurent Pinchart return -EINVAL; 2393ead8610dSLaurent Pinchart } 2394ead8610dSLaurent Pinchart 2395b36552b3SMatt Roper /* 2396b36552b3SMatt Roper * setplane_internal - setplane handler for internal callers 23978cf5c917SJesse Barnes * 2398b36552b3SMatt Roper * Note that we assume an extra reference has already been taken on fb. If the 2399b36552b3SMatt Roper * update fails, this reference will be dropped before return; if it succeeds, 2400b36552b3SMatt Roper * the previous framebuffer (if any) will be unreferenced instead. 2401c8e32cc1SDaniel Vetter * 2402b36552b3SMatt Roper * src_{x,y,w,h} are provided in 16.16 fixed point format 24038cf5c917SJesse Barnes */ 2404f2b50c11SDaniel Vetter static int __setplane_internal(struct drm_plane *plane, 240517cfd91fSChris Wilson struct drm_crtc *crtc, 2406b36552b3SMatt Roper struct drm_framebuffer *fb, 2407b36552b3SMatt Roper int32_t crtc_x, int32_t crtc_y, 2408b36552b3SMatt Roper uint32_t crtc_w, uint32_t crtc_h, 2409b36552b3SMatt Roper /* src_{x,y,w,h} values are 16.16 fixed point */ 2410b36552b3SMatt Roper uint32_t src_x, uint32_t src_y, 2411b36552b3SMatt Roper uint32_t src_w, uint32_t src_h) 24128cf5c917SJesse Barnes { 24138cf5c917SJesse Barnes int ret = 0; 241442ef8789SVille Syrjälä unsigned int fb_width, fb_height; 24158cf5c917SJesse Barnes 24168cf5c917SJesse Barnes /* No fb means shut it down */ 2417b36552b3SMatt Roper if (!fb) { 24183d30a59bSDaniel Vetter plane->old_fb = plane->fb; 2419731cce48SDaniel Vetter ret = plane->funcs->disable_plane(plane); 2420731cce48SDaniel Vetter if (!ret) { 2421e5e3b44cSVille Syrjälä plane->crtc = NULL; 2422e5e3b44cSVille Syrjälä plane->fb = NULL; 2423731cce48SDaniel Vetter } else { 24243d30a59bSDaniel Vetter plane->old_fb = NULL; 2425731cce48SDaniel Vetter } 24268cf5c917SJesse Barnes goto out; 24278cf5c917SJesse Barnes } 24288cf5c917SJesse Barnes 24297f994f3fSMatt Roper /* Check whether this plane is usable on this CRTC */ 24307f994f3fSMatt Roper if (!(plane->possible_crtcs & drm_crtc_mask(crtc))) { 24317f994f3fSMatt Roper DRM_DEBUG_KMS("Invalid crtc for plane\n"); 24327f994f3fSMatt Roper ret = -EINVAL; 24337f994f3fSMatt Roper goto out; 24347f994f3fSMatt Roper } 24357f994f3fSMatt Roper 243662443be6SVille Syrjälä /* Check whether this plane supports the fb pixel format. */ 2437ead8610dSLaurent Pinchart ret = drm_plane_check_pixel_format(plane, fb->pixel_format); 2438ead8610dSLaurent Pinchart if (ret) { 24396ba6d03eSVille Syrjälä DRM_DEBUG_KMS("Invalid pixel format %s\n", 24406ba6d03eSVille Syrjälä drm_get_format_name(fb->pixel_format)); 244162443be6SVille Syrjälä goto out; 244262443be6SVille Syrjälä } 244362443be6SVille Syrjälä 24443968be94SMatt Roper /* Give drivers some help against integer overflows */ 24453968be94SMatt Roper if (crtc_w > INT_MAX || 24463968be94SMatt Roper crtc_x > INT_MAX - (int32_t) crtc_w || 24473968be94SMatt Roper crtc_h > INT_MAX || 24483968be94SMatt Roper crtc_y > INT_MAX - (int32_t) crtc_h) { 24493968be94SMatt Roper DRM_DEBUG_KMS("Invalid CRTC coordinates %ux%u+%d+%d\n", 24503968be94SMatt Roper crtc_w, crtc_h, crtc_x, crtc_y); 24513968be94SMatt Roper return -ERANGE; 24523968be94SMatt Roper } 24533968be94SMatt Roper 24543968be94SMatt Roper 245542ef8789SVille Syrjälä fb_width = fb->width << 16; 245642ef8789SVille Syrjälä fb_height = fb->height << 16; 245742ef8789SVille Syrjälä 245842ef8789SVille Syrjälä /* Make sure source coordinates are inside the fb. */ 2459b36552b3SMatt Roper if (src_w > fb_width || 2460b36552b3SMatt Roper src_x > fb_width - src_w || 2461b36552b3SMatt Roper src_h > fb_height || 2462b36552b3SMatt Roper src_y > fb_height - src_h) { 246342ef8789SVille Syrjälä DRM_DEBUG_KMS("Invalid source coordinates " 246442ef8789SVille Syrjälä "%u.%06ux%u.%06u+%u.%06u+%u.%06u\n", 2465b36552b3SMatt Roper src_w >> 16, ((src_w & 0xffff) * 15625) >> 10, 2466b36552b3SMatt Roper src_h >> 16, ((src_h & 0xffff) * 15625) >> 10, 2467b36552b3SMatt Roper src_x >> 16, ((src_x & 0xffff) * 15625) >> 10, 2468b36552b3SMatt Roper src_y >> 16, ((src_y & 0xffff) * 15625) >> 10); 246942ef8789SVille Syrjälä ret = -ENOSPC; 247042ef8789SVille Syrjälä goto out; 247142ef8789SVille Syrjälä } 247242ef8789SVille Syrjälä 24733d30a59bSDaniel Vetter plane->old_fb = plane->fb; 24748cf5c917SJesse Barnes ret = plane->funcs->update_plane(plane, crtc, fb, 2475b36552b3SMatt Roper crtc_x, crtc_y, crtc_w, crtc_h, 2476b36552b3SMatt Roper src_x, src_y, src_w, src_h); 24778cf5c917SJesse Barnes if (!ret) { 24788cf5c917SJesse Barnes plane->crtc = crtc; 24798cf5c917SJesse Barnes plane->fb = fb; 248035f8badcSDaniel Vetter fb = NULL; 24810fe27f06SDaniel Vetter } else { 24823d30a59bSDaniel Vetter plane->old_fb = NULL; 24838cf5c917SJesse Barnes } 24848cf5c917SJesse Barnes 24858cf5c917SJesse Barnes out: 24866c2a7532SDaniel Vetter if (fb) 24876c2a7532SDaniel Vetter drm_framebuffer_unreference(fb); 24883d30a59bSDaniel Vetter if (plane->old_fb) 24893d30a59bSDaniel Vetter drm_framebuffer_unreference(plane->old_fb); 24903d30a59bSDaniel Vetter plane->old_fb = NULL; 24918cf5c917SJesse Barnes 24928cf5c917SJesse Barnes return ret; 2493f2b50c11SDaniel Vetter } 2494b36552b3SMatt Roper 2495f2b50c11SDaniel Vetter static int setplane_internal(struct drm_plane *plane, 2496f2b50c11SDaniel Vetter struct drm_crtc *crtc, 2497f2b50c11SDaniel Vetter struct drm_framebuffer *fb, 2498f2b50c11SDaniel Vetter int32_t crtc_x, int32_t crtc_y, 2499f2b50c11SDaniel Vetter uint32_t crtc_w, uint32_t crtc_h, 2500f2b50c11SDaniel Vetter /* src_{x,y,w,h} values are 16.16 fixed point */ 2501f2b50c11SDaniel Vetter uint32_t src_x, uint32_t src_y, 2502f2b50c11SDaniel Vetter uint32_t src_w, uint32_t src_h) 2503f2b50c11SDaniel Vetter { 2504f2b50c11SDaniel Vetter int ret; 2505f2b50c11SDaniel Vetter 2506f2b50c11SDaniel Vetter drm_modeset_lock_all(plane->dev); 2507f2b50c11SDaniel Vetter ret = __setplane_internal(plane, crtc, fb, 2508f2b50c11SDaniel Vetter crtc_x, crtc_y, crtc_w, crtc_h, 2509f2b50c11SDaniel Vetter src_x, src_y, src_w, src_h); 2510f2b50c11SDaniel Vetter drm_modeset_unlock_all(plane->dev); 2511f2b50c11SDaniel Vetter 2512f2b50c11SDaniel Vetter return ret; 2513b36552b3SMatt Roper } 2514b36552b3SMatt Roper 2515b36552b3SMatt Roper /** 2516b36552b3SMatt Roper * drm_mode_setplane - configure a plane's configuration 2517b36552b3SMatt Roper * @dev: DRM device 2518b36552b3SMatt Roper * @data: ioctl data* 2519b36552b3SMatt Roper * @file_priv: DRM file info 2520b36552b3SMatt Roper * 2521b36552b3SMatt Roper * Set plane configuration, including placement, fb, scaling, and other factors. 2522b36552b3SMatt Roper * Or pass a NULL fb to disable (planes may be disabled without providing a 2523b36552b3SMatt Roper * valid crtc). 2524b36552b3SMatt Roper * 2525b36552b3SMatt Roper * Returns: 25261a498633SDaniel Vetter * Zero on success, negative errno on failure. 2527b36552b3SMatt Roper */ 2528b36552b3SMatt Roper int drm_mode_setplane(struct drm_device *dev, void *data, 2529b36552b3SMatt Roper struct drm_file *file_priv) 2530b36552b3SMatt Roper { 2531b36552b3SMatt Roper struct drm_mode_set_plane *plane_req = data; 2532b36552b3SMatt Roper struct drm_plane *plane; 2533b36552b3SMatt Roper struct drm_crtc *crtc = NULL; 2534b36552b3SMatt Roper struct drm_framebuffer *fb = NULL; 2535b36552b3SMatt Roper 2536b36552b3SMatt Roper if (!drm_core_check_feature(dev, DRIVER_MODESET)) 2537b36552b3SMatt Roper return -EINVAL; 2538b36552b3SMatt Roper 2539b36552b3SMatt Roper /* 2540b36552b3SMatt Roper * First, find the plane, crtc, and fb objects. If not available, 2541b36552b3SMatt Roper * we don't bother to call the driver. 2542b36552b3SMatt Roper */ 2543933f622fSRob Clark plane = drm_plane_find(dev, plane_req->plane_id); 2544933f622fSRob Clark if (!plane) { 2545b36552b3SMatt Roper DRM_DEBUG_KMS("Unknown plane ID %d\n", 2546b36552b3SMatt Roper plane_req->plane_id); 2547b36552b3SMatt Roper return -ENOENT; 2548b36552b3SMatt Roper } 2549b36552b3SMatt Roper 2550b36552b3SMatt Roper if (plane_req->fb_id) { 2551b36552b3SMatt Roper fb = drm_framebuffer_lookup(dev, plane_req->fb_id); 2552b36552b3SMatt Roper if (!fb) { 2553b36552b3SMatt Roper DRM_DEBUG_KMS("Unknown framebuffer ID %d\n", 2554b36552b3SMatt Roper plane_req->fb_id); 2555b36552b3SMatt Roper return -ENOENT; 2556b36552b3SMatt Roper } 2557b36552b3SMatt Roper 2558933f622fSRob Clark crtc = drm_crtc_find(dev, plane_req->crtc_id); 2559933f622fSRob Clark if (!crtc) { 2560b36552b3SMatt Roper DRM_DEBUG_KMS("Unknown crtc ID %d\n", 2561b36552b3SMatt Roper plane_req->crtc_id); 2562b36552b3SMatt Roper return -ENOENT; 2563b36552b3SMatt Roper } 2564b36552b3SMatt Roper } 2565b36552b3SMatt Roper 2566161d0dc1SMatt Roper /* 2567161d0dc1SMatt Roper * setplane_internal will take care of deref'ing either the old or new 2568161d0dc1SMatt Roper * framebuffer depending on success. 2569161d0dc1SMatt Roper */ 257017cfd91fSChris Wilson return setplane_internal(plane, crtc, fb, 2571b36552b3SMatt Roper plane_req->crtc_x, plane_req->crtc_y, 2572b36552b3SMatt Roper plane_req->crtc_w, plane_req->crtc_h, 2573b36552b3SMatt Roper plane_req->src_x, plane_req->src_y, 2574b36552b3SMatt Roper plane_req->src_w, plane_req->src_h); 25758cf5c917SJesse Barnes } 25768cf5c917SJesse Barnes 25778cf5c917SJesse Barnes /** 25782d13b679SDaniel Vetter * drm_mode_set_config_internal - helper to call ->set_config 25792d13b679SDaniel Vetter * @set: modeset config to set 25802d13b679SDaniel Vetter * 25812d13b679SDaniel Vetter * This is a little helper to wrap internal calls to the ->set_config driver 25822d13b679SDaniel Vetter * interface. The only thing it adds is correct refcounting dance. 2583c8e32cc1SDaniel Vetter * 2584c8e32cc1SDaniel Vetter * Returns: 25851a498633SDaniel Vetter * Zero on success, negative errno on failure. 25862d13b679SDaniel Vetter */ 25872d13b679SDaniel Vetter int drm_mode_set_config_internal(struct drm_mode_set *set) 25882d13b679SDaniel Vetter { 25892d13b679SDaniel Vetter struct drm_crtc *crtc = set->crtc; 25905cef29aaSDaniel Vetter struct drm_framebuffer *fb; 25915cef29aaSDaniel Vetter struct drm_crtc *tmp; 2592b0d12325SDaniel Vetter int ret; 25932d13b679SDaniel Vetter 25945cef29aaSDaniel Vetter /* 25955cef29aaSDaniel Vetter * NOTE: ->set_config can also disable other crtcs (if we steal all 25965cef29aaSDaniel Vetter * connectors from it), hence we need to refcount the fbs across all 25975cef29aaSDaniel Vetter * crtcs. Atomic modeset will have saner semantics ... 25985cef29aaSDaniel Vetter */ 25995cef29aaSDaniel Vetter list_for_each_entry(tmp, &crtc->dev->mode_config.crtc_list, head) 26003d30a59bSDaniel Vetter tmp->primary->old_fb = tmp->primary->fb; 26015cef29aaSDaniel Vetter 2602b0d12325SDaniel Vetter fb = set->fb; 2603b0d12325SDaniel Vetter 2604b0d12325SDaniel Vetter ret = crtc->funcs->set_config(set); 2605b0d12325SDaniel Vetter if (ret == 0) { 2606e13161afSMatt Roper crtc->primary->crtc = crtc; 26070fe27f06SDaniel Vetter crtc->primary->fb = fb; 26085cef29aaSDaniel Vetter } 2609cc85e121SDaniel Vetter 26105cef29aaSDaniel Vetter list_for_each_entry(tmp, &crtc->dev->mode_config.crtc_list, head) { 2611f4510a27SMatt Roper if (tmp->primary->fb) 2612f4510a27SMatt Roper drm_framebuffer_reference(tmp->primary->fb); 26133d30a59bSDaniel Vetter if (tmp->primary->old_fb) 26143d30a59bSDaniel Vetter drm_framebuffer_unreference(tmp->primary->old_fb); 26153d30a59bSDaniel Vetter tmp->primary->old_fb = NULL; 2616b0d12325SDaniel Vetter } 2617b0d12325SDaniel Vetter 2618b0d12325SDaniel Vetter return ret; 26192d13b679SDaniel Vetter } 26202d13b679SDaniel Vetter EXPORT_SYMBOL(drm_mode_set_config_internal); 26212d13b679SDaniel Vetter 2622af93629dSMatt Roper /** 2623ecb7e16bSGustavo Padovan * drm_crtc_get_hv_timing - Fetches hdisplay/vdisplay for given mode 2624ecb7e16bSGustavo Padovan * @mode: mode to query 2625ecb7e16bSGustavo Padovan * @hdisplay: hdisplay value to fill in 2626ecb7e16bSGustavo Padovan * @vdisplay: vdisplay value to fill in 2627ecb7e16bSGustavo Padovan * 2628ecb7e16bSGustavo Padovan * The vdisplay value will be doubled if the specified mode is a stereo mode of 2629ecb7e16bSGustavo Padovan * the appropriate layout. 2630ecb7e16bSGustavo Padovan */ 2631ecb7e16bSGustavo Padovan void drm_crtc_get_hv_timing(const struct drm_display_mode *mode, 2632ecb7e16bSGustavo Padovan int *hdisplay, int *vdisplay) 2633ecb7e16bSGustavo Padovan { 2634ecb7e16bSGustavo Padovan struct drm_display_mode adjusted; 2635ecb7e16bSGustavo Padovan 2636ecb7e16bSGustavo Padovan drm_mode_copy(&adjusted, mode); 2637ecb7e16bSGustavo Padovan drm_mode_set_crtcinfo(&adjusted, CRTC_STEREO_DOUBLE_ONLY); 2638ecb7e16bSGustavo Padovan *hdisplay = adjusted.crtc_hdisplay; 2639ecb7e16bSGustavo Padovan *vdisplay = adjusted.crtc_vdisplay; 2640ecb7e16bSGustavo Padovan } 2641ecb7e16bSGustavo Padovan EXPORT_SYMBOL(drm_crtc_get_hv_timing); 2642ecb7e16bSGustavo Padovan 2643ecb7e16bSGustavo Padovan /** 2644af93629dSMatt Roper * drm_crtc_check_viewport - Checks that a framebuffer is big enough for the 2645af93629dSMatt Roper * CRTC viewport 2646af93629dSMatt Roper * @crtc: CRTC that framebuffer will be displayed on 2647af93629dSMatt Roper * @x: x panning 2648af93629dSMatt Roper * @y: y panning 2649af93629dSMatt Roper * @mode: mode that framebuffer will be displayed under 2650af93629dSMatt Roper * @fb: framebuffer to check size of 2651c11e9283SDamien Lespiau */ 2652af93629dSMatt Roper int drm_crtc_check_viewport(const struct drm_crtc *crtc, 2653c11e9283SDamien Lespiau int x, int y, 2654c11e9283SDamien Lespiau const struct drm_display_mode *mode, 2655c11e9283SDamien Lespiau const struct drm_framebuffer *fb) 2656c11e9283SDamien Lespiau 2657c11e9283SDamien Lespiau { 2658c11e9283SDamien Lespiau int hdisplay, vdisplay; 2659c11e9283SDamien Lespiau 2660ecb7e16bSGustavo Padovan drm_crtc_get_hv_timing(mode, &hdisplay, &vdisplay); 2661a0c1bbb0SDamien Lespiau 2662c11e9283SDamien Lespiau if (crtc->invert_dimensions) 2663c11e9283SDamien Lespiau swap(hdisplay, vdisplay); 2664c11e9283SDamien Lespiau 2665c11e9283SDamien Lespiau if (hdisplay > fb->width || 2666c11e9283SDamien Lespiau vdisplay > fb->height || 2667c11e9283SDamien Lespiau x > fb->width - hdisplay || 2668c11e9283SDamien Lespiau y > fb->height - vdisplay) { 2669c11e9283SDamien Lespiau DRM_DEBUG_KMS("Invalid fb size %ux%u for CRTC viewport %ux%u+%d+%d%s.\n", 2670c11e9283SDamien Lespiau fb->width, fb->height, hdisplay, vdisplay, x, y, 2671c11e9283SDamien Lespiau crtc->invert_dimensions ? " (inverted)" : ""); 2672c11e9283SDamien Lespiau return -ENOSPC; 2673c11e9283SDamien Lespiau } 2674c11e9283SDamien Lespiau 2675c11e9283SDamien Lespiau return 0; 2676c11e9283SDamien Lespiau } 2677af93629dSMatt Roper EXPORT_SYMBOL(drm_crtc_check_viewport); 2678c11e9283SDamien Lespiau 26792d13b679SDaniel Vetter /** 2680f453ba04SDave Airlie * drm_mode_setcrtc - set CRTC configuration 2681065a50edSDaniel Vetter * @dev: drm device for the ioctl 2682065a50edSDaniel Vetter * @data: data pointer for the ioctl 2683065a50edSDaniel Vetter * @file_priv: drm file for the ioctl call 2684f453ba04SDave Airlie * 2685f453ba04SDave Airlie * Build a new CRTC configuration based on user request. 2686f453ba04SDave Airlie * 2687f453ba04SDave Airlie * Called by the user via ioctl. 2688f453ba04SDave Airlie * 2689c8e32cc1SDaniel Vetter * Returns: 26901a498633SDaniel Vetter * Zero on success, negative errno on failure. 2691f453ba04SDave Airlie */ 2692f453ba04SDave Airlie int drm_mode_setcrtc(struct drm_device *dev, void *data, 2693f453ba04SDave Airlie struct drm_file *file_priv) 2694f453ba04SDave Airlie { 2695f453ba04SDave Airlie struct drm_mode_config *config = &dev->mode_config; 2696f453ba04SDave Airlie struct drm_mode_crtc *crtc_req = data; 26976653cc8dSVille Syrjälä struct drm_crtc *crtc; 2698f453ba04SDave Airlie struct drm_connector **connector_set = NULL, *connector; 2699f453ba04SDave Airlie struct drm_framebuffer *fb = NULL; 2700f453ba04SDave Airlie struct drm_display_mode *mode = NULL; 2701f453ba04SDave Airlie struct drm_mode_set set; 2702f453ba04SDave Airlie uint32_t __user *set_connectors_ptr; 27034a1b0714SLaurent Pinchart int ret; 2704f453ba04SDave Airlie int i; 2705f453ba04SDave Airlie 2706fb3b06c8SDave Airlie if (!drm_core_check_feature(dev, DRIVER_MODESET)) 2707fb3b06c8SDave Airlie return -EINVAL; 2708fb3b06c8SDave Airlie 27091d97e915SVille Syrjälä /* For some reason crtc x/y offsets are signed internally. */ 27101d97e915SVille Syrjälä if (crtc_req->x > INT_MAX || crtc_req->y > INT_MAX) 27111d97e915SVille Syrjälä return -ERANGE; 27121d97e915SVille Syrjälä 271384849903SDaniel Vetter drm_modeset_lock_all(dev); 2714a2b34e22SRob Clark crtc = drm_crtc_find(dev, crtc_req->crtc_id); 2715a2b34e22SRob Clark if (!crtc) { 271658367ed6SZhao Yakui DRM_DEBUG_KMS("Unknown CRTC ID %d\n", crtc_req->crtc_id); 2717f27657f2SVille Syrjälä ret = -ENOENT; 2718f453ba04SDave Airlie goto out; 2719f453ba04SDave Airlie } 27209440106bSJerome Glisse DRM_DEBUG_KMS("[CRTC:%d]\n", crtc->base.id); 2721f453ba04SDave Airlie 2722f453ba04SDave Airlie if (crtc_req->mode_valid) { 2723f453ba04SDave Airlie /* If we have a mode we need a framebuffer. */ 2724f453ba04SDave Airlie /* If we pass -1, set the mode with the currently bound fb */ 2725f453ba04SDave Airlie if (crtc_req->fb_id == -1) { 2726f4510a27SMatt Roper if (!crtc->primary->fb) { 27276653cc8dSVille Syrjälä DRM_DEBUG_KMS("CRTC doesn't have current FB\n"); 27286653cc8dSVille Syrjälä ret = -EINVAL; 27296653cc8dSVille Syrjälä goto out; 27306653cc8dSVille Syrjälä } 2731f4510a27SMatt Roper fb = crtc->primary->fb; 2732b0d12325SDaniel Vetter /* Make refcounting symmetric with the lookup path. */ 2733b0d12325SDaniel Vetter drm_framebuffer_reference(fb); 2734f453ba04SDave Airlie } else { 2735786b99edSDaniel Vetter fb = drm_framebuffer_lookup(dev, crtc_req->fb_id); 2736786b99edSDaniel Vetter if (!fb) { 273758367ed6SZhao Yakui DRM_DEBUG_KMS("Unknown FB ID%d\n", 273858367ed6SZhao Yakui crtc_req->fb_id); 273937c4e705SVille Syrjälä ret = -ENOENT; 2740f453ba04SDave Airlie goto out; 2741f453ba04SDave Airlie } 2742f453ba04SDave Airlie } 2743f453ba04SDave Airlie 2744f453ba04SDave Airlie mode = drm_mode_create(dev); 2745ee34ab5bSVille Syrjälä if (!mode) { 2746ee34ab5bSVille Syrjälä ret = -ENOMEM; 2747ee34ab5bSVille Syrjälä goto out; 2748ee34ab5bSVille Syrjälä } 2749ee34ab5bSVille Syrjälä 2750934a8a89SDaniel Stone ret = drm_mode_convert_umode(mode, &crtc_req->mode); 275190367bf6SVille Syrjälä if (ret) { 275290367bf6SVille Syrjälä DRM_DEBUG_KMS("Invalid mode\n"); 275390367bf6SVille Syrjälä goto out; 275490367bf6SVille Syrjälä } 275590367bf6SVille Syrjälä 2756f453ba04SDave Airlie drm_mode_set_crtcinfo(mode, CRTC_INTERLACE_HALVE_V); 27575f61bb42SVille Syrjälä 27587eb5f302SLaurent Pinchart /* 27597eb5f302SLaurent Pinchart * Check whether the primary plane supports the fb pixel format. 27607eb5f302SLaurent Pinchart * Drivers not implementing the universal planes API use a 27617eb5f302SLaurent Pinchart * default formats list provided by the DRM core which doesn't 27627eb5f302SLaurent Pinchart * match real hardware capabilities. Skip the check in that 27637eb5f302SLaurent Pinchart * case. 27647eb5f302SLaurent Pinchart */ 27657eb5f302SLaurent Pinchart if (!crtc->primary->format_default) { 27667eb5f302SLaurent Pinchart ret = drm_plane_check_pixel_format(crtc->primary, 27677eb5f302SLaurent Pinchart fb->pixel_format); 27687eb5f302SLaurent Pinchart if (ret) { 27697eb5f302SLaurent Pinchart DRM_DEBUG_KMS("Invalid pixel format %s\n", 27707eb5f302SLaurent Pinchart drm_get_format_name(fb->pixel_format)); 27717eb5f302SLaurent Pinchart goto out; 27727eb5f302SLaurent Pinchart } 27737eb5f302SLaurent Pinchart } 27747eb5f302SLaurent Pinchart 2775c11e9283SDamien Lespiau ret = drm_crtc_check_viewport(crtc, crtc_req->x, crtc_req->y, 2776c11e9283SDamien Lespiau mode, fb); 2777c11e9283SDamien Lespiau if (ret) 27785f61bb42SVille Syrjälä goto out; 2779c11e9283SDamien Lespiau 2780f453ba04SDave Airlie } 2781f453ba04SDave Airlie 2782f453ba04SDave Airlie if (crtc_req->count_connectors == 0 && mode) { 278358367ed6SZhao Yakui DRM_DEBUG_KMS("Count connectors is 0 but mode set\n"); 2784f453ba04SDave Airlie ret = -EINVAL; 2785f453ba04SDave Airlie goto out; 2786f453ba04SDave Airlie } 2787f453ba04SDave Airlie 27887781de74SJakob Bornecrantz if (crtc_req->count_connectors > 0 && (!mode || !fb)) { 278958367ed6SZhao Yakui DRM_DEBUG_KMS("Count connectors is %d but no mode or fb set\n", 2790f453ba04SDave Airlie crtc_req->count_connectors); 2791f453ba04SDave Airlie ret = -EINVAL; 2792f453ba04SDave Airlie goto out; 2793f453ba04SDave Airlie } 2794f453ba04SDave Airlie 2795f453ba04SDave Airlie if (crtc_req->count_connectors > 0) { 2796f453ba04SDave Airlie u32 out_id; 2797f453ba04SDave Airlie 2798f453ba04SDave Airlie /* Avoid unbounded kernel memory allocation */ 2799f453ba04SDave Airlie if (crtc_req->count_connectors > config->num_connector) { 2800f453ba04SDave Airlie ret = -EINVAL; 2801f453ba04SDave Airlie goto out; 2802f453ba04SDave Airlie } 2803f453ba04SDave Airlie 28042f6c5389SThierry Reding connector_set = kmalloc_array(crtc_req->count_connectors, 2805f453ba04SDave Airlie sizeof(struct drm_connector *), 2806f453ba04SDave Airlie GFP_KERNEL); 2807f453ba04SDave Airlie if (!connector_set) { 2808f453ba04SDave Airlie ret = -ENOMEM; 2809f453ba04SDave Airlie goto out; 2810f453ba04SDave Airlie } 2811f453ba04SDave Airlie 2812f453ba04SDave Airlie for (i = 0; i < crtc_req->count_connectors; i++) { 281381f6c7f8SVille Syrjälä set_connectors_ptr = (uint32_t __user *)(unsigned long)crtc_req->set_connectors_ptr; 2814f453ba04SDave Airlie if (get_user(out_id, &set_connectors_ptr[i])) { 2815f453ba04SDave Airlie ret = -EFAULT; 2816f453ba04SDave Airlie goto out; 2817f453ba04SDave Airlie } 2818f453ba04SDave Airlie 2819a2b34e22SRob Clark connector = drm_connector_find(dev, out_id); 2820a2b34e22SRob Clark if (!connector) { 282158367ed6SZhao Yakui DRM_DEBUG_KMS("Connector id %d unknown\n", 282258367ed6SZhao Yakui out_id); 2823f27657f2SVille Syrjälä ret = -ENOENT; 2824f453ba04SDave Airlie goto out; 2825f453ba04SDave Airlie } 28269440106bSJerome Glisse DRM_DEBUG_KMS("[CONNECTOR:%d:%s]\n", 28279440106bSJerome Glisse connector->base.id, 282825933820SJani Nikula connector->name); 2829f453ba04SDave Airlie 2830f453ba04SDave Airlie connector_set[i] = connector; 2831f453ba04SDave Airlie } 2832f453ba04SDave Airlie } 2833f453ba04SDave Airlie 2834f453ba04SDave Airlie set.crtc = crtc; 2835f453ba04SDave Airlie set.x = crtc_req->x; 2836f453ba04SDave Airlie set.y = crtc_req->y; 2837f453ba04SDave Airlie set.mode = mode; 2838f453ba04SDave Airlie set.connectors = connector_set; 2839f453ba04SDave Airlie set.num_connectors = crtc_req->count_connectors; 2840f453ba04SDave Airlie set.fb = fb; 28412d13b679SDaniel Vetter ret = drm_mode_set_config_internal(&set); 2842f453ba04SDave Airlie 2843f453ba04SDave Airlie out: 2844b0d12325SDaniel Vetter if (fb) 2845b0d12325SDaniel Vetter drm_framebuffer_unreference(fb); 2846b0d12325SDaniel Vetter 2847f453ba04SDave Airlie kfree(connector_set); 2848ee34ab5bSVille Syrjälä drm_mode_destroy(dev, mode); 284984849903SDaniel Vetter drm_modeset_unlock_all(dev); 2850f453ba04SDave Airlie return ret; 2851f453ba04SDave Airlie } 2852f453ba04SDave Airlie 2853161d0dc1SMatt Roper /** 2854161d0dc1SMatt Roper * drm_mode_cursor_universal - translate legacy cursor ioctl call into a 2855161d0dc1SMatt Roper * universal plane handler call 2856161d0dc1SMatt Roper * @crtc: crtc to update cursor for 2857161d0dc1SMatt Roper * @req: data pointer for the ioctl 2858161d0dc1SMatt Roper * @file_priv: drm file for the ioctl call 2859161d0dc1SMatt Roper * 2860161d0dc1SMatt Roper * Legacy cursor ioctl's work directly with driver buffer handles. To 2861161d0dc1SMatt Roper * translate legacy ioctl calls into universal plane handler calls, we need to 2862161d0dc1SMatt Roper * wrap the native buffer handle in a drm_framebuffer. 2863161d0dc1SMatt Roper * 2864161d0dc1SMatt Roper * Note that we assume any handle passed to the legacy ioctls was a 32-bit ARGB 2865161d0dc1SMatt Roper * buffer with a pitch of 4*width; the universal plane interface should be used 2866161d0dc1SMatt Roper * directly in cases where the hardware can support other buffer settings and 2867161d0dc1SMatt Roper * userspace wants to make use of these capabilities. 2868161d0dc1SMatt Roper * 2869161d0dc1SMatt Roper * Returns: 28701a498633SDaniel Vetter * Zero on success, negative errno on failure. 2871161d0dc1SMatt Roper */ 2872161d0dc1SMatt Roper static int drm_mode_cursor_universal(struct drm_crtc *crtc, 2873161d0dc1SMatt Roper struct drm_mode_cursor2 *req, 2874161d0dc1SMatt Roper struct drm_file *file_priv) 2875161d0dc1SMatt Roper { 2876161d0dc1SMatt Roper struct drm_device *dev = crtc->dev; 2877161d0dc1SMatt Roper struct drm_framebuffer *fb = NULL; 2878161d0dc1SMatt Roper struct drm_mode_fb_cmd2 fbreq = { 2879161d0dc1SMatt Roper .width = req->width, 2880161d0dc1SMatt Roper .height = req->height, 2881161d0dc1SMatt Roper .pixel_format = DRM_FORMAT_ARGB8888, 2882161d0dc1SMatt Roper .pitches = { req->width * 4 }, 2883161d0dc1SMatt Roper .handles = { req->handle }, 2884161d0dc1SMatt Roper }; 2885161d0dc1SMatt Roper int32_t crtc_x, crtc_y; 2886161d0dc1SMatt Roper uint32_t crtc_w = 0, crtc_h = 0; 2887161d0dc1SMatt Roper uint32_t src_w = 0, src_h = 0; 2888161d0dc1SMatt Roper int ret = 0; 2889161d0dc1SMatt Roper 2890161d0dc1SMatt Roper BUG_ON(!crtc->cursor); 2891f2b50c11SDaniel Vetter WARN_ON(crtc->cursor->crtc != crtc && crtc->cursor->crtc != NULL); 2892161d0dc1SMatt Roper 2893161d0dc1SMatt Roper /* 2894161d0dc1SMatt Roper * Obtain fb we'll be using (either new or existing) and take an extra 2895161d0dc1SMatt Roper * reference to it if fb != null. setplane will take care of dropping 2896161d0dc1SMatt Roper * the reference if the plane update fails. 2897161d0dc1SMatt Roper */ 2898161d0dc1SMatt Roper if (req->flags & DRM_MODE_CURSOR_BO) { 2899161d0dc1SMatt Roper if (req->handle) { 29009a6f5130SChris Wilson fb = internal_framebuffer_create(dev, &fbreq, file_priv); 2901161d0dc1SMatt Roper if (IS_ERR(fb)) { 2902161d0dc1SMatt Roper DRM_DEBUG_KMS("failed to wrap cursor buffer in drm framebuffer\n"); 2903161d0dc1SMatt Roper return PTR_ERR(fb); 2904161d0dc1SMatt Roper } 2905161d0dc1SMatt Roper } else { 2906161d0dc1SMatt Roper fb = NULL; 2907161d0dc1SMatt Roper } 2908161d0dc1SMatt Roper } else { 2909161d0dc1SMatt Roper fb = crtc->cursor->fb; 2910161d0dc1SMatt Roper if (fb) 2911161d0dc1SMatt Roper drm_framebuffer_reference(fb); 2912161d0dc1SMatt Roper } 2913161d0dc1SMatt Roper 2914161d0dc1SMatt Roper if (req->flags & DRM_MODE_CURSOR_MOVE) { 2915161d0dc1SMatt Roper crtc_x = req->x; 2916161d0dc1SMatt Roper crtc_y = req->y; 2917161d0dc1SMatt Roper } else { 2918161d0dc1SMatt Roper crtc_x = crtc->cursor_x; 2919161d0dc1SMatt Roper crtc_y = crtc->cursor_y; 2920161d0dc1SMatt Roper } 2921161d0dc1SMatt Roper 2922161d0dc1SMatt Roper if (fb) { 2923161d0dc1SMatt Roper crtc_w = fb->width; 2924161d0dc1SMatt Roper crtc_h = fb->height; 2925161d0dc1SMatt Roper src_w = fb->width << 16; 2926161d0dc1SMatt Roper src_h = fb->height << 16; 2927161d0dc1SMatt Roper } 2928161d0dc1SMatt Roper 2929161d0dc1SMatt Roper /* 2930161d0dc1SMatt Roper * setplane_internal will take care of deref'ing either the old or new 2931161d0dc1SMatt Roper * framebuffer depending on success. 2932161d0dc1SMatt Roper */ 2933f2b50c11SDaniel Vetter ret = __setplane_internal(crtc->cursor, crtc, fb, 2934161d0dc1SMatt Roper crtc_x, crtc_y, crtc_w, crtc_h, 2935161d0dc1SMatt Roper 0, 0, src_w, src_h); 2936161d0dc1SMatt Roper 2937161d0dc1SMatt Roper /* Update successful; save new cursor position, if necessary */ 2938161d0dc1SMatt Roper if (ret == 0 && req->flags & DRM_MODE_CURSOR_MOVE) { 2939161d0dc1SMatt Roper crtc->cursor_x = req->x; 2940161d0dc1SMatt Roper crtc->cursor_y = req->y; 2941161d0dc1SMatt Roper } 2942161d0dc1SMatt Roper 2943161d0dc1SMatt Roper return ret; 2944161d0dc1SMatt Roper } 2945161d0dc1SMatt Roper 29464c813d4dSDave Airlie static int drm_mode_cursor_common(struct drm_device *dev, 29474c813d4dSDave Airlie struct drm_mode_cursor2 *req, 29484c813d4dSDave Airlie struct drm_file *file_priv) 2949f453ba04SDave Airlie { 2950f453ba04SDave Airlie struct drm_crtc *crtc; 2951f453ba04SDave Airlie int ret = 0; 2952f453ba04SDave Airlie 2953fb3b06c8SDave Airlie if (!drm_core_check_feature(dev, DRIVER_MODESET)) 2954fb3b06c8SDave Airlie return -EINVAL; 2955fb3b06c8SDave Airlie 29567c4eaca4SJakob Bornecrantz if (!req->flags || (~DRM_MODE_CURSOR_FLAGS & req->flags)) 2957f453ba04SDave Airlie return -EINVAL; 2958f453ba04SDave Airlie 2959a2b34e22SRob Clark crtc = drm_crtc_find(dev, req->crtc_id); 2960a2b34e22SRob Clark if (!crtc) { 296158367ed6SZhao Yakui DRM_DEBUG_KMS("Unknown CRTC ID %d\n", req->crtc_id); 2962f27657f2SVille Syrjälä return -ENOENT; 2963f453ba04SDave Airlie } 2964f453ba04SDave Airlie 2965161d0dc1SMatt Roper /* 2966161d0dc1SMatt Roper * If this crtc has a universal cursor plane, call that plane's update 2967161d0dc1SMatt Roper * handler rather than using legacy cursor handlers. 2968161d0dc1SMatt Roper */ 29694d02e2deSDaniel Vetter drm_modeset_lock_crtc(crtc, crtc->cursor); 2970f2b50c11SDaniel Vetter if (crtc->cursor) { 2971f2b50c11SDaniel Vetter ret = drm_mode_cursor_universal(crtc, req, file_priv); 2972f2b50c11SDaniel Vetter goto out; 2973f2b50c11SDaniel Vetter } 2974f2b50c11SDaniel Vetter 2975f453ba04SDave Airlie if (req->flags & DRM_MODE_CURSOR_BO) { 29764c813d4dSDave Airlie if (!crtc->funcs->cursor_set && !crtc->funcs->cursor_set2) { 2977f453ba04SDave Airlie ret = -ENXIO; 2978f453ba04SDave Airlie goto out; 2979f453ba04SDave Airlie } 2980f453ba04SDave Airlie /* Turns off the cursor if handle is 0 */ 29814c813d4dSDave Airlie if (crtc->funcs->cursor_set2) 29824c813d4dSDave Airlie ret = crtc->funcs->cursor_set2(crtc, file_priv, req->handle, 29834c813d4dSDave Airlie req->width, req->height, req->hot_x, req->hot_y); 29844c813d4dSDave Airlie else 2985f453ba04SDave Airlie ret = crtc->funcs->cursor_set(crtc, file_priv, req->handle, 2986f453ba04SDave Airlie req->width, req->height); 2987f453ba04SDave Airlie } 2988f453ba04SDave Airlie 2989f453ba04SDave Airlie if (req->flags & DRM_MODE_CURSOR_MOVE) { 2990f453ba04SDave Airlie if (crtc->funcs->cursor_move) { 2991f453ba04SDave Airlie ret = crtc->funcs->cursor_move(crtc, req->x, req->y); 2992f453ba04SDave Airlie } else { 2993f453ba04SDave Airlie ret = -EFAULT; 2994f453ba04SDave Airlie goto out; 2995f453ba04SDave Airlie } 2996f453ba04SDave Airlie } 2997f453ba04SDave Airlie out: 2998d059f652SDaniel Vetter drm_modeset_unlock_crtc(crtc); 2999dac35663SDaniel Vetter 3000f453ba04SDave Airlie return ret; 30014c813d4dSDave Airlie 30024c813d4dSDave Airlie } 3003c8e32cc1SDaniel Vetter 3004c8e32cc1SDaniel Vetter 3005c8e32cc1SDaniel Vetter /** 3006c8e32cc1SDaniel Vetter * drm_mode_cursor_ioctl - set CRTC's cursor configuration 3007c8e32cc1SDaniel Vetter * @dev: drm device for the ioctl 3008c8e32cc1SDaniel Vetter * @data: data pointer for the ioctl 3009c8e32cc1SDaniel Vetter * @file_priv: drm file for the ioctl call 3010c8e32cc1SDaniel Vetter * 3011c8e32cc1SDaniel Vetter * Set the cursor configuration based on user request. 3012c8e32cc1SDaniel Vetter * 3013c8e32cc1SDaniel Vetter * Called by the user via ioctl. 3014c8e32cc1SDaniel Vetter * 3015c8e32cc1SDaniel Vetter * Returns: 30161a498633SDaniel Vetter * Zero on success, negative errno on failure. 3017c8e32cc1SDaniel Vetter */ 30184c813d4dSDave Airlie int drm_mode_cursor_ioctl(struct drm_device *dev, 30194c813d4dSDave Airlie void *data, struct drm_file *file_priv) 30204c813d4dSDave Airlie { 30214c813d4dSDave Airlie struct drm_mode_cursor *req = data; 30224c813d4dSDave Airlie struct drm_mode_cursor2 new_req; 30234c813d4dSDave Airlie 30244c813d4dSDave Airlie memcpy(&new_req, req, sizeof(struct drm_mode_cursor)); 30254c813d4dSDave Airlie new_req.hot_x = new_req.hot_y = 0; 30264c813d4dSDave Airlie 30274c813d4dSDave Airlie return drm_mode_cursor_common(dev, &new_req, file_priv); 30284c813d4dSDave Airlie } 30294c813d4dSDave Airlie 3030c8e32cc1SDaniel Vetter /** 3031c8e32cc1SDaniel Vetter * drm_mode_cursor2_ioctl - set CRTC's cursor configuration 3032c8e32cc1SDaniel Vetter * @dev: drm device for the ioctl 3033c8e32cc1SDaniel Vetter * @data: data pointer for the ioctl 3034c8e32cc1SDaniel Vetter * @file_priv: drm file for the ioctl call 3035c8e32cc1SDaniel Vetter * 3036c8e32cc1SDaniel Vetter * Set the cursor configuration based on user request. This implements the 2nd 3037c8e32cc1SDaniel Vetter * version of the cursor ioctl, which allows userspace to additionally specify 3038c8e32cc1SDaniel Vetter * the hotspot of the pointer. 3039c8e32cc1SDaniel Vetter * 3040c8e32cc1SDaniel Vetter * Called by the user via ioctl. 3041c8e32cc1SDaniel Vetter * 3042c8e32cc1SDaniel Vetter * Returns: 30431a498633SDaniel Vetter * Zero on success, negative errno on failure. 3044c8e32cc1SDaniel Vetter */ 30454c813d4dSDave Airlie int drm_mode_cursor2_ioctl(struct drm_device *dev, 30464c813d4dSDave Airlie void *data, struct drm_file *file_priv) 30474c813d4dSDave Airlie { 30484c813d4dSDave Airlie struct drm_mode_cursor2 *req = data; 30494dfd909fSThierry Reding 30504c813d4dSDave Airlie return drm_mode_cursor_common(dev, req, file_priv); 3051f453ba04SDave Airlie } 3052f453ba04SDave Airlie 3053c8e32cc1SDaniel Vetter /** 3054c8e32cc1SDaniel Vetter * drm_mode_legacy_fb_format - compute drm fourcc code from legacy description 3055c8e32cc1SDaniel Vetter * @bpp: bits per pixels 3056c8e32cc1SDaniel Vetter * @depth: bit depth per pixel 3057c8e32cc1SDaniel Vetter * 3058c8e32cc1SDaniel Vetter * Computes a drm fourcc pixel format code for the given @bpp/@depth values. 3059c8e32cc1SDaniel Vetter * Useful in fbdev emulation code, since that deals in those values. 3060c8e32cc1SDaniel Vetter */ 3061308e5bcbSJesse Barnes uint32_t drm_mode_legacy_fb_format(uint32_t bpp, uint32_t depth) 3062308e5bcbSJesse Barnes { 3063308e5bcbSJesse Barnes uint32_t fmt; 3064308e5bcbSJesse Barnes 3065308e5bcbSJesse Barnes switch (bpp) { 3066308e5bcbSJesse Barnes case 8: 3067d84f031bSVille Syrjälä fmt = DRM_FORMAT_C8; 3068308e5bcbSJesse Barnes break; 3069308e5bcbSJesse Barnes case 16: 3070308e5bcbSJesse Barnes if (depth == 15) 307104b3924dSVille Syrjälä fmt = DRM_FORMAT_XRGB1555; 3072308e5bcbSJesse Barnes else 307304b3924dSVille Syrjälä fmt = DRM_FORMAT_RGB565; 3074308e5bcbSJesse Barnes break; 3075308e5bcbSJesse Barnes case 24: 307604b3924dSVille Syrjälä fmt = DRM_FORMAT_RGB888; 3077308e5bcbSJesse Barnes break; 3078308e5bcbSJesse Barnes case 32: 3079308e5bcbSJesse Barnes if (depth == 24) 308004b3924dSVille Syrjälä fmt = DRM_FORMAT_XRGB8888; 3081308e5bcbSJesse Barnes else if (depth == 30) 308204b3924dSVille Syrjälä fmt = DRM_FORMAT_XRGB2101010; 3083308e5bcbSJesse Barnes else 308404b3924dSVille Syrjälä fmt = DRM_FORMAT_ARGB8888; 3085308e5bcbSJesse Barnes break; 3086308e5bcbSJesse Barnes default: 308704b3924dSVille Syrjälä DRM_ERROR("bad bpp, assuming x8r8g8b8 pixel format\n"); 308804b3924dSVille Syrjälä fmt = DRM_FORMAT_XRGB8888; 3089308e5bcbSJesse Barnes break; 3090308e5bcbSJesse Barnes } 3091308e5bcbSJesse Barnes 3092308e5bcbSJesse Barnes return fmt; 3093308e5bcbSJesse Barnes } 3094308e5bcbSJesse Barnes EXPORT_SYMBOL(drm_mode_legacy_fb_format); 3095308e5bcbSJesse Barnes 3096f453ba04SDave Airlie /** 3097f453ba04SDave Airlie * drm_mode_addfb - add an FB to the graphics configuration 3098065a50edSDaniel Vetter * @dev: drm device for the ioctl 3099065a50edSDaniel Vetter * @data: data pointer for the ioctl 3100065a50edSDaniel Vetter * @file_priv: drm file for the ioctl call 3101f453ba04SDave Airlie * 3102c8e32cc1SDaniel Vetter * Add a new FB to the specified CRTC, given a user request. This is the 3103209f5527SChuck Ebbert * original addfb ioctl which only supported RGB formats. 3104f453ba04SDave Airlie * 3105f453ba04SDave Airlie * Called by the user via ioctl. 3106f453ba04SDave Airlie * 3107c8e32cc1SDaniel Vetter * Returns: 31081a498633SDaniel Vetter * Zero on success, negative errno on failure. 3109f453ba04SDave Airlie */ 3110f453ba04SDave Airlie int drm_mode_addfb(struct drm_device *dev, 3111f453ba04SDave Airlie void *data, struct drm_file *file_priv) 3112f453ba04SDave Airlie { 3113308e5bcbSJesse Barnes struct drm_mode_fb_cmd *or = data; 3114308e5bcbSJesse Barnes struct drm_mode_fb_cmd2 r = {}; 3115228f2cb3SChuck Ebbert int ret; 3116308e5bcbSJesse Barnes 3117228f2cb3SChuck Ebbert /* convert to new format and call new ioctl */ 3118308e5bcbSJesse Barnes r.fb_id = or->fb_id; 3119308e5bcbSJesse Barnes r.width = or->width; 3120308e5bcbSJesse Barnes r.height = or->height; 3121308e5bcbSJesse Barnes r.pitches[0] = or->pitch; 3122308e5bcbSJesse Barnes r.pixel_format = drm_mode_legacy_fb_format(or->bpp, or->depth); 3123308e5bcbSJesse Barnes r.handles[0] = or->handle; 3124308e5bcbSJesse Barnes 3125228f2cb3SChuck Ebbert ret = drm_mode_addfb2(dev, &r, file_priv); 3126228f2cb3SChuck Ebbert if (ret) 3127228f2cb3SChuck Ebbert return ret; 3128308e5bcbSJesse Barnes 3129228f2cb3SChuck Ebbert or->fb_id = r.fb_id; 31304b096ac1SDaniel Vetter 3131baf698b0SDaniel Vetter return 0; 3132308e5bcbSJesse Barnes } 3133308e5bcbSJesse Barnes 3134cff91b62SVille Syrjälä static int format_check(const struct drm_mode_fb_cmd2 *r) 3135935b5977SVille Syrjälä { 3136935b5977SVille Syrjälä uint32_t format = r->pixel_format & ~DRM_FORMAT_BIG_ENDIAN; 3137935b5977SVille Syrjälä 3138935b5977SVille Syrjälä switch (format) { 3139935b5977SVille Syrjälä case DRM_FORMAT_C8: 3140935b5977SVille Syrjälä case DRM_FORMAT_RGB332: 3141935b5977SVille Syrjälä case DRM_FORMAT_BGR233: 3142935b5977SVille Syrjälä case DRM_FORMAT_XRGB4444: 3143935b5977SVille Syrjälä case DRM_FORMAT_XBGR4444: 3144935b5977SVille Syrjälä case DRM_FORMAT_RGBX4444: 3145935b5977SVille Syrjälä case DRM_FORMAT_BGRX4444: 3146935b5977SVille Syrjälä case DRM_FORMAT_ARGB4444: 3147935b5977SVille Syrjälä case DRM_FORMAT_ABGR4444: 3148935b5977SVille Syrjälä case DRM_FORMAT_RGBA4444: 3149935b5977SVille Syrjälä case DRM_FORMAT_BGRA4444: 3150935b5977SVille Syrjälä case DRM_FORMAT_XRGB1555: 3151935b5977SVille Syrjälä case DRM_FORMAT_XBGR1555: 3152935b5977SVille Syrjälä case DRM_FORMAT_RGBX5551: 3153935b5977SVille Syrjälä case DRM_FORMAT_BGRX5551: 3154935b5977SVille Syrjälä case DRM_FORMAT_ARGB1555: 3155935b5977SVille Syrjälä case DRM_FORMAT_ABGR1555: 3156935b5977SVille Syrjälä case DRM_FORMAT_RGBA5551: 3157935b5977SVille Syrjälä case DRM_FORMAT_BGRA5551: 3158935b5977SVille Syrjälä case DRM_FORMAT_RGB565: 3159935b5977SVille Syrjälä case DRM_FORMAT_BGR565: 3160935b5977SVille Syrjälä case DRM_FORMAT_RGB888: 3161935b5977SVille Syrjälä case DRM_FORMAT_BGR888: 3162935b5977SVille Syrjälä case DRM_FORMAT_XRGB8888: 3163935b5977SVille Syrjälä case DRM_FORMAT_XBGR8888: 3164935b5977SVille Syrjälä case DRM_FORMAT_RGBX8888: 3165935b5977SVille Syrjälä case DRM_FORMAT_BGRX8888: 3166935b5977SVille Syrjälä case DRM_FORMAT_ARGB8888: 3167935b5977SVille Syrjälä case DRM_FORMAT_ABGR8888: 3168935b5977SVille Syrjälä case DRM_FORMAT_RGBA8888: 3169935b5977SVille Syrjälä case DRM_FORMAT_BGRA8888: 3170935b5977SVille Syrjälä case DRM_FORMAT_XRGB2101010: 3171935b5977SVille Syrjälä case DRM_FORMAT_XBGR2101010: 3172935b5977SVille Syrjälä case DRM_FORMAT_RGBX1010102: 3173935b5977SVille Syrjälä case DRM_FORMAT_BGRX1010102: 3174935b5977SVille Syrjälä case DRM_FORMAT_ARGB2101010: 3175935b5977SVille Syrjälä case DRM_FORMAT_ABGR2101010: 3176935b5977SVille Syrjälä case DRM_FORMAT_RGBA1010102: 3177935b5977SVille Syrjälä case DRM_FORMAT_BGRA1010102: 3178935b5977SVille Syrjälä case DRM_FORMAT_YUYV: 3179935b5977SVille Syrjälä case DRM_FORMAT_YVYU: 3180935b5977SVille Syrjälä case DRM_FORMAT_UYVY: 3181935b5977SVille Syrjälä case DRM_FORMAT_VYUY: 3182935b5977SVille Syrjälä case DRM_FORMAT_AYUV: 3183935b5977SVille Syrjälä case DRM_FORMAT_NV12: 3184935b5977SVille Syrjälä case DRM_FORMAT_NV21: 3185935b5977SVille Syrjälä case DRM_FORMAT_NV16: 3186935b5977SVille Syrjälä case DRM_FORMAT_NV61: 3187ba623f6aSLaurent Pinchart case DRM_FORMAT_NV24: 3188ba623f6aSLaurent Pinchart case DRM_FORMAT_NV42: 3189935b5977SVille Syrjälä case DRM_FORMAT_YUV410: 3190935b5977SVille Syrjälä case DRM_FORMAT_YVU410: 3191935b5977SVille Syrjälä case DRM_FORMAT_YUV411: 3192935b5977SVille Syrjälä case DRM_FORMAT_YVU411: 3193935b5977SVille Syrjälä case DRM_FORMAT_YUV420: 3194935b5977SVille Syrjälä case DRM_FORMAT_YVU420: 3195935b5977SVille Syrjälä case DRM_FORMAT_YUV422: 3196935b5977SVille Syrjälä case DRM_FORMAT_YVU422: 3197935b5977SVille Syrjälä case DRM_FORMAT_YUV444: 3198935b5977SVille Syrjälä case DRM_FORMAT_YVU444: 3199935b5977SVille Syrjälä return 0; 3200935b5977SVille Syrjälä default: 320123c453a4SVille Syrjälä DRM_DEBUG_KMS("invalid pixel format %s\n", 320223c453a4SVille Syrjälä drm_get_format_name(r->pixel_format)); 3203935b5977SVille Syrjälä return -EINVAL; 3204935b5977SVille Syrjälä } 3205935b5977SVille Syrjälä } 3206935b5977SVille Syrjälä 3207cff91b62SVille Syrjälä static int framebuffer_check(const struct drm_mode_fb_cmd2 *r) 3208d1b45d5fSVille Syrjälä { 3209d1b45d5fSVille Syrjälä int ret, hsub, vsub, num_planes, i; 3210d1b45d5fSVille Syrjälä 3211d1b45d5fSVille Syrjälä ret = format_check(r); 3212d1b45d5fSVille Syrjälä if (ret) { 32136ba6d03eSVille Syrjälä DRM_DEBUG_KMS("bad framebuffer format %s\n", 32146ba6d03eSVille Syrjälä drm_get_format_name(r->pixel_format)); 3215d1b45d5fSVille Syrjälä return ret; 3216d1b45d5fSVille Syrjälä } 3217d1b45d5fSVille Syrjälä 3218d1b45d5fSVille Syrjälä hsub = drm_format_horz_chroma_subsampling(r->pixel_format); 3219d1b45d5fSVille Syrjälä vsub = drm_format_vert_chroma_subsampling(r->pixel_format); 3220d1b45d5fSVille Syrjälä num_planes = drm_format_num_planes(r->pixel_format); 3221d1b45d5fSVille Syrjälä 3222d1b45d5fSVille Syrjälä if (r->width == 0 || r->width % hsub) { 3223209f5527SChuck Ebbert DRM_DEBUG_KMS("bad framebuffer width %u\n", r->width); 3224d1b45d5fSVille Syrjälä return -EINVAL; 3225d1b45d5fSVille Syrjälä } 3226d1b45d5fSVille Syrjälä 3227d1b45d5fSVille Syrjälä if (r->height == 0 || r->height % vsub) { 32281aa1b11cSDave Airlie DRM_DEBUG_KMS("bad framebuffer height %u\n", r->height); 3229d1b45d5fSVille Syrjälä return -EINVAL; 3230d1b45d5fSVille Syrjälä } 3231d1b45d5fSVille Syrjälä 3232d1b45d5fSVille Syrjälä for (i = 0; i < num_planes; i++) { 3233d1b45d5fSVille Syrjälä unsigned int width = r->width / (i != 0 ? hsub : 1); 3234b180b5d1SVille Syrjälä unsigned int height = r->height / (i != 0 ? vsub : 1); 3235b180b5d1SVille Syrjälä unsigned int cpp = drm_format_plane_cpp(r->pixel_format, i); 3236d1b45d5fSVille Syrjälä 3237d1b45d5fSVille Syrjälä if (!r->handles[i]) { 32381aa1b11cSDave Airlie DRM_DEBUG_KMS("no buffer object handle for plane %d\n", i); 3239d1b45d5fSVille Syrjälä return -EINVAL; 3240d1b45d5fSVille Syrjälä } 3241d1b45d5fSVille Syrjälä 3242b180b5d1SVille Syrjälä if ((uint64_t) width * cpp > UINT_MAX) 3243b180b5d1SVille Syrjälä return -ERANGE; 3244b180b5d1SVille Syrjälä 3245b180b5d1SVille Syrjälä if ((uint64_t) height * r->pitches[i] + r->offsets[i] > UINT_MAX) 3246b180b5d1SVille Syrjälä return -ERANGE; 3247b180b5d1SVille Syrjälä 3248b180b5d1SVille Syrjälä if (r->pitches[i] < width * cpp) { 32491aa1b11cSDave Airlie DRM_DEBUG_KMS("bad pitch %u for plane %d\n", r->pitches[i], i); 3250d1b45d5fSVille Syrjälä return -EINVAL; 3251d1b45d5fSVille Syrjälä } 3252e3eb3250SRob Clark 3253e3eb3250SRob Clark if (r->modifier[i] && !(r->flags & DRM_MODE_FB_MODIFIERS)) { 3254e3eb3250SRob Clark DRM_DEBUG_KMS("bad fb modifier %llu for plane %d\n", 3255e3eb3250SRob Clark r->modifier[i], i); 3256e3eb3250SRob Clark return -EINVAL; 3257e3eb3250SRob Clark } 3258570655b0SRob Clark 3259570655b0SRob Clark /* modifier specific checks: */ 3260570655b0SRob Clark switch (r->modifier[i]) { 3261570655b0SRob Clark case DRM_FORMAT_MOD_SAMSUNG_64_32_TILE: 3262570655b0SRob Clark /* NOTE: the pitch restriction may be lifted later if it turns 3263570655b0SRob Clark * out that no hw has this restriction: 3264570655b0SRob Clark */ 3265570655b0SRob Clark if (r->pixel_format != DRM_FORMAT_NV12 || 3266570655b0SRob Clark width % 128 || height % 32 || 3267570655b0SRob Clark r->pitches[i] % 128) { 3268570655b0SRob Clark DRM_DEBUG_KMS("bad modifier data for plane %d\n", i); 3269570655b0SRob Clark return -EINVAL; 3270570655b0SRob Clark } 3271570655b0SRob Clark break; 3272570655b0SRob Clark 3273570655b0SRob Clark default: 3274570655b0SRob Clark break; 3275570655b0SRob Clark } 3276d1b45d5fSVille Syrjälä } 3277d1b45d5fSVille Syrjälä 3278bbe16a40SDaniel Vetter for (i = num_planes; i < 4; i++) { 3279bbe16a40SDaniel Vetter if (r->modifier[i]) { 3280bbe16a40SDaniel Vetter DRM_DEBUG_KMS("non-zero modifier for unused plane %d\n", i); 3281bbe16a40SDaniel Vetter return -EINVAL; 3282bbe16a40SDaniel Vetter } 3283bbe16a40SDaniel Vetter 3284bbe16a40SDaniel Vetter /* Pre-FB_MODIFIERS userspace didn't clear the structs properly. */ 3285bbe16a40SDaniel Vetter if (!(r->flags & DRM_MODE_FB_MODIFIERS)) 3286bbe16a40SDaniel Vetter continue; 3287bbe16a40SDaniel Vetter 3288bbe16a40SDaniel Vetter if (r->handles[i]) { 3289bbe16a40SDaniel Vetter DRM_DEBUG_KMS("buffer object handle for unused plane %d\n", i); 3290bbe16a40SDaniel Vetter return -EINVAL; 3291bbe16a40SDaniel Vetter } 3292bbe16a40SDaniel Vetter 3293bbe16a40SDaniel Vetter if (r->pitches[i]) { 3294bbe16a40SDaniel Vetter DRM_DEBUG_KMS("non-zero pitch for unused plane %d\n", i); 3295bbe16a40SDaniel Vetter return -EINVAL; 3296bbe16a40SDaniel Vetter } 3297bbe16a40SDaniel Vetter 3298bbe16a40SDaniel Vetter if (r->offsets[i]) { 3299bbe16a40SDaniel Vetter DRM_DEBUG_KMS("non-zero offset for unused plane %d\n", i); 3300bbe16a40SDaniel Vetter return -EINVAL; 3301bbe16a40SDaniel Vetter } 3302bbe16a40SDaniel Vetter } 3303bbe16a40SDaniel Vetter 3304d1b45d5fSVille Syrjälä return 0; 3305d1b45d5fSVille Syrjälä } 3306d1b45d5fSVille Syrjälä 33079a6f5130SChris Wilson static struct drm_framebuffer * 33089a6f5130SChris Wilson internal_framebuffer_create(struct drm_device *dev, 3309c394c2b0SMatt Roper struct drm_mode_fb_cmd2 *r, 3310c394c2b0SMatt Roper struct drm_file *file_priv) 3311c394c2b0SMatt Roper { 3312c394c2b0SMatt Roper struct drm_mode_config *config = &dev->mode_config; 3313c394c2b0SMatt Roper struct drm_framebuffer *fb; 3314c394c2b0SMatt Roper int ret; 3315c394c2b0SMatt Roper 3316e3eb3250SRob Clark if (r->flags & ~(DRM_MODE_FB_INTERLACED | DRM_MODE_FB_MODIFIERS)) { 3317c394c2b0SMatt Roper DRM_DEBUG_KMS("bad framebuffer flags 0x%08x\n", r->flags); 3318c394c2b0SMatt Roper return ERR_PTR(-EINVAL); 3319c394c2b0SMatt Roper } 3320c394c2b0SMatt Roper 3321c394c2b0SMatt Roper if ((config->min_width > r->width) || (r->width > config->max_width)) { 3322c394c2b0SMatt Roper DRM_DEBUG_KMS("bad framebuffer width %d, should be >= %d && <= %d\n", 3323c394c2b0SMatt Roper r->width, config->min_width, config->max_width); 3324c394c2b0SMatt Roper return ERR_PTR(-EINVAL); 3325c394c2b0SMatt Roper } 3326c394c2b0SMatt Roper if ((config->min_height > r->height) || (r->height > config->max_height)) { 3327c394c2b0SMatt Roper DRM_DEBUG_KMS("bad framebuffer height %d, should be >= %d && <= %d\n", 3328c394c2b0SMatt Roper r->height, config->min_height, config->max_height); 3329c394c2b0SMatt Roper return ERR_PTR(-EINVAL); 3330c394c2b0SMatt Roper } 3331c394c2b0SMatt Roper 3332e3eb3250SRob Clark if (r->flags & DRM_MODE_FB_MODIFIERS && 3333e3eb3250SRob Clark !dev->mode_config.allow_fb_modifiers) { 3334e3eb3250SRob Clark DRM_DEBUG_KMS("driver does not support fb modifiers\n"); 3335e3eb3250SRob Clark return ERR_PTR(-EINVAL); 3336e3eb3250SRob Clark } 3337e3eb3250SRob Clark 3338c394c2b0SMatt Roper ret = framebuffer_check(r); 3339c394c2b0SMatt Roper if (ret) 3340c394c2b0SMatt Roper return ERR_PTR(ret); 3341c394c2b0SMatt Roper 3342c394c2b0SMatt Roper fb = dev->mode_config.funcs->fb_create(dev, file_priv, r); 3343c394c2b0SMatt Roper if (IS_ERR(fb)) { 3344c394c2b0SMatt Roper DRM_DEBUG_KMS("could not create framebuffer\n"); 3345c394c2b0SMatt Roper return fb; 3346c394c2b0SMatt Roper } 3347c394c2b0SMatt Roper 3348c394c2b0SMatt Roper return fb; 3349c394c2b0SMatt Roper } 3350c394c2b0SMatt Roper 3351308e5bcbSJesse Barnes /** 3352308e5bcbSJesse Barnes * drm_mode_addfb2 - add an FB to the graphics configuration 3353065a50edSDaniel Vetter * @dev: drm device for the ioctl 3354065a50edSDaniel Vetter * @data: data pointer for the ioctl 3355065a50edSDaniel Vetter * @file_priv: drm file for the ioctl call 3356308e5bcbSJesse Barnes * 3357c8e32cc1SDaniel Vetter * Add a new FB to the specified CRTC, given a user request with format. This is 3358c8e32cc1SDaniel Vetter * the 2nd version of the addfb ioctl, which supports multi-planar framebuffers 3359c8e32cc1SDaniel Vetter * and uses fourcc codes as pixel format specifiers. 3360308e5bcbSJesse Barnes * 3361308e5bcbSJesse Barnes * Called by the user via ioctl. 3362308e5bcbSJesse Barnes * 3363c8e32cc1SDaniel Vetter * Returns: 33641a498633SDaniel Vetter * Zero on success, negative errno on failure. 3365308e5bcbSJesse Barnes */ 3366308e5bcbSJesse Barnes int drm_mode_addfb2(struct drm_device *dev, 3367308e5bcbSJesse Barnes void *data, struct drm_file *file_priv) 3368308e5bcbSJesse Barnes { 33699a6f5130SChris Wilson struct drm_mode_fb_cmd2 *r = data; 3370f453ba04SDave Airlie struct drm_framebuffer *fb; 3371f453ba04SDave Airlie 3372fb3b06c8SDave Airlie if (!drm_core_check_feature(dev, DRIVER_MODESET)) 3373fb3b06c8SDave Airlie return -EINVAL; 3374fb3b06c8SDave Airlie 33759a6f5130SChris Wilson fb = internal_framebuffer_create(dev, r, file_priv); 3376c394c2b0SMatt Roper if (IS_ERR(fb)) 33774b096ac1SDaniel Vetter return PTR_ERR(fb); 3378f453ba04SDave Airlie 33799a6f5130SChris Wilson /* Transfer ownership to the filp for reaping on close */ 33809a6f5130SChris Wilson 33819a6f5130SChris Wilson DRM_DEBUG_KMS("[FB:%d]\n", fb->base.id); 33829a6f5130SChris Wilson mutex_lock(&file_priv->fbs_lock); 33839a6f5130SChris Wilson r->fb_id = fb->base.id; 33849a6f5130SChris Wilson list_add(&fb->filp_head, &file_priv->fbs); 33859a6f5130SChris Wilson mutex_unlock(&file_priv->fbs_lock); 33869a6f5130SChris Wilson 3387c394c2b0SMatt Roper return 0; 3388f453ba04SDave Airlie } 3389f453ba04SDave Airlie 3390f453ba04SDave Airlie /** 3391f453ba04SDave Airlie * drm_mode_rmfb - remove an FB from the configuration 3392065a50edSDaniel Vetter * @dev: drm device for the ioctl 3393065a50edSDaniel Vetter * @data: data pointer for the ioctl 3394065a50edSDaniel Vetter * @file_priv: drm file for the ioctl call 3395f453ba04SDave Airlie * 3396f453ba04SDave Airlie * Remove the FB specified by the user. 3397f453ba04SDave Airlie * 3398f453ba04SDave Airlie * Called by the user via ioctl. 3399f453ba04SDave Airlie * 3400c8e32cc1SDaniel Vetter * Returns: 34011a498633SDaniel Vetter * Zero on success, negative errno on failure. 3402f453ba04SDave Airlie */ 3403f453ba04SDave Airlie int drm_mode_rmfb(struct drm_device *dev, 3404f453ba04SDave Airlie void *data, struct drm_file *file_priv) 3405f453ba04SDave Airlie { 3406f453ba04SDave Airlie struct drm_framebuffer *fb = NULL; 3407f453ba04SDave Airlie struct drm_framebuffer *fbl = NULL; 3408f453ba04SDave Airlie uint32_t *id = data; 3409f453ba04SDave Airlie int found = 0; 3410f453ba04SDave Airlie 3411fb3b06c8SDave Airlie if (!drm_core_check_feature(dev, DRIVER_MODESET)) 3412fb3b06c8SDave Airlie return -EINVAL; 3413fb3b06c8SDave Airlie 34144b096ac1SDaniel Vetter mutex_lock(&file_priv->fbs_lock); 34152b677e8cSDaniel Vetter mutex_lock(&dev->mode_config.fb_lock); 34162b677e8cSDaniel Vetter fb = __drm_framebuffer_lookup(dev, *id); 34172b677e8cSDaniel Vetter if (!fb) 34182b677e8cSDaniel Vetter goto fail_lookup; 34192b677e8cSDaniel Vetter 3420f453ba04SDave Airlie list_for_each_entry(fbl, &file_priv->fbs, filp_head) 3421f453ba04SDave Airlie if (fb == fbl) 3422f453ba04SDave Airlie found = 1; 34232b677e8cSDaniel Vetter if (!found) 34242b677e8cSDaniel Vetter goto fail_lookup; 34252b677e8cSDaniel Vetter 34262b677e8cSDaniel Vetter /* Mark fb as reaped, we still have a ref from fpriv->fbs. */ 34272b677e8cSDaniel Vetter __drm_framebuffer_unregister(dev, fb); 3428f453ba04SDave Airlie 34294b096ac1SDaniel Vetter list_del_init(&fb->filp_head); 34302b677e8cSDaniel Vetter mutex_unlock(&dev->mode_config.fb_lock); 34314b096ac1SDaniel Vetter mutex_unlock(&file_priv->fbs_lock); 3432f453ba04SDave Airlie 34334b096ac1SDaniel Vetter drm_framebuffer_remove(fb); 34344b096ac1SDaniel Vetter 34352b677e8cSDaniel Vetter return 0; 34362b677e8cSDaniel Vetter 34372b677e8cSDaniel Vetter fail_lookup: 34382b677e8cSDaniel Vetter mutex_unlock(&dev->mode_config.fb_lock); 34392b677e8cSDaniel Vetter mutex_unlock(&file_priv->fbs_lock); 34402b677e8cSDaniel Vetter 344137c4e705SVille Syrjälä return -ENOENT; 3442f453ba04SDave Airlie } 3443f453ba04SDave Airlie 3444f453ba04SDave Airlie /** 3445f453ba04SDave Airlie * drm_mode_getfb - get FB info 3446065a50edSDaniel Vetter * @dev: drm device for the ioctl 3447065a50edSDaniel Vetter * @data: data pointer for the ioctl 3448065a50edSDaniel Vetter * @file_priv: drm file for the ioctl call 3449f453ba04SDave Airlie * 3450f453ba04SDave Airlie * Lookup the FB given its ID and return info about it. 3451f453ba04SDave Airlie * 3452f453ba04SDave Airlie * Called by the user via ioctl. 3453f453ba04SDave Airlie * 3454c8e32cc1SDaniel Vetter * Returns: 34551a498633SDaniel Vetter * Zero on success, negative errno on failure. 3456f453ba04SDave Airlie */ 3457f453ba04SDave Airlie int drm_mode_getfb(struct drm_device *dev, 3458f453ba04SDave Airlie void *data, struct drm_file *file_priv) 3459f453ba04SDave Airlie { 3460f453ba04SDave Airlie struct drm_mode_fb_cmd *r = data; 3461f453ba04SDave Airlie struct drm_framebuffer *fb; 346258c0dca1SDaniel Vetter int ret; 3463f453ba04SDave Airlie 3464fb3b06c8SDave Airlie if (!drm_core_check_feature(dev, DRIVER_MODESET)) 3465fb3b06c8SDave Airlie return -EINVAL; 3466fb3b06c8SDave Airlie 3467786b99edSDaniel Vetter fb = drm_framebuffer_lookup(dev, r->fb_id); 346858c0dca1SDaniel Vetter if (!fb) 346937c4e705SVille Syrjälä return -ENOENT; 3470f453ba04SDave Airlie 3471f453ba04SDave Airlie r->height = fb->height; 3472f453ba04SDave Airlie r->width = fb->width; 3473f453ba04SDave Airlie r->depth = fb->depth; 3474f453ba04SDave Airlie r->bpp = fb->bits_per_pixel; 347501f2c773SVille Syrjälä r->pitch = fb->pitches[0]; 3476101b96f3SDavid Herrmann if (fb->funcs->create_handle) { 347709f308f7SThomas Hellstrom if (file_priv->is_master || capable(CAP_SYS_ADMIN) || 347843683057SThomas Hellstrom drm_is_control_client(file_priv)) { 3479101b96f3SDavid Herrmann ret = fb->funcs->create_handle(fb, file_priv, 3480101b96f3SDavid Herrmann &r->handle); 3481101b96f3SDavid Herrmann } else { 3482101b96f3SDavid Herrmann /* GET_FB() is an unprivileged ioctl so we must not 3483101b96f3SDavid Herrmann * return a buffer-handle to non-master processes! For 3484101b96f3SDavid Herrmann * backwards-compatibility reasons, we cannot make 3485101b96f3SDavid Herrmann * GET_FB() privileged, so just return an invalid handle 3486101b96f3SDavid Herrmann * for non-masters. */ 3487101b96f3SDavid Herrmann r->handle = 0; 3488101b96f3SDavid Herrmann ret = 0; 3489101b96f3SDavid Herrmann } 3490101b96f3SDavid Herrmann } else { 3491af26ef3bSDaniel Vetter ret = -ENODEV; 3492101b96f3SDavid Herrmann } 3493f453ba04SDave Airlie 349458c0dca1SDaniel Vetter drm_framebuffer_unreference(fb); 349558c0dca1SDaniel Vetter 3496f453ba04SDave Airlie return ret; 3497f453ba04SDave Airlie } 3498f453ba04SDave Airlie 3499c8e32cc1SDaniel Vetter /** 3500c8e32cc1SDaniel Vetter * drm_mode_dirtyfb_ioctl - flush frontbuffer rendering on an FB 3501c8e32cc1SDaniel Vetter * @dev: drm device for the ioctl 3502c8e32cc1SDaniel Vetter * @data: data pointer for the ioctl 3503c8e32cc1SDaniel Vetter * @file_priv: drm file for the ioctl call 3504c8e32cc1SDaniel Vetter * 3505c8e32cc1SDaniel Vetter * Lookup the FB and flush out the damaged area supplied by userspace as a clip 3506c8e32cc1SDaniel Vetter * rectangle list. Generic userspace which does frontbuffer rendering must call 3507c8e32cc1SDaniel Vetter * this ioctl to flush out the changes on manual-update display outputs, e.g. 3508c8e32cc1SDaniel Vetter * usb display-link, mipi manual update panels or edp panel self refresh modes. 3509c8e32cc1SDaniel Vetter * 3510c8e32cc1SDaniel Vetter * Modesetting drivers which always update the frontbuffer do not need to 3511c8e32cc1SDaniel Vetter * implement the corresponding ->dirty framebuffer callback. 3512c8e32cc1SDaniel Vetter * 3513c8e32cc1SDaniel Vetter * Called by the user via ioctl. 3514c8e32cc1SDaniel Vetter * 3515c8e32cc1SDaniel Vetter * Returns: 35161a498633SDaniel Vetter * Zero on success, negative errno on failure. 3517c8e32cc1SDaniel Vetter */ 3518884840aaSJakob Bornecrantz int drm_mode_dirtyfb_ioctl(struct drm_device *dev, 3519884840aaSJakob Bornecrantz void *data, struct drm_file *file_priv) 3520884840aaSJakob Bornecrantz { 3521884840aaSJakob Bornecrantz struct drm_clip_rect __user *clips_ptr; 3522884840aaSJakob Bornecrantz struct drm_clip_rect *clips = NULL; 3523884840aaSJakob Bornecrantz struct drm_mode_fb_dirty_cmd *r = data; 3524884840aaSJakob Bornecrantz struct drm_framebuffer *fb; 3525884840aaSJakob Bornecrantz unsigned flags; 3526884840aaSJakob Bornecrantz int num_clips; 35274a1b0714SLaurent Pinchart int ret; 3528884840aaSJakob Bornecrantz 3529fb3b06c8SDave Airlie if (!drm_core_check_feature(dev, DRIVER_MODESET)) 3530fb3b06c8SDave Airlie return -EINVAL; 3531fb3b06c8SDave Airlie 3532786b99edSDaniel Vetter fb = drm_framebuffer_lookup(dev, r->fb_id); 35334ccf097fSDaniel Vetter if (!fb) 353437c4e705SVille Syrjälä return -ENOENT; 3535884840aaSJakob Bornecrantz 3536884840aaSJakob Bornecrantz num_clips = r->num_clips; 353781f6c7f8SVille Syrjälä clips_ptr = (struct drm_clip_rect __user *)(unsigned long)r->clips_ptr; 3538884840aaSJakob Bornecrantz 3539884840aaSJakob Bornecrantz if (!num_clips != !clips_ptr) { 3540884840aaSJakob Bornecrantz ret = -EINVAL; 3541884840aaSJakob Bornecrantz goto out_err1; 3542884840aaSJakob Bornecrantz } 3543884840aaSJakob Bornecrantz 3544884840aaSJakob Bornecrantz flags = DRM_MODE_FB_DIRTY_FLAGS & r->flags; 3545884840aaSJakob Bornecrantz 3546884840aaSJakob Bornecrantz /* If userspace annotates copy, clips must come in pairs */ 3547884840aaSJakob Bornecrantz if (flags & DRM_MODE_FB_DIRTY_ANNOTATE_COPY && (num_clips % 2)) { 3548884840aaSJakob Bornecrantz ret = -EINVAL; 3549884840aaSJakob Bornecrantz goto out_err1; 3550884840aaSJakob Bornecrantz } 3551884840aaSJakob Bornecrantz 3552884840aaSJakob Bornecrantz if (num_clips && clips_ptr) { 3553a5cd3351SXi Wang if (num_clips < 0 || num_clips > DRM_MODE_FB_DIRTY_MAX_CLIPS) { 3554a5cd3351SXi Wang ret = -EINVAL; 3555a5cd3351SXi Wang goto out_err1; 3556a5cd3351SXi Wang } 3557bd3f0ff9SThierry Reding clips = kcalloc(num_clips, sizeof(*clips), GFP_KERNEL); 3558884840aaSJakob Bornecrantz if (!clips) { 3559884840aaSJakob Bornecrantz ret = -ENOMEM; 3560884840aaSJakob Bornecrantz goto out_err1; 3561884840aaSJakob Bornecrantz } 3562884840aaSJakob Bornecrantz 3563884840aaSJakob Bornecrantz ret = copy_from_user(clips, clips_ptr, 3564884840aaSJakob Bornecrantz num_clips * sizeof(*clips)); 3565e902a358SDan Carpenter if (ret) { 3566e902a358SDan Carpenter ret = -EFAULT; 3567884840aaSJakob Bornecrantz goto out_err2; 3568884840aaSJakob Bornecrantz } 3569e902a358SDan Carpenter } 3570884840aaSJakob Bornecrantz 3571884840aaSJakob Bornecrantz if (fb->funcs->dirty) { 357202b00162SThomas Hellstrom ret = fb->funcs->dirty(fb, file_priv, flags, r->color, 357302b00162SThomas Hellstrom clips, num_clips); 3574884840aaSJakob Bornecrantz } else { 3575884840aaSJakob Bornecrantz ret = -ENOSYS; 3576884840aaSJakob Bornecrantz } 3577884840aaSJakob Bornecrantz 3578884840aaSJakob Bornecrantz out_err2: 3579884840aaSJakob Bornecrantz kfree(clips); 3580884840aaSJakob Bornecrantz out_err1: 35814ccf097fSDaniel Vetter drm_framebuffer_unreference(fb); 35824ccf097fSDaniel Vetter 3583884840aaSJakob Bornecrantz return ret; 3584884840aaSJakob Bornecrantz } 3585884840aaSJakob Bornecrantz 3586884840aaSJakob Bornecrantz 3587f453ba04SDave Airlie /** 3588f453ba04SDave Airlie * drm_fb_release - remove and free the FBs on this file 3589065a50edSDaniel Vetter * @priv: drm file for the ioctl 3590f453ba04SDave Airlie * 3591f453ba04SDave Airlie * Destroy all the FBs associated with @filp. 3592f453ba04SDave Airlie * 3593f453ba04SDave Airlie * Called by the user via ioctl. 3594f453ba04SDave Airlie * 3595c8e32cc1SDaniel Vetter * Returns: 35961a498633SDaniel Vetter * Zero on success, negative errno on failure. 3597f453ba04SDave Airlie */ 3598ea39f835SKristian Høgsberg void drm_fb_release(struct drm_file *priv) 3599f453ba04SDave Airlie { 3600f453ba04SDave Airlie struct drm_device *dev = priv->minor->dev; 3601f453ba04SDave Airlie struct drm_framebuffer *fb, *tfb; 3602f453ba04SDave Airlie 36031b116297SDaniel Vetter /* 36041b116297SDaniel Vetter * When the file gets released that means no one else can access the fb 3605e2db726bSMartin Peres * list any more, so no need to grab fpriv->fbs_lock. And we need to 36061b116297SDaniel Vetter * avoid upsetting lockdep since the universal cursor code adds a 36071b116297SDaniel Vetter * framebuffer while holding mutex locks. 36081b116297SDaniel Vetter * 36091b116297SDaniel Vetter * Note that a real deadlock between fpriv->fbs_lock and the modeset 36101b116297SDaniel Vetter * locks is impossible here since no one else but this function can get 36111b116297SDaniel Vetter * at it any more. 36121b116297SDaniel Vetter */ 3613f453ba04SDave Airlie list_for_each_entry_safe(fb, tfb, &priv->fbs, filp_head) { 36142b677e8cSDaniel Vetter 36152b677e8cSDaniel Vetter mutex_lock(&dev->mode_config.fb_lock); 36162b677e8cSDaniel Vetter /* Mark fb as reaped, we still have a ref from fpriv->fbs. */ 36172b677e8cSDaniel Vetter __drm_framebuffer_unregister(dev, fb); 36182b677e8cSDaniel Vetter mutex_unlock(&dev->mode_config.fb_lock); 36192b677e8cSDaniel Vetter 36204b096ac1SDaniel Vetter list_del_init(&fb->filp_head); 36212b677e8cSDaniel Vetter 36222b677e8cSDaniel Vetter /* This will also drop the fpriv->fbs reference. */ 3623f7eff60eSRob Clark drm_framebuffer_remove(fb); 3624f453ba04SDave Airlie } 3625f453ba04SDave Airlie } 3626f453ba04SDave Airlie 3627c8e32cc1SDaniel Vetter /** 3628c8e32cc1SDaniel Vetter * drm_property_create - create a new property type 3629c8e32cc1SDaniel Vetter * @dev: drm device 3630c8e32cc1SDaniel Vetter * @flags: flags specifying the property type 3631c8e32cc1SDaniel Vetter * @name: name of the property 3632c8e32cc1SDaniel Vetter * @num_values: number of pre-defined values 3633c8e32cc1SDaniel Vetter * 3634c8e32cc1SDaniel Vetter * This creates a new generic drm property which can then be attached to a drm 3635c8e32cc1SDaniel Vetter * object with drm_object_attach_property. The returned property object must be 3636c8e32cc1SDaniel Vetter * freed with drm_property_destroy. 3637c8e32cc1SDaniel Vetter * 36383b5b9932SDamien Lespiau * Note that the DRM core keeps a per-device list of properties and that, if 36393b5b9932SDamien Lespiau * drm_mode_config_cleanup() is called, it will destroy all properties created 36403b5b9932SDamien Lespiau * by the driver. 36413b5b9932SDamien Lespiau * 3642c8e32cc1SDaniel Vetter * Returns: 3643c8e32cc1SDaniel Vetter * A pointer to the newly created property on success, NULL on failure. 3644c8e32cc1SDaniel Vetter */ 3645f453ba04SDave Airlie struct drm_property *drm_property_create(struct drm_device *dev, int flags, 3646f453ba04SDave Airlie const char *name, int num_values) 3647f453ba04SDave Airlie { 3648f453ba04SDave Airlie struct drm_property *property = NULL; 36496bfc56aaSVille Syrjälä int ret; 3650f453ba04SDave Airlie 3651f453ba04SDave Airlie property = kzalloc(sizeof(struct drm_property), GFP_KERNEL); 3652f453ba04SDave Airlie if (!property) 3653f453ba04SDave Airlie return NULL; 3654f453ba04SDave Airlie 365598f75de4SRob Clark property->dev = dev; 365698f75de4SRob Clark 3657f453ba04SDave Airlie if (num_values) { 3658bd3f0ff9SThierry Reding property->values = kcalloc(num_values, sizeof(uint64_t), 3659bd3f0ff9SThierry Reding GFP_KERNEL); 3660f453ba04SDave Airlie if (!property->values) 3661f453ba04SDave Airlie goto fail; 3662f453ba04SDave Airlie } 3663f453ba04SDave Airlie 36646bfc56aaSVille Syrjälä ret = drm_mode_object_get(dev, &property->base, DRM_MODE_OBJECT_PROPERTY); 36656bfc56aaSVille Syrjälä if (ret) 36666bfc56aaSVille Syrjälä goto fail; 36676bfc56aaSVille Syrjälä 3668f453ba04SDave Airlie property->flags = flags; 3669f453ba04SDave Airlie property->num_values = num_values; 36703758b341SDaniel Vetter INIT_LIST_HEAD(&property->enum_list); 3671f453ba04SDave Airlie 3672471dd2efSVinson Lee if (name) { 3673f453ba04SDave Airlie strncpy(property->name, name, DRM_PROP_NAME_LEN); 3674471dd2efSVinson Lee property->name[DRM_PROP_NAME_LEN-1] = '\0'; 3675471dd2efSVinson Lee } 3676f453ba04SDave Airlie 3677f453ba04SDave Airlie list_add_tail(&property->head, &dev->mode_config.property_list); 36785ea22f24SRob Clark 36795ea22f24SRob Clark WARN_ON(!drm_property_type_valid(property)); 36805ea22f24SRob Clark 3681f453ba04SDave Airlie return property; 3682f453ba04SDave Airlie fail: 36836bfc56aaSVille Syrjälä kfree(property->values); 3684f453ba04SDave Airlie kfree(property); 3685f453ba04SDave Airlie return NULL; 3686f453ba04SDave Airlie } 3687f453ba04SDave Airlie EXPORT_SYMBOL(drm_property_create); 3688f453ba04SDave Airlie 3689c8e32cc1SDaniel Vetter /** 36902aa9d2bcSThierry Reding * drm_property_create_enum - create a new enumeration property type 3691c8e32cc1SDaniel Vetter * @dev: drm device 3692c8e32cc1SDaniel Vetter * @flags: flags specifying the property type 3693c8e32cc1SDaniel Vetter * @name: name of the property 3694c8e32cc1SDaniel Vetter * @props: enumeration lists with property values 3695c8e32cc1SDaniel Vetter * @num_values: number of pre-defined values 3696c8e32cc1SDaniel Vetter * 3697c8e32cc1SDaniel Vetter * This creates a new generic drm property which can then be attached to a drm 3698c8e32cc1SDaniel Vetter * object with drm_object_attach_property. The returned property object must be 3699c8e32cc1SDaniel Vetter * freed with drm_property_destroy. 3700c8e32cc1SDaniel Vetter * 3701c8e32cc1SDaniel Vetter * Userspace is only allowed to set one of the predefined values for enumeration 3702c8e32cc1SDaniel Vetter * properties. 3703c8e32cc1SDaniel Vetter * 3704c8e32cc1SDaniel Vetter * Returns: 3705c8e32cc1SDaniel Vetter * A pointer to the newly created property on success, NULL on failure. 3706c8e32cc1SDaniel Vetter */ 37074a67d391SSascha Hauer struct drm_property *drm_property_create_enum(struct drm_device *dev, int flags, 37084a67d391SSascha Hauer const char *name, 37094a67d391SSascha Hauer const struct drm_prop_enum_list *props, 37104a67d391SSascha Hauer int num_values) 37114a67d391SSascha Hauer { 37124a67d391SSascha Hauer struct drm_property *property; 37134a67d391SSascha Hauer int i, ret; 37144a67d391SSascha Hauer 37154a67d391SSascha Hauer flags |= DRM_MODE_PROP_ENUM; 37164a67d391SSascha Hauer 37174a67d391SSascha Hauer property = drm_property_create(dev, flags, name, num_values); 37184a67d391SSascha Hauer if (!property) 37194a67d391SSascha Hauer return NULL; 37204a67d391SSascha Hauer 37214a67d391SSascha Hauer for (i = 0; i < num_values; i++) { 37224a67d391SSascha Hauer ret = drm_property_add_enum(property, i, 37234a67d391SSascha Hauer props[i].type, 37244a67d391SSascha Hauer props[i].name); 37254a67d391SSascha Hauer if (ret) { 37264a67d391SSascha Hauer drm_property_destroy(dev, property); 37274a67d391SSascha Hauer return NULL; 37284a67d391SSascha Hauer } 37294a67d391SSascha Hauer } 37304a67d391SSascha Hauer 37314a67d391SSascha Hauer return property; 37324a67d391SSascha Hauer } 37334a67d391SSascha Hauer EXPORT_SYMBOL(drm_property_create_enum); 37344a67d391SSascha Hauer 3735c8e32cc1SDaniel Vetter /** 37362aa9d2bcSThierry Reding * drm_property_create_bitmask - create a new bitmask property type 3737c8e32cc1SDaniel Vetter * @dev: drm device 3738c8e32cc1SDaniel Vetter * @flags: flags specifying the property type 3739c8e32cc1SDaniel Vetter * @name: name of the property 3740c8e32cc1SDaniel Vetter * @props: enumeration lists with property bitflags 3741295ee853SDaniel Vetter * @num_props: size of the @props array 3742295ee853SDaniel Vetter * @supported_bits: bitmask of all supported enumeration values 3743c8e32cc1SDaniel Vetter * 3744295ee853SDaniel Vetter * This creates a new bitmask drm property which can then be attached to a drm 3745c8e32cc1SDaniel Vetter * object with drm_object_attach_property. The returned property object must be 3746c8e32cc1SDaniel Vetter * freed with drm_property_destroy. 3747c8e32cc1SDaniel Vetter * 3748c8e32cc1SDaniel Vetter * Compared to plain enumeration properties userspace is allowed to set any 3749c8e32cc1SDaniel Vetter * or'ed together combination of the predefined property bitflag values 3750c8e32cc1SDaniel Vetter * 3751c8e32cc1SDaniel Vetter * Returns: 3752c8e32cc1SDaniel Vetter * A pointer to the newly created property on success, NULL on failure. 3753c8e32cc1SDaniel Vetter */ 375449e27545SRob Clark struct drm_property *drm_property_create_bitmask(struct drm_device *dev, 375549e27545SRob Clark int flags, const char *name, 375649e27545SRob Clark const struct drm_prop_enum_list *props, 37577689ffb3SVille Syrjälä int num_props, 37587689ffb3SVille Syrjälä uint64_t supported_bits) 375949e27545SRob Clark { 376049e27545SRob Clark struct drm_property *property; 37617689ffb3SVille Syrjälä int i, ret, index = 0; 37627689ffb3SVille Syrjälä int num_values = hweight64(supported_bits); 376349e27545SRob Clark 376449e27545SRob Clark flags |= DRM_MODE_PROP_BITMASK; 376549e27545SRob Clark 376649e27545SRob Clark property = drm_property_create(dev, flags, name, num_values); 376749e27545SRob Clark if (!property) 376849e27545SRob Clark return NULL; 37697689ffb3SVille Syrjälä for (i = 0; i < num_props; i++) { 37707689ffb3SVille Syrjälä if (!(supported_bits & (1ULL << props[i].type))) 37717689ffb3SVille Syrjälä continue; 377249e27545SRob Clark 37737689ffb3SVille Syrjälä if (WARN_ON(index >= num_values)) { 37747689ffb3SVille Syrjälä drm_property_destroy(dev, property); 37757689ffb3SVille Syrjälä return NULL; 37767689ffb3SVille Syrjälä } 37777689ffb3SVille Syrjälä 37787689ffb3SVille Syrjälä ret = drm_property_add_enum(property, index++, 377949e27545SRob Clark props[i].type, 378049e27545SRob Clark props[i].name); 378149e27545SRob Clark if (ret) { 378249e27545SRob Clark drm_property_destroy(dev, property); 378349e27545SRob Clark return NULL; 378449e27545SRob Clark } 378549e27545SRob Clark } 378649e27545SRob Clark 378749e27545SRob Clark return property; 378849e27545SRob Clark } 378949e27545SRob Clark EXPORT_SYMBOL(drm_property_create_bitmask); 379049e27545SRob Clark 3791ebc44cf3SRob Clark static struct drm_property *property_create_range(struct drm_device *dev, 3792ebc44cf3SRob Clark int flags, const char *name, 3793ebc44cf3SRob Clark uint64_t min, uint64_t max) 3794ebc44cf3SRob Clark { 3795ebc44cf3SRob Clark struct drm_property *property; 3796ebc44cf3SRob Clark 3797ebc44cf3SRob Clark property = drm_property_create(dev, flags, name, 2); 3798ebc44cf3SRob Clark if (!property) 3799ebc44cf3SRob Clark return NULL; 3800ebc44cf3SRob Clark 3801ebc44cf3SRob Clark property->values[0] = min; 3802ebc44cf3SRob Clark property->values[1] = max; 3803ebc44cf3SRob Clark 3804ebc44cf3SRob Clark return property; 3805ebc44cf3SRob Clark } 3806ebc44cf3SRob Clark 3807c8e32cc1SDaniel Vetter /** 3808960cd9d4SDaniel Vetter * drm_property_create_range - create a new unsigned ranged property type 3809c8e32cc1SDaniel Vetter * @dev: drm device 3810c8e32cc1SDaniel Vetter * @flags: flags specifying the property type 3811c8e32cc1SDaniel Vetter * @name: name of the property 3812c8e32cc1SDaniel Vetter * @min: minimum value of the property 3813c8e32cc1SDaniel Vetter * @max: maximum value of the property 3814c8e32cc1SDaniel Vetter * 3815c8e32cc1SDaniel Vetter * This creates a new generic drm property which can then be attached to a drm 3816c8e32cc1SDaniel Vetter * object with drm_object_attach_property. The returned property object must be 3817c8e32cc1SDaniel Vetter * freed with drm_property_destroy. 3818c8e32cc1SDaniel Vetter * 3819960cd9d4SDaniel Vetter * Userspace is allowed to set any unsigned integer value in the (min, max) 3820960cd9d4SDaniel Vetter * range inclusive. 3821c8e32cc1SDaniel Vetter * 3822c8e32cc1SDaniel Vetter * Returns: 3823c8e32cc1SDaniel Vetter * A pointer to the newly created property on success, NULL on failure. 3824c8e32cc1SDaniel Vetter */ 3825d9bc3c02SSascha Hauer struct drm_property *drm_property_create_range(struct drm_device *dev, int flags, 3826d9bc3c02SSascha Hauer const char *name, 3827d9bc3c02SSascha Hauer uint64_t min, uint64_t max) 3828d9bc3c02SSascha Hauer { 3829ebc44cf3SRob Clark return property_create_range(dev, DRM_MODE_PROP_RANGE | flags, 3830ebc44cf3SRob Clark name, min, max); 3831d9bc3c02SSascha Hauer } 3832d9bc3c02SSascha Hauer EXPORT_SYMBOL(drm_property_create_range); 3833d9bc3c02SSascha Hauer 3834960cd9d4SDaniel Vetter /** 3835960cd9d4SDaniel Vetter * drm_property_create_signed_range - create a new signed ranged property type 3836960cd9d4SDaniel Vetter * @dev: drm device 3837960cd9d4SDaniel Vetter * @flags: flags specifying the property type 3838960cd9d4SDaniel Vetter * @name: name of the property 3839960cd9d4SDaniel Vetter * @min: minimum value of the property 3840960cd9d4SDaniel Vetter * @max: maximum value of the property 3841960cd9d4SDaniel Vetter * 3842960cd9d4SDaniel Vetter * This creates a new generic drm property which can then be attached to a drm 3843960cd9d4SDaniel Vetter * object with drm_object_attach_property. The returned property object must be 3844960cd9d4SDaniel Vetter * freed with drm_property_destroy. 3845960cd9d4SDaniel Vetter * 3846960cd9d4SDaniel Vetter * Userspace is allowed to set any signed integer value in the (min, max) 3847960cd9d4SDaniel Vetter * range inclusive. 3848960cd9d4SDaniel Vetter * 3849960cd9d4SDaniel Vetter * Returns: 3850960cd9d4SDaniel Vetter * A pointer to the newly created property on success, NULL on failure. 3851960cd9d4SDaniel Vetter */ 3852ebc44cf3SRob Clark struct drm_property *drm_property_create_signed_range(struct drm_device *dev, 3853ebc44cf3SRob Clark int flags, const char *name, 3854ebc44cf3SRob Clark int64_t min, int64_t max) 3855ebc44cf3SRob Clark { 3856ebc44cf3SRob Clark return property_create_range(dev, DRM_MODE_PROP_SIGNED_RANGE | flags, 3857ebc44cf3SRob Clark name, I642U64(min), I642U64(max)); 3858ebc44cf3SRob Clark } 3859ebc44cf3SRob Clark EXPORT_SYMBOL(drm_property_create_signed_range); 3860ebc44cf3SRob Clark 3861960cd9d4SDaniel Vetter /** 3862960cd9d4SDaniel Vetter * drm_property_create_object - create a new object property type 3863960cd9d4SDaniel Vetter * @dev: drm device 3864960cd9d4SDaniel Vetter * @flags: flags specifying the property type 3865960cd9d4SDaniel Vetter * @name: name of the property 3866960cd9d4SDaniel Vetter * @type: object type from DRM_MODE_OBJECT_* defines 3867960cd9d4SDaniel Vetter * 3868960cd9d4SDaniel Vetter * This creates a new generic drm property which can then be attached to a drm 3869960cd9d4SDaniel Vetter * object with drm_object_attach_property. The returned property object must be 3870960cd9d4SDaniel Vetter * freed with drm_property_destroy. 3871960cd9d4SDaniel Vetter * 3872960cd9d4SDaniel Vetter * Userspace is only allowed to set this to any property value of the given 3873960cd9d4SDaniel Vetter * @type. Only useful for atomic properties, which is enforced. 3874960cd9d4SDaniel Vetter * 3875960cd9d4SDaniel Vetter * Returns: 3876960cd9d4SDaniel Vetter * A pointer to the newly created property on success, NULL on failure. 3877960cd9d4SDaniel Vetter */ 387898f75de4SRob Clark struct drm_property *drm_property_create_object(struct drm_device *dev, 387998f75de4SRob Clark int flags, const char *name, uint32_t type) 388098f75de4SRob Clark { 388198f75de4SRob Clark struct drm_property *property; 388298f75de4SRob Clark 388398f75de4SRob Clark flags |= DRM_MODE_PROP_OBJECT; 388498f75de4SRob Clark 3885960cd9d4SDaniel Vetter if (WARN_ON(!(flags & DRM_MODE_PROP_ATOMIC))) 3886960cd9d4SDaniel Vetter return NULL; 3887960cd9d4SDaniel Vetter 388898f75de4SRob Clark property = drm_property_create(dev, flags, name, 1); 388998f75de4SRob Clark if (!property) 389098f75de4SRob Clark return NULL; 389198f75de4SRob Clark 389298f75de4SRob Clark property->values[0] = type; 389398f75de4SRob Clark 389498f75de4SRob Clark return property; 389598f75de4SRob Clark } 389698f75de4SRob Clark EXPORT_SYMBOL(drm_property_create_object); 389798f75de4SRob Clark 3898c8e32cc1SDaniel Vetter /** 3899960cd9d4SDaniel Vetter * drm_property_create_bool - create a new boolean property type 3900960cd9d4SDaniel Vetter * @dev: drm device 3901960cd9d4SDaniel Vetter * @flags: flags specifying the property type 3902960cd9d4SDaniel Vetter * @name: name of the property 3903960cd9d4SDaniel Vetter * 3904960cd9d4SDaniel Vetter * This creates a new generic drm property which can then be attached to a drm 3905960cd9d4SDaniel Vetter * object with drm_object_attach_property. The returned property object must be 3906960cd9d4SDaniel Vetter * freed with drm_property_destroy. 3907960cd9d4SDaniel Vetter * 3908960cd9d4SDaniel Vetter * This is implemented as a ranged property with only {0, 1} as valid values. 3909960cd9d4SDaniel Vetter * 3910960cd9d4SDaniel Vetter * Returns: 3911960cd9d4SDaniel Vetter * A pointer to the newly created property on success, NULL on failure. 3912960cd9d4SDaniel Vetter */ 3913960cd9d4SDaniel Vetter struct drm_property *drm_property_create_bool(struct drm_device *dev, int flags, 3914960cd9d4SDaniel Vetter const char *name) 3915960cd9d4SDaniel Vetter { 3916960cd9d4SDaniel Vetter return drm_property_create_range(dev, flags, name, 0, 1); 3917960cd9d4SDaniel Vetter } 3918960cd9d4SDaniel Vetter EXPORT_SYMBOL(drm_property_create_bool); 3919960cd9d4SDaniel Vetter 3920960cd9d4SDaniel Vetter /** 3921c8e32cc1SDaniel Vetter * drm_property_add_enum - add a possible value to an enumeration property 3922c8e32cc1SDaniel Vetter * @property: enumeration property to change 3923c8e32cc1SDaniel Vetter * @index: index of the new enumeration 3924c8e32cc1SDaniel Vetter * @value: value of the new enumeration 3925c8e32cc1SDaniel Vetter * @name: symbolic name of the new enumeration 3926c8e32cc1SDaniel Vetter * 3927c8e32cc1SDaniel Vetter * This functions adds enumerations to a property. 3928c8e32cc1SDaniel Vetter * 3929c8e32cc1SDaniel Vetter * It's use is deprecated, drivers should use one of the more specific helpers 3930c8e32cc1SDaniel Vetter * to directly create the property with all enumerations already attached. 3931c8e32cc1SDaniel Vetter * 3932c8e32cc1SDaniel Vetter * Returns: 3933c8e32cc1SDaniel Vetter * Zero on success, error code on failure. 3934c8e32cc1SDaniel Vetter */ 3935f453ba04SDave Airlie int drm_property_add_enum(struct drm_property *property, int index, 3936f453ba04SDave Airlie uint64_t value, const char *name) 3937f453ba04SDave Airlie { 3938f453ba04SDave Airlie struct drm_property_enum *prop_enum; 3939f453ba04SDave Airlie 39405ea22f24SRob Clark if (!(drm_property_type_is(property, DRM_MODE_PROP_ENUM) || 39415ea22f24SRob Clark drm_property_type_is(property, DRM_MODE_PROP_BITMASK))) 394249e27545SRob Clark return -EINVAL; 394349e27545SRob Clark 394449e27545SRob Clark /* 394549e27545SRob Clark * Bitmask enum properties have the additional constraint of values 394649e27545SRob Clark * from 0 to 63 394749e27545SRob Clark */ 39485ea22f24SRob Clark if (drm_property_type_is(property, DRM_MODE_PROP_BITMASK) && 39495ea22f24SRob Clark (value > 63)) 3950f453ba04SDave Airlie return -EINVAL; 3951f453ba04SDave Airlie 39523758b341SDaniel Vetter if (!list_empty(&property->enum_list)) { 39533758b341SDaniel Vetter list_for_each_entry(prop_enum, &property->enum_list, head) { 3954f453ba04SDave Airlie if (prop_enum->value == value) { 3955f453ba04SDave Airlie strncpy(prop_enum->name, name, DRM_PROP_NAME_LEN); 3956f453ba04SDave Airlie prop_enum->name[DRM_PROP_NAME_LEN-1] = '\0'; 3957f453ba04SDave Airlie return 0; 3958f453ba04SDave Airlie } 3959f453ba04SDave Airlie } 3960f453ba04SDave Airlie } 3961f453ba04SDave Airlie 3962f453ba04SDave Airlie prop_enum = kzalloc(sizeof(struct drm_property_enum), GFP_KERNEL); 3963f453ba04SDave Airlie if (!prop_enum) 3964f453ba04SDave Airlie return -ENOMEM; 3965f453ba04SDave Airlie 3966f453ba04SDave Airlie strncpy(prop_enum->name, name, DRM_PROP_NAME_LEN); 3967f453ba04SDave Airlie prop_enum->name[DRM_PROP_NAME_LEN-1] = '\0'; 3968f453ba04SDave Airlie prop_enum->value = value; 3969f453ba04SDave Airlie 3970f453ba04SDave Airlie property->values[index] = value; 39713758b341SDaniel Vetter list_add_tail(&prop_enum->head, &property->enum_list); 3972f453ba04SDave Airlie return 0; 3973f453ba04SDave Airlie } 3974f453ba04SDave Airlie EXPORT_SYMBOL(drm_property_add_enum); 3975f453ba04SDave Airlie 3976c8e32cc1SDaniel Vetter /** 3977c8e32cc1SDaniel Vetter * drm_property_destroy - destroy a drm property 3978c8e32cc1SDaniel Vetter * @dev: drm device 3979c8e32cc1SDaniel Vetter * @property: property to destry 3980c8e32cc1SDaniel Vetter * 3981c8e32cc1SDaniel Vetter * This function frees a property including any attached resources like 3982c8e32cc1SDaniel Vetter * enumeration values. 3983c8e32cc1SDaniel Vetter */ 3984f453ba04SDave Airlie void drm_property_destroy(struct drm_device *dev, struct drm_property *property) 3985f453ba04SDave Airlie { 3986f453ba04SDave Airlie struct drm_property_enum *prop_enum, *pt; 3987f453ba04SDave Airlie 39883758b341SDaniel Vetter list_for_each_entry_safe(prop_enum, pt, &property->enum_list, head) { 3989f453ba04SDave Airlie list_del(&prop_enum->head); 3990f453ba04SDave Airlie kfree(prop_enum); 3991f453ba04SDave Airlie } 3992f453ba04SDave Airlie 3993f453ba04SDave Airlie if (property->num_values) 3994f453ba04SDave Airlie kfree(property->values); 3995f453ba04SDave Airlie drm_mode_object_put(dev, &property->base); 3996f453ba04SDave Airlie list_del(&property->head); 3997f453ba04SDave Airlie kfree(property); 3998f453ba04SDave Airlie } 3999f453ba04SDave Airlie EXPORT_SYMBOL(drm_property_destroy); 4000f453ba04SDave Airlie 4001c8e32cc1SDaniel Vetter /** 4002c8e32cc1SDaniel Vetter * drm_object_attach_property - attach a property to a modeset object 4003c8e32cc1SDaniel Vetter * @obj: drm modeset object 4004c8e32cc1SDaniel Vetter * @property: property to attach 4005c8e32cc1SDaniel Vetter * @init_val: initial value of the property 4006c8e32cc1SDaniel Vetter * 4007c8e32cc1SDaniel Vetter * This attaches the given property to the modeset object with the given initial 4008c8e32cc1SDaniel Vetter * value. Currently this function cannot fail since the properties are stored in 4009c8e32cc1SDaniel Vetter * a statically sized array. 4010c8e32cc1SDaniel Vetter */ 4011c543188aSPaulo Zanoni void drm_object_attach_property(struct drm_mode_object *obj, 4012c543188aSPaulo Zanoni struct drm_property *property, 4013c543188aSPaulo Zanoni uint64_t init_val) 4014c543188aSPaulo Zanoni { 40157f88a9beSPaulo Zanoni int count = obj->properties->count; 4016c543188aSPaulo Zanoni 40177f88a9beSPaulo Zanoni if (count == DRM_OBJECT_MAX_PROPERTY) { 40187f88a9beSPaulo Zanoni WARN(1, "Failed to attach object property (type: 0x%x). Please " 40197f88a9beSPaulo Zanoni "increase DRM_OBJECT_MAX_PROPERTY by 1 for each time " 40207f88a9beSPaulo Zanoni "you see this message on the same object type.\n", 40217f88a9beSPaulo Zanoni obj->type); 4022c543188aSPaulo Zanoni return; 4023c543188aSPaulo Zanoni } 4024c543188aSPaulo Zanoni 4025b17cd757SRob Clark obj->properties->properties[count] = property; 40267f88a9beSPaulo Zanoni obj->properties->values[count] = init_val; 40277f88a9beSPaulo Zanoni obj->properties->count++; 402888a48e29SRob Clark if (property->flags & DRM_MODE_PROP_ATOMIC) 402988a48e29SRob Clark obj->properties->atomic_count++; 4030c543188aSPaulo Zanoni } 4031c543188aSPaulo Zanoni EXPORT_SYMBOL(drm_object_attach_property); 4032c543188aSPaulo Zanoni 4033c8e32cc1SDaniel Vetter /** 4034c8e32cc1SDaniel Vetter * drm_object_property_set_value - set the value of a property 4035c8e32cc1SDaniel Vetter * @obj: drm mode object to set property value for 4036c8e32cc1SDaniel Vetter * @property: property to set 4037c8e32cc1SDaniel Vetter * @val: value the property should be set to 4038c8e32cc1SDaniel Vetter * 4039c8e32cc1SDaniel Vetter * This functions sets a given property on a given object. This function only 4040c8e32cc1SDaniel Vetter * changes the software state of the property, it does not call into the 4041c8e32cc1SDaniel Vetter * driver's ->set_property callback. 4042c8e32cc1SDaniel Vetter * 4043c8e32cc1SDaniel Vetter * Returns: 4044c8e32cc1SDaniel Vetter * Zero on success, error code on failure. 4045c8e32cc1SDaniel Vetter */ 4046c543188aSPaulo Zanoni int drm_object_property_set_value(struct drm_mode_object *obj, 4047c543188aSPaulo Zanoni struct drm_property *property, uint64_t val) 4048c543188aSPaulo Zanoni { 4049c543188aSPaulo Zanoni int i; 4050c543188aSPaulo Zanoni 40517f88a9beSPaulo Zanoni for (i = 0; i < obj->properties->count; i++) { 4052b17cd757SRob Clark if (obj->properties->properties[i] == property) { 4053c543188aSPaulo Zanoni obj->properties->values[i] = val; 4054c543188aSPaulo Zanoni return 0; 4055c543188aSPaulo Zanoni } 4056c543188aSPaulo Zanoni } 4057c543188aSPaulo Zanoni 4058c543188aSPaulo Zanoni return -EINVAL; 4059c543188aSPaulo Zanoni } 4060c543188aSPaulo Zanoni EXPORT_SYMBOL(drm_object_property_set_value); 4061c543188aSPaulo Zanoni 4062c8e32cc1SDaniel Vetter /** 4063c8e32cc1SDaniel Vetter * drm_object_property_get_value - retrieve the value of a property 4064c8e32cc1SDaniel Vetter * @obj: drm mode object to get property value from 4065c8e32cc1SDaniel Vetter * @property: property to retrieve 4066c8e32cc1SDaniel Vetter * @val: storage for the property value 4067c8e32cc1SDaniel Vetter * 4068c8e32cc1SDaniel Vetter * This function retrieves the softare state of the given property for the given 4069c8e32cc1SDaniel Vetter * property. Since there is no driver callback to retrieve the current property 4070c8e32cc1SDaniel Vetter * value this might be out of sync with the hardware, depending upon the driver 4071c8e32cc1SDaniel Vetter * and property. 4072c8e32cc1SDaniel Vetter * 4073c8e32cc1SDaniel Vetter * Returns: 4074c8e32cc1SDaniel Vetter * Zero on success, error code on failure. 4075c8e32cc1SDaniel Vetter */ 4076c543188aSPaulo Zanoni int drm_object_property_get_value(struct drm_mode_object *obj, 4077c543188aSPaulo Zanoni struct drm_property *property, uint64_t *val) 4078c543188aSPaulo Zanoni { 4079c543188aSPaulo Zanoni int i; 4080c543188aSPaulo Zanoni 408188a48e29SRob Clark /* read-only properties bypass atomic mechanism and still store 408288a48e29SRob Clark * their value in obj->properties->values[].. mostly to avoid 408388a48e29SRob Clark * having to deal w/ EDID and similar props in atomic paths: 408488a48e29SRob Clark */ 408588a48e29SRob Clark if (drm_core_check_feature(property->dev, DRIVER_ATOMIC) && 408688a48e29SRob Clark !(property->flags & DRM_MODE_PROP_IMMUTABLE)) 408788a48e29SRob Clark return drm_atomic_get_property(obj, property, val); 408888a48e29SRob Clark 40897f88a9beSPaulo Zanoni for (i = 0; i < obj->properties->count; i++) { 4090b17cd757SRob Clark if (obj->properties->properties[i] == property) { 4091c543188aSPaulo Zanoni *val = obj->properties->values[i]; 4092c543188aSPaulo Zanoni return 0; 4093c543188aSPaulo Zanoni } 4094c543188aSPaulo Zanoni } 4095c543188aSPaulo Zanoni 4096c543188aSPaulo Zanoni return -EINVAL; 4097c543188aSPaulo Zanoni } 4098c543188aSPaulo Zanoni EXPORT_SYMBOL(drm_object_property_get_value); 4099c543188aSPaulo Zanoni 4100c8e32cc1SDaniel Vetter /** 41011a498633SDaniel Vetter * drm_mode_getproperty_ioctl - get the property metadata 4102c8e32cc1SDaniel Vetter * @dev: DRM device 4103c8e32cc1SDaniel Vetter * @data: ioctl data 4104c8e32cc1SDaniel Vetter * @file_priv: DRM file info 4105c8e32cc1SDaniel Vetter * 41061a498633SDaniel Vetter * This function retrieves the metadata for a given property, like the different 41071a498633SDaniel Vetter * possible values for an enum property or the limits for a range property. 41081a498633SDaniel Vetter * 41091a498633SDaniel Vetter * Blob properties are special 4110c8e32cc1SDaniel Vetter * 4111c8e32cc1SDaniel Vetter * Called by the user via ioctl. 4112c8e32cc1SDaniel Vetter * 4113c8e32cc1SDaniel Vetter * Returns: 41141a498633SDaniel Vetter * Zero on success, negative errno on failure. 4115c8e32cc1SDaniel Vetter */ 4116f453ba04SDave Airlie int drm_mode_getproperty_ioctl(struct drm_device *dev, 4117f453ba04SDave Airlie void *data, struct drm_file *file_priv) 4118f453ba04SDave Airlie { 4119f453ba04SDave Airlie struct drm_mode_get_property *out_resp = data; 4120f453ba04SDave Airlie struct drm_property *property; 4121f453ba04SDave Airlie int enum_count = 0; 4122f453ba04SDave Airlie int value_count = 0; 4123f453ba04SDave Airlie int ret = 0, i; 4124f453ba04SDave Airlie int copied; 4125f453ba04SDave Airlie struct drm_property_enum *prop_enum; 4126f453ba04SDave Airlie struct drm_mode_property_enum __user *enum_ptr; 4127f453ba04SDave Airlie uint64_t __user *values_ptr; 4128f453ba04SDave Airlie 4129fb3b06c8SDave Airlie if (!drm_core_check_feature(dev, DRIVER_MODESET)) 4130fb3b06c8SDave Airlie return -EINVAL; 4131fb3b06c8SDave Airlie 413284849903SDaniel Vetter drm_modeset_lock_all(dev); 4133a2b34e22SRob Clark property = drm_property_find(dev, out_resp->prop_id); 4134a2b34e22SRob Clark if (!property) { 4135f27657f2SVille Syrjälä ret = -ENOENT; 4136f453ba04SDave Airlie goto done; 4137f453ba04SDave Airlie } 4138f453ba04SDave Airlie 41395ea22f24SRob Clark if (drm_property_type_is(property, DRM_MODE_PROP_ENUM) || 41405ea22f24SRob Clark drm_property_type_is(property, DRM_MODE_PROP_BITMASK)) { 41413758b341SDaniel Vetter list_for_each_entry(prop_enum, &property->enum_list, head) 4142f453ba04SDave Airlie enum_count++; 4143f453ba04SDave Airlie } 4144f453ba04SDave Airlie 4145f453ba04SDave Airlie value_count = property->num_values; 4146f453ba04SDave Airlie 4147f453ba04SDave Airlie strncpy(out_resp->name, property->name, DRM_PROP_NAME_LEN); 4148f453ba04SDave Airlie out_resp->name[DRM_PROP_NAME_LEN-1] = 0; 4149f453ba04SDave Airlie out_resp->flags = property->flags; 4150f453ba04SDave Airlie 4151f453ba04SDave Airlie if ((out_resp->count_values >= value_count) && value_count) { 415281f6c7f8SVille Syrjälä values_ptr = (uint64_t __user *)(unsigned long)out_resp->values_ptr; 4153f453ba04SDave Airlie for (i = 0; i < value_count; i++) { 4154f453ba04SDave Airlie if (copy_to_user(values_ptr + i, &property->values[i], sizeof(uint64_t))) { 4155f453ba04SDave Airlie ret = -EFAULT; 4156f453ba04SDave Airlie goto done; 4157f453ba04SDave Airlie } 4158f453ba04SDave Airlie } 4159f453ba04SDave Airlie } 4160f453ba04SDave Airlie out_resp->count_values = value_count; 4161f453ba04SDave Airlie 41625ea22f24SRob Clark if (drm_property_type_is(property, DRM_MODE_PROP_ENUM) || 41635ea22f24SRob Clark drm_property_type_is(property, DRM_MODE_PROP_BITMASK)) { 4164f453ba04SDave Airlie if ((out_resp->count_enum_blobs >= enum_count) && enum_count) { 4165f453ba04SDave Airlie copied = 0; 416681f6c7f8SVille Syrjälä enum_ptr = (struct drm_mode_property_enum __user *)(unsigned long)out_resp->enum_blob_ptr; 41673758b341SDaniel Vetter list_for_each_entry(prop_enum, &property->enum_list, head) { 4168f453ba04SDave Airlie 4169f453ba04SDave Airlie if (copy_to_user(&enum_ptr[copied].value, &prop_enum->value, sizeof(uint64_t))) { 4170f453ba04SDave Airlie ret = -EFAULT; 4171f453ba04SDave Airlie goto done; 4172f453ba04SDave Airlie } 4173f453ba04SDave Airlie 4174f453ba04SDave Airlie if (copy_to_user(&enum_ptr[copied].name, 4175f453ba04SDave Airlie &prop_enum->name, DRM_PROP_NAME_LEN)) { 4176f453ba04SDave Airlie ret = -EFAULT; 4177f453ba04SDave Airlie goto done; 4178f453ba04SDave Airlie } 4179f453ba04SDave Airlie copied++; 4180f453ba04SDave Airlie } 4181f453ba04SDave Airlie } 4182f453ba04SDave Airlie out_resp->count_enum_blobs = enum_count; 4183f453ba04SDave Airlie } 4184f453ba04SDave Airlie 41853758b341SDaniel Vetter /* 41863758b341SDaniel Vetter * NOTE: The idea seems to have been to use this to read all the blob 41873758b341SDaniel Vetter * property values. But nothing ever added them to the corresponding 41883758b341SDaniel Vetter * list, userspace always used the special-purpose get_blob ioctl to 41893758b341SDaniel Vetter * read the value for a blob property. It also doesn't make a lot of 41903758b341SDaniel Vetter * sense to return values here when everything else is just metadata for 41913758b341SDaniel Vetter * the property itself. 41923758b341SDaniel Vetter */ 41933758b341SDaniel Vetter if (drm_property_type_is(property, DRM_MODE_PROP_BLOB)) 41943758b341SDaniel Vetter out_resp->count_enum_blobs = 0; 4195f453ba04SDave Airlie done: 419684849903SDaniel Vetter drm_modeset_unlock_all(dev); 4197f453ba04SDave Airlie return ret; 4198f453ba04SDave Airlie } 4199f453ba04SDave Airlie 420099531d9bSDaniel Stone /** 420199531d9bSDaniel Stone * drm_property_create_blob - Create new blob property 420299531d9bSDaniel Stone * 420399531d9bSDaniel Stone * Creates a new blob property for a specified DRM device, optionally 420499531d9bSDaniel Stone * copying data. 420599531d9bSDaniel Stone * 420699531d9bSDaniel Stone * @dev: DRM device to create property for 420799531d9bSDaniel Stone * @length: Length to allocate for blob data 420899531d9bSDaniel Stone * @data: If specified, copies data into blob 420910e8cb7eSDaniel Stone * 421010e8cb7eSDaniel Stone * Returns: 421110e8cb7eSDaniel Stone * New blob property with a single reference on success, or an ERR_PTR 421210e8cb7eSDaniel Stone * value on failure. 421399531d9bSDaniel Stone */ 42146bcacf51SDaniel Stone struct drm_property_blob * 4215ecbbe59bSThierry Reding drm_property_create_blob(struct drm_device *dev, size_t length, 421612e6cecdSThierry Reding const void *data) 4217f453ba04SDave Airlie { 4218f453ba04SDave Airlie struct drm_property_blob *blob; 42196bfc56aaSVille Syrjälä int ret; 4220f453ba04SDave Airlie 422199531d9bSDaniel Stone if (!length) 422210e8cb7eSDaniel Stone return ERR_PTR(-EINVAL); 4223f453ba04SDave Airlie 4224f453ba04SDave Airlie blob = kzalloc(sizeof(struct drm_property_blob)+length, GFP_KERNEL); 4225f453ba04SDave Airlie if (!blob) 422610e8cb7eSDaniel Stone return ERR_PTR(-ENOMEM); 4227f453ba04SDave Airlie 4228e2f5d2eaSDaniel Stone /* This must be explicitly initialised, so we can safely call list_del 4229e2f5d2eaSDaniel Stone * on it in the removal handler, even if it isn't in a file list. */ 4230e2f5d2eaSDaniel Stone INIT_LIST_HEAD(&blob->head_file); 4231f453ba04SDave Airlie blob->length = length; 42326bcacf51SDaniel Stone blob->dev = dev; 4233f453ba04SDave Airlie 423499531d9bSDaniel Stone if (data) 4235f453ba04SDave Airlie memcpy(blob->data, data, length); 4236f453ba04SDave Airlie 42378fb6e7a5SDaniel Stone mutex_lock(&dev->mode_config.blob_lock); 42388fb6e7a5SDaniel Stone 42398fb6e7a5SDaniel Stone ret = drm_mode_object_get(dev, &blob->base, DRM_MODE_OBJECT_BLOB); 42408fb6e7a5SDaniel Stone if (ret) { 42418fb6e7a5SDaniel Stone kfree(blob); 42428fb6e7a5SDaniel Stone mutex_unlock(&dev->mode_config.blob_lock); 424310e8cb7eSDaniel Stone return ERR_PTR(-EINVAL); 42448fb6e7a5SDaniel Stone } 42458fb6e7a5SDaniel Stone 42466bcacf51SDaniel Stone kref_init(&blob->refcount); 42476bcacf51SDaniel Stone 4248e2f5d2eaSDaniel Stone list_add_tail(&blob->head_global, 4249e2f5d2eaSDaniel Stone &dev->mode_config.property_blob_list); 42508fb6e7a5SDaniel Stone 42518fb6e7a5SDaniel Stone mutex_unlock(&dev->mode_config.blob_lock); 42528fb6e7a5SDaniel Stone 4253f453ba04SDave Airlie return blob; 4254f453ba04SDave Airlie } 42556bcacf51SDaniel Stone EXPORT_SYMBOL(drm_property_create_blob); 4256f453ba04SDave Airlie 42576bcacf51SDaniel Stone /** 42586bcacf51SDaniel Stone * drm_property_free_blob - Blob property destructor 42596bcacf51SDaniel Stone * 42606bcacf51SDaniel Stone * Internal free function for blob properties; must not be used directly. 42616bcacf51SDaniel Stone * 4262f102c16eSDaniel Stone * @kref: Reference 42636bcacf51SDaniel Stone */ 42646bcacf51SDaniel Stone static void drm_property_free_blob(struct kref *kref) 4265f453ba04SDave Airlie { 42666bcacf51SDaniel Stone struct drm_property_blob *blob = 42676bcacf51SDaniel Stone container_of(kref, struct drm_property_blob, refcount); 42686bcacf51SDaniel Stone 42696bcacf51SDaniel Stone WARN_ON(!mutex_is_locked(&blob->dev->mode_config.blob_lock)); 42706bcacf51SDaniel Stone 4271e2f5d2eaSDaniel Stone list_del(&blob->head_global); 4272e2f5d2eaSDaniel Stone list_del(&blob->head_file); 42736bcacf51SDaniel Stone drm_mode_object_put(blob->dev, &blob->base); 42748fb6e7a5SDaniel Stone 4275f453ba04SDave Airlie kfree(blob); 4276f453ba04SDave Airlie } 4277f453ba04SDave Airlie 4278c8e32cc1SDaniel Vetter /** 42796bcacf51SDaniel Stone * drm_property_unreference_blob - Unreference a blob property 42806bcacf51SDaniel Stone * 42816bcacf51SDaniel Stone * Drop a reference on a blob property. May free the object. 42826bcacf51SDaniel Stone * 4283f102c16eSDaniel Stone * @blob: Pointer to blob property 42846bcacf51SDaniel Stone */ 42856bcacf51SDaniel Stone void drm_property_unreference_blob(struct drm_property_blob *blob) 42866bcacf51SDaniel Stone { 42876bcacf51SDaniel Stone struct drm_device *dev; 42886bcacf51SDaniel Stone 42896bcacf51SDaniel Stone if (!blob) 42906bcacf51SDaniel Stone return; 42916bcacf51SDaniel Stone 42926bcacf51SDaniel Stone dev = blob->dev; 42936bcacf51SDaniel Stone 42946bcacf51SDaniel Stone DRM_DEBUG("%p: blob ID: %d (%d)\n", blob, blob->base.id, atomic_read(&blob->refcount.refcount)); 42956bcacf51SDaniel Stone 42966bcacf51SDaniel Stone if (kref_put_mutex(&blob->refcount, drm_property_free_blob, 42976bcacf51SDaniel Stone &dev->mode_config.blob_lock)) 42986bcacf51SDaniel Stone mutex_unlock(&dev->mode_config.blob_lock); 42996bcacf51SDaniel Stone else 43006bcacf51SDaniel Stone might_lock(&dev->mode_config.blob_lock); 43016bcacf51SDaniel Stone } 43026bcacf51SDaniel Stone EXPORT_SYMBOL(drm_property_unreference_blob); 43036bcacf51SDaniel Stone 43046bcacf51SDaniel Stone /** 43056bcacf51SDaniel Stone * drm_property_unreference_blob_locked - Unreference a blob property with blob_lock held 43066bcacf51SDaniel Stone * 43076bcacf51SDaniel Stone * Drop a reference on a blob property. May free the object. This must be 43086bcacf51SDaniel Stone * called with blob_lock held. 43096bcacf51SDaniel Stone * 4310f102c16eSDaniel Stone * @blob: Pointer to blob property 43116bcacf51SDaniel Stone */ 43126bcacf51SDaniel Stone static void drm_property_unreference_blob_locked(struct drm_property_blob *blob) 43136bcacf51SDaniel Stone { 43146bcacf51SDaniel Stone if (!blob) 43156bcacf51SDaniel Stone return; 43166bcacf51SDaniel Stone 43176bcacf51SDaniel Stone DRM_DEBUG("%p: blob ID: %d (%d)\n", blob, blob->base.id, atomic_read(&blob->refcount.refcount)); 43186bcacf51SDaniel Stone 43196bcacf51SDaniel Stone kref_put(&blob->refcount, drm_property_free_blob); 43206bcacf51SDaniel Stone } 43216bcacf51SDaniel Stone 43226bcacf51SDaniel Stone /** 4323e2f5d2eaSDaniel Stone * drm_property_destroy_user_blobs - destroy all blobs created by this client 4324e2f5d2eaSDaniel Stone * @dev: DRM device 4325e2f5d2eaSDaniel Stone * @file_priv: destroy all blobs owned by this file handle 4326e2f5d2eaSDaniel Stone */ 4327e2f5d2eaSDaniel Stone void drm_property_destroy_user_blobs(struct drm_device *dev, 4328e2f5d2eaSDaniel Stone struct drm_file *file_priv) 4329e2f5d2eaSDaniel Stone { 4330e2f5d2eaSDaniel Stone struct drm_property_blob *blob, *bt; 4331e2f5d2eaSDaniel Stone 4332e2f5d2eaSDaniel Stone mutex_lock(&dev->mode_config.blob_lock); 4333e2f5d2eaSDaniel Stone 4334e2f5d2eaSDaniel Stone list_for_each_entry_safe(blob, bt, &file_priv->blobs, head_file) { 4335e2f5d2eaSDaniel Stone list_del_init(&blob->head_file); 4336e2f5d2eaSDaniel Stone drm_property_unreference_blob_locked(blob); 4337e2f5d2eaSDaniel Stone } 4338e2f5d2eaSDaniel Stone 4339e2f5d2eaSDaniel Stone mutex_unlock(&dev->mode_config.blob_lock); 4340e2f5d2eaSDaniel Stone } 4341e2f5d2eaSDaniel Stone 4342e2f5d2eaSDaniel Stone /** 43436bcacf51SDaniel Stone * drm_property_reference_blob - Take a reference on an existing property 43446bcacf51SDaniel Stone * 43456bcacf51SDaniel Stone * Take a new reference on an existing blob property. 43466bcacf51SDaniel Stone * 4347f102c16eSDaniel Stone * @blob: Pointer to blob property 43486bcacf51SDaniel Stone */ 43496bcacf51SDaniel Stone struct drm_property_blob *drm_property_reference_blob(struct drm_property_blob *blob) 43506bcacf51SDaniel Stone { 43516bcacf51SDaniel Stone DRM_DEBUG("%p: blob ID: %d (%d)\n", blob, blob->base.id, atomic_read(&blob->refcount.refcount)); 43526bcacf51SDaniel Stone kref_get(&blob->refcount); 43536bcacf51SDaniel Stone return blob; 43546bcacf51SDaniel Stone } 43556bcacf51SDaniel Stone EXPORT_SYMBOL(drm_property_reference_blob); 43566bcacf51SDaniel Stone 43576bcacf51SDaniel Stone /* 43586bcacf51SDaniel Stone * Like drm_property_lookup_blob, but does not return an additional reference. 43596bcacf51SDaniel Stone * Must be called with blob_lock held. 43606bcacf51SDaniel Stone */ 43616bcacf51SDaniel Stone static struct drm_property_blob *__drm_property_lookup_blob(struct drm_device *dev, 43626bcacf51SDaniel Stone uint32_t id) 43636bcacf51SDaniel Stone { 43646bcacf51SDaniel Stone struct drm_mode_object *obj = NULL; 43656bcacf51SDaniel Stone struct drm_property_blob *blob; 43666bcacf51SDaniel Stone 43676bcacf51SDaniel Stone WARN_ON(!mutex_is_locked(&dev->mode_config.blob_lock)); 43686bcacf51SDaniel Stone 43696bcacf51SDaniel Stone mutex_lock(&dev->mode_config.idr_mutex); 43706bcacf51SDaniel Stone obj = idr_find(&dev->mode_config.crtc_idr, id); 43716bcacf51SDaniel Stone if (!obj || (obj->type != DRM_MODE_OBJECT_BLOB) || (obj->id != id)) 43726bcacf51SDaniel Stone blob = NULL; 43736bcacf51SDaniel Stone else 43746bcacf51SDaniel Stone blob = obj_to_blob(obj); 43756bcacf51SDaniel Stone mutex_unlock(&dev->mode_config.idr_mutex); 43766bcacf51SDaniel Stone 4377f453ba04SDave Airlie return blob; 4378f453ba04SDave Airlie } 4379f453ba04SDave Airlie 43806bcacf51SDaniel Stone /** 43816bcacf51SDaniel Stone * drm_property_lookup_blob - look up a blob property and take a reference 43826bcacf51SDaniel Stone * @dev: drm device 43836bcacf51SDaniel Stone * @id: id of the blob property 43846bcacf51SDaniel Stone * 43856bcacf51SDaniel Stone * If successful, this takes an additional reference to the blob property. 43866bcacf51SDaniel Stone * callers need to make sure to eventually unreference the returned property 43876bcacf51SDaniel Stone * again, using @drm_property_unreference_blob. 43886bcacf51SDaniel Stone */ 43896bcacf51SDaniel Stone struct drm_property_blob *drm_property_lookup_blob(struct drm_device *dev, 43906bcacf51SDaniel Stone uint32_t id) 4391f453ba04SDave Airlie { 43926bcacf51SDaniel Stone struct drm_property_blob *blob; 43936bcacf51SDaniel Stone 43946bcacf51SDaniel Stone mutex_lock(&dev->mode_config.blob_lock); 43956bcacf51SDaniel Stone blob = __drm_property_lookup_blob(dev, id); 43966bcacf51SDaniel Stone if (blob) { 43976bcacf51SDaniel Stone if (!kref_get_unless_zero(&blob->refcount)) 43986bcacf51SDaniel Stone blob = NULL; 43996bcacf51SDaniel Stone } 44006bcacf51SDaniel Stone mutex_unlock(&dev->mode_config.blob_lock); 44016bcacf51SDaniel Stone 44026bcacf51SDaniel Stone return blob; 44036bcacf51SDaniel Stone } 44046bcacf51SDaniel Stone EXPORT_SYMBOL(drm_property_lookup_blob); 44056bcacf51SDaniel Stone 44066bcacf51SDaniel Stone /** 4407d2ed3436SDaniel Stone * drm_property_replace_global_blob - atomically replace existing blob property 4408d2ed3436SDaniel Stone * @dev: drm device 4409d2ed3436SDaniel Stone * @replace: location of blob property pointer to be replaced 4410d2ed3436SDaniel Stone * @length: length of data for new blob, or 0 for no data 4411d2ed3436SDaniel Stone * @data: content for new blob, or NULL for no data 4412d2ed3436SDaniel Stone * @obj_holds_id: optional object for property holding blob ID 4413d2ed3436SDaniel Stone * @prop_holds_id: optional property holding blob ID 4414d2ed3436SDaniel Stone * @return 0 on success or error on failure 4415d2ed3436SDaniel Stone * 4416d2ed3436SDaniel Stone * This function will atomically replace a global property in the blob list, 4417d2ed3436SDaniel Stone * optionally updating a property which holds the ID of that property. It is 4418d2ed3436SDaniel Stone * guaranteed to be atomic: no caller will be allowed to see intermediate 4419d2ed3436SDaniel Stone * results, and either the entire operation will succeed and clean up the 4420d2ed3436SDaniel Stone * previous property, or it will fail and the state will be unchanged. 4421d2ed3436SDaniel Stone * 4422d2ed3436SDaniel Stone * If length is 0 or data is NULL, no new blob will be created, and the holding 4423d2ed3436SDaniel Stone * property, if specified, will be set to 0. 4424d2ed3436SDaniel Stone * 4425d2ed3436SDaniel Stone * Access to the replace pointer is assumed to be protected by the caller, e.g. 4426d2ed3436SDaniel Stone * by holding the relevant modesetting object lock for its parent. 4427d2ed3436SDaniel Stone * 4428d2ed3436SDaniel Stone * For example, a drm_connector has a 'PATH' property, which contains the ID 4429d2ed3436SDaniel Stone * of a blob property with the value of the MST path information. Calling this 4430d2ed3436SDaniel Stone * function with replace pointing to the connector's path_blob_ptr, length and 4431d2ed3436SDaniel Stone * data set for the new path information, obj_holds_id set to the connector's 4432d2ed3436SDaniel Stone * base object, and prop_holds_id set to the path property name, will perform 4433d2ed3436SDaniel Stone * a completely atomic update. The access to path_blob_ptr is protected by the 4434d2ed3436SDaniel Stone * caller holding a lock on the connector. 4435d2ed3436SDaniel Stone */ 4436d2ed3436SDaniel Stone static int drm_property_replace_global_blob(struct drm_device *dev, 4437d2ed3436SDaniel Stone struct drm_property_blob **replace, 4438d2ed3436SDaniel Stone size_t length, 4439d2ed3436SDaniel Stone const void *data, 4440d2ed3436SDaniel Stone struct drm_mode_object *obj_holds_id, 4441d2ed3436SDaniel Stone struct drm_property *prop_holds_id) 4442d2ed3436SDaniel Stone { 4443d2ed3436SDaniel Stone struct drm_property_blob *new_blob = NULL; 4444d2ed3436SDaniel Stone struct drm_property_blob *old_blob = NULL; 4445d2ed3436SDaniel Stone int ret; 4446d2ed3436SDaniel Stone 4447d2ed3436SDaniel Stone WARN_ON(replace == NULL); 4448d2ed3436SDaniel Stone 4449d2ed3436SDaniel Stone old_blob = *replace; 4450d2ed3436SDaniel Stone 4451d2ed3436SDaniel Stone if (length && data) { 4452d2ed3436SDaniel Stone new_blob = drm_property_create_blob(dev, length, data); 445310e8cb7eSDaniel Stone if (IS_ERR(new_blob)) 445410e8cb7eSDaniel Stone return PTR_ERR(new_blob); 4455d2ed3436SDaniel Stone } 4456d2ed3436SDaniel Stone 4457d2ed3436SDaniel Stone /* This does not need to be synchronised with blob_lock, as the 4458d2ed3436SDaniel Stone * get_properties ioctl locks all modesetting objects, and 4459d2ed3436SDaniel Stone * obj_holds_id must be locked before calling here, so we cannot 4460d2ed3436SDaniel Stone * have its value out of sync with the list membership modified 4461d2ed3436SDaniel Stone * below under blob_lock. */ 4462d2ed3436SDaniel Stone if (obj_holds_id) { 4463d2ed3436SDaniel Stone ret = drm_object_property_set_value(obj_holds_id, 4464d2ed3436SDaniel Stone prop_holds_id, 4465d2ed3436SDaniel Stone new_blob ? 4466d2ed3436SDaniel Stone new_blob->base.id : 0); 4467d2ed3436SDaniel Stone if (ret != 0) 4468d2ed3436SDaniel Stone goto err_created; 4469d2ed3436SDaniel Stone } 4470d2ed3436SDaniel Stone 4471d2ed3436SDaniel Stone if (old_blob) 44726bcacf51SDaniel Stone drm_property_unreference_blob(old_blob); 4473d2ed3436SDaniel Stone 4474d2ed3436SDaniel Stone *replace = new_blob; 4475d2ed3436SDaniel Stone 4476d2ed3436SDaniel Stone return 0; 4477d2ed3436SDaniel Stone 4478d2ed3436SDaniel Stone err_created: 44796bcacf51SDaniel Stone drm_property_unreference_blob(new_blob); 4480d2ed3436SDaniel Stone return ret; 4481f453ba04SDave Airlie } 4482f453ba04SDave Airlie 4483c8e32cc1SDaniel Vetter /** 4484c8e32cc1SDaniel Vetter * drm_mode_getblob_ioctl - get the contents of a blob property value 4485c8e32cc1SDaniel Vetter * @dev: DRM device 4486c8e32cc1SDaniel Vetter * @data: ioctl data 4487c8e32cc1SDaniel Vetter * @file_priv: DRM file info 4488c8e32cc1SDaniel Vetter * 4489c8e32cc1SDaniel Vetter * This function retrieves the contents of a blob property. The value stored in 4490c8e32cc1SDaniel Vetter * an object's blob property is just a normal modeset object id. 4491c8e32cc1SDaniel Vetter * 4492c8e32cc1SDaniel Vetter * Called by the user via ioctl. 4493c8e32cc1SDaniel Vetter * 4494c8e32cc1SDaniel Vetter * Returns: 44951a498633SDaniel Vetter * Zero on success, negative errno on failure. 4496c8e32cc1SDaniel Vetter */ 4497f453ba04SDave Airlie int drm_mode_getblob_ioctl(struct drm_device *dev, 4498f453ba04SDave Airlie void *data, struct drm_file *file_priv) 4499f453ba04SDave Airlie { 4500f453ba04SDave Airlie struct drm_mode_get_blob *out_resp = data; 4501f453ba04SDave Airlie struct drm_property_blob *blob; 4502f453ba04SDave Airlie int ret = 0; 450381f6c7f8SVille Syrjälä void __user *blob_ptr; 4504f453ba04SDave Airlie 4505fb3b06c8SDave Airlie if (!drm_core_check_feature(dev, DRIVER_MODESET)) 4506fb3b06c8SDave Airlie return -EINVAL; 4507fb3b06c8SDave Airlie 450884849903SDaniel Vetter drm_modeset_lock_all(dev); 45098fb6e7a5SDaniel Stone mutex_lock(&dev->mode_config.blob_lock); 45106bcacf51SDaniel Stone blob = __drm_property_lookup_blob(dev, out_resp->blob_id); 4511a2b34e22SRob Clark if (!blob) { 4512f27657f2SVille Syrjälä ret = -ENOENT; 4513f453ba04SDave Airlie goto done; 4514f453ba04SDave Airlie } 4515f453ba04SDave Airlie 4516f453ba04SDave Airlie if (out_resp->length == blob->length) { 451781f6c7f8SVille Syrjälä blob_ptr = (void __user *)(unsigned long)out_resp->data; 4518f453ba04SDave Airlie if (copy_to_user(blob_ptr, blob->data, blob->length)) { 4519f453ba04SDave Airlie ret = -EFAULT; 4520f453ba04SDave Airlie goto done; 4521f453ba04SDave Airlie } 4522f453ba04SDave Airlie } 4523f453ba04SDave Airlie out_resp->length = blob->length; 4524f453ba04SDave Airlie 4525f453ba04SDave Airlie done: 45268fb6e7a5SDaniel Stone mutex_unlock(&dev->mode_config.blob_lock); 452784849903SDaniel Vetter drm_modeset_unlock_all(dev); 4528f453ba04SDave Airlie return ret; 4529f453ba04SDave Airlie } 4530f453ba04SDave Airlie 4531cc7096fbSDave Airlie /** 4532e2f5d2eaSDaniel Stone * drm_mode_createblob_ioctl - create a new blob property 4533e2f5d2eaSDaniel Stone * @dev: DRM device 4534e2f5d2eaSDaniel Stone * @data: ioctl data 4535e2f5d2eaSDaniel Stone * @file_priv: DRM file info 4536e2f5d2eaSDaniel Stone * 4537e2f5d2eaSDaniel Stone * This function creates a new blob property with user-defined values. In order 4538e2f5d2eaSDaniel Stone * to give us sensible validation and checking when creating, rather than at 4539e2f5d2eaSDaniel Stone * every potential use, we also require a type to be provided upfront. 4540e2f5d2eaSDaniel Stone * 4541e2f5d2eaSDaniel Stone * Called by the user via ioctl. 4542e2f5d2eaSDaniel Stone * 4543e2f5d2eaSDaniel Stone * Returns: 4544e2f5d2eaSDaniel Stone * Zero on success, negative errno on failure. 4545e2f5d2eaSDaniel Stone */ 4546e2f5d2eaSDaniel Stone int drm_mode_createblob_ioctl(struct drm_device *dev, 4547e2f5d2eaSDaniel Stone void *data, struct drm_file *file_priv) 4548e2f5d2eaSDaniel Stone { 4549e2f5d2eaSDaniel Stone struct drm_mode_create_blob *out_resp = data; 4550e2f5d2eaSDaniel Stone struct drm_property_blob *blob; 4551e2f5d2eaSDaniel Stone void __user *blob_ptr; 4552e2f5d2eaSDaniel Stone int ret = 0; 4553e2f5d2eaSDaniel Stone 4554e2f5d2eaSDaniel Stone if (!drm_core_check_feature(dev, DRIVER_MODESET)) 4555e2f5d2eaSDaniel Stone return -EINVAL; 4556e2f5d2eaSDaniel Stone 4557e2f5d2eaSDaniel Stone blob = drm_property_create_blob(dev, out_resp->length, NULL); 4558e2f5d2eaSDaniel Stone if (IS_ERR(blob)) 4559e2f5d2eaSDaniel Stone return PTR_ERR(blob); 4560e2f5d2eaSDaniel Stone 4561e2f5d2eaSDaniel Stone blob_ptr = (void __user *)(unsigned long)out_resp->data; 4562e2f5d2eaSDaniel Stone if (copy_from_user(blob->data, blob_ptr, out_resp->length)) { 4563e2f5d2eaSDaniel Stone ret = -EFAULT; 4564e2f5d2eaSDaniel Stone goto out_blob; 4565e2f5d2eaSDaniel Stone } 4566e2f5d2eaSDaniel Stone 4567e2f5d2eaSDaniel Stone /* Dropping the lock between create_blob and our access here is safe 4568e2f5d2eaSDaniel Stone * as only the same file_priv can remove the blob; at this point, it is 4569e2f5d2eaSDaniel Stone * not associated with any file_priv. */ 4570e2f5d2eaSDaniel Stone mutex_lock(&dev->mode_config.blob_lock); 4571e2f5d2eaSDaniel Stone out_resp->blob_id = blob->base.id; 4572e2f5d2eaSDaniel Stone list_add_tail(&file_priv->blobs, &blob->head_file); 4573e2f5d2eaSDaniel Stone mutex_unlock(&dev->mode_config.blob_lock); 4574e2f5d2eaSDaniel Stone 4575e2f5d2eaSDaniel Stone return 0; 4576e2f5d2eaSDaniel Stone 4577e2f5d2eaSDaniel Stone out_blob: 4578e2f5d2eaSDaniel Stone drm_property_unreference_blob(blob); 4579e2f5d2eaSDaniel Stone return ret; 4580e2f5d2eaSDaniel Stone } 4581e2f5d2eaSDaniel Stone 4582e2f5d2eaSDaniel Stone /** 4583e2f5d2eaSDaniel Stone * drm_mode_destroyblob_ioctl - destroy a user blob property 4584e2f5d2eaSDaniel Stone * @dev: DRM device 4585e2f5d2eaSDaniel Stone * @data: ioctl data 4586e2f5d2eaSDaniel Stone * @file_priv: DRM file info 4587e2f5d2eaSDaniel Stone * 4588e2f5d2eaSDaniel Stone * Destroy an existing user-defined blob property. 4589e2f5d2eaSDaniel Stone * 4590e2f5d2eaSDaniel Stone * Called by the user via ioctl. 4591e2f5d2eaSDaniel Stone * 4592e2f5d2eaSDaniel Stone * Returns: 4593e2f5d2eaSDaniel Stone * Zero on success, negative errno on failure. 4594e2f5d2eaSDaniel Stone */ 4595e2f5d2eaSDaniel Stone int drm_mode_destroyblob_ioctl(struct drm_device *dev, 4596e2f5d2eaSDaniel Stone void *data, struct drm_file *file_priv) 4597e2f5d2eaSDaniel Stone { 4598e2f5d2eaSDaniel Stone struct drm_mode_destroy_blob *out_resp = data; 4599e2f5d2eaSDaniel Stone struct drm_property_blob *blob = NULL, *bt; 4600e2f5d2eaSDaniel Stone bool found = false; 4601e2f5d2eaSDaniel Stone int ret = 0; 4602e2f5d2eaSDaniel Stone 4603e2f5d2eaSDaniel Stone if (!drm_core_check_feature(dev, DRIVER_MODESET)) 4604e2f5d2eaSDaniel Stone return -EINVAL; 4605e2f5d2eaSDaniel Stone 4606e2f5d2eaSDaniel Stone mutex_lock(&dev->mode_config.blob_lock); 4607e2f5d2eaSDaniel Stone blob = __drm_property_lookup_blob(dev, out_resp->blob_id); 4608e2f5d2eaSDaniel Stone if (!blob) { 4609e2f5d2eaSDaniel Stone ret = -ENOENT; 4610e2f5d2eaSDaniel Stone goto err; 4611e2f5d2eaSDaniel Stone } 4612e2f5d2eaSDaniel Stone 4613e2f5d2eaSDaniel Stone /* Ensure the property was actually created by this user. */ 4614e2f5d2eaSDaniel Stone list_for_each_entry(bt, &file_priv->blobs, head_file) { 4615e2f5d2eaSDaniel Stone if (bt == blob) { 4616e2f5d2eaSDaniel Stone found = true; 4617e2f5d2eaSDaniel Stone break; 4618e2f5d2eaSDaniel Stone } 4619e2f5d2eaSDaniel Stone } 4620e2f5d2eaSDaniel Stone 4621e2f5d2eaSDaniel Stone if (!found) { 4622e2f5d2eaSDaniel Stone ret = -EPERM; 4623e2f5d2eaSDaniel Stone goto err; 4624e2f5d2eaSDaniel Stone } 4625e2f5d2eaSDaniel Stone 4626e2f5d2eaSDaniel Stone /* We must drop head_file here, because we may not be the last 4627e2f5d2eaSDaniel Stone * reference on the blob. */ 4628e2f5d2eaSDaniel Stone list_del_init(&blob->head_file); 4629e2f5d2eaSDaniel Stone drm_property_unreference_blob_locked(blob); 4630e2f5d2eaSDaniel Stone mutex_unlock(&dev->mode_config.blob_lock); 4631e2f5d2eaSDaniel Stone 4632e2f5d2eaSDaniel Stone return 0; 4633e2f5d2eaSDaniel Stone 4634e2f5d2eaSDaniel Stone err: 4635e2f5d2eaSDaniel Stone mutex_unlock(&dev->mode_config.blob_lock); 4636e2f5d2eaSDaniel Stone return ret; 4637e2f5d2eaSDaniel Stone } 4638e2f5d2eaSDaniel Stone 4639e2f5d2eaSDaniel Stone /** 4640cc7096fbSDave Airlie * drm_mode_connector_set_path_property - set tile property on connector 4641cc7096fbSDave Airlie * @connector: connector to set property on. 4642d2ed3436SDaniel Stone * @path: path to use for property; must not be NULL. 4643cc7096fbSDave Airlie * 4644cc7096fbSDave Airlie * This creates a property to expose to userspace to specify a 4645cc7096fbSDave Airlie * connector path. This is mainly used for DisplayPort MST where 4646cc7096fbSDave Airlie * connectors have a topology and we want to allow userspace to give 4647cc7096fbSDave Airlie * them more meaningful names. 4648cc7096fbSDave Airlie * 4649cc7096fbSDave Airlie * Returns: 46501a498633SDaniel Vetter * Zero on success, negative errno on failure. 4651cc7096fbSDave Airlie */ 465243aba7ebSDave Airlie int drm_mode_connector_set_path_property(struct drm_connector *connector, 465312e6cecdSThierry Reding const char *path) 465443aba7ebSDave Airlie { 465543aba7ebSDave Airlie struct drm_device *dev = connector->dev; 4656ecbbe59bSThierry Reding int ret; 465743aba7ebSDave Airlie 4658d2ed3436SDaniel Stone ret = drm_property_replace_global_blob(dev, 4659d2ed3436SDaniel Stone &connector->path_blob_ptr, 4660d2ed3436SDaniel Stone strlen(path) + 1, 4661d2ed3436SDaniel Stone path, 4662d2ed3436SDaniel Stone &connector->base, 4663d2ed3436SDaniel Stone dev->mode_config.path_property); 466443aba7ebSDave Airlie return ret; 466543aba7ebSDave Airlie } 466643aba7ebSDave Airlie EXPORT_SYMBOL(drm_mode_connector_set_path_property); 466743aba7ebSDave Airlie 4668c8e32cc1SDaniel Vetter /** 46696f134d7bSDave Airlie * drm_mode_connector_set_tile_property - set tile property on connector 46706f134d7bSDave Airlie * @connector: connector to set property on. 46716f134d7bSDave Airlie * 46726f134d7bSDave Airlie * This looks up the tile information for a connector, and creates a 46736f134d7bSDave Airlie * property for userspace to parse if it exists. The property is of 46746f134d7bSDave Airlie * the form of 8 integers using ':' as a separator. 46756f134d7bSDave Airlie * 46766f134d7bSDave Airlie * Returns: 46776f134d7bSDave Airlie * Zero on success, errno on failure. 46786f134d7bSDave Airlie */ 46796f134d7bSDave Airlie int drm_mode_connector_set_tile_property(struct drm_connector *connector) 46806f134d7bSDave Airlie { 46816f134d7bSDave Airlie struct drm_device *dev = connector->dev; 46826f134d7bSDave Airlie char tile[256]; 4683d2ed3436SDaniel Stone int ret; 46846f134d7bSDave Airlie 46856f134d7bSDave Airlie if (!connector->has_tile) { 4686d2ed3436SDaniel Stone ret = drm_property_replace_global_blob(dev, 4687d2ed3436SDaniel Stone &connector->tile_blob_ptr, 4688d2ed3436SDaniel Stone 0, 4689d2ed3436SDaniel Stone NULL, 4690d2ed3436SDaniel Stone &connector->base, 4691d2ed3436SDaniel Stone dev->mode_config.tile_property); 46926f134d7bSDave Airlie return ret; 46936f134d7bSDave Airlie } 46946f134d7bSDave Airlie 46956f134d7bSDave Airlie snprintf(tile, 256, "%d:%d:%d:%d:%d:%d:%d:%d", 46966f134d7bSDave Airlie connector->tile_group->id, connector->tile_is_single_monitor, 46976f134d7bSDave Airlie connector->num_h_tile, connector->num_v_tile, 46986f134d7bSDave Airlie connector->tile_h_loc, connector->tile_v_loc, 46996f134d7bSDave Airlie connector->tile_h_size, connector->tile_v_size); 47006f134d7bSDave Airlie 4701d2ed3436SDaniel Stone ret = drm_property_replace_global_blob(dev, 4702d2ed3436SDaniel Stone &connector->tile_blob_ptr, 4703d2ed3436SDaniel Stone strlen(tile) + 1, 4704d2ed3436SDaniel Stone tile, 4705d2ed3436SDaniel Stone &connector->base, 4706d2ed3436SDaniel Stone dev->mode_config.tile_property); 47076f134d7bSDave Airlie return ret; 47086f134d7bSDave Airlie } 47096f134d7bSDave Airlie EXPORT_SYMBOL(drm_mode_connector_set_tile_property); 47106f134d7bSDave Airlie 47116f134d7bSDave Airlie /** 4712c8e32cc1SDaniel Vetter * drm_mode_connector_update_edid_property - update the edid property of a connector 4713c8e32cc1SDaniel Vetter * @connector: drm connector 4714c8e32cc1SDaniel Vetter * @edid: new value of the edid property 4715c8e32cc1SDaniel Vetter * 4716c8e32cc1SDaniel Vetter * This function creates a new blob modeset object and assigns its id to the 4717c8e32cc1SDaniel Vetter * connector's edid property. 4718c8e32cc1SDaniel Vetter * 4719c8e32cc1SDaniel Vetter * Returns: 47201a498633SDaniel Vetter * Zero on success, negative errno on failure. 4721c8e32cc1SDaniel Vetter */ 4722f453ba04SDave Airlie int drm_mode_connector_update_edid_property(struct drm_connector *connector, 472312e6cecdSThierry Reding const struct edid *edid) 4724f453ba04SDave Airlie { 4725f453ba04SDave Airlie struct drm_device *dev = connector->dev; 4726d2ed3436SDaniel Stone size_t size = 0; 4727ecbbe59bSThierry Reding int ret; 4728f453ba04SDave Airlie 47294cf2b281SThomas Wood /* ignore requests to set edid when overridden */ 47304cf2b281SThomas Wood if (connector->override_edid) 47314cf2b281SThomas Wood return 0; 47324cf2b281SThomas Wood 4733d2ed3436SDaniel Stone if (edid) 4734d2ed3436SDaniel Stone size = EDID_LENGTH + (1 + edid->extensions); 4735f453ba04SDave Airlie 4736d2ed3436SDaniel Stone ret = drm_property_replace_global_blob(dev, 4737d2ed3436SDaniel Stone &connector->edid_blob_ptr, 4738d2ed3436SDaniel Stone size, 4739d2ed3436SDaniel Stone edid, 4740d2ed3436SDaniel Stone &connector->base, 4741d2ed3436SDaniel Stone dev->mode_config.edid_property); 4742f453ba04SDave Airlie return ret; 4743f453ba04SDave Airlie } 4744f453ba04SDave Airlie EXPORT_SYMBOL(drm_mode_connector_update_edid_property); 4745f453ba04SDave Airlie 47463843e71fSRob Clark /* Some properties could refer to dynamic refcnt'd objects, or things that 47473843e71fSRob Clark * need special locking to handle lifetime issues (ie. to ensure the prop 47483843e71fSRob Clark * value doesn't become invalid part way through the property update due to 47493843e71fSRob Clark * race). The value returned by reference via 'obj' should be passed back 47503843e71fSRob Clark * to drm_property_change_valid_put() after the property is set (and the 47513843e71fSRob Clark * object to which the property is attached has a chance to take it's own 47523843e71fSRob Clark * reference). 47533843e71fSRob Clark */ 4754d34f20d6SRob Clark bool drm_property_change_valid_get(struct drm_property *property, 47553843e71fSRob Clark uint64_t value, struct drm_mode_object **ref) 475626a34815SPaulo Zanoni { 47572ca651d1SThierry Reding int i; 47582ca651d1SThierry Reding 475926a34815SPaulo Zanoni if (property->flags & DRM_MODE_PROP_IMMUTABLE) 476026a34815SPaulo Zanoni return false; 47615ea22f24SRob Clark 47623843e71fSRob Clark *ref = NULL; 47633843e71fSRob Clark 47645ea22f24SRob Clark if (drm_property_type_is(property, DRM_MODE_PROP_RANGE)) { 476526a34815SPaulo Zanoni if (value < property->values[0] || value > property->values[1]) 476626a34815SPaulo Zanoni return false; 476726a34815SPaulo Zanoni return true; 4768ebc44cf3SRob Clark } else if (drm_property_type_is(property, DRM_MODE_PROP_SIGNED_RANGE)) { 4769ebc44cf3SRob Clark int64_t svalue = U642I64(value); 47704dfd909fSThierry Reding 4771ebc44cf3SRob Clark if (svalue < U642I64(property->values[0]) || 4772ebc44cf3SRob Clark svalue > U642I64(property->values[1])) 4773ebc44cf3SRob Clark return false; 4774ebc44cf3SRob Clark return true; 47755ea22f24SRob Clark } else if (drm_property_type_is(property, DRM_MODE_PROP_BITMASK)) { 4776592c20eeSVille Syrjälä uint64_t valid_mask = 0; 47774dfd909fSThierry Reding 477849e27545SRob Clark for (i = 0; i < property->num_values; i++) 477949e27545SRob Clark valid_mask |= (1ULL << property->values[i]); 478049e27545SRob Clark return !(value & ~valid_mask); 47815ea22f24SRob Clark } else if (drm_property_type_is(property, DRM_MODE_PROP_BLOB)) { 47826bcacf51SDaniel Stone struct drm_property_blob *blob; 47836bcacf51SDaniel Stone 47846bcacf51SDaniel Stone if (value == 0) 4785c4a56750SVille Syrjälä return true; 47866bcacf51SDaniel Stone 47876bcacf51SDaniel Stone blob = drm_property_lookup_blob(property->dev, value); 47886bcacf51SDaniel Stone if (blob) { 47896bcacf51SDaniel Stone *ref = &blob->base; 47906bcacf51SDaniel Stone return true; 47916bcacf51SDaniel Stone } else { 47926bcacf51SDaniel Stone return false; 47936bcacf51SDaniel Stone } 479498f75de4SRob Clark } else if (drm_property_type_is(property, DRM_MODE_PROP_OBJECT)) { 479598f75de4SRob Clark /* a zero value for an object property translates to null: */ 479698f75de4SRob Clark if (value == 0) 479798f75de4SRob Clark return true; 47983843e71fSRob Clark 47993843e71fSRob Clark /* handle refcnt'd objects specially: */ 48003843e71fSRob Clark if (property->values[0] == DRM_MODE_OBJECT_FB) { 48013843e71fSRob Clark struct drm_framebuffer *fb; 48023843e71fSRob Clark fb = drm_framebuffer_lookup(property->dev, value); 48033843e71fSRob Clark if (fb) { 48043843e71fSRob Clark *ref = &fb->base; 48053843e71fSRob Clark return true; 48063843e71fSRob Clark } else { 48073843e71fSRob Clark return false; 48083843e71fSRob Clark } 48093843e71fSRob Clark } else { 48103843e71fSRob Clark return _object_find(property->dev, value, property->values[0]) != NULL; 48113843e71fSRob Clark } 48122ca651d1SThierry Reding } 48132ca651d1SThierry Reding 481426a34815SPaulo Zanoni for (i = 0; i < property->num_values; i++) 481526a34815SPaulo Zanoni if (property->values[i] == value) 481626a34815SPaulo Zanoni return true; 481726a34815SPaulo Zanoni return false; 481826a34815SPaulo Zanoni } 481926a34815SPaulo Zanoni 4820d34f20d6SRob Clark void drm_property_change_valid_put(struct drm_property *property, 48213843e71fSRob Clark struct drm_mode_object *ref) 48223843e71fSRob Clark { 48233843e71fSRob Clark if (!ref) 48243843e71fSRob Clark return; 48253843e71fSRob Clark 48263843e71fSRob Clark if (drm_property_type_is(property, DRM_MODE_PROP_OBJECT)) { 48273843e71fSRob Clark if (property->values[0] == DRM_MODE_OBJECT_FB) 48283843e71fSRob Clark drm_framebuffer_unreference(obj_to_fb(ref)); 4829da9b2a38SDaniel Stone } else if (drm_property_type_is(property, DRM_MODE_PROP_BLOB)) 4830da9b2a38SDaniel Stone drm_property_unreference_blob(obj_to_blob(ref)); 48313843e71fSRob Clark } 48323843e71fSRob Clark 4833c8e32cc1SDaniel Vetter /** 4834c8e32cc1SDaniel Vetter * drm_mode_connector_property_set_ioctl - set the current value of a connector property 4835c8e32cc1SDaniel Vetter * @dev: DRM device 4836c8e32cc1SDaniel Vetter * @data: ioctl data 4837c8e32cc1SDaniel Vetter * @file_priv: DRM file info 4838c8e32cc1SDaniel Vetter * 4839c8e32cc1SDaniel Vetter * This function sets the current value for a connectors's property. It also 4840c8e32cc1SDaniel Vetter * calls into a driver's ->set_property callback to update the hardware state 4841c8e32cc1SDaniel Vetter * 4842c8e32cc1SDaniel Vetter * Called by the user via ioctl. 4843c8e32cc1SDaniel Vetter * 4844c8e32cc1SDaniel Vetter * Returns: 48451a498633SDaniel Vetter * Zero on success, negative errno on failure. 4846c8e32cc1SDaniel Vetter */ 4847f453ba04SDave Airlie int drm_mode_connector_property_set_ioctl(struct drm_device *dev, 4848f453ba04SDave Airlie void *data, struct drm_file *file_priv) 4849f453ba04SDave Airlie { 48500057d8ddSPaulo Zanoni struct drm_mode_connector_set_property *conn_set_prop = data; 48510057d8ddSPaulo Zanoni struct drm_mode_obj_set_property obj_set_prop = { 48520057d8ddSPaulo Zanoni .value = conn_set_prop->value, 48530057d8ddSPaulo Zanoni .prop_id = conn_set_prop->prop_id, 48540057d8ddSPaulo Zanoni .obj_id = conn_set_prop->connector_id, 48550057d8ddSPaulo Zanoni .obj_type = DRM_MODE_OBJECT_CONNECTOR 48560057d8ddSPaulo Zanoni }; 4857f453ba04SDave Airlie 48580057d8ddSPaulo Zanoni /* It does all the locking and checking we need */ 48590057d8ddSPaulo Zanoni return drm_mode_obj_set_property_ioctl(dev, &obj_set_prop, file_priv); 4860f453ba04SDave Airlie } 4861f453ba04SDave Airlie 4862c543188aSPaulo Zanoni static int drm_mode_connector_set_obj_prop(struct drm_mode_object *obj, 4863c543188aSPaulo Zanoni struct drm_property *property, 4864c543188aSPaulo Zanoni uint64_t value) 4865c543188aSPaulo Zanoni { 4866c543188aSPaulo Zanoni int ret = -EINVAL; 4867c543188aSPaulo Zanoni struct drm_connector *connector = obj_to_connector(obj); 4868c543188aSPaulo Zanoni 4869c543188aSPaulo Zanoni /* Do DPMS ourselves */ 4870c543188aSPaulo Zanoni if (property == connector->dev->mode_config.dpms_property) { 4871c543188aSPaulo Zanoni if (connector->funcs->dpms) 4872c543188aSPaulo Zanoni (*connector->funcs->dpms)(connector, (int)value); 4873c543188aSPaulo Zanoni ret = 0; 4874c543188aSPaulo Zanoni } else if (connector->funcs->set_property) 4875c543188aSPaulo Zanoni ret = connector->funcs->set_property(connector, property, value); 4876c543188aSPaulo Zanoni 4877c543188aSPaulo Zanoni /* store the property value if successful */ 4878c543188aSPaulo Zanoni if (!ret) 487958495563SRob Clark drm_object_property_set_value(&connector->base, property, value); 4880c543188aSPaulo Zanoni return ret; 4881c543188aSPaulo Zanoni } 4882c543188aSPaulo Zanoni 4883bffd9de0SPaulo Zanoni static int drm_mode_crtc_set_obj_prop(struct drm_mode_object *obj, 4884bffd9de0SPaulo Zanoni struct drm_property *property, 4885bffd9de0SPaulo Zanoni uint64_t value) 4886bffd9de0SPaulo Zanoni { 4887bffd9de0SPaulo Zanoni int ret = -EINVAL; 4888bffd9de0SPaulo Zanoni struct drm_crtc *crtc = obj_to_crtc(obj); 4889bffd9de0SPaulo Zanoni 4890bffd9de0SPaulo Zanoni if (crtc->funcs->set_property) 4891bffd9de0SPaulo Zanoni ret = crtc->funcs->set_property(crtc, property, value); 4892bffd9de0SPaulo Zanoni if (!ret) 4893bffd9de0SPaulo Zanoni drm_object_property_set_value(obj, property, value); 4894bffd9de0SPaulo Zanoni 4895bffd9de0SPaulo Zanoni return ret; 4896bffd9de0SPaulo Zanoni } 4897bffd9de0SPaulo Zanoni 48983a5f87c2SThomas Wood /** 48993a5f87c2SThomas Wood * drm_mode_plane_set_obj_prop - set the value of a property 49003a5f87c2SThomas Wood * @plane: drm plane object to set property value for 49013a5f87c2SThomas Wood * @property: property to set 49023a5f87c2SThomas Wood * @value: value the property should be set to 49033a5f87c2SThomas Wood * 49043a5f87c2SThomas Wood * This functions sets a given property on a given plane object. This function 49053a5f87c2SThomas Wood * calls the driver's ->set_property callback and changes the software state of 49063a5f87c2SThomas Wood * the property if the callback succeeds. 49073a5f87c2SThomas Wood * 49083a5f87c2SThomas Wood * Returns: 49093a5f87c2SThomas Wood * Zero on success, error code on failure. 49103a5f87c2SThomas Wood */ 49113a5f87c2SThomas Wood int drm_mode_plane_set_obj_prop(struct drm_plane *plane, 49124d93914aSRob Clark struct drm_property *property, 49134d93914aSRob Clark uint64_t value) 49144d93914aSRob Clark { 49154d93914aSRob Clark int ret = -EINVAL; 49163a5f87c2SThomas Wood struct drm_mode_object *obj = &plane->base; 49174d93914aSRob Clark 49184d93914aSRob Clark if (plane->funcs->set_property) 49194d93914aSRob Clark ret = plane->funcs->set_property(plane, property, value); 49204d93914aSRob Clark if (!ret) 49214d93914aSRob Clark drm_object_property_set_value(obj, property, value); 49224d93914aSRob Clark 49234d93914aSRob Clark return ret; 49244d93914aSRob Clark } 49253a5f87c2SThomas Wood EXPORT_SYMBOL(drm_mode_plane_set_obj_prop); 49264d93914aSRob Clark 4927c8e32cc1SDaniel Vetter /** 49281a498633SDaniel Vetter * drm_mode_obj_get_properties_ioctl - get the current value of a object's property 4929c8e32cc1SDaniel Vetter * @dev: DRM device 4930c8e32cc1SDaniel Vetter * @data: ioctl data 4931c8e32cc1SDaniel Vetter * @file_priv: DRM file info 4932c8e32cc1SDaniel Vetter * 4933c8e32cc1SDaniel Vetter * This function retrieves the current value for an object's property. Compared 4934c8e32cc1SDaniel Vetter * to the connector specific ioctl this one is extended to also work on crtc and 4935c8e32cc1SDaniel Vetter * plane objects. 4936c8e32cc1SDaniel Vetter * 4937c8e32cc1SDaniel Vetter * Called by the user via ioctl. 4938c8e32cc1SDaniel Vetter * 4939c8e32cc1SDaniel Vetter * Returns: 49401a498633SDaniel Vetter * Zero on success, negative errno on failure. 4941c8e32cc1SDaniel Vetter */ 4942c543188aSPaulo Zanoni int drm_mode_obj_get_properties_ioctl(struct drm_device *dev, void *data, 4943c543188aSPaulo Zanoni struct drm_file *file_priv) 4944c543188aSPaulo Zanoni { 4945c543188aSPaulo Zanoni struct drm_mode_obj_get_properties *arg = data; 4946c543188aSPaulo Zanoni struct drm_mode_object *obj; 4947c543188aSPaulo Zanoni int ret = 0; 4948c543188aSPaulo Zanoni 4949c543188aSPaulo Zanoni if (!drm_core_check_feature(dev, DRIVER_MODESET)) 4950c543188aSPaulo Zanoni return -EINVAL; 4951c543188aSPaulo Zanoni 495284849903SDaniel Vetter drm_modeset_lock_all(dev); 4953c543188aSPaulo Zanoni 4954c543188aSPaulo Zanoni obj = drm_mode_object_find(dev, arg->obj_id, arg->obj_type); 4955c543188aSPaulo Zanoni if (!obj) { 4956f27657f2SVille Syrjälä ret = -ENOENT; 4957c543188aSPaulo Zanoni goto out; 4958c543188aSPaulo Zanoni } 4959c543188aSPaulo Zanoni if (!obj->properties) { 4960c543188aSPaulo Zanoni ret = -EINVAL; 4961c543188aSPaulo Zanoni goto out; 4962c543188aSPaulo Zanoni } 4963c543188aSPaulo Zanoni 496488a48e29SRob Clark ret = get_properties(obj, file_priv->atomic, 496595cbf110SRob Clark (uint32_t __user *)(unsigned long)(arg->props_ptr), 496695cbf110SRob Clark (uint64_t __user *)(unsigned long)(arg->prop_values_ptr), 496795cbf110SRob Clark &arg->count_props); 4968c543188aSPaulo Zanoni 4969c543188aSPaulo Zanoni out: 497084849903SDaniel Vetter drm_modeset_unlock_all(dev); 4971c543188aSPaulo Zanoni return ret; 4972c543188aSPaulo Zanoni } 4973c543188aSPaulo Zanoni 4974c8e32cc1SDaniel Vetter /** 4975c8e32cc1SDaniel Vetter * drm_mode_obj_set_property_ioctl - set the current value of an object's property 4976c8e32cc1SDaniel Vetter * @dev: DRM device 4977c8e32cc1SDaniel Vetter * @data: ioctl data 4978c8e32cc1SDaniel Vetter * @file_priv: DRM file info 4979c8e32cc1SDaniel Vetter * 4980c8e32cc1SDaniel Vetter * This function sets the current value for an object's property. It also calls 4981c8e32cc1SDaniel Vetter * into a driver's ->set_property callback to update the hardware state. 4982c8e32cc1SDaniel Vetter * Compared to the connector specific ioctl this one is extended to also work on 4983c8e32cc1SDaniel Vetter * crtc and plane objects. 4984c8e32cc1SDaniel Vetter * 4985c8e32cc1SDaniel Vetter * Called by the user via ioctl. 4986c8e32cc1SDaniel Vetter * 4987c8e32cc1SDaniel Vetter * Returns: 49881a498633SDaniel Vetter * Zero on success, negative errno on failure. 4989c8e32cc1SDaniel Vetter */ 4990c543188aSPaulo Zanoni int drm_mode_obj_set_property_ioctl(struct drm_device *dev, void *data, 4991c543188aSPaulo Zanoni struct drm_file *file_priv) 4992c543188aSPaulo Zanoni { 4993c543188aSPaulo Zanoni struct drm_mode_obj_set_property *arg = data; 4994c543188aSPaulo Zanoni struct drm_mode_object *arg_obj; 4995c543188aSPaulo Zanoni struct drm_mode_object *prop_obj; 4996c543188aSPaulo Zanoni struct drm_property *property; 49973843e71fSRob Clark int i, ret = -EINVAL; 49983843e71fSRob Clark struct drm_mode_object *ref; 4999c543188aSPaulo Zanoni 5000c543188aSPaulo Zanoni if (!drm_core_check_feature(dev, DRIVER_MODESET)) 5001c543188aSPaulo Zanoni return -EINVAL; 5002c543188aSPaulo Zanoni 500384849903SDaniel Vetter drm_modeset_lock_all(dev); 5004c543188aSPaulo Zanoni 5005c543188aSPaulo Zanoni arg_obj = drm_mode_object_find(dev, arg->obj_id, arg->obj_type); 5006f27657f2SVille Syrjälä if (!arg_obj) { 5007f27657f2SVille Syrjälä ret = -ENOENT; 5008c543188aSPaulo Zanoni goto out; 5009f27657f2SVille Syrjälä } 5010c543188aSPaulo Zanoni if (!arg_obj->properties) 5011c543188aSPaulo Zanoni goto out; 5012c543188aSPaulo Zanoni 50137f88a9beSPaulo Zanoni for (i = 0; i < arg_obj->properties->count; i++) 5014b17cd757SRob Clark if (arg_obj->properties->properties[i]->base.id == arg->prop_id) 5015c543188aSPaulo Zanoni break; 5016c543188aSPaulo Zanoni 50177f88a9beSPaulo Zanoni if (i == arg_obj->properties->count) 5018c543188aSPaulo Zanoni goto out; 5019c543188aSPaulo Zanoni 5020c543188aSPaulo Zanoni prop_obj = drm_mode_object_find(dev, arg->prop_id, 5021c543188aSPaulo Zanoni DRM_MODE_OBJECT_PROPERTY); 5022f27657f2SVille Syrjälä if (!prop_obj) { 5023f27657f2SVille Syrjälä ret = -ENOENT; 5024c543188aSPaulo Zanoni goto out; 5025f27657f2SVille Syrjälä } 5026c543188aSPaulo Zanoni property = obj_to_property(prop_obj); 5027c543188aSPaulo Zanoni 50283843e71fSRob Clark if (!drm_property_change_valid_get(property, arg->value, &ref)) 5029c543188aSPaulo Zanoni goto out; 5030c543188aSPaulo Zanoni 5031c543188aSPaulo Zanoni switch (arg_obj->type) { 5032c543188aSPaulo Zanoni case DRM_MODE_OBJECT_CONNECTOR: 5033c543188aSPaulo Zanoni ret = drm_mode_connector_set_obj_prop(arg_obj, property, 5034c543188aSPaulo Zanoni arg->value); 5035c543188aSPaulo Zanoni break; 5036bffd9de0SPaulo Zanoni case DRM_MODE_OBJECT_CRTC: 5037bffd9de0SPaulo Zanoni ret = drm_mode_crtc_set_obj_prop(arg_obj, property, arg->value); 5038bffd9de0SPaulo Zanoni break; 50394d93914aSRob Clark case DRM_MODE_OBJECT_PLANE: 50403a5f87c2SThomas Wood ret = drm_mode_plane_set_obj_prop(obj_to_plane(arg_obj), 50413a5f87c2SThomas Wood property, arg->value); 50424d93914aSRob Clark break; 5043c543188aSPaulo Zanoni } 5044c543188aSPaulo Zanoni 50453843e71fSRob Clark drm_property_change_valid_put(property, ref); 50463843e71fSRob Clark 5047c543188aSPaulo Zanoni out: 504884849903SDaniel Vetter drm_modeset_unlock_all(dev); 5049c543188aSPaulo Zanoni return ret; 5050c543188aSPaulo Zanoni } 5051c543188aSPaulo Zanoni 5052c8e32cc1SDaniel Vetter /** 5053c8e32cc1SDaniel Vetter * drm_mode_connector_attach_encoder - attach a connector to an encoder 5054c8e32cc1SDaniel Vetter * @connector: connector to attach 5055c8e32cc1SDaniel Vetter * @encoder: encoder to attach @connector to 5056c8e32cc1SDaniel Vetter * 5057c8e32cc1SDaniel Vetter * This function links up a connector to an encoder. Note that the routing 5058c8e32cc1SDaniel Vetter * restrictions between encoders and crtcs are exposed to userspace through the 5059c8e32cc1SDaniel Vetter * possible_clones and possible_crtcs bitmasks. 5060c8e32cc1SDaniel Vetter * 5061c8e32cc1SDaniel Vetter * Returns: 50621a498633SDaniel Vetter * Zero on success, negative errno on failure. 5063c8e32cc1SDaniel Vetter */ 5064f453ba04SDave Airlie int drm_mode_connector_attach_encoder(struct drm_connector *connector, 5065f453ba04SDave Airlie struct drm_encoder *encoder) 5066f453ba04SDave Airlie { 5067f453ba04SDave Airlie int i; 5068f453ba04SDave Airlie 5069f453ba04SDave Airlie for (i = 0; i < DRM_CONNECTOR_MAX_ENCODER; i++) { 5070f453ba04SDave Airlie if (connector->encoder_ids[i] == 0) { 5071f453ba04SDave Airlie connector->encoder_ids[i] = encoder->base.id; 5072f453ba04SDave Airlie return 0; 5073f453ba04SDave Airlie } 5074f453ba04SDave Airlie } 5075f453ba04SDave Airlie return -ENOMEM; 5076f453ba04SDave Airlie } 5077f453ba04SDave Airlie EXPORT_SYMBOL(drm_mode_connector_attach_encoder); 5078f453ba04SDave Airlie 5079c8e32cc1SDaniel Vetter /** 5080c8e32cc1SDaniel Vetter * drm_mode_crtc_set_gamma_size - set the gamma table size 5081c8e32cc1SDaniel Vetter * @crtc: CRTC to set the gamma table size for 5082c8e32cc1SDaniel Vetter * @gamma_size: size of the gamma table 5083c8e32cc1SDaniel Vetter * 5084c8e32cc1SDaniel Vetter * Drivers which support gamma tables should set this to the supported gamma 5085c8e32cc1SDaniel Vetter * table size when initializing the CRTC. Currently the drm core only supports a 5086c8e32cc1SDaniel Vetter * fixed gamma table size. 5087c8e32cc1SDaniel Vetter * 5088c8e32cc1SDaniel Vetter * Returns: 50891a498633SDaniel Vetter * Zero on success, negative errno on failure. 5090c8e32cc1SDaniel Vetter */ 50914cae5b84SSascha Hauer int drm_mode_crtc_set_gamma_size(struct drm_crtc *crtc, 5092f453ba04SDave Airlie int gamma_size) 5093f453ba04SDave Airlie { 5094f453ba04SDave Airlie crtc->gamma_size = gamma_size; 5095f453ba04SDave Airlie 5096bd3f0ff9SThierry Reding crtc->gamma_store = kcalloc(gamma_size, sizeof(uint16_t) * 3, 5097bd3f0ff9SThierry Reding GFP_KERNEL); 5098f453ba04SDave Airlie if (!crtc->gamma_store) { 5099f453ba04SDave Airlie crtc->gamma_size = 0; 51004cae5b84SSascha Hauer return -ENOMEM; 5101f453ba04SDave Airlie } 5102f453ba04SDave Airlie 51034cae5b84SSascha Hauer return 0; 5104f453ba04SDave Airlie } 5105f453ba04SDave Airlie EXPORT_SYMBOL(drm_mode_crtc_set_gamma_size); 5106f453ba04SDave Airlie 5107c8e32cc1SDaniel Vetter /** 5108c8e32cc1SDaniel Vetter * drm_mode_gamma_set_ioctl - set the gamma table 5109c8e32cc1SDaniel Vetter * @dev: DRM device 5110c8e32cc1SDaniel Vetter * @data: ioctl data 5111c8e32cc1SDaniel Vetter * @file_priv: DRM file info 5112c8e32cc1SDaniel Vetter * 5113c8e32cc1SDaniel Vetter * Set the gamma table of a CRTC to the one passed in by the user. Userspace can 5114c8e32cc1SDaniel Vetter * inquire the required gamma table size through drm_mode_gamma_get_ioctl. 5115c8e32cc1SDaniel Vetter * 5116c8e32cc1SDaniel Vetter * Called by the user via ioctl. 5117c8e32cc1SDaniel Vetter * 5118c8e32cc1SDaniel Vetter * Returns: 51191a498633SDaniel Vetter * Zero on success, negative errno on failure. 5120c8e32cc1SDaniel Vetter */ 5121f453ba04SDave Airlie int drm_mode_gamma_set_ioctl(struct drm_device *dev, 5122f453ba04SDave Airlie void *data, struct drm_file *file_priv) 5123f453ba04SDave Airlie { 5124f453ba04SDave Airlie struct drm_mode_crtc_lut *crtc_lut = data; 5125f453ba04SDave Airlie struct drm_crtc *crtc; 5126f453ba04SDave Airlie void *r_base, *g_base, *b_base; 5127f453ba04SDave Airlie int size; 5128f453ba04SDave Airlie int ret = 0; 5129f453ba04SDave Airlie 5130fb3b06c8SDave Airlie if (!drm_core_check_feature(dev, DRIVER_MODESET)) 5131fb3b06c8SDave Airlie return -EINVAL; 5132fb3b06c8SDave Airlie 513384849903SDaniel Vetter drm_modeset_lock_all(dev); 5134a2b34e22SRob Clark crtc = drm_crtc_find(dev, crtc_lut->crtc_id); 5135a2b34e22SRob Clark if (!crtc) { 5136f27657f2SVille Syrjälä ret = -ENOENT; 5137f453ba04SDave Airlie goto out; 5138f453ba04SDave Airlie } 5139f453ba04SDave Airlie 5140ebe0f244SLaurent Pinchart if (crtc->funcs->gamma_set == NULL) { 5141ebe0f244SLaurent Pinchart ret = -ENOSYS; 5142ebe0f244SLaurent Pinchart goto out; 5143ebe0f244SLaurent Pinchart } 5144ebe0f244SLaurent Pinchart 5145f453ba04SDave Airlie /* memcpy into gamma store */ 5146f453ba04SDave Airlie if (crtc_lut->gamma_size != crtc->gamma_size) { 5147f453ba04SDave Airlie ret = -EINVAL; 5148f453ba04SDave Airlie goto out; 5149f453ba04SDave Airlie } 5150f453ba04SDave Airlie 5151f453ba04SDave Airlie size = crtc_lut->gamma_size * (sizeof(uint16_t)); 5152f453ba04SDave Airlie r_base = crtc->gamma_store; 5153f453ba04SDave Airlie if (copy_from_user(r_base, (void __user *)(unsigned long)crtc_lut->red, size)) { 5154f453ba04SDave Airlie ret = -EFAULT; 5155f453ba04SDave Airlie goto out; 5156f453ba04SDave Airlie } 5157f453ba04SDave Airlie 5158f453ba04SDave Airlie g_base = r_base + size; 5159f453ba04SDave Airlie if (copy_from_user(g_base, (void __user *)(unsigned long)crtc_lut->green, size)) { 5160f453ba04SDave Airlie ret = -EFAULT; 5161f453ba04SDave Airlie goto out; 5162f453ba04SDave Airlie } 5163f453ba04SDave Airlie 5164f453ba04SDave Airlie b_base = g_base + size; 5165f453ba04SDave Airlie if (copy_from_user(b_base, (void __user *)(unsigned long)crtc_lut->blue, size)) { 5166f453ba04SDave Airlie ret = -EFAULT; 5167f453ba04SDave Airlie goto out; 5168f453ba04SDave Airlie } 5169f453ba04SDave Airlie 51707203425aSJames Simmons crtc->funcs->gamma_set(crtc, r_base, g_base, b_base, 0, crtc->gamma_size); 5171f453ba04SDave Airlie 5172f453ba04SDave Airlie out: 517384849903SDaniel Vetter drm_modeset_unlock_all(dev); 5174f453ba04SDave Airlie return ret; 5175f453ba04SDave Airlie 5176f453ba04SDave Airlie } 5177f453ba04SDave Airlie 5178c8e32cc1SDaniel Vetter /** 5179c8e32cc1SDaniel Vetter * drm_mode_gamma_get_ioctl - get the gamma table 5180c8e32cc1SDaniel Vetter * @dev: DRM device 5181c8e32cc1SDaniel Vetter * @data: ioctl data 5182c8e32cc1SDaniel Vetter * @file_priv: DRM file info 5183c8e32cc1SDaniel Vetter * 5184c8e32cc1SDaniel Vetter * Copy the current gamma table into the storage provided. This also provides 5185c8e32cc1SDaniel Vetter * the gamma table size the driver expects, which can be used to size the 5186c8e32cc1SDaniel Vetter * allocated storage. 5187c8e32cc1SDaniel Vetter * 5188c8e32cc1SDaniel Vetter * Called by the user via ioctl. 5189c8e32cc1SDaniel Vetter * 5190c8e32cc1SDaniel Vetter * Returns: 51911a498633SDaniel Vetter * Zero on success, negative errno on failure. 5192c8e32cc1SDaniel Vetter */ 5193f453ba04SDave Airlie int drm_mode_gamma_get_ioctl(struct drm_device *dev, 5194f453ba04SDave Airlie void *data, struct drm_file *file_priv) 5195f453ba04SDave Airlie { 5196f453ba04SDave Airlie struct drm_mode_crtc_lut *crtc_lut = data; 5197f453ba04SDave Airlie struct drm_crtc *crtc; 5198f453ba04SDave Airlie void *r_base, *g_base, *b_base; 5199f453ba04SDave Airlie int size; 5200f453ba04SDave Airlie int ret = 0; 5201f453ba04SDave Airlie 5202fb3b06c8SDave Airlie if (!drm_core_check_feature(dev, DRIVER_MODESET)) 5203fb3b06c8SDave Airlie return -EINVAL; 5204fb3b06c8SDave Airlie 520584849903SDaniel Vetter drm_modeset_lock_all(dev); 5206a2b34e22SRob Clark crtc = drm_crtc_find(dev, crtc_lut->crtc_id); 5207a2b34e22SRob Clark if (!crtc) { 5208f27657f2SVille Syrjälä ret = -ENOENT; 5209f453ba04SDave Airlie goto out; 5210f453ba04SDave Airlie } 5211f453ba04SDave Airlie 5212f453ba04SDave Airlie /* memcpy into gamma store */ 5213f453ba04SDave Airlie if (crtc_lut->gamma_size != crtc->gamma_size) { 5214f453ba04SDave Airlie ret = -EINVAL; 5215f453ba04SDave Airlie goto out; 5216f453ba04SDave Airlie } 5217f453ba04SDave Airlie 5218f453ba04SDave Airlie size = crtc_lut->gamma_size * (sizeof(uint16_t)); 5219f453ba04SDave Airlie r_base = crtc->gamma_store; 5220f453ba04SDave Airlie if (copy_to_user((void __user *)(unsigned long)crtc_lut->red, r_base, size)) { 5221f453ba04SDave Airlie ret = -EFAULT; 5222f453ba04SDave Airlie goto out; 5223f453ba04SDave Airlie } 5224f453ba04SDave Airlie 5225f453ba04SDave Airlie g_base = r_base + size; 5226f453ba04SDave Airlie if (copy_to_user((void __user *)(unsigned long)crtc_lut->green, g_base, size)) { 5227f453ba04SDave Airlie ret = -EFAULT; 5228f453ba04SDave Airlie goto out; 5229f453ba04SDave Airlie } 5230f453ba04SDave Airlie 5231f453ba04SDave Airlie b_base = g_base + size; 5232f453ba04SDave Airlie if (copy_to_user((void __user *)(unsigned long)crtc_lut->blue, b_base, size)) { 5233f453ba04SDave Airlie ret = -EFAULT; 5234f453ba04SDave Airlie goto out; 5235f453ba04SDave Airlie } 5236f453ba04SDave Airlie out: 523784849903SDaniel Vetter drm_modeset_unlock_all(dev); 5238f453ba04SDave Airlie return ret; 5239f453ba04SDave Airlie } 5240d91d8a3fSKristian Høgsberg 5241c8e32cc1SDaniel Vetter /** 5242c8e32cc1SDaniel Vetter * drm_mode_page_flip_ioctl - schedule an asynchronous fb update 5243c8e32cc1SDaniel Vetter * @dev: DRM device 5244c8e32cc1SDaniel Vetter * @data: ioctl data 5245c8e32cc1SDaniel Vetter * @file_priv: DRM file info 5246c8e32cc1SDaniel Vetter * 5247c8e32cc1SDaniel Vetter * This schedules an asynchronous update on a given CRTC, called page flip. 5248c8e32cc1SDaniel Vetter * Optionally a drm event is generated to signal the completion of the event. 5249c8e32cc1SDaniel Vetter * Generic drivers cannot assume that a pageflip with changed framebuffer 5250c8e32cc1SDaniel Vetter * properties (including driver specific metadata like tiling layout) will work, 5251c8e32cc1SDaniel Vetter * but some drivers support e.g. pixel format changes through the pageflip 5252c8e32cc1SDaniel Vetter * ioctl. 5253c8e32cc1SDaniel Vetter * 5254c8e32cc1SDaniel Vetter * Called by the user via ioctl. 5255c8e32cc1SDaniel Vetter * 5256c8e32cc1SDaniel Vetter * Returns: 52571a498633SDaniel Vetter * Zero on success, negative errno on failure. 5258c8e32cc1SDaniel Vetter */ 5259d91d8a3fSKristian Høgsberg int drm_mode_page_flip_ioctl(struct drm_device *dev, 5260d91d8a3fSKristian Høgsberg void *data, struct drm_file *file_priv) 5261d91d8a3fSKristian Høgsberg { 5262d91d8a3fSKristian Høgsberg struct drm_mode_crtc_page_flip *page_flip = data; 5263d91d8a3fSKristian Høgsberg struct drm_crtc *crtc; 52643d30a59bSDaniel Vetter struct drm_framebuffer *fb = NULL; 5265d91d8a3fSKristian Høgsberg struct drm_pending_vblank_event *e = NULL; 5266d91d8a3fSKristian Høgsberg unsigned long flags; 5267d91d8a3fSKristian Høgsberg int ret = -EINVAL; 5268d91d8a3fSKristian Høgsberg 5269d91d8a3fSKristian Høgsberg if (page_flip->flags & ~DRM_MODE_PAGE_FLIP_FLAGS || 5270d91d8a3fSKristian Høgsberg page_flip->reserved != 0) 5271d91d8a3fSKristian Høgsberg return -EINVAL; 5272d91d8a3fSKristian Høgsberg 527362f2104fSKeith Packard if ((page_flip->flags & DRM_MODE_PAGE_FLIP_ASYNC) && !dev->mode_config.async_page_flip) 527462f2104fSKeith Packard return -EINVAL; 527562f2104fSKeith Packard 5276a2b34e22SRob Clark crtc = drm_crtc_find(dev, page_flip->crtc_id); 5277a2b34e22SRob Clark if (!crtc) 5278f27657f2SVille Syrjälä return -ENOENT; 5279d91d8a3fSKristian Høgsberg 52804d02e2deSDaniel Vetter drm_modeset_lock_crtc(crtc, crtc->primary); 5281f4510a27SMatt Roper if (crtc->primary->fb == NULL) { 528290c1efddSChris Wilson /* The framebuffer is currently unbound, presumably 528390c1efddSChris Wilson * due to a hotplug event, that userspace has not 528490c1efddSChris Wilson * yet discovered. 528590c1efddSChris Wilson */ 528690c1efddSChris Wilson ret = -EBUSY; 528790c1efddSChris Wilson goto out; 528890c1efddSChris Wilson } 528990c1efddSChris Wilson 5290d91d8a3fSKristian Høgsberg if (crtc->funcs->page_flip == NULL) 5291d91d8a3fSKristian Høgsberg goto out; 5292d91d8a3fSKristian Høgsberg 5293786b99edSDaniel Vetter fb = drm_framebuffer_lookup(dev, page_flip->fb_id); 529437c4e705SVille Syrjälä if (!fb) { 529537c4e705SVille Syrjälä ret = -ENOENT; 5296d91d8a3fSKristian Høgsberg goto out; 529737c4e705SVille Syrjälä } 5298d91d8a3fSKristian Høgsberg 5299c11e9283SDamien Lespiau ret = drm_crtc_check_viewport(crtc, crtc->x, crtc->y, &crtc->mode, fb); 5300c11e9283SDamien Lespiau if (ret) 53015f61bb42SVille Syrjälä goto out; 53025f61bb42SVille Syrjälä 5303f4510a27SMatt Roper if (crtc->primary->fb->pixel_format != fb->pixel_format) { 5304909d9cdaSLaurent Pinchart DRM_DEBUG_KMS("Page flip is not allowed to change frame buffer format.\n"); 5305909d9cdaSLaurent Pinchart ret = -EINVAL; 5306909d9cdaSLaurent Pinchart goto out; 5307909d9cdaSLaurent Pinchart } 5308909d9cdaSLaurent Pinchart 5309d91d8a3fSKristian Høgsberg if (page_flip->flags & DRM_MODE_PAGE_FLIP_EVENT) { 5310d91d8a3fSKristian Høgsberg ret = -ENOMEM; 5311d91d8a3fSKristian Høgsberg spin_lock_irqsave(&dev->event_lock, flags); 5312f76511b9SThierry Reding if (file_priv->event_space < sizeof(e->event)) { 5313d91d8a3fSKristian Høgsberg spin_unlock_irqrestore(&dev->event_lock, flags); 5314d91d8a3fSKristian Høgsberg goto out; 5315d91d8a3fSKristian Høgsberg } 5316f76511b9SThierry Reding file_priv->event_space -= sizeof(e->event); 5317d91d8a3fSKristian Høgsberg spin_unlock_irqrestore(&dev->event_lock, flags); 5318d91d8a3fSKristian Høgsberg 5319f76511b9SThierry Reding e = kzalloc(sizeof(*e), GFP_KERNEL); 5320d91d8a3fSKristian Høgsberg if (e == NULL) { 5321d91d8a3fSKristian Høgsberg spin_lock_irqsave(&dev->event_lock, flags); 5322f76511b9SThierry Reding file_priv->event_space += sizeof(e->event); 5323d91d8a3fSKristian Høgsberg spin_unlock_irqrestore(&dev->event_lock, flags); 5324d91d8a3fSKristian Høgsberg goto out; 5325d91d8a3fSKristian Høgsberg } 5326d91d8a3fSKristian Høgsberg 53277bd4d7beSJesse Barnes e->event.base.type = DRM_EVENT_FLIP_COMPLETE; 5328f76511b9SThierry Reding e->event.base.length = sizeof(e->event); 5329d91d8a3fSKristian Høgsberg e->event.user_data = page_flip->user_data; 5330d91d8a3fSKristian Høgsberg e->base.event = &e->event.base; 5331d91d8a3fSKristian Høgsberg e->base.file_priv = file_priv; 5332d91d8a3fSKristian Høgsberg e->base.destroy = 5333d91d8a3fSKristian Høgsberg (void (*) (struct drm_pending_event *)) kfree; 5334d91d8a3fSKristian Høgsberg } 5335d91d8a3fSKristian Høgsberg 53363d30a59bSDaniel Vetter crtc->primary->old_fb = crtc->primary->fb; 5337ed8d1975SKeith Packard ret = crtc->funcs->page_flip(crtc, fb, e, page_flip->flags); 5338d91d8a3fSKristian Høgsberg if (ret) { 5339aef6a7eeSJoonyoung Shim if (page_flip->flags & DRM_MODE_PAGE_FLIP_EVENT) { 5340d91d8a3fSKristian Høgsberg spin_lock_irqsave(&dev->event_lock, flags); 5341f76511b9SThierry Reding file_priv->event_space += sizeof(e->event); 5342d91d8a3fSKristian Høgsberg spin_unlock_irqrestore(&dev->event_lock, flags); 5343d91d8a3fSKristian Høgsberg kfree(e); 5344d91d8a3fSKristian Høgsberg } 5345b0d12325SDaniel Vetter /* Keep the old fb, don't unref it. */ 53463d30a59bSDaniel Vetter crtc->primary->old_fb = NULL; 5347b0d12325SDaniel Vetter } else { 53483cb43cc0SDaniel Vetter crtc->primary->fb = fb; 5349b0d12325SDaniel Vetter /* Unref only the old framebuffer. */ 5350b0d12325SDaniel Vetter fb = NULL; 5351aef6a7eeSJoonyoung Shim } 5352d91d8a3fSKristian Høgsberg 5353d91d8a3fSKristian Høgsberg out: 5354b0d12325SDaniel Vetter if (fb) 5355b0d12325SDaniel Vetter drm_framebuffer_unreference(fb); 53563d30a59bSDaniel Vetter if (crtc->primary->old_fb) 53573d30a59bSDaniel Vetter drm_framebuffer_unreference(crtc->primary->old_fb); 53583d30a59bSDaniel Vetter crtc->primary->old_fb = NULL; 5359d059f652SDaniel Vetter drm_modeset_unlock_crtc(crtc); 5360b4d5e7d1SDaniel Vetter 5361d91d8a3fSKristian Høgsberg return ret; 5362d91d8a3fSKristian Høgsberg } 5363eb033556SChris Wilson 5364c8e32cc1SDaniel Vetter /** 5365c8e32cc1SDaniel Vetter * drm_mode_config_reset - call ->reset callbacks 5366c8e32cc1SDaniel Vetter * @dev: drm device 5367c8e32cc1SDaniel Vetter * 5368c8e32cc1SDaniel Vetter * This functions calls all the crtc's, encoder's and connector's ->reset 5369c8e32cc1SDaniel Vetter * callback. Drivers can use this in e.g. their driver load or resume code to 5370c8e32cc1SDaniel Vetter * reset hardware and software state. 5371c8e32cc1SDaniel Vetter */ 5372eb033556SChris Wilson void drm_mode_config_reset(struct drm_device *dev) 5373eb033556SChris Wilson { 5374eb033556SChris Wilson struct drm_crtc *crtc; 53752a0d7cfdSDaniel Vetter struct drm_plane *plane; 5376eb033556SChris Wilson struct drm_encoder *encoder; 5377eb033556SChris Wilson struct drm_connector *connector; 5378eb033556SChris Wilson 53792a0d7cfdSDaniel Vetter list_for_each_entry(plane, &dev->mode_config.plane_list, head) 53802a0d7cfdSDaniel Vetter if (plane->funcs->reset) 53812a0d7cfdSDaniel Vetter plane->funcs->reset(plane); 53822a0d7cfdSDaniel Vetter 5383eb033556SChris Wilson list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) 5384eb033556SChris Wilson if (crtc->funcs->reset) 5385eb033556SChris Wilson crtc->funcs->reset(crtc); 5386eb033556SChris Wilson 5387eb033556SChris Wilson list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) 5388eb033556SChris Wilson if (encoder->funcs->reset) 5389eb033556SChris Wilson encoder->funcs->reset(encoder); 5390eb033556SChris Wilson 53915e2cb2f6SDaniel Vetter list_for_each_entry(connector, &dev->mode_config.connector_list, head) { 53925e2cb2f6SDaniel Vetter connector->status = connector_status_unknown; 53935e2cb2f6SDaniel Vetter 5394eb033556SChris Wilson if (connector->funcs->reset) 5395eb033556SChris Wilson connector->funcs->reset(connector); 5396eb033556SChris Wilson } 53975e2cb2f6SDaniel Vetter } 5398eb033556SChris Wilson EXPORT_SYMBOL(drm_mode_config_reset); 5399ff72145bSDave Airlie 5400c8e32cc1SDaniel Vetter /** 5401c8e32cc1SDaniel Vetter * drm_mode_create_dumb_ioctl - create a dumb backing storage buffer 5402c8e32cc1SDaniel Vetter * @dev: DRM device 5403c8e32cc1SDaniel Vetter * @data: ioctl data 5404c8e32cc1SDaniel Vetter * @file_priv: DRM file info 5405c8e32cc1SDaniel Vetter * 5406c8e32cc1SDaniel Vetter * This creates a new dumb buffer in the driver's backing storage manager (GEM, 5407c8e32cc1SDaniel Vetter * TTM or something else entirely) and returns the resulting buffer handle. This 5408c8e32cc1SDaniel Vetter * handle can then be wrapped up into a framebuffer modeset object. 5409c8e32cc1SDaniel Vetter * 5410c8e32cc1SDaniel Vetter * Note that userspace is not allowed to use such objects for render 5411c8e32cc1SDaniel Vetter * acceleration - drivers must create their own private ioctls for such a use 5412c8e32cc1SDaniel Vetter * case. 5413c8e32cc1SDaniel Vetter * 5414c8e32cc1SDaniel Vetter * Called by the user via ioctl. 5415c8e32cc1SDaniel Vetter * 5416c8e32cc1SDaniel Vetter * Returns: 54171a498633SDaniel Vetter * Zero on success, negative errno on failure. 5418c8e32cc1SDaniel Vetter */ 5419ff72145bSDave Airlie int drm_mode_create_dumb_ioctl(struct drm_device *dev, 5420ff72145bSDave Airlie void *data, struct drm_file *file_priv) 5421ff72145bSDave Airlie { 5422ff72145bSDave Airlie struct drm_mode_create_dumb *args = data; 5423b28cd41fSDavid Herrmann u32 cpp, stride, size; 5424ff72145bSDave Airlie 5425ff72145bSDave Airlie if (!dev->driver->dumb_create) 5426ff72145bSDave Airlie return -ENOSYS; 5427b28cd41fSDavid Herrmann if (!args->width || !args->height || !args->bpp) 5428b28cd41fSDavid Herrmann return -EINVAL; 5429b28cd41fSDavid Herrmann 5430b28cd41fSDavid Herrmann /* overflow checks for 32bit size calculations */ 543100e72089SDavid Herrmann /* NOTE: DIV_ROUND_UP() can overflow */ 5432b28cd41fSDavid Herrmann cpp = DIV_ROUND_UP(args->bpp, 8); 543300e72089SDavid Herrmann if (!cpp || cpp > 0xffffffffU / args->width) 5434b28cd41fSDavid Herrmann return -EINVAL; 5435b28cd41fSDavid Herrmann stride = cpp * args->width; 5436b28cd41fSDavid Herrmann if (args->height > 0xffffffffU / stride) 5437b28cd41fSDavid Herrmann return -EINVAL; 5438b28cd41fSDavid Herrmann 5439b28cd41fSDavid Herrmann /* test for wrap-around */ 5440b28cd41fSDavid Herrmann size = args->height * stride; 5441b28cd41fSDavid Herrmann if (PAGE_ALIGN(size) == 0) 5442b28cd41fSDavid Herrmann return -EINVAL; 5443b28cd41fSDavid Herrmann 5444f6085952SThierry Reding /* 5445f6085952SThierry Reding * handle, pitch and size are output parameters. Zero them out to 5446f6085952SThierry Reding * prevent drivers from accidentally using uninitialized data. Since 5447f6085952SThierry Reding * not all existing userspace is clearing these fields properly we 5448f6085952SThierry Reding * cannot reject IOCTL with garbage in them. 5449f6085952SThierry Reding */ 5450f6085952SThierry Reding args->handle = 0; 5451f6085952SThierry Reding args->pitch = 0; 5452f6085952SThierry Reding args->size = 0; 5453f6085952SThierry Reding 5454ff72145bSDave Airlie return dev->driver->dumb_create(file_priv, dev, args); 5455ff72145bSDave Airlie } 5456ff72145bSDave Airlie 5457c8e32cc1SDaniel Vetter /** 5458c8e32cc1SDaniel Vetter * drm_mode_mmap_dumb_ioctl - create an mmap offset for a dumb backing storage buffer 5459c8e32cc1SDaniel Vetter * @dev: DRM device 5460c8e32cc1SDaniel Vetter * @data: ioctl data 5461c8e32cc1SDaniel Vetter * @file_priv: DRM file info 5462c8e32cc1SDaniel Vetter * 5463c8e32cc1SDaniel Vetter * Allocate an offset in the drm device node's address space to be able to 5464c8e32cc1SDaniel Vetter * memory map a dumb buffer. 5465c8e32cc1SDaniel Vetter * 5466c8e32cc1SDaniel Vetter * Called by the user via ioctl. 5467c8e32cc1SDaniel Vetter * 5468c8e32cc1SDaniel Vetter * Returns: 54691a498633SDaniel Vetter * Zero on success, negative errno on failure. 5470c8e32cc1SDaniel Vetter */ 5471ff72145bSDave Airlie int drm_mode_mmap_dumb_ioctl(struct drm_device *dev, 5472ff72145bSDave Airlie void *data, struct drm_file *file_priv) 5473ff72145bSDave Airlie { 5474ff72145bSDave Airlie struct drm_mode_map_dumb *args = data; 5475ff72145bSDave Airlie 5476ff72145bSDave Airlie /* call driver ioctl to get mmap offset */ 5477ff72145bSDave Airlie if (!dev->driver->dumb_map_offset) 5478ff72145bSDave Airlie return -ENOSYS; 5479ff72145bSDave Airlie 5480ff72145bSDave Airlie return dev->driver->dumb_map_offset(file_priv, dev, args->handle, &args->offset); 5481ff72145bSDave Airlie } 5482ff72145bSDave Airlie 5483c8e32cc1SDaniel Vetter /** 5484c8e32cc1SDaniel Vetter * drm_mode_destroy_dumb_ioctl - destroy a dumb backing strage buffer 5485c8e32cc1SDaniel Vetter * @dev: DRM device 5486c8e32cc1SDaniel Vetter * @data: ioctl data 5487c8e32cc1SDaniel Vetter * @file_priv: DRM file info 5488c8e32cc1SDaniel Vetter * 5489c8e32cc1SDaniel Vetter * This destroys the userspace handle for the given dumb backing storage buffer. 5490c8e32cc1SDaniel Vetter * Since buffer objects must be reference counted in the kernel a buffer object 5491c8e32cc1SDaniel Vetter * won't be immediately freed if a framebuffer modeset object still uses it. 5492c8e32cc1SDaniel Vetter * 5493c8e32cc1SDaniel Vetter * Called by the user via ioctl. 5494c8e32cc1SDaniel Vetter * 5495c8e32cc1SDaniel Vetter * Returns: 54961a498633SDaniel Vetter * Zero on success, negative errno on failure. 5497c8e32cc1SDaniel Vetter */ 5498ff72145bSDave Airlie int drm_mode_destroy_dumb_ioctl(struct drm_device *dev, 5499ff72145bSDave Airlie void *data, struct drm_file *file_priv) 5500ff72145bSDave Airlie { 5501ff72145bSDave Airlie struct drm_mode_destroy_dumb *args = data; 5502ff72145bSDave Airlie 5503ff72145bSDave Airlie if (!dev->driver->dumb_destroy) 5504ff72145bSDave Airlie return -ENOSYS; 5505ff72145bSDave Airlie 5506ff72145bSDave Airlie return dev->driver->dumb_destroy(file_priv, dev, args->handle); 5507ff72145bSDave Airlie } 5508248dbc23SDave Airlie 5509c8e32cc1SDaniel Vetter /** 5510c8e32cc1SDaniel Vetter * drm_fb_get_bpp_depth - get the bpp/depth values for format 5511c8e32cc1SDaniel Vetter * @format: pixel format (DRM_FORMAT_*) 5512c8e32cc1SDaniel Vetter * @depth: storage for the depth value 5513c8e32cc1SDaniel Vetter * @bpp: storage for the bpp value 5514c8e32cc1SDaniel Vetter * 5515c8e32cc1SDaniel Vetter * This only supports RGB formats here for compat with code that doesn't use 5516c8e32cc1SDaniel Vetter * pixel formats directly yet. 5517248dbc23SDave Airlie */ 5518248dbc23SDave Airlie void drm_fb_get_bpp_depth(uint32_t format, unsigned int *depth, 5519248dbc23SDave Airlie int *bpp) 5520248dbc23SDave Airlie { 5521248dbc23SDave Airlie switch (format) { 5522c51a6bc5SVille Syrjälä case DRM_FORMAT_C8: 552304b3924dSVille Syrjälä case DRM_FORMAT_RGB332: 552404b3924dSVille Syrjälä case DRM_FORMAT_BGR233: 5525248dbc23SDave Airlie *depth = 8; 5526248dbc23SDave Airlie *bpp = 8; 5527248dbc23SDave Airlie break; 552804b3924dSVille Syrjälä case DRM_FORMAT_XRGB1555: 552904b3924dSVille Syrjälä case DRM_FORMAT_XBGR1555: 553004b3924dSVille Syrjälä case DRM_FORMAT_RGBX5551: 553104b3924dSVille Syrjälä case DRM_FORMAT_BGRX5551: 553204b3924dSVille Syrjälä case DRM_FORMAT_ARGB1555: 553304b3924dSVille Syrjälä case DRM_FORMAT_ABGR1555: 553404b3924dSVille Syrjälä case DRM_FORMAT_RGBA5551: 553504b3924dSVille Syrjälä case DRM_FORMAT_BGRA5551: 5536248dbc23SDave Airlie *depth = 15; 5537248dbc23SDave Airlie *bpp = 16; 5538248dbc23SDave Airlie break; 553904b3924dSVille Syrjälä case DRM_FORMAT_RGB565: 554004b3924dSVille Syrjälä case DRM_FORMAT_BGR565: 5541248dbc23SDave Airlie *depth = 16; 5542248dbc23SDave Airlie *bpp = 16; 5543248dbc23SDave Airlie break; 554404b3924dSVille Syrjälä case DRM_FORMAT_RGB888: 554504b3924dSVille Syrjälä case DRM_FORMAT_BGR888: 554604b3924dSVille Syrjälä *depth = 24; 554704b3924dSVille Syrjälä *bpp = 24; 554804b3924dSVille Syrjälä break; 554904b3924dSVille Syrjälä case DRM_FORMAT_XRGB8888: 555004b3924dSVille Syrjälä case DRM_FORMAT_XBGR8888: 555104b3924dSVille Syrjälä case DRM_FORMAT_RGBX8888: 555204b3924dSVille Syrjälä case DRM_FORMAT_BGRX8888: 5553248dbc23SDave Airlie *depth = 24; 5554248dbc23SDave Airlie *bpp = 32; 5555248dbc23SDave Airlie break; 555604b3924dSVille Syrjälä case DRM_FORMAT_XRGB2101010: 555704b3924dSVille Syrjälä case DRM_FORMAT_XBGR2101010: 555804b3924dSVille Syrjälä case DRM_FORMAT_RGBX1010102: 555904b3924dSVille Syrjälä case DRM_FORMAT_BGRX1010102: 556004b3924dSVille Syrjälä case DRM_FORMAT_ARGB2101010: 556104b3924dSVille Syrjälä case DRM_FORMAT_ABGR2101010: 556204b3924dSVille Syrjälä case DRM_FORMAT_RGBA1010102: 556304b3924dSVille Syrjälä case DRM_FORMAT_BGRA1010102: 5564248dbc23SDave Airlie *depth = 30; 5565248dbc23SDave Airlie *bpp = 32; 5566248dbc23SDave Airlie break; 556704b3924dSVille Syrjälä case DRM_FORMAT_ARGB8888: 556804b3924dSVille Syrjälä case DRM_FORMAT_ABGR8888: 556904b3924dSVille Syrjälä case DRM_FORMAT_RGBA8888: 557004b3924dSVille Syrjälä case DRM_FORMAT_BGRA8888: 5571248dbc23SDave Airlie *depth = 32; 5572248dbc23SDave Airlie *bpp = 32; 5573248dbc23SDave Airlie break; 5574248dbc23SDave Airlie default: 557523c453a4SVille Syrjälä DRM_DEBUG_KMS("unsupported pixel format %s\n", 557623c453a4SVille Syrjälä drm_get_format_name(format)); 5577248dbc23SDave Airlie *depth = 0; 5578248dbc23SDave Airlie *bpp = 0; 5579248dbc23SDave Airlie break; 5580248dbc23SDave Airlie } 5581248dbc23SDave Airlie } 5582248dbc23SDave Airlie EXPORT_SYMBOL(drm_fb_get_bpp_depth); 5583141670e9SVille Syrjälä 5584141670e9SVille Syrjälä /** 5585141670e9SVille Syrjälä * drm_format_num_planes - get the number of planes for format 5586141670e9SVille Syrjälä * @format: pixel format (DRM_FORMAT_*) 5587141670e9SVille Syrjälä * 5588c8e32cc1SDaniel Vetter * Returns: 5589141670e9SVille Syrjälä * The number of planes used by the specified pixel format. 5590141670e9SVille Syrjälä */ 5591141670e9SVille Syrjälä int drm_format_num_planes(uint32_t format) 5592141670e9SVille Syrjälä { 5593141670e9SVille Syrjälä switch (format) { 5594141670e9SVille Syrjälä case DRM_FORMAT_YUV410: 5595141670e9SVille Syrjälä case DRM_FORMAT_YVU410: 5596141670e9SVille Syrjälä case DRM_FORMAT_YUV411: 5597141670e9SVille Syrjälä case DRM_FORMAT_YVU411: 5598141670e9SVille Syrjälä case DRM_FORMAT_YUV420: 5599141670e9SVille Syrjälä case DRM_FORMAT_YVU420: 5600141670e9SVille Syrjälä case DRM_FORMAT_YUV422: 5601141670e9SVille Syrjälä case DRM_FORMAT_YVU422: 5602141670e9SVille Syrjälä case DRM_FORMAT_YUV444: 5603141670e9SVille Syrjälä case DRM_FORMAT_YVU444: 5604141670e9SVille Syrjälä return 3; 5605141670e9SVille Syrjälä case DRM_FORMAT_NV12: 5606141670e9SVille Syrjälä case DRM_FORMAT_NV21: 5607141670e9SVille Syrjälä case DRM_FORMAT_NV16: 5608141670e9SVille Syrjälä case DRM_FORMAT_NV61: 5609ba623f6aSLaurent Pinchart case DRM_FORMAT_NV24: 5610ba623f6aSLaurent Pinchart case DRM_FORMAT_NV42: 5611141670e9SVille Syrjälä return 2; 5612141670e9SVille Syrjälä default: 5613141670e9SVille Syrjälä return 1; 5614141670e9SVille Syrjälä } 5615141670e9SVille Syrjälä } 5616141670e9SVille Syrjälä EXPORT_SYMBOL(drm_format_num_planes); 56175a86bd55SVille Syrjälä 56185a86bd55SVille Syrjälä /** 56195a86bd55SVille Syrjälä * drm_format_plane_cpp - determine the bytes per pixel value 56205a86bd55SVille Syrjälä * @format: pixel format (DRM_FORMAT_*) 56215a86bd55SVille Syrjälä * @plane: plane index 56225a86bd55SVille Syrjälä * 5623c8e32cc1SDaniel Vetter * Returns: 56245a86bd55SVille Syrjälä * The bytes per pixel value for the specified plane. 56255a86bd55SVille Syrjälä */ 56265a86bd55SVille Syrjälä int drm_format_plane_cpp(uint32_t format, int plane) 56275a86bd55SVille Syrjälä { 56285a86bd55SVille Syrjälä unsigned int depth; 56295a86bd55SVille Syrjälä int bpp; 56305a86bd55SVille Syrjälä 56315a86bd55SVille Syrjälä if (plane >= drm_format_num_planes(format)) 56325a86bd55SVille Syrjälä return 0; 56335a86bd55SVille Syrjälä 56345a86bd55SVille Syrjälä switch (format) { 56355a86bd55SVille Syrjälä case DRM_FORMAT_YUYV: 56365a86bd55SVille Syrjälä case DRM_FORMAT_YVYU: 56375a86bd55SVille Syrjälä case DRM_FORMAT_UYVY: 56385a86bd55SVille Syrjälä case DRM_FORMAT_VYUY: 56395a86bd55SVille Syrjälä return 2; 56405a86bd55SVille Syrjälä case DRM_FORMAT_NV12: 56415a86bd55SVille Syrjälä case DRM_FORMAT_NV21: 56425a86bd55SVille Syrjälä case DRM_FORMAT_NV16: 56435a86bd55SVille Syrjälä case DRM_FORMAT_NV61: 5644ba623f6aSLaurent Pinchart case DRM_FORMAT_NV24: 5645ba623f6aSLaurent Pinchart case DRM_FORMAT_NV42: 56465a86bd55SVille Syrjälä return plane ? 2 : 1; 56475a86bd55SVille Syrjälä case DRM_FORMAT_YUV410: 56485a86bd55SVille Syrjälä case DRM_FORMAT_YVU410: 56495a86bd55SVille Syrjälä case DRM_FORMAT_YUV411: 56505a86bd55SVille Syrjälä case DRM_FORMAT_YVU411: 56515a86bd55SVille Syrjälä case DRM_FORMAT_YUV420: 56525a86bd55SVille Syrjälä case DRM_FORMAT_YVU420: 56535a86bd55SVille Syrjälä case DRM_FORMAT_YUV422: 56545a86bd55SVille Syrjälä case DRM_FORMAT_YVU422: 56555a86bd55SVille Syrjälä case DRM_FORMAT_YUV444: 56565a86bd55SVille Syrjälä case DRM_FORMAT_YVU444: 56575a86bd55SVille Syrjälä return 1; 56585a86bd55SVille Syrjälä default: 56595a86bd55SVille Syrjälä drm_fb_get_bpp_depth(format, &depth, &bpp); 56605a86bd55SVille Syrjälä return bpp >> 3; 56615a86bd55SVille Syrjälä } 56625a86bd55SVille Syrjälä } 56635a86bd55SVille Syrjälä EXPORT_SYMBOL(drm_format_plane_cpp); 566401b68b04SVille Syrjälä 566501b68b04SVille Syrjälä /** 566601b68b04SVille Syrjälä * drm_format_horz_chroma_subsampling - get the horizontal chroma subsampling factor 566701b68b04SVille Syrjälä * @format: pixel format (DRM_FORMAT_*) 566801b68b04SVille Syrjälä * 5669c8e32cc1SDaniel Vetter * Returns: 567001b68b04SVille Syrjälä * The horizontal chroma subsampling factor for the 567101b68b04SVille Syrjälä * specified pixel format. 567201b68b04SVille Syrjälä */ 567301b68b04SVille Syrjälä int drm_format_horz_chroma_subsampling(uint32_t format) 567401b68b04SVille Syrjälä { 567501b68b04SVille Syrjälä switch (format) { 567601b68b04SVille Syrjälä case DRM_FORMAT_YUV411: 567701b68b04SVille Syrjälä case DRM_FORMAT_YVU411: 567801b68b04SVille Syrjälä case DRM_FORMAT_YUV410: 567901b68b04SVille Syrjälä case DRM_FORMAT_YVU410: 568001b68b04SVille Syrjälä return 4; 568101b68b04SVille Syrjälä case DRM_FORMAT_YUYV: 568201b68b04SVille Syrjälä case DRM_FORMAT_YVYU: 568301b68b04SVille Syrjälä case DRM_FORMAT_UYVY: 568401b68b04SVille Syrjälä case DRM_FORMAT_VYUY: 568501b68b04SVille Syrjälä case DRM_FORMAT_NV12: 568601b68b04SVille Syrjälä case DRM_FORMAT_NV21: 568701b68b04SVille Syrjälä case DRM_FORMAT_NV16: 568801b68b04SVille Syrjälä case DRM_FORMAT_NV61: 568901b68b04SVille Syrjälä case DRM_FORMAT_YUV422: 569001b68b04SVille Syrjälä case DRM_FORMAT_YVU422: 569101b68b04SVille Syrjälä case DRM_FORMAT_YUV420: 569201b68b04SVille Syrjälä case DRM_FORMAT_YVU420: 569301b68b04SVille Syrjälä return 2; 569401b68b04SVille Syrjälä default: 569501b68b04SVille Syrjälä return 1; 569601b68b04SVille Syrjälä } 569701b68b04SVille Syrjälä } 569801b68b04SVille Syrjälä EXPORT_SYMBOL(drm_format_horz_chroma_subsampling); 569901b68b04SVille Syrjälä 570001b68b04SVille Syrjälä /** 570101b68b04SVille Syrjälä * drm_format_vert_chroma_subsampling - get the vertical chroma subsampling factor 570201b68b04SVille Syrjälä * @format: pixel format (DRM_FORMAT_*) 570301b68b04SVille Syrjälä * 5704c8e32cc1SDaniel Vetter * Returns: 570501b68b04SVille Syrjälä * The vertical chroma subsampling factor for the 570601b68b04SVille Syrjälä * specified pixel format. 570701b68b04SVille Syrjälä */ 570801b68b04SVille Syrjälä int drm_format_vert_chroma_subsampling(uint32_t format) 570901b68b04SVille Syrjälä { 571001b68b04SVille Syrjälä switch (format) { 571101b68b04SVille Syrjälä case DRM_FORMAT_YUV410: 571201b68b04SVille Syrjälä case DRM_FORMAT_YVU410: 571301b68b04SVille Syrjälä return 4; 571401b68b04SVille Syrjälä case DRM_FORMAT_YUV420: 571501b68b04SVille Syrjälä case DRM_FORMAT_YVU420: 571601b68b04SVille Syrjälä case DRM_FORMAT_NV12: 571701b68b04SVille Syrjälä case DRM_FORMAT_NV21: 571801b68b04SVille Syrjälä return 2; 571901b68b04SVille Syrjälä default: 572001b68b04SVille Syrjälä return 1; 572101b68b04SVille Syrjälä } 572201b68b04SVille Syrjälä } 572301b68b04SVille Syrjälä EXPORT_SYMBOL(drm_format_vert_chroma_subsampling); 572487d24fc3SLaurent Pinchart 572587d24fc3SLaurent Pinchart /** 57263c9855f6SVille Syrjälä * drm_rotation_simplify() - Try to simplify the rotation 57273c9855f6SVille Syrjälä * @rotation: Rotation to be simplified 57283c9855f6SVille Syrjälä * @supported_rotations: Supported rotations 57293c9855f6SVille Syrjälä * 57303c9855f6SVille Syrjälä * Attempt to simplify the rotation to a form that is supported. 57313c9855f6SVille Syrjälä * Eg. if the hardware supports everything except DRM_REFLECT_X 57323c9855f6SVille Syrjälä * one could call this function like this: 57333c9855f6SVille Syrjälä * 57343c9855f6SVille Syrjälä * drm_rotation_simplify(rotation, BIT(DRM_ROTATE_0) | 57353c9855f6SVille Syrjälä * BIT(DRM_ROTATE_90) | BIT(DRM_ROTATE_180) | 57363c9855f6SVille Syrjälä * BIT(DRM_ROTATE_270) | BIT(DRM_REFLECT_Y)); 57373c9855f6SVille Syrjälä * 57383c9855f6SVille Syrjälä * to eliminate the DRM_ROTATE_X flag. Depending on what kind of 57393c9855f6SVille Syrjälä * transforms the hardware supports, this function may not 57403c9855f6SVille Syrjälä * be able to produce a supported transform, so the caller should 57413c9855f6SVille Syrjälä * check the result afterwards. 57423c9855f6SVille Syrjälä */ 57433c9855f6SVille Syrjälä unsigned int drm_rotation_simplify(unsigned int rotation, 57443c9855f6SVille Syrjälä unsigned int supported_rotations) 57453c9855f6SVille Syrjälä { 57463c9855f6SVille Syrjälä if (rotation & ~supported_rotations) { 57473c9855f6SVille Syrjälä rotation ^= BIT(DRM_REFLECT_X) | BIT(DRM_REFLECT_Y); 57483c9855f6SVille Syrjälä rotation = (rotation & ~0xf) | BIT((ffs(rotation & 0xf) + 1) % 4); 57493c9855f6SVille Syrjälä } 57503c9855f6SVille Syrjälä 57513c9855f6SVille Syrjälä return rotation; 57523c9855f6SVille Syrjälä } 57533c9855f6SVille Syrjälä EXPORT_SYMBOL(drm_rotation_simplify); 57543c9855f6SVille Syrjälä 57553c9855f6SVille Syrjälä /** 575687d24fc3SLaurent Pinchart * drm_mode_config_init - initialize DRM mode_configuration structure 575787d24fc3SLaurent Pinchart * @dev: DRM device 575887d24fc3SLaurent Pinchart * 575987d24fc3SLaurent Pinchart * Initialize @dev's mode_config structure, used for tracking the graphics 576087d24fc3SLaurent Pinchart * configuration of @dev. 576187d24fc3SLaurent Pinchart * 576287d24fc3SLaurent Pinchart * Since this initializes the modeset locks, no locking is possible. Which is no 576387d24fc3SLaurent Pinchart * problem, since this should happen single threaded at init time. It is the 576487d24fc3SLaurent Pinchart * driver's problem to ensure this guarantee. 576587d24fc3SLaurent Pinchart * 576687d24fc3SLaurent Pinchart */ 576787d24fc3SLaurent Pinchart void drm_mode_config_init(struct drm_device *dev) 576887d24fc3SLaurent Pinchart { 576987d24fc3SLaurent Pinchart mutex_init(&dev->mode_config.mutex); 577051fd371bSRob Clark drm_modeset_lock_init(&dev->mode_config.connection_mutex); 577187d24fc3SLaurent Pinchart mutex_init(&dev->mode_config.idr_mutex); 577287d24fc3SLaurent Pinchart mutex_init(&dev->mode_config.fb_lock); 57738fb6e7a5SDaniel Stone mutex_init(&dev->mode_config.blob_lock); 577487d24fc3SLaurent Pinchart INIT_LIST_HEAD(&dev->mode_config.fb_list); 577587d24fc3SLaurent Pinchart INIT_LIST_HEAD(&dev->mode_config.crtc_list); 577687d24fc3SLaurent Pinchart INIT_LIST_HEAD(&dev->mode_config.connector_list); 577787d24fc3SLaurent Pinchart INIT_LIST_HEAD(&dev->mode_config.encoder_list); 577887d24fc3SLaurent Pinchart INIT_LIST_HEAD(&dev->mode_config.property_list); 577987d24fc3SLaurent Pinchart INIT_LIST_HEAD(&dev->mode_config.property_blob_list); 578087d24fc3SLaurent Pinchart INIT_LIST_HEAD(&dev->mode_config.plane_list); 578187d24fc3SLaurent Pinchart idr_init(&dev->mode_config.crtc_idr); 5782138f9ebbSDave Airlie idr_init(&dev->mode_config.tile_idr); 578387d24fc3SLaurent Pinchart 578487d24fc3SLaurent Pinchart drm_modeset_lock_all(dev); 57856b4959f4SRob Clark drm_mode_create_standard_properties(dev); 578687d24fc3SLaurent Pinchart drm_modeset_unlock_all(dev); 578787d24fc3SLaurent Pinchart 578887d24fc3SLaurent Pinchart /* Just to be sure */ 578987d24fc3SLaurent Pinchart dev->mode_config.num_fb = 0; 579087d24fc3SLaurent Pinchart dev->mode_config.num_connector = 0; 579187d24fc3SLaurent Pinchart dev->mode_config.num_crtc = 0; 579287d24fc3SLaurent Pinchart dev->mode_config.num_encoder = 0; 5793e27dde3eSMatt Roper dev->mode_config.num_overlay_plane = 0; 5794e27dde3eSMatt Roper dev->mode_config.num_total_plane = 0; 579587d24fc3SLaurent Pinchart } 579687d24fc3SLaurent Pinchart EXPORT_SYMBOL(drm_mode_config_init); 579787d24fc3SLaurent Pinchart 579887d24fc3SLaurent Pinchart /** 579987d24fc3SLaurent Pinchart * drm_mode_config_cleanup - free up DRM mode_config info 580087d24fc3SLaurent Pinchart * @dev: DRM device 580187d24fc3SLaurent Pinchart * 580287d24fc3SLaurent Pinchart * Free up all the connectors and CRTCs associated with this DRM device, then 580387d24fc3SLaurent Pinchart * free up the framebuffers and associated buffer objects. 580487d24fc3SLaurent Pinchart * 580587d24fc3SLaurent Pinchart * Note that since this /should/ happen single-threaded at driver/device 580687d24fc3SLaurent Pinchart * teardown time, no locking is required. It's the driver's job to ensure that 580787d24fc3SLaurent Pinchart * this guarantee actually holds true. 580887d24fc3SLaurent Pinchart * 580987d24fc3SLaurent Pinchart * FIXME: cleanup any dangling user buffer objects too 581087d24fc3SLaurent Pinchart */ 581187d24fc3SLaurent Pinchart void drm_mode_config_cleanup(struct drm_device *dev) 581287d24fc3SLaurent Pinchart { 581387d24fc3SLaurent Pinchart struct drm_connector *connector, *ot; 581487d24fc3SLaurent Pinchart struct drm_crtc *crtc, *ct; 581587d24fc3SLaurent Pinchart struct drm_encoder *encoder, *enct; 581687d24fc3SLaurent Pinchart struct drm_framebuffer *fb, *fbt; 581787d24fc3SLaurent Pinchart struct drm_property *property, *pt; 581887d24fc3SLaurent Pinchart struct drm_property_blob *blob, *bt; 581987d24fc3SLaurent Pinchart struct drm_plane *plane, *plt; 582087d24fc3SLaurent Pinchart 582187d24fc3SLaurent Pinchart list_for_each_entry_safe(encoder, enct, &dev->mode_config.encoder_list, 582287d24fc3SLaurent Pinchart head) { 582387d24fc3SLaurent Pinchart encoder->funcs->destroy(encoder); 582487d24fc3SLaurent Pinchart } 582587d24fc3SLaurent Pinchart 582687d24fc3SLaurent Pinchart list_for_each_entry_safe(connector, ot, 582787d24fc3SLaurent Pinchart &dev->mode_config.connector_list, head) { 582887d24fc3SLaurent Pinchart connector->funcs->destroy(connector); 582987d24fc3SLaurent Pinchart } 583087d24fc3SLaurent Pinchart 583187d24fc3SLaurent Pinchart list_for_each_entry_safe(property, pt, &dev->mode_config.property_list, 583287d24fc3SLaurent Pinchart head) { 583387d24fc3SLaurent Pinchart drm_property_destroy(dev, property); 583487d24fc3SLaurent Pinchart } 583587d24fc3SLaurent Pinchart 583687d24fc3SLaurent Pinchart list_for_each_entry_safe(blob, bt, &dev->mode_config.property_blob_list, 5837e2f5d2eaSDaniel Stone head_global) { 58386bcacf51SDaniel Stone drm_property_unreference_blob(blob); 583987d24fc3SLaurent Pinchart } 584087d24fc3SLaurent Pinchart 584187d24fc3SLaurent Pinchart /* 584287d24fc3SLaurent Pinchart * Single-threaded teardown context, so it's not required to grab the 584387d24fc3SLaurent Pinchart * fb_lock to protect against concurrent fb_list access. Contrary, it 584487d24fc3SLaurent Pinchart * would actually deadlock with the drm_framebuffer_cleanup function. 584587d24fc3SLaurent Pinchart * 584687d24fc3SLaurent Pinchart * Also, if there are any framebuffers left, that's a driver leak now, 584787d24fc3SLaurent Pinchart * so politely WARN about this. 584887d24fc3SLaurent Pinchart */ 584987d24fc3SLaurent Pinchart WARN_ON(!list_empty(&dev->mode_config.fb_list)); 585087d24fc3SLaurent Pinchart list_for_each_entry_safe(fb, fbt, &dev->mode_config.fb_list, head) { 585187d24fc3SLaurent Pinchart drm_framebuffer_remove(fb); 585287d24fc3SLaurent Pinchart } 585387d24fc3SLaurent Pinchart 585487d24fc3SLaurent Pinchart list_for_each_entry_safe(plane, plt, &dev->mode_config.plane_list, 585587d24fc3SLaurent Pinchart head) { 585687d24fc3SLaurent Pinchart plane->funcs->destroy(plane); 585787d24fc3SLaurent Pinchart } 585887d24fc3SLaurent Pinchart 585987d24fc3SLaurent Pinchart list_for_each_entry_safe(crtc, ct, &dev->mode_config.crtc_list, head) { 586087d24fc3SLaurent Pinchart crtc->funcs->destroy(crtc); 586187d24fc3SLaurent Pinchart } 586287d24fc3SLaurent Pinchart 5863138f9ebbSDave Airlie idr_destroy(&dev->mode_config.tile_idr); 586487d24fc3SLaurent Pinchart idr_destroy(&dev->mode_config.crtc_idr); 586551fd371bSRob Clark drm_modeset_lock_fini(&dev->mode_config.connection_mutex); 586687d24fc3SLaurent Pinchart } 586787d24fc3SLaurent Pinchart EXPORT_SYMBOL(drm_mode_config_cleanup); 5868c1df5f3cSVille Syrjälä 5869c1df5f3cSVille Syrjälä struct drm_property *drm_mode_create_rotation_property(struct drm_device *dev, 5870c1df5f3cSVille Syrjälä unsigned int supported_rotations) 5871c1df5f3cSVille Syrjälä { 5872c1df5f3cSVille Syrjälä static const struct drm_prop_enum_list props[] = { 5873c1df5f3cSVille Syrjälä { DRM_ROTATE_0, "rotate-0" }, 5874c1df5f3cSVille Syrjälä { DRM_ROTATE_90, "rotate-90" }, 5875c1df5f3cSVille Syrjälä { DRM_ROTATE_180, "rotate-180" }, 5876c1df5f3cSVille Syrjälä { DRM_ROTATE_270, "rotate-270" }, 5877c1df5f3cSVille Syrjälä { DRM_REFLECT_X, "reflect-x" }, 5878c1df5f3cSVille Syrjälä { DRM_REFLECT_Y, "reflect-y" }, 5879c1df5f3cSVille Syrjälä }; 5880c1df5f3cSVille Syrjälä 5881c1df5f3cSVille Syrjälä return drm_property_create_bitmask(dev, 0, "rotation", 5882c1df5f3cSVille Syrjälä props, ARRAY_SIZE(props), 5883c1df5f3cSVille Syrjälä supported_rotations); 5884c1df5f3cSVille Syrjälä } 5885c1df5f3cSVille Syrjälä EXPORT_SYMBOL(drm_mode_create_rotation_property); 5886138f9ebbSDave Airlie 5887138f9ebbSDave Airlie /** 5888138f9ebbSDave Airlie * DOC: Tile group 5889138f9ebbSDave Airlie * 5890138f9ebbSDave Airlie * Tile groups are used to represent tiled monitors with a unique 5891138f9ebbSDave Airlie * integer identifier. Tiled monitors using DisplayID v1.3 have 5892138f9ebbSDave Airlie * a unique 8-byte handle, we store this in a tile group, so we 5893138f9ebbSDave Airlie * have a common identifier for all tiles in a monitor group. 5894138f9ebbSDave Airlie */ 5895138f9ebbSDave Airlie static void drm_tile_group_free(struct kref *kref) 5896138f9ebbSDave Airlie { 5897138f9ebbSDave Airlie struct drm_tile_group *tg = container_of(kref, struct drm_tile_group, refcount); 5898138f9ebbSDave Airlie struct drm_device *dev = tg->dev; 5899138f9ebbSDave Airlie mutex_lock(&dev->mode_config.idr_mutex); 5900138f9ebbSDave Airlie idr_remove(&dev->mode_config.tile_idr, tg->id); 5901138f9ebbSDave Airlie mutex_unlock(&dev->mode_config.idr_mutex); 5902138f9ebbSDave Airlie kfree(tg); 5903138f9ebbSDave Airlie } 5904138f9ebbSDave Airlie 5905138f9ebbSDave Airlie /** 5906138f9ebbSDave Airlie * drm_mode_put_tile_group - drop a reference to a tile group. 5907138f9ebbSDave Airlie * @dev: DRM device 5908138f9ebbSDave Airlie * @tg: tile group to drop reference to. 5909138f9ebbSDave Airlie * 5910138f9ebbSDave Airlie * drop reference to tile group and free if 0. 5911138f9ebbSDave Airlie */ 5912138f9ebbSDave Airlie void drm_mode_put_tile_group(struct drm_device *dev, 5913138f9ebbSDave Airlie struct drm_tile_group *tg) 5914138f9ebbSDave Airlie { 5915138f9ebbSDave Airlie kref_put(&tg->refcount, drm_tile_group_free); 5916138f9ebbSDave Airlie } 5917138f9ebbSDave Airlie 5918138f9ebbSDave Airlie /** 5919138f9ebbSDave Airlie * drm_mode_get_tile_group - get a reference to an existing tile group 5920138f9ebbSDave Airlie * @dev: DRM device 5921138f9ebbSDave Airlie * @topology: 8-bytes unique per monitor. 5922138f9ebbSDave Airlie * 5923138f9ebbSDave Airlie * Use the unique bytes to get a reference to an existing tile group. 5924138f9ebbSDave Airlie * 5925138f9ebbSDave Airlie * RETURNS: 5926138f9ebbSDave Airlie * tile group or NULL if not found. 5927138f9ebbSDave Airlie */ 5928138f9ebbSDave Airlie struct drm_tile_group *drm_mode_get_tile_group(struct drm_device *dev, 5929138f9ebbSDave Airlie char topology[8]) 5930138f9ebbSDave Airlie { 5931138f9ebbSDave Airlie struct drm_tile_group *tg; 5932138f9ebbSDave Airlie int id; 5933138f9ebbSDave Airlie mutex_lock(&dev->mode_config.idr_mutex); 5934138f9ebbSDave Airlie idr_for_each_entry(&dev->mode_config.tile_idr, tg, id) { 5935138f9ebbSDave Airlie if (!memcmp(tg->group_data, topology, 8)) { 5936138f9ebbSDave Airlie if (!kref_get_unless_zero(&tg->refcount)) 5937138f9ebbSDave Airlie tg = NULL; 5938138f9ebbSDave Airlie mutex_unlock(&dev->mode_config.idr_mutex); 5939138f9ebbSDave Airlie return tg; 5940138f9ebbSDave Airlie } 5941138f9ebbSDave Airlie } 5942138f9ebbSDave Airlie mutex_unlock(&dev->mode_config.idr_mutex); 5943138f9ebbSDave Airlie return NULL; 5944138f9ebbSDave Airlie } 594581ddd1bcSRob Clark EXPORT_SYMBOL(drm_mode_get_tile_group); 5946138f9ebbSDave Airlie 5947138f9ebbSDave Airlie /** 5948138f9ebbSDave Airlie * drm_mode_create_tile_group - create a tile group from a displayid description 5949138f9ebbSDave Airlie * @dev: DRM device 5950138f9ebbSDave Airlie * @topology: 8-bytes unique per monitor. 5951138f9ebbSDave Airlie * 5952138f9ebbSDave Airlie * Create a tile group for the unique monitor, and get a unique 5953138f9ebbSDave Airlie * identifier for the tile group. 5954138f9ebbSDave Airlie * 5955138f9ebbSDave Airlie * RETURNS: 5956138f9ebbSDave Airlie * new tile group or error. 5957138f9ebbSDave Airlie */ 5958138f9ebbSDave Airlie struct drm_tile_group *drm_mode_create_tile_group(struct drm_device *dev, 5959138f9ebbSDave Airlie char topology[8]) 5960138f9ebbSDave Airlie { 5961138f9ebbSDave Airlie struct drm_tile_group *tg; 5962138f9ebbSDave Airlie int ret; 5963138f9ebbSDave Airlie 5964138f9ebbSDave Airlie tg = kzalloc(sizeof(*tg), GFP_KERNEL); 5965138f9ebbSDave Airlie if (!tg) 5966138f9ebbSDave Airlie return ERR_PTR(-ENOMEM); 5967138f9ebbSDave Airlie 5968138f9ebbSDave Airlie kref_init(&tg->refcount); 5969138f9ebbSDave Airlie memcpy(tg->group_data, topology, 8); 5970138f9ebbSDave Airlie tg->dev = dev; 5971138f9ebbSDave Airlie 5972138f9ebbSDave Airlie mutex_lock(&dev->mode_config.idr_mutex); 5973138f9ebbSDave Airlie ret = idr_alloc(&dev->mode_config.tile_idr, tg, 1, 0, GFP_KERNEL); 5974138f9ebbSDave Airlie if (ret >= 0) { 5975138f9ebbSDave Airlie tg->id = ret; 5976138f9ebbSDave Airlie } else { 5977138f9ebbSDave Airlie kfree(tg); 5978138f9ebbSDave Airlie tg = ERR_PTR(ret); 5979138f9ebbSDave Airlie } 5980138f9ebbSDave Airlie 5981138f9ebbSDave Airlie mutex_unlock(&dev->mode_config.idr_mutex); 5982138f9ebbSDave Airlie return tg; 5983138f9ebbSDave Airlie } 598481ddd1bcSRob Clark EXPORT_SYMBOL(drm_mode_create_tile_group); 5985