1f453ba04SDave Airlie /* 2f453ba04SDave Airlie * Copyright (c) 2006-2008 Intel Corporation 3f453ba04SDave Airlie * Copyright (c) 2007 Dave Airlie <airlied@linux.ie> 4f453ba04SDave Airlie * Copyright (c) 2008 Red Hat Inc. 5f453ba04SDave Airlie * 6f453ba04SDave Airlie * DRM core CRTC related functions 7f453ba04SDave Airlie * 8f453ba04SDave Airlie * Permission to use, copy, modify, distribute, and sell this software and its 9f453ba04SDave Airlie * documentation for any purpose is hereby granted without fee, provided that 10f453ba04SDave Airlie * the above copyright notice appear in all copies and that both that copyright 11f453ba04SDave Airlie * notice and this permission notice appear in supporting documentation, and 12f453ba04SDave Airlie * that the name of the copyright holders not be used in advertising or 13f453ba04SDave Airlie * publicity pertaining to distribution of the software without specific, 14f453ba04SDave Airlie * written prior permission. The copyright holders make no representations 15f453ba04SDave Airlie * about the suitability of this software for any purpose. It is provided "as 16f453ba04SDave Airlie * is" without express or implied warranty. 17f453ba04SDave Airlie * 18f453ba04SDave Airlie * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, 19f453ba04SDave Airlie * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO 20f453ba04SDave Airlie * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR 21f453ba04SDave Airlie * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, 22f453ba04SDave Airlie * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER 23f453ba04SDave Airlie * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE 24f453ba04SDave Airlie * OF THIS SOFTWARE. 25f453ba04SDave Airlie * 26f453ba04SDave Airlie * Authors: 27f453ba04SDave Airlie * Keith Packard 28f453ba04SDave Airlie * Eric Anholt <eric@anholt.net> 29f453ba04SDave Airlie * Dave Airlie <airlied@linux.ie> 30f453ba04SDave Airlie * Jesse Barnes <jesse.barnes@intel.com> 31f453ba04SDave Airlie */ 326ba6d03eSVille Syrjälä #include <linux/ctype.h> 33f453ba04SDave Airlie #include <linux/list.h> 345a0e3ad6STejun Heo #include <linux/slab.h> 352d1a8a48SPaul Gortmaker #include <linux/export.h> 36760285e7SDavid Howells #include <drm/drmP.h> 37760285e7SDavid Howells #include <drm/drm_crtc.h> 38760285e7SDavid Howells #include <drm/drm_edid.h> 39760285e7SDavid Howells #include <drm/drm_fourcc.h> 4051fd371bSRob Clark #include <drm/drm_modeset_lock.h> 4188a48e29SRob Clark #include <drm/drm_atomic.h> 42f453ba04SDave Airlie 438bd441b2SDaniel Vetter #include "drm_crtc_internal.h" 4467d0ec4eSDaniel Vetter #include "drm_internal.h" 458bd441b2SDaniel Vetter 469a6f5130SChris Wilson static struct drm_framebuffer * 479a6f5130SChris Wilson internal_framebuffer_create(struct drm_device *dev, 481eb83451SVille Syrjälä const struct drm_mode_fb_cmd2 *r, 49c394c2b0SMatt Roper struct drm_file *file_priv); 50c394c2b0SMatt Roper 51f453ba04SDave Airlie /* Avoid boilerplate. I'm tired of typing. */ 52f453ba04SDave Airlie #define DRM_ENUM_NAME_FN(fnname, list) \ 53d20d3174SVille Syrjälä const char *fnname(int val) \ 54f453ba04SDave Airlie { \ 55f453ba04SDave Airlie int i; \ 56f453ba04SDave Airlie for (i = 0; i < ARRAY_SIZE(list); i++) { \ 57f453ba04SDave Airlie if (list[i].type == val) \ 58f453ba04SDave Airlie return list[i].name; \ 59f453ba04SDave Airlie } \ 60f453ba04SDave Airlie return "(unknown)"; \ 61f453ba04SDave Airlie } 62f453ba04SDave Airlie 63f453ba04SDave Airlie /* 64f453ba04SDave Airlie * Global properties 65f453ba04SDave Airlie */ 664dfd909fSThierry Reding static const struct drm_prop_enum_list drm_dpms_enum_list[] = { 674dfd909fSThierry Reding { DRM_MODE_DPMS_ON, "On" }, 68f453ba04SDave Airlie { DRM_MODE_DPMS_STANDBY, "Standby" }, 69f453ba04SDave Airlie { DRM_MODE_DPMS_SUSPEND, "Suspend" }, 70f453ba04SDave Airlie { DRM_MODE_DPMS_OFF, "Off" } 71f453ba04SDave Airlie }; 72f453ba04SDave Airlie 73f453ba04SDave Airlie DRM_ENUM_NAME_FN(drm_get_dpms_name, drm_dpms_enum_list) 74f453ba04SDave Airlie 754dfd909fSThierry Reding static const struct drm_prop_enum_list drm_plane_type_enum_list[] = { 769922ab5aSRob Clark { DRM_PLANE_TYPE_OVERLAY, "Overlay" }, 779922ab5aSRob Clark { DRM_PLANE_TYPE_PRIMARY, "Primary" }, 789922ab5aSRob Clark { DRM_PLANE_TYPE_CURSOR, "Cursor" }, 799922ab5aSRob Clark }; 809922ab5aSRob Clark 81f453ba04SDave Airlie /* 82f453ba04SDave Airlie * Optional properties 83f453ba04SDave Airlie */ 844dfd909fSThierry Reding static const struct drm_prop_enum_list drm_scaling_mode_enum_list[] = { 8553bd8389SJesse Barnes { DRM_MODE_SCALE_NONE, "None" }, 8653bd8389SJesse Barnes { DRM_MODE_SCALE_FULLSCREEN, "Full" }, 8753bd8389SJesse Barnes { DRM_MODE_SCALE_CENTER, "Center" }, 8853bd8389SJesse Barnes { DRM_MODE_SCALE_ASPECT, "Full aspect" }, 89f453ba04SDave Airlie }; 90f453ba04SDave Airlie 91ff587e45SVandana Kannan static const struct drm_prop_enum_list drm_aspect_ratio_enum_list[] = { 92ff587e45SVandana Kannan { DRM_MODE_PICTURE_ASPECT_NONE, "Automatic" }, 93ff587e45SVandana Kannan { DRM_MODE_PICTURE_ASPECT_4_3, "4:3" }, 94ff587e45SVandana Kannan { DRM_MODE_PICTURE_ASPECT_16_9, "16:9" }, 95ff587e45SVandana Kannan }; 96ff587e45SVandana Kannan 97f453ba04SDave Airlie /* 98f453ba04SDave Airlie * Non-global properties, but "required" for certain connectors. 99f453ba04SDave Airlie */ 1004dfd909fSThierry Reding static const struct drm_prop_enum_list drm_dvi_i_select_enum_list[] = { 101f453ba04SDave Airlie { DRM_MODE_SUBCONNECTOR_Automatic, "Automatic" }, /* DVI-I and TV-out */ 102f453ba04SDave Airlie { DRM_MODE_SUBCONNECTOR_DVID, "DVI-D" }, /* DVI-I */ 103f453ba04SDave Airlie { DRM_MODE_SUBCONNECTOR_DVIA, "DVI-A" }, /* DVI-I */ 104f453ba04SDave Airlie }; 105f453ba04SDave Airlie 106f453ba04SDave Airlie DRM_ENUM_NAME_FN(drm_get_dvi_i_select_name, drm_dvi_i_select_enum_list) 107f453ba04SDave Airlie 1084dfd909fSThierry Reding static const struct drm_prop_enum_list drm_dvi_i_subconnector_enum_list[] = { 109f453ba04SDave Airlie { DRM_MODE_SUBCONNECTOR_Unknown, "Unknown" }, /* DVI-I and TV-out */ 110f453ba04SDave Airlie { DRM_MODE_SUBCONNECTOR_DVID, "DVI-D" }, /* DVI-I */ 111f453ba04SDave Airlie { DRM_MODE_SUBCONNECTOR_DVIA, "DVI-A" }, /* DVI-I */ 112f453ba04SDave Airlie }; 113f453ba04SDave Airlie 114f453ba04SDave Airlie DRM_ENUM_NAME_FN(drm_get_dvi_i_subconnector_name, 115f453ba04SDave Airlie drm_dvi_i_subconnector_enum_list) 116f453ba04SDave Airlie 1174dfd909fSThierry Reding static const struct drm_prop_enum_list drm_tv_select_enum_list[] = { 118f453ba04SDave Airlie { DRM_MODE_SUBCONNECTOR_Automatic, "Automatic" }, /* DVI-I and TV-out */ 119f453ba04SDave Airlie { DRM_MODE_SUBCONNECTOR_Composite, "Composite" }, /* TV-out */ 120f453ba04SDave Airlie { DRM_MODE_SUBCONNECTOR_SVIDEO, "SVIDEO" }, /* TV-out */ 121f453ba04SDave Airlie { DRM_MODE_SUBCONNECTOR_Component, "Component" }, /* TV-out */ 122aeaa1ad3SFrancisco Jerez { DRM_MODE_SUBCONNECTOR_SCART, "SCART" }, /* TV-out */ 123f453ba04SDave Airlie }; 124f453ba04SDave Airlie 125f453ba04SDave Airlie DRM_ENUM_NAME_FN(drm_get_tv_select_name, drm_tv_select_enum_list) 126f453ba04SDave Airlie 1274dfd909fSThierry Reding static const struct drm_prop_enum_list drm_tv_subconnector_enum_list[] = { 128f453ba04SDave Airlie { DRM_MODE_SUBCONNECTOR_Unknown, "Unknown" }, /* DVI-I and TV-out */ 129f453ba04SDave Airlie { DRM_MODE_SUBCONNECTOR_Composite, "Composite" }, /* TV-out */ 130f453ba04SDave Airlie { DRM_MODE_SUBCONNECTOR_SVIDEO, "SVIDEO" }, /* TV-out */ 131f453ba04SDave Airlie { DRM_MODE_SUBCONNECTOR_Component, "Component" }, /* TV-out */ 132aeaa1ad3SFrancisco Jerez { DRM_MODE_SUBCONNECTOR_SCART, "SCART" }, /* TV-out */ 133f453ba04SDave Airlie }; 134f453ba04SDave Airlie 135f453ba04SDave Airlie DRM_ENUM_NAME_FN(drm_get_tv_subconnector_name, 136f453ba04SDave Airlie drm_tv_subconnector_enum_list) 137f453ba04SDave Airlie 138d20d3174SVille Syrjälä static const struct drm_prop_enum_list drm_dirty_info_enum_list[] = { 139884840aaSJakob Bornecrantz { DRM_MODE_DIRTY_OFF, "Off" }, 140884840aaSJakob Bornecrantz { DRM_MODE_DIRTY_ON, "On" }, 141884840aaSJakob Bornecrantz { DRM_MODE_DIRTY_ANNOTATE, "Annotate" }, 142884840aaSJakob Bornecrantz }; 143884840aaSJakob Bornecrantz 144f453ba04SDave Airlie struct drm_conn_prop_enum_list { 145f453ba04SDave Airlie int type; 146d20d3174SVille Syrjälä const char *name; 147b21e3afeSIlia Mirkin struct ida ida; 148f453ba04SDave Airlie }; 149f453ba04SDave Airlie 150f453ba04SDave Airlie /* 151f453ba04SDave Airlie * Connector and encoder types. 152f453ba04SDave Airlie */ 1534dfd909fSThierry Reding static struct drm_conn_prop_enum_list drm_connector_enum_list[] = { 1544dfd909fSThierry Reding { DRM_MODE_CONNECTOR_Unknown, "Unknown" }, 155b21e3afeSIlia Mirkin { DRM_MODE_CONNECTOR_VGA, "VGA" }, 156b21e3afeSIlia Mirkin { DRM_MODE_CONNECTOR_DVII, "DVI-I" }, 157b21e3afeSIlia Mirkin { DRM_MODE_CONNECTOR_DVID, "DVI-D" }, 158b21e3afeSIlia Mirkin { DRM_MODE_CONNECTOR_DVIA, "DVI-A" }, 159b21e3afeSIlia Mirkin { DRM_MODE_CONNECTOR_Composite, "Composite" }, 160b21e3afeSIlia Mirkin { DRM_MODE_CONNECTOR_SVIDEO, "SVIDEO" }, 161b21e3afeSIlia Mirkin { DRM_MODE_CONNECTOR_LVDS, "LVDS" }, 162b21e3afeSIlia Mirkin { DRM_MODE_CONNECTOR_Component, "Component" }, 163b21e3afeSIlia Mirkin { DRM_MODE_CONNECTOR_9PinDIN, "DIN" }, 164b21e3afeSIlia Mirkin { DRM_MODE_CONNECTOR_DisplayPort, "DP" }, 165b21e3afeSIlia Mirkin { DRM_MODE_CONNECTOR_HDMIA, "HDMI-A" }, 166b21e3afeSIlia Mirkin { DRM_MODE_CONNECTOR_HDMIB, "HDMI-B" }, 167b21e3afeSIlia Mirkin { DRM_MODE_CONNECTOR_TV, "TV" }, 168b21e3afeSIlia Mirkin { DRM_MODE_CONNECTOR_eDP, "eDP" }, 169b21e3afeSIlia Mirkin { DRM_MODE_CONNECTOR_VIRTUAL, "Virtual" }, 170b8923273SShobhit Kumar { DRM_MODE_CONNECTOR_DSI, "DSI" }, 171f453ba04SDave Airlie }; 172f453ba04SDave Airlie 1734dfd909fSThierry Reding static const struct drm_prop_enum_list drm_encoder_enum_list[] = { 1744dfd909fSThierry Reding { DRM_MODE_ENCODER_NONE, "None" }, 175f453ba04SDave Airlie { DRM_MODE_ENCODER_DAC, "DAC" }, 176f453ba04SDave Airlie { DRM_MODE_ENCODER_TMDS, "TMDS" }, 177f453ba04SDave Airlie { DRM_MODE_ENCODER_LVDS, "LVDS" }, 178f453ba04SDave Airlie { DRM_MODE_ENCODER_TVDAC, "TV" }, 179a7331e5cSThomas Hellstrom { DRM_MODE_ENCODER_VIRTUAL, "Virtual" }, 180b8923273SShobhit Kumar { DRM_MODE_ENCODER_DSI, "DSI" }, 181182407a6SDave Airlie { DRM_MODE_ENCODER_DPMST, "DP MST" }, 182f453ba04SDave Airlie }; 183f453ba04SDave Airlie 1844dfd909fSThierry Reding static const struct drm_prop_enum_list drm_subpixel_enum_list[] = { 185ac1bb36cSJesse Barnes { SubPixelUnknown, "Unknown" }, 186ac1bb36cSJesse Barnes { SubPixelHorizontalRGB, "Horizontal RGB" }, 187ac1bb36cSJesse Barnes { SubPixelHorizontalBGR, "Horizontal BGR" }, 188ac1bb36cSJesse Barnes { SubPixelVerticalRGB, "Vertical RGB" }, 189ac1bb36cSJesse Barnes { SubPixelVerticalBGR, "Vertical BGR" }, 190ac1bb36cSJesse Barnes { SubPixelNone, "None" }, 191ac1bb36cSJesse Barnes }; 192ac1bb36cSJesse Barnes 193b21e3afeSIlia Mirkin void drm_connector_ida_init(void) 194b21e3afeSIlia Mirkin { 195b21e3afeSIlia Mirkin int i; 196b21e3afeSIlia Mirkin 197b21e3afeSIlia Mirkin for (i = 0; i < ARRAY_SIZE(drm_connector_enum_list); i++) 198b21e3afeSIlia Mirkin ida_init(&drm_connector_enum_list[i].ida); 199b21e3afeSIlia Mirkin } 200b21e3afeSIlia Mirkin 201b21e3afeSIlia Mirkin void drm_connector_ida_destroy(void) 202b21e3afeSIlia Mirkin { 203b21e3afeSIlia Mirkin int i; 204b21e3afeSIlia Mirkin 205b21e3afeSIlia Mirkin for (i = 0; i < ARRAY_SIZE(drm_connector_enum_list); i++) 206b21e3afeSIlia Mirkin ida_destroy(&drm_connector_enum_list[i].ida); 207b21e3afeSIlia Mirkin } 208b21e3afeSIlia Mirkin 209c8e32cc1SDaniel Vetter /** 210c8e32cc1SDaniel Vetter * drm_get_connector_status_name - return a string for connector status 211c8e32cc1SDaniel Vetter * @status: connector status to compute name of 212c8e32cc1SDaniel Vetter * 213c8e32cc1SDaniel Vetter * In contrast to the other drm_get_*_name functions this one here returns a 214c8e32cc1SDaniel Vetter * const pointer and hence is threadsafe. 215c8e32cc1SDaniel Vetter */ 216d20d3174SVille Syrjälä const char *drm_get_connector_status_name(enum drm_connector_status status) 217f453ba04SDave Airlie { 218f453ba04SDave Airlie if (status == connector_status_connected) 219f453ba04SDave Airlie return "connected"; 220f453ba04SDave Airlie else if (status == connector_status_disconnected) 221f453ba04SDave Airlie return "disconnected"; 222f453ba04SDave Airlie else 223f453ba04SDave Airlie return "unknown"; 224f453ba04SDave Airlie } 225ed7951dcSLespiau, Damien EXPORT_SYMBOL(drm_get_connector_status_name); 226f453ba04SDave Airlie 227ac1bb36cSJesse Barnes /** 228ac1bb36cSJesse Barnes * drm_get_subpixel_order_name - return a string for a given subpixel enum 229ac1bb36cSJesse Barnes * @order: enum of subpixel_order 230ac1bb36cSJesse Barnes * 231ac1bb36cSJesse Barnes * Note you could abuse this and return something out of bounds, but that 232ac1bb36cSJesse Barnes * would be a caller error. No unscrubbed user data should make it here. 233ac1bb36cSJesse Barnes */ 234ac1bb36cSJesse Barnes const char *drm_get_subpixel_order_name(enum subpixel_order order) 235ac1bb36cSJesse Barnes { 236ac1bb36cSJesse Barnes return drm_subpixel_enum_list[order].name; 237ac1bb36cSJesse Barnes } 238ac1bb36cSJesse Barnes EXPORT_SYMBOL(drm_get_subpixel_order_name); 239ac1bb36cSJesse Barnes 2406ba6d03eSVille Syrjälä static char printable_char(int c) 2416ba6d03eSVille Syrjälä { 2426ba6d03eSVille Syrjälä return isascii(c) && isprint(c) ? c : '?'; 2436ba6d03eSVille Syrjälä } 2446ba6d03eSVille Syrjälä 245c8e32cc1SDaniel Vetter /** 246c8e32cc1SDaniel Vetter * drm_get_format_name - return a string for drm fourcc format 247c8e32cc1SDaniel Vetter * @format: format to compute name of 248c8e32cc1SDaniel Vetter * 249c8e32cc1SDaniel Vetter * Note that the buffer used by this function is globally shared and owned by 250c8e32cc1SDaniel Vetter * the function itself. 251c8e32cc1SDaniel Vetter * 252c8e32cc1SDaniel Vetter * FIXME: This isn't really multithreading safe. 253c8e32cc1SDaniel Vetter */ 254d20d3174SVille Syrjälä const char *drm_get_format_name(uint32_t format) 2556ba6d03eSVille Syrjälä { 2566ba6d03eSVille Syrjälä static char buf[32]; 2576ba6d03eSVille Syrjälä 2586ba6d03eSVille Syrjälä snprintf(buf, sizeof(buf), 2596ba6d03eSVille Syrjälä "%c%c%c%c %s-endian (0x%08x)", 2606ba6d03eSVille Syrjälä printable_char(format & 0xff), 2616ba6d03eSVille Syrjälä printable_char((format >> 8) & 0xff), 2626ba6d03eSVille Syrjälä printable_char((format >> 16) & 0xff), 2636ba6d03eSVille Syrjälä printable_char((format >> 24) & 0x7f), 2646ba6d03eSVille Syrjälä format & DRM_FORMAT_BIG_ENDIAN ? "big" : "little", 2656ba6d03eSVille Syrjälä format); 2666ba6d03eSVille Syrjälä 2676ba6d03eSVille Syrjälä return buf; 2686ba6d03eSVille Syrjälä } 2696ba6d03eSVille Syrjälä EXPORT_SYMBOL(drm_get_format_name); 2706ba6d03eSVille Syrjälä 2712ee39452SDave Airlie /* 2722ee39452SDave Airlie * Internal function to assign a slot in the object idr and optionally 2732ee39452SDave Airlie * register the object into the idr. 2742ee39452SDave Airlie */ 2752ee39452SDave Airlie static int drm_mode_object_get_reg(struct drm_device *dev, 2762ee39452SDave Airlie struct drm_mode_object *obj, 2772ee39452SDave Airlie uint32_t obj_type, 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: 3093c67d839SLukas Wunner * Zero on success, error code on failure. 310f453ba04SDave Airlie */ 3118bd441b2SDaniel Vetter int drm_mode_object_get(struct drm_device *dev, 312f453ba04SDave Airlie struct drm_mode_object *obj, uint32_t obj_type) 313f453ba04SDave Airlie { 3142ee39452SDave Airlie return drm_mode_object_get_reg(dev, obj, obj_type, true); 3154b096ac1SDaniel Vetter } 3164b096ac1SDaniel Vetter 3172ee39452SDave Airlie static void drm_mode_object_register(struct drm_device *dev, 3182ee39452SDave Airlie struct drm_mode_object *obj) 3192ee39452SDave Airlie { 3202ee39452SDave Airlie mutex_lock(&dev->mode_config.idr_mutex); 3212ee39452SDave Airlie idr_replace(&dev->mode_config.crtc_idr, obj, obj->id); 3222ee39452SDave Airlie mutex_unlock(&dev->mode_config.idr_mutex); 323f453ba04SDave Airlie } 324f453ba04SDave Airlie 325f453ba04SDave Airlie /** 326065a50edSDaniel Vetter * drm_mode_object_put - free a modeset identifer 327f453ba04SDave Airlie * @dev: DRM device 328065a50edSDaniel Vetter * @object: object to free 329f453ba04SDave Airlie * 330c8e32cc1SDaniel Vetter * Free @id from @dev's unique identifier pool. Note that despite the _get 331c8e32cc1SDaniel Vetter * postfix modeset identifiers are _not_ reference counted. Hence don't use this 332c8e32cc1SDaniel Vetter * for reference counted modeset objects like framebuffers. 333f453ba04SDave Airlie */ 3348bd441b2SDaniel Vetter void drm_mode_object_put(struct drm_device *dev, 335f453ba04SDave Airlie struct drm_mode_object *object) 336f453ba04SDave Airlie { 337ad2563c2SJesse Barnes mutex_lock(&dev->mode_config.idr_mutex); 338f453ba04SDave Airlie idr_remove(&dev->mode_config.crtc_idr, object->id); 339ad2563c2SJesse Barnes mutex_unlock(&dev->mode_config.idr_mutex); 340f453ba04SDave Airlie } 341f453ba04SDave Airlie 34298f75de4SRob Clark static struct drm_mode_object *_object_find(struct drm_device *dev, 34398f75de4SRob Clark uint32_t id, uint32_t type) 34498f75de4SRob Clark { 34598f75de4SRob Clark struct drm_mode_object *obj = NULL; 34698f75de4SRob Clark 34798f75de4SRob Clark mutex_lock(&dev->mode_config.idr_mutex); 34898f75de4SRob Clark obj = idr_find(&dev->mode_config.crtc_idr, id); 349168c02ecSDaniel Vetter if (obj && type != DRM_MODE_OBJECT_ANY && obj->type != type) 350168c02ecSDaniel Vetter obj = NULL; 351168c02ecSDaniel Vetter if (obj && obj->id != id) 352168c02ecSDaniel Vetter obj = NULL; 353168c02ecSDaniel Vetter /* don't leak out unref'd fb's */ 3546bcacf51SDaniel Stone if (obj && 3556bcacf51SDaniel Stone (obj->type == DRM_MODE_OBJECT_FB || 3566bcacf51SDaniel Stone obj->type == DRM_MODE_OBJECT_BLOB)) 35798f75de4SRob Clark obj = NULL; 35898f75de4SRob Clark mutex_unlock(&dev->mode_config.idr_mutex); 35998f75de4SRob Clark 36098f75de4SRob Clark return obj; 36198f75de4SRob Clark } 36298f75de4SRob Clark 363786b99edSDaniel Vetter /** 364786b99edSDaniel Vetter * drm_mode_object_find - look up a drm object with static lifetime 365786b99edSDaniel Vetter * @dev: drm device 366786b99edSDaniel Vetter * @id: id of the mode object 367786b99edSDaniel Vetter * @type: type of the mode object 368786b99edSDaniel Vetter * 369786b99edSDaniel Vetter * Note that framebuffers cannot be looked up with this functions - since those 37098f75de4SRob Clark * are reference counted, they need special treatment. Even with 37198f75de4SRob Clark * DRM_MODE_OBJECT_ANY (although that will simply return NULL 37298f75de4SRob Clark * rather than WARN_ON()). 373786b99edSDaniel Vetter */ 3747a9c9060SDaniel Vetter struct drm_mode_object *drm_mode_object_find(struct drm_device *dev, 3757a9c9060SDaniel Vetter uint32_t id, uint32_t type) 376f453ba04SDave Airlie { 377ad2563c2SJesse Barnes struct drm_mode_object *obj = NULL; 378f453ba04SDave Airlie 379786b99edSDaniel Vetter /* Framebuffers are reference counted and need their own lookup 380786b99edSDaniel Vetter * function.*/ 3816bcacf51SDaniel Stone WARN_ON(type == DRM_MODE_OBJECT_FB || type == DRM_MODE_OBJECT_BLOB); 38298f75de4SRob Clark obj = _object_find(dev, id, type); 383f453ba04SDave Airlie return obj; 384f453ba04SDave Airlie } 385f453ba04SDave Airlie EXPORT_SYMBOL(drm_mode_object_find); 386f453ba04SDave Airlie 387f453ba04SDave Airlie /** 388f453ba04SDave Airlie * drm_framebuffer_init - initialize a framebuffer 389f453ba04SDave Airlie * @dev: DRM device 390065a50edSDaniel Vetter * @fb: framebuffer to be initialized 391065a50edSDaniel Vetter * @funcs: ... with these functions 392f453ba04SDave Airlie * 393f453ba04SDave Airlie * Allocates an ID for the framebuffer's parent mode object, sets its mode 394f453ba04SDave Airlie * functions & device file and adds it to the master fd list. 395f453ba04SDave Airlie * 3964b096ac1SDaniel Vetter * IMPORTANT: 3974b096ac1SDaniel Vetter * This functions publishes the fb and makes it available for concurrent access 3984b096ac1SDaniel Vetter * by other users. Which means by this point the fb _must_ be fully set up - 3994b096ac1SDaniel Vetter * since all the fb attributes are invariant over its lifetime, no further 4004b096ac1SDaniel Vetter * locking but only correct reference counting is required. 4014b096ac1SDaniel Vetter * 402c8e32cc1SDaniel Vetter * Returns: 403af901ca1SAndré Goddard Rosa * Zero on success, error code on failure. 404f453ba04SDave Airlie */ 405f453ba04SDave Airlie int drm_framebuffer_init(struct drm_device *dev, struct drm_framebuffer *fb, 406f453ba04SDave Airlie const struct drm_framebuffer_funcs *funcs) 407f453ba04SDave Airlie { 408f453ba04SDave Airlie int ret; 409f453ba04SDave Airlie 4104b096ac1SDaniel Vetter mutex_lock(&dev->mode_config.fb_lock); 411f7eff60eSRob Clark kref_init(&fb->refcount); 4124b096ac1SDaniel Vetter INIT_LIST_HEAD(&fb->filp_head); 4134b096ac1SDaniel Vetter fb->dev = dev; 4144b096ac1SDaniel Vetter fb->funcs = funcs; 415f7eff60eSRob Clark 416f453ba04SDave Airlie ret = drm_mode_object_get(dev, &fb->base, DRM_MODE_OBJECT_FB); 4176bfc56aaSVille Syrjälä if (ret) 4184b096ac1SDaniel Vetter goto out; 419f453ba04SDave Airlie 420f453ba04SDave Airlie dev->mode_config.num_fb++; 421f453ba04SDave Airlie list_add(&fb->head, &dev->mode_config.fb_list); 4224b096ac1SDaniel Vetter out: 4234b096ac1SDaniel Vetter mutex_unlock(&dev->mode_config.fb_lock); 424f453ba04SDave Airlie 4253c67d839SLukas Wunner return ret; 426f453ba04SDave Airlie } 427f453ba04SDave Airlie EXPORT_SYMBOL(drm_framebuffer_init); 428f453ba04SDave Airlie 42983f45fc3SDaniel Vetter /* dev->mode_config.fb_lock must be held! */ 43083f45fc3SDaniel Vetter static void __drm_framebuffer_unregister(struct drm_device *dev, 43183f45fc3SDaniel Vetter struct drm_framebuffer *fb) 43283f45fc3SDaniel Vetter { 43332709793SLiu Ying drm_mode_object_put(dev, &fb->base); 43483f45fc3SDaniel Vetter 43583f45fc3SDaniel Vetter fb->base.id = 0; 43683f45fc3SDaniel Vetter } 43783f45fc3SDaniel Vetter 438f7eff60eSRob Clark static void drm_framebuffer_free(struct kref *kref) 439f7eff60eSRob Clark { 440f7eff60eSRob Clark struct drm_framebuffer *fb = 441f7eff60eSRob Clark container_of(kref, struct drm_framebuffer, refcount); 44283f45fc3SDaniel Vetter struct drm_device *dev = fb->dev; 44383f45fc3SDaniel Vetter 44483f45fc3SDaniel Vetter /* 44583f45fc3SDaniel Vetter * The lookup idr holds a weak reference, which has not necessarily been 44683f45fc3SDaniel Vetter * removed at this point. Check for that. 44783f45fc3SDaniel Vetter */ 44883f45fc3SDaniel Vetter mutex_lock(&dev->mode_config.fb_lock); 44983f45fc3SDaniel Vetter if (fb->base.id) { 45083f45fc3SDaniel Vetter /* Mark fb as reaped and drop idr ref. */ 45183f45fc3SDaniel Vetter __drm_framebuffer_unregister(dev, fb); 45283f45fc3SDaniel Vetter } 45383f45fc3SDaniel Vetter mutex_unlock(&dev->mode_config.fb_lock); 45483f45fc3SDaniel Vetter 455f7eff60eSRob Clark fb->funcs->destroy(fb); 456f7eff60eSRob Clark } 457f7eff60eSRob Clark 4582b677e8cSDaniel Vetter static struct drm_framebuffer *__drm_framebuffer_lookup(struct drm_device *dev, 4592b677e8cSDaniel Vetter uint32_t id) 4602b677e8cSDaniel Vetter { 4612b677e8cSDaniel Vetter struct drm_mode_object *obj = NULL; 4622b677e8cSDaniel Vetter struct drm_framebuffer *fb; 4632b677e8cSDaniel Vetter 4642b677e8cSDaniel Vetter mutex_lock(&dev->mode_config.idr_mutex); 4652b677e8cSDaniel Vetter obj = idr_find(&dev->mode_config.crtc_idr, id); 4662b677e8cSDaniel Vetter if (!obj || (obj->type != DRM_MODE_OBJECT_FB) || (obj->id != id)) 4672b677e8cSDaniel Vetter fb = NULL; 4682b677e8cSDaniel Vetter else 4692b677e8cSDaniel Vetter fb = obj_to_fb(obj); 4702b677e8cSDaniel Vetter mutex_unlock(&dev->mode_config.idr_mutex); 4712b677e8cSDaniel Vetter 4722b677e8cSDaniel Vetter return fb; 4732b677e8cSDaniel Vetter } 4742b677e8cSDaniel Vetter 475f7eff60eSRob Clark /** 476786b99edSDaniel Vetter * drm_framebuffer_lookup - look up a drm framebuffer and grab a reference 477786b99edSDaniel Vetter * @dev: drm device 478786b99edSDaniel Vetter * @id: id of the fb object 479786b99edSDaniel Vetter * 480786b99edSDaniel Vetter * If successful, this grabs an additional reference to the framebuffer - 481786b99edSDaniel Vetter * callers need to make sure to eventually unreference the returned framebuffer 482c8e32cc1SDaniel Vetter * again, using @drm_framebuffer_unreference. 483786b99edSDaniel Vetter */ 484786b99edSDaniel Vetter struct drm_framebuffer *drm_framebuffer_lookup(struct drm_device *dev, 485786b99edSDaniel Vetter uint32_t id) 486786b99edSDaniel Vetter { 487786b99edSDaniel Vetter struct drm_framebuffer *fb; 488786b99edSDaniel Vetter 489786b99edSDaniel Vetter mutex_lock(&dev->mode_config.fb_lock); 4902b677e8cSDaniel Vetter fb = __drm_framebuffer_lookup(dev, id); 49183f45fc3SDaniel Vetter if (fb) { 49283f45fc3SDaniel Vetter if (!kref_get_unless_zero(&fb->refcount)) 49383f45fc3SDaniel Vetter fb = NULL; 49483f45fc3SDaniel Vetter } 495786b99edSDaniel Vetter mutex_unlock(&dev->mode_config.fb_lock); 496786b99edSDaniel Vetter 497786b99edSDaniel Vetter return fb; 498786b99edSDaniel Vetter } 499786b99edSDaniel Vetter EXPORT_SYMBOL(drm_framebuffer_lookup); 500786b99edSDaniel Vetter 501786b99edSDaniel Vetter /** 502f7eff60eSRob Clark * drm_framebuffer_unreference - unref a framebuffer 503065a50edSDaniel Vetter * @fb: framebuffer to unref 504065a50edSDaniel Vetter * 505065a50edSDaniel Vetter * This functions decrements the fb's refcount and frees it if it drops to zero. 506f7eff60eSRob Clark */ 507f7eff60eSRob Clark void drm_framebuffer_unreference(struct drm_framebuffer *fb) 508f7eff60eSRob Clark { 5098291272aSRob Clark DRM_DEBUG("%p: FB ID: %d (%d)\n", fb, fb->base.id, atomic_read(&fb->refcount.refcount)); 510f7eff60eSRob Clark kref_put(&fb->refcount, drm_framebuffer_free); 511f7eff60eSRob Clark } 512f7eff60eSRob Clark EXPORT_SYMBOL(drm_framebuffer_unreference); 513f7eff60eSRob Clark 514f7eff60eSRob Clark /** 515f7eff60eSRob Clark * drm_framebuffer_reference - incr the fb refcnt 516065a50edSDaniel Vetter * @fb: framebuffer 517c8e32cc1SDaniel Vetter * 518c8e32cc1SDaniel Vetter * This functions increments the fb's refcount. 519f7eff60eSRob Clark */ 520f7eff60eSRob Clark void drm_framebuffer_reference(struct drm_framebuffer *fb) 521f7eff60eSRob Clark { 5228291272aSRob Clark DRM_DEBUG("%p: FB ID: %d (%d)\n", fb, fb->base.id, atomic_read(&fb->refcount.refcount)); 523f7eff60eSRob Clark kref_get(&fb->refcount); 524f7eff60eSRob Clark } 525f7eff60eSRob Clark EXPORT_SYMBOL(drm_framebuffer_reference); 526f7eff60eSRob Clark 527f453ba04SDave Airlie /** 52836206361SDaniel Vetter * drm_framebuffer_unregister_private - unregister a private fb from the lookup idr 52936206361SDaniel Vetter * @fb: fb to unregister 53036206361SDaniel Vetter * 53136206361SDaniel Vetter * Drivers need to call this when cleaning up driver-private framebuffers, e.g. 53236206361SDaniel Vetter * those used for fbdev. Note that the caller must hold a reference of it's own, 53336206361SDaniel Vetter * i.e. the object may not be destroyed through this call (since it'll lead to a 53436206361SDaniel Vetter * locking inversion). 53536206361SDaniel Vetter */ 53636206361SDaniel Vetter void drm_framebuffer_unregister_private(struct drm_framebuffer *fb) 53736206361SDaniel Vetter { 538a39a357cSDaniel Vetter struct drm_device *dev; 539a39a357cSDaniel Vetter 540a39a357cSDaniel Vetter if (!fb) 541a39a357cSDaniel Vetter return; 542a39a357cSDaniel Vetter 543a39a357cSDaniel Vetter dev = fb->dev; 5442b677e8cSDaniel Vetter 5452b677e8cSDaniel Vetter mutex_lock(&dev->mode_config.fb_lock); 5462b677e8cSDaniel Vetter /* Mark fb as reaped and drop idr ref. */ 5472b677e8cSDaniel Vetter __drm_framebuffer_unregister(dev, fb); 5482b677e8cSDaniel Vetter mutex_unlock(&dev->mode_config.fb_lock); 54936206361SDaniel Vetter } 55036206361SDaniel Vetter EXPORT_SYMBOL(drm_framebuffer_unregister_private); 55136206361SDaniel Vetter 55236206361SDaniel Vetter /** 553f453ba04SDave Airlie * drm_framebuffer_cleanup - remove a framebuffer object 554f453ba04SDave Airlie * @fb: framebuffer to remove 555f453ba04SDave Airlie * 556c8e32cc1SDaniel Vetter * Cleanup framebuffer. This function is intended to be used from the drivers 557c8e32cc1SDaniel Vetter * ->destroy callback. It can also be used to clean up driver private 558c8e32cc1SDaniel Vetter * framebuffers embedded into a larger structure. 55936206361SDaniel Vetter * 56036206361SDaniel Vetter * Note that this function does not remove the fb from active usuage - if it is 56136206361SDaniel Vetter * still used anywhere, hilarity can ensue since userspace could call getfb on 56236206361SDaniel Vetter * the id and get back -EINVAL. Obviously no concern at driver unload time. 56336206361SDaniel Vetter * 56436206361SDaniel Vetter * Also, the framebuffer will not be removed from the lookup idr - for 56536206361SDaniel Vetter * user-created framebuffers this will happen in in the rmfb ioctl. For 56636206361SDaniel Vetter * driver-private objects (e.g. for fbdev) drivers need to explicitly call 56736206361SDaniel Vetter * drm_framebuffer_unregister_private. 568f453ba04SDave Airlie */ 569f453ba04SDave Airlie void drm_framebuffer_cleanup(struct drm_framebuffer *fb) 570f453ba04SDave Airlie { 571f453ba04SDave Airlie struct drm_device *dev = fb->dev; 5728faf6b18SDaniel Vetter 5734b096ac1SDaniel Vetter mutex_lock(&dev->mode_config.fb_lock); 574f7eff60eSRob Clark list_del(&fb->head); 575f7eff60eSRob Clark dev->mode_config.num_fb--; 5764b096ac1SDaniel Vetter mutex_unlock(&dev->mode_config.fb_lock); 577f7eff60eSRob Clark } 578f7eff60eSRob Clark EXPORT_SYMBOL(drm_framebuffer_cleanup); 579f7eff60eSRob Clark 580f7eff60eSRob Clark /** 581f7eff60eSRob Clark * drm_framebuffer_remove - remove and unreference a framebuffer object 582f7eff60eSRob Clark * @fb: framebuffer to remove 583f7eff60eSRob Clark * 584f7eff60eSRob Clark * Scans all the CRTCs and planes in @dev's mode_config. If they're 58536206361SDaniel Vetter * using @fb, removes it, setting it to NULL. Then drops the reference to the 586b62584e3SDaniel Vetter * passed-in framebuffer. Might take the modeset locks. 587b62584e3SDaniel Vetter * 588b62584e3SDaniel Vetter * Note that this function optimizes the cleanup away if the caller holds the 589b62584e3SDaniel Vetter * last reference to the framebuffer. It is also guaranteed to not take the 590b62584e3SDaniel Vetter * modeset locks in this case. 591f7eff60eSRob Clark */ 592f7eff60eSRob Clark void drm_framebuffer_remove(struct drm_framebuffer *fb) 593f7eff60eSRob Clark { 594a39a357cSDaniel Vetter struct drm_device *dev; 595f453ba04SDave Airlie struct drm_crtc *crtc; 5968cf5c917SJesse Barnes struct drm_plane *plane; 5975ef5f72fSDave Airlie struct drm_mode_set set; 5985ef5f72fSDave Airlie int ret; 599f453ba04SDave Airlie 600a39a357cSDaniel Vetter if (!fb) 601a39a357cSDaniel Vetter return; 602a39a357cSDaniel Vetter 603a39a357cSDaniel Vetter dev = fb->dev; 604a39a357cSDaniel Vetter 6054b096ac1SDaniel Vetter WARN_ON(!list_empty(&fb->filp_head)); 6068faf6b18SDaniel Vetter 607b62584e3SDaniel Vetter /* 608b62584e3SDaniel Vetter * drm ABI mandates that we remove any deleted framebuffers from active 609b62584e3SDaniel Vetter * useage. But since most sane clients only remove framebuffers they no 610b62584e3SDaniel Vetter * longer need, try to optimize this away. 611b62584e3SDaniel Vetter * 612b62584e3SDaniel Vetter * Since we're holding a reference ourselves, observing a refcount of 1 613b62584e3SDaniel Vetter * means that we're the last holder and can skip it. Also, the refcount 614b62584e3SDaniel Vetter * can never increase from 1 again, so we don't need any barriers or 615b62584e3SDaniel Vetter * locks. 616b62584e3SDaniel Vetter * 617b62584e3SDaniel Vetter * Note that userspace could try to race with use and instate a new 618b62584e3SDaniel Vetter * usage _after_ we've cleared all current ones. End result will be an 619b62584e3SDaniel Vetter * in-use fb with fb-id == 0. Userspace is allowed to shoot its own foot 620b62584e3SDaniel Vetter * in this manner. 621b62584e3SDaniel Vetter */ 622b62584e3SDaniel Vetter if (atomic_read(&fb->refcount.refcount) > 1) { 623b62584e3SDaniel Vetter drm_modeset_lock_all(dev); 624f453ba04SDave Airlie /* remove from any CRTC */ 6256295d607SDaniel Vetter drm_for_each_crtc(crtc, dev) { 626f4510a27SMatt Roper if (crtc->primary->fb == fb) { 6275ef5f72fSDave Airlie /* should turn off the crtc */ 6285ef5f72fSDave Airlie memset(&set, 0, sizeof(struct drm_mode_set)); 6295ef5f72fSDave Airlie set.crtc = crtc; 6305ef5f72fSDave Airlie set.fb = NULL; 6312d13b679SDaniel Vetter ret = drm_mode_set_config_internal(&set); 6325ef5f72fSDave Airlie if (ret) 6335ef5f72fSDave Airlie DRM_ERROR("failed to reset crtc %p when fb was deleted\n", crtc); 6345ef5f72fSDave Airlie } 635f453ba04SDave Airlie } 636f453ba04SDave Airlie 6376295d607SDaniel Vetter drm_for_each_plane(plane, dev) { 6389125e618SVille Syrjälä if (plane->fb == fb) 6399125e618SVille Syrjälä drm_plane_force_disable(plane); 6408cf5c917SJesse Barnes } 641b62584e3SDaniel Vetter drm_modeset_unlock_all(dev); 642b62584e3SDaniel Vetter } 6438cf5c917SJesse Barnes 644f7eff60eSRob Clark drm_framebuffer_unreference(fb); 645f453ba04SDave Airlie } 646f7eff60eSRob Clark EXPORT_SYMBOL(drm_framebuffer_remove); 647f453ba04SDave Airlie 64851fd371bSRob Clark DEFINE_WW_CLASS(crtc_ww_class); 64951fd371bSRob Clark 650fa3ab4c2SVille Syrjälä static unsigned int drm_num_crtcs(struct drm_device *dev) 651fa3ab4c2SVille Syrjälä { 652fa3ab4c2SVille Syrjälä unsigned int num = 0; 653fa3ab4c2SVille Syrjälä struct drm_crtc *tmp; 654fa3ab4c2SVille Syrjälä 655fa3ab4c2SVille Syrjälä drm_for_each_crtc(tmp, dev) { 656fa3ab4c2SVille Syrjälä num++; 657fa3ab4c2SVille Syrjälä } 658fa3ab4c2SVille Syrjälä 659fa3ab4c2SVille Syrjälä return num; 660fa3ab4c2SVille Syrjälä } 661fa3ab4c2SVille Syrjälä 662f453ba04SDave Airlie /** 663e13161afSMatt Roper * drm_crtc_init_with_planes - Initialise a new CRTC object with 664e13161afSMatt Roper * specified primary and cursor planes. 665f453ba04SDave Airlie * @dev: DRM device 666f453ba04SDave Airlie * @crtc: CRTC object to init 667e13161afSMatt Roper * @primary: Primary plane for CRTC 668e13161afSMatt Roper * @cursor: Cursor plane for CRTC 669f453ba04SDave Airlie * @funcs: callbacks for the new CRTC 670f9882876SVille Syrjälä * @name: printf style format string for the CRTC name, or NULL for default name 671f453ba04SDave Airlie * 672ad6f5c34SVille Syrjälä * Inits a new object created as base part of a driver crtc object. 6736bfc56aaSVille Syrjälä * 674c8e32cc1SDaniel Vetter * Returns: 6756bfc56aaSVille Syrjälä * Zero on success, error code on failure. 676f453ba04SDave Airlie */ 677e13161afSMatt Roper int drm_crtc_init_with_planes(struct drm_device *dev, struct drm_crtc *crtc, 678e13161afSMatt Roper struct drm_plane *primary, 679fc1d3e44SMatt Roper struct drm_plane *cursor, 680f9882876SVille Syrjälä const struct drm_crtc_funcs *funcs, 681f9882876SVille Syrjälä const char *name, ...) 682f453ba04SDave Airlie { 68351fd371bSRob Clark struct drm_mode_config *config = &dev->mode_config; 6846bfc56aaSVille Syrjälä int ret; 6856bfc56aaSVille Syrjälä 686522cf91fSBenjamin Gaignard WARN_ON(primary && primary->type != DRM_PLANE_TYPE_PRIMARY); 687522cf91fSBenjamin Gaignard WARN_ON(cursor && cursor->type != DRM_PLANE_TYPE_CURSOR); 688522cf91fSBenjamin Gaignard 689f453ba04SDave Airlie crtc->dev = dev; 690f453ba04SDave Airlie crtc->funcs = funcs; 691f453ba04SDave Airlie 69251fd371bSRob Clark drm_modeset_lock_init(&crtc->mutex); 6936bfc56aaSVille Syrjälä ret = drm_mode_object_get(dev, &crtc->base, DRM_MODE_OBJECT_CRTC); 6946bfc56aaSVille Syrjälä if (ret) 695baf698b0SDaniel Vetter return ret; 696f453ba04SDave Airlie 697fa3ab4c2SVille Syrjälä if (name) { 698fa3ab4c2SVille Syrjälä va_list ap; 699fa3ab4c2SVille Syrjälä 700fa3ab4c2SVille Syrjälä va_start(ap, name); 701fa3ab4c2SVille Syrjälä crtc->name = kvasprintf(GFP_KERNEL, name, ap); 702fa3ab4c2SVille Syrjälä va_end(ap); 703fa3ab4c2SVille Syrjälä } else { 704fa3ab4c2SVille Syrjälä crtc->name = kasprintf(GFP_KERNEL, "crtc-%d", 705fa3ab4c2SVille Syrjälä drm_num_crtcs(dev)); 706fa3ab4c2SVille Syrjälä } 707fa3ab4c2SVille Syrjälä if (!crtc->name) { 708fa3ab4c2SVille Syrjälä drm_mode_object_put(dev, &crtc->base); 709fa3ab4c2SVille Syrjälä return -ENOMEM; 710fa3ab4c2SVille Syrjälä } 711fa3ab4c2SVille Syrjälä 712bffd9de0SPaulo Zanoni crtc->base.properties = &crtc->properties; 713bffd9de0SPaulo Zanoni 71451fd371bSRob Clark list_add_tail(&crtc->head, &config->crtc_list); 71551fd371bSRob Clark config->num_crtc++; 7166bfc56aaSVille Syrjälä 717e13161afSMatt Roper crtc->primary = primary; 718fc1d3e44SMatt Roper crtc->cursor = cursor; 719e13161afSMatt Roper if (primary) 720e13161afSMatt Roper primary->possible_crtcs = 1 << drm_crtc_index(crtc); 721fc1d3e44SMatt Roper if (cursor) 722fc1d3e44SMatt Roper cursor->possible_crtcs = 1 << drm_crtc_index(crtc); 723e13161afSMatt Roper 724eab3bbefSDaniel Vetter if (drm_core_check_feature(dev, DRIVER_ATOMIC)) { 725eab3bbefSDaniel Vetter drm_object_attach_property(&crtc->base, config->prop_active, 0); 726955f3c33SDaniel Stone drm_object_attach_property(&crtc->base, config->prop_mode_id, 0); 727eab3bbefSDaniel Vetter } 728eab3bbefSDaniel Vetter 729baf698b0SDaniel Vetter return 0; 730f453ba04SDave Airlie } 731e13161afSMatt Roper EXPORT_SYMBOL(drm_crtc_init_with_planes); 732f453ba04SDave Airlie 733f453ba04SDave Airlie /** 734ad6f5c34SVille Syrjälä * drm_crtc_cleanup - Clean up the core crtc usage 735f453ba04SDave Airlie * @crtc: CRTC to cleanup 736f453ba04SDave Airlie * 737ad6f5c34SVille Syrjälä * This function cleans up @crtc and removes it from the DRM mode setting 738ad6f5c34SVille Syrjälä * core. Note that the function does *not* free the crtc structure itself, 739ad6f5c34SVille Syrjälä * this is the responsibility of the caller. 740f453ba04SDave Airlie */ 741f453ba04SDave Airlie void drm_crtc_cleanup(struct drm_crtc *crtc) 742f453ba04SDave Airlie { 743f453ba04SDave Airlie struct drm_device *dev = crtc->dev; 744f453ba04SDave Airlie 745f453ba04SDave Airlie kfree(crtc->gamma_store); 746f453ba04SDave Airlie crtc->gamma_store = NULL; 747f453ba04SDave Airlie 74851fd371bSRob Clark drm_modeset_lock_fini(&crtc->mutex); 74951fd371bSRob Clark 750f453ba04SDave Airlie drm_mode_object_put(dev, &crtc->base); 751f453ba04SDave Airlie list_del(&crtc->head); 752f453ba04SDave Airlie dev->mode_config.num_crtc--; 7533009c037SThierry Reding 7543009c037SThierry Reding WARN_ON(crtc->state && !crtc->funcs->atomic_destroy_state); 7553009c037SThierry Reding if (crtc->state && crtc->funcs->atomic_destroy_state) 7563009c037SThierry Reding crtc->funcs->atomic_destroy_state(crtc, crtc->state); 757a18c0af1SThierry Reding 758fa3ab4c2SVille Syrjälä kfree(crtc->name); 759fa3ab4c2SVille Syrjälä 760a18c0af1SThierry Reding memset(crtc, 0, sizeof(*crtc)); 761f453ba04SDave Airlie } 762f453ba04SDave Airlie EXPORT_SYMBOL(drm_crtc_cleanup); 763f453ba04SDave Airlie 764f453ba04SDave Airlie /** 765db5f7a6eSRussell King * drm_crtc_index - find the index of a registered CRTC 766db5f7a6eSRussell King * @crtc: CRTC to find index for 767db5f7a6eSRussell King * 768db5f7a6eSRussell King * Given a registered CRTC, return the index of that CRTC within a DRM 769db5f7a6eSRussell King * device's list of CRTCs. 770db5f7a6eSRussell King */ 771db5f7a6eSRussell King unsigned int drm_crtc_index(struct drm_crtc *crtc) 772db5f7a6eSRussell King { 773db5f7a6eSRussell King unsigned int index = 0; 774db5f7a6eSRussell King struct drm_crtc *tmp; 775db5f7a6eSRussell King 776e4f62546SDaniel Vetter drm_for_each_crtc(tmp, crtc->dev) { 777db5f7a6eSRussell King if (tmp == crtc) 778db5f7a6eSRussell King return index; 779db5f7a6eSRussell King 780db5f7a6eSRussell King index++; 781db5f7a6eSRussell King } 782db5f7a6eSRussell King 783db5f7a6eSRussell King BUG(); 784db5f7a6eSRussell King } 785db5f7a6eSRussell King EXPORT_SYMBOL(drm_crtc_index); 786db5f7a6eSRussell King 78786f422d5SLespiau, Damien /* 788f453ba04SDave Airlie * drm_mode_remove - remove and free a mode 789f453ba04SDave Airlie * @connector: connector list to modify 790f453ba04SDave Airlie * @mode: mode to remove 791f453ba04SDave Airlie * 792f453ba04SDave Airlie * Remove @mode from @connector's mode list, then free it. 793f453ba04SDave Airlie */ 79486f422d5SLespiau, Damien static void drm_mode_remove(struct drm_connector *connector, 795f453ba04SDave Airlie struct drm_display_mode *mode) 796f453ba04SDave Airlie { 797f453ba04SDave Airlie list_del(&mode->head); 798554f1d78SSascha Hauer drm_mode_destroy(connector->dev, mode); 799f453ba04SDave Airlie } 800f453ba04SDave Airlie 801f453ba04SDave Airlie /** 802b5571e9dSBoris Brezillon * drm_display_info_set_bus_formats - set the supported bus formats 803b5571e9dSBoris Brezillon * @info: display info to store bus formats in 804e37bfa1aSBoris Brezillon * @formats: array containing the supported bus formats 805e37bfa1aSBoris Brezillon * @num_formats: the number of entries in the fmts array 806b5571e9dSBoris Brezillon * 807b5571e9dSBoris Brezillon * Store the supported bus formats in display info structure. 808b5571e9dSBoris Brezillon * See MEDIA_BUS_FMT_* definitions in include/uapi/linux/media-bus-format.h for 809b5571e9dSBoris Brezillon * a full list of available formats. 810b5571e9dSBoris Brezillon */ 811b5571e9dSBoris Brezillon int drm_display_info_set_bus_formats(struct drm_display_info *info, 812b5571e9dSBoris Brezillon const u32 *formats, 813b5571e9dSBoris Brezillon unsigned int num_formats) 814b5571e9dSBoris Brezillon { 815b5571e9dSBoris Brezillon u32 *fmts = NULL; 816b5571e9dSBoris Brezillon 817b5571e9dSBoris Brezillon if (!formats && num_formats) 818b5571e9dSBoris Brezillon return -EINVAL; 819b5571e9dSBoris Brezillon 820b5571e9dSBoris Brezillon if (formats && num_formats) { 821b5571e9dSBoris Brezillon fmts = kmemdup(formats, sizeof(*formats) * num_formats, 822b5571e9dSBoris Brezillon GFP_KERNEL); 823944579c5SDan Carpenter if (!fmts) 824b5571e9dSBoris Brezillon return -ENOMEM; 825b5571e9dSBoris Brezillon } 826b5571e9dSBoris Brezillon 827b5571e9dSBoris Brezillon kfree(info->bus_formats); 828b5571e9dSBoris Brezillon info->bus_formats = fmts; 829b5571e9dSBoris Brezillon info->num_bus_formats = num_formats; 830b5571e9dSBoris Brezillon 831b5571e9dSBoris Brezillon return 0; 832b5571e9dSBoris Brezillon } 833b5571e9dSBoris Brezillon EXPORT_SYMBOL(drm_display_info_set_bus_formats); 834b5571e9dSBoris Brezillon 835b5571e9dSBoris Brezillon /** 836eaf99c74SChris Wilson * drm_connector_get_cmdline_mode - reads the user's cmdline mode 837eaf99c74SChris Wilson * @connector: connector to quwery 838eaf99c74SChris Wilson * 839eaf99c74SChris Wilson * The kernel supports per-connector configration of its consoles through 840eaf99c74SChris Wilson * use of the video= parameter. This function parses that option and 841eaf99c74SChris Wilson * extracts the user's specified mode (or enable/disable status) for a 842eaf99c74SChris Wilson * particular connector. This is typically only used during the early fbdev 843eaf99c74SChris Wilson * setup. 844eaf99c74SChris Wilson */ 845eaf99c74SChris Wilson static void drm_connector_get_cmdline_mode(struct drm_connector *connector) 846eaf99c74SChris Wilson { 847eaf99c74SChris Wilson struct drm_cmdline_mode *mode = &connector->cmdline_mode; 848eaf99c74SChris Wilson char *option = NULL; 849eaf99c74SChris Wilson 850eaf99c74SChris Wilson if (fb_get_options(connector->name, &option)) 851eaf99c74SChris Wilson return; 852eaf99c74SChris Wilson 853eaf99c74SChris Wilson if (!drm_mode_parse_command_line_for_connector(option, 854eaf99c74SChris Wilson connector, 855eaf99c74SChris Wilson mode)) 856eaf99c74SChris Wilson return; 857eaf99c74SChris Wilson 858eaf99c74SChris Wilson if (mode->force) { 859eaf99c74SChris Wilson const char *s; 860eaf99c74SChris Wilson 861eaf99c74SChris Wilson switch (mode->force) { 862eaf99c74SChris Wilson case DRM_FORCE_OFF: 863eaf99c74SChris Wilson s = "OFF"; 864eaf99c74SChris Wilson break; 865eaf99c74SChris Wilson case DRM_FORCE_ON_DIGITAL: 866eaf99c74SChris Wilson s = "ON - dig"; 867eaf99c74SChris Wilson break; 868eaf99c74SChris Wilson default: 869eaf99c74SChris Wilson case DRM_FORCE_ON: 870eaf99c74SChris Wilson s = "ON"; 871eaf99c74SChris Wilson break; 872eaf99c74SChris Wilson } 873eaf99c74SChris Wilson 874eaf99c74SChris Wilson DRM_INFO("forcing %s connector %s\n", connector->name, s); 875eaf99c74SChris Wilson connector->force = mode->force; 876eaf99c74SChris Wilson } 877eaf99c74SChris Wilson 878eaf99c74SChris Wilson DRM_DEBUG_KMS("cmdline mode for connector %s %dx%d@%dHz%s%s%s\n", 879eaf99c74SChris Wilson connector->name, 880eaf99c74SChris Wilson mode->xres, mode->yres, 881eaf99c74SChris Wilson mode->refresh_specified ? mode->refresh : 60, 882eaf99c74SChris Wilson mode->rb ? " reduced blanking" : "", 883eaf99c74SChris Wilson mode->margins ? " with margins" : "", 884eaf99c74SChris Wilson mode->interlace ? " interlaced" : ""); 885eaf99c74SChris Wilson } 886eaf99c74SChris Wilson 887eaf99c74SChris Wilson /** 888f453ba04SDave Airlie * drm_connector_init - Init a preallocated connector 889f453ba04SDave Airlie * @dev: DRM device 890f453ba04SDave Airlie * @connector: the connector to init 891f453ba04SDave Airlie * @funcs: callbacks for this connector 892065a50edSDaniel Vetter * @connector_type: user visible type of the connector 893f453ba04SDave Airlie * 894f453ba04SDave Airlie * Initialises a preallocated connector. Connectors should be 895f453ba04SDave Airlie * subclassed as part of driver connector objects. 8966bfc56aaSVille Syrjälä * 897c8e32cc1SDaniel Vetter * Returns: 8986bfc56aaSVille Syrjälä * Zero on success, error code on failure. 899f453ba04SDave Airlie */ 9006bfc56aaSVille Syrjälä int drm_connector_init(struct drm_device *dev, 901f453ba04SDave Airlie struct drm_connector *connector, 902f453ba04SDave Airlie const struct drm_connector_funcs *funcs, 903f453ba04SDave Airlie int connector_type) 904f453ba04SDave Airlie { 905ae16c597SRob Clark struct drm_mode_config *config = &dev->mode_config; 9066bfc56aaSVille Syrjälä int ret; 907b21e3afeSIlia Mirkin struct ida *connector_ida = 908b21e3afeSIlia Mirkin &drm_connector_enum_list[connector_type].ida; 9096bfc56aaSVille Syrjälä 91084849903SDaniel Vetter drm_modeset_lock_all(dev); 911f453ba04SDave Airlie 9122ee39452SDave Airlie ret = drm_mode_object_get_reg(dev, &connector->base, DRM_MODE_OBJECT_CONNECTOR, false); 9136bfc56aaSVille Syrjälä if (ret) 9142abdd313SJani Nikula goto out_unlock; 9156bfc56aaSVille Syrjälä 9167e3bdf4aSPaulo Zanoni connector->base.properties = &connector->properties; 917f453ba04SDave Airlie connector->dev = dev; 918f453ba04SDave Airlie connector->funcs = funcs; 9195fff80bbSMaarten Lankhorst 9205fff80bbSMaarten Lankhorst connector->connector_id = ida_simple_get(&config->connector_ida, 0, 0, GFP_KERNEL); 9215fff80bbSMaarten Lankhorst if (connector->connector_id < 0) { 9225fff80bbSMaarten Lankhorst ret = connector->connector_id; 9235fff80bbSMaarten Lankhorst goto out_put; 9245fff80bbSMaarten Lankhorst } 9255fff80bbSMaarten Lankhorst 926f453ba04SDave Airlie connector->connector_type = connector_type; 927f453ba04SDave Airlie connector->connector_type_id = 928b21e3afeSIlia Mirkin ida_simple_get(connector_ida, 1, 0, GFP_KERNEL); 929b21e3afeSIlia Mirkin if (connector->connector_type_id < 0) { 930b21e3afeSIlia Mirkin ret = connector->connector_type_id; 9315fff80bbSMaarten Lankhorst goto out_put_id; 932b21e3afeSIlia Mirkin } 9332abdd313SJani Nikula connector->name = 9342abdd313SJani Nikula kasprintf(GFP_KERNEL, "%s-%d", 9352abdd313SJani Nikula drm_connector_enum_list[connector_type].name, 9362abdd313SJani Nikula connector->connector_type_id); 9372abdd313SJani Nikula if (!connector->name) { 9382abdd313SJani Nikula ret = -ENOMEM; 9395fff80bbSMaarten Lankhorst goto out_put_type_id; 9402abdd313SJani Nikula } 9412abdd313SJani Nikula 942f453ba04SDave Airlie INIT_LIST_HEAD(&connector->probed_modes); 943f453ba04SDave Airlie INIT_LIST_HEAD(&connector->modes); 944f453ba04SDave Airlie connector->edid_blob_ptr = NULL; 9455e2cb2f6SDaniel Vetter connector->status = connector_status_unknown; 946f453ba04SDave Airlie 947eaf99c74SChris Wilson drm_connector_get_cmdline_mode(connector); 948eaf99c74SChris Wilson 949c7eb76f4SDaniel Vetter /* We should add connectors at the end to avoid upsetting the connector 950c7eb76f4SDaniel Vetter * index too much. */ 951ae16c597SRob Clark list_add_tail(&connector->head, &config->connector_list); 952ae16c597SRob Clark config->num_connector++; 953f453ba04SDave Airlie 954a7331e5cSThomas Hellstrom if (connector_type != DRM_MODE_CONNECTOR_VIRTUAL) 95558495563SRob Clark drm_object_attach_property(&connector->base, 956ae16c597SRob Clark config->edid_property, 957a7331e5cSThomas Hellstrom 0); 958f453ba04SDave Airlie 95958495563SRob Clark drm_object_attach_property(&connector->base, 960ae16c597SRob Clark config->dpms_property, 0); 961ae16c597SRob Clark 962ae16c597SRob Clark if (drm_core_check_feature(dev, DRIVER_ATOMIC)) { 963ae16c597SRob Clark drm_object_attach_property(&connector->base, config->prop_crtc_id, 0); 964ae16c597SRob Clark } 965f453ba04SDave Airlie 96630f65707SThomas Wood connector->debugfs_entry = NULL; 9675fff80bbSMaarten Lankhorst out_put_type_id: 9685fff80bbSMaarten Lankhorst if (ret) 9695fff80bbSMaarten Lankhorst ida_remove(connector_ida, connector->connector_type_id); 9705fff80bbSMaarten Lankhorst out_put_id: 9715fff80bbSMaarten Lankhorst if (ret) 9725fff80bbSMaarten Lankhorst ida_remove(&config->connector_ida, connector->connector_id); 9732abdd313SJani Nikula out_put: 9742abdd313SJani Nikula if (ret) 9752abdd313SJani Nikula drm_mode_object_put(dev, &connector->base); 9762abdd313SJani Nikula 9772abdd313SJani Nikula out_unlock: 97884849903SDaniel Vetter drm_modeset_unlock_all(dev); 9796bfc56aaSVille Syrjälä 9806bfc56aaSVille Syrjälä return ret; 981f453ba04SDave Airlie } 982f453ba04SDave Airlie EXPORT_SYMBOL(drm_connector_init); 983f453ba04SDave Airlie 984f453ba04SDave Airlie /** 985f453ba04SDave Airlie * drm_connector_cleanup - cleans up an initialised connector 986f453ba04SDave Airlie * @connector: connector to cleanup 987f453ba04SDave Airlie * 988f453ba04SDave Airlie * Cleans up the connector but doesn't free the object. 989f453ba04SDave Airlie */ 990f453ba04SDave Airlie void drm_connector_cleanup(struct drm_connector *connector) 991f453ba04SDave Airlie { 992f453ba04SDave Airlie struct drm_device *dev = connector->dev; 993f453ba04SDave Airlie struct drm_display_mode *mode, *t; 994f453ba04SDave Airlie 99540d9b043SDave Airlie if (connector->tile_group) { 99640d9b043SDave Airlie drm_mode_put_tile_group(dev, connector->tile_group); 99740d9b043SDave Airlie connector->tile_group = NULL; 99840d9b043SDave Airlie } 99940d9b043SDave Airlie 1000f453ba04SDave Airlie list_for_each_entry_safe(mode, t, &connector->probed_modes, head) 1001f453ba04SDave Airlie drm_mode_remove(connector, mode); 1002f453ba04SDave Airlie 1003f453ba04SDave Airlie list_for_each_entry_safe(mode, t, &connector->modes, head) 1004f453ba04SDave Airlie drm_mode_remove(connector, mode); 1005f453ba04SDave Airlie 1006b21e3afeSIlia Mirkin ida_remove(&drm_connector_enum_list[connector->connector_type].ida, 1007b21e3afeSIlia Mirkin connector->connector_type_id); 1008b21e3afeSIlia Mirkin 10095fff80bbSMaarten Lankhorst ida_remove(&dev->mode_config.connector_ida, 10105fff80bbSMaarten Lankhorst connector->connector_id); 10115fff80bbSMaarten Lankhorst 1012b5571e9dSBoris Brezillon kfree(connector->display_info.bus_formats); 1013f453ba04SDave Airlie drm_mode_object_put(dev, &connector->base); 10142abdd313SJani Nikula kfree(connector->name); 10152abdd313SJani Nikula connector->name = NULL; 1016f453ba04SDave Airlie list_del(&connector->head); 10176380c509SJoonyoung Shim dev->mode_config.num_connector--; 10183009c037SThierry Reding 10193009c037SThierry Reding WARN_ON(connector->state && !connector->funcs->atomic_destroy_state); 10203009c037SThierry Reding if (connector->state && connector->funcs->atomic_destroy_state) 10213009c037SThierry Reding connector->funcs->atomic_destroy_state(connector, 10223009c037SThierry Reding connector->state); 1023a18c0af1SThierry Reding 1024a18c0af1SThierry Reding memset(connector, 0, sizeof(*connector)); 1025f453ba04SDave Airlie } 1026f453ba04SDave Airlie EXPORT_SYMBOL(drm_connector_cleanup); 1027f453ba04SDave Airlie 1028c8e32cc1SDaniel Vetter /** 102934ea3d38SThomas Wood * drm_connector_register - register a connector 103034ea3d38SThomas Wood * @connector: the connector to register 103134ea3d38SThomas Wood * 103234ea3d38SThomas Wood * Register userspace interfaces for a connector 103334ea3d38SThomas Wood * 103434ea3d38SThomas Wood * Returns: 103534ea3d38SThomas Wood * Zero on success, error code on failure. 103634ea3d38SThomas Wood */ 103734ea3d38SThomas Wood int drm_connector_register(struct drm_connector *connector) 103834ea3d38SThomas Wood { 103930f65707SThomas Wood int ret; 104030f65707SThomas Wood 10412ee39452SDave Airlie drm_mode_object_register(connector->dev, &connector->base); 10422ee39452SDave Airlie 104330f65707SThomas Wood ret = drm_sysfs_connector_add(connector); 104430f65707SThomas Wood if (ret) 104530f65707SThomas Wood return ret; 104630f65707SThomas Wood 104730f65707SThomas Wood ret = drm_debugfs_connector_add(connector); 104830f65707SThomas Wood if (ret) { 104930f65707SThomas Wood drm_sysfs_connector_remove(connector); 105030f65707SThomas Wood return ret; 105130f65707SThomas Wood } 105230f65707SThomas Wood 105330f65707SThomas Wood return 0; 105434ea3d38SThomas Wood } 105534ea3d38SThomas Wood EXPORT_SYMBOL(drm_connector_register); 105634ea3d38SThomas Wood 105734ea3d38SThomas Wood /** 105834ea3d38SThomas Wood * drm_connector_unregister - unregister a connector 105934ea3d38SThomas Wood * @connector: the connector to unregister 106034ea3d38SThomas Wood * 106134ea3d38SThomas Wood * Unregister userspace interfaces for a connector 106234ea3d38SThomas Wood */ 106334ea3d38SThomas Wood void drm_connector_unregister(struct drm_connector *connector) 106434ea3d38SThomas Wood { 106534ea3d38SThomas Wood drm_sysfs_connector_remove(connector); 106630f65707SThomas Wood drm_debugfs_connector_remove(connector); 106734ea3d38SThomas Wood } 106834ea3d38SThomas Wood EXPORT_SYMBOL(drm_connector_unregister); 106934ea3d38SThomas Wood 107034ea3d38SThomas Wood /** 107154d2c2daSAlexey Brodkin * drm_connector_register_all - register all connectors 107254d2c2daSAlexey Brodkin * @dev: drm device 107354d2c2daSAlexey Brodkin * 107454d2c2daSAlexey Brodkin * This function registers all connectors in sysfs and other places so that 107554d2c2daSAlexey Brodkin * userspace can start to access them. Drivers can call it after calling 107654d2c2daSAlexey Brodkin * drm_dev_register() to complete the device registration, if they don't call 107754d2c2daSAlexey Brodkin * drm_connector_register() on each connector individually. 107854d2c2daSAlexey Brodkin * 107954d2c2daSAlexey Brodkin * When a device is unplugged and should be removed from userspace access, 108054d2c2daSAlexey Brodkin * call drm_connector_unregister_all(), which is the inverse of this 108154d2c2daSAlexey Brodkin * function. 108254d2c2daSAlexey Brodkin * 108354d2c2daSAlexey Brodkin * Returns: 108454d2c2daSAlexey Brodkin * Zero on success, error code on failure. 108554d2c2daSAlexey Brodkin */ 108654d2c2daSAlexey Brodkin int drm_connector_register_all(struct drm_device *dev) 108754d2c2daSAlexey Brodkin { 108854d2c2daSAlexey Brodkin struct drm_connector *connector; 108954d2c2daSAlexey Brodkin int ret; 109054d2c2daSAlexey Brodkin 109154d2c2daSAlexey Brodkin mutex_lock(&dev->mode_config.mutex); 109254d2c2daSAlexey Brodkin 109354d2c2daSAlexey Brodkin drm_for_each_connector(connector, dev) { 109454d2c2daSAlexey Brodkin ret = drm_connector_register(connector); 109554d2c2daSAlexey Brodkin if (ret) 109654d2c2daSAlexey Brodkin goto err; 109754d2c2daSAlexey Brodkin } 109854d2c2daSAlexey Brodkin 109954d2c2daSAlexey Brodkin mutex_unlock(&dev->mode_config.mutex); 110054d2c2daSAlexey Brodkin 110154d2c2daSAlexey Brodkin return 0; 110254d2c2daSAlexey Brodkin 110354d2c2daSAlexey Brodkin err: 110454d2c2daSAlexey Brodkin mutex_unlock(&dev->mode_config.mutex); 110554d2c2daSAlexey Brodkin drm_connector_unregister_all(dev); 110654d2c2daSAlexey Brodkin return ret; 110754d2c2daSAlexey Brodkin } 110854d2c2daSAlexey Brodkin EXPORT_SYMBOL(drm_connector_register_all); 110954d2c2daSAlexey Brodkin 111054d2c2daSAlexey Brodkin /** 11116c87e5c3SAlexey Brodkin * drm_connector_unregister_all - unregister connector userspace interfaces 1112c8e32cc1SDaniel Vetter * @dev: drm device 1113c8e32cc1SDaniel Vetter * 11146c87e5c3SAlexey Brodkin * This functions unregisters all connectors from sysfs and other places so 11156c87e5c3SAlexey Brodkin * that userspace can no longer access them. Drivers should call this as the 11166c87e5c3SAlexey Brodkin * first step tearing down the device instace, or when the underlying 11176c87e5c3SAlexey Brodkin * physical device disappeared (e.g. USB unplug), right before calling 11186c87e5c3SAlexey Brodkin * drm_dev_unregister(). 1119c8e32cc1SDaniel Vetter */ 11206c87e5c3SAlexey Brodkin void drm_connector_unregister_all(struct drm_device *dev) 1121cbc7e221SDave Airlie { 1122cbc7e221SDave Airlie struct drm_connector *connector; 1123cbc7e221SDave Airlie 11249a9f5ce8SDaniel Vetter /* FIXME: taking the mode config mutex ends up in a clash with sysfs */ 112514ba0031SLaurent Pinchart list_for_each_entry(connector, &dev->mode_config.connector_list, head) 112634ea3d38SThomas Wood drm_connector_unregister(connector); 1127cbc7e221SDave Airlie } 11286c87e5c3SAlexey Brodkin EXPORT_SYMBOL(drm_connector_unregister_all); 1129cbc7e221SDave Airlie 1130c8e32cc1SDaniel Vetter /** 1131c8e32cc1SDaniel Vetter * drm_encoder_init - Init a preallocated encoder 1132c8e32cc1SDaniel Vetter * @dev: drm device 1133c8e32cc1SDaniel Vetter * @encoder: the encoder to init 1134c8e32cc1SDaniel Vetter * @funcs: callbacks for this encoder 1135c8e32cc1SDaniel Vetter * @encoder_type: user visible type of the encoder 113613a3d91fSVille Syrjälä * @name: printf style format string for the encoder name, or NULL for default name 1137c8e32cc1SDaniel Vetter * 1138c8e32cc1SDaniel Vetter * Initialises a preallocated encoder. Encoder should be 1139c8e32cc1SDaniel Vetter * subclassed as part of driver encoder objects. 1140c8e32cc1SDaniel Vetter * 1141c8e32cc1SDaniel Vetter * Returns: 1142c8e32cc1SDaniel Vetter * Zero on success, error code on failure. 1143c8e32cc1SDaniel Vetter */ 11446bfc56aaSVille Syrjälä int drm_encoder_init(struct drm_device *dev, 1145f453ba04SDave Airlie struct drm_encoder *encoder, 1146f453ba04SDave Airlie const struct drm_encoder_funcs *funcs, 114713a3d91fSVille Syrjälä int encoder_type, const char *name, ...) 1148f453ba04SDave Airlie { 11496bfc56aaSVille Syrjälä int ret; 11506bfc56aaSVille Syrjälä 115184849903SDaniel Vetter drm_modeset_lock_all(dev); 1152f453ba04SDave Airlie 11536bfc56aaSVille Syrjälä ret = drm_mode_object_get(dev, &encoder->base, DRM_MODE_OBJECT_ENCODER); 11546bfc56aaSVille Syrjälä if (ret) 1155e5748946SJani Nikula goto out_unlock; 1156f453ba04SDave Airlie 11576bfc56aaSVille Syrjälä encoder->dev = dev; 1158f453ba04SDave Airlie encoder->encoder_type = encoder_type; 1159f453ba04SDave Airlie encoder->funcs = funcs; 116086bf546bSVille Syrjälä if (name) { 116186bf546bSVille Syrjälä va_list ap; 116286bf546bSVille Syrjälä 116386bf546bSVille Syrjälä va_start(ap, name); 116486bf546bSVille Syrjälä encoder->name = kvasprintf(GFP_KERNEL, name, ap); 116586bf546bSVille Syrjälä va_end(ap); 116686bf546bSVille Syrjälä } else { 1167e5748946SJani Nikula encoder->name = kasprintf(GFP_KERNEL, "%s-%d", 1168e5748946SJani Nikula drm_encoder_enum_list[encoder_type].name, 1169e5748946SJani Nikula encoder->base.id); 117086bf546bSVille Syrjälä } 1171e5748946SJani Nikula if (!encoder->name) { 1172e5748946SJani Nikula ret = -ENOMEM; 1173e5748946SJani Nikula goto out_put; 1174e5748946SJani Nikula } 1175f453ba04SDave Airlie 1176f453ba04SDave Airlie list_add_tail(&encoder->head, &dev->mode_config.encoder_list); 1177f453ba04SDave Airlie dev->mode_config.num_encoder++; 1178f453ba04SDave Airlie 1179e5748946SJani Nikula out_put: 1180e5748946SJani Nikula if (ret) 1181e5748946SJani Nikula drm_mode_object_put(dev, &encoder->base); 1182e5748946SJani Nikula 1183e5748946SJani Nikula out_unlock: 118484849903SDaniel Vetter drm_modeset_unlock_all(dev); 11856bfc56aaSVille Syrjälä 11866bfc56aaSVille Syrjälä return ret; 1187f453ba04SDave Airlie } 1188f453ba04SDave Airlie EXPORT_SYMBOL(drm_encoder_init); 1189f453ba04SDave Airlie 1190c8e32cc1SDaniel Vetter /** 119147d7777fSMaarten Lankhorst * drm_encoder_index - find the index of a registered encoder 119247d7777fSMaarten Lankhorst * @encoder: encoder to find index for 119347d7777fSMaarten Lankhorst * 119447d7777fSMaarten Lankhorst * Given a registered encoder, return the index of that encoder within a DRM 119547d7777fSMaarten Lankhorst * device's list of encoders. 119647d7777fSMaarten Lankhorst */ 119747d7777fSMaarten Lankhorst unsigned int drm_encoder_index(struct drm_encoder *encoder) 119847d7777fSMaarten Lankhorst { 119947d7777fSMaarten Lankhorst unsigned int index = 0; 120047d7777fSMaarten Lankhorst struct drm_encoder *tmp; 120147d7777fSMaarten Lankhorst 120247d7777fSMaarten Lankhorst drm_for_each_encoder(tmp, encoder->dev) { 120347d7777fSMaarten Lankhorst if (tmp == encoder) 120447d7777fSMaarten Lankhorst return index; 120547d7777fSMaarten Lankhorst 120647d7777fSMaarten Lankhorst index++; 120747d7777fSMaarten Lankhorst } 120847d7777fSMaarten Lankhorst 120947d7777fSMaarten Lankhorst BUG(); 121047d7777fSMaarten Lankhorst } 121147d7777fSMaarten Lankhorst EXPORT_SYMBOL(drm_encoder_index); 121247d7777fSMaarten Lankhorst 121347d7777fSMaarten Lankhorst /** 1214c8e32cc1SDaniel Vetter * drm_encoder_cleanup - cleans up an initialised encoder 1215c8e32cc1SDaniel Vetter * @encoder: encoder to cleanup 1216c8e32cc1SDaniel Vetter * 1217c8e32cc1SDaniel Vetter * Cleans up the encoder but doesn't free the object. 1218c8e32cc1SDaniel Vetter */ 1219f453ba04SDave Airlie void drm_encoder_cleanup(struct drm_encoder *encoder) 1220f453ba04SDave Airlie { 1221f453ba04SDave Airlie struct drm_device *dev = encoder->dev; 12224dfd909fSThierry Reding 122384849903SDaniel Vetter drm_modeset_lock_all(dev); 1224f453ba04SDave Airlie drm_mode_object_put(dev, &encoder->base); 1225e5748946SJani Nikula kfree(encoder->name); 1226f453ba04SDave Airlie list_del(&encoder->head); 12276380c509SJoonyoung Shim dev->mode_config.num_encoder--; 122884849903SDaniel Vetter drm_modeset_unlock_all(dev); 1229a18c0af1SThierry Reding 1230a18c0af1SThierry Reding memset(encoder, 0, sizeof(*encoder)); 1231f453ba04SDave Airlie } 1232f453ba04SDave Airlie EXPORT_SYMBOL(drm_encoder_cleanup); 1233f453ba04SDave Airlie 12349f4c97a2SVille Syrjälä static unsigned int drm_num_planes(struct drm_device *dev) 12359f4c97a2SVille Syrjälä { 12369f4c97a2SVille Syrjälä unsigned int num = 0; 12379f4c97a2SVille Syrjälä struct drm_plane *tmp; 12389f4c97a2SVille Syrjälä 12399f4c97a2SVille Syrjälä drm_for_each_plane(tmp, dev) { 12409f4c97a2SVille Syrjälä num++; 12419f4c97a2SVille Syrjälä } 12429f4c97a2SVille Syrjälä 12439f4c97a2SVille Syrjälä return num; 12449f4c97a2SVille Syrjälä } 12459f4c97a2SVille Syrjälä 124635f2c3aeSVille Syrjälä /** 1247dc415ff9SMatt Roper * drm_universal_plane_init - Initialize a new universal plane object 124835f2c3aeSVille Syrjälä * @dev: DRM device 124935f2c3aeSVille Syrjälä * @plane: plane object to init 125035f2c3aeSVille Syrjälä * @possible_crtcs: bitmask of possible CRTCs 125135f2c3aeSVille Syrjälä * @funcs: callbacks for the new plane 125235f2c3aeSVille Syrjälä * @formats: array of supported formats (%DRM_FORMAT_*) 125335f2c3aeSVille Syrjälä * @format_count: number of elements in @formats 1254dc415ff9SMatt Roper * @type: type of plane (overlay, primary, cursor) 1255b0b3b795SVille Syrjälä * @name: printf style format string for the plane name, or NULL for default name 125635f2c3aeSVille Syrjälä * 1257dc415ff9SMatt Roper * Initializes a plane object of type @type. 125835f2c3aeSVille Syrjälä * 1259c8e32cc1SDaniel Vetter * Returns: 126035f2c3aeSVille Syrjälä * Zero on success, error code on failure. 126135f2c3aeSVille Syrjälä */ 1262dc415ff9SMatt Roper int drm_universal_plane_init(struct drm_device *dev, struct drm_plane *plane, 12638cf5c917SJesse Barnes unsigned long possible_crtcs, 12648cf5c917SJesse Barnes const struct drm_plane_funcs *funcs, 126545e3743aSThierry Reding const uint32_t *formats, unsigned int format_count, 1266b0b3b795SVille Syrjälä enum drm_plane_type type, 1267b0b3b795SVille Syrjälä const char *name, ...) 12688cf5c917SJesse Barnes { 12696b4959f4SRob Clark struct drm_mode_config *config = &dev->mode_config; 12706bfc56aaSVille Syrjälä int ret; 12716bfc56aaSVille Syrjälä 12726bfc56aaSVille Syrjälä ret = drm_mode_object_get(dev, &plane->base, DRM_MODE_OBJECT_PLANE); 12736bfc56aaSVille Syrjälä if (ret) 1274baf698b0SDaniel Vetter return ret; 12756bfc56aaSVille Syrjälä 12764d02e2deSDaniel Vetter drm_modeset_lock_init(&plane->mutex); 12774d02e2deSDaniel Vetter 12784d93914aSRob Clark plane->base.properties = &plane->properties; 12798cf5c917SJesse Barnes plane->dev = dev; 12808cf5c917SJesse Barnes plane->funcs = funcs; 12812f6c5389SThierry Reding plane->format_types = kmalloc_array(format_count, sizeof(uint32_t), 12828cf5c917SJesse Barnes GFP_KERNEL); 12838cf5c917SJesse Barnes if (!plane->format_types) { 12848cf5c917SJesse Barnes DRM_DEBUG_KMS("out of memory when allocating plane\n"); 12858cf5c917SJesse Barnes drm_mode_object_put(dev, &plane->base); 1286baf698b0SDaniel Vetter return -ENOMEM; 12878cf5c917SJesse Barnes } 12888cf5c917SJesse Barnes 12899f4c97a2SVille Syrjälä if (name) { 12909f4c97a2SVille Syrjälä va_list ap; 12919f4c97a2SVille Syrjälä 12929f4c97a2SVille Syrjälä va_start(ap, name); 12939f4c97a2SVille Syrjälä plane->name = kvasprintf(GFP_KERNEL, name, ap); 12949f4c97a2SVille Syrjälä va_end(ap); 12959f4c97a2SVille Syrjälä } else { 12969f4c97a2SVille Syrjälä plane->name = kasprintf(GFP_KERNEL, "plane-%d", 12979f4c97a2SVille Syrjälä drm_num_planes(dev)); 12989f4c97a2SVille Syrjälä } 12999f4c97a2SVille Syrjälä if (!plane->name) { 13009f4c97a2SVille Syrjälä kfree(plane->format_types); 13019f4c97a2SVille Syrjälä drm_mode_object_put(dev, &plane->base); 13029f4c97a2SVille Syrjälä return -ENOMEM; 13039f4c97a2SVille Syrjälä } 13049f4c97a2SVille Syrjälä 1305308e5bcbSJesse Barnes memcpy(plane->format_types, formats, format_count * sizeof(uint32_t)); 13068cf5c917SJesse Barnes plane->format_count = format_count; 13078cf5c917SJesse Barnes plane->possible_crtcs = possible_crtcs; 1308dc415ff9SMatt Roper plane->type = type; 13098cf5c917SJesse Barnes 13106b4959f4SRob Clark list_add_tail(&plane->head, &config->plane_list); 13116b4959f4SRob Clark config->num_total_plane++; 1312e27dde3eSMatt Roper if (plane->type == DRM_PLANE_TYPE_OVERLAY) 13136b4959f4SRob Clark config->num_overlay_plane++; 13148cf5c917SJesse Barnes 13159922ab5aSRob Clark drm_object_attach_property(&plane->base, 13166b4959f4SRob Clark config->plane_type_property, 13179922ab5aSRob Clark plane->type); 13189922ab5aSRob Clark 13196b4959f4SRob Clark if (drm_core_check_feature(dev, DRIVER_ATOMIC)) { 13206b4959f4SRob Clark drm_object_attach_property(&plane->base, config->prop_fb_id, 0); 13216b4959f4SRob Clark drm_object_attach_property(&plane->base, config->prop_crtc_id, 0); 13226b4959f4SRob Clark drm_object_attach_property(&plane->base, config->prop_crtc_x, 0); 13236b4959f4SRob Clark drm_object_attach_property(&plane->base, config->prop_crtc_y, 0); 13246b4959f4SRob Clark drm_object_attach_property(&plane->base, config->prop_crtc_w, 0); 13256b4959f4SRob Clark drm_object_attach_property(&plane->base, config->prop_crtc_h, 0); 13266b4959f4SRob Clark drm_object_attach_property(&plane->base, config->prop_src_x, 0); 13276b4959f4SRob Clark drm_object_attach_property(&plane->base, config->prop_src_y, 0); 13286b4959f4SRob Clark drm_object_attach_property(&plane->base, config->prop_src_w, 0); 13296b4959f4SRob Clark drm_object_attach_property(&plane->base, config->prop_src_h, 0); 13306b4959f4SRob Clark } 13316b4959f4SRob Clark 1332baf698b0SDaniel Vetter return 0; 13338cf5c917SJesse Barnes } 1334dc415ff9SMatt Roper EXPORT_SYMBOL(drm_universal_plane_init); 1335dc415ff9SMatt Roper 1336dc415ff9SMatt Roper /** 1337dc415ff9SMatt Roper * drm_plane_init - Initialize a legacy plane 1338dc415ff9SMatt Roper * @dev: DRM device 1339dc415ff9SMatt Roper * @plane: plane object to init 1340dc415ff9SMatt Roper * @possible_crtcs: bitmask of possible CRTCs 1341dc415ff9SMatt Roper * @funcs: callbacks for the new plane 1342dc415ff9SMatt Roper * @formats: array of supported formats (%DRM_FORMAT_*) 1343dc415ff9SMatt Roper * @format_count: number of elements in @formats 1344dc415ff9SMatt Roper * @is_primary: plane type (primary vs overlay) 1345dc415ff9SMatt Roper * 1346dc415ff9SMatt Roper * Legacy API to initialize a DRM plane. 1347dc415ff9SMatt Roper * 1348dc415ff9SMatt Roper * New drivers should call drm_universal_plane_init() instead. 1349dc415ff9SMatt Roper * 1350dc415ff9SMatt Roper * Returns: 1351dc415ff9SMatt Roper * Zero on success, error code on failure. 1352dc415ff9SMatt Roper */ 1353dc415ff9SMatt Roper int drm_plane_init(struct drm_device *dev, struct drm_plane *plane, 1354dc415ff9SMatt Roper unsigned long possible_crtcs, 1355dc415ff9SMatt Roper const struct drm_plane_funcs *funcs, 135645e3743aSThierry Reding const uint32_t *formats, unsigned int format_count, 1357dc415ff9SMatt Roper bool is_primary) 1358dc415ff9SMatt Roper { 1359dc415ff9SMatt Roper enum drm_plane_type type; 1360dc415ff9SMatt Roper 1361dc415ff9SMatt Roper type = is_primary ? DRM_PLANE_TYPE_PRIMARY : DRM_PLANE_TYPE_OVERLAY; 1362dc415ff9SMatt Roper return drm_universal_plane_init(dev, plane, possible_crtcs, funcs, 1363b0b3b795SVille Syrjälä formats, format_count, type, NULL); 1364dc415ff9SMatt Roper } 13658cf5c917SJesse Barnes EXPORT_SYMBOL(drm_plane_init); 13668cf5c917SJesse Barnes 136735f2c3aeSVille Syrjälä /** 136835f2c3aeSVille Syrjälä * drm_plane_cleanup - Clean up the core plane usage 136935f2c3aeSVille Syrjälä * @plane: plane to cleanup 137035f2c3aeSVille Syrjälä * 137135f2c3aeSVille Syrjälä * This function cleans up @plane and removes it from the DRM mode setting 137235f2c3aeSVille Syrjälä * core. Note that the function does *not* free the plane structure itself, 137335f2c3aeSVille Syrjälä * this is the responsibility of the caller. 137435f2c3aeSVille Syrjälä */ 13758cf5c917SJesse Barnes void drm_plane_cleanup(struct drm_plane *plane) 13768cf5c917SJesse Barnes { 13778cf5c917SJesse Barnes struct drm_device *dev = plane->dev; 13788cf5c917SJesse Barnes 137984849903SDaniel Vetter drm_modeset_lock_all(dev); 13808cf5c917SJesse Barnes kfree(plane->format_types); 13818cf5c917SJesse Barnes drm_mode_object_put(dev, &plane->base); 1382dc415ff9SMatt Roper 1383dc415ff9SMatt Roper BUG_ON(list_empty(&plane->head)); 1384dc415ff9SMatt Roper 13858cf5c917SJesse Barnes list_del(&plane->head); 1386e27dde3eSMatt Roper dev->mode_config.num_total_plane--; 1387e27dde3eSMatt Roper if (plane->type == DRM_PLANE_TYPE_OVERLAY) 1388e27dde3eSMatt Roper dev->mode_config.num_overlay_plane--; 138984849903SDaniel Vetter drm_modeset_unlock_all(dev); 13903009c037SThierry Reding 13913009c037SThierry Reding WARN_ON(plane->state && !plane->funcs->atomic_destroy_state); 13923009c037SThierry Reding if (plane->state && plane->funcs->atomic_destroy_state) 13933009c037SThierry Reding plane->funcs->atomic_destroy_state(plane, plane->state); 1394a18c0af1SThierry Reding 13959f4c97a2SVille Syrjälä kfree(plane->name); 13969f4c97a2SVille Syrjälä 1397a18c0af1SThierry Reding memset(plane, 0, sizeof(*plane)); 13988cf5c917SJesse Barnes } 13998cf5c917SJesse Barnes EXPORT_SYMBOL(drm_plane_cleanup); 14008cf5c917SJesse Barnes 140135f2c3aeSVille Syrjälä /** 140210f637bfSDaniel Vetter * drm_plane_index - find the index of a registered plane 140310f637bfSDaniel Vetter * @plane: plane to find index for 140410f637bfSDaniel Vetter * 140510f637bfSDaniel Vetter * Given a registered plane, return the index of that CRTC within a DRM 140610f637bfSDaniel Vetter * device's list of planes. 140710f637bfSDaniel Vetter */ 140810f637bfSDaniel Vetter unsigned int drm_plane_index(struct drm_plane *plane) 140910f637bfSDaniel Vetter { 141010f637bfSDaniel Vetter unsigned int index = 0; 141110f637bfSDaniel Vetter struct drm_plane *tmp; 141210f637bfSDaniel Vetter 1413e4f62546SDaniel Vetter drm_for_each_plane(tmp, plane->dev) { 141410f637bfSDaniel Vetter if (tmp == plane) 141510f637bfSDaniel Vetter return index; 141610f637bfSDaniel Vetter 141710f637bfSDaniel Vetter index++; 141810f637bfSDaniel Vetter } 141910f637bfSDaniel Vetter 142010f637bfSDaniel Vetter BUG(); 142110f637bfSDaniel Vetter } 142210f637bfSDaniel Vetter EXPORT_SYMBOL(drm_plane_index); 142310f637bfSDaniel Vetter 142410f637bfSDaniel Vetter /** 1425f81338a5SChandra Konduru * drm_plane_from_index - find the registered plane at an index 1426f81338a5SChandra Konduru * @dev: DRM device 1427f81338a5SChandra Konduru * @idx: index of registered plane to find for 1428f81338a5SChandra Konduru * 1429f81338a5SChandra Konduru * Given a plane index, return the registered plane from DRM device's 1430f81338a5SChandra Konduru * list of planes with matching index. 1431f81338a5SChandra Konduru */ 1432f81338a5SChandra Konduru struct drm_plane * 1433f81338a5SChandra Konduru drm_plane_from_index(struct drm_device *dev, int idx) 1434f81338a5SChandra Konduru { 1435f81338a5SChandra Konduru struct drm_plane *plane; 1436f81338a5SChandra Konduru unsigned int i = 0; 1437f81338a5SChandra Konduru 14386295d607SDaniel Vetter drm_for_each_plane(plane, dev) { 1439f81338a5SChandra Konduru if (i == idx) 1440f81338a5SChandra Konduru return plane; 1441f81338a5SChandra Konduru i++; 1442f81338a5SChandra Konduru } 1443f81338a5SChandra Konduru return NULL; 1444f81338a5SChandra Konduru } 1445f81338a5SChandra Konduru EXPORT_SYMBOL(drm_plane_from_index); 1446f81338a5SChandra Konduru 1447f81338a5SChandra Konduru /** 144835f2c3aeSVille Syrjälä * drm_plane_force_disable - Forcibly disable a plane 144935f2c3aeSVille Syrjälä * @plane: plane to disable 145035f2c3aeSVille Syrjälä * 145135f2c3aeSVille Syrjälä * Forces the plane to be disabled. 145235f2c3aeSVille Syrjälä * 145335f2c3aeSVille Syrjälä * Used when the plane's current framebuffer is destroyed, 145435f2c3aeSVille Syrjälä * and when restoring fbdev mode. 145535f2c3aeSVille Syrjälä */ 14569125e618SVille Syrjälä void drm_plane_force_disable(struct drm_plane *plane) 14579125e618SVille Syrjälä { 14589125e618SVille Syrjälä int ret; 14599125e618SVille Syrjälä 14603d30a59bSDaniel Vetter if (!plane->fb) 14619125e618SVille Syrjälä return; 14629125e618SVille Syrjälä 14633d30a59bSDaniel Vetter plane->old_fb = plane->fb; 14649125e618SVille Syrjälä ret = plane->funcs->disable_plane(plane); 1465731cce48SDaniel Vetter if (ret) { 14669125e618SVille Syrjälä DRM_ERROR("failed to disable plane with busy fb\n"); 14673d30a59bSDaniel Vetter plane->old_fb = NULL; 1468731cce48SDaniel Vetter return; 1469731cce48SDaniel Vetter } 14709125e618SVille Syrjälä /* disconnect the plane from the fb and crtc: */ 1471220dd2bcSDaniel Vetter drm_framebuffer_unreference(plane->old_fb); 14723d30a59bSDaniel Vetter plane->old_fb = NULL; 14739125e618SVille Syrjälä plane->fb = NULL; 14749125e618SVille Syrjälä plane->crtc = NULL; 14759125e618SVille Syrjälä } 14769125e618SVille Syrjälä EXPORT_SYMBOL(drm_plane_force_disable); 14779125e618SVille Syrjälä 14786b4959f4SRob Clark static int drm_mode_create_standard_properties(struct drm_device *dev) 1479f453ba04SDave Airlie { 1480356af0e1SRob Clark struct drm_property *prop; 1481f453ba04SDave Airlie 1482f453ba04SDave Airlie /* 1483f453ba04SDave Airlie * Standard properties (apply to all connectors) 1484f453ba04SDave Airlie */ 1485356af0e1SRob Clark prop = drm_property_create(dev, DRM_MODE_PROP_BLOB | 1486f453ba04SDave Airlie DRM_MODE_PROP_IMMUTABLE, 1487f453ba04SDave Airlie "EDID", 0); 1488356af0e1SRob Clark if (!prop) 1489356af0e1SRob Clark return -ENOMEM; 1490356af0e1SRob Clark dev->mode_config.edid_property = prop; 1491f453ba04SDave Airlie 1492356af0e1SRob Clark prop = drm_property_create_enum(dev, 0, 14934a67d391SSascha Hauer "DPMS", drm_dpms_enum_list, 14944a67d391SSascha Hauer ARRAY_SIZE(drm_dpms_enum_list)); 1495356af0e1SRob Clark if (!prop) 1496356af0e1SRob Clark return -ENOMEM; 1497356af0e1SRob Clark dev->mode_config.dpms_property = prop; 1498f453ba04SDave Airlie 1499356af0e1SRob Clark prop = drm_property_create(dev, 150043aba7ebSDave Airlie DRM_MODE_PROP_BLOB | 150143aba7ebSDave Airlie DRM_MODE_PROP_IMMUTABLE, 150243aba7ebSDave Airlie "PATH", 0); 1503356af0e1SRob Clark if (!prop) 1504356af0e1SRob Clark return -ENOMEM; 1505356af0e1SRob Clark dev->mode_config.path_property = prop; 150643aba7ebSDave Airlie 1507356af0e1SRob Clark prop = drm_property_create(dev, 15086f134d7bSDave Airlie DRM_MODE_PROP_BLOB | 15096f134d7bSDave Airlie DRM_MODE_PROP_IMMUTABLE, 15106f134d7bSDave Airlie "TILE", 0); 1511356af0e1SRob Clark if (!prop) 1512356af0e1SRob Clark return -ENOMEM; 1513356af0e1SRob Clark dev->mode_config.tile_property = prop; 15146f134d7bSDave Airlie 15156b4959f4SRob Clark prop = drm_property_create_enum(dev, DRM_MODE_PROP_IMMUTABLE, 15169922ab5aSRob Clark "type", drm_plane_type_enum_list, 15179922ab5aSRob Clark ARRAY_SIZE(drm_plane_type_enum_list)); 15186b4959f4SRob Clark if (!prop) 15196b4959f4SRob Clark return -ENOMEM; 15206b4959f4SRob Clark dev->mode_config.plane_type_property = prop; 15216b4959f4SRob Clark 15226b4959f4SRob Clark prop = drm_property_create_range(dev, DRM_MODE_PROP_ATOMIC, 15236b4959f4SRob Clark "SRC_X", 0, UINT_MAX); 15246b4959f4SRob Clark if (!prop) 15256b4959f4SRob Clark return -ENOMEM; 15266b4959f4SRob Clark dev->mode_config.prop_src_x = prop; 15276b4959f4SRob Clark 15286b4959f4SRob Clark prop = drm_property_create_range(dev, DRM_MODE_PROP_ATOMIC, 15296b4959f4SRob Clark "SRC_Y", 0, UINT_MAX); 15306b4959f4SRob Clark if (!prop) 15316b4959f4SRob Clark return -ENOMEM; 15326b4959f4SRob Clark dev->mode_config.prop_src_y = prop; 15336b4959f4SRob Clark 15346b4959f4SRob Clark prop = drm_property_create_range(dev, DRM_MODE_PROP_ATOMIC, 15356b4959f4SRob Clark "SRC_W", 0, UINT_MAX); 15366b4959f4SRob Clark if (!prop) 15376b4959f4SRob Clark return -ENOMEM; 15386b4959f4SRob Clark dev->mode_config.prop_src_w = prop; 15396b4959f4SRob Clark 15406b4959f4SRob Clark prop = drm_property_create_range(dev, DRM_MODE_PROP_ATOMIC, 15416b4959f4SRob Clark "SRC_H", 0, UINT_MAX); 15426b4959f4SRob Clark if (!prop) 15436b4959f4SRob Clark return -ENOMEM; 15446b4959f4SRob Clark dev->mode_config.prop_src_h = prop; 15456b4959f4SRob Clark 15466b4959f4SRob Clark prop = drm_property_create_signed_range(dev, DRM_MODE_PROP_ATOMIC, 15476b4959f4SRob Clark "CRTC_X", INT_MIN, INT_MAX); 15486b4959f4SRob Clark if (!prop) 15496b4959f4SRob Clark return -ENOMEM; 15506b4959f4SRob Clark dev->mode_config.prop_crtc_x = prop; 15516b4959f4SRob Clark 15526b4959f4SRob Clark prop = drm_property_create_signed_range(dev, DRM_MODE_PROP_ATOMIC, 15536b4959f4SRob Clark "CRTC_Y", INT_MIN, INT_MAX); 15546b4959f4SRob Clark if (!prop) 15556b4959f4SRob Clark return -ENOMEM; 15566b4959f4SRob Clark dev->mode_config.prop_crtc_y = prop; 15576b4959f4SRob Clark 15586b4959f4SRob Clark prop = drm_property_create_range(dev, DRM_MODE_PROP_ATOMIC, 15596b4959f4SRob Clark "CRTC_W", 0, INT_MAX); 15606b4959f4SRob Clark if (!prop) 15616b4959f4SRob Clark return -ENOMEM; 15626b4959f4SRob Clark dev->mode_config.prop_crtc_w = prop; 15636b4959f4SRob Clark 15646b4959f4SRob Clark prop = drm_property_create_range(dev, DRM_MODE_PROP_ATOMIC, 15656b4959f4SRob Clark "CRTC_H", 0, INT_MAX); 15666b4959f4SRob Clark if (!prop) 15676b4959f4SRob Clark return -ENOMEM; 15686b4959f4SRob Clark dev->mode_config.prop_crtc_h = prop; 15696b4959f4SRob Clark 15706b4959f4SRob Clark prop = drm_property_create_object(dev, DRM_MODE_PROP_ATOMIC, 15716b4959f4SRob Clark "FB_ID", DRM_MODE_OBJECT_FB); 15726b4959f4SRob Clark if (!prop) 15736b4959f4SRob Clark return -ENOMEM; 15746b4959f4SRob Clark dev->mode_config.prop_fb_id = prop; 15756b4959f4SRob Clark 15766b4959f4SRob Clark prop = drm_property_create_object(dev, DRM_MODE_PROP_ATOMIC, 15776b4959f4SRob Clark "CRTC_ID", DRM_MODE_OBJECT_CRTC); 15786b4959f4SRob Clark if (!prop) 15796b4959f4SRob Clark return -ENOMEM; 15806b4959f4SRob Clark dev->mode_config.prop_crtc_id = prop; 15819922ab5aSRob Clark 1582eab3bbefSDaniel Vetter prop = drm_property_create_bool(dev, DRM_MODE_PROP_ATOMIC, 1583eab3bbefSDaniel Vetter "ACTIVE"); 1584eab3bbefSDaniel Vetter if (!prop) 1585eab3bbefSDaniel Vetter return -ENOMEM; 1586eab3bbefSDaniel Vetter dev->mode_config.prop_active = prop; 1587eab3bbefSDaniel Vetter 1588955f3c33SDaniel Stone prop = drm_property_create(dev, 1589955f3c33SDaniel Stone DRM_MODE_PROP_ATOMIC | DRM_MODE_PROP_BLOB, 1590955f3c33SDaniel Stone "MODE_ID", 0); 1591955f3c33SDaniel Stone if (!prop) 1592955f3c33SDaniel Stone return -ENOMEM; 1593955f3c33SDaniel Stone dev->mode_config.prop_mode_id = prop; 1594955f3c33SDaniel Stone 15955488dc16SLionel Landwerlin prop = drm_property_create(dev, 15965488dc16SLionel Landwerlin DRM_MODE_PROP_BLOB, 15975488dc16SLionel Landwerlin "DEGAMMA_LUT", 0); 15985488dc16SLionel Landwerlin if (!prop) 15995488dc16SLionel Landwerlin return -ENOMEM; 16005488dc16SLionel Landwerlin dev->mode_config.degamma_lut_property = prop; 16015488dc16SLionel Landwerlin 16025488dc16SLionel Landwerlin prop = drm_property_create_range(dev, 16035488dc16SLionel Landwerlin DRM_MODE_PROP_IMMUTABLE, 16045488dc16SLionel Landwerlin "DEGAMMA_LUT_SIZE", 0, UINT_MAX); 16055488dc16SLionel Landwerlin if (!prop) 16065488dc16SLionel Landwerlin return -ENOMEM; 16075488dc16SLionel Landwerlin dev->mode_config.degamma_lut_size_property = prop; 16085488dc16SLionel Landwerlin 16095488dc16SLionel Landwerlin prop = drm_property_create(dev, 16105488dc16SLionel Landwerlin DRM_MODE_PROP_BLOB, 16115488dc16SLionel Landwerlin "CTM", 0); 16125488dc16SLionel Landwerlin if (!prop) 16135488dc16SLionel Landwerlin return -ENOMEM; 16145488dc16SLionel Landwerlin dev->mode_config.ctm_property = prop; 16155488dc16SLionel Landwerlin 16165488dc16SLionel Landwerlin prop = drm_property_create(dev, 16175488dc16SLionel Landwerlin DRM_MODE_PROP_BLOB, 16185488dc16SLionel Landwerlin "GAMMA_LUT", 0); 16195488dc16SLionel Landwerlin if (!prop) 16205488dc16SLionel Landwerlin return -ENOMEM; 16215488dc16SLionel Landwerlin dev->mode_config.gamma_lut_property = prop; 16225488dc16SLionel Landwerlin 16235488dc16SLionel Landwerlin prop = drm_property_create_range(dev, 16245488dc16SLionel Landwerlin DRM_MODE_PROP_IMMUTABLE, 16255488dc16SLionel Landwerlin "GAMMA_LUT_SIZE", 0, UINT_MAX); 16265488dc16SLionel Landwerlin if (!prop) 16275488dc16SLionel Landwerlin return -ENOMEM; 16285488dc16SLionel Landwerlin dev->mode_config.gamma_lut_size_property = prop; 16295488dc16SLionel Landwerlin 16309922ab5aSRob Clark return 0; 16319922ab5aSRob Clark } 16329922ab5aSRob Clark 1633f453ba04SDave Airlie /** 1634f453ba04SDave Airlie * drm_mode_create_dvi_i_properties - create DVI-I specific connector properties 1635f453ba04SDave Airlie * @dev: DRM device 1636f453ba04SDave Airlie * 1637f453ba04SDave Airlie * Called by a driver the first time a DVI-I connector is made. 1638f453ba04SDave Airlie */ 1639f453ba04SDave Airlie int drm_mode_create_dvi_i_properties(struct drm_device *dev) 1640f453ba04SDave Airlie { 1641f453ba04SDave Airlie struct drm_property *dvi_i_selector; 1642f453ba04SDave Airlie struct drm_property *dvi_i_subconnector; 1643f453ba04SDave Airlie 1644f453ba04SDave Airlie if (dev->mode_config.dvi_i_select_subconnector_property) 1645f453ba04SDave Airlie return 0; 1646f453ba04SDave Airlie 1647f453ba04SDave Airlie dvi_i_selector = 16484a67d391SSascha Hauer drm_property_create_enum(dev, 0, 1649f453ba04SDave Airlie "select subconnector", 16504a67d391SSascha Hauer drm_dvi_i_select_enum_list, 1651f453ba04SDave Airlie ARRAY_SIZE(drm_dvi_i_select_enum_list)); 1652f453ba04SDave Airlie dev->mode_config.dvi_i_select_subconnector_property = dvi_i_selector; 1653f453ba04SDave Airlie 16544a67d391SSascha Hauer dvi_i_subconnector = drm_property_create_enum(dev, DRM_MODE_PROP_IMMUTABLE, 1655f453ba04SDave Airlie "subconnector", 16564a67d391SSascha Hauer drm_dvi_i_subconnector_enum_list, 1657f453ba04SDave Airlie ARRAY_SIZE(drm_dvi_i_subconnector_enum_list)); 1658f453ba04SDave Airlie dev->mode_config.dvi_i_subconnector_property = dvi_i_subconnector; 1659f453ba04SDave Airlie 1660f453ba04SDave Airlie return 0; 1661f453ba04SDave Airlie } 1662f453ba04SDave Airlie EXPORT_SYMBOL(drm_mode_create_dvi_i_properties); 1663f453ba04SDave Airlie 1664f453ba04SDave Airlie /** 1665f453ba04SDave Airlie * drm_create_tv_properties - create TV specific connector properties 1666f453ba04SDave Airlie * @dev: DRM device 1667f453ba04SDave Airlie * @num_modes: number of different TV formats (modes) supported 1668f453ba04SDave Airlie * @modes: array of pointers to strings containing name of each format 1669f453ba04SDave Airlie * 1670f453ba04SDave Airlie * Called by a driver's TV initialization routine, this function creates 1671f453ba04SDave Airlie * the TV specific connector properties for a given device. Caller is 1672f453ba04SDave Airlie * responsible for allocating a list of format names and passing them to 1673f453ba04SDave Airlie * this routine. 1674f453ba04SDave Airlie */ 16752f763312SThierry Reding int drm_mode_create_tv_properties(struct drm_device *dev, 16762f763312SThierry Reding unsigned int num_modes, 1677b7c914b3SVille Syrjälä const char * const modes[]) 1678f453ba04SDave Airlie { 1679f453ba04SDave Airlie struct drm_property *tv_selector; 1680f453ba04SDave Airlie struct drm_property *tv_subconnector; 16812f763312SThierry Reding unsigned int i; 1682f453ba04SDave Airlie 1683f453ba04SDave Airlie if (dev->mode_config.tv_select_subconnector_property) 1684f453ba04SDave Airlie return 0; 1685f453ba04SDave Airlie 1686f453ba04SDave Airlie /* 1687f453ba04SDave Airlie * Basic connector properties 1688f453ba04SDave Airlie */ 16894a67d391SSascha Hauer tv_selector = drm_property_create_enum(dev, 0, 1690f453ba04SDave Airlie "select subconnector", 16914a67d391SSascha Hauer drm_tv_select_enum_list, 1692f453ba04SDave Airlie ARRAY_SIZE(drm_tv_select_enum_list)); 169348aa1e74SInsu Yun if (!tv_selector) 169448aa1e74SInsu Yun goto nomem; 169548aa1e74SInsu Yun 1696f453ba04SDave Airlie dev->mode_config.tv_select_subconnector_property = tv_selector; 1697f453ba04SDave Airlie 1698f453ba04SDave Airlie tv_subconnector = 16994a67d391SSascha Hauer drm_property_create_enum(dev, DRM_MODE_PROP_IMMUTABLE, 17004a67d391SSascha Hauer "subconnector", 17014a67d391SSascha Hauer drm_tv_subconnector_enum_list, 1702f453ba04SDave Airlie ARRAY_SIZE(drm_tv_subconnector_enum_list)); 170348aa1e74SInsu Yun if (!tv_subconnector) 170448aa1e74SInsu Yun goto nomem; 1705f453ba04SDave Airlie dev->mode_config.tv_subconnector_property = tv_subconnector; 1706f453ba04SDave Airlie 1707f453ba04SDave Airlie /* 1708f453ba04SDave Airlie * Other, TV specific properties: margins & TV modes. 1709f453ba04SDave Airlie */ 1710f453ba04SDave Airlie dev->mode_config.tv_left_margin_property = 1711d9bc3c02SSascha Hauer drm_property_create_range(dev, 0, "left margin", 0, 100); 171248aa1e74SInsu Yun if (!dev->mode_config.tv_left_margin_property) 171348aa1e74SInsu Yun goto nomem; 1714f453ba04SDave Airlie 1715f453ba04SDave Airlie dev->mode_config.tv_right_margin_property = 1716d9bc3c02SSascha Hauer drm_property_create_range(dev, 0, "right margin", 0, 100); 171748aa1e74SInsu Yun if (!dev->mode_config.tv_right_margin_property) 171848aa1e74SInsu Yun goto nomem; 1719f453ba04SDave Airlie 1720f453ba04SDave Airlie dev->mode_config.tv_top_margin_property = 1721d9bc3c02SSascha Hauer drm_property_create_range(dev, 0, "top margin", 0, 100); 172248aa1e74SInsu Yun if (!dev->mode_config.tv_top_margin_property) 172348aa1e74SInsu Yun goto nomem; 1724f453ba04SDave Airlie 1725f453ba04SDave Airlie dev->mode_config.tv_bottom_margin_property = 1726d9bc3c02SSascha Hauer drm_property_create_range(dev, 0, "bottom margin", 0, 100); 172748aa1e74SInsu Yun if (!dev->mode_config.tv_bottom_margin_property) 172848aa1e74SInsu Yun goto nomem; 1729f453ba04SDave Airlie 1730f453ba04SDave Airlie dev->mode_config.tv_mode_property = 1731f453ba04SDave Airlie drm_property_create(dev, DRM_MODE_PROP_ENUM, 1732f453ba04SDave Airlie "mode", num_modes); 173348aa1e74SInsu Yun if (!dev->mode_config.tv_mode_property) 173448aa1e74SInsu Yun goto nomem; 173548aa1e74SInsu Yun 1736f453ba04SDave Airlie for (i = 0; i < num_modes; i++) 1737f453ba04SDave Airlie drm_property_add_enum(dev->mode_config.tv_mode_property, i, 1738f453ba04SDave Airlie i, modes[i]); 1739f453ba04SDave Airlie 1740b6b7902eSFrancisco Jerez dev->mode_config.tv_brightness_property = 1741d9bc3c02SSascha Hauer drm_property_create_range(dev, 0, "brightness", 0, 100); 174248aa1e74SInsu Yun if (!dev->mode_config.tv_brightness_property) 174348aa1e74SInsu Yun goto nomem; 1744b6b7902eSFrancisco Jerez 1745b6b7902eSFrancisco Jerez dev->mode_config.tv_contrast_property = 1746d9bc3c02SSascha Hauer drm_property_create_range(dev, 0, "contrast", 0, 100); 174748aa1e74SInsu Yun if (!dev->mode_config.tv_contrast_property) 174848aa1e74SInsu Yun goto nomem; 1749b6b7902eSFrancisco Jerez 1750b6b7902eSFrancisco Jerez dev->mode_config.tv_flicker_reduction_property = 1751d9bc3c02SSascha Hauer drm_property_create_range(dev, 0, "flicker reduction", 0, 100); 175248aa1e74SInsu Yun if (!dev->mode_config.tv_flicker_reduction_property) 175348aa1e74SInsu Yun goto nomem; 1754b6b7902eSFrancisco Jerez 1755a75f0236SFrancisco Jerez dev->mode_config.tv_overscan_property = 1756d9bc3c02SSascha Hauer drm_property_create_range(dev, 0, "overscan", 0, 100); 175748aa1e74SInsu Yun if (!dev->mode_config.tv_overscan_property) 175848aa1e74SInsu Yun goto nomem; 1759a75f0236SFrancisco Jerez 1760a75f0236SFrancisco Jerez dev->mode_config.tv_saturation_property = 1761d9bc3c02SSascha Hauer drm_property_create_range(dev, 0, "saturation", 0, 100); 176248aa1e74SInsu Yun if (!dev->mode_config.tv_saturation_property) 176348aa1e74SInsu Yun goto nomem; 1764a75f0236SFrancisco Jerez 1765a75f0236SFrancisco Jerez dev->mode_config.tv_hue_property = 1766d9bc3c02SSascha Hauer drm_property_create_range(dev, 0, "hue", 0, 100); 176748aa1e74SInsu Yun if (!dev->mode_config.tv_hue_property) 176848aa1e74SInsu Yun goto nomem; 1769a75f0236SFrancisco Jerez 1770f453ba04SDave Airlie return 0; 177148aa1e74SInsu Yun nomem: 177248aa1e74SInsu Yun return -ENOMEM; 1773f453ba04SDave Airlie } 1774f453ba04SDave Airlie EXPORT_SYMBOL(drm_mode_create_tv_properties); 1775f453ba04SDave Airlie 1776f453ba04SDave Airlie /** 1777f453ba04SDave Airlie * drm_mode_create_scaling_mode_property - create scaling mode property 1778f453ba04SDave Airlie * @dev: DRM device 1779f453ba04SDave Airlie * 1780f453ba04SDave Airlie * Called by a driver the first time it's needed, must be attached to desired 1781f453ba04SDave Airlie * connectors. 1782f453ba04SDave Airlie */ 1783f453ba04SDave Airlie int drm_mode_create_scaling_mode_property(struct drm_device *dev) 1784f453ba04SDave Airlie { 1785f453ba04SDave Airlie struct drm_property *scaling_mode; 1786f453ba04SDave Airlie 1787f453ba04SDave Airlie if (dev->mode_config.scaling_mode_property) 1788f453ba04SDave Airlie return 0; 1789f453ba04SDave Airlie 1790f453ba04SDave Airlie scaling_mode = 17914a67d391SSascha Hauer drm_property_create_enum(dev, 0, "scaling mode", 17924a67d391SSascha Hauer drm_scaling_mode_enum_list, 1793f453ba04SDave Airlie ARRAY_SIZE(drm_scaling_mode_enum_list)); 1794f453ba04SDave Airlie 1795f453ba04SDave Airlie dev->mode_config.scaling_mode_property = scaling_mode; 1796f453ba04SDave Airlie 1797f453ba04SDave Airlie return 0; 1798f453ba04SDave Airlie } 1799f453ba04SDave Airlie EXPORT_SYMBOL(drm_mode_create_scaling_mode_property); 1800f453ba04SDave Airlie 1801f453ba04SDave Airlie /** 1802ff587e45SVandana Kannan * drm_mode_create_aspect_ratio_property - create aspect ratio property 1803ff587e45SVandana Kannan * @dev: DRM device 1804ff587e45SVandana Kannan * 1805ff587e45SVandana Kannan * Called by a driver the first time it's needed, must be attached to desired 1806ff587e45SVandana Kannan * connectors. 1807ff587e45SVandana Kannan * 1808ff587e45SVandana Kannan * Returns: 18091a498633SDaniel Vetter * Zero on success, negative errno on failure. 1810ff587e45SVandana Kannan */ 1811ff587e45SVandana Kannan int drm_mode_create_aspect_ratio_property(struct drm_device *dev) 1812ff587e45SVandana Kannan { 1813ff587e45SVandana Kannan if (dev->mode_config.aspect_ratio_property) 1814ff587e45SVandana Kannan return 0; 1815ff587e45SVandana Kannan 1816ff587e45SVandana Kannan dev->mode_config.aspect_ratio_property = 1817ff587e45SVandana Kannan drm_property_create_enum(dev, 0, "aspect ratio", 1818ff587e45SVandana Kannan drm_aspect_ratio_enum_list, 1819ff587e45SVandana Kannan ARRAY_SIZE(drm_aspect_ratio_enum_list)); 1820ff587e45SVandana Kannan 1821ff587e45SVandana Kannan if (dev->mode_config.aspect_ratio_property == NULL) 1822ff587e45SVandana Kannan return -ENOMEM; 1823ff587e45SVandana Kannan 1824ff587e45SVandana Kannan return 0; 1825ff587e45SVandana Kannan } 1826ff587e45SVandana Kannan EXPORT_SYMBOL(drm_mode_create_aspect_ratio_property); 1827ff587e45SVandana Kannan 1828ff587e45SVandana Kannan /** 1829884840aaSJakob Bornecrantz * drm_mode_create_dirty_property - create dirty property 1830884840aaSJakob Bornecrantz * @dev: DRM device 1831884840aaSJakob Bornecrantz * 1832884840aaSJakob Bornecrantz * Called by a driver the first time it's needed, must be attached to desired 1833884840aaSJakob Bornecrantz * connectors. 1834884840aaSJakob Bornecrantz */ 1835884840aaSJakob Bornecrantz int drm_mode_create_dirty_info_property(struct drm_device *dev) 1836884840aaSJakob Bornecrantz { 1837884840aaSJakob Bornecrantz struct drm_property *dirty_info; 1838884840aaSJakob Bornecrantz 1839884840aaSJakob Bornecrantz if (dev->mode_config.dirty_info_property) 1840884840aaSJakob Bornecrantz return 0; 1841884840aaSJakob Bornecrantz 1842884840aaSJakob Bornecrantz dirty_info = 18434a67d391SSascha Hauer drm_property_create_enum(dev, DRM_MODE_PROP_IMMUTABLE, 1844884840aaSJakob Bornecrantz "dirty", 18454a67d391SSascha Hauer drm_dirty_info_enum_list, 1846884840aaSJakob Bornecrantz ARRAY_SIZE(drm_dirty_info_enum_list)); 1847884840aaSJakob Bornecrantz dev->mode_config.dirty_info_property = dirty_info; 1848884840aaSJakob Bornecrantz 1849884840aaSJakob Bornecrantz return 0; 1850884840aaSJakob Bornecrantz } 1851884840aaSJakob Bornecrantz EXPORT_SYMBOL(drm_mode_create_dirty_info_property); 1852884840aaSJakob Bornecrantz 18535bb2bbf5SDave Airlie /** 18545bb2bbf5SDave Airlie * drm_mode_create_suggested_offset_properties - create suggests offset properties 18555bb2bbf5SDave Airlie * @dev: DRM device 18565bb2bbf5SDave Airlie * 18575bb2bbf5SDave Airlie * Create the the suggested x/y offset property for connectors. 18585bb2bbf5SDave Airlie */ 18595bb2bbf5SDave Airlie int drm_mode_create_suggested_offset_properties(struct drm_device *dev) 18605bb2bbf5SDave Airlie { 18615bb2bbf5SDave Airlie if (dev->mode_config.suggested_x_property && dev->mode_config.suggested_y_property) 18625bb2bbf5SDave Airlie return 0; 18635bb2bbf5SDave Airlie 18645bb2bbf5SDave Airlie dev->mode_config.suggested_x_property = 18655bb2bbf5SDave Airlie drm_property_create_range(dev, DRM_MODE_PROP_IMMUTABLE, "suggested X", 0, 0xffffffff); 18665bb2bbf5SDave Airlie 18675bb2bbf5SDave Airlie dev->mode_config.suggested_y_property = 18685bb2bbf5SDave Airlie drm_property_create_range(dev, DRM_MODE_PROP_IMMUTABLE, "suggested Y", 0, 0xffffffff); 18695bb2bbf5SDave Airlie 18705bb2bbf5SDave Airlie if (dev->mode_config.suggested_x_property == NULL || 18715bb2bbf5SDave Airlie dev->mode_config.suggested_y_property == NULL) 18725bb2bbf5SDave Airlie return -ENOMEM; 18735bb2bbf5SDave Airlie return 0; 18745bb2bbf5SDave Airlie } 18755bb2bbf5SDave Airlie EXPORT_SYMBOL(drm_mode_create_suggested_offset_properties); 18765bb2bbf5SDave Airlie 1877f453ba04SDave Airlie /** 1878f453ba04SDave Airlie * drm_mode_getresources - get graphics configuration 1879065a50edSDaniel Vetter * @dev: drm device for the ioctl 1880065a50edSDaniel Vetter * @data: data pointer for the ioctl 1881065a50edSDaniel Vetter * @file_priv: drm file for the ioctl call 1882f453ba04SDave Airlie * 1883f453ba04SDave Airlie * Construct a set of configuration description structures and return 1884f453ba04SDave Airlie * them to the user, including CRTC, connector and framebuffer configuration. 1885f453ba04SDave Airlie * 1886f453ba04SDave Airlie * Called by the user via ioctl. 1887f453ba04SDave Airlie * 1888c8e32cc1SDaniel Vetter * Returns: 18891a498633SDaniel Vetter * Zero on success, negative errno on failure. 1890f453ba04SDave Airlie */ 1891f453ba04SDave Airlie int drm_mode_getresources(struct drm_device *dev, void *data, 1892f453ba04SDave Airlie struct drm_file *file_priv) 1893f453ba04SDave Airlie { 1894f453ba04SDave Airlie struct drm_mode_card_res *card_res = data; 1895f453ba04SDave Airlie struct list_head *lh; 1896f453ba04SDave Airlie struct drm_framebuffer *fb; 1897f453ba04SDave Airlie struct drm_connector *connector; 1898f453ba04SDave Airlie struct drm_crtc *crtc; 1899f453ba04SDave Airlie struct drm_encoder *encoder; 1900f453ba04SDave Airlie int ret = 0; 1901f453ba04SDave Airlie int connector_count = 0; 1902f453ba04SDave Airlie int crtc_count = 0; 1903f453ba04SDave Airlie int fb_count = 0; 1904f453ba04SDave Airlie int encoder_count = 0; 19059c7060f7SDaniel Vetter int copied = 0; 1906f453ba04SDave Airlie uint32_t __user *fb_id; 1907f453ba04SDave Airlie uint32_t __user *crtc_id; 1908f453ba04SDave Airlie uint32_t __user *connector_id; 1909f453ba04SDave Airlie uint32_t __user *encoder_id; 1910f453ba04SDave Airlie 1911fb3b06c8SDave Airlie if (!drm_core_check_feature(dev, DRIVER_MODESET)) 1912fb3b06c8SDave Airlie return -EINVAL; 1913fb3b06c8SDave Airlie 1914f453ba04SDave Airlie 19154b096ac1SDaniel Vetter mutex_lock(&file_priv->fbs_lock); 1916f453ba04SDave Airlie /* 1917f453ba04SDave Airlie * For the non-control nodes we need to limit the list of resources 1918f453ba04SDave Airlie * by IDs in the group list for this node 1919f453ba04SDave Airlie */ 1920f453ba04SDave Airlie list_for_each(lh, &file_priv->fbs) 1921f453ba04SDave Airlie fb_count++; 1922f453ba04SDave Airlie 19234b096ac1SDaniel Vetter /* handle this in 4 parts */ 19244b096ac1SDaniel Vetter /* FBs */ 19254b096ac1SDaniel Vetter if (card_res->count_fbs >= fb_count) { 19264b096ac1SDaniel Vetter copied = 0; 19274b096ac1SDaniel Vetter fb_id = (uint32_t __user *)(unsigned long)card_res->fb_id_ptr; 19284b096ac1SDaniel Vetter list_for_each_entry(fb, &file_priv->fbs, filp_head) { 19294b096ac1SDaniel Vetter if (put_user(fb->base.id, fb_id + copied)) { 19304b096ac1SDaniel Vetter mutex_unlock(&file_priv->fbs_lock); 19314b096ac1SDaniel Vetter return -EFAULT; 19324b096ac1SDaniel Vetter } 19334b096ac1SDaniel Vetter copied++; 19344b096ac1SDaniel Vetter } 19354b096ac1SDaniel Vetter } 19364b096ac1SDaniel Vetter card_res->count_fbs = fb_count; 19374b096ac1SDaniel Vetter mutex_unlock(&file_priv->fbs_lock); 19384b096ac1SDaniel Vetter 1939fcf93f69SDaniel Vetter /* mode_config.mutex protects the connector list against e.g. DP MST 1940fcf93f69SDaniel Vetter * connector hot-adding. CRTC/Plane lists are invariant. */ 1941fcf93f69SDaniel Vetter mutex_lock(&dev->mode_config.mutex); 1942e4f62546SDaniel Vetter drm_for_each_crtc(crtc, dev) 1943f453ba04SDave Airlie crtc_count++; 1944f453ba04SDave Airlie 19459a9f5ce8SDaniel Vetter drm_for_each_connector(connector, dev) 1946f453ba04SDave Airlie connector_count++; 1947f453ba04SDave Airlie 1948e4f62546SDaniel Vetter drm_for_each_encoder(encoder, dev) 1949f453ba04SDave Airlie encoder_count++; 1950f453ba04SDave Airlie 1951f453ba04SDave Airlie card_res->max_height = dev->mode_config.max_height; 1952f453ba04SDave Airlie card_res->min_height = dev->mode_config.min_height; 1953f453ba04SDave Airlie card_res->max_width = dev->mode_config.max_width; 1954f453ba04SDave Airlie card_res->min_width = dev->mode_config.min_width; 1955f453ba04SDave Airlie 1956f453ba04SDave Airlie /* CRTCs */ 1957f453ba04SDave Airlie if (card_res->count_crtcs >= crtc_count) { 1958f453ba04SDave Airlie copied = 0; 1959f453ba04SDave Airlie crtc_id = (uint32_t __user *)(unsigned long)card_res->crtc_id_ptr; 19606295d607SDaniel Vetter drm_for_each_crtc(crtc, dev) { 1961fa3ab4c2SVille Syrjälä DRM_DEBUG_KMS("[CRTC:%d:%s]\n", 1962fa3ab4c2SVille Syrjälä crtc->base.id, crtc->name); 1963f453ba04SDave Airlie if (put_user(crtc->base.id, crtc_id + copied)) { 1964f453ba04SDave Airlie ret = -EFAULT; 1965f453ba04SDave Airlie goto out; 1966f453ba04SDave Airlie } 1967f453ba04SDave Airlie copied++; 1968f453ba04SDave Airlie } 1969f453ba04SDave Airlie } 1970f453ba04SDave Airlie card_res->count_crtcs = crtc_count; 1971f453ba04SDave Airlie 1972f453ba04SDave Airlie /* Encoders */ 1973f453ba04SDave Airlie if (card_res->count_encoders >= encoder_count) { 1974f453ba04SDave Airlie copied = 0; 1975f453ba04SDave Airlie encoder_id = (uint32_t __user *)(unsigned long)card_res->encoder_id_ptr; 19766295d607SDaniel Vetter drm_for_each_encoder(encoder, dev) { 19779440106bSJerome Glisse DRM_DEBUG_KMS("[ENCODER:%d:%s]\n", encoder->base.id, 197883a8cfd3SJani Nikula encoder->name); 1979f453ba04SDave Airlie if (put_user(encoder->base.id, encoder_id + 1980f453ba04SDave Airlie copied)) { 1981f453ba04SDave Airlie ret = -EFAULT; 1982f453ba04SDave Airlie goto out; 1983f453ba04SDave Airlie } 1984f453ba04SDave Airlie copied++; 1985f453ba04SDave Airlie } 1986f453ba04SDave Airlie } 1987f453ba04SDave Airlie card_res->count_encoders = encoder_count; 1988f453ba04SDave Airlie 1989f453ba04SDave Airlie /* Connectors */ 1990f453ba04SDave Airlie if (card_res->count_connectors >= connector_count) { 1991f453ba04SDave Airlie copied = 0; 1992f453ba04SDave Airlie connector_id = (uint32_t __user *)(unsigned long)card_res->connector_id_ptr; 19936295d607SDaniel Vetter drm_for_each_connector(connector, dev) { 19949440106bSJerome Glisse DRM_DEBUG_KMS("[CONNECTOR:%d:%s]\n", 19959440106bSJerome Glisse connector->base.id, 199625933820SJani Nikula connector->name); 1997f453ba04SDave Airlie if (put_user(connector->base.id, 1998f453ba04SDave Airlie connector_id + copied)) { 1999f453ba04SDave Airlie ret = -EFAULT; 2000f453ba04SDave Airlie goto out; 2001f453ba04SDave Airlie } 2002f453ba04SDave Airlie copied++; 2003f453ba04SDave Airlie } 2004f453ba04SDave Airlie } 2005f453ba04SDave Airlie card_res->count_connectors = connector_count; 2006f453ba04SDave Airlie 20079440106bSJerome Glisse DRM_DEBUG_KMS("CRTC[%d] CONNECTORS[%d] ENCODERS[%d]\n", card_res->count_crtcs, 2008f453ba04SDave Airlie card_res->count_connectors, card_res->count_encoders); 2009f453ba04SDave Airlie 2010f453ba04SDave Airlie out: 2011fcf93f69SDaniel Vetter mutex_unlock(&dev->mode_config.mutex); 2012f453ba04SDave Airlie return ret; 2013f453ba04SDave Airlie } 2014f453ba04SDave Airlie 2015f453ba04SDave Airlie /** 2016f453ba04SDave Airlie * drm_mode_getcrtc - get CRTC configuration 2017065a50edSDaniel Vetter * @dev: drm device for the ioctl 2018065a50edSDaniel Vetter * @data: data pointer for the ioctl 2019065a50edSDaniel Vetter * @file_priv: drm file for the ioctl call 2020f453ba04SDave Airlie * 2021f453ba04SDave Airlie * Construct a CRTC configuration structure to return to the user. 2022f453ba04SDave Airlie * 2023f453ba04SDave Airlie * Called by the user via ioctl. 2024f453ba04SDave Airlie * 2025c8e32cc1SDaniel Vetter * Returns: 20261a498633SDaniel Vetter * Zero on success, negative errno on failure. 2027f453ba04SDave Airlie */ 2028f453ba04SDave Airlie int drm_mode_getcrtc(struct drm_device *dev, 2029f453ba04SDave Airlie void *data, struct drm_file *file_priv) 2030f453ba04SDave Airlie { 2031f453ba04SDave Airlie struct drm_mode_crtc *crtc_resp = data; 2032f453ba04SDave Airlie struct drm_crtc *crtc; 2033f453ba04SDave Airlie 2034fb3b06c8SDave Airlie if (!drm_core_check_feature(dev, DRIVER_MODESET)) 2035fb3b06c8SDave Airlie return -EINVAL; 2036fb3b06c8SDave Airlie 2037a2b34e22SRob Clark crtc = drm_crtc_find(dev, crtc_resp->crtc_id); 2038fcf93f69SDaniel Vetter if (!crtc) 2039fcf93f69SDaniel Vetter return -ENOENT; 2040f453ba04SDave Airlie 2041fcf93f69SDaniel Vetter drm_modeset_lock_crtc(crtc, crtc->primary); 2042f453ba04SDave Airlie crtc_resp->gamma_size = crtc->gamma_size; 2043f4510a27SMatt Roper if (crtc->primary->fb) 2044f4510a27SMatt Roper crtc_resp->fb_id = crtc->primary->fb->base.id; 2045f453ba04SDave Airlie else 2046f453ba04SDave Airlie crtc_resp->fb_id = 0; 2047f453ba04SDave Airlie 204831c946e8SDaniel Vetter if (crtc->state) { 204931c946e8SDaniel Vetter crtc_resp->x = crtc->primary->state->src_x >> 16; 205031c946e8SDaniel Vetter crtc_resp->y = crtc->primary->state->src_y >> 16; 205131c946e8SDaniel Vetter if (crtc->state->enable) { 2052934a8a89SDaniel Stone drm_mode_convert_to_umode(&crtc_resp->mode, &crtc->state->mode); 205331c946e8SDaniel Vetter crtc_resp->mode_valid = 1; 2054f453ba04SDave Airlie 205531c946e8SDaniel Vetter } else { 205631c946e8SDaniel Vetter crtc_resp->mode_valid = 0; 205731c946e8SDaniel Vetter } 205831c946e8SDaniel Vetter } else { 205931c946e8SDaniel Vetter crtc_resp->x = crtc->x; 206031c946e8SDaniel Vetter crtc_resp->y = crtc->y; 206131c946e8SDaniel Vetter if (crtc->enabled) { 2062934a8a89SDaniel Stone drm_mode_convert_to_umode(&crtc_resp->mode, &crtc->mode); 2063f453ba04SDave Airlie crtc_resp->mode_valid = 1; 2064f453ba04SDave Airlie 2065f453ba04SDave Airlie } else { 2066f453ba04SDave Airlie crtc_resp->mode_valid = 0; 2067f453ba04SDave Airlie } 206831c946e8SDaniel Vetter } 2069fcf93f69SDaniel Vetter drm_modeset_unlock_crtc(crtc); 2070f453ba04SDave Airlie 2071baf698b0SDaniel Vetter return 0; 2072f453ba04SDave Airlie } 2073f453ba04SDave Airlie 207461d8e328SDamien Lespiau static bool drm_mode_expose_to_userspace(const struct drm_display_mode *mode, 207561d8e328SDamien Lespiau const struct drm_file *file_priv) 207661d8e328SDamien Lespiau { 207761d8e328SDamien Lespiau /* 207861d8e328SDamien Lespiau * If user-space hasn't configured the driver to expose the stereo 3D 207961d8e328SDamien Lespiau * modes, don't expose them. 208061d8e328SDamien Lespiau */ 208161d8e328SDamien Lespiau if (!file_priv->stereo_allowed && drm_mode_is_stereo(mode)) 208261d8e328SDamien Lespiau return false; 208361d8e328SDamien Lespiau 208461d8e328SDamien Lespiau return true; 208561d8e328SDamien Lespiau } 208661d8e328SDamien Lespiau 2087abd69c55SDaniel Vetter static struct drm_encoder *drm_connector_get_encoder(struct drm_connector *connector) 2088abd69c55SDaniel Vetter { 2089abd69c55SDaniel Vetter /* For atomic drivers only state objects are synchronously updated and 2090abd69c55SDaniel Vetter * protected by modeset locks, so check those first. */ 2091abd69c55SDaniel Vetter if (connector->state) 2092abd69c55SDaniel Vetter return connector->state->best_encoder; 2093abd69c55SDaniel Vetter return connector->encoder; 2094abd69c55SDaniel Vetter } 2095abd69c55SDaniel Vetter 209695cbf110SRob Clark /* helper for getconnector and getproperties ioctls */ 209788a48e29SRob Clark static int get_properties(struct drm_mode_object *obj, bool atomic, 209895cbf110SRob Clark uint32_t __user *prop_ptr, uint64_t __user *prop_values, 209995cbf110SRob Clark uint32_t *arg_count_props) 210095cbf110SRob Clark { 210188a48e29SRob Clark int props_count; 210288a48e29SRob Clark int i, ret, copied; 210388a48e29SRob Clark 210488a48e29SRob Clark props_count = obj->properties->count; 210588a48e29SRob Clark if (!atomic) 210688a48e29SRob Clark props_count -= obj->properties->atomic_count; 210795cbf110SRob Clark 210895cbf110SRob Clark if ((*arg_count_props >= props_count) && props_count) { 210988a48e29SRob Clark for (i = 0, copied = 0; copied < props_count; i++) { 211095cbf110SRob Clark struct drm_property *prop = obj->properties->properties[i]; 211195cbf110SRob Clark uint64_t val; 211295cbf110SRob Clark 211388a48e29SRob Clark if ((prop->flags & DRM_MODE_PROP_ATOMIC) && !atomic) 211488a48e29SRob Clark continue; 211588a48e29SRob Clark 211695cbf110SRob Clark ret = drm_object_property_get_value(obj, prop, &val); 211795cbf110SRob Clark if (ret) 211895cbf110SRob Clark return ret; 211995cbf110SRob Clark 212095cbf110SRob Clark if (put_user(prop->base.id, prop_ptr + copied)) 212195cbf110SRob Clark return -EFAULT; 212295cbf110SRob Clark 212395cbf110SRob Clark if (put_user(val, prop_values + copied)) 212495cbf110SRob Clark return -EFAULT; 212595cbf110SRob Clark 212695cbf110SRob Clark copied++; 212795cbf110SRob Clark } 212895cbf110SRob Clark } 212995cbf110SRob Clark *arg_count_props = props_count; 213095cbf110SRob Clark 213195cbf110SRob Clark return 0; 213295cbf110SRob Clark } 213395cbf110SRob Clark 2134f453ba04SDave Airlie /** 2135f453ba04SDave Airlie * drm_mode_getconnector - get connector configuration 2136065a50edSDaniel Vetter * @dev: drm device for the ioctl 2137065a50edSDaniel Vetter * @data: data pointer for the ioctl 2138065a50edSDaniel Vetter * @file_priv: drm file for the ioctl call 2139f453ba04SDave Airlie * 2140f453ba04SDave Airlie * Construct a connector configuration structure to return to the user. 2141f453ba04SDave Airlie * 2142f453ba04SDave Airlie * Called by the user via ioctl. 2143f453ba04SDave Airlie * 2144c8e32cc1SDaniel Vetter * Returns: 21451a498633SDaniel Vetter * Zero on success, negative errno on failure. 2146f453ba04SDave Airlie */ 2147f453ba04SDave Airlie int drm_mode_getconnector(struct drm_device *dev, void *data, 2148f453ba04SDave Airlie struct drm_file *file_priv) 2149f453ba04SDave Airlie { 2150f453ba04SDave Airlie struct drm_mode_get_connector *out_resp = data; 2151f453ba04SDave Airlie struct drm_connector *connector; 2152abd69c55SDaniel Vetter struct drm_encoder *encoder; 2153f453ba04SDave Airlie struct drm_display_mode *mode; 2154f453ba04SDave Airlie int mode_count = 0; 2155f453ba04SDave Airlie int encoders_count = 0; 2156f453ba04SDave Airlie int ret = 0; 2157f453ba04SDave Airlie int copied = 0; 2158f453ba04SDave Airlie int i; 2159f453ba04SDave Airlie struct drm_mode_modeinfo u_mode; 2160f453ba04SDave Airlie struct drm_mode_modeinfo __user *mode_ptr; 2161f453ba04SDave Airlie uint32_t __user *encoder_ptr; 2162f453ba04SDave Airlie 2163fb3b06c8SDave Airlie if (!drm_core_check_feature(dev, DRIVER_MODESET)) 2164fb3b06c8SDave Airlie return -EINVAL; 2165fb3b06c8SDave Airlie 2166f453ba04SDave Airlie memset(&u_mode, 0, sizeof(struct drm_mode_modeinfo)); 2167f453ba04SDave Airlie 21689440106bSJerome Glisse DRM_DEBUG_KMS("[CONNECTOR:%d:?]\n", out_resp->connector_id); 2169f453ba04SDave Airlie 21707b24056bSDaniel Vetter mutex_lock(&dev->mode_config.mutex); 2171f453ba04SDave Airlie 2172a2b34e22SRob Clark connector = drm_connector_find(dev, out_resp->connector_id); 2173a2b34e22SRob Clark if (!connector) { 2174f27657f2SVille Syrjälä ret = -ENOENT; 217504bdf441STommi Rantala goto out_unlock; 2176f453ba04SDave Airlie } 2177f453ba04SDave Airlie 217801073b08SThierry Reding for (i = 0; i < DRM_CONNECTOR_MAX_ENCODER; i++) 217901073b08SThierry Reding if (connector->encoder_ids[i] != 0) 2180f453ba04SDave Airlie encoders_count++; 2181f453ba04SDave Airlie 2182f453ba04SDave Airlie if (out_resp->count_modes == 0) { 2183f453ba04SDave Airlie connector->funcs->fill_modes(connector, 2184f453ba04SDave Airlie dev->mode_config.max_width, 2185f453ba04SDave Airlie dev->mode_config.max_height); 2186f453ba04SDave Airlie } 2187f453ba04SDave Airlie 2188f453ba04SDave Airlie /* delayed so we get modes regardless of pre-fill_modes state */ 2189f453ba04SDave Airlie list_for_each_entry(mode, &connector->modes, head) 219061d8e328SDamien Lespiau if (drm_mode_expose_to_userspace(mode, file_priv)) 2191f453ba04SDave Airlie mode_count++; 2192f453ba04SDave Airlie 2193f453ba04SDave Airlie out_resp->connector_id = connector->base.id; 2194f453ba04SDave Airlie out_resp->connector_type = connector->connector_type; 2195f453ba04SDave Airlie out_resp->connector_type_id = connector->connector_type_id; 2196f453ba04SDave Airlie out_resp->mm_width = connector->display_info.width_mm; 2197f453ba04SDave Airlie out_resp->mm_height = connector->display_info.height_mm; 2198f453ba04SDave Airlie out_resp->subpixel = connector->display_info.subpixel_order; 2199f453ba04SDave Airlie out_resp->connection = connector->status; 22002caa80e7SDaniel Vetter 22012caa80e7SDaniel Vetter drm_modeset_lock(&dev->mode_config.connection_mutex, NULL); 2202abd69c55SDaniel Vetter encoder = drm_connector_get_encoder(connector); 2203abd69c55SDaniel Vetter if (encoder) 2204abd69c55SDaniel Vetter out_resp->encoder_id = encoder->base.id; 2205f453ba04SDave Airlie else 2206f453ba04SDave Airlie out_resp->encoder_id = 0; 2207f453ba04SDave Airlie 2208f453ba04SDave Airlie /* 2209f453ba04SDave Airlie * This ioctl is called twice, once to determine how much space is 2210f453ba04SDave Airlie * needed, and the 2nd time to fill it. 2211f453ba04SDave Airlie */ 2212f453ba04SDave Airlie if ((out_resp->count_modes >= mode_count) && mode_count) { 2213f453ba04SDave Airlie copied = 0; 221481f6c7f8SVille Syrjälä mode_ptr = (struct drm_mode_modeinfo __user *)(unsigned long)out_resp->modes_ptr; 2215f453ba04SDave Airlie list_for_each_entry(mode, &connector->modes, head) { 221661d8e328SDamien Lespiau if (!drm_mode_expose_to_userspace(mode, file_priv)) 221761d8e328SDamien Lespiau continue; 221861d8e328SDamien Lespiau 2219934a8a89SDaniel Stone drm_mode_convert_to_umode(&u_mode, mode); 2220f453ba04SDave Airlie if (copy_to_user(mode_ptr + copied, 2221f453ba04SDave Airlie &u_mode, sizeof(u_mode))) { 2222f453ba04SDave Airlie ret = -EFAULT; 2223f453ba04SDave Airlie goto out; 2224f453ba04SDave Airlie } 2225f453ba04SDave Airlie copied++; 2226f453ba04SDave Airlie } 2227f453ba04SDave Airlie } 2228f453ba04SDave Airlie out_resp->count_modes = mode_count; 2229f453ba04SDave Airlie 223088a48e29SRob Clark ret = get_properties(&connector->base, file_priv->atomic, 223195cbf110SRob Clark (uint32_t __user *)(unsigned long)(out_resp->props_ptr), 223295cbf110SRob Clark (uint64_t __user *)(unsigned long)(out_resp->prop_values_ptr), 223395cbf110SRob Clark &out_resp->count_props); 223422b8b13bSRob Clark if (ret) 2235f453ba04SDave Airlie goto out; 2236f453ba04SDave Airlie 2237f453ba04SDave Airlie if ((out_resp->count_encoders >= encoders_count) && encoders_count) { 2238f453ba04SDave Airlie copied = 0; 223981f6c7f8SVille Syrjälä encoder_ptr = (uint32_t __user *)(unsigned long)(out_resp->encoders_ptr); 2240f453ba04SDave Airlie for (i = 0; i < DRM_CONNECTOR_MAX_ENCODER; i++) { 2241f453ba04SDave Airlie if (connector->encoder_ids[i] != 0) { 2242f453ba04SDave Airlie if (put_user(connector->encoder_ids[i], 2243f453ba04SDave Airlie encoder_ptr + copied)) { 2244f453ba04SDave Airlie ret = -EFAULT; 2245f453ba04SDave Airlie goto out; 2246f453ba04SDave Airlie } 2247f453ba04SDave Airlie copied++; 2248f453ba04SDave Airlie } 2249f453ba04SDave Airlie } 2250f453ba04SDave Airlie } 2251f453ba04SDave Airlie out_resp->count_encoders = encoders_count; 2252f453ba04SDave Airlie 2253f453ba04SDave Airlie out: 2254ccfc0865SRob Clark drm_modeset_unlock(&dev->mode_config.connection_mutex); 225504bdf441STommi Rantala 225604bdf441STommi Rantala out_unlock: 22577b24056bSDaniel Vetter mutex_unlock(&dev->mode_config.mutex); 22587b24056bSDaniel Vetter 2259f453ba04SDave Airlie return ret; 2260f453ba04SDave Airlie } 2261f453ba04SDave Airlie 2262abd69c55SDaniel Vetter static struct drm_crtc *drm_encoder_get_crtc(struct drm_encoder *encoder) 2263abd69c55SDaniel Vetter { 2264abd69c55SDaniel Vetter struct drm_connector *connector; 2265abd69c55SDaniel Vetter struct drm_device *dev = encoder->dev; 2266abd69c55SDaniel Vetter bool uses_atomic = false; 2267abd69c55SDaniel Vetter 2268abd69c55SDaniel Vetter /* For atomic drivers only state objects are synchronously updated and 2269abd69c55SDaniel Vetter * protected by modeset locks, so check those first. */ 22706295d607SDaniel Vetter drm_for_each_connector(connector, dev) { 2271abd69c55SDaniel Vetter if (!connector->state) 2272abd69c55SDaniel Vetter continue; 2273abd69c55SDaniel Vetter 2274abd69c55SDaniel Vetter uses_atomic = true; 2275abd69c55SDaniel Vetter 2276abd69c55SDaniel Vetter if (connector->state->best_encoder != encoder) 2277abd69c55SDaniel Vetter continue; 2278abd69c55SDaniel Vetter 2279abd69c55SDaniel Vetter return connector->state->crtc; 2280abd69c55SDaniel Vetter } 2281abd69c55SDaniel Vetter 2282abd69c55SDaniel Vetter /* Don't return stale data (e.g. pending async disable). */ 2283abd69c55SDaniel Vetter if (uses_atomic) 2284abd69c55SDaniel Vetter return NULL; 2285abd69c55SDaniel Vetter 2286abd69c55SDaniel Vetter return encoder->crtc; 2287abd69c55SDaniel Vetter } 2288abd69c55SDaniel Vetter 2289c8e32cc1SDaniel Vetter /** 2290c8e32cc1SDaniel Vetter * drm_mode_getencoder - get encoder configuration 2291c8e32cc1SDaniel Vetter * @dev: drm device for the ioctl 2292c8e32cc1SDaniel Vetter * @data: data pointer for the ioctl 2293c8e32cc1SDaniel Vetter * @file_priv: drm file for the ioctl call 2294c8e32cc1SDaniel Vetter * 2295c8e32cc1SDaniel Vetter * Construct a encoder configuration structure to return to the user. 2296c8e32cc1SDaniel Vetter * 2297c8e32cc1SDaniel Vetter * Called by the user via ioctl. 2298c8e32cc1SDaniel Vetter * 2299c8e32cc1SDaniel Vetter * Returns: 23001a498633SDaniel Vetter * Zero on success, negative errno on failure. 2301c8e32cc1SDaniel Vetter */ 2302f453ba04SDave Airlie int drm_mode_getencoder(struct drm_device *dev, void *data, 2303f453ba04SDave Airlie struct drm_file *file_priv) 2304f453ba04SDave Airlie { 2305f453ba04SDave Airlie struct drm_mode_get_encoder *enc_resp = data; 2306f453ba04SDave Airlie struct drm_encoder *encoder; 2307abd69c55SDaniel Vetter struct drm_crtc *crtc; 2308f453ba04SDave Airlie 2309fb3b06c8SDave Airlie if (!drm_core_check_feature(dev, DRIVER_MODESET)) 2310fb3b06c8SDave Airlie return -EINVAL; 2311fb3b06c8SDave Airlie 2312a2b34e22SRob Clark encoder = drm_encoder_find(dev, enc_resp->encoder_id); 2313fcf93f69SDaniel Vetter if (!encoder) 2314fcf93f69SDaniel Vetter return -ENOENT; 2315f453ba04SDave Airlie 2316fcf93f69SDaniel Vetter drm_modeset_lock(&dev->mode_config.connection_mutex, NULL); 2317abd69c55SDaniel Vetter crtc = drm_encoder_get_crtc(encoder); 2318abd69c55SDaniel Vetter if (crtc) 2319abd69c55SDaniel Vetter enc_resp->crtc_id = crtc->base.id; 2320f453ba04SDave Airlie else 2321f453ba04SDave Airlie enc_resp->crtc_id = 0; 2322fcf93f69SDaniel Vetter drm_modeset_unlock(&dev->mode_config.connection_mutex); 2323fcf93f69SDaniel Vetter 2324f453ba04SDave Airlie enc_resp->encoder_type = encoder->encoder_type; 2325f453ba04SDave Airlie enc_resp->encoder_id = encoder->base.id; 2326f453ba04SDave Airlie enc_resp->possible_crtcs = encoder->possible_crtcs; 2327f453ba04SDave Airlie enc_resp->possible_clones = encoder->possible_clones; 2328f453ba04SDave Airlie 2329baf698b0SDaniel Vetter return 0; 2330f453ba04SDave Airlie } 2331f453ba04SDave Airlie 2332f453ba04SDave Airlie /** 2333c8e32cc1SDaniel Vetter * drm_mode_getplane_res - enumerate all plane resources 23348cf5c917SJesse Barnes * @dev: DRM device 23358cf5c917SJesse Barnes * @data: ioctl data 23368cf5c917SJesse Barnes * @file_priv: DRM file info 23378cf5c917SJesse Barnes * 2338c8e32cc1SDaniel Vetter * Construct a list of plane ids to return to the user. 2339c8e32cc1SDaniel Vetter * 2340c8e32cc1SDaniel Vetter * Called by the user via ioctl. 2341c8e32cc1SDaniel Vetter * 2342c8e32cc1SDaniel Vetter * Returns: 23431a498633SDaniel Vetter * Zero on success, negative errno on failure. 23448cf5c917SJesse Barnes */ 23458cf5c917SJesse Barnes int drm_mode_getplane_res(struct drm_device *dev, void *data, 23468cf5c917SJesse Barnes struct drm_file *file_priv) 23478cf5c917SJesse Barnes { 23488cf5c917SJesse Barnes struct drm_mode_get_plane_res *plane_resp = data; 23498cf5c917SJesse Barnes struct drm_mode_config *config; 23508cf5c917SJesse Barnes struct drm_plane *plane; 23518cf5c917SJesse Barnes uint32_t __user *plane_ptr; 2352fcf93f69SDaniel Vetter int copied = 0; 2353681e7ec7SMatt Roper unsigned num_planes; 23548cf5c917SJesse Barnes 23558cf5c917SJesse Barnes if (!drm_core_check_feature(dev, DRIVER_MODESET)) 23568cf5c917SJesse Barnes return -EINVAL; 23578cf5c917SJesse Barnes 23588cf5c917SJesse Barnes config = &dev->mode_config; 23598cf5c917SJesse Barnes 2360681e7ec7SMatt Roper if (file_priv->universal_planes) 2361681e7ec7SMatt Roper num_planes = config->num_total_plane; 2362681e7ec7SMatt Roper else 2363681e7ec7SMatt Roper num_planes = config->num_overlay_plane; 2364681e7ec7SMatt Roper 23658cf5c917SJesse Barnes /* 23668cf5c917SJesse Barnes * This ioctl is called twice, once to determine how much space is 23678cf5c917SJesse Barnes * needed, and the 2nd time to fill it. 23688cf5c917SJesse Barnes */ 2369681e7ec7SMatt Roper if (num_planes && 2370681e7ec7SMatt Roper (plane_resp->count_planes >= num_planes)) { 237181f6c7f8SVille Syrjälä plane_ptr = (uint32_t __user *)(unsigned long)plane_resp->plane_id_ptr; 23728cf5c917SJesse Barnes 2373fcf93f69SDaniel Vetter /* Plane lists are invariant, no locking needed. */ 2374e4f62546SDaniel Vetter drm_for_each_plane(plane, dev) { 2375681e7ec7SMatt Roper /* 2376681e7ec7SMatt Roper * Unless userspace set the 'universal planes' 2377681e7ec7SMatt Roper * capability bit, only advertise overlays. 2378681e7ec7SMatt Roper */ 2379681e7ec7SMatt Roper if (plane->type != DRM_PLANE_TYPE_OVERLAY && 2380681e7ec7SMatt Roper !file_priv->universal_planes) 2381e27dde3eSMatt Roper continue; 2382e27dde3eSMatt Roper 2383fcf93f69SDaniel Vetter if (put_user(plane->base.id, plane_ptr + copied)) 2384fcf93f69SDaniel Vetter return -EFAULT; 23858cf5c917SJesse Barnes copied++; 23868cf5c917SJesse Barnes } 23878cf5c917SJesse Barnes } 2388681e7ec7SMatt Roper plane_resp->count_planes = num_planes; 23898cf5c917SJesse Barnes 2390fcf93f69SDaniel Vetter return 0; 23918cf5c917SJesse Barnes } 23928cf5c917SJesse Barnes 23938cf5c917SJesse Barnes /** 2394c8e32cc1SDaniel Vetter * drm_mode_getplane - get plane configuration 23958cf5c917SJesse Barnes * @dev: DRM device 23968cf5c917SJesse Barnes * @data: ioctl data 23978cf5c917SJesse Barnes * @file_priv: DRM file info 23988cf5c917SJesse Barnes * 2399c8e32cc1SDaniel Vetter * Construct a plane configuration structure to return to the user. 2400c8e32cc1SDaniel Vetter * 2401c8e32cc1SDaniel Vetter * Called by the user via ioctl. 2402c8e32cc1SDaniel Vetter * 2403c8e32cc1SDaniel Vetter * Returns: 24041a498633SDaniel Vetter * Zero on success, negative errno on failure. 24058cf5c917SJesse Barnes */ 24068cf5c917SJesse Barnes int drm_mode_getplane(struct drm_device *dev, void *data, 24078cf5c917SJesse Barnes struct drm_file *file_priv) 24088cf5c917SJesse Barnes { 24098cf5c917SJesse Barnes struct drm_mode_get_plane *plane_resp = data; 24108cf5c917SJesse Barnes struct drm_plane *plane; 24118cf5c917SJesse Barnes uint32_t __user *format_ptr; 24128cf5c917SJesse Barnes 24138cf5c917SJesse Barnes if (!drm_core_check_feature(dev, DRIVER_MODESET)) 24148cf5c917SJesse Barnes return -EINVAL; 24158cf5c917SJesse Barnes 2416a2b34e22SRob Clark plane = drm_plane_find(dev, plane_resp->plane_id); 2417fcf93f69SDaniel Vetter if (!plane) 2418fcf93f69SDaniel Vetter return -ENOENT; 24198cf5c917SJesse Barnes 2420fcf93f69SDaniel Vetter drm_modeset_lock(&plane->mutex, NULL); 24218cf5c917SJesse Barnes if (plane->crtc) 24228cf5c917SJesse Barnes plane_resp->crtc_id = plane->crtc->base.id; 24238cf5c917SJesse Barnes else 24248cf5c917SJesse Barnes plane_resp->crtc_id = 0; 24258cf5c917SJesse Barnes 24268cf5c917SJesse Barnes if (plane->fb) 24278cf5c917SJesse Barnes plane_resp->fb_id = plane->fb->base.id; 24288cf5c917SJesse Barnes else 24298cf5c917SJesse Barnes plane_resp->fb_id = 0; 2430fcf93f69SDaniel Vetter drm_modeset_unlock(&plane->mutex); 24318cf5c917SJesse Barnes 24328cf5c917SJesse Barnes plane_resp->plane_id = plane->base.id; 24338cf5c917SJesse Barnes plane_resp->possible_crtcs = plane->possible_crtcs; 2434778ad903SVille Syrjälä plane_resp->gamma_size = 0; 24358cf5c917SJesse Barnes 24368cf5c917SJesse Barnes /* 24378cf5c917SJesse Barnes * This ioctl is called twice, once to determine how much space is 24388cf5c917SJesse Barnes * needed, and the 2nd time to fill it. 24398cf5c917SJesse Barnes */ 24408cf5c917SJesse Barnes if (plane->format_count && 24418cf5c917SJesse Barnes (plane_resp->count_format_types >= plane->format_count)) { 244281f6c7f8SVille Syrjälä format_ptr = (uint32_t __user *)(unsigned long)plane_resp->format_type_ptr; 24438cf5c917SJesse Barnes if (copy_to_user(format_ptr, 24448cf5c917SJesse Barnes plane->format_types, 24458cf5c917SJesse Barnes sizeof(uint32_t) * plane->format_count)) { 2446fcf93f69SDaniel Vetter return -EFAULT; 24478cf5c917SJesse Barnes } 24488cf5c917SJesse Barnes } 24498cf5c917SJesse Barnes plane_resp->count_format_types = plane->format_count; 24508cf5c917SJesse Barnes 2451baf698b0SDaniel Vetter return 0; 24528cf5c917SJesse Barnes } 24538cf5c917SJesse Barnes 2454ead8610dSLaurent Pinchart /** 2455ead8610dSLaurent Pinchart * drm_plane_check_pixel_format - Check if the plane supports the pixel format 2456ead8610dSLaurent Pinchart * @plane: plane to check for format support 2457ead8610dSLaurent Pinchart * @format: the pixel format 2458ead8610dSLaurent Pinchart * 2459ead8610dSLaurent Pinchart * Returns: 2460ead8610dSLaurent Pinchart * Zero of @plane has @format in its list of supported pixel formats, -EINVAL 2461ead8610dSLaurent Pinchart * otherwise. 2462ead8610dSLaurent Pinchart */ 2463ead8610dSLaurent Pinchart int drm_plane_check_pixel_format(const struct drm_plane *plane, u32 format) 2464ead8610dSLaurent Pinchart { 2465ead8610dSLaurent Pinchart unsigned int i; 2466ead8610dSLaurent Pinchart 2467ead8610dSLaurent Pinchart for (i = 0; i < plane->format_count; i++) { 2468ead8610dSLaurent Pinchart if (format == plane->format_types[i]) 2469ead8610dSLaurent Pinchart return 0; 2470ead8610dSLaurent Pinchart } 2471ead8610dSLaurent Pinchart 2472ead8610dSLaurent Pinchart return -EINVAL; 2473ead8610dSLaurent Pinchart } 2474ead8610dSLaurent Pinchart 2475ce8d9eccSVille Syrjälä static int check_src_coords(uint32_t src_x, uint32_t src_y, 2476ce8d9eccSVille Syrjälä uint32_t src_w, uint32_t src_h, 2477ce8d9eccSVille Syrjälä const struct drm_framebuffer *fb) 2478ce8d9eccSVille Syrjälä { 2479ce8d9eccSVille Syrjälä unsigned int fb_width, fb_height; 2480ce8d9eccSVille Syrjälä 2481ce8d9eccSVille Syrjälä fb_width = fb->width << 16; 2482ce8d9eccSVille Syrjälä fb_height = fb->height << 16; 2483ce8d9eccSVille Syrjälä 2484ce8d9eccSVille Syrjälä /* Make sure source coordinates are inside the fb. */ 2485ce8d9eccSVille Syrjälä if (src_w > fb_width || 2486ce8d9eccSVille Syrjälä src_x > fb_width - src_w || 2487ce8d9eccSVille Syrjälä src_h > fb_height || 2488ce8d9eccSVille Syrjälä src_y > fb_height - src_h) { 2489ce8d9eccSVille Syrjälä DRM_DEBUG_KMS("Invalid source coordinates " 2490ce8d9eccSVille Syrjälä "%u.%06ux%u.%06u+%u.%06u+%u.%06u\n", 2491ce8d9eccSVille Syrjälä src_w >> 16, ((src_w & 0xffff) * 15625) >> 10, 2492ce8d9eccSVille Syrjälä src_h >> 16, ((src_h & 0xffff) * 15625) >> 10, 2493ce8d9eccSVille Syrjälä src_x >> 16, ((src_x & 0xffff) * 15625) >> 10, 2494ce8d9eccSVille Syrjälä src_y >> 16, ((src_y & 0xffff) * 15625) >> 10); 2495ce8d9eccSVille Syrjälä return -ENOSPC; 2496ce8d9eccSVille Syrjälä } 2497ce8d9eccSVille Syrjälä 2498ce8d9eccSVille Syrjälä return 0; 2499ce8d9eccSVille Syrjälä } 2500ce8d9eccSVille Syrjälä 2501b36552b3SMatt Roper /* 2502b36552b3SMatt Roper * setplane_internal - setplane handler for internal callers 25038cf5c917SJesse Barnes * 2504b36552b3SMatt Roper * Note that we assume an extra reference has already been taken on fb. If the 2505b36552b3SMatt Roper * update fails, this reference will be dropped before return; if it succeeds, 2506b36552b3SMatt Roper * the previous framebuffer (if any) will be unreferenced instead. 2507c8e32cc1SDaniel Vetter * 2508b36552b3SMatt Roper * src_{x,y,w,h} are provided in 16.16 fixed point format 25098cf5c917SJesse Barnes */ 2510f2b50c11SDaniel Vetter static int __setplane_internal(struct drm_plane *plane, 251117cfd91fSChris Wilson struct drm_crtc *crtc, 2512b36552b3SMatt Roper struct drm_framebuffer *fb, 2513b36552b3SMatt Roper int32_t crtc_x, int32_t crtc_y, 2514b36552b3SMatt Roper uint32_t crtc_w, uint32_t crtc_h, 2515b36552b3SMatt Roper /* src_{x,y,w,h} values are 16.16 fixed point */ 2516b36552b3SMatt Roper uint32_t src_x, uint32_t src_y, 2517b36552b3SMatt Roper uint32_t src_w, uint32_t src_h) 25188cf5c917SJesse Barnes { 25198cf5c917SJesse Barnes int ret = 0; 25208cf5c917SJesse Barnes 25218cf5c917SJesse Barnes /* No fb means shut it down */ 2522b36552b3SMatt Roper if (!fb) { 25233d30a59bSDaniel Vetter plane->old_fb = plane->fb; 2524731cce48SDaniel Vetter ret = plane->funcs->disable_plane(plane); 2525731cce48SDaniel Vetter if (!ret) { 2526e5e3b44cSVille Syrjälä plane->crtc = NULL; 2527e5e3b44cSVille Syrjälä plane->fb = NULL; 2528731cce48SDaniel Vetter } else { 25293d30a59bSDaniel Vetter plane->old_fb = NULL; 2530731cce48SDaniel Vetter } 25318cf5c917SJesse Barnes goto out; 25328cf5c917SJesse Barnes } 25338cf5c917SJesse Barnes 25347f994f3fSMatt Roper /* Check whether this plane is usable on this CRTC */ 25357f994f3fSMatt Roper if (!(plane->possible_crtcs & drm_crtc_mask(crtc))) { 25367f994f3fSMatt Roper DRM_DEBUG_KMS("Invalid crtc for plane\n"); 25377f994f3fSMatt Roper ret = -EINVAL; 25387f994f3fSMatt Roper goto out; 25397f994f3fSMatt Roper } 25407f994f3fSMatt Roper 254162443be6SVille Syrjälä /* Check whether this plane supports the fb pixel format. */ 2542ead8610dSLaurent Pinchart ret = drm_plane_check_pixel_format(plane, fb->pixel_format); 2543ead8610dSLaurent Pinchart if (ret) { 25446ba6d03eSVille Syrjälä DRM_DEBUG_KMS("Invalid pixel format %s\n", 25456ba6d03eSVille Syrjälä drm_get_format_name(fb->pixel_format)); 254662443be6SVille Syrjälä goto out; 254762443be6SVille Syrjälä } 254862443be6SVille Syrjälä 25493968be94SMatt Roper /* Give drivers some help against integer overflows */ 25503968be94SMatt Roper if (crtc_w > INT_MAX || 25513968be94SMatt Roper crtc_x > INT_MAX - (int32_t) crtc_w || 25523968be94SMatt Roper crtc_h > INT_MAX || 25533968be94SMatt Roper crtc_y > INT_MAX - (int32_t) crtc_h) { 25543968be94SMatt Roper DRM_DEBUG_KMS("Invalid CRTC coordinates %ux%u+%d+%d\n", 25553968be94SMatt Roper crtc_w, crtc_h, crtc_x, crtc_y); 2556c390eed0SVille Syrjälä ret = -ERANGE; 255742ef8789SVille Syrjälä goto out; 255842ef8789SVille Syrjälä } 255942ef8789SVille Syrjälä 2560ce8d9eccSVille Syrjälä ret = check_src_coords(src_x, src_y, src_w, src_h, fb); 2561ce8d9eccSVille Syrjälä if (ret) 2562f453ba04SDave Airlie goto out; 2563f453ba04SDave Airlie 25643d30a59bSDaniel Vetter plane->old_fb = plane->fb; 2565f453ba04SDave Airlie ret = plane->funcs->update_plane(plane, crtc, fb, 2566b36552b3SMatt Roper crtc_x, crtc_y, crtc_w, crtc_h, 2567b36552b3SMatt Roper src_x, src_y, src_w, src_h); 2568f453ba04SDave Airlie if (!ret) { 2569f453ba04SDave Airlie plane->crtc = crtc; 2570f453ba04SDave Airlie plane->fb = fb; 257135f8badcSDaniel Vetter fb = NULL; 25720fe27f06SDaniel Vetter } else { 25733d30a59bSDaniel Vetter plane->old_fb = NULL; 2574f453ba04SDave Airlie } 2575f453ba04SDave Airlie 2576f453ba04SDave Airlie out: 25776c2a7532SDaniel Vetter if (fb) 25786c2a7532SDaniel Vetter drm_framebuffer_unreference(fb); 25793d30a59bSDaniel Vetter if (plane->old_fb) 25803d30a59bSDaniel Vetter drm_framebuffer_unreference(plane->old_fb); 25813d30a59bSDaniel Vetter plane->old_fb = NULL; 2582f453ba04SDave Airlie 2583f453ba04SDave Airlie return ret; 2584f2b50c11SDaniel Vetter } 2585b36552b3SMatt Roper 2586f2b50c11SDaniel Vetter static int setplane_internal(struct drm_plane *plane, 2587f2b50c11SDaniel Vetter struct drm_crtc *crtc, 2588f2b50c11SDaniel Vetter struct drm_framebuffer *fb, 2589f2b50c11SDaniel Vetter int32_t crtc_x, int32_t crtc_y, 2590f2b50c11SDaniel Vetter uint32_t crtc_w, uint32_t crtc_h, 2591f2b50c11SDaniel Vetter /* src_{x,y,w,h} values are 16.16 fixed point */ 2592f2b50c11SDaniel Vetter uint32_t src_x, uint32_t src_y, 2593f2b50c11SDaniel Vetter uint32_t src_w, uint32_t src_h) 2594f2b50c11SDaniel Vetter { 2595f2b50c11SDaniel Vetter int ret; 2596f2b50c11SDaniel Vetter 2597f2b50c11SDaniel Vetter drm_modeset_lock_all(plane->dev); 2598f2b50c11SDaniel Vetter ret = __setplane_internal(plane, crtc, fb, 2599f2b50c11SDaniel Vetter crtc_x, crtc_y, crtc_w, crtc_h, 2600f2b50c11SDaniel Vetter src_x, src_y, src_w, src_h); 2601f2b50c11SDaniel Vetter drm_modeset_unlock_all(plane->dev); 2602f2b50c11SDaniel Vetter 2603f2b50c11SDaniel Vetter return ret; 2604b36552b3SMatt Roper } 2605b36552b3SMatt Roper 2606b36552b3SMatt Roper /** 2607b36552b3SMatt Roper * drm_mode_setplane - configure a plane's configuration 2608b36552b3SMatt Roper * @dev: DRM device 2609b36552b3SMatt Roper * @data: ioctl data* 2610b36552b3SMatt Roper * @file_priv: DRM file info 2611b36552b3SMatt Roper * 2612b36552b3SMatt Roper * Set plane configuration, including placement, fb, scaling, and other factors. 2613b36552b3SMatt Roper * Or pass a NULL fb to disable (planes may be disabled without providing a 2614b36552b3SMatt Roper * valid crtc). 2615b36552b3SMatt Roper * 2616b36552b3SMatt Roper * Returns: 26171a498633SDaniel Vetter * Zero on success, negative errno on failure. 2618b36552b3SMatt Roper */ 2619b36552b3SMatt Roper int drm_mode_setplane(struct drm_device *dev, void *data, 2620b36552b3SMatt Roper struct drm_file *file_priv) 2621b36552b3SMatt Roper { 2622b36552b3SMatt Roper struct drm_mode_set_plane *plane_req = data; 2623b36552b3SMatt Roper struct drm_plane *plane; 2624b36552b3SMatt Roper struct drm_crtc *crtc = NULL; 2625b36552b3SMatt Roper struct drm_framebuffer *fb = NULL; 2626b36552b3SMatt Roper 2627b36552b3SMatt Roper if (!drm_core_check_feature(dev, DRIVER_MODESET)) 2628b36552b3SMatt Roper return -EINVAL; 2629b36552b3SMatt Roper 2630b36552b3SMatt Roper /* 2631b36552b3SMatt Roper * First, find the plane, crtc, and fb objects. If not available, 2632b36552b3SMatt Roper * we don't bother to call the driver. 2633b36552b3SMatt Roper */ 2634933f622fSRob Clark plane = drm_plane_find(dev, plane_req->plane_id); 2635933f622fSRob Clark if (!plane) { 2636b36552b3SMatt Roper DRM_DEBUG_KMS("Unknown plane ID %d\n", 2637b36552b3SMatt Roper plane_req->plane_id); 2638b36552b3SMatt Roper return -ENOENT; 2639b36552b3SMatt Roper } 2640b36552b3SMatt Roper 2641b36552b3SMatt Roper if (plane_req->fb_id) { 2642b36552b3SMatt Roper fb = drm_framebuffer_lookup(dev, plane_req->fb_id); 2643b36552b3SMatt Roper if (!fb) { 2644b36552b3SMatt Roper DRM_DEBUG_KMS("Unknown framebuffer ID %d\n", 2645b36552b3SMatt Roper plane_req->fb_id); 2646b36552b3SMatt Roper return -ENOENT; 2647b36552b3SMatt Roper } 2648b36552b3SMatt Roper 2649933f622fSRob Clark crtc = drm_crtc_find(dev, plane_req->crtc_id); 2650933f622fSRob Clark if (!crtc) { 2651b36552b3SMatt Roper DRM_DEBUG_KMS("Unknown crtc ID %d\n", 2652b36552b3SMatt Roper plane_req->crtc_id); 2653b36552b3SMatt Roper return -ENOENT; 2654b36552b3SMatt Roper } 2655b36552b3SMatt Roper } 2656b36552b3SMatt Roper 2657161d0dc1SMatt Roper /* 2658161d0dc1SMatt Roper * setplane_internal will take care of deref'ing either the old or new 2659161d0dc1SMatt Roper * framebuffer depending on success. 2660161d0dc1SMatt Roper */ 266117cfd91fSChris Wilson return setplane_internal(plane, crtc, fb, 2662b36552b3SMatt Roper plane_req->crtc_x, plane_req->crtc_y, 2663b36552b3SMatt Roper plane_req->crtc_w, plane_req->crtc_h, 2664b36552b3SMatt Roper plane_req->src_x, plane_req->src_y, 2665b36552b3SMatt Roper plane_req->src_w, plane_req->src_h); 2666f453ba04SDave Airlie } 2667f453ba04SDave Airlie 2668f453ba04SDave Airlie /** 26692d13b679SDaniel Vetter * drm_mode_set_config_internal - helper to call ->set_config 26702d13b679SDaniel Vetter * @set: modeset config to set 26712d13b679SDaniel Vetter * 26722d13b679SDaniel Vetter * This is a little helper to wrap internal calls to the ->set_config driver 26732d13b679SDaniel Vetter * interface. The only thing it adds is correct refcounting dance. 2674c8e32cc1SDaniel Vetter * 2675c8e32cc1SDaniel Vetter * Returns: 26761a498633SDaniel Vetter * Zero on success, negative errno on failure. 26772d13b679SDaniel Vetter */ 26782d13b679SDaniel Vetter int drm_mode_set_config_internal(struct drm_mode_set *set) 26792d13b679SDaniel Vetter { 26802d13b679SDaniel Vetter struct drm_crtc *crtc = set->crtc; 26815cef29aaSDaniel Vetter struct drm_framebuffer *fb; 26825cef29aaSDaniel Vetter struct drm_crtc *tmp; 2683b0d12325SDaniel Vetter int ret; 26842d13b679SDaniel Vetter 26855cef29aaSDaniel Vetter /* 26865cef29aaSDaniel Vetter * NOTE: ->set_config can also disable other crtcs (if we steal all 26875cef29aaSDaniel Vetter * connectors from it), hence we need to refcount the fbs across all 26885cef29aaSDaniel Vetter * crtcs. Atomic modeset will have saner semantics ... 26895cef29aaSDaniel Vetter */ 2690e4f62546SDaniel Vetter drm_for_each_crtc(tmp, crtc->dev) 26913d30a59bSDaniel Vetter tmp->primary->old_fb = tmp->primary->fb; 26925cef29aaSDaniel Vetter 2693b0d12325SDaniel Vetter fb = set->fb; 2694b0d12325SDaniel Vetter 2695b0d12325SDaniel Vetter ret = crtc->funcs->set_config(set); 2696b0d12325SDaniel Vetter if (ret == 0) { 2697e13161afSMatt Roper crtc->primary->crtc = crtc; 26980fe27f06SDaniel Vetter crtc->primary->fb = fb; 26995cef29aaSDaniel Vetter } 2700cc85e121SDaniel Vetter 2701e4f62546SDaniel Vetter drm_for_each_crtc(tmp, crtc->dev) { 2702f4510a27SMatt Roper if (tmp->primary->fb) 2703f4510a27SMatt Roper drm_framebuffer_reference(tmp->primary->fb); 27043d30a59bSDaniel Vetter if (tmp->primary->old_fb) 27053d30a59bSDaniel Vetter drm_framebuffer_unreference(tmp->primary->old_fb); 27063d30a59bSDaniel Vetter tmp->primary->old_fb = NULL; 2707b0d12325SDaniel Vetter } 2708b0d12325SDaniel Vetter 2709b0d12325SDaniel Vetter return ret; 27102d13b679SDaniel Vetter } 27112d13b679SDaniel Vetter EXPORT_SYMBOL(drm_mode_set_config_internal); 27122d13b679SDaniel Vetter 2713af93629dSMatt Roper /** 2714ecb7e16bSGustavo Padovan * drm_crtc_get_hv_timing - Fetches hdisplay/vdisplay for given mode 2715ecb7e16bSGustavo Padovan * @mode: mode to query 2716ecb7e16bSGustavo Padovan * @hdisplay: hdisplay value to fill in 2717ecb7e16bSGustavo Padovan * @vdisplay: vdisplay value to fill in 2718ecb7e16bSGustavo Padovan * 2719ecb7e16bSGustavo Padovan * The vdisplay value will be doubled if the specified mode is a stereo mode of 2720ecb7e16bSGustavo Padovan * the appropriate layout. 2721ecb7e16bSGustavo Padovan */ 2722ecb7e16bSGustavo Padovan void drm_crtc_get_hv_timing(const struct drm_display_mode *mode, 2723ecb7e16bSGustavo Padovan int *hdisplay, int *vdisplay) 2724ecb7e16bSGustavo Padovan { 2725ecb7e16bSGustavo Padovan struct drm_display_mode adjusted; 2726ecb7e16bSGustavo Padovan 2727ecb7e16bSGustavo Padovan drm_mode_copy(&adjusted, mode); 2728ecb7e16bSGustavo Padovan drm_mode_set_crtcinfo(&adjusted, CRTC_STEREO_DOUBLE_ONLY); 2729ecb7e16bSGustavo Padovan *hdisplay = adjusted.crtc_hdisplay; 2730ecb7e16bSGustavo Padovan *vdisplay = adjusted.crtc_vdisplay; 2731ecb7e16bSGustavo Padovan } 2732ecb7e16bSGustavo Padovan EXPORT_SYMBOL(drm_crtc_get_hv_timing); 2733ecb7e16bSGustavo Padovan 2734ecb7e16bSGustavo Padovan /** 2735af93629dSMatt Roper * drm_crtc_check_viewport - Checks that a framebuffer is big enough for the 2736af93629dSMatt Roper * CRTC viewport 2737af93629dSMatt Roper * @crtc: CRTC that framebuffer will be displayed on 2738af93629dSMatt Roper * @x: x panning 2739af93629dSMatt Roper * @y: y panning 2740af93629dSMatt Roper * @mode: mode that framebuffer will be displayed under 2741af93629dSMatt Roper * @fb: framebuffer to check size of 2742c11e9283SDamien Lespiau */ 2743af93629dSMatt Roper int drm_crtc_check_viewport(const struct drm_crtc *crtc, 2744c11e9283SDamien Lespiau int x, int y, 2745c11e9283SDamien Lespiau const struct drm_display_mode *mode, 2746c11e9283SDamien Lespiau const struct drm_framebuffer *fb) 2747c11e9283SDamien Lespiau 2748c11e9283SDamien Lespiau { 2749c11e9283SDamien Lespiau int hdisplay, vdisplay; 2750c11e9283SDamien Lespiau 2751ecb7e16bSGustavo Padovan drm_crtc_get_hv_timing(mode, &hdisplay, &vdisplay); 2752a0c1bbb0SDamien Lespiau 275333e0be63SVille Syrjälä if (crtc->state && 275433e0be63SVille Syrjälä crtc->primary->state->rotation & (BIT(DRM_ROTATE_90) | 275533e0be63SVille Syrjälä BIT(DRM_ROTATE_270))) 2756c11e9283SDamien Lespiau swap(hdisplay, vdisplay); 2757c11e9283SDamien Lespiau 2758ce8d9eccSVille Syrjälä return check_src_coords(x << 16, y << 16, 2759ce8d9eccSVille Syrjälä hdisplay << 16, vdisplay << 16, fb); 2760c11e9283SDamien Lespiau } 2761af93629dSMatt Roper EXPORT_SYMBOL(drm_crtc_check_viewport); 2762c11e9283SDamien Lespiau 27632d13b679SDaniel Vetter /** 2764f453ba04SDave Airlie * drm_mode_setcrtc - set CRTC configuration 2765065a50edSDaniel Vetter * @dev: drm device for the ioctl 2766065a50edSDaniel Vetter * @data: data pointer for the ioctl 2767065a50edSDaniel Vetter * @file_priv: drm file for the ioctl call 2768f453ba04SDave Airlie * 2769f453ba04SDave Airlie * Build a new CRTC configuration based on user request. 2770f453ba04SDave Airlie * 2771f453ba04SDave Airlie * Called by the user via ioctl. 2772f453ba04SDave Airlie * 2773c8e32cc1SDaniel Vetter * Returns: 27741a498633SDaniel Vetter * Zero on success, negative errno on failure. 2775f453ba04SDave Airlie */ 2776f453ba04SDave Airlie int drm_mode_setcrtc(struct drm_device *dev, void *data, 2777f453ba04SDave Airlie struct drm_file *file_priv) 2778f453ba04SDave Airlie { 2779f453ba04SDave Airlie struct drm_mode_config *config = &dev->mode_config; 2780f453ba04SDave Airlie struct drm_mode_crtc *crtc_req = data; 27816653cc8dSVille Syrjälä struct drm_crtc *crtc; 2782f453ba04SDave Airlie struct drm_connector **connector_set = NULL, *connector; 2783f453ba04SDave Airlie struct drm_framebuffer *fb = NULL; 2784f453ba04SDave Airlie struct drm_display_mode *mode = NULL; 2785f453ba04SDave Airlie struct drm_mode_set set; 2786f453ba04SDave Airlie uint32_t __user *set_connectors_ptr; 27874a1b0714SLaurent Pinchart int ret; 2788f453ba04SDave Airlie int i; 2789f453ba04SDave Airlie 2790fb3b06c8SDave Airlie if (!drm_core_check_feature(dev, DRIVER_MODESET)) 2791fb3b06c8SDave Airlie return -EINVAL; 2792fb3b06c8SDave Airlie 279301447e9fSZhao Junwang /* 279401447e9fSZhao Junwang * Universal plane src offsets are only 16.16, prevent havoc for 279501447e9fSZhao Junwang * drivers using universal plane code internally. 279601447e9fSZhao Junwang */ 279701447e9fSZhao Junwang if (crtc_req->x & 0xffff0000 || crtc_req->y & 0xffff0000) 27981d97e915SVille Syrjälä return -ERANGE; 27991d97e915SVille Syrjälä 280084849903SDaniel Vetter drm_modeset_lock_all(dev); 2801a2b34e22SRob Clark crtc = drm_crtc_find(dev, crtc_req->crtc_id); 2802a2b34e22SRob Clark if (!crtc) { 280358367ed6SZhao Yakui DRM_DEBUG_KMS("Unknown CRTC ID %d\n", crtc_req->crtc_id); 2804f27657f2SVille Syrjälä ret = -ENOENT; 2805f453ba04SDave Airlie goto out; 2806f453ba04SDave Airlie } 2807fa3ab4c2SVille Syrjälä DRM_DEBUG_KMS("[CRTC:%d:%s]\n", crtc->base.id, crtc->name); 2808f453ba04SDave Airlie 2809f453ba04SDave Airlie if (crtc_req->mode_valid) { 2810f453ba04SDave Airlie /* If we have a mode we need a framebuffer. */ 2811f453ba04SDave Airlie /* If we pass -1, set the mode with the currently bound fb */ 2812f453ba04SDave Airlie if (crtc_req->fb_id == -1) { 2813f4510a27SMatt Roper if (!crtc->primary->fb) { 28146653cc8dSVille Syrjälä DRM_DEBUG_KMS("CRTC doesn't have current FB\n"); 28156653cc8dSVille Syrjälä ret = -EINVAL; 28166653cc8dSVille Syrjälä goto out; 28176653cc8dSVille Syrjälä } 2818f4510a27SMatt Roper fb = crtc->primary->fb; 2819b0d12325SDaniel Vetter /* Make refcounting symmetric with the lookup path. */ 2820b0d12325SDaniel Vetter drm_framebuffer_reference(fb); 2821f453ba04SDave Airlie } else { 2822786b99edSDaniel Vetter fb = drm_framebuffer_lookup(dev, crtc_req->fb_id); 2823786b99edSDaniel Vetter if (!fb) { 282458367ed6SZhao Yakui DRM_DEBUG_KMS("Unknown FB ID%d\n", 282558367ed6SZhao Yakui crtc_req->fb_id); 282637c4e705SVille Syrjälä ret = -ENOENT; 2827f453ba04SDave Airlie goto out; 2828f453ba04SDave Airlie } 2829f453ba04SDave Airlie } 2830f453ba04SDave Airlie 2831f453ba04SDave Airlie mode = drm_mode_create(dev); 2832ee34ab5bSVille Syrjälä if (!mode) { 2833ee34ab5bSVille Syrjälä ret = -ENOMEM; 2834ee34ab5bSVille Syrjälä goto out; 2835ee34ab5bSVille Syrjälä } 2836ee34ab5bSVille Syrjälä 2837934a8a89SDaniel Stone ret = drm_mode_convert_umode(mode, &crtc_req->mode); 283890367bf6SVille Syrjälä if (ret) { 283990367bf6SVille Syrjälä DRM_DEBUG_KMS("Invalid mode\n"); 284090367bf6SVille Syrjälä goto out; 284190367bf6SVille Syrjälä } 284290367bf6SVille Syrjälä 2843f453ba04SDave Airlie drm_mode_set_crtcinfo(mode, CRTC_INTERLACE_HALVE_V); 28445f61bb42SVille Syrjälä 28457eb5f302SLaurent Pinchart /* 28467eb5f302SLaurent Pinchart * Check whether the primary plane supports the fb pixel format. 28477eb5f302SLaurent Pinchart * Drivers not implementing the universal planes API use a 28487eb5f302SLaurent Pinchart * default formats list provided by the DRM core which doesn't 28497eb5f302SLaurent Pinchart * match real hardware capabilities. Skip the check in that 28507eb5f302SLaurent Pinchart * case. 28517eb5f302SLaurent Pinchart */ 28527eb5f302SLaurent Pinchart if (!crtc->primary->format_default) { 28537eb5f302SLaurent Pinchart ret = drm_plane_check_pixel_format(crtc->primary, 28547eb5f302SLaurent Pinchart fb->pixel_format); 28557eb5f302SLaurent Pinchart if (ret) { 28567eb5f302SLaurent Pinchart DRM_DEBUG_KMS("Invalid pixel format %s\n", 28577eb5f302SLaurent Pinchart drm_get_format_name(fb->pixel_format)); 28587eb5f302SLaurent Pinchart goto out; 28597eb5f302SLaurent Pinchart } 28607eb5f302SLaurent Pinchart } 28617eb5f302SLaurent Pinchart 2862c11e9283SDamien Lespiau ret = drm_crtc_check_viewport(crtc, crtc_req->x, crtc_req->y, 2863c11e9283SDamien Lespiau mode, fb); 2864c11e9283SDamien Lespiau if (ret) 28655f61bb42SVille Syrjälä goto out; 2866c11e9283SDamien Lespiau 2867f453ba04SDave Airlie } 2868f453ba04SDave Airlie 2869f453ba04SDave Airlie if (crtc_req->count_connectors == 0 && mode) { 287058367ed6SZhao Yakui DRM_DEBUG_KMS("Count connectors is 0 but mode set\n"); 2871f453ba04SDave Airlie ret = -EINVAL; 2872f453ba04SDave Airlie goto out; 2873f453ba04SDave Airlie } 2874f453ba04SDave Airlie 28757781de74SJakob Bornecrantz if (crtc_req->count_connectors > 0 && (!mode || !fb)) { 287658367ed6SZhao Yakui DRM_DEBUG_KMS("Count connectors is %d but no mode or fb set\n", 2877f453ba04SDave Airlie crtc_req->count_connectors); 2878f453ba04SDave Airlie ret = -EINVAL; 2879f453ba04SDave Airlie goto out; 2880f453ba04SDave Airlie } 2881f453ba04SDave Airlie 2882f453ba04SDave Airlie if (crtc_req->count_connectors > 0) { 2883f453ba04SDave Airlie u32 out_id; 2884f453ba04SDave Airlie 2885f453ba04SDave Airlie /* Avoid unbounded kernel memory allocation */ 2886f453ba04SDave Airlie if (crtc_req->count_connectors > config->num_connector) { 2887f453ba04SDave Airlie ret = -EINVAL; 2888f453ba04SDave Airlie goto out; 2889f453ba04SDave Airlie } 2890f453ba04SDave Airlie 28912f6c5389SThierry Reding connector_set = kmalloc_array(crtc_req->count_connectors, 2892f453ba04SDave Airlie sizeof(struct drm_connector *), 2893f453ba04SDave Airlie GFP_KERNEL); 2894f453ba04SDave Airlie if (!connector_set) { 2895f453ba04SDave Airlie ret = -ENOMEM; 2896f453ba04SDave Airlie goto out; 2897f453ba04SDave Airlie } 2898f453ba04SDave Airlie 2899f453ba04SDave Airlie for (i = 0; i < crtc_req->count_connectors; i++) { 290081f6c7f8SVille Syrjälä set_connectors_ptr = (uint32_t __user *)(unsigned long)crtc_req->set_connectors_ptr; 2901f453ba04SDave Airlie if (get_user(out_id, &set_connectors_ptr[i])) { 2902f453ba04SDave Airlie ret = -EFAULT; 2903f453ba04SDave Airlie goto out; 2904f453ba04SDave Airlie } 2905f453ba04SDave Airlie 2906a2b34e22SRob Clark connector = drm_connector_find(dev, out_id); 2907a2b34e22SRob Clark if (!connector) { 290858367ed6SZhao Yakui DRM_DEBUG_KMS("Connector id %d unknown\n", 290958367ed6SZhao Yakui out_id); 2910f27657f2SVille Syrjälä ret = -ENOENT; 2911f453ba04SDave Airlie goto out; 2912f453ba04SDave Airlie } 29139440106bSJerome Glisse DRM_DEBUG_KMS("[CONNECTOR:%d:%s]\n", 29149440106bSJerome Glisse connector->base.id, 291525933820SJani Nikula connector->name); 2916f453ba04SDave Airlie 2917f453ba04SDave Airlie connector_set[i] = connector; 2918f453ba04SDave Airlie } 2919f453ba04SDave Airlie } 2920f453ba04SDave Airlie 2921f453ba04SDave Airlie set.crtc = crtc; 2922f453ba04SDave Airlie set.x = crtc_req->x; 2923f453ba04SDave Airlie set.y = crtc_req->y; 2924f453ba04SDave Airlie set.mode = mode; 2925f453ba04SDave Airlie set.connectors = connector_set; 2926f453ba04SDave Airlie set.num_connectors = crtc_req->count_connectors; 2927f453ba04SDave Airlie set.fb = fb; 29282d13b679SDaniel Vetter ret = drm_mode_set_config_internal(&set); 2929f453ba04SDave Airlie 2930f453ba04SDave Airlie out: 2931b0d12325SDaniel Vetter if (fb) 2932b0d12325SDaniel Vetter drm_framebuffer_unreference(fb); 2933b0d12325SDaniel Vetter 2934f453ba04SDave Airlie kfree(connector_set); 2935ee34ab5bSVille Syrjälä drm_mode_destroy(dev, mode); 293684849903SDaniel Vetter drm_modeset_unlock_all(dev); 2937f453ba04SDave Airlie return ret; 2938f453ba04SDave Airlie } 2939f453ba04SDave Airlie 2940161d0dc1SMatt Roper /** 2941161d0dc1SMatt Roper * drm_mode_cursor_universal - translate legacy cursor ioctl call into a 2942161d0dc1SMatt Roper * universal plane handler call 2943161d0dc1SMatt Roper * @crtc: crtc to update cursor for 2944161d0dc1SMatt Roper * @req: data pointer for the ioctl 2945161d0dc1SMatt Roper * @file_priv: drm file for the ioctl call 2946161d0dc1SMatt Roper * 2947161d0dc1SMatt Roper * Legacy cursor ioctl's work directly with driver buffer handles. To 2948161d0dc1SMatt Roper * translate legacy ioctl calls into universal plane handler calls, we need to 2949161d0dc1SMatt Roper * wrap the native buffer handle in a drm_framebuffer. 2950161d0dc1SMatt Roper * 2951161d0dc1SMatt Roper * Note that we assume any handle passed to the legacy ioctls was a 32-bit ARGB 2952161d0dc1SMatt Roper * buffer with a pitch of 4*width; the universal plane interface should be used 2953161d0dc1SMatt Roper * directly in cases where the hardware can support other buffer settings and 2954161d0dc1SMatt Roper * userspace wants to make use of these capabilities. 2955161d0dc1SMatt Roper * 2956161d0dc1SMatt Roper * Returns: 29571a498633SDaniel Vetter * Zero on success, negative errno on failure. 2958161d0dc1SMatt Roper */ 2959161d0dc1SMatt Roper static int drm_mode_cursor_universal(struct drm_crtc *crtc, 2960161d0dc1SMatt Roper struct drm_mode_cursor2 *req, 2961161d0dc1SMatt Roper struct drm_file *file_priv) 2962161d0dc1SMatt Roper { 2963161d0dc1SMatt Roper struct drm_device *dev = crtc->dev; 2964161d0dc1SMatt Roper struct drm_framebuffer *fb = NULL; 2965161d0dc1SMatt Roper struct drm_mode_fb_cmd2 fbreq = { 2966161d0dc1SMatt Roper .width = req->width, 2967161d0dc1SMatt Roper .height = req->height, 2968161d0dc1SMatt Roper .pixel_format = DRM_FORMAT_ARGB8888, 2969161d0dc1SMatt Roper .pitches = { req->width * 4 }, 2970161d0dc1SMatt Roper .handles = { req->handle }, 2971161d0dc1SMatt Roper }; 2972161d0dc1SMatt Roper int32_t crtc_x, crtc_y; 2973161d0dc1SMatt Roper uint32_t crtc_w = 0, crtc_h = 0; 2974161d0dc1SMatt Roper uint32_t src_w = 0, src_h = 0; 2975161d0dc1SMatt Roper int ret = 0; 2976161d0dc1SMatt Roper 2977161d0dc1SMatt Roper BUG_ON(!crtc->cursor); 2978f2b50c11SDaniel Vetter WARN_ON(crtc->cursor->crtc != crtc && crtc->cursor->crtc != NULL); 2979161d0dc1SMatt Roper 2980161d0dc1SMatt Roper /* 2981161d0dc1SMatt Roper * Obtain fb we'll be using (either new or existing) and take an extra 2982161d0dc1SMatt Roper * reference to it if fb != null. setplane will take care of dropping 2983161d0dc1SMatt Roper * the reference if the plane update fails. 2984161d0dc1SMatt Roper */ 2985161d0dc1SMatt Roper if (req->flags & DRM_MODE_CURSOR_BO) { 2986161d0dc1SMatt Roper if (req->handle) { 29879a6f5130SChris Wilson fb = internal_framebuffer_create(dev, &fbreq, file_priv); 2988161d0dc1SMatt Roper if (IS_ERR(fb)) { 2989161d0dc1SMatt Roper DRM_DEBUG_KMS("failed to wrap cursor buffer in drm framebuffer\n"); 2990161d0dc1SMatt Roper return PTR_ERR(fb); 2991161d0dc1SMatt Roper } 2992161d0dc1SMatt Roper } else { 2993161d0dc1SMatt Roper fb = NULL; 2994161d0dc1SMatt Roper } 2995161d0dc1SMatt Roper } else { 2996161d0dc1SMatt Roper fb = crtc->cursor->fb; 2997161d0dc1SMatt Roper if (fb) 2998161d0dc1SMatt Roper drm_framebuffer_reference(fb); 2999161d0dc1SMatt Roper } 3000161d0dc1SMatt Roper 3001161d0dc1SMatt Roper if (req->flags & DRM_MODE_CURSOR_MOVE) { 3002161d0dc1SMatt Roper crtc_x = req->x; 3003161d0dc1SMatt Roper crtc_y = req->y; 3004161d0dc1SMatt Roper } else { 3005161d0dc1SMatt Roper crtc_x = crtc->cursor_x; 3006161d0dc1SMatt Roper crtc_y = crtc->cursor_y; 3007161d0dc1SMatt Roper } 3008161d0dc1SMatt Roper 3009161d0dc1SMatt Roper if (fb) { 3010161d0dc1SMatt Roper crtc_w = fb->width; 3011161d0dc1SMatt Roper crtc_h = fb->height; 3012161d0dc1SMatt Roper src_w = fb->width << 16; 3013161d0dc1SMatt Roper src_h = fb->height << 16; 3014161d0dc1SMatt Roper } 3015161d0dc1SMatt Roper 3016161d0dc1SMatt Roper /* 3017161d0dc1SMatt Roper * setplane_internal will take care of deref'ing either the old or new 3018161d0dc1SMatt Roper * framebuffer depending on success. 3019161d0dc1SMatt Roper */ 3020f2b50c11SDaniel Vetter ret = __setplane_internal(crtc->cursor, crtc, fb, 3021161d0dc1SMatt Roper crtc_x, crtc_y, crtc_w, crtc_h, 3022161d0dc1SMatt Roper 0, 0, src_w, src_h); 3023161d0dc1SMatt Roper 3024161d0dc1SMatt Roper /* Update successful; save new cursor position, if necessary */ 3025161d0dc1SMatt Roper if (ret == 0 && req->flags & DRM_MODE_CURSOR_MOVE) { 3026161d0dc1SMatt Roper crtc->cursor_x = req->x; 3027161d0dc1SMatt Roper crtc->cursor_y = req->y; 3028161d0dc1SMatt Roper } 3029161d0dc1SMatt Roper 3030161d0dc1SMatt Roper return ret; 3031161d0dc1SMatt Roper } 3032161d0dc1SMatt Roper 30334c813d4dSDave Airlie static int drm_mode_cursor_common(struct drm_device *dev, 30344c813d4dSDave Airlie struct drm_mode_cursor2 *req, 30354c813d4dSDave Airlie struct drm_file *file_priv) 3036f453ba04SDave Airlie { 3037f453ba04SDave Airlie struct drm_crtc *crtc; 3038f453ba04SDave Airlie int ret = 0; 3039f453ba04SDave Airlie 3040fb3b06c8SDave Airlie if (!drm_core_check_feature(dev, DRIVER_MODESET)) 3041fb3b06c8SDave Airlie return -EINVAL; 3042fb3b06c8SDave Airlie 30437c4eaca4SJakob Bornecrantz if (!req->flags || (~DRM_MODE_CURSOR_FLAGS & req->flags)) 3044f453ba04SDave Airlie return -EINVAL; 3045f453ba04SDave Airlie 3046a2b34e22SRob Clark crtc = drm_crtc_find(dev, req->crtc_id); 3047a2b34e22SRob Clark if (!crtc) { 304858367ed6SZhao Yakui DRM_DEBUG_KMS("Unknown CRTC ID %d\n", req->crtc_id); 3049f27657f2SVille Syrjälä return -ENOENT; 3050f453ba04SDave Airlie } 3051f453ba04SDave Airlie 3052161d0dc1SMatt Roper /* 3053161d0dc1SMatt Roper * If this crtc has a universal cursor plane, call that plane's update 3054161d0dc1SMatt Roper * handler rather than using legacy cursor handlers. 3055161d0dc1SMatt Roper */ 30564d02e2deSDaniel Vetter drm_modeset_lock_crtc(crtc, crtc->cursor); 3057f2b50c11SDaniel Vetter if (crtc->cursor) { 3058f2b50c11SDaniel Vetter ret = drm_mode_cursor_universal(crtc, req, file_priv); 3059f2b50c11SDaniel Vetter goto out; 3060f2b50c11SDaniel Vetter } 3061f2b50c11SDaniel Vetter 3062f453ba04SDave Airlie if (req->flags & DRM_MODE_CURSOR_BO) { 30634c813d4dSDave Airlie if (!crtc->funcs->cursor_set && !crtc->funcs->cursor_set2) { 3064f453ba04SDave Airlie ret = -ENXIO; 3065f453ba04SDave Airlie goto out; 3066f453ba04SDave Airlie } 3067f453ba04SDave Airlie /* Turns off the cursor if handle is 0 */ 30684c813d4dSDave Airlie if (crtc->funcs->cursor_set2) 30694c813d4dSDave Airlie ret = crtc->funcs->cursor_set2(crtc, file_priv, req->handle, 30704c813d4dSDave Airlie req->width, req->height, req->hot_x, req->hot_y); 30714c813d4dSDave Airlie else 3072f453ba04SDave Airlie ret = crtc->funcs->cursor_set(crtc, file_priv, req->handle, 3073f453ba04SDave Airlie req->width, req->height); 3074f453ba04SDave Airlie } 3075f453ba04SDave Airlie 3076f453ba04SDave Airlie if (req->flags & DRM_MODE_CURSOR_MOVE) { 3077f453ba04SDave Airlie if (crtc->funcs->cursor_move) { 3078f453ba04SDave Airlie ret = crtc->funcs->cursor_move(crtc, req->x, req->y); 3079f453ba04SDave Airlie } else { 3080f453ba04SDave Airlie ret = -EFAULT; 3081f453ba04SDave Airlie goto out; 3082f453ba04SDave Airlie } 3083f453ba04SDave Airlie } 3084f453ba04SDave Airlie out: 3085d059f652SDaniel Vetter drm_modeset_unlock_crtc(crtc); 3086dac35663SDaniel Vetter 3087f453ba04SDave Airlie return ret; 30884c813d4dSDave Airlie 30894c813d4dSDave Airlie } 3090c8e32cc1SDaniel Vetter 3091c8e32cc1SDaniel Vetter 3092c8e32cc1SDaniel Vetter /** 3093c8e32cc1SDaniel Vetter * drm_mode_cursor_ioctl - set CRTC's cursor configuration 3094c8e32cc1SDaniel Vetter * @dev: drm device for the ioctl 3095c8e32cc1SDaniel Vetter * @data: data pointer for the ioctl 3096c8e32cc1SDaniel Vetter * @file_priv: drm file for the ioctl call 3097c8e32cc1SDaniel Vetter * 3098c8e32cc1SDaniel Vetter * Set the cursor configuration based on user request. 3099c8e32cc1SDaniel Vetter * 3100c8e32cc1SDaniel Vetter * Called by the user via ioctl. 3101c8e32cc1SDaniel Vetter * 3102c8e32cc1SDaniel Vetter * Returns: 31031a498633SDaniel Vetter * Zero on success, negative errno on failure. 3104c8e32cc1SDaniel Vetter */ 31054c813d4dSDave Airlie int drm_mode_cursor_ioctl(struct drm_device *dev, 31064c813d4dSDave Airlie void *data, struct drm_file *file_priv) 31074c813d4dSDave Airlie { 31084c813d4dSDave Airlie struct drm_mode_cursor *req = data; 31094c813d4dSDave Airlie struct drm_mode_cursor2 new_req; 31104c813d4dSDave Airlie 31114c813d4dSDave Airlie memcpy(&new_req, req, sizeof(struct drm_mode_cursor)); 31124c813d4dSDave Airlie new_req.hot_x = new_req.hot_y = 0; 31134c813d4dSDave Airlie 31144c813d4dSDave Airlie return drm_mode_cursor_common(dev, &new_req, file_priv); 31154c813d4dSDave Airlie } 31164c813d4dSDave Airlie 3117c8e32cc1SDaniel Vetter /** 3118c8e32cc1SDaniel Vetter * drm_mode_cursor2_ioctl - set CRTC's cursor configuration 3119c8e32cc1SDaniel Vetter * @dev: drm device for the ioctl 3120c8e32cc1SDaniel Vetter * @data: data pointer for the ioctl 3121c8e32cc1SDaniel Vetter * @file_priv: drm file for the ioctl call 3122c8e32cc1SDaniel Vetter * 3123c8e32cc1SDaniel Vetter * Set the cursor configuration based on user request. This implements the 2nd 3124c8e32cc1SDaniel Vetter * version of the cursor ioctl, which allows userspace to additionally specify 3125c8e32cc1SDaniel Vetter * the hotspot of the pointer. 3126c8e32cc1SDaniel Vetter * 3127c8e32cc1SDaniel Vetter * Called by the user via ioctl. 3128c8e32cc1SDaniel Vetter * 3129c8e32cc1SDaniel Vetter * Returns: 31301a498633SDaniel Vetter * Zero on success, negative errno on failure. 3131c8e32cc1SDaniel Vetter */ 31324c813d4dSDave Airlie int drm_mode_cursor2_ioctl(struct drm_device *dev, 31334c813d4dSDave Airlie void *data, struct drm_file *file_priv) 31344c813d4dSDave Airlie { 31354c813d4dSDave Airlie struct drm_mode_cursor2 *req = data; 31364dfd909fSThierry Reding 31374c813d4dSDave Airlie return drm_mode_cursor_common(dev, req, file_priv); 3138f453ba04SDave Airlie } 3139f453ba04SDave Airlie 3140c8e32cc1SDaniel Vetter /** 3141c8e32cc1SDaniel Vetter * drm_mode_legacy_fb_format - compute drm fourcc code from legacy description 3142c8e32cc1SDaniel Vetter * @bpp: bits per pixels 3143c8e32cc1SDaniel Vetter * @depth: bit depth per pixel 3144c8e32cc1SDaniel Vetter * 3145c8e32cc1SDaniel Vetter * Computes a drm fourcc pixel format code for the given @bpp/@depth values. 3146c8e32cc1SDaniel Vetter * Useful in fbdev emulation code, since that deals in those values. 3147c8e32cc1SDaniel Vetter */ 3148308e5bcbSJesse Barnes uint32_t drm_mode_legacy_fb_format(uint32_t bpp, uint32_t depth) 3149308e5bcbSJesse Barnes { 3150308e5bcbSJesse Barnes uint32_t fmt; 3151308e5bcbSJesse Barnes 3152308e5bcbSJesse Barnes switch (bpp) { 3153308e5bcbSJesse Barnes case 8: 3154d84f031bSVille Syrjälä fmt = DRM_FORMAT_C8; 3155308e5bcbSJesse Barnes break; 3156308e5bcbSJesse Barnes case 16: 3157308e5bcbSJesse Barnes if (depth == 15) 315804b3924dSVille Syrjälä fmt = DRM_FORMAT_XRGB1555; 3159308e5bcbSJesse Barnes else 316004b3924dSVille Syrjälä fmt = DRM_FORMAT_RGB565; 3161308e5bcbSJesse Barnes break; 3162308e5bcbSJesse Barnes case 24: 316304b3924dSVille Syrjälä fmt = DRM_FORMAT_RGB888; 3164308e5bcbSJesse Barnes break; 3165308e5bcbSJesse Barnes case 32: 3166308e5bcbSJesse Barnes if (depth == 24) 316704b3924dSVille Syrjälä fmt = DRM_FORMAT_XRGB8888; 3168308e5bcbSJesse Barnes else if (depth == 30) 316904b3924dSVille Syrjälä fmt = DRM_FORMAT_XRGB2101010; 3170308e5bcbSJesse Barnes else 317104b3924dSVille Syrjälä fmt = DRM_FORMAT_ARGB8888; 3172308e5bcbSJesse Barnes break; 3173308e5bcbSJesse Barnes default: 317404b3924dSVille Syrjälä DRM_ERROR("bad bpp, assuming x8r8g8b8 pixel format\n"); 317504b3924dSVille Syrjälä fmt = DRM_FORMAT_XRGB8888; 3176308e5bcbSJesse Barnes break; 3177308e5bcbSJesse Barnes } 3178308e5bcbSJesse Barnes 3179308e5bcbSJesse Barnes return fmt; 3180308e5bcbSJesse Barnes } 3181308e5bcbSJesse Barnes EXPORT_SYMBOL(drm_mode_legacy_fb_format); 3182308e5bcbSJesse Barnes 3183f453ba04SDave Airlie /** 3184f453ba04SDave Airlie * drm_mode_addfb - add an FB to the graphics configuration 3185065a50edSDaniel Vetter * @dev: drm device for the ioctl 3186065a50edSDaniel Vetter * @data: data pointer for the ioctl 3187065a50edSDaniel Vetter * @file_priv: drm file for the ioctl call 3188f453ba04SDave Airlie * 3189c8e32cc1SDaniel Vetter * Add a new FB to the specified CRTC, given a user request. This is the 3190209f5527SChuck Ebbert * original addfb ioctl which only supported RGB formats. 3191f453ba04SDave Airlie * 3192f453ba04SDave Airlie * Called by the user via ioctl. 3193f453ba04SDave Airlie * 3194c8e32cc1SDaniel Vetter * Returns: 31951a498633SDaniel Vetter * Zero on success, negative errno on failure. 3196f453ba04SDave Airlie */ 3197f453ba04SDave Airlie int drm_mode_addfb(struct drm_device *dev, 3198f453ba04SDave Airlie void *data, struct drm_file *file_priv) 3199f453ba04SDave Airlie { 3200308e5bcbSJesse Barnes struct drm_mode_fb_cmd *or = data; 3201308e5bcbSJesse Barnes struct drm_mode_fb_cmd2 r = {}; 3202228f2cb3SChuck Ebbert int ret; 3203308e5bcbSJesse Barnes 3204228f2cb3SChuck Ebbert /* convert to new format and call new ioctl */ 3205308e5bcbSJesse Barnes r.fb_id = or->fb_id; 3206308e5bcbSJesse Barnes r.width = or->width; 3207308e5bcbSJesse Barnes r.height = or->height; 3208308e5bcbSJesse Barnes r.pitches[0] = or->pitch; 3209308e5bcbSJesse Barnes r.pixel_format = drm_mode_legacy_fb_format(or->bpp, or->depth); 3210308e5bcbSJesse Barnes r.handles[0] = or->handle; 3211308e5bcbSJesse Barnes 3212228f2cb3SChuck Ebbert ret = drm_mode_addfb2(dev, &r, file_priv); 3213228f2cb3SChuck Ebbert if (ret) 3214228f2cb3SChuck Ebbert return ret; 3215308e5bcbSJesse Barnes 3216228f2cb3SChuck Ebbert or->fb_id = r.fb_id; 32174b096ac1SDaniel Vetter 3218baf698b0SDaniel Vetter return 0; 3219308e5bcbSJesse Barnes } 3220308e5bcbSJesse Barnes 3221cff91b62SVille Syrjälä static int format_check(const struct drm_mode_fb_cmd2 *r) 3222935b5977SVille Syrjälä { 3223935b5977SVille Syrjälä uint32_t format = r->pixel_format & ~DRM_FORMAT_BIG_ENDIAN; 3224935b5977SVille Syrjälä 3225935b5977SVille Syrjälä switch (format) { 3226935b5977SVille Syrjälä case DRM_FORMAT_C8: 3227935b5977SVille Syrjälä case DRM_FORMAT_RGB332: 3228935b5977SVille Syrjälä case DRM_FORMAT_BGR233: 3229935b5977SVille Syrjälä case DRM_FORMAT_XRGB4444: 3230935b5977SVille Syrjälä case DRM_FORMAT_XBGR4444: 3231935b5977SVille Syrjälä case DRM_FORMAT_RGBX4444: 3232935b5977SVille Syrjälä case DRM_FORMAT_BGRX4444: 3233935b5977SVille Syrjälä case DRM_FORMAT_ARGB4444: 3234935b5977SVille Syrjälä case DRM_FORMAT_ABGR4444: 3235935b5977SVille Syrjälä case DRM_FORMAT_RGBA4444: 3236935b5977SVille Syrjälä case DRM_FORMAT_BGRA4444: 3237935b5977SVille Syrjälä case DRM_FORMAT_XRGB1555: 3238935b5977SVille Syrjälä case DRM_FORMAT_XBGR1555: 3239935b5977SVille Syrjälä case DRM_FORMAT_RGBX5551: 3240935b5977SVille Syrjälä case DRM_FORMAT_BGRX5551: 3241935b5977SVille Syrjälä case DRM_FORMAT_ARGB1555: 3242935b5977SVille Syrjälä case DRM_FORMAT_ABGR1555: 3243935b5977SVille Syrjälä case DRM_FORMAT_RGBA5551: 3244935b5977SVille Syrjälä case DRM_FORMAT_BGRA5551: 3245935b5977SVille Syrjälä case DRM_FORMAT_RGB565: 3246935b5977SVille Syrjälä case DRM_FORMAT_BGR565: 3247935b5977SVille Syrjälä case DRM_FORMAT_RGB888: 3248935b5977SVille Syrjälä case DRM_FORMAT_BGR888: 3249935b5977SVille Syrjälä case DRM_FORMAT_XRGB8888: 3250935b5977SVille Syrjälä case DRM_FORMAT_XBGR8888: 3251935b5977SVille Syrjälä case DRM_FORMAT_RGBX8888: 3252935b5977SVille Syrjälä case DRM_FORMAT_BGRX8888: 3253935b5977SVille Syrjälä case DRM_FORMAT_ARGB8888: 3254935b5977SVille Syrjälä case DRM_FORMAT_ABGR8888: 3255935b5977SVille Syrjälä case DRM_FORMAT_RGBA8888: 3256935b5977SVille Syrjälä case DRM_FORMAT_BGRA8888: 3257935b5977SVille Syrjälä case DRM_FORMAT_XRGB2101010: 3258935b5977SVille Syrjälä case DRM_FORMAT_XBGR2101010: 3259935b5977SVille Syrjälä case DRM_FORMAT_RGBX1010102: 3260935b5977SVille Syrjälä case DRM_FORMAT_BGRX1010102: 3261935b5977SVille Syrjälä case DRM_FORMAT_ARGB2101010: 3262935b5977SVille Syrjälä case DRM_FORMAT_ABGR2101010: 3263935b5977SVille Syrjälä case DRM_FORMAT_RGBA1010102: 3264935b5977SVille Syrjälä case DRM_FORMAT_BGRA1010102: 3265935b5977SVille Syrjälä case DRM_FORMAT_YUYV: 3266935b5977SVille Syrjälä case DRM_FORMAT_YVYU: 3267935b5977SVille Syrjälä case DRM_FORMAT_UYVY: 3268935b5977SVille Syrjälä case DRM_FORMAT_VYUY: 3269935b5977SVille Syrjälä case DRM_FORMAT_AYUV: 3270935b5977SVille Syrjälä case DRM_FORMAT_NV12: 3271935b5977SVille Syrjälä case DRM_FORMAT_NV21: 3272935b5977SVille Syrjälä case DRM_FORMAT_NV16: 3273935b5977SVille Syrjälä case DRM_FORMAT_NV61: 3274ba623f6aSLaurent Pinchart case DRM_FORMAT_NV24: 3275ba623f6aSLaurent Pinchart case DRM_FORMAT_NV42: 3276935b5977SVille Syrjälä case DRM_FORMAT_YUV410: 3277935b5977SVille Syrjälä case DRM_FORMAT_YVU410: 3278935b5977SVille Syrjälä case DRM_FORMAT_YUV411: 3279935b5977SVille Syrjälä case DRM_FORMAT_YVU411: 3280935b5977SVille Syrjälä case DRM_FORMAT_YUV420: 3281935b5977SVille Syrjälä case DRM_FORMAT_YVU420: 3282935b5977SVille Syrjälä case DRM_FORMAT_YUV422: 3283935b5977SVille Syrjälä case DRM_FORMAT_YVU422: 3284935b5977SVille Syrjälä case DRM_FORMAT_YUV444: 3285935b5977SVille Syrjälä case DRM_FORMAT_YVU444: 3286935b5977SVille Syrjälä return 0; 3287935b5977SVille Syrjälä default: 328823c453a4SVille Syrjälä DRM_DEBUG_KMS("invalid pixel format %s\n", 328923c453a4SVille Syrjälä drm_get_format_name(r->pixel_format)); 3290935b5977SVille Syrjälä return -EINVAL; 3291935b5977SVille Syrjälä } 3292935b5977SVille Syrjälä } 3293935b5977SVille Syrjälä 3294cff91b62SVille Syrjälä static int framebuffer_check(const struct drm_mode_fb_cmd2 *r) 3295d1b45d5fSVille Syrjälä { 3296d1b45d5fSVille Syrjälä int ret, hsub, vsub, num_planes, i; 3297d1b45d5fSVille Syrjälä 3298d1b45d5fSVille Syrjälä ret = format_check(r); 3299d1b45d5fSVille Syrjälä if (ret) { 33006ba6d03eSVille Syrjälä DRM_DEBUG_KMS("bad framebuffer format %s\n", 33016ba6d03eSVille Syrjälä drm_get_format_name(r->pixel_format)); 3302d1b45d5fSVille Syrjälä return ret; 3303d1b45d5fSVille Syrjälä } 3304d1b45d5fSVille Syrjälä 3305d1b45d5fSVille Syrjälä hsub = drm_format_horz_chroma_subsampling(r->pixel_format); 3306d1b45d5fSVille Syrjälä vsub = drm_format_vert_chroma_subsampling(r->pixel_format); 3307d1b45d5fSVille Syrjälä num_planes = drm_format_num_planes(r->pixel_format); 3308d1b45d5fSVille Syrjälä 3309d1b45d5fSVille Syrjälä if (r->width == 0 || r->width % hsub) { 3310209f5527SChuck Ebbert DRM_DEBUG_KMS("bad framebuffer width %u\n", r->width); 3311d1b45d5fSVille Syrjälä return -EINVAL; 3312d1b45d5fSVille Syrjälä } 3313d1b45d5fSVille Syrjälä 3314d1b45d5fSVille Syrjälä if (r->height == 0 || r->height % vsub) { 33151aa1b11cSDave Airlie DRM_DEBUG_KMS("bad framebuffer height %u\n", r->height); 3316d1b45d5fSVille Syrjälä return -EINVAL; 3317d1b45d5fSVille Syrjälä } 3318d1b45d5fSVille Syrjälä 3319d1b45d5fSVille Syrjälä for (i = 0; i < num_planes; i++) { 3320d1b45d5fSVille Syrjälä unsigned int width = r->width / (i != 0 ? hsub : 1); 3321b180b5d1SVille Syrjälä unsigned int height = r->height / (i != 0 ? vsub : 1); 3322b180b5d1SVille Syrjälä unsigned int cpp = drm_format_plane_cpp(r->pixel_format, i); 3323d1b45d5fSVille Syrjälä 3324d1b45d5fSVille Syrjälä if (!r->handles[i]) { 33251aa1b11cSDave Airlie DRM_DEBUG_KMS("no buffer object handle for plane %d\n", i); 3326d1b45d5fSVille Syrjälä return -EINVAL; 3327d1b45d5fSVille Syrjälä } 3328d1b45d5fSVille Syrjälä 3329b180b5d1SVille Syrjälä if ((uint64_t) width * cpp > UINT_MAX) 3330b180b5d1SVille Syrjälä return -ERANGE; 3331b180b5d1SVille Syrjälä 3332b180b5d1SVille Syrjälä if ((uint64_t) height * r->pitches[i] + r->offsets[i] > UINT_MAX) 3333b180b5d1SVille Syrjälä return -ERANGE; 3334b180b5d1SVille Syrjälä 3335b180b5d1SVille Syrjälä if (r->pitches[i] < width * cpp) { 33361aa1b11cSDave Airlie DRM_DEBUG_KMS("bad pitch %u for plane %d\n", r->pitches[i], i); 3337d1b45d5fSVille Syrjälä return -EINVAL; 3338d1b45d5fSVille Syrjälä } 3339e3eb3250SRob Clark 3340e3eb3250SRob Clark if (r->modifier[i] && !(r->flags & DRM_MODE_FB_MODIFIERS)) { 3341e3eb3250SRob Clark DRM_DEBUG_KMS("bad fb modifier %llu for plane %d\n", 3342e3eb3250SRob Clark r->modifier[i], i); 3343e3eb3250SRob Clark return -EINVAL; 3344e3eb3250SRob Clark } 3345570655b0SRob Clark 3346570655b0SRob Clark /* modifier specific checks: */ 3347570655b0SRob Clark switch (r->modifier[i]) { 3348570655b0SRob Clark case DRM_FORMAT_MOD_SAMSUNG_64_32_TILE: 3349570655b0SRob Clark /* NOTE: the pitch restriction may be lifted later if it turns 3350570655b0SRob Clark * out that no hw has this restriction: 3351570655b0SRob Clark */ 3352570655b0SRob Clark if (r->pixel_format != DRM_FORMAT_NV12 || 3353570655b0SRob Clark width % 128 || height % 32 || 3354570655b0SRob Clark r->pitches[i] % 128) { 3355570655b0SRob Clark DRM_DEBUG_KMS("bad modifier data for plane %d\n", i); 3356570655b0SRob Clark return -EINVAL; 3357570655b0SRob Clark } 3358570655b0SRob Clark break; 3359570655b0SRob Clark 3360570655b0SRob Clark default: 3361570655b0SRob Clark break; 3362570655b0SRob Clark } 3363d1b45d5fSVille Syrjälä } 3364d1b45d5fSVille Syrjälä 3365bbe16a40SDaniel Vetter for (i = num_planes; i < 4; i++) { 3366bbe16a40SDaniel Vetter if (r->modifier[i]) { 3367bbe16a40SDaniel Vetter DRM_DEBUG_KMS("non-zero modifier for unused plane %d\n", i); 3368bbe16a40SDaniel Vetter return -EINVAL; 3369bbe16a40SDaniel Vetter } 3370bbe16a40SDaniel Vetter 3371bbe16a40SDaniel Vetter /* Pre-FB_MODIFIERS userspace didn't clear the structs properly. */ 3372bbe16a40SDaniel Vetter if (!(r->flags & DRM_MODE_FB_MODIFIERS)) 3373bbe16a40SDaniel Vetter continue; 3374bbe16a40SDaniel Vetter 3375bbe16a40SDaniel Vetter if (r->handles[i]) { 3376bbe16a40SDaniel Vetter DRM_DEBUG_KMS("buffer object handle for unused plane %d\n", i); 3377bbe16a40SDaniel Vetter return -EINVAL; 3378bbe16a40SDaniel Vetter } 3379bbe16a40SDaniel Vetter 3380bbe16a40SDaniel Vetter if (r->pitches[i]) { 3381bbe16a40SDaniel Vetter DRM_DEBUG_KMS("non-zero pitch for unused plane %d\n", i); 3382bbe16a40SDaniel Vetter return -EINVAL; 3383bbe16a40SDaniel Vetter } 3384bbe16a40SDaniel Vetter 3385bbe16a40SDaniel Vetter if (r->offsets[i]) { 3386bbe16a40SDaniel Vetter DRM_DEBUG_KMS("non-zero offset for unused plane %d\n", i); 3387bbe16a40SDaniel Vetter return -EINVAL; 3388bbe16a40SDaniel Vetter } 3389bbe16a40SDaniel Vetter } 3390bbe16a40SDaniel Vetter 3391d1b45d5fSVille Syrjälä return 0; 3392d1b45d5fSVille Syrjälä } 3393d1b45d5fSVille Syrjälä 33949a6f5130SChris Wilson static struct drm_framebuffer * 33959a6f5130SChris Wilson internal_framebuffer_create(struct drm_device *dev, 33961eb83451SVille Syrjälä const struct drm_mode_fb_cmd2 *r, 3397c394c2b0SMatt Roper struct drm_file *file_priv) 3398c394c2b0SMatt Roper { 3399c394c2b0SMatt Roper struct drm_mode_config *config = &dev->mode_config; 3400c394c2b0SMatt Roper struct drm_framebuffer *fb; 3401c394c2b0SMatt Roper int ret; 3402c394c2b0SMatt Roper 3403e3eb3250SRob Clark if (r->flags & ~(DRM_MODE_FB_INTERLACED | DRM_MODE_FB_MODIFIERS)) { 3404c394c2b0SMatt Roper DRM_DEBUG_KMS("bad framebuffer flags 0x%08x\n", r->flags); 3405c394c2b0SMatt Roper return ERR_PTR(-EINVAL); 3406c394c2b0SMatt Roper } 3407c394c2b0SMatt Roper 3408c394c2b0SMatt Roper if ((config->min_width > r->width) || (r->width > config->max_width)) { 3409c394c2b0SMatt Roper DRM_DEBUG_KMS("bad framebuffer width %d, should be >= %d && <= %d\n", 3410c394c2b0SMatt Roper r->width, config->min_width, config->max_width); 3411c394c2b0SMatt Roper return ERR_PTR(-EINVAL); 3412c394c2b0SMatt Roper } 3413c394c2b0SMatt Roper if ((config->min_height > r->height) || (r->height > config->max_height)) { 3414c394c2b0SMatt Roper DRM_DEBUG_KMS("bad framebuffer height %d, should be >= %d && <= %d\n", 3415c394c2b0SMatt Roper r->height, config->min_height, config->max_height); 3416c394c2b0SMatt Roper return ERR_PTR(-EINVAL); 3417c394c2b0SMatt Roper } 3418c394c2b0SMatt Roper 3419e3eb3250SRob Clark if (r->flags & DRM_MODE_FB_MODIFIERS && 3420e3eb3250SRob Clark !dev->mode_config.allow_fb_modifiers) { 3421e3eb3250SRob Clark DRM_DEBUG_KMS("driver does not support fb modifiers\n"); 3422e3eb3250SRob Clark return ERR_PTR(-EINVAL); 3423e3eb3250SRob Clark } 3424e3eb3250SRob Clark 3425c394c2b0SMatt Roper ret = framebuffer_check(r); 3426c394c2b0SMatt Roper if (ret) 3427c394c2b0SMatt Roper return ERR_PTR(ret); 3428c394c2b0SMatt Roper 3429c394c2b0SMatt Roper fb = dev->mode_config.funcs->fb_create(dev, file_priv, r); 3430c394c2b0SMatt Roper if (IS_ERR(fb)) { 3431c394c2b0SMatt Roper DRM_DEBUG_KMS("could not create framebuffer\n"); 3432c394c2b0SMatt Roper return fb; 3433c394c2b0SMatt Roper } 3434c394c2b0SMatt Roper 3435c394c2b0SMatt Roper return fb; 3436c394c2b0SMatt Roper } 3437c394c2b0SMatt Roper 3438308e5bcbSJesse Barnes /** 3439308e5bcbSJesse Barnes * drm_mode_addfb2 - add an FB to the graphics configuration 3440065a50edSDaniel Vetter * @dev: drm device for the ioctl 3441065a50edSDaniel Vetter * @data: data pointer for the ioctl 3442065a50edSDaniel Vetter * @file_priv: drm file for the ioctl call 3443308e5bcbSJesse Barnes * 3444c8e32cc1SDaniel Vetter * Add a new FB to the specified CRTC, given a user request with format. This is 3445c8e32cc1SDaniel Vetter * the 2nd version of the addfb ioctl, which supports multi-planar framebuffers 3446c8e32cc1SDaniel Vetter * and uses fourcc codes as pixel format specifiers. 3447308e5bcbSJesse Barnes * 3448308e5bcbSJesse Barnes * Called by the user via ioctl. 3449308e5bcbSJesse Barnes * 3450c8e32cc1SDaniel Vetter * Returns: 34511a498633SDaniel Vetter * Zero on success, negative errno on failure. 3452308e5bcbSJesse Barnes */ 3453308e5bcbSJesse Barnes int drm_mode_addfb2(struct drm_device *dev, 3454308e5bcbSJesse Barnes void *data, struct drm_file *file_priv) 3455308e5bcbSJesse Barnes { 34569a6f5130SChris Wilson struct drm_mode_fb_cmd2 *r = data; 3457f453ba04SDave Airlie struct drm_framebuffer *fb; 3458f453ba04SDave Airlie 3459fb3b06c8SDave Airlie if (!drm_core_check_feature(dev, DRIVER_MODESET)) 3460fb3b06c8SDave Airlie return -EINVAL; 3461fb3b06c8SDave Airlie 34629a6f5130SChris Wilson fb = internal_framebuffer_create(dev, r, file_priv); 3463c394c2b0SMatt Roper if (IS_ERR(fb)) 34644b096ac1SDaniel Vetter return PTR_ERR(fb); 3465f453ba04SDave Airlie 34669a6f5130SChris Wilson /* Transfer ownership to the filp for reaping on close */ 34679a6f5130SChris Wilson 34689a6f5130SChris Wilson DRM_DEBUG_KMS("[FB:%d]\n", fb->base.id); 34699a6f5130SChris Wilson mutex_lock(&file_priv->fbs_lock); 34709a6f5130SChris Wilson r->fb_id = fb->base.id; 34719a6f5130SChris Wilson list_add(&fb->filp_head, &file_priv->fbs); 34729a6f5130SChris Wilson mutex_unlock(&file_priv->fbs_lock); 34739a6f5130SChris Wilson 3474c394c2b0SMatt Roper return 0; 3475f453ba04SDave Airlie } 3476f453ba04SDave Airlie 3477f453ba04SDave Airlie /** 3478f453ba04SDave Airlie * drm_mode_rmfb - remove an FB from the configuration 3479065a50edSDaniel Vetter * @dev: drm device for the ioctl 3480065a50edSDaniel Vetter * @data: data pointer for the ioctl 3481065a50edSDaniel Vetter * @file_priv: drm file for the ioctl call 3482f453ba04SDave Airlie * 3483f453ba04SDave Airlie * Remove the FB specified by the user. 3484f453ba04SDave Airlie * 3485f453ba04SDave Airlie * Called by the user via ioctl. 3486f453ba04SDave Airlie * 3487c8e32cc1SDaniel Vetter * Returns: 34881a498633SDaniel Vetter * Zero on success, negative errno on failure. 3489f453ba04SDave Airlie */ 3490f453ba04SDave Airlie int drm_mode_rmfb(struct drm_device *dev, 3491f453ba04SDave Airlie void *data, struct drm_file *file_priv) 3492f453ba04SDave Airlie { 3493f453ba04SDave Airlie struct drm_framebuffer *fb = NULL; 3494f453ba04SDave Airlie struct drm_framebuffer *fbl = NULL; 3495f453ba04SDave Airlie uint32_t *id = data; 3496f453ba04SDave Airlie int found = 0; 3497f453ba04SDave Airlie 3498fb3b06c8SDave Airlie if (!drm_core_check_feature(dev, DRIVER_MODESET)) 3499fb3b06c8SDave Airlie return -EINVAL; 3500fb3b06c8SDave Airlie 35014b096ac1SDaniel Vetter mutex_lock(&file_priv->fbs_lock); 35022b677e8cSDaniel Vetter mutex_lock(&dev->mode_config.fb_lock); 35032b677e8cSDaniel Vetter fb = __drm_framebuffer_lookup(dev, *id); 35042b677e8cSDaniel Vetter if (!fb) 35052b677e8cSDaniel Vetter goto fail_lookup; 35062b677e8cSDaniel Vetter 3507f453ba04SDave Airlie list_for_each_entry(fbl, &file_priv->fbs, filp_head) 3508f453ba04SDave Airlie if (fb == fbl) 3509f453ba04SDave Airlie found = 1; 35102b677e8cSDaniel Vetter if (!found) 35112b677e8cSDaniel Vetter goto fail_lookup; 35122b677e8cSDaniel Vetter 35134b096ac1SDaniel Vetter list_del_init(&fb->filp_head); 35142b677e8cSDaniel Vetter mutex_unlock(&dev->mode_config.fb_lock); 35154b096ac1SDaniel Vetter mutex_unlock(&file_priv->fbs_lock); 3516f453ba04SDave Airlie 351713803132SMaarten Lankhorst drm_framebuffer_unreference(fb); 35184b096ac1SDaniel Vetter 35192b677e8cSDaniel Vetter return 0; 35202b677e8cSDaniel Vetter 35212b677e8cSDaniel Vetter fail_lookup: 35222b677e8cSDaniel Vetter mutex_unlock(&dev->mode_config.fb_lock); 35232b677e8cSDaniel Vetter mutex_unlock(&file_priv->fbs_lock); 35242b677e8cSDaniel Vetter 352537c4e705SVille Syrjälä return -ENOENT; 3526f453ba04SDave Airlie } 3527f453ba04SDave Airlie 3528f453ba04SDave Airlie /** 3529f453ba04SDave Airlie * drm_mode_getfb - get FB info 3530065a50edSDaniel Vetter * @dev: drm device for the ioctl 3531065a50edSDaniel Vetter * @data: data pointer for the ioctl 3532065a50edSDaniel Vetter * @file_priv: drm file for the ioctl call 3533f453ba04SDave Airlie * 3534f453ba04SDave Airlie * Lookup the FB given its ID and return info about it. 3535f453ba04SDave Airlie * 3536f453ba04SDave Airlie * Called by the user via ioctl. 3537f453ba04SDave Airlie * 3538c8e32cc1SDaniel Vetter * Returns: 35391a498633SDaniel Vetter * Zero on success, negative errno on failure. 3540f453ba04SDave Airlie */ 3541f453ba04SDave Airlie int drm_mode_getfb(struct drm_device *dev, 3542f453ba04SDave Airlie void *data, struct drm_file *file_priv) 3543f453ba04SDave Airlie { 3544f453ba04SDave Airlie struct drm_mode_fb_cmd *r = data; 3545f453ba04SDave Airlie struct drm_framebuffer *fb; 354658c0dca1SDaniel Vetter int ret; 3547f453ba04SDave Airlie 3548fb3b06c8SDave Airlie if (!drm_core_check_feature(dev, DRIVER_MODESET)) 3549fb3b06c8SDave Airlie return -EINVAL; 3550fb3b06c8SDave Airlie 3551786b99edSDaniel Vetter fb = drm_framebuffer_lookup(dev, r->fb_id); 355258c0dca1SDaniel Vetter if (!fb) 355337c4e705SVille Syrjälä return -ENOENT; 3554f453ba04SDave Airlie 3555f453ba04SDave Airlie r->height = fb->height; 3556f453ba04SDave Airlie r->width = fb->width; 3557f453ba04SDave Airlie r->depth = fb->depth; 3558f453ba04SDave Airlie r->bpp = fb->bits_per_pixel; 355901f2c773SVille Syrjälä r->pitch = fb->pitches[0]; 3560101b96f3SDavid Herrmann if (fb->funcs->create_handle) { 356109f308f7SThomas Hellstrom if (file_priv->is_master || capable(CAP_SYS_ADMIN) || 356243683057SThomas Hellstrom drm_is_control_client(file_priv)) { 3563101b96f3SDavid Herrmann ret = fb->funcs->create_handle(fb, file_priv, 3564101b96f3SDavid Herrmann &r->handle); 3565101b96f3SDavid Herrmann } else { 3566101b96f3SDavid Herrmann /* GET_FB() is an unprivileged ioctl so we must not 3567101b96f3SDavid Herrmann * return a buffer-handle to non-master processes! For 3568101b96f3SDavid Herrmann * backwards-compatibility reasons, we cannot make 3569101b96f3SDavid Herrmann * GET_FB() privileged, so just return an invalid handle 3570101b96f3SDavid Herrmann * for non-masters. */ 3571101b96f3SDavid Herrmann r->handle = 0; 3572101b96f3SDavid Herrmann ret = 0; 3573101b96f3SDavid Herrmann } 3574101b96f3SDavid Herrmann } else { 3575af26ef3bSDaniel Vetter ret = -ENODEV; 3576101b96f3SDavid Herrmann } 3577f453ba04SDave Airlie 357858c0dca1SDaniel Vetter drm_framebuffer_unreference(fb); 357958c0dca1SDaniel Vetter 3580f453ba04SDave Airlie return ret; 3581f453ba04SDave Airlie } 3582f453ba04SDave Airlie 3583c8e32cc1SDaniel Vetter /** 3584c8e32cc1SDaniel Vetter * drm_mode_dirtyfb_ioctl - flush frontbuffer rendering on an FB 3585c8e32cc1SDaniel Vetter * @dev: drm device for the ioctl 3586c8e32cc1SDaniel Vetter * @data: data pointer for the ioctl 3587c8e32cc1SDaniel Vetter * @file_priv: drm file for the ioctl call 3588c8e32cc1SDaniel Vetter * 3589c8e32cc1SDaniel Vetter * Lookup the FB and flush out the damaged area supplied by userspace as a clip 3590c8e32cc1SDaniel Vetter * rectangle list. Generic userspace which does frontbuffer rendering must call 3591c8e32cc1SDaniel Vetter * this ioctl to flush out the changes on manual-update display outputs, e.g. 3592c8e32cc1SDaniel Vetter * usb display-link, mipi manual update panels or edp panel self refresh modes. 3593c8e32cc1SDaniel Vetter * 3594c8e32cc1SDaniel Vetter * Modesetting drivers which always update the frontbuffer do not need to 3595c8e32cc1SDaniel Vetter * implement the corresponding ->dirty framebuffer callback. 3596c8e32cc1SDaniel Vetter * 3597c8e32cc1SDaniel Vetter * Called by the user via ioctl. 3598c8e32cc1SDaniel Vetter * 3599c8e32cc1SDaniel Vetter * Returns: 36001a498633SDaniel Vetter * Zero on success, negative errno on failure. 3601c8e32cc1SDaniel Vetter */ 3602884840aaSJakob Bornecrantz int drm_mode_dirtyfb_ioctl(struct drm_device *dev, 3603884840aaSJakob Bornecrantz void *data, struct drm_file *file_priv) 3604884840aaSJakob Bornecrantz { 3605884840aaSJakob Bornecrantz struct drm_clip_rect __user *clips_ptr; 3606884840aaSJakob Bornecrantz struct drm_clip_rect *clips = NULL; 3607884840aaSJakob Bornecrantz struct drm_mode_fb_dirty_cmd *r = data; 3608884840aaSJakob Bornecrantz struct drm_framebuffer *fb; 3609884840aaSJakob Bornecrantz unsigned flags; 3610884840aaSJakob Bornecrantz int num_clips; 36114a1b0714SLaurent Pinchart int ret; 3612884840aaSJakob Bornecrantz 3613fb3b06c8SDave Airlie if (!drm_core_check_feature(dev, DRIVER_MODESET)) 3614fb3b06c8SDave Airlie return -EINVAL; 3615fb3b06c8SDave Airlie 3616786b99edSDaniel Vetter fb = drm_framebuffer_lookup(dev, r->fb_id); 36174ccf097fSDaniel Vetter if (!fb) 361837c4e705SVille Syrjälä return -ENOENT; 3619884840aaSJakob Bornecrantz 3620884840aaSJakob Bornecrantz num_clips = r->num_clips; 362181f6c7f8SVille Syrjälä clips_ptr = (struct drm_clip_rect __user *)(unsigned long)r->clips_ptr; 3622884840aaSJakob Bornecrantz 3623884840aaSJakob Bornecrantz if (!num_clips != !clips_ptr) { 3624884840aaSJakob Bornecrantz ret = -EINVAL; 3625884840aaSJakob Bornecrantz goto out_err1; 3626884840aaSJakob Bornecrantz } 3627884840aaSJakob Bornecrantz 3628884840aaSJakob Bornecrantz flags = DRM_MODE_FB_DIRTY_FLAGS & r->flags; 3629884840aaSJakob Bornecrantz 3630884840aaSJakob Bornecrantz /* If userspace annotates copy, clips must come in pairs */ 3631884840aaSJakob Bornecrantz if (flags & DRM_MODE_FB_DIRTY_ANNOTATE_COPY && (num_clips % 2)) { 3632884840aaSJakob Bornecrantz ret = -EINVAL; 3633884840aaSJakob Bornecrantz goto out_err1; 3634884840aaSJakob Bornecrantz } 3635884840aaSJakob Bornecrantz 3636884840aaSJakob Bornecrantz if (num_clips && clips_ptr) { 3637a5cd3351SXi Wang if (num_clips < 0 || num_clips > DRM_MODE_FB_DIRTY_MAX_CLIPS) { 3638a5cd3351SXi Wang ret = -EINVAL; 3639a5cd3351SXi Wang goto out_err1; 3640a5cd3351SXi Wang } 3641bd3f0ff9SThierry Reding clips = kcalloc(num_clips, sizeof(*clips), GFP_KERNEL); 3642884840aaSJakob Bornecrantz if (!clips) { 3643884840aaSJakob Bornecrantz ret = -ENOMEM; 3644884840aaSJakob Bornecrantz goto out_err1; 3645884840aaSJakob Bornecrantz } 3646884840aaSJakob Bornecrantz 3647884840aaSJakob Bornecrantz ret = copy_from_user(clips, clips_ptr, 3648884840aaSJakob Bornecrantz num_clips * sizeof(*clips)); 3649e902a358SDan Carpenter if (ret) { 3650e902a358SDan Carpenter ret = -EFAULT; 3651884840aaSJakob Bornecrantz goto out_err2; 3652884840aaSJakob Bornecrantz } 3653e902a358SDan Carpenter } 3654884840aaSJakob Bornecrantz 3655884840aaSJakob Bornecrantz if (fb->funcs->dirty) { 365602b00162SThomas Hellstrom ret = fb->funcs->dirty(fb, file_priv, flags, r->color, 365702b00162SThomas Hellstrom clips, num_clips); 3658884840aaSJakob Bornecrantz } else { 3659884840aaSJakob Bornecrantz ret = -ENOSYS; 3660884840aaSJakob Bornecrantz } 3661884840aaSJakob Bornecrantz 3662884840aaSJakob Bornecrantz out_err2: 3663884840aaSJakob Bornecrantz kfree(clips); 3664884840aaSJakob Bornecrantz out_err1: 36654ccf097fSDaniel Vetter drm_framebuffer_unreference(fb); 36664ccf097fSDaniel Vetter 3667884840aaSJakob Bornecrantz return ret; 3668884840aaSJakob Bornecrantz } 3669884840aaSJakob Bornecrantz 3670884840aaSJakob Bornecrantz 3671f453ba04SDave Airlie /** 3672f453ba04SDave Airlie * drm_fb_release - remove and free the FBs on this file 3673065a50edSDaniel Vetter * @priv: drm file for the ioctl 3674f453ba04SDave Airlie * 3675f453ba04SDave Airlie * Destroy all the FBs associated with @filp. 3676f453ba04SDave Airlie * 3677f453ba04SDave Airlie * Called by the user via ioctl. 3678f453ba04SDave Airlie * 3679c8e32cc1SDaniel Vetter * Returns: 36801a498633SDaniel Vetter * Zero on success, negative errno on failure. 3681f453ba04SDave Airlie */ 3682ea39f835SKristian Høgsberg void drm_fb_release(struct drm_file *priv) 3683f453ba04SDave Airlie { 3684f453ba04SDave Airlie struct drm_framebuffer *fb, *tfb; 3685f453ba04SDave Airlie 36861b116297SDaniel Vetter /* 36871b116297SDaniel Vetter * When the file gets released that means no one else can access the fb 3688e2db726bSMartin Peres * list any more, so no need to grab fpriv->fbs_lock. And we need to 36891b116297SDaniel Vetter * avoid upsetting lockdep since the universal cursor code adds a 36901b116297SDaniel Vetter * framebuffer while holding mutex locks. 36911b116297SDaniel Vetter * 36921b116297SDaniel Vetter * Note that a real deadlock between fpriv->fbs_lock and the modeset 36931b116297SDaniel Vetter * locks is impossible here since no one else but this function can get 36941b116297SDaniel Vetter * at it any more. 36951b116297SDaniel Vetter */ 3696f453ba04SDave Airlie list_for_each_entry_safe(fb, tfb, &priv->fbs, filp_head) { 36974b096ac1SDaniel Vetter list_del_init(&fb->filp_head); 36982b677e8cSDaniel Vetter 369973f7570bSMaarten Lankhorst /* This drops the fpriv->fbs reference. */ 370013803132SMaarten Lankhorst drm_framebuffer_unreference(fb); 3701f453ba04SDave Airlie } 3702f453ba04SDave Airlie } 3703f453ba04SDave Airlie 3704c8e32cc1SDaniel Vetter /** 3705c8e32cc1SDaniel Vetter * drm_property_create - create a new property type 3706c8e32cc1SDaniel Vetter * @dev: drm device 3707c8e32cc1SDaniel Vetter * @flags: flags specifying the property type 3708c8e32cc1SDaniel Vetter * @name: name of the property 3709c8e32cc1SDaniel Vetter * @num_values: number of pre-defined values 3710c8e32cc1SDaniel Vetter * 3711c8e32cc1SDaniel Vetter * This creates a new generic drm property which can then be attached to a drm 3712c8e32cc1SDaniel Vetter * object with drm_object_attach_property. The returned property object must be 3713c8e32cc1SDaniel Vetter * freed with drm_property_destroy. 3714c8e32cc1SDaniel Vetter * 37153b5b9932SDamien Lespiau * Note that the DRM core keeps a per-device list of properties and that, if 37163b5b9932SDamien Lespiau * drm_mode_config_cleanup() is called, it will destroy all properties created 37173b5b9932SDamien Lespiau * by the driver. 37183b5b9932SDamien Lespiau * 3719c8e32cc1SDaniel Vetter * Returns: 3720c8e32cc1SDaniel Vetter * A pointer to the newly created property on success, NULL on failure. 3721c8e32cc1SDaniel Vetter */ 3722f453ba04SDave Airlie struct drm_property *drm_property_create(struct drm_device *dev, int flags, 3723f453ba04SDave Airlie const char *name, int num_values) 3724f453ba04SDave Airlie { 3725f453ba04SDave Airlie struct drm_property *property = NULL; 37266bfc56aaSVille Syrjälä int ret; 3727f453ba04SDave Airlie 3728f453ba04SDave Airlie property = kzalloc(sizeof(struct drm_property), GFP_KERNEL); 3729f453ba04SDave Airlie if (!property) 3730f453ba04SDave Airlie return NULL; 3731f453ba04SDave Airlie 373298f75de4SRob Clark property->dev = dev; 373398f75de4SRob Clark 3734f453ba04SDave Airlie if (num_values) { 3735bd3f0ff9SThierry Reding property->values = kcalloc(num_values, sizeof(uint64_t), 3736bd3f0ff9SThierry Reding GFP_KERNEL); 3737f453ba04SDave Airlie if (!property->values) 3738f453ba04SDave Airlie goto fail; 3739f453ba04SDave Airlie } 3740f453ba04SDave Airlie 37416bfc56aaSVille Syrjälä ret = drm_mode_object_get(dev, &property->base, DRM_MODE_OBJECT_PROPERTY); 37426bfc56aaSVille Syrjälä if (ret) 37436bfc56aaSVille Syrjälä goto fail; 37446bfc56aaSVille Syrjälä 3745f453ba04SDave Airlie property->flags = flags; 3746f453ba04SDave Airlie property->num_values = num_values; 37473758b341SDaniel Vetter INIT_LIST_HEAD(&property->enum_list); 3748f453ba04SDave Airlie 3749471dd2efSVinson Lee if (name) { 3750f453ba04SDave Airlie strncpy(property->name, name, DRM_PROP_NAME_LEN); 3751471dd2efSVinson Lee property->name[DRM_PROP_NAME_LEN-1] = '\0'; 3752471dd2efSVinson Lee } 3753f453ba04SDave Airlie 3754f453ba04SDave Airlie list_add_tail(&property->head, &dev->mode_config.property_list); 37555ea22f24SRob Clark 37565ea22f24SRob Clark WARN_ON(!drm_property_type_valid(property)); 37575ea22f24SRob Clark 3758f453ba04SDave Airlie return property; 3759f453ba04SDave Airlie fail: 37606bfc56aaSVille Syrjälä kfree(property->values); 3761f453ba04SDave Airlie kfree(property); 3762f453ba04SDave Airlie return NULL; 3763f453ba04SDave Airlie } 3764f453ba04SDave Airlie EXPORT_SYMBOL(drm_property_create); 3765f453ba04SDave Airlie 3766c8e32cc1SDaniel Vetter /** 37672aa9d2bcSThierry Reding * drm_property_create_enum - create a new enumeration property type 3768c8e32cc1SDaniel Vetter * @dev: drm device 3769c8e32cc1SDaniel Vetter * @flags: flags specifying the property type 3770c8e32cc1SDaniel Vetter * @name: name of the property 3771c8e32cc1SDaniel Vetter * @props: enumeration lists with property values 3772c8e32cc1SDaniel Vetter * @num_values: number of pre-defined values 3773c8e32cc1SDaniel Vetter * 3774c8e32cc1SDaniel Vetter * This creates a new generic drm property which can then be attached to a drm 3775c8e32cc1SDaniel Vetter * object with drm_object_attach_property. The returned property object must be 3776c8e32cc1SDaniel Vetter * freed with drm_property_destroy. 3777c8e32cc1SDaniel Vetter * 3778c8e32cc1SDaniel Vetter * Userspace is only allowed to set one of the predefined values for enumeration 3779c8e32cc1SDaniel Vetter * properties. 3780c8e32cc1SDaniel Vetter * 3781c8e32cc1SDaniel Vetter * Returns: 3782c8e32cc1SDaniel Vetter * A pointer to the newly created property on success, NULL on failure. 3783c8e32cc1SDaniel Vetter */ 37844a67d391SSascha Hauer struct drm_property *drm_property_create_enum(struct drm_device *dev, int flags, 37854a67d391SSascha Hauer const char *name, 37864a67d391SSascha Hauer const struct drm_prop_enum_list *props, 37874a67d391SSascha Hauer int num_values) 37884a67d391SSascha Hauer { 37894a67d391SSascha Hauer struct drm_property *property; 37904a67d391SSascha Hauer int i, ret; 37914a67d391SSascha Hauer 37924a67d391SSascha Hauer flags |= DRM_MODE_PROP_ENUM; 37934a67d391SSascha Hauer 37944a67d391SSascha Hauer property = drm_property_create(dev, flags, name, num_values); 37954a67d391SSascha Hauer if (!property) 37964a67d391SSascha Hauer return NULL; 37974a67d391SSascha Hauer 37984a67d391SSascha Hauer for (i = 0; i < num_values; i++) { 37994a67d391SSascha Hauer ret = drm_property_add_enum(property, i, 38004a67d391SSascha Hauer props[i].type, 38014a67d391SSascha Hauer props[i].name); 38024a67d391SSascha Hauer if (ret) { 38034a67d391SSascha Hauer drm_property_destroy(dev, property); 38044a67d391SSascha Hauer return NULL; 38054a67d391SSascha Hauer } 38064a67d391SSascha Hauer } 38074a67d391SSascha Hauer 38084a67d391SSascha Hauer return property; 38094a67d391SSascha Hauer } 38104a67d391SSascha Hauer EXPORT_SYMBOL(drm_property_create_enum); 38114a67d391SSascha Hauer 3812c8e32cc1SDaniel Vetter /** 38132aa9d2bcSThierry Reding * drm_property_create_bitmask - create a new bitmask property type 3814c8e32cc1SDaniel Vetter * @dev: drm device 3815c8e32cc1SDaniel Vetter * @flags: flags specifying the property type 3816c8e32cc1SDaniel Vetter * @name: name of the property 3817c8e32cc1SDaniel Vetter * @props: enumeration lists with property bitflags 3818295ee853SDaniel Vetter * @num_props: size of the @props array 3819295ee853SDaniel Vetter * @supported_bits: bitmask of all supported enumeration values 3820c8e32cc1SDaniel Vetter * 3821295ee853SDaniel Vetter * This creates a new bitmask drm property which can then be attached to a drm 3822c8e32cc1SDaniel Vetter * object with drm_object_attach_property. The returned property object must be 3823c8e32cc1SDaniel Vetter * freed with drm_property_destroy. 3824c8e32cc1SDaniel Vetter * 3825c8e32cc1SDaniel Vetter * Compared to plain enumeration properties userspace is allowed to set any 3826c8e32cc1SDaniel Vetter * or'ed together combination of the predefined property bitflag values 3827c8e32cc1SDaniel Vetter * 3828c8e32cc1SDaniel Vetter * Returns: 3829c8e32cc1SDaniel Vetter * A pointer to the newly created property on success, NULL on failure. 3830c8e32cc1SDaniel Vetter */ 383149e27545SRob Clark struct drm_property *drm_property_create_bitmask(struct drm_device *dev, 383249e27545SRob Clark int flags, const char *name, 383349e27545SRob Clark const struct drm_prop_enum_list *props, 38347689ffb3SVille Syrjälä int num_props, 38357689ffb3SVille Syrjälä uint64_t supported_bits) 383649e27545SRob Clark { 383749e27545SRob Clark struct drm_property *property; 38387689ffb3SVille Syrjälä int i, ret, index = 0; 38397689ffb3SVille Syrjälä int num_values = hweight64(supported_bits); 384049e27545SRob Clark 384149e27545SRob Clark flags |= DRM_MODE_PROP_BITMASK; 384249e27545SRob Clark 384349e27545SRob Clark property = drm_property_create(dev, flags, name, num_values); 384449e27545SRob Clark if (!property) 384549e27545SRob Clark return NULL; 38467689ffb3SVille Syrjälä for (i = 0; i < num_props; i++) { 38477689ffb3SVille Syrjälä if (!(supported_bits & (1ULL << props[i].type))) 38487689ffb3SVille Syrjälä continue; 384949e27545SRob Clark 38507689ffb3SVille Syrjälä if (WARN_ON(index >= num_values)) { 38517689ffb3SVille Syrjälä drm_property_destroy(dev, property); 38527689ffb3SVille Syrjälä return NULL; 38537689ffb3SVille Syrjälä } 38547689ffb3SVille Syrjälä 38557689ffb3SVille Syrjälä ret = drm_property_add_enum(property, index++, 385649e27545SRob Clark props[i].type, 385749e27545SRob Clark props[i].name); 385849e27545SRob Clark if (ret) { 385949e27545SRob Clark drm_property_destroy(dev, property); 386049e27545SRob Clark return NULL; 386149e27545SRob Clark } 386249e27545SRob Clark } 386349e27545SRob Clark 386449e27545SRob Clark return property; 386549e27545SRob Clark } 386649e27545SRob Clark EXPORT_SYMBOL(drm_property_create_bitmask); 386749e27545SRob Clark 3868ebc44cf3SRob Clark static struct drm_property *property_create_range(struct drm_device *dev, 3869ebc44cf3SRob Clark int flags, const char *name, 3870ebc44cf3SRob Clark uint64_t min, uint64_t max) 3871ebc44cf3SRob Clark { 3872ebc44cf3SRob Clark struct drm_property *property; 3873ebc44cf3SRob Clark 3874ebc44cf3SRob Clark property = drm_property_create(dev, flags, name, 2); 3875ebc44cf3SRob Clark if (!property) 3876ebc44cf3SRob Clark return NULL; 3877ebc44cf3SRob Clark 3878ebc44cf3SRob Clark property->values[0] = min; 3879ebc44cf3SRob Clark property->values[1] = max; 3880ebc44cf3SRob Clark 3881ebc44cf3SRob Clark return property; 3882ebc44cf3SRob Clark } 3883ebc44cf3SRob Clark 3884c8e32cc1SDaniel Vetter /** 3885960cd9d4SDaniel Vetter * drm_property_create_range - create a new unsigned ranged property type 3886c8e32cc1SDaniel Vetter * @dev: drm device 3887c8e32cc1SDaniel Vetter * @flags: flags specifying the property type 3888c8e32cc1SDaniel Vetter * @name: name of the property 3889c8e32cc1SDaniel Vetter * @min: minimum value of the property 3890c8e32cc1SDaniel Vetter * @max: maximum value of the property 3891c8e32cc1SDaniel Vetter * 3892c8e32cc1SDaniel Vetter * This creates a new generic drm property which can then be attached to a drm 3893c8e32cc1SDaniel Vetter * object with drm_object_attach_property. The returned property object must be 3894c8e32cc1SDaniel Vetter * freed with drm_property_destroy. 3895c8e32cc1SDaniel Vetter * 3896960cd9d4SDaniel Vetter * Userspace is allowed to set any unsigned integer value in the (min, max) 3897960cd9d4SDaniel Vetter * range inclusive. 3898c8e32cc1SDaniel Vetter * 3899c8e32cc1SDaniel Vetter * Returns: 3900c8e32cc1SDaniel Vetter * A pointer to the newly created property on success, NULL on failure. 3901c8e32cc1SDaniel Vetter */ 3902d9bc3c02SSascha Hauer struct drm_property *drm_property_create_range(struct drm_device *dev, int flags, 3903d9bc3c02SSascha Hauer const char *name, 3904d9bc3c02SSascha Hauer uint64_t min, uint64_t max) 3905d9bc3c02SSascha Hauer { 3906ebc44cf3SRob Clark return property_create_range(dev, DRM_MODE_PROP_RANGE | flags, 3907ebc44cf3SRob Clark name, min, max); 3908d9bc3c02SSascha Hauer } 3909d9bc3c02SSascha Hauer EXPORT_SYMBOL(drm_property_create_range); 3910d9bc3c02SSascha Hauer 3911960cd9d4SDaniel Vetter /** 3912960cd9d4SDaniel Vetter * drm_property_create_signed_range - create a new signed ranged property type 3913960cd9d4SDaniel Vetter * @dev: drm device 3914960cd9d4SDaniel Vetter * @flags: flags specifying the property type 3915960cd9d4SDaniel Vetter * @name: name of the property 3916960cd9d4SDaniel Vetter * @min: minimum value of the property 3917960cd9d4SDaniel Vetter * @max: maximum value of the property 3918960cd9d4SDaniel Vetter * 3919960cd9d4SDaniel Vetter * This creates a new generic drm property which can then be attached to a drm 3920960cd9d4SDaniel Vetter * object with drm_object_attach_property. The returned property object must be 3921960cd9d4SDaniel Vetter * freed with drm_property_destroy. 3922960cd9d4SDaniel Vetter * 3923960cd9d4SDaniel Vetter * Userspace is allowed to set any signed integer value in the (min, max) 3924960cd9d4SDaniel Vetter * range inclusive. 3925960cd9d4SDaniel Vetter * 3926960cd9d4SDaniel Vetter * Returns: 3927960cd9d4SDaniel Vetter * A pointer to the newly created property on success, NULL on failure. 3928960cd9d4SDaniel Vetter */ 3929ebc44cf3SRob Clark struct drm_property *drm_property_create_signed_range(struct drm_device *dev, 3930ebc44cf3SRob Clark int flags, const char *name, 3931ebc44cf3SRob Clark int64_t min, int64_t max) 3932ebc44cf3SRob Clark { 3933ebc44cf3SRob Clark return property_create_range(dev, DRM_MODE_PROP_SIGNED_RANGE | flags, 3934ebc44cf3SRob Clark name, I642U64(min), I642U64(max)); 3935ebc44cf3SRob Clark } 3936ebc44cf3SRob Clark EXPORT_SYMBOL(drm_property_create_signed_range); 3937ebc44cf3SRob Clark 3938960cd9d4SDaniel Vetter /** 3939960cd9d4SDaniel Vetter * drm_property_create_object - create a new object property type 3940960cd9d4SDaniel Vetter * @dev: drm device 3941960cd9d4SDaniel Vetter * @flags: flags specifying the property type 3942960cd9d4SDaniel Vetter * @name: name of the property 3943960cd9d4SDaniel Vetter * @type: object type from DRM_MODE_OBJECT_* defines 3944960cd9d4SDaniel Vetter * 3945960cd9d4SDaniel Vetter * This creates a new generic drm property which can then be attached to a drm 3946960cd9d4SDaniel Vetter * object with drm_object_attach_property. The returned property object must be 3947960cd9d4SDaniel Vetter * freed with drm_property_destroy. 3948960cd9d4SDaniel Vetter * 3949960cd9d4SDaniel Vetter * Userspace is only allowed to set this to any property value of the given 3950960cd9d4SDaniel Vetter * @type. Only useful for atomic properties, which is enforced. 3951960cd9d4SDaniel Vetter * 3952960cd9d4SDaniel Vetter * Returns: 3953960cd9d4SDaniel Vetter * A pointer to the newly created property on success, NULL on failure. 3954960cd9d4SDaniel Vetter */ 395598f75de4SRob Clark struct drm_property *drm_property_create_object(struct drm_device *dev, 395698f75de4SRob Clark int flags, const char *name, uint32_t type) 395798f75de4SRob Clark { 395898f75de4SRob Clark struct drm_property *property; 395998f75de4SRob Clark 396098f75de4SRob Clark flags |= DRM_MODE_PROP_OBJECT; 396198f75de4SRob Clark 3962960cd9d4SDaniel Vetter if (WARN_ON(!(flags & DRM_MODE_PROP_ATOMIC))) 3963960cd9d4SDaniel Vetter return NULL; 3964960cd9d4SDaniel Vetter 396598f75de4SRob Clark property = drm_property_create(dev, flags, name, 1); 396698f75de4SRob Clark if (!property) 396798f75de4SRob Clark return NULL; 396898f75de4SRob Clark 396998f75de4SRob Clark property->values[0] = type; 397098f75de4SRob Clark 397198f75de4SRob Clark return property; 397298f75de4SRob Clark } 397398f75de4SRob Clark EXPORT_SYMBOL(drm_property_create_object); 397498f75de4SRob Clark 3975c8e32cc1SDaniel Vetter /** 3976960cd9d4SDaniel Vetter * drm_property_create_bool - create a new boolean property type 3977960cd9d4SDaniel Vetter * @dev: drm device 3978960cd9d4SDaniel Vetter * @flags: flags specifying the property type 3979960cd9d4SDaniel Vetter * @name: name of the property 3980960cd9d4SDaniel Vetter * 3981960cd9d4SDaniel Vetter * This creates a new generic drm property which can then be attached to a drm 3982960cd9d4SDaniel Vetter * object with drm_object_attach_property. The returned property object must be 3983960cd9d4SDaniel Vetter * freed with drm_property_destroy. 3984960cd9d4SDaniel Vetter * 3985960cd9d4SDaniel Vetter * This is implemented as a ranged property with only {0, 1} as valid values. 3986960cd9d4SDaniel Vetter * 3987960cd9d4SDaniel Vetter * Returns: 3988960cd9d4SDaniel Vetter * A pointer to the newly created property on success, NULL on failure. 3989960cd9d4SDaniel Vetter */ 3990960cd9d4SDaniel Vetter struct drm_property *drm_property_create_bool(struct drm_device *dev, int flags, 3991960cd9d4SDaniel Vetter const char *name) 3992960cd9d4SDaniel Vetter { 3993960cd9d4SDaniel Vetter return drm_property_create_range(dev, flags, name, 0, 1); 3994960cd9d4SDaniel Vetter } 3995960cd9d4SDaniel Vetter EXPORT_SYMBOL(drm_property_create_bool); 3996960cd9d4SDaniel Vetter 3997960cd9d4SDaniel Vetter /** 3998c8e32cc1SDaniel Vetter * drm_property_add_enum - add a possible value to an enumeration property 3999c8e32cc1SDaniel Vetter * @property: enumeration property to change 4000c8e32cc1SDaniel Vetter * @index: index of the new enumeration 4001c8e32cc1SDaniel Vetter * @value: value of the new enumeration 4002c8e32cc1SDaniel Vetter * @name: symbolic name of the new enumeration 4003c8e32cc1SDaniel Vetter * 4004c8e32cc1SDaniel Vetter * This functions adds enumerations to a property. 4005c8e32cc1SDaniel Vetter * 4006c8e32cc1SDaniel Vetter * It's use is deprecated, drivers should use one of the more specific helpers 4007c8e32cc1SDaniel Vetter * to directly create the property with all enumerations already attached. 4008c8e32cc1SDaniel Vetter * 4009c8e32cc1SDaniel Vetter * Returns: 4010c8e32cc1SDaniel Vetter * Zero on success, error code on failure. 4011c8e32cc1SDaniel Vetter */ 4012f453ba04SDave Airlie int drm_property_add_enum(struct drm_property *property, int index, 4013f453ba04SDave Airlie uint64_t value, const char *name) 4014f453ba04SDave Airlie { 4015f453ba04SDave Airlie struct drm_property_enum *prop_enum; 4016f453ba04SDave Airlie 40175ea22f24SRob Clark if (!(drm_property_type_is(property, DRM_MODE_PROP_ENUM) || 40185ea22f24SRob Clark drm_property_type_is(property, DRM_MODE_PROP_BITMASK))) 401949e27545SRob Clark return -EINVAL; 402049e27545SRob Clark 402149e27545SRob Clark /* 402249e27545SRob Clark * Bitmask enum properties have the additional constraint of values 402349e27545SRob Clark * from 0 to 63 402449e27545SRob Clark */ 40255ea22f24SRob Clark if (drm_property_type_is(property, DRM_MODE_PROP_BITMASK) && 40265ea22f24SRob Clark (value > 63)) 4027f453ba04SDave Airlie return -EINVAL; 4028f453ba04SDave Airlie 40293758b341SDaniel Vetter if (!list_empty(&property->enum_list)) { 40303758b341SDaniel Vetter list_for_each_entry(prop_enum, &property->enum_list, head) { 4031f453ba04SDave Airlie if (prop_enum->value == value) { 4032f453ba04SDave Airlie strncpy(prop_enum->name, name, DRM_PROP_NAME_LEN); 4033f453ba04SDave Airlie prop_enum->name[DRM_PROP_NAME_LEN-1] = '\0'; 4034f453ba04SDave Airlie return 0; 4035f453ba04SDave Airlie } 4036f453ba04SDave Airlie } 4037f453ba04SDave Airlie } 4038f453ba04SDave Airlie 4039f453ba04SDave Airlie prop_enum = kzalloc(sizeof(struct drm_property_enum), GFP_KERNEL); 4040f453ba04SDave Airlie if (!prop_enum) 4041f453ba04SDave Airlie return -ENOMEM; 4042f453ba04SDave Airlie 4043f453ba04SDave Airlie strncpy(prop_enum->name, name, DRM_PROP_NAME_LEN); 4044f453ba04SDave Airlie prop_enum->name[DRM_PROP_NAME_LEN-1] = '\0'; 4045f453ba04SDave Airlie prop_enum->value = value; 4046f453ba04SDave Airlie 4047f453ba04SDave Airlie property->values[index] = value; 40483758b341SDaniel Vetter list_add_tail(&prop_enum->head, &property->enum_list); 4049f453ba04SDave Airlie return 0; 4050f453ba04SDave Airlie } 4051f453ba04SDave Airlie EXPORT_SYMBOL(drm_property_add_enum); 4052f453ba04SDave Airlie 4053c8e32cc1SDaniel Vetter /** 4054c8e32cc1SDaniel Vetter * drm_property_destroy - destroy a drm property 4055c8e32cc1SDaniel Vetter * @dev: drm device 4056c8e32cc1SDaniel Vetter * @property: property to destry 4057c8e32cc1SDaniel Vetter * 4058c8e32cc1SDaniel Vetter * This function frees a property including any attached resources like 4059c8e32cc1SDaniel Vetter * enumeration values. 4060c8e32cc1SDaniel Vetter */ 4061f453ba04SDave Airlie void drm_property_destroy(struct drm_device *dev, struct drm_property *property) 4062f453ba04SDave Airlie { 4063f453ba04SDave Airlie struct drm_property_enum *prop_enum, *pt; 4064f453ba04SDave Airlie 40653758b341SDaniel Vetter list_for_each_entry_safe(prop_enum, pt, &property->enum_list, head) { 4066f453ba04SDave Airlie list_del(&prop_enum->head); 4067f453ba04SDave Airlie kfree(prop_enum); 4068f453ba04SDave Airlie } 4069f453ba04SDave Airlie 4070f453ba04SDave Airlie if (property->num_values) 4071f453ba04SDave Airlie kfree(property->values); 4072f453ba04SDave Airlie drm_mode_object_put(dev, &property->base); 4073f453ba04SDave Airlie list_del(&property->head); 4074f453ba04SDave Airlie kfree(property); 4075f453ba04SDave Airlie } 4076f453ba04SDave Airlie EXPORT_SYMBOL(drm_property_destroy); 4077f453ba04SDave Airlie 4078c8e32cc1SDaniel Vetter /** 4079c8e32cc1SDaniel Vetter * drm_object_attach_property - attach a property to a modeset object 4080c8e32cc1SDaniel Vetter * @obj: drm modeset object 4081c8e32cc1SDaniel Vetter * @property: property to attach 4082c8e32cc1SDaniel Vetter * @init_val: initial value of the property 4083c8e32cc1SDaniel Vetter * 4084c8e32cc1SDaniel Vetter * This attaches the given property to the modeset object with the given initial 4085c8e32cc1SDaniel Vetter * value. Currently this function cannot fail since the properties are stored in 4086c8e32cc1SDaniel Vetter * a statically sized array. 4087c8e32cc1SDaniel Vetter */ 4088c543188aSPaulo Zanoni void drm_object_attach_property(struct drm_mode_object *obj, 4089c543188aSPaulo Zanoni struct drm_property *property, 4090c543188aSPaulo Zanoni uint64_t init_val) 4091c543188aSPaulo Zanoni { 40927f88a9beSPaulo Zanoni int count = obj->properties->count; 4093c543188aSPaulo Zanoni 40947f88a9beSPaulo Zanoni if (count == DRM_OBJECT_MAX_PROPERTY) { 40957f88a9beSPaulo Zanoni WARN(1, "Failed to attach object property (type: 0x%x). Please " 40967f88a9beSPaulo Zanoni "increase DRM_OBJECT_MAX_PROPERTY by 1 for each time " 40977f88a9beSPaulo Zanoni "you see this message on the same object type.\n", 40987f88a9beSPaulo Zanoni obj->type); 4099c543188aSPaulo Zanoni return; 4100c543188aSPaulo Zanoni } 4101c543188aSPaulo Zanoni 4102b17cd757SRob Clark obj->properties->properties[count] = property; 41037f88a9beSPaulo Zanoni obj->properties->values[count] = init_val; 41047f88a9beSPaulo Zanoni obj->properties->count++; 410588a48e29SRob Clark if (property->flags & DRM_MODE_PROP_ATOMIC) 410688a48e29SRob Clark obj->properties->atomic_count++; 4107c543188aSPaulo Zanoni } 4108c543188aSPaulo Zanoni EXPORT_SYMBOL(drm_object_attach_property); 4109c543188aSPaulo Zanoni 4110c8e32cc1SDaniel Vetter /** 4111c8e32cc1SDaniel Vetter * drm_object_property_set_value - set the value of a property 4112c8e32cc1SDaniel Vetter * @obj: drm mode object to set property value for 4113c8e32cc1SDaniel Vetter * @property: property to set 4114c8e32cc1SDaniel Vetter * @val: value the property should be set to 4115c8e32cc1SDaniel Vetter * 4116c8e32cc1SDaniel Vetter * This functions sets a given property on a given object. This function only 4117c8e32cc1SDaniel Vetter * changes the software state of the property, it does not call into the 4118c8e32cc1SDaniel Vetter * driver's ->set_property callback. 4119c8e32cc1SDaniel Vetter * 4120c8e32cc1SDaniel Vetter * Returns: 4121c8e32cc1SDaniel Vetter * Zero on success, error code on failure. 4122c8e32cc1SDaniel Vetter */ 4123c543188aSPaulo Zanoni int drm_object_property_set_value(struct drm_mode_object *obj, 4124c543188aSPaulo Zanoni struct drm_property *property, uint64_t val) 4125c543188aSPaulo Zanoni { 4126c543188aSPaulo Zanoni int i; 4127c543188aSPaulo Zanoni 41287f88a9beSPaulo Zanoni for (i = 0; i < obj->properties->count; i++) { 4129b17cd757SRob Clark if (obj->properties->properties[i] == property) { 4130c543188aSPaulo Zanoni obj->properties->values[i] = val; 4131c543188aSPaulo Zanoni return 0; 4132c543188aSPaulo Zanoni } 4133c543188aSPaulo Zanoni } 4134c543188aSPaulo Zanoni 4135c543188aSPaulo Zanoni return -EINVAL; 4136c543188aSPaulo Zanoni } 4137c543188aSPaulo Zanoni EXPORT_SYMBOL(drm_object_property_set_value); 4138c543188aSPaulo Zanoni 4139c8e32cc1SDaniel Vetter /** 4140c8e32cc1SDaniel Vetter * drm_object_property_get_value - retrieve the value of a property 4141c8e32cc1SDaniel Vetter * @obj: drm mode object to get property value from 4142c8e32cc1SDaniel Vetter * @property: property to retrieve 4143c8e32cc1SDaniel Vetter * @val: storage for the property value 4144c8e32cc1SDaniel Vetter * 4145c8e32cc1SDaniel Vetter * This function retrieves the softare state of the given property for the given 4146c8e32cc1SDaniel Vetter * property. Since there is no driver callback to retrieve the current property 4147c8e32cc1SDaniel Vetter * value this might be out of sync with the hardware, depending upon the driver 4148c8e32cc1SDaniel Vetter * and property. 4149c8e32cc1SDaniel Vetter * 4150c8e32cc1SDaniel Vetter * Returns: 4151c8e32cc1SDaniel Vetter * Zero on success, error code on failure. 4152c8e32cc1SDaniel Vetter */ 4153c543188aSPaulo Zanoni int drm_object_property_get_value(struct drm_mode_object *obj, 4154c543188aSPaulo Zanoni struct drm_property *property, uint64_t *val) 4155c543188aSPaulo Zanoni { 4156c543188aSPaulo Zanoni int i; 4157c543188aSPaulo Zanoni 415888a48e29SRob Clark /* read-only properties bypass atomic mechanism and still store 415988a48e29SRob Clark * their value in obj->properties->values[].. mostly to avoid 416088a48e29SRob Clark * having to deal w/ EDID and similar props in atomic paths: 416188a48e29SRob Clark */ 416288a48e29SRob Clark if (drm_core_check_feature(property->dev, DRIVER_ATOMIC) && 416388a48e29SRob Clark !(property->flags & DRM_MODE_PROP_IMMUTABLE)) 416488a48e29SRob Clark return drm_atomic_get_property(obj, property, val); 416588a48e29SRob Clark 41667f88a9beSPaulo Zanoni for (i = 0; i < obj->properties->count; i++) { 4167b17cd757SRob Clark if (obj->properties->properties[i] == property) { 4168c543188aSPaulo Zanoni *val = obj->properties->values[i]; 4169c543188aSPaulo Zanoni return 0; 4170c543188aSPaulo Zanoni } 4171c543188aSPaulo Zanoni } 4172c543188aSPaulo Zanoni 4173c543188aSPaulo Zanoni return -EINVAL; 4174c543188aSPaulo Zanoni } 4175c543188aSPaulo Zanoni EXPORT_SYMBOL(drm_object_property_get_value); 4176c543188aSPaulo Zanoni 4177c8e32cc1SDaniel Vetter /** 41781a498633SDaniel Vetter * drm_mode_getproperty_ioctl - get the property metadata 4179c8e32cc1SDaniel Vetter * @dev: DRM device 4180c8e32cc1SDaniel Vetter * @data: ioctl data 4181c8e32cc1SDaniel Vetter * @file_priv: DRM file info 4182c8e32cc1SDaniel Vetter * 41831a498633SDaniel Vetter * This function retrieves the metadata for a given property, like the different 41841a498633SDaniel Vetter * possible values for an enum property or the limits for a range property. 41851a498633SDaniel Vetter * 41861a498633SDaniel Vetter * Blob properties are special 4187c8e32cc1SDaniel Vetter * 4188c8e32cc1SDaniel Vetter * Called by the user via ioctl. 4189c8e32cc1SDaniel Vetter * 4190c8e32cc1SDaniel Vetter * Returns: 41911a498633SDaniel Vetter * Zero on success, negative errno on failure. 4192c8e32cc1SDaniel Vetter */ 4193f453ba04SDave Airlie int drm_mode_getproperty_ioctl(struct drm_device *dev, 4194f453ba04SDave Airlie void *data, struct drm_file *file_priv) 4195f453ba04SDave Airlie { 4196f453ba04SDave Airlie struct drm_mode_get_property *out_resp = data; 4197f453ba04SDave Airlie struct drm_property *property; 4198f453ba04SDave Airlie int enum_count = 0; 4199f453ba04SDave Airlie int value_count = 0; 4200f453ba04SDave Airlie int ret = 0, i; 4201f453ba04SDave Airlie int copied; 4202f453ba04SDave Airlie struct drm_property_enum *prop_enum; 4203f453ba04SDave Airlie struct drm_mode_property_enum __user *enum_ptr; 4204f453ba04SDave Airlie uint64_t __user *values_ptr; 4205f453ba04SDave Airlie 4206fb3b06c8SDave Airlie if (!drm_core_check_feature(dev, DRIVER_MODESET)) 4207fb3b06c8SDave Airlie return -EINVAL; 4208fb3b06c8SDave Airlie 420984849903SDaniel Vetter drm_modeset_lock_all(dev); 4210a2b34e22SRob Clark property = drm_property_find(dev, out_resp->prop_id); 4211a2b34e22SRob Clark if (!property) { 4212f27657f2SVille Syrjälä ret = -ENOENT; 4213f453ba04SDave Airlie goto done; 4214f453ba04SDave Airlie } 4215f453ba04SDave Airlie 42165ea22f24SRob Clark if (drm_property_type_is(property, DRM_MODE_PROP_ENUM) || 42175ea22f24SRob Clark drm_property_type_is(property, DRM_MODE_PROP_BITMASK)) { 42183758b341SDaniel Vetter list_for_each_entry(prop_enum, &property->enum_list, head) 4219f453ba04SDave Airlie enum_count++; 4220f453ba04SDave Airlie } 4221f453ba04SDave Airlie 4222f453ba04SDave Airlie value_count = property->num_values; 4223f453ba04SDave Airlie 4224f453ba04SDave Airlie strncpy(out_resp->name, property->name, DRM_PROP_NAME_LEN); 4225f453ba04SDave Airlie out_resp->name[DRM_PROP_NAME_LEN-1] = 0; 4226f453ba04SDave Airlie out_resp->flags = property->flags; 4227f453ba04SDave Airlie 4228f453ba04SDave Airlie if ((out_resp->count_values >= value_count) && value_count) { 422981f6c7f8SVille Syrjälä values_ptr = (uint64_t __user *)(unsigned long)out_resp->values_ptr; 4230f453ba04SDave Airlie for (i = 0; i < value_count; i++) { 4231f453ba04SDave Airlie if (copy_to_user(values_ptr + i, &property->values[i], sizeof(uint64_t))) { 4232f453ba04SDave Airlie ret = -EFAULT; 4233f453ba04SDave Airlie goto done; 4234f453ba04SDave Airlie } 4235f453ba04SDave Airlie } 4236f453ba04SDave Airlie } 4237f453ba04SDave Airlie out_resp->count_values = value_count; 4238f453ba04SDave Airlie 42395ea22f24SRob Clark if (drm_property_type_is(property, DRM_MODE_PROP_ENUM) || 42405ea22f24SRob Clark drm_property_type_is(property, DRM_MODE_PROP_BITMASK)) { 4241f453ba04SDave Airlie if ((out_resp->count_enum_blobs >= enum_count) && enum_count) { 4242f453ba04SDave Airlie copied = 0; 424381f6c7f8SVille Syrjälä enum_ptr = (struct drm_mode_property_enum __user *)(unsigned long)out_resp->enum_blob_ptr; 42443758b341SDaniel Vetter list_for_each_entry(prop_enum, &property->enum_list, head) { 4245f453ba04SDave Airlie 4246f453ba04SDave Airlie if (copy_to_user(&enum_ptr[copied].value, &prop_enum->value, sizeof(uint64_t))) { 4247f453ba04SDave Airlie ret = -EFAULT; 4248f453ba04SDave Airlie goto done; 4249f453ba04SDave Airlie } 4250f453ba04SDave Airlie 4251f453ba04SDave Airlie if (copy_to_user(&enum_ptr[copied].name, 4252f453ba04SDave Airlie &prop_enum->name, DRM_PROP_NAME_LEN)) { 4253f453ba04SDave Airlie ret = -EFAULT; 4254f453ba04SDave Airlie goto done; 4255f453ba04SDave Airlie } 4256f453ba04SDave Airlie copied++; 4257f453ba04SDave Airlie } 4258f453ba04SDave Airlie } 4259f453ba04SDave Airlie out_resp->count_enum_blobs = enum_count; 4260f453ba04SDave Airlie } 4261f453ba04SDave Airlie 42623758b341SDaniel Vetter /* 42633758b341SDaniel Vetter * NOTE: The idea seems to have been to use this to read all the blob 42643758b341SDaniel Vetter * property values. But nothing ever added them to the corresponding 42653758b341SDaniel Vetter * list, userspace always used the special-purpose get_blob ioctl to 42663758b341SDaniel Vetter * read the value for a blob property. It also doesn't make a lot of 42673758b341SDaniel Vetter * sense to return values here when everything else is just metadata for 42683758b341SDaniel Vetter * the property itself. 42693758b341SDaniel Vetter */ 42703758b341SDaniel Vetter if (drm_property_type_is(property, DRM_MODE_PROP_BLOB)) 42713758b341SDaniel Vetter out_resp->count_enum_blobs = 0; 4272f453ba04SDave Airlie done: 427384849903SDaniel Vetter drm_modeset_unlock_all(dev); 4274f453ba04SDave Airlie return ret; 4275f453ba04SDave Airlie } 4276f453ba04SDave Airlie 427799531d9bSDaniel Stone /** 427899531d9bSDaniel Stone * drm_property_create_blob - Create new blob property 427999531d9bSDaniel Stone * 428099531d9bSDaniel Stone * Creates a new blob property for a specified DRM device, optionally 428199531d9bSDaniel Stone * copying data. 428299531d9bSDaniel Stone * 428399531d9bSDaniel Stone * @dev: DRM device to create property for 428499531d9bSDaniel Stone * @length: Length to allocate for blob data 428599531d9bSDaniel Stone * @data: If specified, copies data into blob 428610e8cb7eSDaniel Stone * 428710e8cb7eSDaniel Stone * Returns: 428810e8cb7eSDaniel Stone * New blob property with a single reference on success, or an ERR_PTR 428910e8cb7eSDaniel Stone * value on failure. 429099531d9bSDaniel Stone */ 42916bcacf51SDaniel Stone struct drm_property_blob * 4292ecbbe59bSThierry Reding drm_property_create_blob(struct drm_device *dev, size_t length, 429312e6cecdSThierry Reding const void *data) 4294f453ba04SDave Airlie { 4295f453ba04SDave Airlie struct drm_property_blob *blob; 42966bfc56aaSVille Syrjälä int ret; 4297f453ba04SDave Airlie 42989ac0934bSDan Carpenter if (!length || length > ULONG_MAX - sizeof(struct drm_property_blob)) 429910e8cb7eSDaniel Stone return ERR_PTR(-EINVAL); 4300f453ba04SDave Airlie 4301f453ba04SDave Airlie blob = kzalloc(sizeof(struct drm_property_blob)+length, GFP_KERNEL); 4302f453ba04SDave Airlie if (!blob) 430310e8cb7eSDaniel Stone return ERR_PTR(-ENOMEM); 4304f453ba04SDave Airlie 4305e2f5d2eaSDaniel Stone /* This must be explicitly initialised, so we can safely call list_del 4306e2f5d2eaSDaniel Stone * on it in the removal handler, even if it isn't in a file list. */ 4307e2f5d2eaSDaniel Stone INIT_LIST_HEAD(&blob->head_file); 4308f453ba04SDave Airlie blob->length = length; 43096bcacf51SDaniel Stone blob->dev = dev; 4310f453ba04SDave Airlie 431199531d9bSDaniel Stone if (data) 4312f453ba04SDave Airlie memcpy(blob->data, data, length); 4313f453ba04SDave Airlie 43148fb6e7a5SDaniel Stone mutex_lock(&dev->mode_config.blob_lock); 43158fb6e7a5SDaniel Stone 43168fb6e7a5SDaniel Stone ret = drm_mode_object_get(dev, &blob->base, DRM_MODE_OBJECT_BLOB); 43178fb6e7a5SDaniel Stone if (ret) { 43188fb6e7a5SDaniel Stone kfree(blob); 43198fb6e7a5SDaniel Stone mutex_unlock(&dev->mode_config.blob_lock); 432010e8cb7eSDaniel Stone return ERR_PTR(-EINVAL); 43218fb6e7a5SDaniel Stone } 43228fb6e7a5SDaniel Stone 43236bcacf51SDaniel Stone kref_init(&blob->refcount); 43246bcacf51SDaniel Stone 4325e2f5d2eaSDaniel Stone list_add_tail(&blob->head_global, 4326e2f5d2eaSDaniel Stone &dev->mode_config.property_blob_list); 43278fb6e7a5SDaniel Stone 43288fb6e7a5SDaniel Stone mutex_unlock(&dev->mode_config.blob_lock); 43298fb6e7a5SDaniel Stone 4330f453ba04SDave Airlie return blob; 4331f453ba04SDave Airlie } 43326bcacf51SDaniel Stone EXPORT_SYMBOL(drm_property_create_blob); 4333f453ba04SDave Airlie 43346bcacf51SDaniel Stone /** 43356bcacf51SDaniel Stone * drm_property_free_blob - Blob property destructor 43366bcacf51SDaniel Stone * 43376bcacf51SDaniel Stone * Internal free function for blob properties; must not be used directly. 43386bcacf51SDaniel Stone * 4339f102c16eSDaniel Stone * @kref: Reference 43406bcacf51SDaniel Stone */ 43416bcacf51SDaniel Stone static void drm_property_free_blob(struct kref *kref) 4342f453ba04SDave Airlie { 43436bcacf51SDaniel Stone struct drm_property_blob *blob = 43446bcacf51SDaniel Stone container_of(kref, struct drm_property_blob, refcount); 43456bcacf51SDaniel Stone 43466bcacf51SDaniel Stone WARN_ON(!mutex_is_locked(&blob->dev->mode_config.blob_lock)); 43476bcacf51SDaniel Stone 4348e2f5d2eaSDaniel Stone list_del(&blob->head_global); 4349e2f5d2eaSDaniel Stone list_del(&blob->head_file); 43506bcacf51SDaniel Stone drm_mode_object_put(blob->dev, &blob->base); 43518fb6e7a5SDaniel Stone 4352f453ba04SDave Airlie kfree(blob); 4353f453ba04SDave Airlie } 4354f453ba04SDave Airlie 4355c8e32cc1SDaniel Vetter /** 43566bcacf51SDaniel Stone * drm_property_unreference_blob - Unreference a blob property 43576bcacf51SDaniel Stone * 43586bcacf51SDaniel Stone * Drop a reference on a blob property. May free the object. 43596bcacf51SDaniel Stone * 4360f102c16eSDaniel Stone * @blob: Pointer to blob property 43616bcacf51SDaniel Stone */ 43626bcacf51SDaniel Stone void drm_property_unreference_blob(struct drm_property_blob *blob) 43636bcacf51SDaniel Stone { 43646bcacf51SDaniel Stone struct drm_device *dev; 43656bcacf51SDaniel Stone 43666bcacf51SDaniel Stone if (!blob) 43676bcacf51SDaniel Stone return; 43686bcacf51SDaniel Stone 43696bcacf51SDaniel Stone dev = blob->dev; 43706bcacf51SDaniel Stone 43716bcacf51SDaniel Stone DRM_DEBUG("%p: blob ID: %d (%d)\n", blob, blob->base.id, atomic_read(&blob->refcount.refcount)); 43726bcacf51SDaniel Stone 43736bcacf51SDaniel Stone if (kref_put_mutex(&blob->refcount, drm_property_free_blob, 43746bcacf51SDaniel Stone &dev->mode_config.blob_lock)) 43756bcacf51SDaniel Stone mutex_unlock(&dev->mode_config.blob_lock); 43766bcacf51SDaniel Stone else 43776bcacf51SDaniel Stone might_lock(&dev->mode_config.blob_lock); 43786bcacf51SDaniel Stone } 43796bcacf51SDaniel Stone EXPORT_SYMBOL(drm_property_unreference_blob); 43806bcacf51SDaniel Stone 43816bcacf51SDaniel Stone /** 43826bcacf51SDaniel Stone * drm_property_unreference_blob_locked - Unreference a blob property with blob_lock held 43836bcacf51SDaniel Stone * 43846bcacf51SDaniel Stone * Drop a reference on a blob property. May free the object. This must be 43856bcacf51SDaniel Stone * called with blob_lock held. 43866bcacf51SDaniel Stone * 4387f102c16eSDaniel Stone * @blob: Pointer to blob property 43886bcacf51SDaniel Stone */ 43896bcacf51SDaniel Stone static void drm_property_unreference_blob_locked(struct drm_property_blob *blob) 43906bcacf51SDaniel Stone { 43916bcacf51SDaniel Stone if (!blob) 43926bcacf51SDaniel Stone return; 43936bcacf51SDaniel Stone 43946bcacf51SDaniel Stone DRM_DEBUG("%p: blob ID: %d (%d)\n", blob, blob->base.id, atomic_read(&blob->refcount.refcount)); 43956bcacf51SDaniel Stone 43966bcacf51SDaniel Stone kref_put(&blob->refcount, drm_property_free_blob); 43976bcacf51SDaniel Stone } 43986bcacf51SDaniel Stone 43996bcacf51SDaniel Stone /** 4400e2f5d2eaSDaniel Stone * drm_property_destroy_user_blobs - destroy all blobs created by this client 4401e2f5d2eaSDaniel Stone * @dev: DRM device 4402e2f5d2eaSDaniel Stone * @file_priv: destroy all blobs owned by this file handle 4403e2f5d2eaSDaniel Stone */ 4404e2f5d2eaSDaniel Stone void drm_property_destroy_user_blobs(struct drm_device *dev, 4405e2f5d2eaSDaniel Stone struct drm_file *file_priv) 4406e2f5d2eaSDaniel Stone { 4407e2f5d2eaSDaniel Stone struct drm_property_blob *blob, *bt; 4408e2f5d2eaSDaniel Stone 4409e2f5d2eaSDaniel Stone mutex_lock(&dev->mode_config.blob_lock); 4410e2f5d2eaSDaniel Stone 4411e2f5d2eaSDaniel Stone list_for_each_entry_safe(blob, bt, &file_priv->blobs, head_file) { 4412e2f5d2eaSDaniel Stone list_del_init(&blob->head_file); 4413e2f5d2eaSDaniel Stone drm_property_unreference_blob_locked(blob); 4414e2f5d2eaSDaniel Stone } 4415e2f5d2eaSDaniel Stone 4416e2f5d2eaSDaniel Stone mutex_unlock(&dev->mode_config.blob_lock); 4417e2f5d2eaSDaniel Stone } 4418e2f5d2eaSDaniel Stone 4419e2f5d2eaSDaniel Stone /** 44206bcacf51SDaniel Stone * drm_property_reference_blob - Take a reference on an existing property 44216bcacf51SDaniel Stone * 44226bcacf51SDaniel Stone * Take a new reference on an existing blob property. 44236bcacf51SDaniel Stone * 4424f102c16eSDaniel Stone * @blob: Pointer to blob property 44256bcacf51SDaniel Stone */ 44266bcacf51SDaniel Stone struct drm_property_blob *drm_property_reference_blob(struct drm_property_blob *blob) 44276bcacf51SDaniel Stone { 44286bcacf51SDaniel Stone DRM_DEBUG("%p: blob ID: %d (%d)\n", blob, blob->base.id, atomic_read(&blob->refcount.refcount)); 44296bcacf51SDaniel Stone kref_get(&blob->refcount); 44306bcacf51SDaniel Stone return blob; 44316bcacf51SDaniel Stone } 44326bcacf51SDaniel Stone EXPORT_SYMBOL(drm_property_reference_blob); 44336bcacf51SDaniel Stone 44346bcacf51SDaniel Stone /* 44356bcacf51SDaniel Stone * Like drm_property_lookup_blob, but does not return an additional reference. 44366bcacf51SDaniel Stone * Must be called with blob_lock held. 44376bcacf51SDaniel Stone */ 44386bcacf51SDaniel Stone static struct drm_property_blob *__drm_property_lookup_blob(struct drm_device *dev, 44396bcacf51SDaniel Stone uint32_t id) 44406bcacf51SDaniel Stone { 44416bcacf51SDaniel Stone struct drm_mode_object *obj = NULL; 44426bcacf51SDaniel Stone struct drm_property_blob *blob; 44436bcacf51SDaniel Stone 44446bcacf51SDaniel Stone WARN_ON(!mutex_is_locked(&dev->mode_config.blob_lock)); 44456bcacf51SDaniel Stone 44466bcacf51SDaniel Stone mutex_lock(&dev->mode_config.idr_mutex); 44476bcacf51SDaniel Stone obj = idr_find(&dev->mode_config.crtc_idr, id); 44486bcacf51SDaniel Stone if (!obj || (obj->type != DRM_MODE_OBJECT_BLOB) || (obj->id != id)) 44496bcacf51SDaniel Stone blob = NULL; 44506bcacf51SDaniel Stone else 44516bcacf51SDaniel Stone blob = obj_to_blob(obj); 44526bcacf51SDaniel Stone mutex_unlock(&dev->mode_config.idr_mutex); 44536bcacf51SDaniel Stone 4454f453ba04SDave Airlie return blob; 4455f453ba04SDave Airlie } 4456f453ba04SDave Airlie 44576bcacf51SDaniel Stone /** 44586bcacf51SDaniel Stone * drm_property_lookup_blob - look up a blob property and take a reference 44596bcacf51SDaniel Stone * @dev: drm device 44606bcacf51SDaniel Stone * @id: id of the blob property 44616bcacf51SDaniel Stone * 44626bcacf51SDaniel Stone * If successful, this takes an additional reference to the blob property. 44636bcacf51SDaniel Stone * callers need to make sure to eventually unreference the returned property 44646bcacf51SDaniel Stone * again, using @drm_property_unreference_blob. 44656bcacf51SDaniel Stone */ 44666bcacf51SDaniel Stone struct drm_property_blob *drm_property_lookup_blob(struct drm_device *dev, 44676bcacf51SDaniel Stone uint32_t id) 4468f453ba04SDave Airlie { 44696bcacf51SDaniel Stone struct drm_property_blob *blob; 44706bcacf51SDaniel Stone 44716bcacf51SDaniel Stone mutex_lock(&dev->mode_config.blob_lock); 44726bcacf51SDaniel Stone blob = __drm_property_lookup_blob(dev, id); 44736bcacf51SDaniel Stone if (blob) { 44746bcacf51SDaniel Stone if (!kref_get_unless_zero(&blob->refcount)) 44756bcacf51SDaniel Stone blob = NULL; 44766bcacf51SDaniel Stone } 44776bcacf51SDaniel Stone mutex_unlock(&dev->mode_config.blob_lock); 44786bcacf51SDaniel Stone 44796bcacf51SDaniel Stone return blob; 44806bcacf51SDaniel Stone } 44816bcacf51SDaniel Stone EXPORT_SYMBOL(drm_property_lookup_blob); 44826bcacf51SDaniel Stone 44836bcacf51SDaniel Stone /** 4484d2ed3436SDaniel Stone * drm_property_replace_global_blob - atomically replace existing blob property 4485d2ed3436SDaniel Stone * @dev: drm device 4486d2ed3436SDaniel Stone * @replace: location of blob property pointer to be replaced 4487d2ed3436SDaniel Stone * @length: length of data for new blob, or 0 for no data 4488d2ed3436SDaniel Stone * @data: content for new blob, or NULL for no data 4489d2ed3436SDaniel Stone * @obj_holds_id: optional object for property holding blob ID 4490d2ed3436SDaniel Stone * @prop_holds_id: optional property holding blob ID 4491d2ed3436SDaniel Stone * @return 0 on success or error on failure 4492d2ed3436SDaniel Stone * 4493d2ed3436SDaniel Stone * This function will atomically replace a global property in the blob list, 4494d2ed3436SDaniel Stone * optionally updating a property which holds the ID of that property. It is 4495d2ed3436SDaniel Stone * guaranteed to be atomic: no caller will be allowed to see intermediate 4496d2ed3436SDaniel Stone * results, and either the entire operation will succeed and clean up the 4497d2ed3436SDaniel Stone * previous property, or it will fail and the state will be unchanged. 4498d2ed3436SDaniel Stone * 4499d2ed3436SDaniel Stone * If length is 0 or data is NULL, no new blob will be created, and the holding 4500d2ed3436SDaniel Stone * property, if specified, will be set to 0. 4501d2ed3436SDaniel Stone * 4502d2ed3436SDaniel Stone * Access to the replace pointer is assumed to be protected by the caller, e.g. 4503d2ed3436SDaniel Stone * by holding the relevant modesetting object lock for its parent. 4504d2ed3436SDaniel Stone * 4505d2ed3436SDaniel Stone * For example, a drm_connector has a 'PATH' property, which contains the ID 4506d2ed3436SDaniel Stone * of a blob property with the value of the MST path information. Calling this 4507d2ed3436SDaniel Stone * function with replace pointing to the connector's path_blob_ptr, length and 4508d2ed3436SDaniel Stone * data set for the new path information, obj_holds_id set to the connector's 4509d2ed3436SDaniel Stone * base object, and prop_holds_id set to the path property name, will perform 4510d2ed3436SDaniel Stone * a completely atomic update. The access to path_blob_ptr is protected by the 4511d2ed3436SDaniel Stone * caller holding a lock on the connector. 4512d2ed3436SDaniel Stone */ 4513d2ed3436SDaniel Stone static int drm_property_replace_global_blob(struct drm_device *dev, 4514d2ed3436SDaniel Stone struct drm_property_blob **replace, 4515d2ed3436SDaniel Stone size_t length, 4516d2ed3436SDaniel Stone const void *data, 4517d2ed3436SDaniel Stone struct drm_mode_object *obj_holds_id, 4518d2ed3436SDaniel Stone struct drm_property *prop_holds_id) 4519d2ed3436SDaniel Stone { 4520d2ed3436SDaniel Stone struct drm_property_blob *new_blob = NULL; 4521d2ed3436SDaniel Stone struct drm_property_blob *old_blob = NULL; 4522d2ed3436SDaniel Stone int ret; 4523d2ed3436SDaniel Stone 4524d2ed3436SDaniel Stone WARN_ON(replace == NULL); 4525d2ed3436SDaniel Stone 4526d2ed3436SDaniel Stone old_blob = *replace; 4527d2ed3436SDaniel Stone 4528d2ed3436SDaniel Stone if (length && data) { 4529d2ed3436SDaniel Stone new_blob = drm_property_create_blob(dev, length, data); 453010e8cb7eSDaniel Stone if (IS_ERR(new_blob)) 453110e8cb7eSDaniel Stone return PTR_ERR(new_blob); 4532d2ed3436SDaniel Stone } 4533d2ed3436SDaniel Stone 4534d2ed3436SDaniel Stone /* This does not need to be synchronised with blob_lock, as the 4535d2ed3436SDaniel Stone * get_properties ioctl locks all modesetting objects, and 4536d2ed3436SDaniel Stone * obj_holds_id must be locked before calling here, so we cannot 4537d2ed3436SDaniel Stone * have its value out of sync with the list membership modified 4538d2ed3436SDaniel Stone * below under blob_lock. */ 4539d2ed3436SDaniel Stone if (obj_holds_id) { 4540d2ed3436SDaniel Stone ret = drm_object_property_set_value(obj_holds_id, 4541d2ed3436SDaniel Stone prop_holds_id, 4542d2ed3436SDaniel Stone new_blob ? 4543d2ed3436SDaniel Stone new_blob->base.id : 0); 4544d2ed3436SDaniel Stone if (ret != 0) 4545d2ed3436SDaniel Stone goto err_created; 4546d2ed3436SDaniel Stone } 4547d2ed3436SDaniel Stone 45486bcacf51SDaniel Stone drm_property_unreference_blob(old_blob); 4549d2ed3436SDaniel Stone *replace = new_blob; 4550d2ed3436SDaniel Stone 4551d2ed3436SDaniel Stone return 0; 4552d2ed3436SDaniel Stone 4553d2ed3436SDaniel Stone err_created: 45546bcacf51SDaniel Stone drm_property_unreference_blob(new_blob); 4555d2ed3436SDaniel Stone return ret; 4556f453ba04SDave Airlie } 4557f453ba04SDave Airlie 4558c8e32cc1SDaniel Vetter /** 4559c8e32cc1SDaniel Vetter * drm_mode_getblob_ioctl - get the contents of a blob property value 4560c8e32cc1SDaniel Vetter * @dev: DRM device 4561c8e32cc1SDaniel Vetter * @data: ioctl data 4562c8e32cc1SDaniel Vetter * @file_priv: DRM file info 4563c8e32cc1SDaniel Vetter * 4564c8e32cc1SDaniel Vetter * This function retrieves the contents of a blob property. The value stored in 4565c8e32cc1SDaniel Vetter * an object's blob property is just a normal modeset object id. 4566c8e32cc1SDaniel Vetter * 4567c8e32cc1SDaniel Vetter * Called by the user via ioctl. 4568c8e32cc1SDaniel Vetter * 4569c8e32cc1SDaniel Vetter * Returns: 45701a498633SDaniel Vetter * Zero on success, negative errno on failure. 4571c8e32cc1SDaniel Vetter */ 4572f453ba04SDave Airlie int drm_mode_getblob_ioctl(struct drm_device *dev, 4573f453ba04SDave Airlie void *data, struct drm_file *file_priv) 4574f453ba04SDave Airlie { 4575f453ba04SDave Airlie struct drm_mode_get_blob *out_resp = data; 4576f453ba04SDave Airlie struct drm_property_blob *blob; 4577f453ba04SDave Airlie int ret = 0; 457881f6c7f8SVille Syrjälä void __user *blob_ptr; 4579f453ba04SDave Airlie 4580fb3b06c8SDave Airlie if (!drm_core_check_feature(dev, DRIVER_MODESET)) 4581fb3b06c8SDave Airlie return -EINVAL; 4582fb3b06c8SDave Airlie 458384849903SDaniel Vetter drm_modeset_lock_all(dev); 45848fb6e7a5SDaniel Stone mutex_lock(&dev->mode_config.blob_lock); 45856bcacf51SDaniel Stone blob = __drm_property_lookup_blob(dev, out_resp->blob_id); 4586a2b34e22SRob Clark if (!blob) { 4587f27657f2SVille Syrjälä ret = -ENOENT; 4588f453ba04SDave Airlie goto done; 4589f453ba04SDave Airlie } 4590f453ba04SDave Airlie 4591f453ba04SDave Airlie if (out_resp->length == blob->length) { 459281f6c7f8SVille Syrjälä blob_ptr = (void __user *)(unsigned long)out_resp->data; 4593f453ba04SDave Airlie if (copy_to_user(blob_ptr, blob->data, blob->length)) { 4594f453ba04SDave Airlie ret = -EFAULT; 4595f453ba04SDave Airlie goto done; 4596f453ba04SDave Airlie } 4597f453ba04SDave Airlie } 4598f453ba04SDave Airlie out_resp->length = blob->length; 4599f453ba04SDave Airlie 4600f453ba04SDave Airlie done: 46018fb6e7a5SDaniel Stone mutex_unlock(&dev->mode_config.blob_lock); 460284849903SDaniel Vetter drm_modeset_unlock_all(dev); 4603f453ba04SDave Airlie return ret; 4604f453ba04SDave Airlie } 4605f453ba04SDave Airlie 4606cc7096fbSDave Airlie /** 4607e2f5d2eaSDaniel Stone * drm_mode_createblob_ioctl - create a new blob property 4608e2f5d2eaSDaniel Stone * @dev: DRM device 4609e2f5d2eaSDaniel Stone * @data: ioctl data 4610e2f5d2eaSDaniel Stone * @file_priv: DRM file info 4611e2f5d2eaSDaniel Stone * 4612e2f5d2eaSDaniel Stone * This function creates a new blob property with user-defined values. In order 4613e2f5d2eaSDaniel Stone * to give us sensible validation and checking when creating, rather than at 4614e2f5d2eaSDaniel Stone * every potential use, we also require a type to be provided upfront. 4615e2f5d2eaSDaniel Stone * 4616e2f5d2eaSDaniel Stone * Called by the user via ioctl. 4617e2f5d2eaSDaniel Stone * 4618e2f5d2eaSDaniel Stone * Returns: 4619e2f5d2eaSDaniel Stone * Zero on success, negative errno on failure. 4620e2f5d2eaSDaniel Stone */ 4621e2f5d2eaSDaniel Stone int drm_mode_createblob_ioctl(struct drm_device *dev, 4622e2f5d2eaSDaniel Stone void *data, struct drm_file *file_priv) 4623e2f5d2eaSDaniel Stone { 4624e2f5d2eaSDaniel Stone struct drm_mode_create_blob *out_resp = data; 4625e2f5d2eaSDaniel Stone struct drm_property_blob *blob; 4626e2f5d2eaSDaniel Stone void __user *blob_ptr; 4627e2f5d2eaSDaniel Stone int ret = 0; 4628e2f5d2eaSDaniel Stone 4629e2f5d2eaSDaniel Stone if (!drm_core_check_feature(dev, DRIVER_MODESET)) 4630e2f5d2eaSDaniel Stone return -EINVAL; 4631e2f5d2eaSDaniel Stone 4632e2f5d2eaSDaniel Stone blob = drm_property_create_blob(dev, out_resp->length, NULL); 4633e2f5d2eaSDaniel Stone if (IS_ERR(blob)) 4634e2f5d2eaSDaniel Stone return PTR_ERR(blob); 4635e2f5d2eaSDaniel Stone 4636e2f5d2eaSDaniel Stone blob_ptr = (void __user *)(unsigned long)out_resp->data; 4637e2f5d2eaSDaniel Stone if (copy_from_user(blob->data, blob_ptr, out_resp->length)) { 4638e2f5d2eaSDaniel Stone ret = -EFAULT; 4639e2f5d2eaSDaniel Stone goto out_blob; 4640e2f5d2eaSDaniel Stone } 4641e2f5d2eaSDaniel Stone 4642e2f5d2eaSDaniel Stone /* Dropping the lock between create_blob and our access here is safe 4643e2f5d2eaSDaniel Stone * as only the same file_priv can remove the blob; at this point, it is 4644e2f5d2eaSDaniel Stone * not associated with any file_priv. */ 4645e2f5d2eaSDaniel Stone mutex_lock(&dev->mode_config.blob_lock); 4646e2f5d2eaSDaniel Stone out_resp->blob_id = blob->base.id; 46478731b269SManeet Singh list_add_tail(&blob->head_file, &file_priv->blobs); 4648e2f5d2eaSDaniel Stone mutex_unlock(&dev->mode_config.blob_lock); 4649e2f5d2eaSDaniel Stone 4650e2f5d2eaSDaniel Stone return 0; 4651e2f5d2eaSDaniel Stone 4652e2f5d2eaSDaniel Stone out_blob: 4653e2f5d2eaSDaniel Stone drm_property_unreference_blob(blob); 4654e2f5d2eaSDaniel Stone return ret; 4655e2f5d2eaSDaniel Stone } 4656e2f5d2eaSDaniel Stone 4657e2f5d2eaSDaniel Stone /** 4658e2f5d2eaSDaniel Stone * drm_mode_destroyblob_ioctl - destroy a user blob property 4659e2f5d2eaSDaniel Stone * @dev: DRM device 4660e2f5d2eaSDaniel Stone * @data: ioctl data 4661e2f5d2eaSDaniel Stone * @file_priv: DRM file info 4662e2f5d2eaSDaniel Stone * 4663e2f5d2eaSDaniel Stone * Destroy an existing user-defined blob property. 4664e2f5d2eaSDaniel Stone * 4665e2f5d2eaSDaniel Stone * Called by the user via ioctl. 4666e2f5d2eaSDaniel Stone * 4667e2f5d2eaSDaniel Stone * Returns: 4668e2f5d2eaSDaniel Stone * Zero on success, negative errno on failure. 4669e2f5d2eaSDaniel Stone */ 4670e2f5d2eaSDaniel Stone int drm_mode_destroyblob_ioctl(struct drm_device *dev, 4671e2f5d2eaSDaniel Stone void *data, struct drm_file *file_priv) 4672e2f5d2eaSDaniel Stone { 4673e2f5d2eaSDaniel Stone struct drm_mode_destroy_blob *out_resp = data; 4674e2f5d2eaSDaniel Stone struct drm_property_blob *blob = NULL, *bt; 4675e2f5d2eaSDaniel Stone bool found = false; 4676e2f5d2eaSDaniel Stone int ret = 0; 4677e2f5d2eaSDaniel Stone 4678e2f5d2eaSDaniel Stone if (!drm_core_check_feature(dev, DRIVER_MODESET)) 4679e2f5d2eaSDaniel Stone return -EINVAL; 4680e2f5d2eaSDaniel Stone 4681e2f5d2eaSDaniel Stone mutex_lock(&dev->mode_config.blob_lock); 4682e2f5d2eaSDaniel Stone blob = __drm_property_lookup_blob(dev, out_resp->blob_id); 4683e2f5d2eaSDaniel Stone if (!blob) { 4684e2f5d2eaSDaniel Stone ret = -ENOENT; 4685e2f5d2eaSDaniel Stone goto err; 4686e2f5d2eaSDaniel Stone } 4687e2f5d2eaSDaniel Stone 4688e2f5d2eaSDaniel Stone /* Ensure the property was actually created by this user. */ 4689e2f5d2eaSDaniel Stone list_for_each_entry(bt, &file_priv->blobs, head_file) { 4690e2f5d2eaSDaniel Stone if (bt == blob) { 4691e2f5d2eaSDaniel Stone found = true; 4692e2f5d2eaSDaniel Stone break; 4693e2f5d2eaSDaniel Stone } 4694e2f5d2eaSDaniel Stone } 4695e2f5d2eaSDaniel Stone 4696e2f5d2eaSDaniel Stone if (!found) { 4697e2f5d2eaSDaniel Stone ret = -EPERM; 4698e2f5d2eaSDaniel Stone goto err; 4699e2f5d2eaSDaniel Stone } 4700e2f5d2eaSDaniel Stone 4701e2f5d2eaSDaniel Stone /* We must drop head_file here, because we may not be the last 4702e2f5d2eaSDaniel Stone * reference on the blob. */ 4703e2f5d2eaSDaniel Stone list_del_init(&blob->head_file); 4704e2f5d2eaSDaniel Stone drm_property_unreference_blob_locked(blob); 4705e2f5d2eaSDaniel Stone mutex_unlock(&dev->mode_config.blob_lock); 4706e2f5d2eaSDaniel Stone 4707e2f5d2eaSDaniel Stone return 0; 4708e2f5d2eaSDaniel Stone 4709e2f5d2eaSDaniel Stone err: 4710e2f5d2eaSDaniel Stone mutex_unlock(&dev->mode_config.blob_lock); 4711e2f5d2eaSDaniel Stone return ret; 4712e2f5d2eaSDaniel Stone } 4713e2f5d2eaSDaniel Stone 4714e2f5d2eaSDaniel Stone /** 4715cc7096fbSDave Airlie * drm_mode_connector_set_path_property - set tile property on connector 4716cc7096fbSDave Airlie * @connector: connector to set property on. 4717d2ed3436SDaniel Stone * @path: path to use for property; must not be NULL. 4718cc7096fbSDave Airlie * 4719cc7096fbSDave Airlie * This creates a property to expose to userspace to specify a 4720cc7096fbSDave Airlie * connector path. This is mainly used for DisplayPort MST where 4721cc7096fbSDave Airlie * connectors have a topology and we want to allow userspace to give 4722cc7096fbSDave Airlie * them more meaningful names. 4723cc7096fbSDave Airlie * 4724cc7096fbSDave Airlie * Returns: 47251a498633SDaniel Vetter * Zero on success, negative errno on failure. 4726cc7096fbSDave Airlie */ 472743aba7ebSDave Airlie int drm_mode_connector_set_path_property(struct drm_connector *connector, 472812e6cecdSThierry Reding const char *path) 472943aba7ebSDave Airlie { 473043aba7ebSDave Airlie struct drm_device *dev = connector->dev; 4731ecbbe59bSThierry Reding int ret; 473243aba7ebSDave Airlie 4733d2ed3436SDaniel Stone ret = drm_property_replace_global_blob(dev, 4734d2ed3436SDaniel Stone &connector->path_blob_ptr, 4735d2ed3436SDaniel Stone strlen(path) + 1, 4736d2ed3436SDaniel Stone path, 4737d2ed3436SDaniel Stone &connector->base, 4738d2ed3436SDaniel Stone dev->mode_config.path_property); 473943aba7ebSDave Airlie return ret; 474043aba7ebSDave Airlie } 474143aba7ebSDave Airlie EXPORT_SYMBOL(drm_mode_connector_set_path_property); 474243aba7ebSDave Airlie 4743c8e32cc1SDaniel Vetter /** 47446f134d7bSDave Airlie * drm_mode_connector_set_tile_property - set tile property on connector 47456f134d7bSDave Airlie * @connector: connector to set property on. 47466f134d7bSDave Airlie * 47476f134d7bSDave Airlie * This looks up the tile information for a connector, and creates a 47486f134d7bSDave Airlie * property for userspace to parse if it exists. The property is of 47496f134d7bSDave Airlie * the form of 8 integers using ':' as a separator. 47506f134d7bSDave Airlie * 47516f134d7bSDave Airlie * Returns: 47526f134d7bSDave Airlie * Zero on success, errno on failure. 47536f134d7bSDave Airlie */ 47546f134d7bSDave Airlie int drm_mode_connector_set_tile_property(struct drm_connector *connector) 47556f134d7bSDave Airlie { 47566f134d7bSDave Airlie struct drm_device *dev = connector->dev; 47576f134d7bSDave Airlie char tile[256]; 4758d2ed3436SDaniel Stone int ret; 47596f134d7bSDave Airlie 47606f134d7bSDave Airlie if (!connector->has_tile) { 4761d2ed3436SDaniel Stone ret = drm_property_replace_global_blob(dev, 4762d2ed3436SDaniel Stone &connector->tile_blob_ptr, 4763d2ed3436SDaniel Stone 0, 4764d2ed3436SDaniel Stone NULL, 4765d2ed3436SDaniel Stone &connector->base, 4766d2ed3436SDaniel Stone dev->mode_config.tile_property); 47676f134d7bSDave Airlie return ret; 47686f134d7bSDave Airlie } 47696f134d7bSDave Airlie 47706f134d7bSDave Airlie snprintf(tile, 256, "%d:%d:%d:%d:%d:%d:%d:%d", 47716f134d7bSDave Airlie connector->tile_group->id, connector->tile_is_single_monitor, 47726f134d7bSDave Airlie connector->num_h_tile, connector->num_v_tile, 47736f134d7bSDave Airlie connector->tile_h_loc, connector->tile_v_loc, 47746f134d7bSDave Airlie connector->tile_h_size, connector->tile_v_size); 47756f134d7bSDave Airlie 4776d2ed3436SDaniel Stone ret = drm_property_replace_global_blob(dev, 4777d2ed3436SDaniel Stone &connector->tile_blob_ptr, 4778d2ed3436SDaniel Stone strlen(tile) + 1, 4779d2ed3436SDaniel Stone tile, 4780d2ed3436SDaniel Stone &connector->base, 4781d2ed3436SDaniel Stone dev->mode_config.tile_property); 47826f134d7bSDave Airlie return ret; 47836f134d7bSDave Airlie } 47846f134d7bSDave Airlie EXPORT_SYMBOL(drm_mode_connector_set_tile_property); 47856f134d7bSDave Airlie 47866f134d7bSDave Airlie /** 4787c8e32cc1SDaniel Vetter * drm_mode_connector_update_edid_property - update the edid property of a connector 4788c8e32cc1SDaniel Vetter * @connector: drm connector 4789c8e32cc1SDaniel Vetter * @edid: new value of the edid property 4790c8e32cc1SDaniel Vetter * 4791c8e32cc1SDaniel Vetter * This function creates a new blob modeset object and assigns its id to the 4792c8e32cc1SDaniel Vetter * connector's edid property. 4793c8e32cc1SDaniel Vetter * 4794c8e32cc1SDaniel Vetter * Returns: 47951a498633SDaniel Vetter * Zero on success, negative errno on failure. 4796c8e32cc1SDaniel Vetter */ 4797f453ba04SDave Airlie int drm_mode_connector_update_edid_property(struct drm_connector *connector, 479812e6cecdSThierry Reding const struct edid *edid) 4799f453ba04SDave Airlie { 4800f453ba04SDave Airlie struct drm_device *dev = connector->dev; 4801d2ed3436SDaniel Stone size_t size = 0; 4802ecbbe59bSThierry Reding int ret; 4803f453ba04SDave Airlie 48044cf2b281SThomas Wood /* ignore requests to set edid when overridden */ 48054cf2b281SThomas Wood if (connector->override_edid) 48064cf2b281SThomas Wood return 0; 48074cf2b281SThomas Wood 4808d2ed3436SDaniel Stone if (edid) 4809e24ff467SShixin Zeng size = EDID_LENGTH * (1 + edid->extensions); 4810f453ba04SDave Airlie 4811d2ed3436SDaniel Stone ret = drm_property_replace_global_blob(dev, 4812d2ed3436SDaniel Stone &connector->edid_blob_ptr, 4813d2ed3436SDaniel Stone size, 4814d2ed3436SDaniel Stone edid, 4815d2ed3436SDaniel Stone &connector->base, 4816d2ed3436SDaniel Stone dev->mode_config.edid_property); 4817f453ba04SDave Airlie return ret; 4818f453ba04SDave Airlie } 4819f453ba04SDave Airlie EXPORT_SYMBOL(drm_mode_connector_update_edid_property); 4820f453ba04SDave Airlie 48213843e71fSRob Clark /* Some properties could refer to dynamic refcnt'd objects, or things that 48223843e71fSRob Clark * need special locking to handle lifetime issues (ie. to ensure the prop 48233843e71fSRob Clark * value doesn't become invalid part way through the property update due to 48243843e71fSRob Clark * race). The value returned by reference via 'obj' should be passed back 48253843e71fSRob Clark * to drm_property_change_valid_put() after the property is set (and the 48263843e71fSRob Clark * object to which the property is attached has a chance to take it's own 48273843e71fSRob Clark * reference). 48283843e71fSRob Clark */ 4829d34f20d6SRob Clark bool drm_property_change_valid_get(struct drm_property *property, 48303843e71fSRob Clark uint64_t value, struct drm_mode_object **ref) 483126a34815SPaulo Zanoni { 48322ca651d1SThierry Reding int i; 48332ca651d1SThierry Reding 483426a34815SPaulo Zanoni if (property->flags & DRM_MODE_PROP_IMMUTABLE) 483526a34815SPaulo Zanoni return false; 48365ea22f24SRob Clark 48373843e71fSRob Clark *ref = NULL; 48383843e71fSRob Clark 48395ea22f24SRob Clark if (drm_property_type_is(property, DRM_MODE_PROP_RANGE)) { 484026a34815SPaulo Zanoni if (value < property->values[0] || value > property->values[1]) 484126a34815SPaulo Zanoni return false; 484226a34815SPaulo Zanoni return true; 4843ebc44cf3SRob Clark } else if (drm_property_type_is(property, DRM_MODE_PROP_SIGNED_RANGE)) { 4844ebc44cf3SRob Clark int64_t svalue = U642I64(value); 48454dfd909fSThierry Reding 4846ebc44cf3SRob Clark if (svalue < U642I64(property->values[0]) || 4847ebc44cf3SRob Clark svalue > U642I64(property->values[1])) 4848ebc44cf3SRob Clark return false; 4849ebc44cf3SRob Clark return true; 48505ea22f24SRob Clark } else if (drm_property_type_is(property, DRM_MODE_PROP_BITMASK)) { 4851592c20eeSVille Syrjälä uint64_t valid_mask = 0; 48524dfd909fSThierry Reding 485349e27545SRob Clark for (i = 0; i < property->num_values; i++) 485449e27545SRob Clark valid_mask |= (1ULL << property->values[i]); 485549e27545SRob Clark return !(value & ~valid_mask); 48565ea22f24SRob Clark } else if (drm_property_type_is(property, DRM_MODE_PROP_BLOB)) { 48576bcacf51SDaniel Stone struct drm_property_blob *blob; 48586bcacf51SDaniel Stone 48596bcacf51SDaniel Stone if (value == 0) 4860c4a56750SVille Syrjälä return true; 48616bcacf51SDaniel Stone 48626bcacf51SDaniel Stone blob = drm_property_lookup_blob(property->dev, value); 48636bcacf51SDaniel Stone if (blob) { 48646bcacf51SDaniel Stone *ref = &blob->base; 48656bcacf51SDaniel Stone return true; 48666bcacf51SDaniel Stone } else { 48676bcacf51SDaniel Stone return false; 48686bcacf51SDaniel Stone } 486998f75de4SRob Clark } else if (drm_property_type_is(property, DRM_MODE_PROP_OBJECT)) { 487098f75de4SRob Clark /* a zero value for an object property translates to null: */ 487198f75de4SRob Clark if (value == 0) 487298f75de4SRob Clark return true; 48733843e71fSRob Clark 48743843e71fSRob Clark /* handle refcnt'd objects specially: */ 48753843e71fSRob Clark if (property->values[0] == DRM_MODE_OBJECT_FB) { 48763843e71fSRob Clark struct drm_framebuffer *fb; 48773843e71fSRob Clark fb = drm_framebuffer_lookup(property->dev, value); 48783843e71fSRob Clark if (fb) { 48793843e71fSRob Clark *ref = &fb->base; 48803843e71fSRob Clark return true; 48813843e71fSRob Clark } else { 48823843e71fSRob Clark return false; 48833843e71fSRob Clark } 48843843e71fSRob Clark } else { 48853843e71fSRob Clark return _object_find(property->dev, value, property->values[0]) != NULL; 48863843e71fSRob Clark } 48872ca651d1SThierry Reding } 48882ca651d1SThierry Reding 488926a34815SPaulo Zanoni for (i = 0; i < property->num_values; i++) 489026a34815SPaulo Zanoni if (property->values[i] == value) 489126a34815SPaulo Zanoni return true; 489226a34815SPaulo Zanoni return false; 489326a34815SPaulo Zanoni } 489426a34815SPaulo Zanoni 4895d34f20d6SRob Clark void drm_property_change_valid_put(struct drm_property *property, 48963843e71fSRob Clark struct drm_mode_object *ref) 48973843e71fSRob Clark { 48983843e71fSRob Clark if (!ref) 48993843e71fSRob Clark return; 49003843e71fSRob Clark 49013843e71fSRob Clark if (drm_property_type_is(property, DRM_MODE_PROP_OBJECT)) { 49023843e71fSRob Clark if (property->values[0] == DRM_MODE_OBJECT_FB) 49033843e71fSRob Clark drm_framebuffer_unreference(obj_to_fb(ref)); 4904da9b2a38SDaniel Stone } else if (drm_property_type_is(property, DRM_MODE_PROP_BLOB)) 4905da9b2a38SDaniel Stone drm_property_unreference_blob(obj_to_blob(ref)); 49063843e71fSRob Clark } 49073843e71fSRob Clark 4908c8e32cc1SDaniel Vetter /** 4909c8e32cc1SDaniel Vetter * drm_mode_connector_property_set_ioctl - set the current value of a connector property 4910c8e32cc1SDaniel Vetter * @dev: DRM device 4911c8e32cc1SDaniel Vetter * @data: ioctl data 4912c8e32cc1SDaniel Vetter * @file_priv: DRM file info 4913c8e32cc1SDaniel Vetter * 4914c8e32cc1SDaniel Vetter * This function sets the current value for a connectors's property. It also 4915c8e32cc1SDaniel Vetter * calls into a driver's ->set_property callback to update the hardware state 4916c8e32cc1SDaniel Vetter * 4917c8e32cc1SDaniel Vetter * Called by the user via ioctl. 4918c8e32cc1SDaniel Vetter * 4919c8e32cc1SDaniel Vetter * Returns: 49201a498633SDaniel Vetter * Zero on success, negative errno on failure. 4921c8e32cc1SDaniel Vetter */ 4922f453ba04SDave Airlie int drm_mode_connector_property_set_ioctl(struct drm_device *dev, 4923f453ba04SDave Airlie void *data, struct drm_file *file_priv) 4924f453ba04SDave Airlie { 49250057d8ddSPaulo Zanoni struct drm_mode_connector_set_property *conn_set_prop = data; 49260057d8ddSPaulo Zanoni struct drm_mode_obj_set_property obj_set_prop = { 49270057d8ddSPaulo Zanoni .value = conn_set_prop->value, 49280057d8ddSPaulo Zanoni .prop_id = conn_set_prop->prop_id, 49290057d8ddSPaulo Zanoni .obj_id = conn_set_prop->connector_id, 49300057d8ddSPaulo Zanoni .obj_type = DRM_MODE_OBJECT_CONNECTOR 49310057d8ddSPaulo Zanoni }; 4932f453ba04SDave Airlie 49330057d8ddSPaulo Zanoni /* It does all the locking and checking we need */ 49340057d8ddSPaulo Zanoni return drm_mode_obj_set_property_ioctl(dev, &obj_set_prop, file_priv); 4935f453ba04SDave Airlie } 4936f453ba04SDave Airlie 4937c543188aSPaulo Zanoni static int drm_mode_connector_set_obj_prop(struct drm_mode_object *obj, 4938c543188aSPaulo Zanoni struct drm_property *property, 4939c543188aSPaulo Zanoni uint64_t value) 4940c543188aSPaulo Zanoni { 4941c543188aSPaulo Zanoni int ret = -EINVAL; 4942c543188aSPaulo Zanoni struct drm_connector *connector = obj_to_connector(obj); 4943c543188aSPaulo Zanoni 4944c543188aSPaulo Zanoni /* Do DPMS ourselves */ 4945c543188aSPaulo Zanoni if (property == connector->dev->mode_config.dpms_property) { 49469a69a9acSMaarten Lankhorst ret = (*connector->funcs->dpms)(connector, (int)value); 4947c543188aSPaulo Zanoni } else if (connector->funcs->set_property) 4948c543188aSPaulo Zanoni ret = connector->funcs->set_property(connector, property, value); 4949c543188aSPaulo Zanoni 4950c543188aSPaulo Zanoni /* store the property value if successful */ 4951c543188aSPaulo Zanoni if (!ret) 495258495563SRob Clark drm_object_property_set_value(&connector->base, property, value); 4953c543188aSPaulo Zanoni return ret; 4954c543188aSPaulo Zanoni } 4955c543188aSPaulo Zanoni 4956bffd9de0SPaulo Zanoni static int drm_mode_crtc_set_obj_prop(struct drm_mode_object *obj, 4957bffd9de0SPaulo Zanoni struct drm_property *property, 4958bffd9de0SPaulo Zanoni uint64_t value) 4959bffd9de0SPaulo Zanoni { 4960bffd9de0SPaulo Zanoni int ret = -EINVAL; 4961bffd9de0SPaulo Zanoni struct drm_crtc *crtc = obj_to_crtc(obj); 4962bffd9de0SPaulo Zanoni 4963bffd9de0SPaulo Zanoni if (crtc->funcs->set_property) 4964bffd9de0SPaulo Zanoni ret = crtc->funcs->set_property(crtc, property, value); 4965bffd9de0SPaulo Zanoni if (!ret) 4966bffd9de0SPaulo Zanoni drm_object_property_set_value(obj, property, value); 4967bffd9de0SPaulo Zanoni 4968bffd9de0SPaulo Zanoni return ret; 4969bffd9de0SPaulo Zanoni } 4970bffd9de0SPaulo Zanoni 49713a5f87c2SThomas Wood /** 49723a5f87c2SThomas Wood * drm_mode_plane_set_obj_prop - set the value of a property 49733a5f87c2SThomas Wood * @plane: drm plane object to set property value for 49743a5f87c2SThomas Wood * @property: property to set 49753a5f87c2SThomas Wood * @value: value the property should be set to 49763a5f87c2SThomas Wood * 49773a5f87c2SThomas Wood * This functions sets a given property on a given plane object. This function 49783a5f87c2SThomas Wood * calls the driver's ->set_property callback and changes the software state of 49793a5f87c2SThomas Wood * the property if the callback succeeds. 49803a5f87c2SThomas Wood * 49813a5f87c2SThomas Wood * Returns: 49823a5f87c2SThomas Wood * Zero on success, error code on failure. 49833a5f87c2SThomas Wood */ 49843a5f87c2SThomas Wood int drm_mode_plane_set_obj_prop(struct drm_plane *plane, 49854d93914aSRob Clark struct drm_property *property, 49864d93914aSRob Clark uint64_t value) 49874d93914aSRob Clark { 49884d93914aSRob Clark int ret = -EINVAL; 49893a5f87c2SThomas Wood struct drm_mode_object *obj = &plane->base; 49904d93914aSRob Clark 49914d93914aSRob Clark if (plane->funcs->set_property) 49924d93914aSRob Clark ret = plane->funcs->set_property(plane, property, value); 49934d93914aSRob Clark if (!ret) 49944d93914aSRob Clark drm_object_property_set_value(obj, property, value); 49954d93914aSRob Clark 49964d93914aSRob Clark return ret; 49974d93914aSRob Clark } 49983a5f87c2SThomas Wood EXPORT_SYMBOL(drm_mode_plane_set_obj_prop); 49994d93914aSRob Clark 5000c8e32cc1SDaniel Vetter /** 50011a498633SDaniel Vetter * drm_mode_obj_get_properties_ioctl - get the current value of a object's property 5002c8e32cc1SDaniel Vetter * @dev: DRM device 5003c8e32cc1SDaniel Vetter * @data: ioctl data 5004c8e32cc1SDaniel Vetter * @file_priv: DRM file info 5005c8e32cc1SDaniel Vetter * 5006c8e32cc1SDaniel Vetter * This function retrieves the current value for an object's property. Compared 5007c8e32cc1SDaniel Vetter * to the connector specific ioctl this one is extended to also work on crtc and 5008c8e32cc1SDaniel Vetter * plane objects. 5009c8e32cc1SDaniel Vetter * 5010c8e32cc1SDaniel Vetter * Called by the user via ioctl. 5011c8e32cc1SDaniel Vetter * 5012c8e32cc1SDaniel Vetter * Returns: 50131a498633SDaniel Vetter * Zero on success, negative errno on failure. 5014c8e32cc1SDaniel Vetter */ 5015c543188aSPaulo Zanoni int drm_mode_obj_get_properties_ioctl(struct drm_device *dev, void *data, 5016c543188aSPaulo Zanoni struct drm_file *file_priv) 5017c543188aSPaulo Zanoni { 5018c543188aSPaulo Zanoni struct drm_mode_obj_get_properties *arg = data; 5019c543188aSPaulo Zanoni struct drm_mode_object *obj; 5020c543188aSPaulo Zanoni int ret = 0; 5021c543188aSPaulo Zanoni 5022c543188aSPaulo Zanoni if (!drm_core_check_feature(dev, DRIVER_MODESET)) 5023c543188aSPaulo Zanoni return -EINVAL; 5024c543188aSPaulo Zanoni 502584849903SDaniel Vetter drm_modeset_lock_all(dev); 5026c543188aSPaulo Zanoni 5027c543188aSPaulo Zanoni obj = drm_mode_object_find(dev, arg->obj_id, arg->obj_type); 5028c543188aSPaulo Zanoni if (!obj) { 5029f27657f2SVille Syrjälä ret = -ENOENT; 5030c543188aSPaulo Zanoni goto out; 5031c543188aSPaulo Zanoni } 5032c543188aSPaulo Zanoni if (!obj->properties) { 5033c543188aSPaulo Zanoni ret = -EINVAL; 5034c543188aSPaulo Zanoni goto out; 5035c543188aSPaulo Zanoni } 5036c543188aSPaulo Zanoni 503788a48e29SRob Clark ret = get_properties(obj, file_priv->atomic, 503895cbf110SRob Clark (uint32_t __user *)(unsigned long)(arg->props_ptr), 503995cbf110SRob Clark (uint64_t __user *)(unsigned long)(arg->prop_values_ptr), 504095cbf110SRob Clark &arg->count_props); 5041c543188aSPaulo Zanoni 5042c543188aSPaulo Zanoni out: 504384849903SDaniel Vetter drm_modeset_unlock_all(dev); 5044c543188aSPaulo Zanoni return ret; 5045c543188aSPaulo Zanoni } 5046c543188aSPaulo Zanoni 5047c8e32cc1SDaniel Vetter /** 5048c8e32cc1SDaniel Vetter * drm_mode_obj_set_property_ioctl - set the current value of an object's property 5049c8e32cc1SDaniel Vetter * @dev: DRM device 5050c8e32cc1SDaniel Vetter * @data: ioctl data 5051c8e32cc1SDaniel Vetter * @file_priv: DRM file info 5052c8e32cc1SDaniel Vetter * 5053c8e32cc1SDaniel Vetter * This function sets the current value for an object's property. It also calls 5054c8e32cc1SDaniel Vetter * into a driver's ->set_property callback to update the hardware state. 5055c8e32cc1SDaniel Vetter * Compared to the connector specific ioctl this one is extended to also work on 5056c8e32cc1SDaniel Vetter * crtc and plane objects. 5057c8e32cc1SDaniel Vetter * 5058c8e32cc1SDaniel Vetter * Called by the user via ioctl. 5059c8e32cc1SDaniel Vetter * 5060c8e32cc1SDaniel Vetter * Returns: 50611a498633SDaniel Vetter * Zero on success, negative errno on failure. 5062c8e32cc1SDaniel Vetter */ 5063c543188aSPaulo Zanoni int drm_mode_obj_set_property_ioctl(struct drm_device *dev, void *data, 5064c543188aSPaulo Zanoni struct drm_file *file_priv) 5065c543188aSPaulo Zanoni { 5066c543188aSPaulo Zanoni struct drm_mode_obj_set_property *arg = data; 5067c543188aSPaulo Zanoni struct drm_mode_object *arg_obj; 5068c543188aSPaulo Zanoni struct drm_mode_object *prop_obj; 5069c543188aSPaulo Zanoni struct drm_property *property; 50703843e71fSRob Clark int i, ret = -EINVAL; 50713843e71fSRob Clark struct drm_mode_object *ref; 5072c543188aSPaulo Zanoni 5073c543188aSPaulo Zanoni if (!drm_core_check_feature(dev, DRIVER_MODESET)) 5074c543188aSPaulo Zanoni return -EINVAL; 5075c543188aSPaulo Zanoni 507684849903SDaniel Vetter drm_modeset_lock_all(dev); 5077c543188aSPaulo Zanoni 5078c543188aSPaulo Zanoni arg_obj = drm_mode_object_find(dev, arg->obj_id, arg->obj_type); 5079f27657f2SVille Syrjälä if (!arg_obj) { 5080f27657f2SVille Syrjälä ret = -ENOENT; 5081c543188aSPaulo Zanoni goto out; 5082f27657f2SVille Syrjälä } 5083c543188aSPaulo Zanoni if (!arg_obj->properties) 5084c543188aSPaulo Zanoni goto out; 5085c543188aSPaulo Zanoni 50867f88a9beSPaulo Zanoni for (i = 0; i < arg_obj->properties->count; i++) 5087b17cd757SRob Clark if (arg_obj->properties->properties[i]->base.id == arg->prop_id) 5088c543188aSPaulo Zanoni break; 5089c543188aSPaulo Zanoni 50907f88a9beSPaulo Zanoni if (i == arg_obj->properties->count) 5091c543188aSPaulo Zanoni goto out; 5092c543188aSPaulo Zanoni 5093c543188aSPaulo Zanoni prop_obj = drm_mode_object_find(dev, arg->prop_id, 5094c543188aSPaulo Zanoni DRM_MODE_OBJECT_PROPERTY); 5095f27657f2SVille Syrjälä if (!prop_obj) { 5096f27657f2SVille Syrjälä ret = -ENOENT; 5097c543188aSPaulo Zanoni goto out; 5098f27657f2SVille Syrjälä } 5099c543188aSPaulo Zanoni property = obj_to_property(prop_obj); 5100c543188aSPaulo Zanoni 51013843e71fSRob Clark if (!drm_property_change_valid_get(property, arg->value, &ref)) 5102c543188aSPaulo Zanoni goto out; 5103c543188aSPaulo Zanoni 5104c543188aSPaulo Zanoni switch (arg_obj->type) { 5105c543188aSPaulo Zanoni case DRM_MODE_OBJECT_CONNECTOR: 5106c543188aSPaulo Zanoni ret = drm_mode_connector_set_obj_prop(arg_obj, property, 5107c543188aSPaulo Zanoni arg->value); 5108c543188aSPaulo Zanoni break; 5109bffd9de0SPaulo Zanoni case DRM_MODE_OBJECT_CRTC: 5110bffd9de0SPaulo Zanoni ret = drm_mode_crtc_set_obj_prop(arg_obj, property, arg->value); 5111bffd9de0SPaulo Zanoni break; 51124d93914aSRob Clark case DRM_MODE_OBJECT_PLANE: 51133a5f87c2SThomas Wood ret = drm_mode_plane_set_obj_prop(obj_to_plane(arg_obj), 51143a5f87c2SThomas Wood property, arg->value); 51154d93914aSRob Clark break; 5116c543188aSPaulo Zanoni } 5117c543188aSPaulo Zanoni 51183843e71fSRob Clark drm_property_change_valid_put(property, ref); 51193843e71fSRob Clark 5120c543188aSPaulo Zanoni out: 512184849903SDaniel Vetter drm_modeset_unlock_all(dev); 5122c543188aSPaulo Zanoni return ret; 5123c543188aSPaulo Zanoni } 5124c543188aSPaulo Zanoni 5125c8e32cc1SDaniel Vetter /** 5126c8e32cc1SDaniel Vetter * drm_mode_connector_attach_encoder - attach a connector to an encoder 5127c8e32cc1SDaniel Vetter * @connector: connector to attach 5128c8e32cc1SDaniel Vetter * @encoder: encoder to attach @connector to 5129c8e32cc1SDaniel Vetter * 5130c8e32cc1SDaniel Vetter * This function links up a connector to an encoder. Note that the routing 5131c8e32cc1SDaniel Vetter * restrictions between encoders and crtcs are exposed to userspace through the 5132c8e32cc1SDaniel Vetter * possible_clones and possible_crtcs bitmasks. 5133c8e32cc1SDaniel Vetter * 5134c8e32cc1SDaniel Vetter * Returns: 51351a498633SDaniel Vetter * Zero on success, negative errno on failure. 5136c8e32cc1SDaniel Vetter */ 5137f453ba04SDave Airlie int drm_mode_connector_attach_encoder(struct drm_connector *connector, 5138f453ba04SDave Airlie struct drm_encoder *encoder) 5139f453ba04SDave Airlie { 5140f453ba04SDave Airlie int i; 5141f453ba04SDave Airlie 5142eb47fe80SThierry Reding /* 5143eb47fe80SThierry Reding * In the past, drivers have attempted to model the static association 5144eb47fe80SThierry Reding * of connector to encoder in simple connector/encoder devices using a 5145eb47fe80SThierry Reding * direct assignment of connector->encoder = encoder. This connection 5146eb47fe80SThierry Reding * is a logical one and the responsibility of the core, so drivers are 5147eb47fe80SThierry Reding * expected not to mess with this. 5148eb47fe80SThierry Reding * 5149eb47fe80SThierry Reding * Note that the error return should've been enough here, but a large 5150eb47fe80SThierry Reding * majority of drivers ignores the return value, so add in a big WARN 5151eb47fe80SThierry Reding * to get people's attention. 5152eb47fe80SThierry Reding */ 5153eb47fe80SThierry Reding if (WARN_ON(connector->encoder)) 5154eb47fe80SThierry Reding return -EINVAL; 5155eb47fe80SThierry Reding 5156f453ba04SDave Airlie for (i = 0; i < DRM_CONNECTOR_MAX_ENCODER; i++) { 5157f453ba04SDave Airlie if (connector->encoder_ids[i] == 0) { 5158f453ba04SDave Airlie connector->encoder_ids[i] = encoder->base.id; 5159f453ba04SDave Airlie return 0; 5160f453ba04SDave Airlie } 5161f453ba04SDave Airlie } 5162f453ba04SDave Airlie return -ENOMEM; 5163f453ba04SDave Airlie } 5164f453ba04SDave Airlie EXPORT_SYMBOL(drm_mode_connector_attach_encoder); 5165f453ba04SDave Airlie 5166c8e32cc1SDaniel Vetter /** 5167c8e32cc1SDaniel Vetter * drm_mode_crtc_set_gamma_size - set the gamma table size 5168c8e32cc1SDaniel Vetter * @crtc: CRTC to set the gamma table size for 5169c8e32cc1SDaniel Vetter * @gamma_size: size of the gamma table 5170c8e32cc1SDaniel Vetter * 5171c8e32cc1SDaniel Vetter * Drivers which support gamma tables should set this to the supported gamma 5172c8e32cc1SDaniel Vetter * table size when initializing the CRTC. Currently the drm core only supports a 5173c8e32cc1SDaniel Vetter * fixed gamma table size. 5174c8e32cc1SDaniel Vetter * 5175c8e32cc1SDaniel Vetter * Returns: 51761a498633SDaniel Vetter * Zero on success, negative errno on failure. 5177c8e32cc1SDaniel Vetter */ 51784cae5b84SSascha Hauer int drm_mode_crtc_set_gamma_size(struct drm_crtc *crtc, 5179f453ba04SDave Airlie int gamma_size) 5180f453ba04SDave Airlie { 5181f453ba04SDave Airlie crtc->gamma_size = gamma_size; 5182f453ba04SDave Airlie 5183bd3f0ff9SThierry Reding crtc->gamma_store = kcalloc(gamma_size, sizeof(uint16_t) * 3, 5184bd3f0ff9SThierry Reding GFP_KERNEL); 5185f453ba04SDave Airlie if (!crtc->gamma_store) { 5186f453ba04SDave Airlie crtc->gamma_size = 0; 51874cae5b84SSascha Hauer return -ENOMEM; 5188f453ba04SDave Airlie } 5189f453ba04SDave Airlie 51904cae5b84SSascha Hauer return 0; 5191f453ba04SDave Airlie } 5192f453ba04SDave Airlie EXPORT_SYMBOL(drm_mode_crtc_set_gamma_size); 5193f453ba04SDave Airlie 5194c8e32cc1SDaniel Vetter /** 5195c8e32cc1SDaniel Vetter * drm_mode_gamma_set_ioctl - set the gamma table 5196c8e32cc1SDaniel Vetter * @dev: DRM device 5197c8e32cc1SDaniel Vetter * @data: ioctl data 5198c8e32cc1SDaniel Vetter * @file_priv: DRM file info 5199c8e32cc1SDaniel Vetter * 5200c8e32cc1SDaniel Vetter * Set the gamma table of a CRTC to the one passed in by the user. Userspace can 5201c8e32cc1SDaniel Vetter * inquire the required gamma table size through drm_mode_gamma_get_ioctl. 5202c8e32cc1SDaniel Vetter * 5203c8e32cc1SDaniel Vetter * Called by the user via ioctl. 5204c8e32cc1SDaniel Vetter * 5205c8e32cc1SDaniel Vetter * Returns: 52061a498633SDaniel Vetter * Zero on success, negative errno on failure. 5207c8e32cc1SDaniel Vetter */ 5208f453ba04SDave Airlie int drm_mode_gamma_set_ioctl(struct drm_device *dev, 5209f453ba04SDave Airlie void *data, struct drm_file *file_priv) 5210f453ba04SDave Airlie { 5211f453ba04SDave Airlie struct drm_mode_crtc_lut *crtc_lut = data; 5212f453ba04SDave Airlie struct drm_crtc *crtc; 5213f453ba04SDave Airlie void *r_base, *g_base, *b_base; 5214f453ba04SDave Airlie int size; 5215f453ba04SDave Airlie int ret = 0; 5216f453ba04SDave Airlie 5217fb3b06c8SDave Airlie if (!drm_core_check_feature(dev, DRIVER_MODESET)) 5218fb3b06c8SDave Airlie return -EINVAL; 5219fb3b06c8SDave Airlie 522084849903SDaniel Vetter drm_modeset_lock_all(dev); 5221a2b34e22SRob Clark crtc = drm_crtc_find(dev, crtc_lut->crtc_id); 5222a2b34e22SRob Clark if (!crtc) { 5223f27657f2SVille Syrjälä ret = -ENOENT; 5224f453ba04SDave Airlie goto out; 5225f453ba04SDave Airlie } 5226f453ba04SDave Airlie 5227ebe0f244SLaurent Pinchart if (crtc->funcs->gamma_set == NULL) { 5228ebe0f244SLaurent Pinchart ret = -ENOSYS; 5229ebe0f244SLaurent Pinchart goto out; 5230ebe0f244SLaurent Pinchart } 5231ebe0f244SLaurent Pinchart 5232f453ba04SDave Airlie /* memcpy into gamma store */ 5233f453ba04SDave Airlie if (crtc_lut->gamma_size != crtc->gamma_size) { 5234f453ba04SDave Airlie ret = -EINVAL; 5235f453ba04SDave Airlie goto out; 5236f453ba04SDave Airlie } 5237f453ba04SDave Airlie 5238f453ba04SDave Airlie size = crtc_lut->gamma_size * (sizeof(uint16_t)); 5239f453ba04SDave Airlie r_base = crtc->gamma_store; 5240f453ba04SDave Airlie if (copy_from_user(r_base, (void __user *)(unsigned long)crtc_lut->red, size)) { 5241f453ba04SDave Airlie ret = -EFAULT; 5242f453ba04SDave Airlie goto out; 5243f453ba04SDave Airlie } 5244f453ba04SDave Airlie 5245f453ba04SDave Airlie g_base = r_base + size; 5246f453ba04SDave Airlie if (copy_from_user(g_base, (void __user *)(unsigned long)crtc_lut->green, size)) { 5247f453ba04SDave Airlie ret = -EFAULT; 5248f453ba04SDave Airlie goto out; 5249f453ba04SDave Airlie } 5250f453ba04SDave Airlie 5251f453ba04SDave Airlie b_base = g_base + size; 5252f453ba04SDave Airlie if (copy_from_user(b_base, (void __user *)(unsigned long)crtc_lut->blue, size)) { 5253f453ba04SDave Airlie ret = -EFAULT; 5254f453ba04SDave Airlie goto out; 5255f453ba04SDave Airlie } 5256f453ba04SDave Airlie 52577203425aSJames Simmons crtc->funcs->gamma_set(crtc, r_base, g_base, b_base, 0, crtc->gamma_size); 5258f453ba04SDave Airlie 5259f453ba04SDave Airlie out: 526084849903SDaniel Vetter drm_modeset_unlock_all(dev); 5261f453ba04SDave Airlie return ret; 5262f453ba04SDave Airlie 5263f453ba04SDave Airlie } 5264f453ba04SDave Airlie 5265c8e32cc1SDaniel Vetter /** 5266c8e32cc1SDaniel Vetter * drm_mode_gamma_get_ioctl - get the gamma table 5267c8e32cc1SDaniel Vetter * @dev: DRM device 5268c8e32cc1SDaniel Vetter * @data: ioctl data 5269c8e32cc1SDaniel Vetter * @file_priv: DRM file info 5270c8e32cc1SDaniel Vetter * 5271c8e32cc1SDaniel Vetter * Copy the current gamma table into the storage provided. This also provides 5272c8e32cc1SDaniel Vetter * the gamma table size the driver expects, which can be used to size the 5273c8e32cc1SDaniel Vetter * allocated storage. 5274c8e32cc1SDaniel Vetter * 5275c8e32cc1SDaniel Vetter * Called by the user via ioctl. 5276c8e32cc1SDaniel Vetter * 5277c8e32cc1SDaniel Vetter * Returns: 52781a498633SDaniel Vetter * Zero on success, negative errno on failure. 5279c8e32cc1SDaniel Vetter */ 5280f453ba04SDave Airlie int drm_mode_gamma_get_ioctl(struct drm_device *dev, 5281f453ba04SDave Airlie void *data, struct drm_file *file_priv) 5282f453ba04SDave Airlie { 5283f453ba04SDave Airlie struct drm_mode_crtc_lut *crtc_lut = data; 5284f453ba04SDave Airlie struct drm_crtc *crtc; 5285f453ba04SDave Airlie void *r_base, *g_base, *b_base; 5286f453ba04SDave Airlie int size; 5287f453ba04SDave Airlie int ret = 0; 5288f453ba04SDave Airlie 5289fb3b06c8SDave Airlie if (!drm_core_check_feature(dev, DRIVER_MODESET)) 5290fb3b06c8SDave Airlie return -EINVAL; 5291fb3b06c8SDave Airlie 529284849903SDaniel Vetter drm_modeset_lock_all(dev); 5293a2b34e22SRob Clark crtc = drm_crtc_find(dev, crtc_lut->crtc_id); 5294a2b34e22SRob Clark if (!crtc) { 5295f27657f2SVille Syrjälä ret = -ENOENT; 5296f453ba04SDave Airlie goto out; 5297f453ba04SDave Airlie } 5298f453ba04SDave Airlie 5299f453ba04SDave Airlie /* memcpy into gamma store */ 5300f453ba04SDave Airlie if (crtc_lut->gamma_size != crtc->gamma_size) { 5301f453ba04SDave Airlie ret = -EINVAL; 5302f453ba04SDave Airlie goto out; 5303f453ba04SDave Airlie } 5304f453ba04SDave Airlie 5305f453ba04SDave Airlie size = crtc_lut->gamma_size * (sizeof(uint16_t)); 5306f453ba04SDave Airlie r_base = crtc->gamma_store; 5307f453ba04SDave Airlie if (copy_to_user((void __user *)(unsigned long)crtc_lut->red, r_base, size)) { 5308f453ba04SDave Airlie ret = -EFAULT; 5309f453ba04SDave Airlie goto out; 5310f453ba04SDave Airlie } 5311f453ba04SDave Airlie 5312f453ba04SDave Airlie g_base = r_base + size; 5313f453ba04SDave Airlie if (copy_to_user((void __user *)(unsigned long)crtc_lut->green, g_base, size)) { 5314f453ba04SDave Airlie ret = -EFAULT; 5315f453ba04SDave Airlie goto out; 5316f453ba04SDave Airlie } 5317f453ba04SDave Airlie 5318f453ba04SDave Airlie b_base = g_base + size; 5319f453ba04SDave Airlie if (copy_to_user((void __user *)(unsigned long)crtc_lut->blue, b_base, size)) { 5320f453ba04SDave Airlie ret = -EFAULT; 5321f453ba04SDave Airlie goto out; 5322f453ba04SDave Airlie } 5323f453ba04SDave Airlie out: 532484849903SDaniel Vetter drm_modeset_unlock_all(dev); 5325f453ba04SDave Airlie return ret; 5326f453ba04SDave Airlie } 5327d91d8a3fSKristian Høgsberg 5328c8e32cc1SDaniel Vetter /** 5329c8e32cc1SDaniel Vetter * drm_mode_page_flip_ioctl - schedule an asynchronous fb update 5330c8e32cc1SDaniel Vetter * @dev: DRM device 5331c8e32cc1SDaniel Vetter * @data: ioctl data 5332c8e32cc1SDaniel Vetter * @file_priv: DRM file info 5333c8e32cc1SDaniel Vetter * 5334c8e32cc1SDaniel Vetter * This schedules an asynchronous update on a given CRTC, called page flip. 5335c8e32cc1SDaniel Vetter * Optionally a drm event is generated to signal the completion of the event. 5336c8e32cc1SDaniel Vetter * Generic drivers cannot assume that a pageflip with changed framebuffer 5337c8e32cc1SDaniel Vetter * properties (including driver specific metadata like tiling layout) will work, 5338c8e32cc1SDaniel Vetter * but some drivers support e.g. pixel format changes through the pageflip 5339c8e32cc1SDaniel Vetter * ioctl. 5340c8e32cc1SDaniel Vetter * 5341c8e32cc1SDaniel Vetter * Called by the user via ioctl. 5342c8e32cc1SDaniel Vetter * 5343c8e32cc1SDaniel Vetter * Returns: 53441a498633SDaniel Vetter * Zero on success, negative errno on failure. 5345c8e32cc1SDaniel Vetter */ 5346d91d8a3fSKristian Høgsberg int drm_mode_page_flip_ioctl(struct drm_device *dev, 5347d91d8a3fSKristian Høgsberg void *data, struct drm_file *file_priv) 5348d91d8a3fSKristian Høgsberg { 5349d91d8a3fSKristian Høgsberg struct drm_mode_crtc_page_flip *page_flip = data; 5350d91d8a3fSKristian Høgsberg struct drm_crtc *crtc; 53513d30a59bSDaniel Vetter struct drm_framebuffer *fb = NULL; 5352d91d8a3fSKristian Høgsberg struct drm_pending_vblank_event *e = NULL; 5353d91d8a3fSKristian Høgsberg int ret = -EINVAL; 5354d91d8a3fSKristian Høgsberg 5355d91d8a3fSKristian Høgsberg if (page_flip->flags & ~DRM_MODE_PAGE_FLIP_FLAGS || 5356d91d8a3fSKristian Høgsberg page_flip->reserved != 0) 5357d91d8a3fSKristian Høgsberg return -EINVAL; 5358d91d8a3fSKristian Høgsberg 535962f2104fSKeith Packard if ((page_flip->flags & DRM_MODE_PAGE_FLIP_ASYNC) && !dev->mode_config.async_page_flip) 536062f2104fSKeith Packard return -EINVAL; 536162f2104fSKeith Packard 5362a2b34e22SRob Clark crtc = drm_crtc_find(dev, page_flip->crtc_id); 5363a2b34e22SRob Clark if (!crtc) 5364f27657f2SVille Syrjälä return -ENOENT; 5365d91d8a3fSKristian Høgsberg 53664d02e2deSDaniel Vetter drm_modeset_lock_crtc(crtc, crtc->primary); 5367f4510a27SMatt Roper if (crtc->primary->fb == NULL) { 536890c1efddSChris Wilson /* The framebuffer is currently unbound, presumably 536990c1efddSChris Wilson * due to a hotplug event, that userspace has not 537090c1efddSChris Wilson * yet discovered. 537190c1efddSChris Wilson */ 537290c1efddSChris Wilson ret = -EBUSY; 537390c1efddSChris Wilson goto out; 537490c1efddSChris Wilson } 537590c1efddSChris Wilson 5376d91d8a3fSKristian Høgsberg if (crtc->funcs->page_flip == NULL) 5377d91d8a3fSKristian Høgsberg goto out; 5378d91d8a3fSKristian Høgsberg 5379786b99edSDaniel Vetter fb = drm_framebuffer_lookup(dev, page_flip->fb_id); 538037c4e705SVille Syrjälä if (!fb) { 538137c4e705SVille Syrjälä ret = -ENOENT; 5382d91d8a3fSKristian Høgsberg goto out; 538337c4e705SVille Syrjälä } 5384d91d8a3fSKristian Høgsberg 53852afa701dSVille Syrjälä if (crtc->state) { 53862afa701dSVille Syrjälä const struct drm_plane_state *state = crtc->primary->state; 53872afa701dSVille Syrjälä 53882afa701dSVille Syrjälä ret = check_src_coords(state->src_x, state->src_y, 53892afa701dSVille Syrjälä state->src_w, state->src_h, fb); 53902afa701dSVille Syrjälä } else { 5391c11e9283SDamien Lespiau ret = drm_crtc_check_viewport(crtc, crtc->x, crtc->y, &crtc->mode, fb); 53922afa701dSVille Syrjälä } 5393c11e9283SDamien Lespiau if (ret) 53945f61bb42SVille Syrjälä goto out; 53955f61bb42SVille Syrjälä 5396f4510a27SMatt Roper if (crtc->primary->fb->pixel_format != fb->pixel_format) { 5397909d9cdaSLaurent Pinchart DRM_DEBUG_KMS("Page flip is not allowed to change frame buffer format.\n"); 5398909d9cdaSLaurent Pinchart ret = -EINVAL; 5399909d9cdaSLaurent Pinchart goto out; 5400909d9cdaSLaurent Pinchart } 5401909d9cdaSLaurent Pinchart 5402d91d8a3fSKristian Høgsberg if (page_flip->flags & DRM_MODE_PAGE_FLIP_EVENT) { 54032dd500f1SDaniel Vetter e = kzalloc(sizeof *e, GFP_KERNEL); 54042dd500f1SDaniel Vetter if (!e) { 5405d91d8a3fSKristian Høgsberg ret = -ENOMEM; 5406d91d8a3fSKristian Høgsberg goto out; 5407d91d8a3fSKristian Høgsberg } 54087bd4d7beSJesse Barnes e->event.base.type = DRM_EVENT_FLIP_COMPLETE; 5409f76511b9SThierry Reding e->event.base.length = sizeof(e->event); 5410d91d8a3fSKristian Høgsberg e->event.user_data = page_flip->user_data; 54112dd500f1SDaniel Vetter ret = drm_event_reserve_init(dev, file_priv, &e->base, &e->event.base); 54122dd500f1SDaniel Vetter if (ret) { 54132dd500f1SDaniel Vetter kfree(e); 54142dd500f1SDaniel Vetter goto out; 54152dd500f1SDaniel Vetter } 5416d91d8a3fSKristian Høgsberg } 5417d91d8a3fSKristian Høgsberg 54183d30a59bSDaniel Vetter crtc->primary->old_fb = crtc->primary->fb; 5419ed8d1975SKeith Packard ret = crtc->funcs->page_flip(crtc, fb, e, page_flip->flags); 5420d91d8a3fSKristian Høgsberg if (ret) { 54212dd500f1SDaniel Vetter if (page_flip->flags & DRM_MODE_PAGE_FLIP_EVENT) 54222dd500f1SDaniel Vetter drm_event_cancel_free(dev, &e->base); 5423b0d12325SDaniel Vetter /* Keep the old fb, don't unref it. */ 54243d30a59bSDaniel Vetter crtc->primary->old_fb = NULL; 5425b0d12325SDaniel Vetter } else { 54263cb43cc0SDaniel Vetter crtc->primary->fb = fb; 5427b0d12325SDaniel Vetter /* Unref only the old framebuffer. */ 5428b0d12325SDaniel Vetter fb = NULL; 5429aef6a7eeSJoonyoung Shim } 5430d91d8a3fSKristian Høgsberg 5431d91d8a3fSKristian Høgsberg out: 5432b0d12325SDaniel Vetter if (fb) 5433b0d12325SDaniel Vetter drm_framebuffer_unreference(fb); 54343d30a59bSDaniel Vetter if (crtc->primary->old_fb) 54353d30a59bSDaniel Vetter drm_framebuffer_unreference(crtc->primary->old_fb); 54363d30a59bSDaniel Vetter crtc->primary->old_fb = NULL; 5437d059f652SDaniel Vetter drm_modeset_unlock_crtc(crtc); 5438b4d5e7d1SDaniel Vetter 5439d91d8a3fSKristian Høgsberg return ret; 5440d91d8a3fSKristian Høgsberg } 5441eb033556SChris Wilson 5442c8e32cc1SDaniel Vetter /** 5443c8e32cc1SDaniel Vetter * drm_mode_config_reset - call ->reset callbacks 5444c8e32cc1SDaniel Vetter * @dev: drm device 5445c8e32cc1SDaniel Vetter * 5446c8e32cc1SDaniel Vetter * This functions calls all the crtc's, encoder's and connector's ->reset 5447c8e32cc1SDaniel Vetter * callback. Drivers can use this in e.g. their driver load or resume code to 5448c8e32cc1SDaniel Vetter * reset hardware and software state. 5449c8e32cc1SDaniel Vetter */ 5450eb033556SChris Wilson void drm_mode_config_reset(struct drm_device *dev) 5451eb033556SChris Wilson { 5452eb033556SChris Wilson struct drm_crtc *crtc; 54532a0d7cfdSDaniel Vetter struct drm_plane *plane; 5454eb033556SChris Wilson struct drm_encoder *encoder; 5455eb033556SChris Wilson struct drm_connector *connector; 5456eb033556SChris Wilson 5457e4f62546SDaniel Vetter drm_for_each_plane(plane, dev) 54582a0d7cfdSDaniel Vetter if (plane->funcs->reset) 54592a0d7cfdSDaniel Vetter plane->funcs->reset(plane); 54602a0d7cfdSDaniel Vetter 5461e4f62546SDaniel Vetter drm_for_each_crtc(crtc, dev) 5462eb033556SChris Wilson if (crtc->funcs->reset) 5463eb033556SChris Wilson crtc->funcs->reset(crtc); 5464eb033556SChris Wilson 5465e4f62546SDaniel Vetter drm_for_each_encoder(encoder, dev) 5466eb033556SChris Wilson if (encoder->funcs->reset) 5467eb033556SChris Wilson encoder->funcs->reset(encoder); 5468eb033556SChris Wilson 5469f8c2ba31SDaniel Vetter mutex_lock(&dev->mode_config.mutex); 54704eebf60bSDave Airlie drm_for_each_connector(connector, dev) 5471eb033556SChris Wilson if (connector->funcs->reset) 5472eb033556SChris Wilson connector->funcs->reset(connector); 5473f8c2ba31SDaniel Vetter mutex_unlock(&dev->mode_config.mutex); 54745e2cb2f6SDaniel Vetter } 5475eb033556SChris Wilson EXPORT_SYMBOL(drm_mode_config_reset); 5476ff72145bSDave Airlie 5477c8e32cc1SDaniel Vetter /** 5478c8e32cc1SDaniel Vetter * drm_mode_create_dumb_ioctl - create a dumb backing storage buffer 5479c8e32cc1SDaniel Vetter * @dev: DRM device 5480c8e32cc1SDaniel Vetter * @data: ioctl data 5481c8e32cc1SDaniel Vetter * @file_priv: DRM file info 5482c8e32cc1SDaniel Vetter * 5483c8e32cc1SDaniel Vetter * This creates a new dumb buffer in the driver's backing storage manager (GEM, 5484c8e32cc1SDaniel Vetter * TTM or something else entirely) and returns the resulting buffer handle. This 5485c8e32cc1SDaniel Vetter * handle can then be wrapped up into a framebuffer modeset object. 5486c8e32cc1SDaniel Vetter * 5487c8e32cc1SDaniel Vetter * Note that userspace is not allowed to use such objects for render 5488c8e32cc1SDaniel Vetter * acceleration - drivers must create their own private ioctls for such a use 5489c8e32cc1SDaniel Vetter * case. 5490c8e32cc1SDaniel Vetter * 5491c8e32cc1SDaniel Vetter * Called by the user via ioctl. 5492c8e32cc1SDaniel Vetter * 5493c8e32cc1SDaniel Vetter * Returns: 54941a498633SDaniel Vetter * Zero on success, negative errno on failure. 5495c8e32cc1SDaniel Vetter */ 5496ff72145bSDave Airlie int drm_mode_create_dumb_ioctl(struct drm_device *dev, 5497ff72145bSDave Airlie void *data, struct drm_file *file_priv) 5498ff72145bSDave Airlie { 5499ff72145bSDave Airlie struct drm_mode_create_dumb *args = data; 5500b28cd41fSDavid Herrmann u32 cpp, stride, size; 5501ff72145bSDave Airlie 5502ff72145bSDave Airlie if (!dev->driver->dumb_create) 5503ff72145bSDave Airlie return -ENOSYS; 5504b28cd41fSDavid Herrmann if (!args->width || !args->height || !args->bpp) 5505b28cd41fSDavid Herrmann return -EINVAL; 5506b28cd41fSDavid Herrmann 5507b28cd41fSDavid Herrmann /* overflow checks for 32bit size calculations */ 550800e72089SDavid Herrmann /* NOTE: DIV_ROUND_UP() can overflow */ 5509b28cd41fSDavid Herrmann cpp = DIV_ROUND_UP(args->bpp, 8); 551000e72089SDavid Herrmann if (!cpp || cpp > 0xffffffffU / args->width) 5511b28cd41fSDavid Herrmann return -EINVAL; 5512b28cd41fSDavid Herrmann stride = cpp * args->width; 5513b28cd41fSDavid Herrmann if (args->height > 0xffffffffU / stride) 5514b28cd41fSDavid Herrmann return -EINVAL; 5515b28cd41fSDavid Herrmann 5516b28cd41fSDavid Herrmann /* test for wrap-around */ 5517b28cd41fSDavid Herrmann size = args->height * stride; 5518b28cd41fSDavid Herrmann if (PAGE_ALIGN(size) == 0) 5519b28cd41fSDavid Herrmann return -EINVAL; 5520b28cd41fSDavid Herrmann 5521f6085952SThierry Reding /* 5522f6085952SThierry Reding * handle, pitch and size are output parameters. Zero them out to 5523f6085952SThierry Reding * prevent drivers from accidentally using uninitialized data. Since 5524f6085952SThierry Reding * not all existing userspace is clearing these fields properly we 5525f6085952SThierry Reding * cannot reject IOCTL with garbage in them. 5526f6085952SThierry Reding */ 5527f6085952SThierry Reding args->handle = 0; 5528f6085952SThierry Reding args->pitch = 0; 5529f6085952SThierry Reding args->size = 0; 5530f6085952SThierry Reding 5531ff72145bSDave Airlie return dev->driver->dumb_create(file_priv, dev, args); 5532ff72145bSDave Airlie } 5533ff72145bSDave Airlie 5534c8e32cc1SDaniel Vetter /** 5535c8e32cc1SDaniel Vetter * drm_mode_mmap_dumb_ioctl - create an mmap offset for a dumb backing storage buffer 5536c8e32cc1SDaniel Vetter * @dev: DRM device 5537c8e32cc1SDaniel Vetter * @data: ioctl data 5538c8e32cc1SDaniel Vetter * @file_priv: DRM file info 5539c8e32cc1SDaniel Vetter * 5540c8e32cc1SDaniel Vetter * Allocate an offset in the drm device node's address space to be able to 5541c8e32cc1SDaniel Vetter * memory map a dumb buffer. 5542c8e32cc1SDaniel Vetter * 5543c8e32cc1SDaniel Vetter * Called by the user via ioctl. 5544c8e32cc1SDaniel Vetter * 5545c8e32cc1SDaniel Vetter * Returns: 55461a498633SDaniel Vetter * Zero on success, negative errno on failure. 5547c8e32cc1SDaniel Vetter */ 5548ff72145bSDave Airlie int drm_mode_mmap_dumb_ioctl(struct drm_device *dev, 5549ff72145bSDave Airlie void *data, struct drm_file *file_priv) 5550ff72145bSDave Airlie { 5551ff72145bSDave Airlie struct drm_mode_map_dumb *args = data; 5552ff72145bSDave Airlie 5553ff72145bSDave Airlie /* call driver ioctl to get mmap offset */ 5554ff72145bSDave Airlie if (!dev->driver->dumb_map_offset) 5555ff72145bSDave Airlie return -ENOSYS; 5556ff72145bSDave Airlie 5557ff72145bSDave Airlie return dev->driver->dumb_map_offset(file_priv, dev, args->handle, &args->offset); 5558ff72145bSDave Airlie } 5559ff72145bSDave Airlie 5560c8e32cc1SDaniel Vetter /** 5561c8e32cc1SDaniel Vetter * drm_mode_destroy_dumb_ioctl - destroy a dumb backing strage buffer 5562c8e32cc1SDaniel Vetter * @dev: DRM device 5563c8e32cc1SDaniel Vetter * @data: ioctl data 5564c8e32cc1SDaniel Vetter * @file_priv: DRM file info 5565c8e32cc1SDaniel Vetter * 5566c8e32cc1SDaniel Vetter * This destroys the userspace handle for the given dumb backing storage buffer. 5567c8e32cc1SDaniel Vetter * Since buffer objects must be reference counted in the kernel a buffer object 5568c8e32cc1SDaniel Vetter * won't be immediately freed if a framebuffer modeset object still uses it. 5569c8e32cc1SDaniel Vetter * 5570c8e32cc1SDaniel Vetter * Called by the user via ioctl. 5571c8e32cc1SDaniel Vetter * 5572c8e32cc1SDaniel Vetter * Returns: 55731a498633SDaniel Vetter * Zero on success, negative errno on failure. 5574c8e32cc1SDaniel Vetter */ 5575ff72145bSDave Airlie int drm_mode_destroy_dumb_ioctl(struct drm_device *dev, 5576ff72145bSDave Airlie void *data, struct drm_file *file_priv) 5577ff72145bSDave Airlie { 5578ff72145bSDave Airlie struct drm_mode_destroy_dumb *args = data; 5579ff72145bSDave Airlie 5580ff72145bSDave Airlie if (!dev->driver->dumb_destroy) 5581ff72145bSDave Airlie return -ENOSYS; 5582ff72145bSDave Airlie 5583ff72145bSDave Airlie return dev->driver->dumb_destroy(file_priv, dev, args->handle); 5584ff72145bSDave Airlie } 5585248dbc23SDave Airlie 5586c8e32cc1SDaniel Vetter /** 5587c8e32cc1SDaniel Vetter * drm_fb_get_bpp_depth - get the bpp/depth values for format 5588c8e32cc1SDaniel Vetter * @format: pixel format (DRM_FORMAT_*) 5589c8e32cc1SDaniel Vetter * @depth: storage for the depth value 5590c8e32cc1SDaniel Vetter * @bpp: storage for the bpp value 5591c8e32cc1SDaniel Vetter * 5592c8e32cc1SDaniel Vetter * This only supports RGB formats here for compat with code that doesn't use 5593c8e32cc1SDaniel Vetter * pixel formats directly yet. 5594248dbc23SDave Airlie */ 5595248dbc23SDave Airlie void drm_fb_get_bpp_depth(uint32_t format, unsigned int *depth, 5596248dbc23SDave Airlie int *bpp) 5597248dbc23SDave Airlie { 5598248dbc23SDave Airlie switch (format) { 5599c51a6bc5SVille Syrjälä case DRM_FORMAT_C8: 560004b3924dSVille Syrjälä case DRM_FORMAT_RGB332: 560104b3924dSVille Syrjälä case DRM_FORMAT_BGR233: 5602248dbc23SDave Airlie *depth = 8; 5603248dbc23SDave Airlie *bpp = 8; 5604248dbc23SDave Airlie break; 560504b3924dSVille Syrjälä case DRM_FORMAT_XRGB1555: 560604b3924dSVille Syrjälä case DRM_FORMAT_XBGR1555: 560704b3924dSVille Syrjälä case DRM_FORMAT_RGBX5551: 560804b3924dSVille Syrjälä case DRM_FORMAT_BGRX5551: 560904b3924dSVille Syrjälä case DRM_FORMAT_ARGB1555: 561004b3924dSVille Syrjälä case DRM_FORMAT_ABGR1555: 561104b3924dSVille Syrjälä case DRM_FORMAT_RGBA5551: 561204b3924dSVille Syrjälä case DRM_FORMAT_BGRA5551: 5613248dbc23SDave Airlie *depth = 15; 5614248dbc23SDave Airlie *bpp = 16; 5615248dbc23SDave Airlie break; 561604b3924dSVille Syrjälä case DRM_FORMAT_RGB565: 561704b3924dSVille Syrjälä case DRM_FORMAT_BGR565: 5618248dbc23SDave Airlie *depth = 16; 5619248dbc23SDave Airlie *bpp = 16; 5620248dbc23SDave Airlie break; 562104b3924dSVille Syrjälä case DRM_FORMAT_RGB888: 562204b3924dSVille Syrjälä case DRM_FORMAT_BGR888: 562304b3924dSVille Syrjälä *depth = 24; 562404b3924dSVille Syrjälä *bpp = 24; 562504b3924dSVille Syrjälä break; 562604b3924dSVille Syrjälä case DRM_FORMAT_XRGB8888: 562704b3924dSVille Syrjälä case DRM_FORMAT_XBGR8888: 562804b3924dSVille Syrjälä case DRM_FORMAT_RGBX8888: 562904b3924dSVille Syrjälä case DRM_FORMAT_BGRX8888: 5630248dbc23SDave Airlie *depth = 24; 5631248dbc23SDave Airlie *bpp = 32; 5632248dbc23SDave Airlie break; 563304b3924dSVille Syrjälä case DRM_FORMAT_XRGB2101010: 563404b3924dSVille Syrjälä case DRM_FORMAT_XBGR2101010: 563504b3924dSVille Syrjälä case DRM_FORMAT_RGBX1010102: 563604b3924dSVille Syrjälä case DRM_FORMAT_BGRX1010102: 563704b3924dSVille Syrjälä case DRM_FORMAT_ARGB2101010: 563804b3924dSVille Syrjälä case DRM_FORMAT_ABGR2101010: 563904b3924dSVille Syrjälä case DRM_FORMAT_RGBA1010102: 564004b3924dSVille Syrjälä case DRM_FORMAT_BGRA1010102: 5641248dbc23SDave Airlie *depth = 30; 5642248dbc23SDave Airlie *bpp = 32; 5643248dbc23SDave Airlie break; 564404b3924dSVille Syrjälä case DRM_FORMAT_ARGB8888: 564504b3924dSVille Syrjälä case DRM_FORMAT_ABGR8888: 564604b3924dSVille Syrjälä case DRM_FORMAT_RGBA8888: 564704b3924dSVille Syrjälä case DRM_FORMAT_BGRA8888: 5648248dbc23SDave Airlie *depth = 32; 5649248dbc23SDave Airlie *bpp = 32; 5650248dbc23SDave Airlie break; 5651248dbc23SDave Airlie default: 565223c453a4SVille Syrjälä DRM_DEBUG_KMS("unsupported pixel format %s\n", 565323c453a4SVille Syrjälä drm_get_format_name(format)); 5654248dbc23SDave Airlie *depth = 0; 5655248dbc23SDave Airlie *bpp = 0; 5656248dbc23SDave Airlie break; 5657248dbc23SDave Airlie } 5658248dbc23SDave Airlie } 5659248dbc23SDave Airlie EXPORT_SYMBOL(drm_fb_get_bpp_depth); 5660141670e9SVille Syrjälä 5661141670e9SVille Syrjälä /** 5662141670e9SVille Syrjälä * drm_format_num_planes - get the number of planes for format 5663141670e9SVille Syrjälä * @format: pixel format (DRM_FORMAT_*) 5664141670e9SVille Syrjälä * 5665c8e32cc1SDaniel Vetter * Returns: 5666141670e9SVille Syrjälä * The number of planes used by the specified pixel format. 5667141670e9SVille Syrjälä */ 5668141670e9SVille Syrjälä int drm_format_num_planes(uint32_t format) 5669141670e9SVille Syrjälä { 5670141670e9SVille Syrjälä switch (format) { 5671141670e9SVille Syrjälä case DRM_FORMAT_YUV410: 5672141670e9SVille Syrjälä case DRM_FORMAT_YVU410: 5673141670e9SVille Syrjälä case DRM_FORMAT_YUV411: 5674141670e9SVille Syrjälä case DRM_FORMAT_YVU411: 5675141670e9SVille Syrjälä case DRM_FORMAT_YUV420: 5676141670e9SVille Syrjälä case DRM_FORMAT_YVU420: 5677141670e9SVille Syrjälä case DRM_FORMAT_YUV422: 5678141670e9SVille Syrjälä case DRM_FORMAT_YVU422: 5679141670e9SVille Syrjälä case DRM_FORMAT_YUV444: 5680141670e9SVille Syrjälä case DRM_FORMAT_YVU444: 5681141670e9SVille Syrjälä return 3; 5682141670e9SVille Syrjälä case DRM_FORMAT_NV12: 5683141670e9SVille Syrjälä case DRM_FORMAT_NV21: 5684141670e9SVille Syrjälä case DRM_FORMAT_NV16: 5685141670e9SVille Syrjälä case DRM_FORMAT_NV61: 5686ba623f6aSLaurent Pinchart case DRM_FORMAT_NV24: 5687ba623f6aSLaurent Pinchart case DRM_FORMAT_NV42: 5688141670e9SVille Syrjälä return 2; 5689141670e9SVille Syrjälä default: 5690141670e9SVille Syrjälä return 1; 5691141670e9SVille Syrjälä } 5692141670e9SVille Syrjälä } 5693141670e9SVille Syrjälä EXPORT_SYMBOL(drm_format_num_planes); 56945a86bd55SVille Syrjälä 56955a86bd55SVille Syrjälä /** 56965a86bd55SVille Syrjälä * drm_format_plane_cpp - determine the bytes per pixel value 56975a86bd55SVille Syrjälä * @format: pixel format (DRM_FORMAT_*) 56985a86bd55SVille Syrjälä * @plane: plane index 56995a86bd55SVille Syrjälä * 5700c8e32cc1SDaniel Vetter * Returns: 57015a86bd55SVille Syrjälä * The bytes per pixel value for the specified plane. 57025a86bd55SVille Syrjälä */ 57035a86bd55SVille Syrjälä int drm_format_plane_cpp(uint32_t format, int plane) 57045a86bd55SVille Syrjälä { 57055a86bd55SVille Syrjälä unsigned int depth; 57065a86bd55SVille Syrjälä int bpp; 57075a86bd55SVille Syrjälä 57085a86bd55SVille Syrjälä if (plane >= drm_format_num_planes(format)) 57095a86bd55SVille Syrjälä return 0; 57105a86bd55SVille Syrjälä 57115a86bd55SVille Syrjälä switch (format) { 57125a86bd55SVille Syrjälä case DRM_FORMAT_YUYV: 57135a86bd55SVille Syrjälä case DRM_FORMAT_YVYU: 57145a86bd55SVille Syrjälä case DRM_FORMAT_UYVY: 57155a86bd55SVille Syrjälä case DRM_FORMAT_VYUY: 57165a86bd55SVille Syrjälä return 2; 57175a86bd55SVille Syrjälä case DRM_FORMAT_NV12: 57185a86bd55SVille Syrjälä case DRM_FORMAT_NV21: 57195a86bd55SVille Syrjälä case DRM_FORMAT_NV16: 57205a86bd55SVille Syrjälä case DRM_FORMAT_NV61: 5721ba623f6aSLaurent Pinchart case DRM_FORMAT_NV24: 5722ba623f6aSLaurent Pinchart case DRM_FORMAT_NV42: 57235a86bd55SVille Syrjälä return plane ? 2 : 1; 57245a86bd55SVille Syrjälä case DRM_FORMAT_YUV410: 57255a86bd55SVille Syrjälä case DRM_FORMAT_YVU410: 57265a86bd55SVille Syrjälä case DRM_FORMAT_YUV411: 57275a86bd55SVille Syrjälä case DRM_FORMAT_YVU411: 57285a86bd55SVille Syrjälä case DRM_FORMAT_YUV420: 57295a86bd55SVille Syrjälä case DRM_FORMAT_YVU420: 57305a86bd55SVille Syrjälä case DRM_FORMAT_YUV422: 57315a86bd55SVille Syrjälä case DRM_FORMAT_YVU422: 57325a86bd55SVille Syrjälä case DRM_FORMAT_YUV444: 57335a86bd55SVille Syrjälä case DRM_FORMAT_YVU444: 57345a86bd55SVille Syrjälä return 1; 57355a86bd55SVille Syrjälä default: 57365a86bd55SVille Syrjälä drm_fb_get_bpp_depth(format, &depth, &bpp); 57375a86bd55SVille Syrjälä return bpp >> 3; 57385a86bd55SVille Syrjälä } 57395a86bd55SVille Syrjälä } 57405a86bd55SVille Syrjälä EXPORT_SYMBOL(drm_format_plane_cpp); 574101b68b04SVille Syrjälä 574201b68b04SVille Syrjälä /** 574301b68b04SVille Syrjälä * drm_format_horz_chroma_subsampling - get the horizontal chroma subsampling factor 574401b68b04SVille Syrjälä * @format: pixel format (DRM_FORMAT_*) 574501b68b04SVille Syrjälä * 5746c8e32cc1SDaniel Vetter * Returns: 574701b68b04SVille Syrjälä * The horizontal chroma subsampling factor for the 574801b68b04SVille Syrjälä * specified pixel format. 574901b68b04SVille Syrjälä */ 575001b68b04SVille Syrjälä int drm_format_horz_chroma_subsampling(uint32_t format) 575101b68b04SVille Syrjälä { 575201b68b04SVille Syrjälä switch (format) { 575301b68b04SVille Syrjälä case DRM_FORMAT_YUV411: 575401b68b04SVille Syrjälä case DRM_FORMAT_YVU411: 575501b68b04SVille Syrjälä case DRM_FORMAT_YUV410: 575601b68b04SVille Syrjälä case DRM_FORMAT_YVU410: 575701b68b04SVille Syrjälä return 4; 575801b68b04SVille Syrjälä case DRM_FORMAT_YUYV: 575901b68b04SVille Syrjälä case DRM_FORMAT_YVYU: 576001b68b04SVille Syrjälä case DRM_FORMAT_UYVY: 576101b68b04SVille Syrjälä case DRM_FORMAT_VYUY: 576201b68b04SVille Syrjälä case DRM_FORMAT_NV12: 576301b68b04SVille Syrjälä case DRM_FORMAT_NV21: 576401b68b04SVille Syrjälä case DRM_FORMAT_NV16: 576501b68b04SVille Syrjälä case DRM_FORMAT_NV61: 576601b68b04SVille Syrjälä case DRM_FORMAT_YUV422: 576701b68b04SVille Syrjälä case DRM_FORMAT_YVU422: 576801b68b04SVille Syrjälä case DRM_FORMAT_YUV420: 576901b68b04SVille Syrjälä case DRM_FORMAT_YVU420: 577001b68b04SVille Syrjälä return 2; 577101b68b04SVille Syrjälä default: 577201b68b04SVille Syrjälä return 1; 577301b68b04SVille Syrjälä } 577401b68b04SVille Syrjälä } 577501b68b04SVille Syrjälä EXPORT_SYMBOL(drm_format_horz_chroma_subsampling); 577601b68b04SVille Syrjälä 577701b68b04SVille Syrjälä /** 577801b68b04SVille Syrjälä * drm_format_vert_chroma_subsampling - get the vertical chroma subsampling factor 577901b68b04SVille Syrjälä * @format: pixel format (DRM_FORMAT_*) 578001b68b04SVille Syrjälä * 5781c8e32cc1SDaniel Vetter * Returns: 578201b68b04SVille Syrjälä * The vertical chroma subsampling factor for the 578301b68b04SVille Syrjälä * specified pixel format. 578401b68b04SVille Syrjälä */ 578501b68b04SVille Syrjälä int drm_format_vert_chroma_subsampling(uint32_t format) 578601b68b04SVille Syrjälä { 578701b68b04SVille Syrjälä switch (format) { 578801b68b04SVille Syrjälä case DRM_FORMAT_YUV410: 578901b68b04SVille Syrjälä case DRM_FORMAT_YVU410: 579001b68b04SVille Syrjälä return 4; 579101b68b04SVille Syrjälä case DRM_FORMAT_YUV420: 579201b68b04SVille Syrjälä case DRM_FORMAT_YVU420: 579301b68b04SVille Syrjälä case DRM_FORMAT_NV12: 579401b68b04SVille Syrjälä case DRM_FORMAT_NV21: 579501b68b04SVille Syrjälä return 2; 579601b68b04SVille Syrjälä default: 579701b68b04SVille Syrjälä return 1; 579801b68b04SVille Syrjälä } 579901b68b04SVille Syrjälä } 580001b68b04SVille Syrjälä EXPORT_SYMBOL(drm_format_vert_chroma_subsampling); 580187d24fc3SLaurent Pinchart 580287d24fc3SLaurent Pinchart /** 58034c61716cSVille Syrjälä * drm_format_plane_width - width of the plane given the first plane 58044c61716cSVille Syrjälä * @width: width of the first plane 58054c61716cSVille Syrjälä * @format: pixel format 58064c61716cSVille Syrjälä * @plane: plane index 58074c61716cSVille Syrjälä * 58084c61716cSVille Syrjälä * Returns: 58094c61716cSVille Syrjälä * The width of @plane, given that the width of the first plane is @width. 58104c61716cSVille Syrjälä */ 58114c61716cSVille Syrjälä int drm_format_plane_width(int width, uint32_t format, int plane) 58124c61716cSVille Syrjälä { 58134c61716cSVille Syrjälä if (plane >= drm_format_num_planes(format)) 58144c61716cSVille Syrjälä return 0; 58154c61716cSVille Syrjälä 58164c61716cSVille Syrjälä if (plane == 0) 58174c61716cSVille Syrjälä return width; 58184c61716cSVille Syrjälä 58194c61716cSVille Syrjälä return width / drm_format_horz_chroma_subsampling(format); 58204c61716cSVille Syrjälä } 58214c61716cSVille Syrjälä EXPORT_SYMBOL(drm_format_plane_width); 58224c61716cSVille Syrjälä 58234c61716cSVille Syrjälä /** 58244c61716cSVille Syrjälä * drm_format_plane_height - height of the plane given the first plane 58254c61716cSVille Syrjälä * @height: height of the first plane 58264c61716cSVille Syrjälä * @format: pixel format 58274c61716cSVille Syrjälä * @plane: plane index 58284c61716cSVille Syrjälä * 58294c61716cSVille Syrjälä * Returns: 58304c61716cSVille Syrjälä * The height of @plane, given that the height of the first plane is @height. 58314c61716cSVille Syrjälä */ 58324c61716cSVille Syrjälä int drm_format_plane_height(int height, uint32_t format, int plane) 58334c61716cSVille Syrjälä { 58344c61716cSVille Syrjälä if (plane >= drm_format_num_planes(format)) 58354c61716cSVille Syrjälä return 0; 58364c61716cSVille Syrjälä 58374c61716cSVille Syrjälä if (plane == 0) 58384c61716cSVille Syrjälä return height; 58394c61716cSVille Syrjälä 58404c61716cSVille Syrjälä return height / drm_format_vert_chroma_subsampling(format); 58414c61716cSVille Syrjälä } 58424c61716cSVille Syrjälä EXPORT_SYMBOL(drm_format_plane_height); 58434c61716cSVille Syrjälä 58444c61716cSVille Syrjälä /** 58453c9855f6SVille Syrjälä * drm_rotation_simplify() - Try to simplify the rotation 58463c9855f6SVille Syrjälä * @rotation: Rotation to be simplified 58473c9855f6SVille Syrjälä * @supported_rotations: Supported rotations 58483c9855f6SVille Syrjälä * 58493c9855f6SVille Syrjälä * Attempt to simplify the rotation to a form that is supported. 58503c9855f6SVille Syrjälä * Eg. if the hardware supports everything except DRM_REFLECT_X 58513c9855f6SVille Syrjälä * one could call this function like this: 58523c9855f6SVille Syrjälä * 58533c9855f6SVille Syrjälä * drm_rotation_simplify(rotation, BIT(DRM_ROTATE_0) | 58543c9855f6SVille Syrjälä * BIT(DRM_ROTATE_90) | BIT(DRM_ROTATE_180) | 58553c9855f6SVille Syrjälä * BIT(DRM_ROTATE_270) | BIT(DRM_REFLECT_Y)); 58563c9855f6SVille Syrjälä * 58573c9855f6SVille Syrjälä * to eliminate the DRM_ROTATE_X flag. Depending on what kind of 58583c9855f6SVille Syrjälä * transforms the hardware supports, this function may not 58593c9855f6SVille Syrjälä * be able to produce a supported transform, so the caller should 58603c9855f6SVille Syrjälä * check the result afterwards. 58613c9855f6SVille Syrjälä */ 58623c9855f6SVille Syrjälä unsigned int drm_rotation_simplify(unsigned int rotation, 58633c9855f6SVille Syrjälä unsigned int supported_rotations) 58643c9855f6SVille Syrjälä { 58653c9855f6SVille Syrjälä if (rotation & ~supported_rotations) { 58663c9855f6SVille Syrjälä rotation ^= BIT(DRM_REFLECT_X) | BIT(DRM_REFLECT_Y); 586714152c8dSJoonas Lahtinen rotation = (rotation & DRM_REFLECT_MASK) | 586814152c8dSJoonas Lahtinen BIT((ffs(rotation & DRM_ROTATE_MASK) + 1) % 4); 58693c9855f6SVille Syrjälä } 58703c9855f6SVille Syrjälä 58713c9855f6SVille Syrjälä return rotation; 58723c9855f6SVille Syrjälä } 58733c9855f6SVille Syrjälä EXPORT_SYMBOL(drm_rotation_simplify); 58743c9855f6SVille Syrjälä 58753c9855f6SVille Syrjälä /** 587687d24fc3SLaurent Pinchart * drm_mode_config_init - initialize DRM mode_configuration structure 587787d24fc3SLaurent Pinchart * @dev: DRM device 587887d24fc3SLaurent Pinchart * 587987d24fc3SLaurent Pinchart * Initialize @dev's mode_config structure, used for tracking the graphics 588087d24fc3SLaurent Pinchart * configuration of @dev. 588187d24fc3SLaurent Pinchart * 588287d24fc3SLaurent Pinchart * Since this initializes the modeset locks, no locking is possible. Which is no 588387d24fc3SLaurent Pinchart * problem, since this should happen single threaded at init time. It is the 588487d24fc3SLaurent Pinchart * driver's problem to ensure this guarantee. 588587d24fc3SLaurent Pinchart * 588687d24fc3SLaurent Pinchart */ 588787d24fc3SLaurent Pinchart void drm_mode_config_init(struct drm_device *dev) 588887d24fc3SLaurent Pinchart { 588987d24fc3SLaurent Pinchart mutex_init(&dev->mode_config.mutex); 589051fd371bSRob Clark drm_modeset_lock_init(&dev->mode_config.connection_mutex); 589187d24fc3SLaurent Pinchart mutex_init(&dev->mode_config.idr_mutex); 589287d24fc3SLaurent Pinchart mutex_init(&dev->mode_config.fb_lock); 58938fb6e7a5SDaniel Stone mutex_init(&dev->mode_config.blob_lock); 589487d24fc3SLaurent Pinchart INIT_LIST_HEAD(&dev->mode_config.fb_list); 589587d24fc3SLaurent Pinchart INIT_LIST_HEAD(&dev->mode_config.crtc_list); 589687d24fc3SLaurent Pinchart INIT_LIST_HEAD(&dev->mode_config.connector_list); 589787d24fc3SLaurent Pinchart INIT_LIST_HEAD(&dev->mode_config.encoder_list); 589887d24fc3SLaurent Pinchart INIT_LIST_HEAD(&dev->mode_config.property_list); 589987d24fc3SLaurent Pinchart INIT_LIST_HEAD(&dev->mode_config.property_blob_list); 590087d24fc3SLaurent Pinchart INIT_LIST_HEAD(&dev->mode_config.plane_list); 590187d24fc3SLaurent Pinchart idr_init(&dev->mode_config.crtc_idr); 5902138f9ebbSDave Airlie idr_init(&dev->mode_config.tile_idr); 59035fff80bbSMaarten Lankhorst ida_init(&dev->mode_config.connector_ida); 590487d24fc3SLaurent Pinchart 590587d24fc3SLaurent Pinchart drm_modeset_lock_all(dev); 59066b4959f4SRob Clark drm_mode_create_standard_properties(dev); 590787d24fc3SLaurent Pinchart drm_modeset_unlock_all(dev); 590887d24fc3SLaurent Pinchart 590987d24fc3SLaurent Pinchart /* Just to be sure */ 591087d24fc3SLaurent Pinchart dev->mode_config.num_fb = 0; 591187d24fc3SLaurent Pinchart dev->mode_config.num_connector = 0; 591287d24fc3SLaurent Pinchart dev->mode_config.num_crtc = 0; 591387d24fc3SLaurent Pinchart dev->mode_config.num_encoder = 0; 5914e27dde3eSMatt Roper dev->mode_config.num_overlay_plane = 0; 5915e27dde3eSMatt Roper dev->mode_config.num_total_plane = 0; 591687d24fc3SLaurent Pinchart } 591787d24fc3SLaurent Pinchart EXPORT_SYMBOL(drm_mode_config_init); 591887d24fc3SLaurent Pinchart 591987d24fc3SLaurent Pinchart /** 592087d24fc3SLaurent Pinchart * drm_mode_config_cleanup - free up DRM mode_config info 592187d24fc3SLaurent Pinchart * @dev: DRM device 592287d24fc3SLaurent Pinchart * 592387d24fc3SLaurent Pinchart * Free up all the connectors and CRTCs associated with this DRM device, then 592487d24fc3SLaurent Pinchart * free up the framebuffers and associated buffer objects. 592587d24fc3SLaurent Pinchart * 592687d24fc3SLaurent Pinchart * Note that since this /should/ happen single-threaded at driver/device 592787d24fc3SLaurent Pinchart * teardown time, no locking is required. It's the driver's job to ensure that 592887d24fc3SLaurent Pinchart * this guarantee actually holds true. 592987d24fc3SLaurent Pinchart * 593087d24fc3SLaurent Pinchart * FIXME: cleanup any dangling user buffer objects too 593187d24fc3SLaurent Pinchart */ 593287d24fc3SLaurent Pinchart void drm_mode_config_cleanup(struct drm_device *dev) 593387d24fc3SLaurent Pinchart { 593487d24fc3SLaurent Pinchart struct drm_connector *connector, *ot; 593587d24fc3SLaurent Pinchart struct drm_crtc *crtc, *ct; 593687d24fc3SLaurent Pinchart struct drm_encoder *encoder, *enct; 593787d24fc3SLaurent Pinchart struct drm_framebuffer *fb, *fbt; 593887d24fc3SLaurent Pinchart struct drm_property *property, *pt; 593987d24fc3SLaurent Pinchart struct drm_property_blob *blob, *bt; 594087d24fc3SLaurent Pinchart struct drm_plane *plane, *plt; 594187d24fc3SLaurent Pinchart 594287d24fc3SLaurent Pinchart list_for_each_entry_safe(encoder, enct, &dev->mode_config.encoder_list, 594387d24fc3SLaurent Pinchart head) { 594487d24fc3SLaurent Pinchart encoder->funcs->destroy(encoder); 594587d24fc3SLaurent Pinchart } 594687d24fc3SLaurent Pinchart 594787d24fc3SLaurent Pinchart list_for_each_entry_safe(connector, ot, 594887d24fc3SLaurent Pinchart &dev->mode_config.connector_list, head) { 594987d24fc3SLaurent Pinchart connector->funcs->destroy(connector); 595087d24fc3SLaurent Pinchart } 595187d24fc3SLaurent Pinchart 595287d24fc3SLaurent Pinchart list_for_each_entry_safe(property, pt, &dev->mode_config.property_list, 595387d24fc3SLaurent Pinchart head) { 595487d24fc3SLaurent Pinchart drm_property_destroy(dev, property); 595587d24fc3SLaurent Pinchart } 595687d24fc3SLaurent Pinchart 5957f35034f8SMaarten Lankhorst list_for_each_entry_safe(plane, plt, &dev->mode_config.plane_list, 5958f35034f8SMaarten Lankhorst head) { 5959f35034f8SMaarten Lankhorst plane->funcs->destroy(plane); 5960f35034f8SMaarten Lankhorst } 5961f35034f8SMaarten Lankhorst 5962f35034f8SMaarten Lankhorst list_for_each_entry_safe(crtc, ct, &dev->mode_config.crtc_list, head) { 5963f35034f8SMaarten Lankhorst crtc->funcs->destroy(crtc); 5964f35034f8SMaarten Lankhorst } 5965f35034f8SMaarten Lankhorst 596687d24fc3SLaurent Pinchart list_for_each_entry_safe(blob, bt, &dev->mode_config.property_blob_list, 5967e2f5d2eaSDaniel Stone head_global) { 59686bcacf51SDaniel Stone drm_property_unreference_blob(blob); 596987d24fc3SLaurent Pinchart } 597087d24fc3SLaurent Pinchart 597187d24fc3SLaurent Pinchart /* 597287d24fc3SLaurent Pinchart * Single-threaded teardown context, so it's not required to grab the 597387d24fc3SLaurent Pinchart * fb_lock to protect against concurrent fb_list access. Contrary, it 597487d24fc3SLaurent Pinchart * would actually deadlock with the drm_framebuffer_cleanup function. 597587d24fc3SLaurent Pinchart * 597687d24fc3SLaurent Pinchart * Also, if there are any framebuffers left, that's a driver leak now, 597787d24fc3SLaurent Pinchart * so politely WARN about this. 597887d24fc3SLaurent Pinchart */ 597987d24fc3SLaurent Pinchart WARN_ON(!list_empty(&dev->mode_config.fb_list)); 598087d24fc3SLaurent Pinchart list_for_each_entry_safe(fb, fbt, &dev->mode_config.fb_list, head) { 5981c099b55aSMaarten Lankhorst drm_framebuffer_free(&fb->refcount); 598287d24fc3SLaurent Pinchart } 598387d24fc3SLaurent Pinchart 59845fff80bbSMaarten Lankhorst ida_destroy(&dev->mode_config.connector_ida); 5985138f9ebbSDave Airlie idr_destroy(&dev->mode_config.tile_idr); 598687d24fc3SLaurent Pinchart idr_destroy(&dev->mode_config.crtc_idr); 598751fd371bSRob Clark drm_modeset_lock_fini(&dev->mode_config.connection_mutex); 598887d24fc3SLaurent Pinchart } 598987d24fc3SLaurent Pinchart EXPORT_SYMBOL(drm_mode_config_cleanup); 5990c1df5f3cSVille Syrjälä 5991c1df5f3cSVille Syrjälä struct drm_property *drm_mode_create_rotation_property(struct drm_device *dev, 5992c1df5f3cSVille Syrjälä unsigned int supported_rotations) 5993c1df5f3cSVille Syrjälä { 5994c1df5f3cSVille Syrjälä static const struct drm_prop_enum_list props[] = { 5995c1df5f3cSVille Syrjälä { DRM_ROTATE_0, "rotate-0" }, 5996c1df5f3cSVille Syrjälä { DRM_ROTATE_90, "rotate-90" }, 5997c1df5f3cSVille Syrjälä { DRM_ROTATE_180, "rotate-180" }, 5998c1df5f3cSVille Syrjälä { DRM_ROTATE_270, "rotate-270" }, 5999c1df5f3cSVille Syrjälä { DRM_REFLECT_X, "reflect-x" }, 6000c1df5f3cSVille Syrjälä { DRM_REFLECT_Y, "reflect-y" }, 6001c1df5f3cSVille Syrjälä }; 6002c1df5f3cSVille Syrjälä 6003c1df5f3cSVille Syrjälä return drm_property_create_bitmask(dev, 0, "rotation", 6004c1df5f3cSVille Syrjälä props, ARRAY_SIZE(props), 6005c1df5f3cSVille Syrjälä supported_rotations); 6006c1df5f3cSVille Syrjälä } 6007c1df5f3cSVille Syrjälä EXPORT_SYMBOL(drm_mode_create_rotation_property); 6008138f9ebbSDave Airlie 6009138f9ebbSDave Airlie /** 6010138f9ebbSDave Airlie * DOC: Tile group 6011138f9ebbSDave Airlie * 6012138f9ebbSDave Airlie * Tile groups are used to represent tiled monitors with a unique 6013138f9ebbSDave Airlie * integer identifier. Tiled monitors using DisplayID v1.3 have 6014138f9ebbSDave Airlie * a unique 8-byte handle, we store this in a tile group, so we 6015138f9ebbSDave Airlie * have a common identifier for all tiles in a monitor group. 6016138f9ebbSDave Airlie */ 6017138f9ebbSDave Airlie static void drm_tile_group_free(struct kref *kref) 6018138f9ebbSDave Airlie { 6019138f9ebbSDave Airlie struct drm_tile_group *tg = container_of(kref, struct drm_tile_group, refcount); 6020138f9ebbSDave Airlie struct drm_device *dev = tg->dev; 6021138f9ebbSDave Airlie mutex_lock(&dev->mode_config.idr_mutex); 6022138f9ebbSDave Airlie idr_remove(&dev->mode_config.tile_idr, tg->id); 6023138f9ebbSDave Airlie mutex_unlock(&dev->mode_config.idr_mutex); 6024138f9ebbSDave Airlie kfree(tg); 6025138f9ebbSDave Airlie } 6026138f9ebbSDave Airlie 6027138f9ebbSDave Airlie /** 6028138f9ebbSDave Airlie * drm_mode_put_tile_group - drop a reference to a tile group. 6029138f9ebbSDave Airlie * @dev: DRM device 6030138f9ebbSDave Airlie * @tg: tile group to drop reference to. 6031138f9ebbSDave Airlie * 6032138f9ebbSDave Airlie * drop reference to tile group and free if 0. 6033138f9ebbSDave Airlie */ 6034138f9ebbSDave Airlie void drm_mode_put_tile_group(struct drm_device *dev, 6035138f9ebbSDave Airlie struct drm_tile_group *tg) 6036138f9ebbSDave Airlie { 6037138f9ebbSDave Airlie kref_put(&tg->refcount, drm_tile_group_free); 6038138f9ebbSDave Airlie } 6039138f9ebbSDave Airlie 6040138f9ebbSDave Airlie /** 6041138f9ebbSDave Airlie * drm_mode_get_tile_group - get a reference to an existing tile group 6042138f9ebbSDave Airlie * @dev: DRM device 6043138f9ebbSDave Airlie * @topology: 8-bytes unique per monitor. 6044138f9ebbSDave Airlie * 6045138f9ebbSDave Airlie * Use the unique bytes to get a reference to an existing tile group. 6046138f9ebbSDave Airlie * 6047138f9ebbSDave Airlie * RETURNS: 6048138f9ebbSDave Airlie * tile group or NULL if not found. 6049138f9ebbSDave Airlie */ 6050138f9ebbSDave Airlie struct drm_tile_group *drm_mode_get_tile_group(struct drm_device *dev, 6051138f9ebbSDave Airlie char topology[8]) 6052138f9ebbSDave Airlie { 6053138f9ebbSDave Airlie struct drm_tile_group *tg; 6054138f9ebbSDave Airlie int id; 6055138f9ebbSDave Airlie mutex_lock(&dev->mode_config.idr_mutex); 6056138f9ebbSDave Airlie idr_for_each_entry(&dev->mode_config.tile_idr, tg, id) { 6057138f9ebbSDave Airlie if (!memcmp(tg->group_data, topology, 8)) { 6058138f9ebbSDave Airlie if (!kref_get_unless_zero(&tg->refcount)) 6059138f9ebbSDave Airlie tg = NULL; 6060138f9ebbSDave Airlie mutex_unlock(&dev->mode_config.idr_mutex); 6061138f9ebbSDave Airlie return tg; 6062138f9ebbSDave Airlie } 6063138f9ebbSDave Airlie } 6064138f9ebbSDave Airlie mutex_unlock(&dev->mode_config.idr_mutex); 6065138f9ebbSDave Airlie return NULL; 6066138f9ebbSDave Airlie } 606781ddd1bcSRob Clark EXPORT_SYMBOL(drm_mode_get_tile_group); 6068138f9ebbSDave Airlie 6069138f9ebbSDave Airlie /** 6070138f9ebbSDave Airlie * drm_mode_create_tile_group - create a tile group from a displayid description 6071138f9ebbSDave Airlie * @dev: DRM device 6072138f9ebbSDave Airlie * @topology: 8-bytes unique per monitor. 6073138f9ebbSDave Airlie * 6074138f9ebbSDave Airlie * Create a tile group for the unique monitor, and get a unique 6075138f9ebbSDave Airlie * identifier for the tile group. 6076138f9ebbSDave Airlie * 6077138f9ebbSDave Airlie * RETURNS: 6078138f9ebbSDave Airlie * new tile group or error. 6079138f9ebbSDave Airlie */ 6080138f9ebbSDave Airlie struct drm_tile_group *drm_mode_create_tile_group(struct drm_device *dev, 6081138f9ebbSDave Airlie char topology[8]) 6082138f9ebbSDave Airlie { 6083138f9ebbSDave Airlie struct drm_tile_group *tg; 6084138f9ebbSDave Airlie int ret; 6085138f9ebbSDave Airlie 6086138f9ebbSDave Airlie tg = kzalloc(sizeof(*tg), GFP_KERNEL); 6087138f9ebbSDave Airlie if (!tg) 6088138f9ebbSDave Airlie return ERR_PTR(-ENOMEM); 6089138f9ebbSDave Airlie 6090138f9ebbSDave Airlie kref_init(&tg->refcount); 6091138f9ebbSDave Airlie memcpy(tg->group_data, topology, 8); 6092138f9ebbSDave Airlie tg->dev = dev; 6093138f9ebbSDave Airlie 6094138f9ebbSDave Airlie mutex_lock(&dev->mode_config.idr_mutex); 6095138f9ebbSDave Airlie ret = idr_alloc(&dev->mode_config.tile_idr, tg, 1, 0, GFP_KERNEL); 6096138f9ebbSDave Airlie if (ret >= 0) { 6097138f9ebbSDave Airlie tg->id = ret; 6098138f9ebbSDave Airlie } else { 6099138f9ebbSDave Airlie kfree(tg); 6100138f9ebbSDave Airlie tg = ERR_PTR(ret); 6101138f9ebbSDave Airlie } 6102138f9ebbSDave Airlie 6103138f9ebbSDave Airlie mutex_unlock(&dev->mode_config.idr_mutex); 6104138f9ebbSDave Airlie return tg; 6105138f9ebbSDave Airlie } 610681ddd1bcSRob Clark EXPORT_SYMBOL(drm_mode_create_tile_group); 6107