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 { 43383f45fc3SDaniel Vetter mutex_lock(&dev->mode_config.idr_mutex); 43483f45fc3SDaniel Vetter idr_remove(&dev->mode_config.crtc_idr, fb->base.id); 43583f45fc3SDaniel Vetter mutex_unlock(&dev->mode_config.idr_mutex); 43683f45fc3SDaniel Vetter 43783f45fc3SDaniel Vetter fb->base.id = 0; 43883f45fc3SDaniel Vetter } 43983f45fc3SDaniel Vetter 440f7eff60eSRob Clark static void drm_framebuffer_free(struct kref *kref) 441f7eff60eSRob Clark { 442f7eff60eSRob Clark struct drm_framebuffer *fb = 443f7eff60eSRob Clark container_of(kref, struct drm_framebuffer, refcount); 44483f45fc3SDaniel Vetter struct drm_device *dev = fb->dev; 44583f45fc3SDaniel Vetter 44683f45fc3SDaniel Vetter /* 44783f45fc3SDaniel Vetter * The lookup idr holds a weak reference, which has not necessarily been 44883f45fc3SDaniel Vetter * removed at this point. Check for that. 44983f45fc3SDaniel Vetter */ 45083f45fc3SDaniel Vetter mutex_lock(&dev->mode_config.fb_lock); 45183f45fc3SDaniel Vetter if (fb->base.id) { 45283f45fc3SDaniel Vetter /* Mark fb as reaped and drop idr ref. */ 45383f45fc3SDaniel Vetter __drm_framebuffer_unregister(dev, fb); 45483f45fc3SDaniel Vetter } 45583f45fc3SDaniel Vetter mutex_unlock(&dev->mode_config.fb_lock); 45683f45fc3SDaniel Vetter 457f7eff60eSRob Clark fb->funcs->destroy(fb); 458f7eff60eSRob Clark } 459f7eff60eSRob Clark 4602b677e8cSDaniel Vetter static struct drm_framebuffer *__drm_framebuffer_lookup(struct drm_device *dev, 4612b677e8cSDaniel Vetter uint32_t id) 4622b677e8cSDaniel Vetter { 4632b677e8cSDaniel Vetter struct drm_mode_object *obj = NULL; 4642b677e8cSDaniel Vetter struct drm_framebuffer *fb; 4652b677e8cSDaniel Vetter 4662b677e8cSDaniel Vetter mutex_lock(&dev->mode_config.idr_mutex); 4672b677e8cSDaniel Vetter obj = idr_find(&dev->mode_config.crtc_idr, id); 4682b677e8cSDaniel Vetter if (!obj || (obj->type != DRM_MODE_OBJECT_FB) || (obj->id != id)) 4692b677e8cSDaniel Vetter fb = NULL; 4702b677e8cSDaniel Vetter else 4712b677e8cSDaniel Vetter fb = obj_to_fb(obj); 4722b677e8cSDaniel Vetter mutex_unlock(&dev->mode_config.idr_mutex); 4732b677e8cSDaniel Vetter 4742b677e8cSDaniel Vetter return fb; 4752b677e8cSDaniel Vetter } 4762b677e8cSDaniel Vetter 477f7eff60eSRob Clark /** 478786b99edSDaniel Vetter * drm_framebuffer_lookup - look up a drm framebuffer and grab a reference 479786b99edSDaniel Vetter * @dev: drm device 480786b99edSDaniel Vetter * @id: id of the fb object 481786b99edSDaniel Vetter * 482786b99edSDaniel Vetter * If successful, this grabs an additional reference to the framebuffer - 483786b99edSDaniel Vetter * callers need to make sure to eventually unreference the returned framebuffer 484c8e32cc1SDaniel Vetter * again, using @drm_framebuffer_unreference. 485786b99edSDaniel Vetter */ 486786b99edSDaniel Vetter struct drm_framebuffer *drm_framebuffer_lookup(struct drm_device *dev, 487786b99edSDaniel Vetter uint32_t id) 488786b99edSDaniel Vetter { 489786b99edSDaniel Vetter struct drm_framebuffer *fb; 490786b99edSDaniel Vetter 491786b99edSDaniel Vetter mutex_lock(&dev->mode_config.fb_lock); 4922b677e8cSDaniel Vetter fb = __drm_framebuffer_lookup(dev, id); 49383f45fc3SDaniel Vetter if (fb) { 49483f45fc3SDaniel Vetter if (!kref_get_unless_zero(&fb->refcount)) 49583f45fc3SDaniel Vetter fb = NULL; 49683f45fc3SDaniel Vetter } 497786b99edSDaniel Vetter mutex_unlock(&dev->mode_config.fb_lock); 498786b99edSDaniel Vetter 499786b99edSDaniel Vetter return fb; 500786b99edSDaniel Vetter } 501786b99edSDaniel Vetter EXPORT_SYMBOL(drm_framebuffer_lookup); 502786b99edSDaniel Vetter 503786b99edSDaniel Vetter /** 504f7eff60eSRob Clark * drm_framebuffer_unreference - unref a framebuffer 505065a50edSDaniel Vetter * @fb: framebuffer to unref 506065a50edSDaniel Vetter * 507065a50edSDaniel Vetter * This functions decrements the fb's refcount and frees it if it drops to zero. 508f7eff60eSRob Clark */ 509f7eff60eSRob Clark void drm_framebuffer_unreference(struct drm_framebuffer *fb) 510f7eff60eSRob Clark { 5118291272aSRob Clark DRM_DEBUG("%p: FB ID: %d (%d)\n", fb, fb->base.id, atomic_read(&fb->refcount.refcount)); 512f7eff60eSRob Clark kref_put(&fb->refcount, drm_framebuffer_free); 513f7eff60eSRob Clark } 514f7eff60eSRob Clark EXPORT_SYMBOL(drm_framebuffer_unreference); 515f7eff60eSRob Clark 516f7eff60eSRob Clark /** 517f7eff60eSRob Clark * drm_framebuffer_reference - incr the fb refcnt 518065a50edSDaniel Vetter * @fb: framebuffer 519c8e32cc1SDaniel Vetter * 520c8e32cc1SDaniel Vetter * This functions increments the fb's refcount. 521f7eff60eSRob Clark */ 522f7eff60eSRob Clark void drm_framebuffer_reference(struct drm_framebuffer *fb) 523f7eff60eSRob Clark { 5248291272aSRob Clark DRM_DEBUG("%p: FB ID: %d (%d)\n", fb, fb->base.id, atomic_read(&fb->refcount.refcount)); 525f7eff60eSRob Clark kref_get(&fb->refcount); 526f7eff60eSRob Clark } 527f7eff60eSRob Clark EXPORT_SYMBOL(drm_framebuffer_reference); 528f7eff60eSRob Clark 529f453ba04SDave Airlie /** 53036206361SDaniel Vetter * drm_framebuffer_unregister_private - unregister a private fb from the lookup idr 53136206361SDaniel Vetter * @fb: fb to unregister 53236206361SDaniel Vetter * 53336206361SDaniel Vetter * Drivers need to call this when cleaning up driver-private framebuffers, e.g. 53436206361SDaniel Vetter * those used for fbdev. Note that the caller must hold a reference of it's own, 53536206361SDaniel Vetter * i.e. the object may not be destroyed through this call (since it'll lead to a 53636206361SDaniel Vetter * locking inversion). 53736206361SDaniel Vetter */ 53836206361SDaniel Vetter void drm_framebuffer_unregister_private(struct drm_framebuffer *fb) 53936206361SDaniel Vetter { 540a39a357cSDaniel Vetter struct drm_device *dev; 541a39a357cSDaniel Vetter 542a39a357cSDaniel Vetter if (!fb) 543a39a357cSDaniel Vetter return; 544a39a357cSDaniel Vetter 545a39a357cSDaniel Vetter dev = fb->dev; 5462b677e8cSDaniel Vetter 5472b677e8cSDaniel Vetter mutex_lock(&dev->mode_config.fb_lock); 5482b677e8cSDaniel Vetter /* Mark fb as reaped and drop idr ref. */ 5492b677e8cSDaniel Vetter __drm_framebuffer_unregister(dev, fb); 5502b677e8cSDaniel Vetter mutex_unlock(&dev->mode_config.fb_lock); 55136206361SDaniel Vetter } 55236206361SDaniel Vetter EXPORT_SYMBOL(drm_framebuffer_unregister_private); 55336206361SDaniel Vetter 55436206361SDaniel Vetter /** 555f453ba04SDave Airlie * drm_framebuffer_cleanup - remove a framebuffer object 556f453ba04SDave Airlie * @fb: framebuffer to remove 557f453ba04SDave Airlie * 558c8e32cc1SDaniel Vetter * Cleanup framebuffer. This function is intended to be used from the drivers 559c8e32cc1SDaniel Vetter * ->destroy callback. It can also be used to clean up driver private 560c8e32cc1SDaniel Vetter * framebuffers embedded into a larger structure. 56136206361SDaniel Vetter * 56236206361SDaniel Vetter * Note that this function does not remove the fb from active usuage - if it is 56336206361SDaniel Vetter * still used anywhere, hilarity can ensue since userspace could call getfb on 56436206361SDaniel Vetter * the id and get back -EINVAL. Obviously no concern at driver unload time. 56536206361SDaniel Vetter * 56636206361SDaniel Vetter * Also, the framebuffer will not be removed from the lookup idr - for 56736206361SDaniel Vetter * user-created framebuffers this will happen in in the rmfb ioctl. For 56836206361SDaniel Vetter * driver-private objects (e.g. for fbdev) drivers need to explicitly call 56936206361SDaniel Vetter * drm_framebuffer_unregister_private. 570f453ba04SDave Airlie */ 571f453ba04SDave Airlie void drm_framebuffer_cleanup(struct drm_framebuffer *fb) 572f453ba04SDave Airlie { 573f453ba04SDave Airlie struct drm_device *dev = fb->dev; 5748faf6b18SDaniel Vetter 5754b096ac1SDaniel Vetter mutex_lock(&dev->mode_config.fb_lock); 576f7eff60eSRob Clark list_del(&fb->head); 577f7eff60eSRob Clark dev->mode_config.num_fb--; 5784b096ac1SDaniel Vetter mutex_unlock(&dev->mode_config.fb_lock); 579f7eff60eSRob Clark } 580f7eff60eSRob Clark EXPORT_SYMBOL(drm_framebuffer_cleanup); 581f7eff60eSRob Clark 582f7eff60eSRob Clark /** 583f7eff60eSRob Clark * drm_framebuffer_remove - remove and unreference a framebuffer object 584f7eff60eSRob Clark * @fb: framebuffer to remove 585f7eff60eSRob Clark * 586f7eff60eSRob Clark * Scans all the CRTCs and planes in @dev's mode_config. If they're 58736206361SDaniel Vetter * using @fb, removes it, setting it to NULL. Then drops the reference to the 588b62584e3SDaniel Vetter * passed-in framebuffer. Might take the modeset locks. 589b62584e3SDaniel Vetter * 590b62584e3SDaniel Vetter * Note that this function optimizes the cleanup away if the caller holds the 591b62584e3SDaniel Vetter * last reference to the framebuffer. It is also guaranteed to not take the 592b62584e3SDaniel Vetter * modeset locks in this case. 593f7eff60eSRob Clark */ 594f7eff60eSRob Clark void drm_framebuffer_remove(struct drm_framebuffer *fb) 595f7eff60eSRob Clark { 596a39a357cSDaniel Vetter struct drm_device *dev; 597f453ba04SDave Airlie struct drm_crtc *crtc; 5988cf5c917SJesse Barnes struct drm_plane *plane; 5995ef5f72fSDave Airlie struct drm_mode_set set; 6005ef5f72fSDave Airlie int ret; 601f453ba04SDave Airlie 602a39a357cSDaniel Vetter if (!fb) 603a39a357cSDaniel Vetter return; 604a39a357cSDaniel Vetter 605a39a357cSDaniel Vetter dev = fb->dev; 606a39a357cSDaniel Vetter 6074b096ac1SDaniel Vetter WARN_ON(!list_empty(&fb->filp_head)); 6088faf6b18SDaniel Vetter 609b62584e3SDaniel Vetter /* 610b62584e3SDaniel Vetter * drm ABI mandates that we remove any deleted framebuffers from active 611b62584e3SDaniel Vetter * useage. But since most sane clients only remove framebuffers they no 612b62584e3SDaniel Vetter * longer need, try to optimize this away. 613b62584e3SDaniel Vetter * 614b62584e3SDaniel Vetter * Since we're holding a reference ourselves, observing a refcount of 1 615b62584e3SDaniel Vetter * means that we're the last holder and can skip it. Also, the refcount 616b62584e3SDaniel Vetter * can never increase from 1 again, so we don't need any barriers or 617b62584e3SDaniel Vetter * locks. 618b62584e3SDaniel Vetter * 619b62584e3SDaniel Vetter * Note that userspace could try to race with use and instate a new 620b62584e3SDaniel Vetter * usage _after_ we've cleared all current ones. End result will be an 621b62584e3SDaniel Vetter * in-use fb with fb-id == 0. Userspace is allowed to shoot its own foot 622b62584e3SDaniel Vetter * in this manner. 623b62584e3SDaniel Vetter */ 624b62584e3SDaniel Vetter if (atomic_read(&fb->refcount.refcount) > 1) { 625b62584e3SDaniel Vetter drm_modeset_lock_all(dev); 626f453ba04SDave Airlie /* remove from any CRTC */ 6276295d607SDaniel Vetter drm_for_each_crtc(crtc, dev) { 628f4510a27SMatt Roper if (crtc->primary->fb == fb) { 6295ef5f72fSDave Airlie /* should turn off the crtc */ 6305ef5f72fSDave Airlie memset(&set, 0, sizeof(struct drm_mode_set)); 6315ef5f72fSDave Airlie set.crtc = crtc; 6325ef5f72fSDave Airlie set.fb = NULL; 6332d13b679SDaniel Vetter ret = drm_mode_set_config_internal(&set); 6345ef5f72fSDave Airlie if (ret) 6355ef5f72fSDave Airlie DRM_ERROR("failed to reset crtc %p when fb was deleted\n", crtc); 6365ef5f72fSDave Airlie } 637f453ba04SDave Airlie } 638f453ba04SDave Airlie 6396295d607SDaniel Vetter drm_for_each_plane(plane, dev) { 6409125e618SVille Syrjälä if (plane->fb == fb) 6419125e618SVille Syrjälä drm_plane_force_disable(plane); 6428cf5c917SJesse Barnes } 643b62584e3SDaniel Vetter drm_modeset_unlock_all(dev); 644b62584e3SDaniel Vetter } 6458cf5c917SJesse Barnes 646f7eff60eSRob Clark drm_framebuffer_unreference(fb); 647f453ba04SDave Airlie } 648f7eff60eSRob Clark EXPORT_SYMBOL(drm_framebuffer_remove); 649f453ba04SDave Airlie 65051fd371bSRob Clark DEFINE_WW_CLASS(crtc_ww_class); 65151fd371bSRob Clark 652f453ba04SDave Airlie /** 653e13161afSMatt Roper * drm_crtc_init_with_planes - Initialise a new CRTC object with 654e13161afSMatt Roper * specified primary and cursor planes. 655f453ba04SDave Airlie * @dev: DRM device 656f453ba04SDave Airlie * @crtc: CRTC object to init 657e13161afSMatt Roper * @primary: Primary plane for CRTC 658e13161afSMatt Roper * @cursor: Cursor plane for CRTC 659f453ba04SDave Airlie * @funcs: callbacks for the new CRTC 660f453ba04SDave Airlie * 661ad6f5c34SVille Syrjälä * Inits a new object created as base part of a driver crtc object. 6626bfc56aaSVille Syrjälä * 663c8e32cc1SDaniel Vetter * Returns: 6646bfc56aaSVille Syrjälä * Zero on success, error code on failure. 665f453ba04SDave Airlie */ 666e13161afSMatt Roper int drm_crtc_init_with_planes(struct drm_device *dev, struct drm_crtc *crtc, 667e13161afSMatt Roper struct drm_plane *primary, 668fc1d3e44SMatt Roper struct drm_plane *cursor, 669f453ba04SDave Airlie const struct drm_crtc_funcs *funcs) 670f453ba04SDave Airlie { 67151fd371bSRob Clark struct drm_mode_config *config = &dev->mode_config; 6726bfc56aaSVille Syrjälä int ret; 6736bfc56aaSVille Syrjälä 674522cf91fSBenjamin Gaignard WARN_ON(primary && primary->type != DRM_PLANE_TYPE_PRIMARY); 675522cf91fSBenjamin Gaignard WARN_ON(cursor && cursor->type != DRM_PLANE_TYPE_CURSOR); 676522cf91fSBenjamin Gaignard 677f453ba04SDave Airlie crtc->dev = dev; 678f453ba04SDave Airlie crtc->funcs = funcs; 679f453ba04SDave Airlie 68051fd371bSRob Clark drm_modeset_lock_init(&crtc->mutex); 6816bfc56aaSVille Syrjälä ret = drm_mode_object_get(dev, &crtc->base, DRM_MODE_OBJECT_CRTC); 6826bfc56aaSVille Syrjälä if (ret) 683baf698b0SDaniel Vetter return ret; 684f453ba04SDave Airlie 685bffd9de0SPaulo Zanoni crtc->base.properties = &crtc->properties; 686bffd9de0SPaulo Zanoni 68751fd371bSRob Clark list_add_tail(&crtc->head, &config->crtc_list); 68851fd371bSRob Clark config->num_crtc++; 6896bfc56aaSVille Syrjälä 690e13161afSMatt Roper crtc->primary = primary; 691fc1d3e44SMatt Roper crtc->cursor = cursor; 692e13161afSMatt Roper if (primary) 693e13161afSMatt Roper primary->possible_crtcs = 1 << drm_crtc_index(crtc); 694fc1d3e44SMatt Roper if (cursor) 695fc1d3e44SMatt Roper cursor->possible_crtcs = 1 << drm_crtc_index(crtc); 696e13161afSMatt Roper 697eab3bbefSDaniel Vetter if (drm_core_check_feature(dev, DRIVER_ATOMIC)) { 698eab3bbefSDaniel Vetter drm_object_attach_property(&crtc->base, config->prop_active, 0); 699955f3c33SDaniel Stone drm_object_attach_property(&crtc->base, config->prop_mode_id, 0); 700eab3bbefSDaniel Vetter } 701eab3bbefSDaniel Vetter 702baf698b0SDaniel Vetter return 0; 703f453ba04SDave Airlie } 704e13161afSMatt Roper EXPORT_SYMBOL(drm_crtc_init_with_planes); 705f453ba04SDave Airlie 706f453ba04SDave Airlie /** 707ad6f5c34SVille Syrjälä * drm_crtc_cleanup - Clean up the core crtc usage 708f453ba04SDave Airlie * @crtc: CRTC to cleanup 709f453ba04SDave Airlie * 710ad6f5c34SVille Syrjälä * This function cleans up @crtc and removes it from the DRM mode setting 711ad6f5c34SVille Syrjälä * core. Note that the function does *not* free the crtc structure itself, 712ad6f5c34SVille Syrjälä * this is the responsibility of the caller. 713f453ba04SDave Airlie */ 714f453ba04SDave Airlie void drm_crtc_cleanup(struct drm_crtc *crtc) 715f453ba04SDave Airlie { 716f453ba04SDave Airlie struct drm_device *dev = crtc->dev; 717f453ba04SDave Airlie 718f453ba04SDave Airlie kfree(crtc->gamma_store); 719f453ba04SDave Airlie crtc->gamma_store = NULL; 720f453ba04SDave Airlie 72151fd371bSRob Clark drm_modeset_lock_fini(&crtc->mutex); 72251fd371bSRob Clark 723f453ba04SDave Airlie drm_mode_object_put(dev, &crtc->base); 724f453ba04SDave Airlie list_del(&crtc->head); 725f453ba04SDave Airlie dev->mode_config.num_crtc--; 7263009c037SThierry Reding 7273009c037SThierry Reding WARN_ON(crtc->state && !crtc->funcs->atomic_destroy_state); 7283009c037SThierry Reding if (crtc->state && crtc->funcs->atomic_destroy_state) 7293009c037SThierry Reding crtc->funcs->atomic_destroy_state(crtc, crtc->state); 730a18c0af1SThierry Reding 731a18c0af1SThierry Reding memset(crtc, 0, sizeof(*crtc)); 732f453ba04SDave Airlie } 733f453ba04SDave Airlie EXPORT_SYMBOL(drm_crtc_cleanup); 734f453ba04SDave Airlie 735f453ba04SDave Airlie /** 736db5f7a6eSRussell King * drm_crtc_index - find the index of a registered CRTC 737db5f7a6eSRussell King * @crtc: CRTC to find index for 738db5f7a6eSRussell King * 739db5f7a6eSRussell King * Given a registered CRTC, return the index of that CRTC within a DRM 740db5f7a6eSRussell King * device's list of CRTCs. 741db5f7a6eSRussell King */ 742db5f7a6eSRussell King unsigned int drm_crtc_index(struct drm_crtc *crtc) 743db5f7a6eSRussell King { 744db5f7a6eSRussell King unsigned int index = 0; 745db5f7a6eSRussell King struct drm_crtc *tmp; 746db5f7a6eSRussell King 747e4f62546SDaniel Vetter drm_for_each_crtc(tmp, crtc->dev) { 748db5f7a6eSRussell King if (tmp == crtc) 749db5f7a6eSRussell King return index; 750db5f7a6eSRussell King 751db5f7a6eSRussell King index++; 752db5f7a6eSRussell King } 753db5f7a6eSRussell King 754db5f7a6eSRussell King BUG(); 755db5f7a6eSRussell King } 756db5f7a6eSRussell King EXPORT_SYMBOL(drm_crtc_index); 757db5f7a6eSRussell King 75886f422d5SLespiau, Damien /* 759f453ba04SDave Airlie * drm_mode_remove - remove and free a mode 760f453ba04SDave Airlie * @connector: connector list to modify 761f453ba04SDave Airlie * @mode: mode to remove 762f453ba04SDave Airlie * 763f453ba04SDave Airlie * Remove @mode from @connector's mode list, then free it. 764f453ba04SDave Airlie */ 76586f422d5SLespiau, Damien static void drm_mode_remove(struct drm_connector *connector, 766f453ba04SDave Airlie struct drm_display_mode *mode) 767f453ba04SDave Airlie { 768f453ba04SDave Airlie list_del(&mode->head); 769554f1d78SSascha Hauer drm_mode_destroy(connector->dev, mode); 770f453ba04SDave Airlie } 771f453ba04SDave Airlie 772f453ba04SDave Airlie /** 773b5571e9dSBoris Brezillon * drm_display_info_set_bus_formats - set the supported bus formats 774b5571e9dSBoris Brezillon * @info: display info to store bus formats in 775e37bfa1aSBoris Brezillon * @formats: array containing the supported bus formats 776e37bfa1aSBoris Brezillon * @num_formats: the number of entries in the fmts array 777b5571e9dSBoris Brezillon * 778b5571e9dSBoris Brezillon * Store the supported bus formats in display info structure. 779b5571e9dSBoris Brezillon * See MEDIA_BUS_FMT_* definitions in include/uapi/linux/media-bus-format.h for 780b5571e9dSBoris Brezillon * a full list of available formats. 781b5571e9dSBoris Brezillon */ 782b5571e9dSBoris Brezillon int drm_display_info_set_bus_formats(struct drm_display_info *info, 783b5571e9dSBoris Brezillon const u32 *formats, 784b5571e9dSBoris Brezillon unsigned int num_formats) 785b5571e9dSBoris Brezillon { 786b5571e9dSBoris Brezillon u32 *fmts = NULL; 787b5571e9dSBoris Brezillon 788b5571e9dSBoris Brezillon if (!formats && num_formats) 789b5571e9dSBoris Brezillon return -EINVAL; 790b5571e9dSBoris Brezillon 791b5571e9dSBoris Brezillon if (formats && num_formats) { 792b5571e9dSBoris Brezillon fmts = kmemdup(formats, sizeof(*formats) * num_formats, 793b5571e9dSBoris Brezillon GFP_KERNEL); 794944579c5SDan Carpenter if (!fmts) 795b5571e9dSBoris Brezillon return -ENOMEM; 796b5571e9dSBoris Brezillon } 797b5571e9dSBoris Brezillon 798b5571e9dSBoris Brezillon kfree(info->bus_formats); 799b5571e9dSBoris Brezillon info->bus_formats = fmts; 800b5571e9dSBoris Brezillon info->num_bus_formats = num_formats; 801b5571e9dSBoris Brezillon 802b5571e9dSBoris Brezillon return 0; 803b5571e9dSBoris Brezillon } 804b5571e9dSBoris Brezillon EXPORT_SYMBOL(drm_display_info_set_bus_formats); 805b5571e9dSBoris Brezillon 806b5571e9dSBoris Brezillon /** 807eaf99c74SChris Wilson * drm_connector_get_cmdline_mode - reads the user's cmdline mode 808eaf99c74SChris Wilson * @connector: connector to quwery 809eaf99c74SChris Wilson * 810eaf99c74SChris Wilson * The kernel supports per-connector configration of its consoles through 811eaf99c74SChris Wilson * use of the video= parameter. This function parses that option and 812eaf99c74SChris Wilson * extracts the user's specified mode (or enable/disable status) for a 813eaf99c74SChris Wilson * particular connector. This is typically only used during the early fbdev 814eaf99c74SChris Wilson * setup. 815eaf99c74SChris Wilson */ 816eaf99c74SChris Wilson static void drm_connector_get_cmdline_mode(struct drm_connector *connector) 817eaf99c74SChris Wilson { 818eaf99c74SChris Wilson struct drm_cmdline_mode *mode = &connector->cmdline_mode; 819eaf99c74SChris Wilson char *option = NULL; 820eaf99c74SChris Wilson 821eaf99c74SChris Wilson if (fb_get_options(connector->name, &option)) 822eaf99c74SChris Wilson return; 823eaf99c74SChris Wilson 824eaf99c74SChris Wilson if (!drm_mode_parse_command_line_for_connector(option, 825eaf99c74SChris Wilson connector, 826eaf99c74SChris Wilson mode)) 827eaf99c74SChris Wilson return; 828eaf99c74SChris Wilson 829eaf99c74SChris Wilson if (mode->force) { 830eaf99c74SChris Wilson const char *s; 831eaf99c74SChris Wilson 832eaf99c74SChris Wilson switch (mode->force) { 833eaf99c74SChris Wilson case DRM_FORCE_OFF: 834eaf99c74SChris Wilson s = "OFF"; 835eaf99c74SChris Wilson break; 836eaf99c74SChris Wilson case DRM_FORCE_ON_DIGITAL: 837eaf99c74SChris Wilson s = "ON - dig"; 838eaf99c74SChris Wilson break; 839eaf99c74SChris Wilson default: 840eaf99c74SChris Wilson case DRM_FORCE_ON: 841eaf99c74SChris Wilson s = "ON"; 842eaf99c74SChris Wilson break; 843eaf99c74SChris Wilson } 844eaf99c74SChris Wilson 845eaf99c74SChris Wilson DRM_INFO("forcing %s connector %s\n", connector->name, s); 846eaf99c74SChris Wilson connector->force = mode->force; 847eaf99c74SChris Wilson } 848eaf99c74SChris Wilson 849eaf99c74SChris Wilson DRM_DEBUG_KMS("cmdline mode for connector %s %dx%d@%dHz%s%s%s\n", 850eaf99c74SChris Wilson connector->name, 851eaf99c74SChris Wilson mode->xres, mode->yres, 852eaf99c74SChris Wilson mode->refresh_specified ? mode->refresh : 60, 853eaf99c74SChris Wilson mode->rb ? " reduced blanking" : "", 854eaf99c74SChris Wilson mode->margins ? " with margins" : "", 855eaf99c74SChris Wilson mode->interlace ? " interlaced" : ""); 856eaf99c74SChris Wilson } 857eaf99c74SChris Wilson 858eaf99c74SChris Wilson /** 859f453ba04SDave Airlie * drm_connector_init - Init a preallocated connector 860f453ba04SDave Airlie * @dev: DRM device 861f453ba04SDave Airlie * @connector: the connector to init 862f453ba04SDave Airlie * @funcs: callbacks for this connector 863065a50edSDaniel Vetter * @connector_type: user visible type of the connector 864f453ba04SDave Airlie * 865f453ba04SDave Airlie * Initialises a preallocated connector. Connectors should be 866f453ba04SDave Airlie * subclassed as part of driver connector objects. 8676bfc56aaSVille Syrjälä * 868c8e32cc1SDaniel Vetter * Returns: 8696bfc56aaSVille Syrjälä * Zero on success, error code on failure. 870f453ba04SDave Airlie */ 8716bfc56aaSVille Syrjälä int drm_connector_init(struct drm_device *dev, 872f453ba04SDave Airlie struct drm_connector *connector, 873f453ba04SDave Airlie const struct drm_connector_funcs *funcs, 874f453ba04SDave Airlie int connector_type) 875f453ba04SDave Airlie { 876ae16c597SRob Clark struct drm_mode_config *config = &dev->mode_config; 8776bfc56aaSVille Syrjälä int ret; 878b21e3afeSIlia Mirkin struct ida *connector_ida = 879b21e3afeSIlia Mirkin &drm_connector_enum_list[connector_type].ida; 8806bfc56aaSVille Syrjälä 88184849903SDaniel Vetter drm_modeset_lock_all(dev); 882f453ba04SDave Airlie 8832ee39452SDave Airlie ret = drm_mode_object_get_reg(dev, &connector->base, DRM_MODE_OBJECT_CONNECTOR, false); 8846bfc56aaSVille Syrjälä if (ret) 8852abdd313SJani Nikula goto out_unlock; 8866bfc56aaSVille Syrjälä 8877e3bdf4aSPaulo Zanoni connector->base.properties = &connector->properties; 888f453ba04SDave Airlie connector->dev = dev; 889f453ba04SDave Airlie connector->funcs = funcs; 890f453ba04SDave Airlie connector->connector_type = connector_type; 891f453ba04SDave Airlie connector->connector_type_id = 892b21e3afeSIlia Mirkin ida_simple_get(connector_ida, 1, 0, GFP_KERNEL); 893b21e3afeSIlia Mirkin if (connector->connector_type_id < 0) { 894b21e3afeSIlia Mirkin ret = connector->connector_type_id; 8952abdd313SJani Nikula goto out_put; 896b21e3afeSIlia Mirkin } 8972abdd313SJani Nikula connector->name = 8982abdd313SJani Nikula kasprintf(GFP_KERNEL, "%s-%d", 8992abdd313SJani Nikula drm_connector_enum_list[connector_type].name, 9002abdd313SJani Nikula connector->connector_type_id); 9012abdd313SJani Nikula if (!connector->name) { 9022abdd313SJani Nikula ret = -ENOMEM; 9032abdd313SJani Nikula goto out_put; 9042abdd313SJani Nikula } 9052abdd313SJani Nikula 906f453ba04SDave Airlie INIT_LIST_HEAD(&connector->probed_modes); 907f453ba04SDave Airlie INIT_LIST_HEAD(&connector->modes); 908f453ba04SDave Airlie connector->edid_blob_ptr = NULL; 9095e2cb2f6SDaniel Vetter connector->status = connector_status_unknown; 910f453ba04SDave Airlie 911eaf99c74SChris Wilson drm_connector_get_cmdline_mode(connector); 912eaf99c74SChris Wilson 913c7eb76f4SDaniel Vetter /* We should add connectors at the end to avoid upsetting the connector 914c7eb76f4SDaniel Vetter * index too much. */ 915ae16c597SRob Clark list_add_tail(&connector->head, &config->connector_list); 916ae16c597SRob Clark config->num_connector++; 917f453ba04SDave Airlie 918a7331e5cSThomas Hellstrom if (connector_type != DRM_MODE_CONNECTOR_VIRTUAL) 91958495563SRob Clark drm_object_attach_property(&connector->base, 920ae16c597SRob Clark config->edid_property, 921a7331e5cSThomas Hellstrom 0); 922f453ba04SDave Airlie 92358495563SRob Clark drm_object_attach_property(&connector->base, 924ae16c597SRob Clark config->dpms_property, 0); 925ae16c597SRob Clark 926ae16c597SRob Clark if (drm_core_check_feature(dev, DRIVER_ATOMIC)) { 927ae16c597SRob Clark drm_object_attach_property(&connector->base, config->prop_crtc_id, 0); 928ae16c597SRob Clark } 929f453ba04SDave Airlie 93030f65707SThomas Wood connector->debugfs_entry = NULL; 93130f65707SThomas Wood 9322abdd313SJani Nikula out_put: 9332abdd313SJani Nikula if (ret) 9342abdd313SJani Nikula drm_mode_object_put(dev, &connector->base); 9352abdd313SJani Nikula 9362abdd313SJani Nikula out_unlock: 93784849903SDaniel Vetter drm_modeset_unlock_all(dev); 9386bfc56aaSVille Syrjälä 9396bfc56aaSVille Syrjälä return ret; 940f453ba04SDave Airlie } 941f453ba04SDave Airlie EXPORT_SYMBOL(drm_connector_init); 942f453ba04SDave Airlie 943f453ba04SDave Airlie /** 944f453ba04SDave Airlie * drm_connector_cleanup - cleans up an initialised connector 945f453ba04SDave Airlie * @connector: connector to cleanup 946f453ba04SDave Airlie * 947f453ba04SDave Airlie * Cleans up the connector but doesn't free the object. 948f453ba04SDave Airlie */ 949f453ba04SDave Airlie void drm_connector_cleanup(struct drm_connector *connector) 950f453ba04SDave Airlie { 951f453ba04SDave Airlie struct drm_device *dev = connector->dev; 952f453ba04SDave Airlie struct drm_display_mode *mode, *t; 953f453ba04SDave Airlie 95440d9b043SDave Airlie if (connector->tile_group) { 95540d9b043SDave Airlie drm_mode_put_tile_group(dev, connector->tile_group); 95640d9b043SDave Airlie connector->tile_group = NULL; 95740d9b043SDave Airlie } 95840d9b043SDave Airlie 959f453ba04SDave Airlie list_for_each_entry_safe(mode, t, &connector->probed_modes, head) 960f453ba04SDave Airlie drm_mode_remove(connector, mode); 961f453ba04SDave Airlie 962f453ba04SDave Airlie list_for_each_entry_safe(mode, t, &connector->modes, head) 963f453ba04SDave Airlie drm_mode_remove(connector, mode); 964f453ba04SDave Airlie 965b21e3afeSIlia Mirkin ida_remove(&drm_connector_enum_list[connector->connector_type].ida, 966b21e3afeSIlia Mirkin connector->connector_type_id); 967b21e3afeSIlia Mirkin 968b5571e9dSBoris Brezillon kfree(connector->display_info.bus_formats); 969f453ba04SDave Airlie drm_mode_object_put(dev, &connector->base); 9702abdd313SJani Nikula kfree(connector->name); 9712abdd313SJani Nikula connector->name = NULL; 972f453ba04SDave Airlie list_del(&connector->head); 9736380c509SJoonyoung Shim dev->mode_config.num_connector--; 9743009c037SThierry Reding 9753009c037SThierry Reding WARN_ON(connector->state && !connector->funcs->atomic_destroy_state); 9763009c037SThierry Reding if (connector->state && connector->funcs->atomic_destroy_state) 9773009c037SThierry Reding connector->funcs->atomic_destroy_state(connector, 9783009c037SThierry Reding connector->state); 979a18c0af1SThierry Reding 980a18c0af1SThierry Reding memset(connector, 0, sizeof(*connector)); 981f453ba04SDave Airlie } 982f453ba04SDave Airlie EXPORT_SYMBOL(drm_connector_cleanup); 983f453ba04SDave Airlie 984c8e32cc1SDaniel Vetter /** 98510f637bfSDaniel Vetter * drm_connector_index - find the index of a registered connector 98610f637bfSDaniel Vetter * @connector: connector to find index for 98710f637bfSDaniel Vetter * 98810f637bfSDaniel Vetter * Given a registered connector, return the index of that connector within a DRM 98910f637bfSDaniel Vetter * device's list of connectors. 99010f637bfSDaniel Vetter */ 99110f637bfSDaniel Vetter unsigned int drm_connector_index(struct drm_connector *connector) 99210f637bfSDaniel Vetter { 99310f637bfSDaniel Vetter unsigned int index = 0; 99410f637bfSDaniel Vetter struct drm_connector *tmp; 995c7eb76f4SDaniel Vetter struct drm_mode_config *config = &connector->dev->mode_config; 996c7eb76f4SDaniel Vetter 997c7eb76f4SDaniel Vetter WARN_ON(!drm_modeset_is_locked(&config->connection_mutex)); 99810f637bfSDaniel Vetter 9999a9f5ce8SDaniel Vetter drm_for_each_connector(tmp, connector->dev) { 100010f637bfSDaniel Vetter if (tmp == connector) 100110f637bfSDaniel Vetter return index; 100210f637bfSDaniel Vetter 100310f637bfSDaniel Vetter index++; 100410f637bfSDaniel Vetter } 100510f637bfSDaniel Vetter 100610f637bfSDaniel Vetter BUG(); 100710f637bfSDaniel Vetter } 100810f637bfSDaniel Vetter EXPORT_SYMBOL(drm_connector_index); 100910f637bfSDaniel Vetter 101010f637bfSDaniel Vetter /** 101134ea3d38SThomas Wood * drm_connector_register - register a connector 101234ea3d38SThomas Wood * @connector: the connector to register 101334ea3d38SThomas Wood * 101434ea3d38SThomas Wood * Register userspace interfaces for a connector 101534ea3d38SThomas Wood * 101634ea3d38SThomas Wood * Returns: 101734ea3d38SThomas Wood * Zero on success, error code on failure. 101834ea3d38SThomas Wood */ 101934ea3d38SThomas Wood int drm_connector_register(struct drm_connector *connector) 102034ea3d38SThomas Wood { 102130f65707SThomas Wood int ret; 102230f65707SThomas Wood 10232ee39452SDave Airlie drm_mode_object_register(connector->dev, &connector->base); 10242ee39452SDave Airlie 102530f65707SThomas Wood ret = drm_sysfs_connector_add(connector); 102630f65707SThomas Wood if (ret) 102730f65707SThomas Wood return ret; 102830f65707SThomas Wood 102930f65707SThomas Wood ret = drm_debugfs_connector_add(connector); 103030f65707SThomas Wood if (ret) { 103130f65707SThomas Wood drm_sysfs_connector_remove(connector); 103230f65707SThomas Wood return ret; 103330f65707SThomas Wood } 103430f65707SThomas Wood 103530f65707SThomas Wood return 0; 103634ea3d38SThomas Wood } 103734ea3d38SThomas Wood EXPORT_SYMBOL(drm_connector_register); 103834ea3d38SThomas Wood 103934ea3d38SThomas Wood /** 104034ea3d38SThomas Wood * drm_connector_unregister - unregister a connector 104134ea3d38SThomas Wood * @connector: the connector to unregister 104234ea3d38SThomas Wood * 104334ea3d38SThomas Wood * Unregister userspace interfaces for a connector 104434ea3d38SThomas Wood */ 104534ea3d38SThomas Wood void drm_connector_unregister(struct drm_connector *connector) 104634ea3d38SThomas Wood { 104734ea3d38SThomas Wood drm_sysfs_connector_remove(connector); 104830f65707SThomas Wood drm_debugfs_connector_remove(connector); 104934ea3d38SThomas Wood } 105034ea3d38SThomas Wood EXPORT_SYMBOL(drm_connector_unregister); 105134ea3d38SThomas Wood 105234ea3d38SThomas Wood 105334ea3d38SThomas Wood /** 1054c8e32cc1SDaniel Vetter * drm_connector_unplug_all - unregister connector userspace interfaces 1055c8e32cc1SDaniel Vetter * @dev: drm device 1056c8e32cc1SDaniel Vetter * 1057c8e32cc1SDaniel Vetter * This function unregisters all connector userspace interfaces in sysfs. Should 1058c8e32cc1SDaniel Vetter * be call when the device is disconnected, e.g. from an usb driver's 1059c8e32cc1SDaniel Vetter * ->disconnect callback. 1060c8e32cc1SDaniel Vetter */ 1061cbc7e221SDave Airlie void drm_connector_unplug_all(struct drm_device *dev) 1062cbc7e221SDave Airlie { 1063cbc7e221SDave Airlie struct drm_connector *connector; 1064cbc7e221SDave Airlie 10659a9f5ce8SDaniel Vetter /* FIXME: taking the mode config mutex ends up in a clash with sysfs */ 1066cbc7e221SDave Airlie list_for_each_entry(connector, &dev->mode_config.connector_list, head) 106734ea3d38SThomas Wood drm_connector_unregister(connector); 1068cbc7e221SDave Airlie 1069cbc7e221SDave Airlie } 1070cbc7e221SDave Airlie EXPORT_SYMBOL(drm_connector_unplug_all); 1071cbc7e221SDave Airlie 1072c8e32cc1SDaniel Vetter /** 1073c8e32cc1SDaniel Vetter * drm_encoder_init - Init a preallocated encoder 1074c8e32cc1SDaniel Vetter * @dev: drm device 1075c8e32cc1SDaniel Vetter * @encoder: the encoder to init 1076c8e32cc1SDaniel Vetter * @funcs: callbacks for this encoder 1077c8e32cc1SDaniel Vetter * @encoder_type: user visible type of the encoder 1078c8e32cc1SDaniel Vetter * 1079c8e32cc1SDaniel Vetter * Initialises a preallocated encoder. Encoder should be 1080c8e32cc1SDaniel Vetter * subclassed as part of driver encoder objects. 1081c8e32cc1SDaniel Vetter * 1082c8e32cc1SDaniel Vetter * Returns: 1083c8e32cc1SDaniel Vetter * Zero on success, error code on failure. 1084c8e32cc1SDaniel Vetter */ 10856bfc56aaSVille Syrjälä int drm_encoder_init(struct drm_device *dev, 1086f453ba04SDave Airlie struct drm_encoder *encoder, 1087f453ba04SDave Airlie const struct drm_encoder_funcs *funcs, 1088f453ba04SDave Airlie int encoder_type) 1089f453ba04SDave Airlie { 10906bfc56aaSVille Syrjälä int ret; 10916bfc56aaSVille Syrjälä 109284849903SDaniel Vetter drm_modeset_lock_all(dev); 1093f453ba04SDave Airlie 10946bfc56aaSVille Syrjälä ret = drm_mode_object_get(dev, &encoder->base, DRM_MODE_OBJECT_ENCODER); 10956bfc56aaSVille Syrjälä if (ret) 1096e5748946SJani Nikula goto out_unlock; 1097f453ba04SDave Airlie 10986bfc56aaSVille Syrjälä encoder->dev = dev; 1099f453ba04SDave Airlie encoder->encoder_type = encoder_type; 1100f453ba04SDave Airlie encoder->funcs = funcs; 1101e5748946SJani Nikula encoder->name = kasprintf(GFP_KERNEL, "%s-%d", 1102e5748946SJani Nikula drm_encoder_enum_list[encoder_type].name, 1103e5748946SJani Nikula encoder->base.id); 1104e5748946SJani Nikula if (!encoder->name) { 1105e5748946SJani Nikula ret = -ENOMEM; 1106e5748946SJani Nikula goto out_put; 1107e5748946SJani Nikula } 1108f453ba04SDave Airlie 1109f453ba04SDave Airlie list_add_tail(&encoder->head, &dev->mode_config.encoder_list); 1110f453ba04SDave Airlie dev->mode_config.num_encoder++; 1111f453ba04SDave Airlie 1112e5748946SJani Nikula out_put: 1113e5748946SJani Nikula if (ret) 1114e5748946SJani Nikula drm_mode_object_put(dev, &encoder->base); 1115e5748946SJani Nikula 1116e5748946SJani Nikula out_unlock: 111784849903SDaniel Vetter drm_modeset_unlock_all(dev); 11186bfc56aaSVille Syrjälä 11196bfc56aaSVille Syrjälä return ret; 1120f453ba04SDave Airlie } 1121f453ba04SDave Airlie EXPORT_SYMBOL(drm_encoder_init); 1122f453ba04SDave Airlie 1123c8e32cc1SDaniel Vetter /** 1124c8e32cc1SDaniel Vetter * drm_encoder_cleanup - cleans up an initialised encoder 1125c8e32cc1SDaniel Vetter * @encoder: encoder to cleanup 1126c8e32cc1SDaniel Vetter * 1127c8e32cc1SDaniel Vetter * Cleans up the encoder but doesn't free the object. 1128c8e32cc1SDaniel Vetter */ 1129f453ba04SDave Airlie void drm_encoder_cleanup(struct drm_encoder *encoder) 1130f453ba04SDave Airlie { 1131f453ba04SDave Airlie struct drm_device *dev = encoder->dev; 11324dfd909fSThierry Reding 113384849903SDaniel Vetter drm_modeset_lock_all(dev); 1134f453ba04SDave Airlie drm_mode_object_put(dev, &encoder->base); 1135e5748946SJani Nikula kfree(encoder->name); 1136f453ba04SDave Airlie list_del(&encoder->head); 11376380c509SJoonyoung Shim dev->mode_config.num_encoder--; 113884849903SDaniel Vetter drm_modeset_unlock_all(dev); 1139a18c0af1SThierry Reding 1140a18c0af1SThierry Reding memset(encoder, 0, sizeof(*encoder)); 1141f453ba04SDave Airlie } 1142f453ba04SDave Airlie EXPORT_SYMBOL(drm_encoder_cleanup); 1143f453ba04SDave Airlie 114435f2c3aeSVille Syrjälä /** 1145dc415ff9SMatt Roper * drm_universal_plane_init - Initialize a new universal plane object 114635f2c3aeSVille Syrjälä * @dev: DRM device 114735f2c3aeSVille Syrjälä * @plane: plane object to init 114835f2c3aeSVille Syrjälä * @possible_crtcs: bitmask of possible CRTCs 114935f2c3aeSVille Syrjälä * @funcs: callbacks for the new plane 115035f2c3aeSVille Syrjälä * @formats: array of supported formats (%DRM_FORMAT_*) 115135f2c3aeSVille Syrjälä * @format_count: number of elements in @formats 1152dc415ff9SMatt Roper * @type: type of plane (overlay, primary, cursor) 115335f2c3aeSVille Syrjälä * 1154dc415ff9SMatt Roper * Initializes a plane object of type @type. 115535f2c3aeSVille Syrjälä * 1156c8e32cc1SDaniel Vetter * Returns: 115735f2c3aeSVille Syrjälä * Zero on success, error code on failure. 115835f2c3aeSVille Syrjälä */ 1159dc415ff9SMatt Roper int drm_universal_plane_init(struct drm_device *dev, struct drm_plane *plane, 11608cf5c917SJesse Barnes unsigned long possible_crtcs, 11618cf5c917SJesse Barnes const struct drm_plane_funcs *funcs, 116245e3743aSThierry Reding const uint32_t *formats, unsigned int format_count, 1163dc415ff9SMatt Roper enum drm_plane_type type) 11648cf5c917SJesse Barnes { 11656b4959f4SRob Clark struct drm_mode_config *config = &dev->mode_config; 11666bfc56aaSVille Syrjälä int ret; 11676bfc56aaSVille Syrjälä 11686bfc56aaSVille Syrjälä ret = drm_mode_object_get(dev, &plane->base, DRM_MODE_OBJECT_PLANE); 11696bfc56aaSVille Syrjälä if (ret) 1170baf698b0SDaniel Vetter return ret; 11716bfc56aaSVille Syrjälä 11724d02e2deSDaniel Vetter drm_modeset_lock_init(&plane->mutex); 11734d02e2deSDaniel Vetter 11744d93914aSRob Clark plane->base.properties = &plane->properties; 11758cf5c917SJesse Barnes plane->dev = dev; 11768cf5c917SJesse Barnes plane->funcs = funcs; 11772f6c5389SThierry Reding plane->format_types = kmalloc_array(format_count, sizeof(uint32_t), 11788cf5c917SJesse Barnes GFP_KERNEL); 11798cf5c917SJesse Barnes if (!plane->format_types) { 11808cf5c917SJesse Barnes DRM_DEBUG_KMS("out of memory when allocating plane\n"); 11818cf5c917SJesse Barnes drm_mode_object_put(dev, &plane->base); 1182baf698b0SDaniel Vetter return -ENOMEM; 11838cf5c917SJesse Barnes } 11848cf5c917SJesse Barnes 1185308e5bcbSJesse Barnes memcpy(plane->format_types, formats, format_count * sizeof(uint32_t)); 11868cf5c917SJesse Barnes plane->format_count = format_count; 11878cf5c917SJesse Barnes plane->possible_crtcs = possible_crtcs; 1188dc415ff9SMatt Roper plane->type = type; 11898cf5c917SJesse Barnes 11906b4959f4SRob Clark list_add_tail(&plane->head, &config->plane_list); 11916b4959f4SRob Clark config->num_total_plane++; 1192e27dde3eSMatt Roper if (plane->type == DRM_PLANE_TYPE_OVERLAY) 11936b4959f4SRob Clark config->num_overlay_plane++; 11948cf5c917SJesse Barnes 11959922ab5aSRob Clark drm_object_attach_property(&plane->base, 11966b4959f4SRob Clark config->plane_type_property, 11979922ab5aSRob Clark plane->type); 11989922ab5aSRob Clark 11996b4959f4SRob Clark if (drm_core_check_feature(dev, DRIVER_ATOMIC)) { 12006b4959f4SRob Clark drm_object_attach_property(&plane->base, config->prop_fb_id, 0); 12016b4959f4SRob Clark drm_object_attach_property(&plane->base, config->prop_crtc_id, 0); 12026b4959f4SRob Clark drm_object_attach_property(&plane->base, config->prop_crtc_x, 0); 12036b4959f4SRob Clark drm_object_attach_property(&plane->base, config->prop_crtc_y, 0); 12046b4959f4SRob Clark drm_object_attach_property(&plane->base, config->prop_crtc_w, 0); 12056b4959f4SRob Clark drm_object_attach_property(&plane->base, config->prop_crtc_h, 0); 12066b4959f4SRob Clark drm_object_attach_property(&plane->base, config->prop_src_x, 0); 12076b4959f4SRob Clark drm_object_attach_property(&plane->base, config->prop_src_y, 0); 12086b4959f4SRob Clark drm_object_attach_property(&plane->base, config->prop_src_w, 0); 12096b4959f4SRob Clark drm_object_attach_property(&plane->base, config->prop_src_h, 0); 12106b4959f4SRob Clark } 12116b4959f4SRob Clark 1212baf698b0SDaniel Vetter return 0; 12138cf5c917SJesse Barnes } 1214dc415ff9SMatt Roper EXPORT_SYMBOL(drm_universal_plane_init); 1215dc415ff9SMatt Roper 1216dc415ff9SMatt Roper /** 1217dc415ff9SMatt Roper * drm_plane_init - Initialize a legacy plane 1218dc415ff9SMatt Roper * @dev: DRM device 1219dc415ff9SMatt Roper * @plane: plane object to init 1220dc415ff9SMatt Roper * @possible_crtcs: bitmask of possible CRTCs 1221dc415ff9SMatt Roper * @funcs: callbacks for the new plane 1222dc415ff9SMatt Roper * @formats: array of supported formats (%DRM_FORMAT_*) 1223dc415ff9SMatt Roper * @format_count: number of elements in @formats 1224dc415ff9SMatt Roper * @is_primary: plane type (primary vs overlay) 1225dc415ff9SMatt Roper * 1226dc415ff9SMatt Roper * Legacy API to initialize a DRM plane. 1227dc415ff9SMatt Roper * 1228dc415ff9SMatt Roper * New drivers should call drm_universal_plane_init() instead. 1229dc415ff9SMatt Roper * 1230dc415ff9SMatt Roper * Returns: 1231dc415ff9SMatt Roper * Zero on success, error code on failure. 1232dc415ff9SMatt Roper */ 1233dc415ff9SMatt Roper int drm_plane_init(struct drm_device *dev, struct drm_plane *plane, 1234dc415ff9SMatt Roper unsigned long possible_crtcs, 1235dc415ff9SMatt Roper const struct drm_plane_funcs *funcs, 123645e3743aSThierry Reding const uint32_t *formats, unsigned int format_count, 1237dc415ff9SMatt Roper bool is_primary) 1238dc415ff9SMatt Roper { 1239dc415ff9SMatt Roper enum drm_plane_type type; 1240dc415ff9SMatt Roper 1241dc415ff9SMatt Roper type = is_primary ? DRM_PLANE_TYPE_PRIMARY : DRM_PLANE_TYPE_OVERLAY; 1242dc415ff9SMatt Roper return drm_universal_plane_init(dev, plane, possible_crtcs, funcs, 1243dc415ff9SMatt Roper formats, format_count, type); 1244dc415ff9SMatt Roper } 12458cf5c917SJesse Barnes EXPORT_SYMBOL(drm_plane_init); 12468cf5c917SJesse Barnes 124735f2c3aeSVille Syrjälä /** 124835f2c3aeSVille Syrjälä * drm_plane_cleanup - Clean up the core plane usage 124935f2c3aeSVille Syrjälä * @plane: plane to cleanup 125035f2c3aeSVille Syrjälä * 125135f2c3aeSVille Syrjälä * This function cleans up @plane and removes it from the DRM mode setting 125235f2c3aeSVille Syrjälä * core. Note that the function does *not* free the plane structure itself, 125335f2c3aeSVille Syrjälä * this is the responsibility of the caller. 125435f2c3aeSVille Syrjälä */ 12558cf5c917SJesse Barnes void drm_plane_cleanup(struct drm_plane *plane) 12568cf5c917SJesse Barnes { 12578cf5c917SJesse Barnes struct drm_device *dev = plane->dev; 12588cf5c917SJesse Barnes 125984849903SDaniel Vetter drm_modeset_lock_all(dev); 12608cf5c917SJesse Barnes kfree(plane->format_types); 12618cf5c917SJesse Barnes drm_mode_object_put(dev, &plane->base); 1262dc415ff9SMatt Roper 1263dc415ff9SMatt Roper BUG_ON(list_empty(&plane->head)); 1264dc415ff9SMatt Roper 12658cf5c917SJesse Barnes list_del(&plane->head); 1266e27dde3eSMatt Roper dev->mode_config.num_total_plane--; 1267e27dde3eSMatt Roper if (plane->type == DRM_PLANE_TYPE_OVERLAY) 1268e27dde3eSMatt Roper dev->mode_config.num_overlay_plane--; 126984849903SDaniel Vetter drm_modeset_unlock_all(dev); 12703009c037SThierry Reding 12713009c037SThierry Reding WARN_ON(plane->state && !plane->funcs->atomic_destroy_state); 12723009c037SThierry Reding if (plane->state && plane->funcs->atomic_destroy_state) 12733009c037SThierry Reding plane->funcs->atomic_destroy_state(plane, plane->state); 1274a18c0af1SThierry Reding 1275a18c0af1SThierry Reding memset(plane, 0, sizeof(*plane)); 12768cf5c917SJesse Barnes } 12778cf5c917SJesse Barnes EXPORT_SYMBOL(drm_plane_cleanup); 12788cf5c917SJesse Barnes 127935f2c3aeSVille Syrjälä /** 128010f637bfSDaniel Vetter * drm_plane_index - find the index of a registered plane 128110f637bfSDaniel Vetter * @plane: plane to find index for 128210f637bfSDaniel Vetter * 128310f637bfSDaniel Vetter * Given a registered plane, return the index of that CRTC within a DRM 128410f637bfSDaniel Vetter * device's list of planes. 128510f637bfSDaniel Vetter */ 128610f637bfSDaniel Vetter unsigned int drm_plane_index(struct drm_plane *plane) 128710f637bfSDaniel Vetter { 128810f637bfSDaniel Vetter unsigned int index = 0; 128910f637bfSDaniel Vetter struct drm_plane *tmp; 129010f637bfSDaniel Vetter 1291e4f62546SDaniel Vetter drm_for_each_plane(tmp, plane->dev) { 129210f637bfSDaniel Vetter if (tmp == plane) 129310f637bfSDaniel Vetter return index; 129410f637bfSDaniel Vetter 129510f637bfSDaniel Vetter index++; 129610f637bfSDaniel Vetter } 129710f637bfSDaniel Vetter 129810f637bfSDaniel Vetter BUG(); 129910f637bfSDaniel Vetter } 130010f637bfSDaniel Vetter EXPORT_SYMBOL(drm_plane_index); 130110f637bfSDaniel Vetter 130210f637bfSDaniel Vetter /** 1303f81338a5SChandra Konduru * drm_plane_from_index - find the registered plane at an index 1304f81338a5SChandra Konduru * @dev: DRM device 1305f81338a5SChandra Konduru * @idx: index of registered plane to find for 1306f81338a5SChandra Konduru * 1307f81338a5SChandra Konduru * Given a plane index, return the registered plane from DRM device's 1308f81338a5SChandra Konduru * list of planes with matching index. 1309f81338a5SChandra Konduru */ 1310f81338a5SChandra Konduru struct drm_plane * 1311f81338a5SChandra Konduru drm_plane_from_index(struct drm_device *dev, int idx) 1312f81338a5SChandra Konduru { 1313f81338a5SChandra Konduru struct drm_plane *plane; 1314f81338a5SChandra Konduru unsigned int i = 0; 1315f81338a5SChandra Konduru 13166295d607SDaniel Vetter drm_for_each_plane(plane, dev) { 1317f81338a5SChandra Konduru if (i == idx) 1318f81338a5SChandra Konduru return plane; 1319f81338a5SChandra Konduru i++; 1320f81338a5SChandra Konduru } 1321f81338a5SChandra Konduru return NULL; 1322f81338a5SChandra Konduru } 1323f81338a5SChandra Konduru EXPORT_SYMBOL(drm_plane_from_index); 1324f81338a5SChandra Konduru 1325f81338a5SChandra Konduru /** 132635f2c3aeSVille Syrjälä * drm_plane_force_disable - Forcibly disable a plane 132735f2c3aeSVille Syrjälä * @plane: plane to disable 132835f2c3aeSVille Syrjälä * 132935f2c3aeSVille Syrjälä * Forces the plane to be disabled. 133035f2c3aeSVille Syrjälä * 133135f2c3aeSVille Syrjälä * Used when the plane's current framebuffer is destroyed, 133235f2c3aeSVille Syrjälä * and when restoring fbdev mode. 133335f2c3aeSVille Syrjälä */ 13349125e618SVille Syrjälä void drm_plane_force_disable(struct drm_plane *plane) 13359125e618SVille Syrjälä { 13369125e618SVille Syrjälä int ret; 13379125e618SVille Syrjälä 13383d30a59bSDaniel Vetter if (!plane->fb) 13399125e618SVille Syrjälä return; 13409125e618SVille Syrjälä 13413d30a59bSDaniel Vetter plane->old_fb = plane->fb; 13429125e618SVille Syrjälä ret = plane->funcs->disable_plane(plane); 1343731cce48SDaniel Vetter if (ret) { 13449125e618SVille Syrjälä DRM_ERROR("failed to disable plane with busy fb\n"); 13453d30a59bSDaniel Vetter plane->old_fb = NULL; 1346731cce48SDaniel Vetter return; 1347731cce48SDaniel Vetter } 13489125e618SVille Syrjälä /* disconnect the plane from the fb and crtc: */ 1349220dd2bcSDaniel Vetter drm_framebuffer_unreference(plane->old_fb); 13503d30a59bSDaniel Vetter plane->old_fb = NULL; 13519125e618SVille Syrjälä plane->fb = NULL; 13529125e618SVille Syrjälä plane->crtc = NULL; 13539125e618SVille Syrjälä } 13549125e618SVille Syrjälä EXPORT_SYMBOL(drm_plane_force_disable); 13559125e618SVille Syrjälä 13566b4959f4SRob Clark static int drm_mode_create_standard_properties(struct drm_device *dev) 1357f453ba04SDave Airlie { 1358356af0e1SRob Clark struct drm_property *prop; 1359f453ba04SDave Airlie 1360f453ba04SDave Airlie /* 1361f453ba04SDave Airlie * Standard properties (apply to all connectors) 1362f453ba04SDave Airlie */ 1363356af0e1SRob Clark prop = drm_property_create(dev, DRM_MODE_PROP_BLOB | 1364f453ba04SDave Airlie DRM_MODE_PROP_IMMUTABLE, 1365f453ba04SDave Airlie "EDID", 0); 1366356af0e1SRob Clark if (!prop) 1367356af0e1SRob Clark return -ENOMEM; 1368356af0e1SRob Clark dev->mode_config.edid_property = prop; 1369f453ba04SDave Airlie 1370356af0e1SRob Clark prop = drm_property_create_enum(dev, 0, 13714a67d391SSascha Hauer "DPMS", drm_dpms_enum_list, 13724a67d391SSascha Hauer ARRAY_SIZE(drm_dpms_enum_list)); 1373356af0e1SRob Clark if (!prop) 1374356af0e1SRob Clark return -ENOMEM; 1375356af0e1SRob Clark dev->mode_config.dpms_property = prop; 1376f453ba04SDave Airlie 1377356af0e1SRob Clark prop = drm_property_create(dev, 137843aba7ebSDave Airlie DRM_MODE_PROP_BLOB | 137943aba7ebSDave Airlie DRM_MODE_PROP_IMMUTABLE, 138043aba7ebSDave Airlie "PATH", 0); 1381356af0e1SRob Clark if (!prop) 1382356af0e1SRob Clark return -ENOMEM; 1383356af0e1SRob Clark dev->mode_config.path_property = prop; 138443aba7ebSDave Airlie 1385356af0e1SRob Clark prop = drm_property_create(dev, 13866f134d7bSDave Airlie DRM_MODE_PROP_BLOB | 13876f134d7bSDave Airlie DRM_MODE_PROP_IMMUTABLE, 13886f134d7bSDave Airlie "TILE", 0); 1389356af0e1SRob Clark if (!prop) 1390356af0e1SRob Clark return -ENOMEM; 1391356af0e1SRob Clark dev->mode_config.tile_property = prop; 13926f134d7bSDave Airlie 13936b4959f4SRob Clark prop = drm_property_create_enum(dev, DRM_MODE_PROP_IMMUTABLE, 13949922ab5aSRob Clark "type", drm_plane_type_enum_list, 13959922ab5aSRob Clark ARRAY_SIZE(drm_plane_type_enum_list)); 13966b4959f4SRob Clark if (!prop) 13976b4959f4SRob Clark return -ENOMEM; 13986b4959f4SRob Clark dev->mode_config.plane_type_property = prop; 13996b4959f4SRob Clark 14006b4959f4SRob Clark prop = drm_property_create_range(dev, DRM_MODE_PROP_ATOMIC, 14016b4959f4SRob Clark "SRC_X", 0, UINT_MAX); 14026b4959f4SRob Clark if (!prop) 14036b4959f4SRob Clark return -ENOMEM; 14046b4959f4SRob Clark dev->mode_config.prop_src_x = prop; 14056b4959f4SRob Clark 14066b4959f4SRob Clark prop = drm_property_create_range(dev, DRM_MODE_PROP_ATOMIC, 14076b4959f4SRob Clark "SRC_Y", 0, UINT_MAX); 14086b4959f4SRob Clark if (!prop) 14096b4959f4SRob Clark return -ENOMEM; 14106b4959f4SRob Clark dev->mode_config.prop_src_y = prop; 14116b4959f4SRob Clark 14126b4959f4SRob Clark prop = drm_property_create_range(dev, DRM_MODE_PROP_ATOMIC, 14136b4959f4SRob Clark "SRC_W", 0, UINT_MAX); 14146b4959f4SRob Clark if (!prop) 14156b4959f4SRob Clark return -ENOMEM; 14166b4959f4SRob Clark dev->mode_config.prop_src_w = prop; 14176b4959f4SRob Clark 14186b4959f4SRob Clark prop = drm_property_create_range(dev, DRM_MODE_PROP_ATOMIC, 14196b4959f4SRob Clark "SRC_H", 0, UINT_MAX); 14206b4959f4SRob Clark if (!prop) 14216b4959f4SRob Clark return -ENOMEM; 14226b4959f4SRob Clark dev->mode_config.prop_src_h = prop; 14236b4959f4SRob Clark 14246b4959f4SRob Clark prop = drm_property_create_signed_range(dev, DRM_MODE_PROP_ATOMIC, 14256b4959f4SRob Clark "CRTC_X", INT_MIN, INT_MAX); 14266b4959f4SRob Clark if (!prop) 14276b4959f4SRob Clark return -ENOMEM; 14286b4959f4SRob Clark dev->mode_config.prop_crtc_x = prop; 14296b4959f4SRob Clark 14306b4959f4SRob Clark prop = drm_property_create_signed_range(dev, DRM_MODE_PROP_ATOMIC, 14316b4959f4SRob Clark "CRTC_Y", INT_MIN, INT_MAX); 14326b4959f4SRob Clark if (!prop) 14336b4959f4SRob Clark return -ENOMEM; 14346b4959f4SRob Clark dev->mode_config.prop_crtc_y = prop; 14356b4959f4SRob Clark 14366b4959f4SRob Clark prop = drm_property_create_range(dev, DRM_MODE_PROP_ATOMIC, 14376b4959f4SRob Clark "CRTC_W", 0, INT_MAX); 14386b4959f4SRob Clark if (!prop) 14396b4959f4SRob Clark return -ENOMEM; 14406b4959f4SRob Clark dev->mode_config.prop_crtc_w = prop; 14416b4959f4SRob Clark 14426b4959f4SRob Clark prop = drm_property_create_range(dev, DRM_MODE_PROP_ATOMIC, 14436b4959f4SRob Clark "CRTC_H", 0, INT_MAX); 14446b4959f4SRob Clark if (!prop) 14456b4959f4SRob Clark return -ENOMEM; 14466b4959f4SRob Clark dev->mode_config.prop_crtc_h = prop; 14476b4959f4SRob Clark 14486b4959f4SRob Clark prop = drm_property_create_object(dev, DRM_MODE_PROP_ATOMIC, 14496b4959f4SRob Clark "FB_ID", DRM_MODE_OBJECT_FB); 14506b4959f4SRob Clark if (!prop) 14516b4959f4SRob Clark return -ENOMEM; 14526b4959f4SRob Clark dev->mode_config.prop_fb_id = prop; 14536b4959f4SRob Clark 14546b4959f4SRob Clark prop = drm_property_create_object(dev, DRM_MODE_PROP_ATOMIC, 14556b4959f4SRob Clark "CRTC_ID", DRM_MODE_OBJECT_CRTC); 14566b4959f4SRob Clark if (!prop) 14576b4959f4SRob Clark return -ENOMEM; 14586b4959f4SRob Clark dev->mode_config.prop_crtc_id = prop; 14599922ab5aSRob Clark 1460eab3bbefSDaniel Vetter prop = drm_property_create_bool(dev, DRM_MODE_PROP_ATOMIC, 1461eab3bbefSDaniel Vetter "ACTIVE"); 1462eab3bbefSDaniel Vetter if (!prop) 1463eab3bbefSDaniel Vetter return -ENOMEM; 1464eab3bbefSDaniel Vetter dev->mode_config.prop_active = prop; 1465eab3bbefSDaniel Vetter 1466955f3c33SDaniel Stone prop = drm_property_create(dev, 1467955f3c33SDaniel Stone DRM_MODE_PROP_ATOMIC | DRM_MODE_PROP_BLOB, 1468955f3c33SDaniel Stone "MODE_ID", 0); 1469955f3c33SDaniel Stone if (!prop) 1470955f3c33SDaniel Stone return -ENOMEM; 1471955f3c33SDaniel Stone dev->mode_config.prop_mode_id = prop; 1472955f3c33SDaniel Stone 14739922ab5aSRob Clark return 0; 14749922ab5aSRob Clark } 14759922ab5aSRob Clark 1476f453ba04SDave Airlie /** 1477f453ba04SDave Airlie * drm_mode_create_dvi_i_properties - create DVI-I specific connector properties 1478f453ba04SDave Airlie * @dev: DRM device 1479f453ba04SDave Airlie * 1480f453ba04SDave Airlie * Called by a driver the first time a DVI-I connector is made. 1481f453ba04SDave Airlie */ 1482f453ba04SDave Airlie int drm_mode_create_dvi_i_properties(struct drm_device *dev) 1483f453ba04SDave Airlie { 1484f453ba04SDave Airlie struct drm_property *dvi_i_selector; 1485f453ba04SDave Airlie struct drm_property *dvi_i_subconnector; 1486f453ba04SDave Airlie 1487f453ba04SDave Airlie if (dev->mode_config.dvi_i_select_subconnector_property) 1488f453ba04SDave Airlie return 0; 1489f453ba04SDave Airlie 1490f453ba04SDave Airlie dvi_i_selector = 14914a67d391SSascha Hauer drm_property_create_enum(dev, 0, 1492f453ba04SDave Airlie "select subconnector", 14934a67d391SSascha Hauer drm_dvi_i_select_enum_list, 1494f453ba04SDave Airlie ARRAY_SIZE(drm_dvi_i_select_enum_list)); 1495f453ba04SDave Airlie dev->mode_config.dvi_i_select_subconnector_property = dvi_i_selector; 1496f453ba04SDave Airlie 14974a67d391SSascha Hauer dvi_i_subconnector = drm_property_create_enum(dev, DRM_MODE_PROP_IMMUTABLE, 1498f453ba04SDave Airlie "subconnector", 14994a67d391SSascha Hauer drm_dvi_i_subconnector_enum_list, 1500f453ba04SDave Airlie ARRAY_SIZE(drm_dvi_i_subconnector_enum_list)); 1501f453ba04SDave Airlie dev->mode_config.dvi_i_subconnector_property = dvi_i_subconnector; 1502f453ba04SDave Airlie 1503f453ba04SDave Airlie return 0; 1504f453ba04SDave Airlie } 1505f453ba04SDave Airlie EXPORT_SYMBOL(drm_mode_create_dvi_i_properties); 1506f453ba04SDave Airlie 1507f453ba04SDave Airlie /** 1508f453ba04SDave Airlie * drm_create_tv_properties - create TV specific connector properties 1509f453ba04SDave Airlie * @dev: DRM device 1510f453ba04SDave Airlie * @num_modes: number of different TV formats (modes) supported 1511f453ba04SDave Airlie * @modes: array of pointers to strings containing name of each format 1512f453ba04SDave Airlie * 1513f453ba04SDave Airlie * Called by a driver's TV initialization routine, this function creates 1514f453ba04SDave Airlie * the TV specific connector properties for a given device. Caller is 1515f453ba04SDave Airlie * responsible for allocating a list of format names and passing them to 1516f453ba04SDave Airlie * this routine. 1517f453ba04SDave Airlie */ 15182f763312SThierry Reding int drm_mode_create_tv_properties(struct drm_device *dev, 15192f763312SThierry Reding unsigned int num_modes, 1520b7c914b3SVille Syrjälä const char * const modes[]) 1521f453ba04SDave Airlie { 1522f453ba04SDave Airlie struct drm_property *tv_selector; 1523f453ba04SDave Airlie struct drm_property *tv_subconnector; 15242f763312SThierry Reding unsigned int i; 1525f453ba04SDave Airlie 1526f453ba04SDave Airlie if (dev->mode_config.tv_select_subconnector_property) 1527f453ba04SDave Airlie return 0; 1528f453ba04SDave Airlie 1529f453ba04SDave Airlie /* 1530f453ba04SDave Airlie * Basic connector properties 1531f453ba04SDave Airlie */ 15324a67d391SSascha Hauer tv_selector = drm_property_create_enum(dev, 0, 1533f453ba04SDave Airlie "select subconnector", 15344a67d391SSascha Hauer drm_tv_select_enum_list, 1535f453ba04SDave Airlie ARRAY_SIZE(drm_tv_select_enum_list)); 153648aa1e74SInsu Yun if (!tv_selector) 153748aa1e74SInsu Yun goto nomem; 153848aa1e74SInsu Yun 1539f453ba04SDave Airlie dev->mode_config.tv_select_subconnector_property = tv_selector; 1540f453ba04SDave Airlie 1541f453ba04SDave Airlie tv_subconnector = 15424a67d391SSascha Hauer drm_property_create_enum(dev, DRM_MODE_PROP_IMMUTABLE, 15434a67d391SSascha Hauer "subconnector", 15444a67d391SSascha Hauer drm_tv_subconnector_enum_list, 1545f453ba04SDave Airlie ARRAY_SIZE(drm_tv_subconnector_enum_list)); 154648aa1e74SInsu Yun if (!tv_subconnector) 154748aa1e74SInsu Yun goto nomem; 1548f453ba04SDave Airlie dev->mode_config.tv_subconnector_property = tv_subconnector; 1549f453ba04SDave Airlie 1550f453ba04SDave Airlie /* 1551f453ba04SDave Airlie * Other, TV specific properties: margins & TV modes. 1552f453ba04SDave Airlie */ 1553f453ba04SDave Airlie dev->mode_config.tv_left_margin_property = 1554d9bc3c02SSascha Hauer drm_property_create_range(dev, 0, "left margin", 0, 100); 155548aa1e74SInsu Yun if (!dev->mode_config.tv_left_margin_property) 155648aa1e74SInsu Yun goto nomem; 1557f453ba04SDave Airlie 1558f453ba04SDave Airlie dev->mode_config.tv_right_margin_property = 1559d9bc3c02SSascha Hauer drm_property_create_range(dev, 0, "right margin", 0, 100); 156048aa1e74SInsu Yun if (!dev->mode_config.tv_right_margin_property) 156148aa1e74SInsu Yun goto nomem; 1562f453ba04SDave Airlie 1563f453ba04SDave Airlie dev->mode_config.tv_top_margin_property = 1564d9bc3c02SSascha Hauer drm_property_create_range(dev, 0, "top margin", 0, 100); 156548aa1e74SInsu Yun if (!dev->mode_config.tv_top_margin_property) 156648aa1e74SInsu Yun goto nomem; 1567f453ba04SDave Airlie 1568f453ba04SDave Airlie dev->mode_config.tv_bottom_margin_property = 1569d9bc3c02SSascha Hauer drm_property_create_range(dev, 0, "bottom margin", 0, 100); 157048aa1e74SInsu Yun if (!dev->mode_config.tv_bottom_margin_property) 157148aa1e74SInsu Yun goto nomem; 1572f453ba04SDave Airlie 1573f453ba04SDave Airlie dev->mode_config.tv_mode_property = 1574f453ba04SDave Airlie drm_property_create(dev, DRM_MODE_PROP_ENUM, 1575f453ba04SDave Airlie "mode", num_modes); 157648aa1e74SInsu Yun if (!dev->mode_config.tv_mode_property) 157748aa1e74SInsu Yun goto nomem; 157848aa1e74SInsu Yun 1579f453ba04SDave Airlie for (i = 0; i < num_modes; i++) 1580f453ba04SDave Airlie drm_property_add_enum(dev->mode_config.tv_mode_property, i, 1581f453ba04SDave Airlie i, modes[i]); 1582f453ba04SDave Airlie 1583b6b7902eSFrancisco Jerez dev->mode_config.tv_brightness_property = 1584d9bc3c02SSascha Hauer drm_property_create_range(dev, 0, "brightness", 0, 100); 158548aa1e74SInsu Yun if (!dev->mode_config.tv_brightness_property) 158648aa1e74SInsu Yun goto nomem; 1587b6b7902eSFrancisco Jerez 1588b6b7902eSFrancisco Jerez dev->mode_config.tv_contrast_property = 1589d9bc3c02SSascha Hauer drm_property_create_range(dev, 0, "contrast", 0, 100); 159048aa1e74SInsu Yun if (!dev->mode_config.tv_contrast_property) 159148aa1e74SInsu Yun goto nomem; 1592b6b7902eSFrancisco Jerez 1593b6b7902eSFrancisco Jerez dev->mode_config.tv_flicker_reduction_property = 1594d9bc3c02SSascha Hauer drm_property_create_range(dev, 0, "flicker reduction", 0, 100); 159548aa1e74SInsu Yun if (!dev->mode_config.tv_flicker_reduction_property) 159648aa1e74SInsu Yun goto nomem; 1597b6b7902eSFrancisco Jerez 1598a75f0236SFrancisco Jerez dev->mode_config.tv_overscan_property = 1599d9bc3c02SSascha Hauer drm_property_create_range(dev, 0, "overscan", 0, 100); 160048aa1e74SInsu Yun if (!dev->mode_config.tv_overscan_property) 160148aa1e74SInsu Yun goto nomem; 1602a75f0236SFrancisco Jerez 1603a75f0236SFrancisco Jerez dev->mode_config.tv_saturation_property = 1604d9bc3c02SSascha Hauer drm_property_create_range(dev, 0, "saturation", 0, 100); 160548aa1e74SInsu Yun if (!dev->mode_config.tv_saturation_property) 160648aa1e74SInsu Yun goto nomem; 1607a75f0236SFrancisco Jerez 1608a75f0236SFrancisco Jerez dev->mode_config.tv_hue_property = 1609d9bc3c02SSascha Hauer drm_property_create_range(dev, 0, "hue", 0, 100); 161048aa1e74SInsu Yun if (!dev->mode_config.tv_hue_property) 161148aa1e74SInsu Yun goto nomem; 1612a75f0236SFrancisco Jerez 1613f453ba04SDave Airlie return 0; 161448aa1e74SInsu Yun nomem: 161548aa1e74SInsu Yun return -ENOMEM; 1616f453ba04SDave Airlie } 1617f453ba04SDave Airlie EXPORT_SYMBOL(drm_mode_create_tv_properties); 1618f453ba04SDave Airlie 1619f453ba04SDave Airlie /** 1620f453ba04SDave Airlie * drm_mode_create_scaling_mode_property - create scaling mode property 1621f453ba04SDave Airlie * @dev: DRM device 1622f453ba04SDave Airlie * 1623f453ba04SDave Airlie * Called by a driver the first time it's needed, must be attached to desired 1624f453ba04SDave Airlie * connectors. 1625f453ba04SDave Airlie */ 1626f453ba04SDave Airlie int drm_mode_create_scaling_mode_property(struct drm_device *dev) 1627f453ba04SDave Airlie { 1628f453ba04SDave Airlie struct drm_property *scaling_mode; 1629f453ba04SDave Airlie 1630f453ba04SDave Airlie if (dev->mode_config.scaling_mode_property) 1631f453ba04SDave Airlie return 0; 1632f453ba04SDave Airlie 1633f453ba04SDave Airlie scaling_mode = 16344a67d391SSascha Hauer drm_property_create_enum(dev, 0, "scaling mode", 16354a67d391SSascha Hauer drm_scaling_mode_enum_list, 1636f453ba04SDave Airlie ARRAY_SIZE(drm_scaling_mode_enum_list)); 1637f453ba04SDave Airlie 1638f453ba04SDave Airlie dev->mode_config.scaling_mode_property = scaling_mode; 1639f453ba04SDave Airlie 1640f453ba04SDave Airlie return 0; 1641f453ba04SDave Airlie } 1642f453ba04SDave Airlie EXPORT_SYMBOL(drm_mode_create_scaling_mode_property); 1643f453ba04SDave Airlie 1644f453ba04SDave Airlie /** 1645ff587e45SVandana Kannan * drm_mode_create_aspect_ratio_property - create aspect ratio property 1646ff587e45SVandana Kannan * @dev: DRM device 1647ff587e45SVandana Kannan * 1648ff587e45SVandana Kannan * Called by a driver the first time it's needed, must be attached to desired 1649ff587e45SVandana Kannan * connectors. 1650ff587e45SVandana Kannan * 1651ff587e45SVandana Kannan * Returns: 16521a498633SDaniel Vetter * Zero on success, negative errno on failure. 1653ff587e45SVandana Kannan */ 1654ff587e45SVandana Kannan int drm_mode_create_aspect_ratio_property(struct drm_device *dev) 1655ff587e45SVandana Kannan { 1656ff587e45SVandana Kannan if (dev->mode_config.aspect_ratio_property) 1657ff587e45SVandana Kannan return 0; 1658ff587e45SVandana Kannan 1659ff587e45SVandana Kannan dev->mode_config.aspect_ratio_property = 1660ff587e45SVandana Kannan drm_property_create_enum(dev, 0, "aspect ratio", 1661ff587e45SVandana Kannan drm_aspect_ratio_enum_list, 1662ff587e45SVandana Kannan ARRAY_SIZE(drm_aspect_ratio_enum_list)); 1663ff587e45SVandana Kannan 1664ff587e45SVandana Kannan if (dev->mode_config.aspect_ratio_property == NULL) 1665ff587e45SVandana Kannan return -ENOMEM; 1666ff587e45SVandana Kannan 1667ff587e45SVandana Kannan return 0; 1668ff587e45SVandana Kannan } 1669ff587e45SVandana Kannan EXPORT_SYMBOL(drm_mode_create_aspect_ratio_property); 1670ff587e45SVandana Kannan 1671ff587e45SVandana Kannan /** 1672884840aaSJakob Bornecrantz * drm_mode_create_dirty_property - create dirty property 1673884840aaSJakob Bornecrantz * @dev: DRM device 1674884840aaSJakob Bornecrantz * 1675884840aaSJakob Bornecrantz * Called by a driver the first time it's needed, must be attached to desired 1676884840aaSJakob Bornecrantz * connectors. 1677884840aaSJakob Bornecrantz */ 1678884840aaSJakob Bornecrantz int drm_mode_create_dirty_info_property(struct drm_device *dev) 1679884840aaSJakob Bornecrantz { 1680884840aaSJakob Bornecrantz struct drm_property *dirty_info; 1681884840aaSJakob Bornecrantz 1682884840aaSJakob Bornecrantz if (dev->mode_config.dirty_info_property) 1683884840aaSJakob Bornecrantz return 0; 1684884840aaSJakob Bornecrantz 1685884840aaSJakob Bornecrantz dirty_info = 16864a67d391SSascha Hauer drm_property_create_enum(dev, DRM_MODE_PROP_IMMUTABLE, 1687884840aaSJakob Bornecrantz "dirty", 16884a67d391SSascha Hauer drm_dirty_info_enum_list, 1689884840aaSJakob Bornecrantz ARRAY_SIZE(drm_dirty_info_enum_list)); 1690884840aaSJakob Bornecrantz dev->mode_config.dirty_info_property = dirty_info; 1691884840aaSJakob Bornecrantz 1692884840aaSJakob Bornecrantz return 0; 1693884840aaSJakob Bornecrantz } 1694884840aaSJakob Bornecrantz EXPORT_SYMBOL(drm_mode_create_dirty_info_property); 1695884840aaSJakob Bornecrantz 16965bb2bbf5SDave Airlie /** 16975bb2bbf5SDave Airlie * drm_mode_create_suggested_offset_properties - create suggests offset properties 16985bb2bbf5SDave Airlie * @dev: DRM device 16995bb2bbf5SDave Airlie * 17005bb2bbf5SDave Airlie * Create the the suggested x/y offset property for connectors. 17015bb2bbf5SDave Airlie */ 17025bb2bbf5SDave Airlie int drm_mode_create_suggested_offset_properties(struct drm_device *dev) 17035bb2bbf5SDave Airlie { 17045bb2bbf5SDave Airlie if (dev->mode_config.suggested_x_property && dev->mode_config.suggested_y_property) 17055bb2bbf5SDave Airlie return 0; 17065bb2bbf5SDave Airlie 17075bb2bbf5SDave Airlie dev->mode_config.suggested_x_property = 17085bb2bbf5SDave Airlie drm_property_create_range(dev, DRM_MODE_PROP_IMMUTABLE, "suggested X", 0, 0xffffffff); 17095bb2bbf5SDave Airlie 17105bb2bbf5SDave Airlie dev->mode_config.suggested_y_property = 17115bb2bbf5SDave Airlie drm_property_create_range(dev, DRM_MODE_PROP_IMMUTABLE, "suggested Y", 0, 0xffffffff); 17125bb2bbf5SDave Airlie 17135bb2bbf5SDave Airlie if (dev->mode_config.suggested_x_property == NULL || 17145bb2bbf5SDave Airlie dev->mode_config.suggested_y_property == NULL) 17155bb2bbf5SDave Airlie return -ENOMEM; 17165bb2bbf5SDave Airlie return 0; 17175bb2bbf5SDave Airlie } 17185bb2bbf5SDave Airlie EXPORT_SYMBOL(drm_mode_create_suggested_offset_properties); 17195bb2bbf5SDave Airlie 1720f453ba04SDave Airlie /** 1721f453ba04SDave Airlie * drm_mode_getresources - get graphics configuration 1722065a50edSDaniel Vetter * @dev: drm device for the ioctl 1723065a50edSDaniel Vetter * @data: data pointer for the ioctl 1724065a50edSDaniel Vetter * @file_priv: drm file for the ioctl call 1725f453ba04SDave Airlie * 1726f453ba04SDave Airlie * Construct a set of configuration description structures and return 1727f453ba04SDave Airlie * them to the user, including CRTC, connector and framebuffer configuration. 1728f453ba04SDave Airlie * 1729f453ba04SDave Airlie * Called by the user via ioctl. 1730f453ba04SDave Airlie * 1731c8e32cc1SDaniel Vetter * Returns: 17321a498633SDaniel Vetter * Zero on success, negative errno on failure. 1733f453ba04SDave Airlie */ 1734f453ba04SDave Airlie int drm_mode_getresources(struct drm_device *dev, void *data, 1735f453ba04SDave Airlie struct drm_file *file_priv) 1736f453ba04SDave Airlie { 1737f453ba04SDave Airlie struct drm_mode_card_res *card_res = data; 1738f453ba04SDave Airlie struct list_head *lh; 1739f453ba04SDave Airlie struct drm_framebuffer *fb; 1740f453ba04SDave Airlie struct drm_connector *connector; 1741f453ba04SDave Airlie struct drm_crtc *crtc; 1742f453ba04SDave Airlie struct drm_encoder *encoder; 1743f453ba04SDave Airlie int ret = 0; 1744f453ba04SDave Airlie int connector_count = 0; 1745f453ba04SDave Airlie int crtc_count = 0; 1746f453ba04SDave Airlie int fb_count = 0; 1747f453ba04SDave Airlie int encoder_count = 0; 17489c7060f7SDaniel Vetter int copied = 0; 1749f453ba04SDave Airlie uint32_t __user *fb_id; 1750f453ba04SDave Airlie uint32_t __user *crtc_id; 1751f453ba04SDave Airlie uint32_t __user *connector_id; 1752f453ba04SDave Airlie uint32_t __user *encoder_id; 1753f453ba04SDave Airlie 1754fb3b06c8SDave Airlie if (!drm_core_check_feature(dev, DRIVER_MODESET)) 1755fb3b06c8SDave Airlie return -EINVAL; 1756fb3b06c8SDave Airlie 1757f453ba04SDave Airlie 17584b096ac1SDaniel Vetter mutex_lock(&file_priv->fbs_lock); 1759f453ba04SDave Airlie /* 1760f453ba04SDave Airlie * For the non-control nodes we need to limit the list of resources 1761f453ba04SDave Airlie * by IDs in the group list for this node 1762f453ba04SDave Airlie */ 1763f453ba04SDave Airlie list_for_each(lh, &file_priv->fbs) 1764f453ba04SDave Airlie fb_count++; 1765f453ba04SDave Airlie 17664b096ac1SDaniel Vetter /* handle this in 4 parts */ 17674b096ac1SDaniel Vetter /* FBs */ 17684b096ac1SDaniel Vetter if (card_res->count_fbs >= fb_count) { 17694b096ac1SDaniel Vetter copied = 0; 17704b096ac1SDaniel Vetter fb_id = (uint32_t __user *)(unsigned long)card_res->fb_id_ptr; 17714b096ac1SDaniel Vetter list_for_each_entry(fb, &file_priv->fbs, filp_head) { 17724b096ac1SDaniel Vetter if (put_user(fb->base.id, fb_id + copied)) { 17734b096ac1SDaniel Vetter mutex_unlock(&file_priv->fbs_lock); 17744b096ac1SDaniel Vetter return -EFAULT; 17754b096ac1SDaniel Vetter } 17764b096ac1SDaniel Vetter copied++; 17774b096ac1SDaniel Vetter } 17784b096ac1SDaniel Vetter } 17794b096ac1SDaniel Vetter card_res->count_fbs = fb_count; 17804b096ac1SDaniel Vetter mutex_unlock(&file_priv->fbs_lock); 17814b096ac1SDaniel Vetter 1782fcf93f69SDaniel Vetter /* mode_config.mutex protects the connector list against e.g. DP MST 1783fcf93f69SDaniel Vetter * connector hot-adding. CRTC/Plane lists are invariant. */ 1784fcf93f69SDaniel Vetter mutex_lock(&dev->mode_config.mutex); 1785e4f62546SDaniel Vetter drm_for_each_crtc(crtc, dev) 1786f453ba04SDave Airlie crtc_count++; 1787f453ba04SDave Airlie 17889a9f5ce8SDaniel Vetter drm_for_each_connector(connector, dev) 1789f453ba04SDave Airlie connector_count++; 1790f453ba04SDave Airlie 1791e4f62546SDaniel Vetter drm_for_each_encoder(encoder, dev) 1792f453ba04SDave Airlie encoder_count++; 1793f453ba04SDave Airlie 1794f453ba04SDave Airlie card_res->max_height = dev->mode_config.max_height; 1795f453ba04SDave Airlie card_res->min_height = dev->mode_config.min_height; 1796f453ba04SDave Airlie card_res->max_width = dev->mode_config.max_width; 1797f453ba04SDave Airlie card_res->min_width = dev->mode_config.min_width; 1798f453ba04SDave Airlie 1799f453ba04SDave Airlie /* CRTCs */ 1800f453ba04SDave Airlie if (card_res->count_crtcs >= crtc_count) { 1801f453ba04SDave Airlie copied = 0; 1802f453ba04SDave Airlie crtc_id = (uint32_t __user *)(unsigned long)card_res->crtc_id_ptr; 18036295d607SDaniel Vetter drm_for_each_crtc(crtc, dev) { 18049440106bSJerome Glisse DRM_DEBUG_KMS("[CRTC:%d]\n", crtc->base.id); 1805f453ba04SDave Airlie if (put_user(crtc->base.id, crtc_id + copied)) { 1806f453ba04SDave Airlie ret = -EFAULT; 1807f453ba04SDave Airlie goto out; 1808f453ba04SDave Airlie } 1809f453ba04SDave Airlie copied++; 1810f453ba04SDave Airlie } 1811f453ba04SDave Airlie } 1812f453ba04SDave Airlie card_res->count_crtcs = crtc_count; 1813f453ba04SDave Airlie 1814f453ba04SDave Airlie /* Encoders */ 1815f453ba04SDave Airlie if (card_res->count_encoders >= encoder_count) { 1816f453ba04SDave Airlie copied = 0; 1817f453ba04SDave Airlie encoder_id = (uint32_t __user *)(unsigned long)card_res->encoder_id_ptr; 18186295d607SDaniel Vetter drm_for_each_encoder(encoder, dev) { 18199440106bSJerome Glisse DRM_DEBUG_KMS("[ENCODER:%d:%s]\n", encoder->base.id, 182083a8cfd3SJani Nikula encoder->name); 1821f453ba04SDave Airlie if (put_user(encoder->base.id, encoder_id + 1822f453ba04SDave Airlie copied)) { 1823f453ba04SDave Airlie ret = -EFAULT; 1824f453ba04SDave Airlie goto out; 1825f453ba04SDave Airlie } 1826f453ba04SDave Airlie copied++; 1827f453ba04SDave Airlie } 1828f453ba04SDave Airlie } 1829f453ba04SDave Airlie card_res->count_encoders = encoder_count; 1830f453ba04SDave Airlie 1831f453ba04SDave Airlie /* Connectors */ 1832f453ba04SDave Airlie if (card_res->count_connectors >= connector_count) { 1833f453ba04SDave Airlie copied = 0; 1834f453ba04SDave Airlie connector_id = (uint32_t __user *)(unsigned long)card_res->connector_id_ptr; 18356295d607SDaniel Vetter drm_for_each_connector(connector, dev) { 18369440106bSJerome Glisse DRM_DEBUG_KMS("[CONNECTOR:%d:%s]\n", 18379440106bSJerome Glisse connector->base.id, 183825933820SJani Nikula connector->name); 1839f453ba04SDave Airlie if (put_user(connector->base.id, 1840f453ba04SDave Airlie connector_id + copied)) { 1841f453ba04SDave Airlie ret = -EFAULT; 1842f453ba04SDave Airlie goto out; 1843f453ba04SDave Airlie } 1844f453ba04SDave Airlie copied++; 1845f453ba04SDave Airlie } 1846f453ba04SDave Airlie } 1847f453ba04SDave Airlie card_res->count_connectors = connector_count; 1848f453ba04SDave Airlie 18499440106bSJerome Glisse DRM_DEBUG_KMS("CRTC[%d] CONNECTORS[%d] ENCODERS[%d]\n", card_res->count_crtcs, 1850f453ba04SDave Airlie card_res->count_connectors, card_res->count_encoders); 1851f453ba04SDave Airlie 1852f453ba04SDave Airlie out: 1853fcf93f69SDaniel Vetter mutex_unlock(&dev->mode_config.mutex); 1854f453ba04SDave Airlie return ret; 1855f453ba04SDave Airlie } 1856f453ba04SDave Airlie 1857f453ba04SDave Airlie /** 1858f453ba04SDave Airlie * drm_mode_getcrtc - get CRTC configuration 1859065a50edSDaniel Vetter * @dev: drm device for the ioctl 1860065a50edSDaniel Vetter * @data: data pointer for the ioctl 1861065a50edSDaniel Vetter * @file_priv: drm file for the ioctl call 1862f453ba04SDave Airlie * 1863f453ba04SDave Airlie * Construct a CRTC configuration structure to return to the user. 1864f453ba04SDave Airlie * 1865f453ba04SDave Airlie * Called by the user via ioctl. 1866f453ba04SDave Airlie * 1867c8e32cc1SDaniel Vetter * Returns: 18681a498633SDaniel Vetter * Zero on success, negative errno on failure. 1869f453ba04SDave Airlie */ 1870f453ba04SDave Airlie int drm_mode_getcrtc(struct drm_device *dev, 1871f453ba04SDave Airlie void *data, struct drm_file *file_priv) 1872f453ba04SDave Airlie { 1873f453ba04SDave Airlie struct drm_mode_crtc *crtc_resp = data; 1874f453ba04SDave Airlie struct drm_crtc *crtc; 1875f453ba04SDave Airlie 1876fb3b06c8SDave Airlie if (!drm_core_check_feature(dev, DRIVER_MODESET)) 1877fb3b06c8SDave Airlie return -EINVAL; 1878fb3b06c8SDave Airlie 1879a2b34e22SRob Clark crtc = drm_crtc_find(dev, crtc_resp->crtc_id); 1880fcf93f69SDaniel Vetter if (!crtc) 1881fcf93f69SDaniel Vetter return -ENOENT; 1882f453ba04SDave Airlie 1883fcf93f69SDaniel Vetter drm_modeset_lock_crtc(crtc, crtc->primary); 1884f453ba04SDave Airlie crtc_resp->gamma_size = crtc->gamma_size; 1885f4510a27SMatt Roper if (crtc->primary->fb) 1886f4510a27SMatt Roper crtc_resp->fb_id = crtc->primary->fb->base.id; 1887f453ba04SDave Airlie else 1888f453ba04SDave Airlie crtc_resp->fb_id = 0; 1889f453ba04SDave Airlie 189031c946e8SDaniel Vetter if (crtc->state) { 189131c946e8SDaniel Vetter crtc_resp->x = crtc->primary->state->src_x >> 16; 189231c946e8SDaniel Vetter crtc_resp->y = crtc->primary->state->src_y >> 16; 189331c946e8SDaniel Vetter if (crtc->state->enable) { 1894934a8a89SDaniel Stone drm_mode_convert_to_umode(&crtc_resp->mode, &crtc->state->mode); 189531c946e8SDaniel Vetter crtc_resp->mode_valid = 1; 1896f453ba04SDave Airlie 189731c946e8SDaniel Vetter } else { 189831c946e8SDaniel Vetter crtc_resp->mode_valid = 0; 189931c946e8SDaniel Vetter } 190031c946e8SDaniel Vetter } else { 190131c946e8SDaniel Vetter crtc_resp->x = crtc->x; 190231c946e8SDaniel Vetter crtc_resp->y = crtc->y; 190331c946e8SDaniel Vetter if (crtc->enabled) { 1904934a8a89SDaniel Stone drm_mode_convert_to_umode(&crtc_resp->mode, &crtc->mode); 1905f453ba04SDave Airlie crtc_resp->mode_valid = 1; 1906f453ba04SDave Airlie 1907f453ba04SDave Airlie } else { 1908f453ba04SDave Airlie crtc_resp->mode_valid = 0; 1909f453ba04SDave Airlie } 191031c946e8SDaniel Vetter } 1911fcf93f69SDaniel Vetter drm_modeset_unlock_crtc(crtc); 1912f453ba04SDave Airlie 1913baf698b0SDaniel Vetter return 0; 1914f453ba04SDave Airlie } 1915f453ba04SDave Airlie 191661d8e328SDamien Lespiau static bool drm_mode_expose_to_userspace(const struct drm_display_mode *mode, 191761d8e328SDamien Lespiau const struct drm_file *file_priv) 191861d8e328SDamien Lespiau { 191961d8e328SDamien Lespiau /* 192061d8e328SDamien Lespiau * If user-space hasn't configured the driver to expose the stereo 3D 192161d8e328SDamien Lespiau * modes, don't expose them. 192261d8e328SDamien Lespiau */ 192361d8e328SDamien Lespiau if (!file_priv->stereo_allowed && drm_mode_is_stereo(mode)) 192461d8e328SDamien Lespiau return false; 192561d8e328SDamien Lespiau 192661d8e328SDamien Lespiau return true; 192761d8e328SDamien Lespiau } 192861d8e328SDamien Lespiau 1929abd69c55SDaniel Vetter static struct drm_encoder *drm_connector_get_encoder(struct drm_connector *connector) 1930abd69c55SDaniel Vetter { 1931abd69c55SDaniel Vetter /* For atomic drivers only state objects are synchronously updated and 1932abd69c55SDaniel Vetter * protected by modeset locks, so check those first. */ 1933abd69c55SDaniel Vetter if (connector->state) 1934abd69c55SDaniel Vetter return connector->state->best_encoder; 1935abd69c55SDaniel Vetter return connector->encoder; 1936abd69c55SDaniel Vetter } 1937abd69c55SDaniel Vetter 193895cbf110SRob Clark /* helper for getconnector and getproperties ioctls */ 193988a48e29SRob Clark static int get_properties(struct drm_mode_object *obj, bool atomic, 194095cbf110SRob Clark uint32_t __user *prop_ptr, uint64_t __user *prop_values, 194195cbf110SRob Clark uint32_t *arg_count_props) 194295cbf110SRob Clark { 194388a48e29SRob Clark int props_count; 194488a48e29SRob Clark int i, ret, copied; 194588a48e29SRob Clark 194688a48e29SRob Clark props_count = obj->properties->count; 194788a48e29SRob Clark if (!atomic) 194888a48e29SRob Clark props_count -= obj->properties->atomic_count; 194995cbf110SRob Clark 195095cbf110SRob Clark if ((*arg_count_props >= props_count) && props_count) { 195188a48e29SRob Clark for (i = 0, copied = 0; copied < props_count; i++) { 195295cbf110SRob Clark struct drm_property *prop = obj->properties->properties[i]; 195395cbf110SRob Clark uint64_t val; 195495cbf110SRob Clark 195588a48e29SRob Clark if ((prop->flags & DRM_MODE_PROP_ATOMIC) && !atomic) 195688a48e29SRob Clark continue; 195788a48e29SRob Clark 195895cbf110SRob Clark ret = drm_object_property_get_value(obj, prop, &val); 195995cbf110SRob Clark if (ret) 196095cbf110SRob Clark return ret; 196195cbf110SRob Clark 196295cbf110SRob Clark if (put_user(prop->base.id, prop_ptr + copied)) 196395cbf110SRob Clark return -EFAULT; 196495cbf110SRob Clark 196595cbf110SRob Clark if (put_user(val, prop_values + copied)) 196695cbf110SRob Clark return -EFAULT; 196795cbf110SRob Clark 196895cbf110SRob Clark copied++; 196995cbf110SRob Clark } 197095cbf110SRob Clark } 197195cbf110SRob Clark *arg_count_props = props_count; 197295cbf110SRob Clark 197395cbf110SRob Clark return 0; 197495cbf110SRob Clark } 197595cbf110SRob Clark 1976f453ba04SDave Airlie /** 1977f453ba04SDave Airlie * drm_mode_getconnector - get connector configuration 1978065a50edSDaniel Vetter * @dev: drm device for the ioctl 1979065a50edSDaniel Vetter * @data: data pointer for the ioctl 1980065a50edSDaniel Vetter * @file_priv: drm file for the ioctl call 1981f453ba04SDave Airlie * 1982f453ba04SDave Airlie * Construct a connector configuration structure to return to the user. 1983f453ba04SDave Airlie * 1984f453ba04SDave Airlie * Called by the user via ioctl. 1985f453ba04SDave Airlie * 1986c8e32cc1SDaniel Vetter * Returns: 19871a498633SDaniel Vetter * Zero on success, negative errno on failure. 1988f453ba04SDave Airlie */ 1989f453ba04SDave Airlie int drm_mode_getconnector(struct drm_device *dev, void *data, 1990f453ba04SDave Airlie struct drm_file *file_priv) 1991f453ba04SDave Airlie { 1992f453ba04SDave Airlie struct drm_mode_get_connector *out_resp = data; 1993f453ba04SDave Airlie struct drm_connector *connector; 1994abd69c55SDaniel Vetter struct drm_encoder *encoder; 1995f453ba04SDave Airlie struct drm_display_mode *mode; 1996f453ba04SDave Airlie int mode_count = 0; 1997f453ba04SDave Airlie int encoders_count = 0; 1998f453ba04SDave Airlie int ret = 0; 1999f453ba04SDave Airlie int copied = 0; 2000f453ba04SDave Airlie int i; 2001f453ba04SDave Airlie struct drm_mode_modeinfo u_mode; 2002f453ba04SDave Airlie struct drm_mode_modeinfo __user *mode_ptr; 2003f453ba04SDave Airlie uint32_t __user *encoder_ptr; 2004f453ba04SDave Airlie 2005fb3b06c8SDave Airlie if (!drm_core_check_feature(dev, DRIVER_MODESET)) 2006fb3b06c8SDave Airlie return -EINVAL; 2007fb3b06c8SDave Airlie 2008f453ba04SDave Airlie memset(&u_mode, 0, sizeof(struct drm_mode_modeinfo)); 2009f453ba04SDave Airlie 20109440106bSJerome Glisse DRM_DEBUG_KMS("[CONNECTOR:%d:?]\n", out_resp->connector_id); 2011f453ba04SDave Airlie 20127b24056bSDaniel Vetter mutex_lock(&dev->mode_config.mutex); 2013f453ba04SDave Airlie 2014a2b34e22SRob Clark connector = drm_connector_find(dev, out_resp->connector_id); 2015a2b34e22SRob Clark if (!connector) { 2016f27657f2SVille Syrjälä ret = -ENOENT; 201704bdf441STommi Rantala goto out_unlock; 2018f453ba04SDave Airlie } 2019f453ba04SDave Airlie 202001073b08SThierry Reding for (i = 0; i < DRM_CONNECTOR_MAX_ENCODER; i++) 202101073b08SThierry Reding if (connector->encoder_ids[i] != 0) 2022f453ba04SDave Airlie encoders_count++; 2023f453ba04SDave Airlie 2024f453ba04SDave Airlie if (out_resp->count_modes == 0) { 2025f453ba04SDave Airlie connector->funcs->fill_modes(connector, 2026f453ba04SDave Airlie dev->mode_config.max_width, 2027f453ba04SDave Airlie dev->mode_config.max_height); 2028f453ba04SDave Airlie } 2029f453ba04SDave Airlie 2030f453ba04SDave Airlie /* delayed so we get modes regardless of pre-fill_modes state */ 2031f453ba04SDave Airlie list_for_each_entry(mode, &connector->modes, head) 203261d8e328SDamien Lespiau if (drm_mode_expose_to_userspace(mode, file_priv)) 2033f453ba04SDave Airlie mode_count++; 2034f453ba04SDave Airlie 2035f453ba04SDave Airlie out_resp->connector_id = connector->base.id; 2036f453ba04SDave Airlie out_resp->connector_type = connector->connector_type; 2037f453ba04SDave Airlie out_resp->connector_type_id = connector->connector_type_id; 2038f453ba04SDave Airlie out_resp->mm_width = connector->display_info.width_mm; 2039f453ba04SDave Airlie out_resp->mm_height = connector->display_info.height_mm; 2040f453ba04SDave Airlie out_resp->subpixel = connector->display_info.subpixel_order; 2041f453ba04SDave Airlie out_resp->connection = connector->status; 20422caa80e7SDaniel Vetter 20432caa80e7SDaniel Vetter drm_modeset_lock(&dev->mode_config.connection_mutex, NULL); 2044abd69c55SDaniel Vetter encoder = drm_connector_get_encoder(connector); 2045abd69c55SDaniel Vetter if (encoder) 2046abd69c55SDaniel Vetter out_resp->encoder_id = encoder->base.id; 2047f453ba04SDave Airlie else 2048f453ba04SDave Airlie out_resp->encoder_id = 0; 2049f453ba04SDave Airlie 2050f453ba04SDave Airlie /* 2051f453ba04SDave Airlie * This ioctl is called twice, once to determine how much space is 2052f453ba04SDave Airlie * needed, and the 2nd time to fill it. 2053f453ba04SDave Airlie */ 2054f453ba04SDave Airlie if ((out_resp->count_modes >= mode_count) && mode_count) { 2055f453ba04SDave Airlie copied = 0; 205681f6c7f8SVille Syrjälä mode_ptr = (struct drm_mode_modeinfo __user *)(unsigned long)out_resp->modes_ptr; 2057f453ba04SDave Airlie list_for_each_entry(mode, &connector->modes, head) { 205861d8e328SDamien Lespiau if (!drm_mode_expose_to_userspace(mode, file_priv)) 205961d8e328SDamien Lespiau continue; 206061d8e328SDamien Lespiau 2061934a8a89SDaniel Stone drm_mode_convert_to_umode(&u_mode, mode); 2062f453ba04SDave Airlie if (copy_to_user(mode_ptr + copied, 2063f453ba04SDave Airlie &u_mode, sizeof(u_mode))) { 2064f453ba04SDave Airlie ret = -EFAULT; 2065f453ba04SDave Airlie goto out; 2066f453ba04SDave Airlie } 2067f453ba04SDave Airlie copied++; 2068f453ba04SDave Airlie } 2069f453ba04SDave Airlie } 2070f453ba04SDave Airlie out_resp->count_modes = mode_count; 2071f453ba04SDave Airlie 207288a48e29SRob Clark ret = get_properties(&connector->base, file_priv->atomic, 207395cbf110SRob Clark (uint32_t __user *)(unsigned long)(out_resp->props_ptr), 207495cbf110SRob Clark (uint64_t __user *)(unsigned long)(out_resp->prop_values_ptr), 207595cbf110SRob Clark &out_resp->count_props); 207622b8b13bSRob Clark if (ret) 2077f453ba04SDave Airlie goto out; 2078f453ba04SDave Airlie 2079f453ba04SDave Airlie if ((out_resp->count_encoders >= encoders_count) && encoders_count) { 2080f453ba04SDave Airlie copied = 0; 208181f6c7f8SVille Syrjälä encoder_ptr = (uint32_t __user *)(unsigned long)(out_resp->encoders_ptr); 2082f453ba04SDave Airlie for (i = 0; i < DRM_CONNECTOR_MAX_ENCODER; i++) { 2083f453ba04SDave Airlie if (connector->encoder_ids[i] != 0) { 2084f453ba04SDave Airlie if (put_user(connector->encoder_ids[i], 2085f453ba04SDave Airlie encoder_ptr + copied)) { 2086f453ba04SDave Airlie ret = -EFAULT; 2087f453ba04SDave Airlie goto out; 2088f453ba04SDave Airlie } 2089f453ba04SDave Airlie copied++; 2090f453ba04SDave Airlie } 2091f453ba04SDave Airlie } 2092f453ba04SDave Airlie } 2093f453ba04SDave Airlie out_resp->count_encoders = encoders_count; 2094f453ba04SDave Airlie 2095f453ba04SDave Airlie out: 2096ccfc0865SRob Clark drm_modeset_unlock(&dev->mode_config.connection_mutex); 209704bdf441STommi Rantala 209804bdf441STommi Rantala out_unlock: 20997b24056bSDaniel Vetter mutex_unlock(&dev->mode_config.mutex); 21007b24056bSDaniel Vetter 2101f453ba04SDave Airlie return ret; 2102f453ba04SDave Airlie } 2103f453ba04SDave Airlie 2104abd69c55SDaniel Vetter static struct drm_crtc *drm_encoder_get_crtc(struct drm_encoder *encoder) 2105abd69c55SDaniel Vetter { 2106abd69c55SDaniel Vetter struct drm_connector *connector; 2107abd69c55SDaniel Vetter struct drm_device *dev = encoder->dev; 2108abd69c55SDaniel Vetter bool uses_atomic = false; 2109abd69c55SDaniel Vetter 2110abd69c55SDaniel Vetter /* For atomic drivers only state objects are synchronously updated and 2111abd69c55SDaniel Vetter * protected by modeset locks, so check those first. */ 21126295d607SDaniel Vetter drm_for_each_connector(connector, dev) { 2113abd69c55SDaniel Vetter if (!connector->state) 2114abd69c55SDaniel Vetter continue; 2115abd69c55SDaniel Vetter 2116abd69c55SDaniel Vetter uses_atomic = true; 2117abd69c55SDaniel Vetter 2118abd69c55SDaniel Vetter if (connector->state->best_encoder != encoder) 2119abd69c55SDaniel Vetter continue; 2120abd69c55SDaniel Vetter 2121abd69c55SDaniel Vetter return connector->state->crtc; 2122abd69c55SDaniel Vetter } 2123abd69c55SDaniel Vetter 2124abd69c55SDaniel Vetter /* Don't return stale data (e.g. pending async disable). */ 2125abd69c55SDaniel Vetter if (uses_atomic) 2126abd69c55SDaniel Vetter return NULL; 2127abd69c55SDaniel Vetter 2128abd69c55SDaniel Vetter return encoder->crtc; 2129abd69c55SDaniel Vetter } 2130abd69c55SDaniel Vetter 2131c8e32cc1SDaniel Vetter /** 2132c8e32cc1SDaniel Vetter * drm_mode_getencoder - get encoder configuration 2133c8e32cc1SDaniel Vetter * @dev: drm device for the ioctl 2134c8e32cc1SDaniel Vetter * @data: data pointer for the ioctl 2135c8e32cc1SDaniel Vetter * @file_priv: drm file for the ioctl call 2136c8e32cc1SDaniel Vetter * 2137c8e32cc1SDaniel Vetter * Construct a encoder configuration structure to return to the user. 2138c8e32cc1SDaniel Vetter * 2139c8e32cc1SDaniel Vetter * Called by the user via ioctl. 2140c8e32cc1SDaniel Vetter * 2141c8e32cc1SDaniel Vetter * Returns: 21421a498633SDaniel Vetter * Zero on success, negative errno on failure. 2143c8e32cc1SDaniel Vetter */ 2144f453ba04SDave Airlie int drm_mode_getencoder(struct drm_device *dev, void *data, 2145f453ba04SDave Airlie struct drm_file *file_priv) 2146f453ba04SDave Airlie { 2147f453ba04SDave Airlie struct drm_mode_get_encoder *enc_resp = data; 2148f453ba04SDave Airlie struct drm_encoder *encoder; 2149abd69c55SDaniel Vetter struct drm_crtc *crtc; 2150f453ba04SDave Airlie 2151fb3b06c8SDave Airlie if (!drm_core_check_feature(dev, DRIVER_MODESET)) 2152fb3b06c8SDave Airlie return -EINVAL; 2153fb3b06c8SDave Airlie 2154a2b34e22SRob Clark encoder = drm_encoder_find(dev, enc_resp->encoder_id); 2155fcf93f69SDaniel Vetter if (!encoder) 2156fcf93f69SDaniel Vetter return -ENOENT; 2157f453ba04SDave Airlie 2158fcf93f69SDaniel Vetter drm_modeset_lock(&dev->mode_config.connection_mutex, NULL); 2159abd69c55SDaniel Vetter crtc = drm_encoder_get_crtc(encoder); 2160abd69c55SDaniel Vetter if (crtc) 2161abd69c55SDaniel Vetter enc_resp->crtc_id = crtc->base.id; 2162f453ba04SDave Airlie else 2163f453ba04SDave Airlie enc_resp->crtc_id = 0; 2164fcf93f69SDaniel Vetter drm_modeset_unlock(&dev->mode_config.connection_mutex); 2165fcf93f69SDaniel Vetter 2166f453ba04SDave Airlie enc_resp->encoder_type = encoder->encoder_type; 2167f453ba04SDave Airlie enc_resp->encoder_id = encoder->base.id; 2168f453ba04SDave Airlie enc_resp->possible_crtcs = encoder->possible_crtcs; 2169f453ba04SDave Airlie enc_resp->possible_clones = encoder->possible_clones; 2170f453ba04SDave Airlie 2171baf698b0SDaniel Vetter return 0; 2172f453ba04SDave Airlie } 2173f453ba04SDave Airlie 2174f453ba04SDave Airlie /** 2175c8e32cc1SDaniel Vetter * drm_mode_getplane_res - enumerate all plane resources 21768cf5c917SJesse Barnes * @dev: DRM device 21778cf5c917SJesse Barnes * @data: ioctl data 21788cf5c917SJesse Barnes * @file_priv: DRM file info 21798cf5c917SJesse Barnes * 2180c8e32cc1SDaniel Vetter * Construct a list of plane ids to return to the user. 2181c8e32cc1SDaniel Vetter * 2182c8e32cc1SDaniel Vetter * Called by the user via ioctl. 2183c8e32cc1SDaniel Vetter * 2184c8e32cc1SDaniel Vetter * Returns: 21851a498633SDaniel Vetter * Zero on success, negative errno on failure. 21868cf5c917SJesse Barnes */ 21878cf5c917SJesse Barnes int drm_mode_getplane_res(struct drm_device *dev, void *data, 21888cf5c917SJesse Barnes struct drm_file *file_priv) 21898cf5c917SJesse Barnes { 21908cf5c917SJesse Barnes struct drm_mode_get_plane_res *plane_resp = data; 21918cf5c917SJesse Barnes struct drm_mode_config *config; 21928cf5c917SJesse Barnes struct drm_plane *plane; 21938cf5c917SJesse Barnes uint32_t __user *plane_ptr; 2194fcf93f69SDaniel Vetter int copied = 0; 2195681e7ec7SMatt Roper unsigned num_planes; 21968cf5c917SJesse Barnes 21978cf5c917SJesse Barnes if (!drm_core_check_feature(dev, DRIVER_MODESET)) 21988cf5c917SJesse Barnes return -EINVAL; 21998cf5c917SJesse Barnes 22008cf5c917SJesse Barnes config = &dev->mode_config; 22018cf5c917SJesse Barnes 2202681e7ec7SMatt Roper if (file_priv->universal_planes) 2203681e7ec7SMatt Roper num_planes = config->num_total_plane; 2204681e7ec7SMatt Roper else 2205681e7ec7SMatt Roper num_planes = config->num_overlay_plane; 2206681e7ec7SMatt Roper 22078cf5c917SJesse Barnes /* 22088cf5c917SJesse Barnes * This ioctl is called twice, once to determine how much space is 22098cf5c917SJesse Barnes * needed, and the 2nd time to fill it. 22108cf5c917SJesse Barnes */ 2211681e7ec7SMatt Roper if (num_planes && 2212681e7ec7SMatt Roper (plane_resp->count_planes >= num_planes)) { 221381f6c7f8SVille Syrjälä plane_ptr = (uint32_t __user *)(unsigned long)plane_resp->plane_id_ptr; 22148cf5c917SJesse Barnes 2215fcf93f69SDaniel Vetter /* Plane lists are invariant, no locking needed. */ 2216e4f62546SDaniel Vetter drm_for_each_plane(plane, dev) { 2217681e7ec7SMatt Roper /* 2218681e7ec7SMatt Roper * Unless userspace set the 'universal planes' 2219681e7ec7SMatt Roper * capability bit, only advertise overlays. 2220681e7ec7SMatt Roper */ 2221681e7ec7SMatt Roper if (plane->type != DRM_PLANE_TYPE_OVERLAY && 2222681e7ec7SMatt Roper !file_priv->universal_planes) 2223e27dde3eSMatt Roper continue; 2224e27dde3eSMatt Roper 2225fcf93f69SDaniel Vetter if (put_user(plane->base.id, plane_ptr + copied)) 2226fcf93f69SDaniel Vetter return -EFAULT; 22278cf5c917SJesse Barnes copied++; 22288cf5c917SJesse Barnes } 22298cf5c917SJesse Barnes } 2230681e7ec7SMatt Roper plane_resp->count_planes = num_planes; 22318cf5c917SJesse Barnes 2232fcf93f69SDaniel Vetter return 0; 22338cf5c917SJesse Barnes } 22348cf5c917SJesse Barnes 22358cf5c917SJesse Barnes /** 2236c8e32cc1SDaniel Vetter * drm_mode_getplane - get plane configuration 22378cf5c917SJesse Barnes * @dev: DRM device 22388cf5c917SJesse Barnes * @data: ioctl data 22398cf5c917SJesse Barnes * @file_priv: DRM file info 22408cf5c917SJesse Barnes * 2241c8e32cc1SDaniel Vetter * Construct a plane configuration structure to return to the user. 2242c8e32cc1SDaniel Vetter * 2243c8e32cc1SDaniel Vetter * Called by the user via ioctl. 2244c8e32cc1SDaniel Vetter * 2245c8e32cc1SDaniel Vetter * Returns: 22461a498633SDaniel Vetter * Zero on success, negative errno on failure. 22478cf5c917SJesse Barnes */ 22488cf5c917SJesse Barnes int drm_mode_getplane(struct drm_device *dev, void *data, 22498cf5c917SJesse Barnes struct drm_file *file_priv) 22508cf5c917SJesse Barnes { 22518cf5c917SJesse Barnes struct drm_mode_get_plane *plane_resp = data; 22528cf5c917SJesse Barnes struct drm_plane *plane; 22538cf5c917SJesse Barnes uint32_t __user *format_ptr; 22548cf5c917SJesse Barnes 22558cf5c917SJesse Barnes if (!drm_core_check_feature(dev, DRIVER_MODESET)) 22568cf5c917SJesse Barnes return -EINVAL; 22578cf5c917SJesse Barnes 2258a2b34e22SRob Clark plane = drm_plane_find(dev, plane_resp->plane_id); 2259fcf93f69SDaniel Vetter if (!plane) 2260fcf93f69SDaniel Vetter return -ENOENT; 22618cf5c917SJesse Barnes 2262fcf93f69SDaniel Vetter drm_modeset_lock(&plane->mutex, NULL); 22638cf5c917SJesse Barnes if (plane->crtc) 22648cf5c917SJesse Barnes plane_resp->crtc_id = plane->crtc->base.id; 22658cf5c917SJesse Barnes else 22668cf5c917SJesse Barnes plane_resp->crtc_id = 0; 22678cf5c917SJesse Barnes 22688cf5c917SJesse Barnes if (plane->fb) 22698cf5c917SJesse Barnes plane_resp->fb_id = plane->fb->base.id; 22708cf5c917SJesse Barnes else 22718cf5c917SJesse Barnes plane_resp->fb_id = 0; 2272fcf93f69SDaniel Vetter drm_modeset_unlock(&plane->mutex); 22738cf5c917SJesse Barnes 22748cf5c917SJesse Barnes plane_resp->plane_id = plane->base.id; 22758cf5c917SJesse Barnes plane_resp->possible_crtcs = plane->possible_crtcs; 2276778ad903SVille Syrjälä plane_resp->gamma_size = 0; 22778cf5c917SJesse Barnes 22788cf5c917SJesse Barnes /* 22798cf5c917SJesse Barnes * This ioctl is called twice, once to determine how much space is 22808cf5c917SJesse Barnes * needed, and the 2nd time to fill it. 22818cf5c917SJesse Barnes */ 22828cf5c917SJesse Barnes if (plane->format_count && 22838cf5c917SJesse Barnes (plane_resp->count_format_types >= plane->format_count)) { 228481f6c7f8SVille Syrjälä format_ptr = (uint32_t __user *)(unsigned long)plane_resp->format_type_ptr; 22858cf5c917SJesse Barnes if (copy_to_user(format_ptr, 22868cf5c917SJesse Barnes plane->format_types, 22878cf5c917SJesse Barnes sizeof(uint32_t) * plane->format_count)) { 2288fcf93f69SDaniel Vetter return -EFAULT; 22898cf5c917SJesse Barnes } 22908cf5c917SJesse Barnes } 22918cf5c917SJesse Barnes plane_resp->count_format_types = plane->format_count; 22928cf5c917SJesse Barnes 2293baf698b0SDaniel Vetter return 0; 22948cf5c917SJesse Barnes } 22958cf5c917SJesse Barnes 2296ead8610dSLaurent Pinchart /** 2297ead8610dSLaurent Pinchart * drm_plane_check_pixel_format - Check if the plane supports the pixel format 2298ead8610dSLaurent Pinchart * @plane: plane to check for format support 2299ead8610dSLaurent Pinchart * @format: the pixel format 2300ead8610dSLaurent Pinchart * 2301ead8610dSLaurent Pinchart * Returns: 2302ead8610dSLaurent Pinchart * Zero of @plane has @format in its list of supported pixel formats, -EINVAL 2303ead8610dSLaurent Pinchart * otherwise. 2304ead8610dSLaurent Pinchart */ 2305ead8610dSLaurent Pinchart int drm_plane_check_pixel_format(const struct drm_plane *plane, u32 format) 2306ead8610dSLaurent Pinchart { 2307ead8610dSLaurent Pinchart unsigned int i; 2308ead8610dSLaurent Pinchart 2309ead8610dSLaurent Pinchart for (i = 0; i < plane->format_count; i++) { 2310ead8610dSLaurent Pinchart if (format == plane->format_types[i]) 2311ead8610dSLaurent Pinchart return 0; 2312ead8610dSLaurent Pinchart } 2313ead8610dSLaurent Pinchart 2314ead8610dSLaurent Pinchart return -EINVAL; 2315ead8610dSLaurent Pinchart } 2316ead8610dSLaurent Pinchart 2317ce8d9eccSVille Syrjälä static int check_src_coords(uint32_t src_x, uint32_t src_y, 2318ce8d9eccSVille Syrjälä uint32_t src_w, uint32_t src_h, 2319ce8d9eccSVille Syrjälä const struct drm_framebuffer *fb) 2320ce8d9eccSVille Syrjälä { 2321ce8d9eccSVille Syrjälä unsigned int fb_width, fb_height; 2322ce8d9eccSVille Syrjälä 2323ce8d9eccSVille Syrjälä fb_width = fb->width << 16; 2324ce8d9eccSVille Syrjälä fb_height = fb->height << 16; 2325ce8d9eccSVille Syrjälä 2326ce8d9eccSVille Syrjälä /* Make sure source coordinates are inside the fb. */ 2327ce8d9eccSVille Syrjälä if (src_w > fb_width || 2328ce8d9eccSVille Syrjälä src_x > fb_width - src_w || 2329ce8d9eccSVille Syrjälä src_h > fb_height || 2330ce8d9eccSVille Syrjälä src_y > fb_height - src_h) { 2331ce8d9eccSVille Syrjälä DRM_DEBUG_KMS("Invalid source coordinates " 2332ce8d9eccSVille Syrjälä "%u.%06ux%u.%06u+%u.%06u+%u.%06u\n", 2333ce8d9eccSVille Syrjälä src_w >> 16, ((src_w & 0xffff) * 15625) >> 10, 2334ce8d9eccSVille Syrjälä src_h >> 16, ((src_h & 0xffff) * 15625) >> 10, 2335ce8d9eccSVille Syrjälä src_x >> 16, ((src_x & 0xffff) * 15625) >> 10, 2336ce8d9eccSVille Syrjälä src_y >> 16, ((src_y & 0xffff) * 15625) >> 10); 2337ce8d9eccSVille Syrjälä return -ENOSPC; 2338ce8d9eccSVille Syrjälä } 2339ce8d9eccSVille Syrjälä 2340ce8d9eccSVille Syrjälä return 0; 2341ce8d9eccSVille Syrjälä } 2342ce8d9eccSVille Syrjälä 2343b36552b3SMatt Roper /* 2344b36552b3SMatt Roper * setplane_internal - setplane handler for internal callers 23458cf5c917SJesse Barnes * 2346b36552b3SMatt Roper * Note that we assume an extra reference has already been taken on fb. If the 2347b36552b3SMatt Roper * update fails, this reference will be dropped before return; if it succeeds, 2348b36552b3SMatt Roper * the previous framebuffer (if any) will be unreferenced instead. 2349c8e32cc1SDaniel Vetter * 2350b36552b3SMatt Roper * src_{x,y,w,h} are provided in 16.16 fixed point format 23518cf5c917SJesse Barnes */ 2352f2b50c11SDaniel Vetter static int __setplane_internal(struct drm_plane *plane, 235317cfd91fSChris Wilson struct drm_crtc *crtc, 2354b36552b3SMatt Roper struct drm_framebuffer *fb, 2355b36552b3SMatt Roper int32_t crtc_x, int32_t crtc_y, 2356b36552b3SMatt Roper uint32_t crtc_w, uint32_t crtc_h, 2357b36552b3SMatt Roper /* src_{x,y,w,h} values are 16.16 fixed point */ 2358b36552b3SMatt Roper uint32_t src_x, uint32_t src_y, 2359b36552b3SMatt Roper uint32_t src_w, uint32_t src_h) 23608cf5c917SJesse Barnes { 23618cf5c917SJesse Barnes int ret = 0; 23628cf5c917SJesse Barnes 23638cf5c917SJesse Barnes /* No fb means shut it down */ 2364b36552b3SMatt Roper if (!fb) { 23653d30a59bSDaniel Vetter plane->old_fb = plane->fb; 2366731cce48SDaniel Vetter ret = plane->funcs->disable_plane(plane); 2367731cce48SDaniel Vetter if (!ret) { 2368e5e3b44cSVille Syrjälä plane->crtc = NULL; 2369e5e3b44cSVille Syrjälä plane->fb = NULL; 2370731cce48SDaniel Vetter } else { 23713d30a59bSDaniel Vetter plane->old_fb = NULL; 2372731cce48SDaniel Vetter } 23738cf5c917SJesse Barnes goto out; 23748cf5c917SJesse Barnes } 23758cf5c917SJesse Barnes 23767f994f3fSMatt Roper /* Check whether this plane is usable on this CRTC */ 23777f994f3fSMatt Roper if (!(plane->possible_crtcs & drm_crtc_mask(crtc))) { 23787f994f3fSMatt Roper DRM_DEBUG_KMS("Invalid crtc for plane\n"); 23797f994f3fSMatt Roper ret = -EINVAL; 23807f994f3fSMatt Roper goto out; 23817f994f3fSMatt Roper } 23827f994f3fSMatt Roper 238362443be6SVille Syrjälä /* Check whether this plane supports the fb pixel format. */ 2384ead8610dSLaurent Pinchart ret = drm_plane_check_pixel_format(plane, fb->pixel_format); 2385ead8610dSLaurent Pinchart if (ret) { 23866ba6d03eSVille Syrjälä DRM_DEBUG_KMS("Invalid pixel format %s\n", 23876ba6d03eSVille Syrjälä drm_get_format_name(fb->pixel_format)); 238862443be6SVille Syrjälä goto out; 238962443be6SVille Syrjälä } 239062443be6SVille Syrjälä 23913968be94SMatt Roper /* Give drivers some help against integer overflows */ 23923968be94SMatt Roper if (crtc_w > INT_MAX || 23933968be94SMatt Roper crtc_x > INT_MAX - (int32_t) crtc_w || 23943968be94SMatt Roper crtc_h > INT_MAX || 23953968be94SMatt Roper crtc_y > INT_MAX - (int32_t) crtc_h) { 23963968be94SMatt Roper DRM_DEBUG_KMS("Invalid CRTC coordinates %ux%u+%d+%d\n", 23973968be94SMatt Roper crtc_w, crtc_h, crtc_x, crtc_y); 2398c390eed0SVille Syrjälä ret = -ERANGE; 239942ef8789SVille Syrjälä goto out; 240042ef8789SVille Syrjälä } 240142ef8789SVille Syrjälä 2402ce8d9eccSVille Syrjälä ret = check_src_coords(src_x, src_y, src_w, src_h, fb); 2403ce8d9eccSVille Syrjälä if (ret) 2404f453ba04SDave Airlie goto out; 2405f453ba04SDave Airlie 24063d30a59bSDaniel Vetter plane->old_fb = plane->fb; 2407f453ba04SDave Airlie ret = plane->funcs->update_plane(plane, crtc, fb, 2408b36552b3SMatt Roper crtc_x, crtc_y, crtc_w, crtc_h, 2409b36552b3SMatt Roper src_x, src_y, src_w, src_h); 2410f453ba04SDave Airlie if (!ret) { 2411f453ba04SDave Airlie plane->crtc = crtc; 2412f453ba04SDave Airlie plane->fb = fb; 241335f8badcSDaniel Vetter fb = NULL; 24140fe27f06SDaniel Vetter } else { 24153d30a59bSDaniel Vetter plane->old_fb = NULL; 2416f453ba04SDave Airlie } 2417f453ba04SDave Airlie 2418f453ba04SDave Airlie out: 24196c2a7532SDaniel Vetter if (fb) 24206c2a7532SDaniel Vetter drm_framebuffer_unreference(fb); 24213d30a59bSDaniel Vetter if (plane->old_fb) 24223d30a59bSDaniel Vetter drm_framebuffer_unreference(plane->old_fb); 24233d30a59bSDaniel Vetter plane->old_fb = NULL; 2424f453ba04SDave Airlie 2425f453ba04SDave Airlie return ret; 2426f2b50c11SDaniel Vetter } 2427b36552b3SMatt Roper 2428f2b50c11SDaniel Vetter static int setplane_internal(struct drm_plane *plane, 2429f2b50c11SDaniel Vetter struct drm_crtc *crtc, 2430f2b50c11SDaniel Vetter struct drm_framebuffer *fb, 2431f2b50c11SDaniel Vetter int32_t crtc_x, int32_t crtc_y, 2432f2b50c11SDaniel Vetter uint32_t crtc_w, uint32_t crtc_h, 2433f2b50c11SDaniel Vetter /* src_{x,y,w,h} values are 16.16 fixed point */ 2434f2b50c11SDaniel Vetter uint32_t src_x, uint32_t src_y, 2435f2b50c11SDaniel Vetter uint32_t src_w, uint32_t src_h) 2436f2b50c11SDaniel Vetter { 2437f2b50c11SDaniel Vetter int ret; 2438f2b50c11SDaniel Vetter 2439f2b50c11SDaniel Vetter drm_modeset_lock_all(plane->dev); 2440f2b50c11SDaniel Vetter ret = __setplane_internal(plane, crtc, fb, 2441f2b50c11SDaniel Vetter crtc_x, crtc_y, crtc_w, crtc_h, 2442f2b50c11SDaniel Vetter src_x, src_y, src_w, src_h); 2443f2b50c11SDaniel Vetter drm_modeset_unlock_all(plane->dev); 2444f2b50c11SDaniel Vetter 2445f2b50c11SDaniel Vetter return ret; 2446b36552b3SMatt Roper } 2447b36552b3SMatt Roper 2448b36552b3SMatt Roper /** 2449b36552b3SMatt Roper * drm_mode_setplane - configure a plane's configuration 2450b36552b3SMatt Roper * @dev: DRM device 2451b36552b3SMatt Roper * @data: ioctl data* 2452b36552b3SMatt Roper * @file_priv: DRM file info 2453b36552b3SMatt Roper * 2454b36552b3SMatt Roper * Set plane configuration, including placement, fb, scaling, and other factors. 2455b36552b3SMatt Roper * Or pass a NULL fb to disable (planes may be disabled without providing a 2456b36552b3SMatt Roper * valid crtc). 2457b36552b3SMatt Roper * 2458b36552b3SMatt Roper * Returns: 24591a498633SDaniel Vetter * Zero on success, negative errno on failure. 2460b36552b3SMatt Roper */ 2461b36552b3SMatt Roper int drm_mode_setplane(struct drm_device *dev, void *data, 2462b36552b3SMatt Roper struct drm_file *file_priv) 2463b36552b3SMatt Roper { 2464b36552b3SMatt Roper struct drm_mode_set_plane *plane_req = data; 2465b36552b3SMatt Roper struct drm_plane *plane; 2466b36552b3SMatt Roper struct drm_crtc *crtc = NULL; 2467b36552b3SMatt Roper struct drm_framebuffer *fb = NULL; 2468b36552b3SMatt Roper 2469b36552b3SMatt Roper if (!drm_core_check_feature(dev, DRIVER_MODESET)) 2470b36552b3SMatt Roper return -EINVAL; 2471b36552b3SMatt Roper 2472b36552b3SMatt Roper /* 2473b36552b3SMatt Roper * First, find the plane, crtc, and fb objects. If not available, 2474b36552b3SMatt Roper * we don't bother to call the driver. 2475b36552b3SMatt Roper */ 2476933f622fSRob Clark plane = drm_plane_find(dev, plane_req->plane_id); 2477933f622fSRob Clark if (!plane) { 2478b36552b3SMatt Roper DRM_DEBUG_KMS("Unknown plane ID %d\n", 2479b36552b3SMatt Roper plane_req->plane_id); 2480b36552b3SMatt Roper return -ENOENT; 2481b36552b3SMatt Roper } 2482b36552b3SMatt Roper 2483b36552b3SMatt Roper if (plane_req->fb_id) { 2484b36552b3SMatt Roper fb = drm_framebuffer_lookup(dev, plane_req->fb_id); 2485b36552b3SMatt Roper if (!fb) { 2486b36552b3SMatt Roper DRM_DEBUG_KMS("Unknown framebuffer ID %d\n", 2487b36552b3SMatt Roper plane_req->fb_id); 2488b36552b3SMatt Roper return -ENOENT; 2489b36552b3SMatt Roper } 2490b36552b3SMatt Roper 2491933f622fSRob Clark crtc = drm_crtc_find(dev, plane_req->crtc_id); 2492933f622fSRob Clark if (!crtc) { 2493b36552b3SMatt Roper DRM_DEBUG_KMS("Unknown crtc ID %d\n", 2494b36552b3SMatt Roper plane_req->crtc_id); 2495b36552b3SMatt Roper return -ENOENT; 2496b36552b3SMatt Roper } 2497b36552b3SMatt Roper } 2498b36552b3SMatt Roper 2499161d0dc1SMatt Roper /* 2500161d0dc1SMatt Roper * setplane_internal will take care of deref'ing either the old or new 2501161d0dc1SMatt Roper * framebuffer depending on success. 2502161d0dc1SMatt Roper */ 250317cfd91fSChris Wilson return setplane_internal(plane, crtc, fb, 2504b36552b3SMatt Roper plane_req->crtc_x, plane_req->crtc_y, 2505b36552b3SMatt Roper plane_req->crtc_w, plane_req->crtc_h, 2506b36552b3SMatt Roper plane_req->src_x, plane_req->src_y, 2507b36552b3SMatt Roper plane_req->src_w, plane_req->src_h); 2508f453ba04SDave Airlie } 2509f453ba04SDave Airlie 2510f453ba04SDave Airlie /** 25112d13b679SDaniel Vetter * drm_mode_set_config_internal - helper to call ->set_config 25122d13b679SDaniel Vetter * @set: modeset config to set 25132d13b679SDaniel Vetter * 25142d13b679SDaniel Vetter * This is a little helper to wrap internal calls to the ->set_config driver 25152d13b679SDaniel Vetter * interface. The only thing it adds is correct refcounting dance. 2516c8e32cc1SDaniel Vetter * 2517c8e32cc1SDaniel Vetter * Returns: 25181a498633SDaniel Vetter * Zero on success, negative errno on failure. 25192d13b679SDaniel Vetter */ 25202d13b679SDaniel Vetter int drm_mode_set_config_internal(struct drm_mode_set *set) 25212d13b679SDaniel Vetter { 25222d13b679SDaniel Vetter struct drm_crtc *crtc = set->crtc; 25235cef29aaSDaniel Vetter struct drm_framebuffer *fb; 25245cef29aaSDaniel Vetter struct drm_crtc *tmp; 2525b0d12325SDaniel Vetter int ret; 25262d13b679SDaniel Vetter 25275cef29aaSDaniel Vetter /* 25285cef29aaSDaniel Vetter * NOTE: ->set_config can also disable other crtcs (if we steal all 25295cef29aaSDaniel Vetter * connectors from it), hence we need to refcount the fbs across all 25305cef29aaSDaniel Vetter * crtcs. Atomic modeset will have saner semantics ... 25315cef29aaSDaniel Vetter */ 2532e4f62546SDaniel Vetter drm_for_each_crtc(tmp, crtc->dev) 25333d30a59bSDaniel Vetter tmp->primary->old_fb = tmp->primary->fb; 25345cef29aaSDaniel Vetter 2535b0d12325SDaniel Vetter fb = set->fb; 2536b0d12325SDaniel Vetter 2537b0d12325SDaniel Vetter ret = crtc->funcs->set_config(set); 2538b0d12325SDaniel Vetter if (ret == 0) { 2539e13161afSMatt Roper crtc->primary->crtc = crtc; 25400fe27f06SDaniel Vetter crtc->primary->fb = fb; 25415cef29aaSDaniel Vetter } 2542cc85e121SDaniel Vetter 2543e4f62546SDaniel Vetter drm_for_each_crtc(tmp, crtc->dev) { 2544f4510a27SMatt Roper if (tmp->primary->fb) 2545f4510a27SMatt Roper drm_framebuffer_reference(tmp->primary->fb); 25463d30a59bSDaniel Vetter if (tmp->primary->old_fb) 25473d30a59bSDaniel Vetter drm_framebuffer_unreference(tmp->primary->old_fb); 25483d30a59bSDaniel Vetter tmp->primary->old_fb = NULL; 2549b0d12325SDaniel Vetter } 2550b0d12325SDaniel Vetter 2551b0d12325SDaniel Vetter return ret; 25522d13b679SDaniel Vetter } 25532d13b679SDaniel Vetter EXPORT_SYMBOL(drm_mode_set_config_internal); 25542d13b679SDaniel Vetter 2555af93629dSMatt Roper /** 2556ecb7e16bSGustavo Padovan * drm_crtc_get_hv_timing - Fetches hdisplay/vdisplay for given mode 2557ecb7e16bSGustavo Padovan * @mode: mode to query 2558ecb7e16bSGustavo Padovan * @hdisplay: hdisplay value to fill in 2559ecb7e16bSGustavo Padovan * @vdisplay: vdisplay value to fill in 2560ecb7e16bSGustavo Padovan * 2561ecb7e16bSGustavo Padovan * The vdisplay value will be doubled if the specified mode is a stereo mode of 2562ecb7e16bSGustavo Padovan * the appropriate layout. 2563ecb7e16bSGustavo Padovan */ 2564ecb7e16bSGustavo Padovan void drm_crtc_get_hv_timing(const struct drm_display_mode *mode, 2565ecb7e16bSGustavo Padovan int *hdisplay, int *vdisplay) 2566ecb7e16bSGustavo Padovan { 2567ecb7e16bSGustavo Padovan struct drm_display_mode adjusted; 2568ecb7e16bSGustavo Padovan 2569ecb7e16bSGustavo Padovan drm_mode_copy(&adjusted, mode); 2570ecb7e16bSGustavo Padovan drm_mode_set_crtcinfo(&adjusted, CRTC_STEREO_DOUBLE_ONLY); 2571ecb7e16bSGustavo Padovan *hdisplay = adjusted.crtc_hdisplay; 2572ecb7e16bSGustavo Padovan *vdisplay = adjusted.crtc_vdisplay; 2573ecb7e16bSGustavo Padovan } 2574ecb7e16bSGustavo Padovan EXPORT_SYMBOL(drm_crtc_get_hv_timing); 2575ecb7e16bSGustavo Padovan 2576ecb7e16bSGustavo Padovan /** 2577af93629dSMatt Roper * drm_crtc_check_viewport - Checks that a framebuffer is big enough for the 2578af93629dSMatt Roper * CRTC viewport 2579af93629dSMatt Roper * @crtc: CRTC that framebuffer will be displayed on 2580af93629dSMatt Roper * @x: x panning 2581af93629dSMatt Roper * @y: y panning 2582af93629dSMatt Roper * @mode: mode that framebuffer will be displayed under 2583af93629dSMatt Roper * @fb: framebuffer to check size of 2584c11e9283SDamien Lespiau */ 2585af93629dSMatt Roper int drm_crtc_check_viewport(const struct drm_crtc *crtc, 2586c11e9283SDamien Lespiau int x, int y, 2587c11e9283SDamien Lespiau const struct drm_display_mode *mode, 2588c11e9283SDamien Lespiau const struct drm_framebuffer *fb) 2589c11e9283SDamien Lespiau 2590c11e9283SDamien Lespiau { 2591c11e9283SDamien Lespiau int hdisplay, vdisplay; 2592c11e9283SDamien Lespiau 2593ecb7e16bSGustavo Padovan drm_crtc_get_hv_timing(mode, &hdisplay, &vdisplay); 2594a0c1bbb0SDamien Lespiau 259533e0be63SVille Syrjälä if (crtc->state && 259633e0be63SVille Syrjälä crtc->primary->state->rotation & (BIT(DRM_ROTATE_90) | 259733e0be63SVille Syrjälä BIT(DRM_ROTATE_270))) 2598c11e9283SDamien Lespiau swap(hdisplay, vdisplay); 2599c11e9283SDamien Lespiau 2600ce8d9eccSVille Syrjälä return check_src_coords(x << 16, y << 16, 2601ce8d9eccSVille Syrjälä hdisplay << 16, vdisplay << 16, fb); 2602c11e9283SDamien Lespiau } 2603af93629dSMatt Roper EXPORT_SYMBOL(drm_crtc_check_viewport); 2604c11e9283SDamien Lespiau 26052d13b679SDaniel Vetter /** 2606f453ba04SDave Airlie * drm_mode_setcrtc - set CRTC configuration 2607065a50edSDaniel Vetter * @dev: drm device for the ioctl 2608065a50edSDaniel Vetter * @data: data pointer for the ioctl 2609065a50edSDaniel Vetter * @file_priv: drm file for the ioctl call 2610f453ba04SDave Airlie * 2611f453ba04SDave Airlie * Build a new CRTC configuration based on user request. 2612f453ba04SDave Airlie * 2613f453ba04SDave Airlie * Called by the user via ioctl. 2614f453ba04SDave Airlie * 2615c8e32cc1SDaniel Vetter * Returns: 26161a498633SDaniel Vetter * Zero on success, negative errno on failure. 2617f453ba04SDave Airlie */ 2618f453ba04SDave Airlie int drm_mode_setcrtc(struct drm_device *dev, void *data, 2619f453ba04SDave Airlie struct drm_file *file_priv) 2620f453ba04SDave Airlie { 2621f453ba04SDave Airlie struct drm_mode_config *config = &dev->mode_config; 2622f453ba04SDave Airlie struct drm_mode_crtc *crtc_req = data; 26236653cc8dSVille Syrjälä struct drm_crtc *crtc; 2624f453ba04SDave Airlie struct drm_connector **connector_set = NULL, *connector; 2625f453ba04SDave Airlie struct drm_framebuffer *fb = NULL; 2626f453ba04SDave Airlie struct drm_display_mode *mode = NULL; 2627f453ba04SDave Airlie struct drm_mode_set set; 2628f453ba04SDave Airlie uint32_t __user *set_connectors_ptr; 26294a1b0714SLaurent Pinchart int ret; 2630f453ba04SDave Airlie int i; 2631f453ba04SDave Airlie 2632fb3b06c8SDave Airlie if (!drm_core_check_feature(dev, DRIVER_MODESET)) 2633fb3b06c8SDave Airlie return -EINVAL; 2634fb3b06c8SDave Airlie 263501447e9fSZhao Junwang /* 263601447e9fSZhao Junwang * Universal plane src offsets are only 16.16, prevent havoc for 263701447e9fSZhao Junwang * drivers using universal plane code internally. 263801447e9fSZhao Junwang */ 263901447e9fSZhao Junwang if (crtc_req->x & 0xffff0000 || crtc_req->y & 0xffff0000) 26401d97e915SVille Syrjälä return -ERANGE; 26411d97e915SVille Syrjälä 264284849903SDaniel Vetter drm_modeset_lock_all(dev); 2643a2b34e22SRob Clark crtc = drm_crtc_find(dev, crtc_req->crtc_id); 2644a2b34e22SRob Clark if (!crtc) { 264558367ed6SZhao Yakui DRM_DEBUG_KMS("Unknown CRTC ID %d\n", crtc_req->crtc_id); 2646f27657f2SVille Syrjälä ret = -ENOENT; 2647f453ba04SDave Airlie goto out; 2648f453ba04SDave Airlie } 26499440106bSJerome Glisse DRM_DEBUG_KMS("[CRTC:%d]\n", crtc->base.id); 2650f453ba04SDave Airlie 2651f453ba04SDave Airlie if (crtc_req->mode_valid) { 2652f453ba04SDave Airlie /* If we have a mode we need a framebuffer. */ 2653f453ba04SDave Airlie /* If we pass -1, set the mode with the currently bound fb */ 2654f453ba04SDave Airlie if (crtc_req->fb_id == -1) { 2655f4510a27SMatt Roper if (!crtc->primary->fb) { 26566653cc8dSVille Syrjälä DRM_DEBUG_KMS("CRTC doesn't have current FB\n"); 26576653cc8dSVille Syrjälä ret = -EINVAL; 26586653cc8dSVille Syrjälä goto out; 26596653cc8dSVille Syrjälä } 2660f4510a27SMatt Roper fb = crtc->primary->fb; 2661b0d12325SDaniel Vetter /* Make refcounting symmetric with the lookup path. */ 2662b0d12325SDaniel Vetter drm_framebuffer_reference(fb); 2663f453ba04SDave Airlie } else { 2664786b99edSDaniel Vetter fb = drm_framebuffer_lookup(dev, crtc_req->fb_id); 2665786b99edSDaniel Vetter if (!fb) { 266658367ed6SZhao Yakui DRM_DEBUG_KMS("Unknown FB ID%d\n", 266758367ed6SZhao Yakui crtc_req->fb_id); 266837c4e705SVille Syrjälä ret = -ENOENT; 2669f453ba04SDave Airlie goto out; 2670f453ba04SDave Airlie } 2671f453ba04SDave Airlie } 2672f453ba04SDave Airlie 2673f453ba04SDave Airlie mode = drm_mode_create(dev); 2674ee34ab5bSVille Syrjälä if (!mode) { 2675ee34ab5bSVille Syrjälä ret = -ENOMEM; 2676ee34ab5bSVille Syrjälä goto out; 2677ee34ab5bSVille Syrjälä } 2678ee34ab5bSVille Syrjälä 2679934a8a89SDaniel Stone ret = drm_mode_convert_umode(mode, &crtc_req->mode); 268090367bf6SVille Syrjälä if (ret) { 268190367bf6SVille Syrjälä DRM_DEBUG_KMS("Invalid mode\n"); 268290367bf6SVille Syrjälä goto out; 268390367bf6SVille Syrjälä } 268490367bf6SVille Syrjälä 2685f453ba04SDave Airlie drm_mode_set_crtcinfo(mode, CRTC_INTERLACE_HALVE_V); 26865f61bb42SVille Syrjälä 26877eb5f302SLaurent Pinchart /* 26887eb5f302SLaurent Pinchart * Check whether the primary plane supports the fb pixel format. 26897eb5f302SLaurent Pinchart * Drivers not implementing the universal planes API use a 26907eb5f302SLaurent Pinchart * default formats list provided by the DRM core which doesn't 26917eb5f302SLaurent Pinchart * match real hardware capabilities. Skip the check in that 26927eb5f302SLaurent Pinchart * case. 26937eb5f302SLaurent Pinchart */ 26947eb5f302SLaurent Pinchart if (!crtc->primary->format_default) { 26957eb5f302SLaurent Pinchart ret = drm_plane_check_pixel_format(crtc->primary, 26967eb5f302SLaurent Pinchart fb->pixel_format); 26977eb5f302SLaurent Pinchart if (ret) { 26987eb5f302SLaurent Pinchart DRM_DEBUG_KMS("Invalid pixel format %s\n", 26997eb5f302SLaurent Pinchart drm_get_format_name(fb->pixel_format)); 27007eb5f302SLaurent Pinchart goto out; 27017eb5f302SLaurent Pinchart } 27027eb5f302SLaurent Pinchart } 27037eb5f302SLaurent Pinchart 2704c11e9283SDamien Lespiau ret = drm_crtc_check_viewport(crtc, crtc_req->x, crtc_req->y, 2705c11e9283SDamien Lespiau mode, fb); 2706c11e9283SDamien Lespiau if (ret) 27075f61bb42SVille Syrjälä goto out; 2708c11e9283SDamien Lespiau 2709f453ba04SDave Airlie } 2710f453ba04SDave Airlie 2711f453ba04SDave Airlie if (crtc_req->count_connectors == 0 && mode) { 271258367ed6SZhao Yakui DRM_DEBUG_KMS("Count connectors is 0 but mode set\n"); 2713f453ba04SDave Airlie ret = -EINVAL; 2714f453ba04SDave Airlie goto out; 2715f453ba04SDave Airlie } 2716f453ba04SDave Airlie 27177781de74SJakob Bornecrantz if (crtc_req->count_connectors > 0 && (!mode || !fb)) { 271858367ed6SZhao Yakui DRM_DEBUG_KMS("Count connectors is %d but no mode or fb set\n", 2719f453ba04SDave Airlie crtc_req->count_connectors); 2720f453ba04SDave Airlie ret = -EINVAL; 2721f453ba04SDave Airlie goto out; 2722f453ba04SDave Airlie } 2723f453ba04SDave Airlie 2724f453ba04SDave Airlie if (crtc_req->count_connectors > 0) { 2725f453ba04SDave Airlie u32 out_id; 2726f453ba04SDave Airlie 2727f453ba04SDave Airlie /* Avoid unbounded kernel memory allocation */ 2728f453ba04SDave Airlie if (crtc_req->count_connectors > config->num_connector) { 2729f453ba04SDave Airlie ret = -EINVAL; 2730f453ba04SDave Airlie goto out; 2731f453ba04SDave Airlie } 2732f453ba04SDave Airlie 27332f6c5389SThierry Reding connector_set = kmalloc_array(crtc_req->count_connectors, 2734f453ba04SDave Airlie sizeof(struct drm_connector *), 2735f453ba04SDave Airlie GFP_KERNEL); 2736f453ba04SDave Airlie if (!connector_set) { 2737f453ba04SDave Airlie ret = -ENOMEM; 2738f453ba04SDave Airlie goto out; 2739f453ba04SDave Airlie } 2740f453ba04SDave Airlie 2741f453ba04SDave Airlie for (i = 0; i < crtc_req->count_connectors; i++) { 274281f6c7f8SVille Syrjälä set_connectors_ptr = (uint32_t __user *)(unsigned long)crtc_req->set_connectors_ptr; 2743f453ba04SDave Airlie if (get_user(out_id, &set_connectors_ptr[i])) { 2744f453ba04SDave Airlie ret = -EFAULT; 2745f453ba04SDave Airlie goto out; 2746f453ba04SDave Airlie } 2747f453ba04SDave Airlie 2748a2b34e22SRob Clark connector = drm_connector_find(dev, out_id); 2749a2b34e22SRob Clark if (!connector) { 275058367ed6SZhao Yakui DRM_DEBUG_KMS("Connector id %d unknown\n", 275158367ed6SZhao Yakui out_id); 2752f27657f2SVille Syrjälä ret = -ENOENT; 2753f453ba04SDave Airlie goto out; 2754f453ba04SDave Airlie } 27559440106bSJerome Glisse DRM_DEBUG_KMS("[CONNECTOR:%d:%s]\n", 27569440106bSJerome Glisse connector->base.id, 275725933820SJani Nikula connector->name); 2758f453ba04SDave Airlie 2759f453ba04SDave Airlie connector_set[i] = connector; 2760f453ba04SDave Airlie } 2761f453ba04SDave Airlie } 2762f453ba04SDave Airlie 2763f453ba04SDave Airlie set.crtc = crtc; 2764f453ba04SDave Airlie set.x = crtc_req->x; 2765f453ba04SDave Airlie set.y = crtc_req->y; 2766f453ba04SDave Airlie set.mode = mode; 2767f453ba04SDave Airlie set.connectors = connector_set; 2768f453ba04SDave Airlie set.num_connectors = crtc_req->count_connectors; 2769f453ba04SDave Airlie set.fb = fb; 27702d13b679SDaniel Vetter ret = drm_mode_set_config_internal(&set); 2771f453ba04SDave Airlie 2772f453ba04SDave Airlie out: 2773b0d12325SDaniel Vetter if (fb) 2774b0d12325SDaniel Vetter drm_framebuffer_unreference(fb); 2775b0d12325SDaniel Vetter 2776f453ba04SDave Airlie kfree(connector_set); 2777ee34ab5bSVille Syrjälä drm_mode_destroy(dev, mode); 277884849903SDaniel Vetter drm_modeset_unlock_all(dev); 2779f453ba04SDave Airlie return ret; 2780f453ba04SDave Airlie } 2781f453ba04SDave Airlie 2782161d0dc1SMatt Roper /** 2783161d0dc1SMatt Roper * drm_mode_cursor_universal - translate legacy cursor ioctl call into a 2784161d0dc1SMatt Roper * universal plane handler call 2785161d0dc1SMatt Roper * @crtc: crtc to update cursor for 2786161d0dc1SMatt Roper * @req: data pointer for the ioctl 2787161d0dc1SMatt Roper * @file_priv: drm file for the ioctl call 2788161d0dc1SMatt Roper * 2789161d0dc1SMatt Roper * Legacy cursor ioctl's work directly with driver buffer handles. To 2790161d0dc1SMatt Roper * translate legacy ioctl calls into universal plane handler calls, we need to 2791161d0dc1SMatt Roper * wrap the native buffer handle in a drm_framebuffer. 2792161d0dc1SMatt Roper * 2793161d0dc1SMatt Roper * Note that we assume any handle passed to the legacy ioctls was a 32-bit ARGB 2794161d0dc1SMatt Roper * buffer with a pitch of 4*width; the universal plane interface should be used 2795161d0dc1SMatt Roper * directly in cases where the hardware can support other buffer settings and 2796161d0dc1SMatt Roper * userspace wants to make use of these capabilities. 2797161d0dc1SMatt Roper * 2798161d0dc1SMatt Roper * Returns: 27991a498633SDaniel Vetter * Zero on success, negative errno on failure. 2800161d0dc1SMatt Roper */ 2801161d0dc1SMatt Roper static int drm_mode_cursor_universal(struct drm_crtc *crtc, 2802161d0dc1SMatt Roper struct drm_mode_cursor2 *req, 2803161d0dc1SMatt Roper struct drm_file *file_priv) 2804161d0dc1SMatt Roper { 2805161d0dc1SMatt Roper struct drm_device *dev = crtc->dev; 2806161d0dc1SMatt Roper struct drm_framebuffer *fb = NULL; 2807161d0dc1SMatt Roper struct drm_mode_fb_cmd2 fbreq = { 2808161d0dc1SMatt Roper .width = req->width, 2809161d0dc1SMatt Roper .height = req->height, 2810161d0dc1SMatt Roper .pixel_format = DRM_FORMAT_ARGB8888, 2811161d0dc1SMatt Roper .pitches = { req->width * 4 }, 2812161d0dc1SMatt Roper .handles = { req->handle }, 2813161d0dc1SMatt Roper }; 2814161d0dc1SMatt Roper int32_t crtc_x, crtc_y; 2815161d0dc1SMatt Roper uint32_t crtc_w = 0, crtc_h = 0; 2816161d0dc1SMatt Roper uint32_t src_w = 0, src_h = 0; 2817161d0dc1SMatt Roper int ret = 0; 2818161d0dc1SMatt Roper 2819161d0dc1SMatt Roper BUG_ON(!crtc->cursor); 2820f2b50c11SDaniel Vetter WARN_ON(crtc->cursor->crtc != crtc && crtc->cursor->crtc != NULL); 2821161d0dc1SMatt Roper 2822161d0dc1SMatt Roper /* 2823161d0dc1SMatt Roper * Obtain fb we'll be using (either new or existing) and take an extra 2824161d0dc1SMatt Roper * reference to it if fb != null. setplane will take care of dropping 2825161d0dc1SMatt Roper * the reference if the plane update fails. 2826161d0dc1SMatt Roper */ 2827161d0dc1SMatt Roper if (req->flags & DRM_MODE_CURSOR_BO) { 2828161d0dc1SMatt Roper if (req->handle) { 28299a6f5130SChris Wilson fb = internal_framebuffer_create(dev, &fbreq, file_priv); 2830161d0dc1SMatt Roper if (IS_ERR(fb)) { 2831161d0dc1SMatt Roper DRM_DEBUG_KMS("failed to wrap cursor buffer in drm framebuffer\n"); 2832161d0dc1SMatt Roper return PTR_ERR(fb); 2833161d0dc1SMatt Roper } 2834161d0dc1SMatt Roper } else { 2835161d0dc1SMatt Roper fb = NULL; 2836161d0dc1SMatt Roper } 2837161d0dc1SMatt Roper } else { 2838161d0dc1SMatt Roper fb = crtc->cursor->fb; 2839161d0dc1SMatt Roper if (fb) 2840161d0dc1SMatt Roper drm_framebuffer_reference(fb); 2841161d0dc1SMatt Roper } 2842161d0dc1SMatt Roper 2843161d0dc1SMatt Roper if (req->flags & DRM_MODE_CURSOR_MOVE) { 2844161d0dc1SMatt Roper crtc_x = req->x; 2845161d0dc1SMatt Roper crtc_y = req->y; 2846161d0dc1SMatt Roper } else { 2847161d0dc1SMatt Roper crtc_x = crtc->cursor_x; 2848161d0dc1SMatt Roper crtc_y = crtc->cursor_y; 2849161d0dc1SMatt Roper } 2850161d0dc1SMatt Roper 2851161d0dc1SMatt Roper if (fb) { 2852161d0dc1SMatt Roper crtc_w = fb->width; 2853161d0dc1SMatt Roper crtc_h = fb->height; 2854161d0dc1SMatt Roper src_w = fb->width << 16; 2855161d0dc1SMatt Roper src_h = fb->height << 16; 2856161d0dc1SMatt Roper } 2857161d0dc1SMatt Roper 2858161d0dc1SMatt Roper /* 2859161d0dc1SMatt Roper * setplane_internal will take care of deref'ing either the old or new 2860161d0dc1SMatt Roper * framebuffer depending on success. 2861161d0dc1SMatt Roper */ 2862f2b50c11SDaniel Vetter ret = __setplane_internal(crtc->cursor, crtc, fb, 2863161d0dc1SMatt Roper crtc_x, crtc_y, crtc_w, crtc_h, 2864161d0dc1SMatt Roper 0, 0, src_w, src_h); 2865161d0dc1SMatt Roper 2866161d0dc1SMatt Roper /* Update successful; save new cursor position, if necessary */ 2867161d0dc1SMatt Roper if (ret == 0 && req->flags & DRM_MODE_CURSOR_MOVE) { 2868161d0dc1SMatt Roper crtc->cursor_x = req->x; 2869161d0dc1SMatt Roper crtc->cursor_y = req->y; 2870161d0dc1SMatt Roper } 2871161d0dc1SMatt Roper 2872161d0dc1SMatt Roper return ret; 2873161d0dc1SMatt Roper } 2874161d0dc1SMatt Roper 28754c813d4dSDave Airlie static int drm_mode_cursor_common(struct drm_device *dev, 28764c813d4dSDave Airlie struct drm_mode_cursor2 *req, 28774c813d4dSDave Airlie struct drm_file *file_priv) 2878f453ba04SDave Airlie { 2879f453ba04SDave Airlie struct drm_crtc *crtc; 2880f453ba04SDave Airlie int ret = 0; 2881f453ba04SDave Airlie 2882fb3b06c8SDave Airlie if (!drm_core_check_feature(dev, DRIVER_MODESET)) 2883fb3b06c8SDave Airlie return -EINVAL; 2884fb3b06c8SDave Airlie 28857c4eaca4SJakob Bornecrantz if (!req->flags || (~DRM_MODE_CURSOR_FLAGS & req->flags)) 2886f453ba04SDave Airlie return -EINVAL; 2887f453ba04SDave Airlie 2888a2b34e22SRob Clark crtc = drm_crtc_find(dev, req->crtc_id); 2889a2b34e22SRob Clark if (!crtc) { 289058367ed6SZhao Yakui DRM_DEBUG_KMS("Unknown CRTC ID %d\n", req->crtc_id); 2891f27657f2SVille Syrjälä return -ENOENT; 2892f453ba04SDave Airlie } 2893f453ba04SDave Airlie 2894161d0dc1SMatt Roper /* 2895161d0dc1SMatt Roper * If this crtc has a universal cursor plane, call that plane's update 2896161d0dc1SMatt Roper * handler rather than using legacy cursor handlers. 2897161d0dc1SMatt Roper */ 28984d02e2deSDaniel Vetter drm_modeset_lock_crtc(crtc, crtc->cursor); 2899f2b50c11SDaniel Vetter if (crtc->cursor) { 2900f2b50c11SDaniel Vetter ret = drm_mode_cursor_universal(crtc, req, file_priv); 2901f2b50c11SDaniel Vetter goto out; 2902f2b50c11SDaniel Vetter } 2903f2b50c11SDaniel Vetter 2904f453ba04SDave Airlie if (req->flags & DRM_MODE_CURSOR_BO) { 29054c813d4dSDave Airlie if (!crtc->funcs->cursor_set && !crtc->funcs->cursor_set2) { 2906f453ba04SDave Airlie ret = -ENXIO; 2907f453ba04SDave Airlie goto out; 2908f453ba04SDave Airlie } 2909f453ba04SDave Airlie /* Turns off the cursor if handle is 0 */ 29104c813d4dSDave Airlie if (crtc->funcs->cursor_set2) 29114c813d4dSDave Airlie ret = crtc->funcs->cursor_set2(crtc, file_priv, req->handle, 29124c813d4dSDave Airlie req->width, req->height, req->hot_x, req->hot_y); 29134c813d4dSDave Airlie else 2914f453ba04SDave Airlie ret = crtc->funcs->cursor_set(crtc, file_priv, req->handle, 2915f453ba04SDave Airlie req->width, req->height); 2916f453ba04SDave Airlie } 2917f453ba04SDave Airlie 2918f453ba04SDave Airlie if (req->flags & DRM_MODE_CURSOR_MOVE) { 2919f453ba04SDave Airlie if (crtc->funcs->cursor_move) { 2920f453ba04SDave Airlie ret = crtc->funcs->cursor_move(crtc, req->x, req->y); 2921f453ba04SDave Airlie } else { 2922f453ba04SDave Airlie ret = -EFAULT; 2923f453ba04SDave Airlie goto out; 2924f453ba04SDave Airlie } 2925f453ba04SDave Airlie } 2926f453ba04SDave Airlie out: 2927d059f652SDaniel Vetter drm_modeset_unlock_crtc(crtc); 2928dac35663SDaniel Vetter 2929f453ba04SDave Airlie return ret; 29304c813d4dSDave Airlie 29314c813d4dSDave Airlie } 2932c8e32cc1SDaniel Vetter 2933c8e32cc1SDaniel Vetter 2934c8e32cc1SDaniel Vetter /** 2935c8e32cc1SDaniel Vetter * drm_mode_cursor_ioctl - set CRTC's cursor configuration 2936c8e32cc1SDaniel Vetter * @dev: drm device for the ioctl 2937c8e32cc1SDaniel Vetter * @data: data pointer for the ioctl 2938c8e32cc1SDaniel Vetter * @file_priv: drm file for the ioctl call 2939c8e32cc1SDaniel Vetter * 2940c8e32cc1SDaniel Vetter * Set the cursor configuration based on user request. 2941c8e32cc1SDaniel Vetter * 2942c8e32cc1SDaniel Vetter * Called by the user via ioctl. 2943c8e32cc1SDaniel Vetter * 2944c8e32cc1SDaniel Vetter * Returns: 29451a498633SDaniel Vetter * Zero on success, negative errno on failure. 2946c8e32cc1SDaniel Vetter */ 29474c813d4dSDave Airlie int drm_mode_cursor_ioctl(struct drm_device *dev, 29484c813d4dSDave Airlie void *data, struct drm_file *file_priv) 29494c813d4dSDave Airlie { 29504c813d4dSDave Airlie struct drm_mode_cursor *req = data; 29514c813d4dSDave Airlie struct drm_mode_cursor2 new_req; 29524c813d4dSDave Airlie 29534c813d4dSDave Airlie memcpy(&new_req, req, sizeof(struct drm_mode_cursor)); 29544c813d4dSDave Airlie new_req.hot_x = new_req.hot_y = 0; 29554c813d4dSDave Airlie 29564c813d4dSDave Airlie return drm_mode_cursor_common(dev, &new_req, file_priv); 29574c813d4dSDave Airlie } 29584c813d4dSDave Airlie 2959c8e32cc1SDaniel Vetter /** 2960c8e32cc1SDaniel Vetter * drm_mode_cursor2_ioctl - set CRTC's cursor configuration 2961c8e32cc1SDaniel Vetter * @dev: drm device for the ioctl 2962c8e32cc1SDaniel Vetter * @data: data pointer for the ioctl 2963c8e32cc1SDaniel Vetter * @file_priv: drm file for the ioctl call 2964c8e32cc1SDaniel Vetter * 2965c8e32cc1SDaniel Vetter * Set the cursor configuration based on user request. This implements the 2nd 2966c8e32cc1SDaniel Vetter * version of the cursor ioctl, which allows userspace to additionally specify 2967c8e32cc1SDaniel Vetter * the hotspot of the pointer. 2968c8e32cc1SDaniel Vetter * 2969c8e32cc1SDaniel Vetter * Called by the user via ioctl. 2970c8e32cc1SDaniel Vetter * 2971c8e32cc1SDaniel Vetter * Returns: 29721a498633SDaniel Vetter * Zero on success, negative errno on failure. 2973c8e32cc1SDaniel Vetter */ 29744c813d4dSDave Airlie int drm_mode_cursor2_ioctl(struct drm_device *dev, 29754c813d4dSDave Airlie void *data, struct drm_file *file_priv) 29764c813d4dSDave Airlie { 29774c813d4dSDave Airlie struct drm_mode_cursor2 *req = data; 29784dfd909fSThierry Reding 29794c813d4dSDave Airlie return drm_mode_cursor_common(dev, req, file_priv); 2980f453ba04SDave Airlie } 2981f453ba04SDave Airlie 2982c8e32cc1SDaniel Vetter /** 2983c8e32cc1SDaniel Vetter * drm_mode_legacy_fb_format - compute drm fourcc code from legacy description 2984c8e32cc1SDaniel Vetter * @bpp: bits per pixels 2985c8e32cc1SDaniel Vetter * @depth: bit depth per pixel 2986c8e32cc1SDaniel Vetter * 2987c8e32cc1SDaniel Vetter * Computes a drm fourcc pixel format code for the given @bpp/@depth values. 2988c8e32cc1SDaniel Vetter * Useful in fbdev emulation code, since that deals in those values. 2989c8e32cc1SDaniel Vetter */ 2990308e5bcbSJesse Barnes uint32_t drm_mode_legacy_fb_format(uint32_t bpp, uint32_t depth) 2991308e5bcbSJesse Barnes { 2992308e5bcbSJesse Barnes uint32_t fmt; 2993308e5bcbSJesse Barnes 2994308e5bcbSJesse Barnes switch (bpp) { 2995308e5bcbSJesse Barnes case 8: 2996d84f031bSVille Syrjälä fmt = DRM_FORMAT_C8; 2997308e5bcbSJesse Barnes break; 2998308e5bcbSJesse Barnes case 16: 2999308e5bcbSJesse Barnes if (depth == 15) 300004b3924dSVille Syrjälä fmt = DRM_FORMAT_XRGB1555; 3001308e5bcbSJesse Barnes else 300204b3924dSVille Syrjälä fmt = DRM_FORMAT_RGB565; 3003308e5bcbSJesse Barnes break; 3004308e5bcbSJesse Barnes case 24: 300504b3924dSVille Syrjälä fmt = DRM_FORMAT_RGB888; 3006308e5bcbSJesse Barnes break; 3007308e5bcbSJesse Barnes case 32: 3008308e5bcbSJesse Barnes if (depth == 24) 300904b3924dSVille Syrjälä fmt = DRM_FORMAT_XRGB8888; 3010308e5bcbSJesse Barnes else if (depth == 30) 301104b3924dSVille Syrjälä fmt = DRM_FORMAT_XRGB2101010; 3012308e5bcbSJesse Barnes else 301304b3924dSVille Syrjälä fmt = DRM_FORMAT_ARGB8888; 3014308e5bcbSJesse Barnes break; 3015308e5bcbSJesse Barnes default: 301604b3924dSVille Syrjälä DRM_ERROR("bad bpp, assuming x8r8g8b8 pixel format\n"); 301704b3924dSVille Syrjälä fmt = DRM_FORMAT_XRGB8888; 3018308e5bcbSJesse Barnes break; 3019308e5bcbSJesse Barnes } 3020308e5bcbSJesse Barnes 3021308e5bcbSJesse Barnes return fmt; 3022308e5bcbSJesse Barnes } 3023308e5bcbSJesse Barnes EXPORT_SYMBOL(drm_mode_legacy_fb_format); 3024308e5bcbSJesse Barnes 3025f453ba04SDave Airlie /** 3026f453ba04SDave Airlie * drm_mode_addfb - add an FB to the graphics configuration 3027065a50edSDaniel Vetter * @dev: drm device for the ioctl 3028065a50edSDaniel Vetter * @data: data pointer for the ioctl 3029065a50edSDaniel Vetter * @file_priv: drm file for the ioctl call 3030f453ba04SDave Airlie * 3031c8e32cc1SDaniel Vetter * Add a new FB to the specified CRTC, given a user request. This is the 3032209f5527SChuck Ebbert * original addfb ioctl which only supported RGB formats. 3033f453ba04SDave Airlie * 3034f453ba04SDave Airlie * Called by the user via ioctl. 3035f453ba04SDave Airlie * 3036c8e32cc1SDaniel Vetter * Returns: 30371a498633SDaniel Vetter * Zero on success, negative errno on failure. 3038f453ba04SDave Airlie */ 3039f453ba04SDave Airlie int drm_mode_addfb(struct drm_device *dev, 3040f453ba04SDave Airlie void *data, struct drm_file *file_priv) 3041f453ba04SDave Airlie { 3042308e5bcbSJesse Barnes struct drm_mode_fb_cmd *or = data; 3043308e5bcbSJesse Barnes struct drm_mode_fb_cmd2 r = {}; 3044228f2cb3SChuck Ebbert int ret; 3045308e5bcbSJesse Barnes 3046228f2cb3SChuck Ebbert /* convert to new format and call new ioctl */ 3047308e5bcbSJesse Barnes r.fb_id = or->fb_id; 3048308e5bcbSJesse Barnes r.width = or->width; 3049308e5bcbSJesse Barnes r.height = or->height; 3050308e5bcbSJesse Barnes r.pitches[0] = or->pitch; 3051308e5bcbSJesse Barnes r.pixel_format = drm_mode_legacy_fb_format(or->bpp, or->depth); 3052308e5bcbSJesse Barnes r.handles[0] = or->handle; 3053308e5bcbSJesse Barnes 3054228f2cb3SChuck Ebbert ret = drm_mode_addfb2(dev, &r, file_priv); 3055228f2cb3SChuck Ebbert if (ret) 3056228f2cb3SChuck Ebbert return ret; 3057308e5bcbSJesse Barnes 3058228f2cb3SChuck Ebbert or->fb_id = r.fb_id; 30594b096ac1SDaniel Vetter 3060baf698b0SDaniel Vetter return 0; 3061308e5bcbSJesse Barnes } 3062308e5bcbSJesse Barnes 3063cff91b62SVille Syrjälä static int format_check(const struct drm_mode_fb_cmd2 *r) 3064935b5977SVille Syrjälä { 3065935b5977SVille Syrjälä uint32_t format = r->pixel_format & ~DRM_FORMAT_BIG_ENDIAN; 3066935b5977SVille Syrjälä 3067935b5977SVille Syrjälä switch (format) { 3068935b5977SVille Syrjälä case DRM_FORMAT_C8: 3069935b5977SVille Syrjälä case DRM_FORMAT_RGB332: 3070935b5977SVille Syrjälä case DRM_FORMAT_BGR233: 3071935b5977SVille Syrjälä case DRM_FORMAT_XRGB4444: 3072935b5977SVille Syrjälä case DRM_FORMAT_XBGR4444: 3073935b5977SVille Syrjälä case DRM_FORMAT_RGBX4444: 3074935b5977SVille Syrjälä case DRM_FORMAT_BGRX4444: 3075935b5977SVille Syrjälä case DRM_FORMAT_ARGB4444: 3076935b5977SVille Syrjälä case DRM_FORMAT_ABGR4444: 3077935b5977SVille Syrjälä case DRM_FORMAT_RGBA4444: 3078935b5977SVille Syrjälä case DRM_FORMAT_BGRA4444: 3079935b5977SVille Syrjälä case DRM_FORMAT_XRGB1555: 3080935b5977SVille Syrjälä case DRM_FORMAT_XBGR1555: 3081935b5977SVille Syrjälä case DRM_FORMAT_RGBX5551: 3082935b5977SVille Syrjälä case DRM_FORMAT_BGRX5551: 3083935b5977SVille Syrjälä case DRM_FORMAT_ARGB1555: 3084935b5977SVille Syrjälä case DRM_FORMAT_ABGR1555: 3085935b5977SVille Syrjälä case DRM_FORMAT_RGBA5551: 3086935b5977SVille Syrjälä case DRM_FORMAT_BGRA5551: 3087935b5977SVille Syrjälä case DRM_FORMAT_RGB565: 3088935b5977SVille Syrjälä case DRM_FORMAT_BGR565: 3089935b5977SVille Syrjälä case DRM_FORMAT_RGB888: 3090935b5977SVille Syrjälä case DRM_FORMAT_BGR888: 3091935b5977SVille Syrjälä case DRM_FORMAT_XRGB8888: 3092935b5977SVille Syrjälä case DRM_FORMAT_XBGR8888: 3093935b5977SVille Syrjälä case DRM_FORMAT_RGBX8888: 3094935b5977SVille Syrjälä case DRM_FORMAT_BGRX8888: 3095935b5977SVille Syrjälä case DRM_FORMAT_ARGB8888: 3096935b5977SVille Syrjälä case DRM_FORMAT_ABGR8888: 3097935b5977SVille Syrjälä case DRM_FORMAT_RGBA8888: 3098935b5977SVille Syrjälä case DRM_FORMAT_BGRA8888: 3099935b5977SVille Syrjälä case DRM_FORMAT_XRGB2101010: 3100935b5977SVille Syrjälä case DRM_FORMAT_XBGR2101010: 3101935b5977SVille Syrjälä case DRM_FORMAT_RGBX1010102: 3102935b5977SVille Syrjälä case DRM_FORMAT_BGRX1010102: 3103935b5977SVille Syrjälä case DRM_FORMAT_ARGB2101010: 3104935b5977SVille Syrjälä case DRM_FORMAT_ABGR2101010: 3105935b5977SVille Syrjälä case DRM_FORMAT_RGBA1010102: 3106935b5977SVille Syrjälä case DRM_FORMAT_BGRA1010102: 3107935b5977SVille Syrjälä case DRM_FORMAT_YUYV: 3108935b5977SVille Syrjälä case DRM_FORMAT_YVYU: 3109935b5977SVille Syrjälä case DRM_FORMAT_UYVY: 3110935b5977SVille Syrjälä case DRM_FORMAT_VYUY: 3111935b5977SVille Syrjälä case DRM_FORMAT_AYUV: 3112935b5977SVille Syrjälä case DRM_FORMAT_NV12: 3113935b5977SVille Syrjälä case DRM_FORMAT_NV21: 3114935b5977SVille Syrjälä case DRM_FORMAT_NV16: 3115935b5977SVille Syrjälä case DRM_FORMAT_NV61: 3116ba623f6aSLaurent Pinchart case DRM_FORMAT_NV24: 3117ba623f6aSLaurent Pinchart case DRM_FORMAT_NV42: 3118935b5977SVille Syrjälä case DRM_FORMAT_YUV410: 3119935b5977SVille Syrjälä case DRM_FORMAT_YVU410: 3120935b5977SVille Syrjälä case DRM_FORMAT_YUV411: 3121935b5977SVille Syrjälä case DRM_FORMAT_YVU411: 3122935b5977SVille Syrjälä case DRM_FORMAT_YUV420: 3123935b5977SVille Syrjälä case DRM_FORMAT_YVU420: 3124935b5977SVille Syrjälä case DRM_FORMAT_YUV422: 3125935b5977SVille Syrjälä case DRM_FORMAT_YVU422: 3126935b5977SVille Syrjälä case DRM_FORMAT_YUV444: 3127935b5977SVille Syrjälä case DRM_FORMAT_YVU444: 3128935b5977SVille Syrjälä return 0; 3129935b5977SVille Syrjälä default: 313023c453a4SVille Syrjälä DRM_DEBUG_KMS("invalid pixel format %s\n", 313123c453a4SVille Syrjälä drm_get_format_name(r->pixel_format)); 3132935b5977SVille Syrjälä return -EINVAL; 3133935b5977SVille Syrjälä } 3134935b5977SVille Syrjälä } 3135935b5977SVille Syrjälä 3136cff91b62SVille Syrjälä static int framebuffer_check(const struct drm_mode_fb_cmd2 *r) 3137d1b45d5fSVille Syrjälä { 3138d1b45d5fSVille Syrjälä int ret, hsub, vsub, num_planes, i; 3139d1b45d5fSVille Syrjälä 3140d1b45d5fSVille Syrjälä ret = format_check(r); 3141d1b45d5fSVille Syrjälä if (ret) { 31426ba6d03eSVille Syrjälä DRM_DEBUG_KMS("bad framebuffer format %s\n", 31436ba6d03eSVille Syrjälä drm_get_format_name(r->pixel_format)); 3144d1b45d5fSVille Syrjälä return ret; 3145d1b45d5fSVille Syrjälä } 3146d1b45d5fSVille Syrjälä 3147d1b45d5fSVille Syrjälä hsub = drm_format_horz_chroma_subsampling(r->pixel_format); 3148d1b45d5fSVille Syrjälä vsub = drm_format_vert_chroma_subsampling(r->pixel_format); 3149d1b45d5fSVille Syrjälä num_planes = drm_format_num_planes(r->pixel_format); 3150d1b45d5fSVille Syrjälä 3151d1b45d5fSVille Syrjälä if (r->width == 0 || r->width % hsub) { 3152209f5527SChuck Ebbert DRM_DEBUG_KMS("bad framebuffer width %u\n", r->width); 3153d1b45d5fSVille Syrjälä return -EINVAL; 3154d1b45d5fSVille Syrjälä } 3155d1b45d5fSVille Syrjälä 3156d1b45d5fSVille Syrjälä if (r->height == 0 || r->height % vsub) { 31571aa1b11cSDave Airlie DRM_DEBUG_KMS("bad framebuffer height %u\n", r->height); 3158d1b45d5fSVille Syrjälä return -EINVAL; 3159d1b45d5fSVille Syrjälä } 3160d1b45d5fSVille Syrjälä 3161d1b45d5fSVille Syrjälä for (i = 0; i < num_planes; i++) { 3162d1b45d5fSVille Syrjälä unsigned int width = r->width / (i != 0 ? hsub : 1); 3163b180b5d1SVille Syrjälä unsigned int height = r->height / (i != 0 ? vsub : 1); 3164b180b5d1SVille Syrjälä unsigned int cpp = drm_format_plane_cpp(r->pixel_format, i); 3165d1b45d5fSVille Syrjälä 3166d1b45d5fSVille Syrjälä if (!r->handles[i]) { 31671aa1b11cSDave Airlie DRM_DEBUG_KMS("no buffer object handle for plane %d\n", i); 3168d1b45d5fSVille Syrjälä return -EINVAL; 3169d1b45d5fSVille Syrjälä } 3170d1b45d5fSVille Syrjälä 3171b180b5d1SVille Syrjälä if ((uint64_t) width * cpp > UINT_MAX) 3172b180b5d1SVille Syrjälä return -ERANGE; 3173b180b5d1SVille Syrjälä 3174b180b5d1SVille Syrjälä if ((uint64_t) height * r->pitches[i] + r->offsets[i] > UINT_MAX) 3175b180b5d1SVille Syrjälä return -ERANGE; 3176b180b5d1SVille Syrjälä 3177b180b5d1SVille Syrjälä if (r->pitches[i] < width * cpp) { 31781aa1b11cSDave Airlie DRM_DEBUG_KMS("bad pitch %u for plane %d\n", r->pitches[i], i); 3179d1b45d5fSVille Syrjälä return -EINVAL; 3180d1b45d5fSVille Syrjälä } 3181e3eb3250SRob Clark 3182e3eb3250SRob Clark if (r->modifier[i] && !(r->flags & DRM_MODE_FB_MODIFIERS)) { 3183e3eb3250SRob Clark DRM_DEBUG_KMS("bad fb modifier %llu for plane %d\n", 3184e3eb3250SRob Clark r->modifier[i], i); 3185e3eb3250SRob Clark return -EINVAL; 3186e3eb3250SRob Clark } 3187570655b0SRob Clark 3188570655b0SRob Clark /* modifier specific checks: */ 3189570655b0SRob Clark switch (r->modifier[i]) { 3190570655b0SRob Clark case DRM_FORMAT_MOD_SAMSUNG_64_32_TILE: 3191570655b0SRob Clark /* NOTE: the pitch restriction may be lifted later if it turns 3192570655b0SRob Clark * out that no hw has this restriction: 3193570655b0SRob Clark */ 3194570655b0SRob Clark if (r->pixel_format != DRM_FORMAT_NV12 || 3195570655b0SRob Clark width % 128 || height % 32 || 3196570655b0SRob Clark r->pitches[i] % 128) { 3197570655b0SRob Clark DRM_DEBUG_KMS("bad modifier data for plane %d\n", i); 3198570655b0SRob Clark return -EINVAL; 3199570655b0SRob Clark } 3200570655b0SRob Clark break; 3201570655b0SRob Clark 3202570655b0SRob Clark default: 3203570655b0SRob Clark break; 3204570655b0SRob Clark } 3205d1b45d5fSVille Syrjälä } 3206d1b45d5fSVille Syrjälä 3207bbe16a40SDaniel Vetter for (i = num_planes; i < 4; i++) { 3208bbe16a40SDaniel Vetter if (r->modifier[i]) { 3209bbe16a40SDaniel Vetter DRM_DEBUG_KMS("non-zero modifier for unused plane %d\n", i); 3210bbe16a40SDaniel Vetter return -EINVAL; 3211bbe16a40SDaniel Vetter } 3212bbe16a40SDaniel Vetter 3213bbe16a40SDaniel Vetter /* Pre-FB_MODIFIERS userspace didn't clear the structs properly. */ 3214bbe16a40SDaniel Vetter if (!(r->flags & DRM_MODE_FB_MODIFIERS)) 3215bbe16a40SDaniel Vetter continue; 3216bbe16a40SDaniel Vetter 3217bbe16a40SDaniel Vetter if (r->handles[i]) { 3218bbe16a40SDaniel Vetter DRM_DEBUG_KMS("buffer object handle for unused plane %d\n", i); 3219bbe16a40SDaniel Vetter return -EINVAL; 3220bbe16a40SDaniel Vetter } 3221bbe16a40SDaniel Vetter 3222bbe16a40SDaniel Vetter if (r->pitches[i]) { 3223bbe16a40SDaniel Vetter DRM_DEBUG_KMS("non-zero pitch for unused plane %d\n", i); 3224bbe16a40SDaniel Vetter return -EINVAL; 3225bbe16a40SDaniel Vetter } 3226bbe16a40SDaniel Vetter 3227bbe16a40SDaniel Vetter if (r->offsets[i]) { 3228bbe16a40SDaniel Vetter DRM_DEBUG_KMS("non-zero offset for unused plane %d\n", i); 3229bbe16a40SDaniel Vetter return -EINVAL; 3230bbe16a40SDaniel Vetter } 3231bbe16a40SDaniel Vetter } 3232bbe16a40SDaniel Vetter 3233d1b45d5fSVille Syrjälä return 0; 3234d1b45d5fSVille Syrjälä } 3235d1b45d5fSVille Syrjälä 32369a6f5130SChris Wilson static struct drm_framebuffer * 32379a6f5130SChris Wilson internal_framebuffer_create(struct drm_device *dev, 32381eb83451SVille Syrjälä const struct drm_mode_fb_cmd2 *r, 3239c394c2b0SMatt Roper struct drm_file *file_priv) 3240c394c2b0SMatt Roper { 3241c394c2b0SMatt Roper struct drm_mode_config *config = &dev->mode_config; 3242c394c2b0SMatt Roper struct drm_framebuffer *fb; 3243c394c2b0SMatt Roper int ret; 3244c394c2b0SMatt Roper 3245e3eb3250SRob Clark if (r->flags & ~(DRM_MODE_FB_INTERLACED | DRM_MODE_FB_MODIFIERS)) { 3246c394c2b0SMatt Roper DRM_DEBUG_KMS("bad framebuffer flags 0x%08x\n", r->flags); 3247c394c2b0SMatt Roper return ERR_PTR(-EINVAL); 3248c394c2b0SMatt Roper } 3249c394c2b0SMatt Roper 3250c394c2b0SMatt Roper if ((config->min_width > r->width) || (r->width > config->max_width)) { 3251c394c2b0SMatt Roper DRM_DEBUG_KMS("bad framebuffer width %d, should be >= %d && <= %d\n", 3252c394c2b0SMatt Roper r->width, config->min_width, config->max_width); 3253c394c2b0SMatt Roper return ERR_PTR(-EINVAL); 3254c394c2b0SMatt Roper } 3255c394c2b0SMatt Roper if ((config->min_height > r->height) || (r->height > config->max_height)) { 3256c394c2b0SMatt Roper DRM_DEBUG_KMS("bad framebuffer height %d, should be >= %d && <= %d\n", 3257c394c2b0SMatt Roper r->height, config->min_height, config->max_height); 3258c394c2b0SMatt Roper return ERR_PTR(-EINVAL); 3259c394c2b0SMatt Roper } 3260c394c2b0SMatt Roper 3261e3eb3250SRob Clark if (r->flags & DRM_MODE_FB_MODIFIERS && 3262e3eb3250SRob Clark !dev->mode_config.allow_fb_modifiers) { 3263e3eb3250SRob Clark DRM_DEBUG_KMS("driver does not support fb modifiers\n"); 3264e3eb3250SRob Clark return ERR_PTR(-EINVAL); 3265e3eb3250SRob Clark } 3266e3eb3250SRob Clark 3267c394c2b0SMatt Roper ret = framebuffer_check(r); 3268c394c2b0SMatt Roper if (ret) 3269c394c2b0SMatt Roper return ERR_PTR(ret); 3270c394c2b0SMatt Roper 3271c394c2b0SMatt Roper fb = dev->mode_config.funcs->fb_create(dev, file_priv, r); 3272c394c2b0SMatt Roper if (IS_ERR(fb)) { 3273c394c2b0SMatt Roper DRM_DEBUG_KMS("could not create framebuffer\n"); 3274c394c2b0SMatt Roper return fb; 3275c394c2b0SMatt Roper } 3276c394c2b0SMatt Roper 3277c394c2b0SMatt Roper return fb; 3278c394c2b0SMatt Roper } 3279c394c2b0SMatt Roper 3280308e5bcbSJesse Barnes /** 3281308e5bcbSJesse Barnes * drm_mode_addfb2 - add an FB to the graphics configuration 3282065a50edSDaniel Vetter * @dev: drm device for the ioctl 3283065a50edSDaniel Vetter * @data: data pointer for the ioctl 3284065a50edSDaniel Vetter * @file_priv: drm file for the ioctl call 3285308e5bcbSJesse Barnes * 3286c8e32cc1SDaniel Vetter * Add a new FB to the specified CRTC, given a user request with format. This is 3287c8e32cc1SDaniel Vetter * the 2nd version of the addfb ioctl, which supports multi-planar framebuffers 3288c8e32cc1SDaniel Vetter * and uses fourcc codes as pixel format specifiers. 3289308e5bcbSJesse Barnes * 3290308e5bcbSJesse Barnes * Called by the user via ioctl. 3291308e5bcbSJesse Barnes * 3292c8e32cc1SDaniel Vetter * Returns: 32931a498633SDaniel Vetter * Zero on success, negative errno on failure. 3294308e5bcbSJesse Barnes */ 3295308e5bcbSJesse Barnes int drm_mode_addfb2(struct drm_device *dev, 3296308e5bcbSJesse Barnes void *data, struct drm_file *file_priv) 3297308e5bcbSJesse Barnes { 32989a6f5130SChris Wilson struct drm_mode_fb_cmd2 *r = data; 3299f453ba04SDave Airlie struct drm_framebuffer *fb; 3300f453ba04SDave Airlie 3301fb3b06c8SDave Airlie if (!drm_core_check_feature(dev, DRIVER_MODESET)) 3302fb3b06c8SDave Airlie return -EINVAL; 3303fb3b06c8SDave Airlie 33049a6f5130SChris Wilson fb = internal_framebuffer_create(dev, r, file_priv); 3305c394c2b0SMatt Roper if (IS_ERR(fb)) 33064b096ac1SDaniel Vetter return PTR_ERR(fb); 3307f453ba04SDave Airlie 33089a6f5130SChris Wilson /* Transfer ownership to the filp for reaping on close */ 33099a6f5130SChris Wilson 33109a6f5130SChris Wilson DRM_DEBUG_KMS("[FB:%d]\n", fb->base.id); 33119a6f5130SChris Wilson mutex_lock(&file_priv->fbs_lock); 33129a6f5130SChris Wilson r->fb_id = fb->base.id; 33139a6f5130SChris Wilson list_add(&fb->filp_head, &file_priv->fbs); 33149a6f5130SChris Wilson mutex_unlock(&file_priv->fbs_lock); 33159a6f5130SChris Wilson 3316c394c2b0SMatt Roper return 0; 3317f453ba04SDave Airlie } 3318f453ba04SDave Airlie 3319f453ba04SDave Airlie /** 3320f453ba04SDave Airlie * drm_mode_rmfb - remove an FB from the configuration 3321065a50edSDaniel Vetter * @dev: drm device for the ioctl 3322065a50edSDaniel Vetter * @data: data pointer for the ioctl 3323065a50edSDaniel Vetter * @file_priv: drm file for the ioctl call 3324f453ba04SDave Airlie * 3325f453ba04SDave Airlie * Remove the FB specified by the user. 3326f453ba04SDave Airlie * 3327f453ba04SDave Airlie * Called by the user via ioctl. 3328f453ba04SDave Airlie * 3329c8e32cc1SDaniel Vetter * Returns: 33301a498633SDaniel Vetter * Zero on success, negative errno on failure. 3331f453ba04SDave Airlie */ 3332f453ba04SDave Airlie int drm_mode_rmfb(struct drm_device *dev, 3333f453ba04SDave Airlie void *data, struct drm_file *file_priv) 3334f453ba04SDave Airlie { 3335f453ba04SDave Airlie struct drm_framebuffer *fb = NULL; 3336f453ba04SDave Airlie struct drm_framebuffer *fbl = NULL; 3337f453ba04SDave Airlie uint32_t *id = data; 3338f453ba04SDave Airlie int found = 0; 3339f453ba04SDave Airlie 3340fb3b06c8SDave Airlie if (!drm_core_check_feature(dev, DRIVER_MODESET)) 3341fb3b06c8SDave Airlie return -EINVAL; 3342fb3b06c8SDave Airlie 33434b096ac1SDaniel Vetter mutex_lock(&file_priv->fbs_lock); 33442b677e8cSDaniel Vetter mutex_lock(&dev->mode_config.fb_lock); 33452b677e8cSDaniel Vetter fb = __drm_framebuffer_lookup(dev, *id); 33462b677e8cSDaniel Vetter if (!fb) 33472b677e8cSDaniel Vetter goto fail_lookup; 33482b677e8cSDaniel Vetter 3349f453ba04SDave Airlie list_for_each_entry(fbl, &file_priv->fbs, filp_head) 3350f453ba04SDave Airlie if (fb == fbl) 3351f453ba04SDave Airlie found = 1; 33522b677e8cSDaniel Vetter if (!found) 33532b677e8cSDaniel Vetter goto fail_lookup; 33542b677e8cSDaniel Vetter 33554b096ac1SDaniel Vetter list_del_init(&fb->filp_head); 33562b677e8cSDaniel Vetter mutex_unlock(&dev->mode_config.fb_lock); 33574b096ac1SDaniel Vetter mutex_unlock(&file_priv->fbs_lock); 3358f453ba04SDave Airlie 335913803132SMaarten Lankhorst drm_framebuffer_unreference(fb); 33604b096ac1SDaniel Vetter 33612b677e8cSDaniel Vetter return 0; 33622b677e8cSDaniel Vetter 33632b677e8cSDaniel Vetter fail_lookup: 33642b677e8cSDaniel Vetter mutex_unlock(&dev->mode_config.fb_lock); 33652b677e8cSDaniel Vetter mutex_unlock(&file_priv->fbs_lock); 33662b677e8cSDaniel Vetter 336737c4e705SVille Syrjälä return -ENOENT; 3368f453ba04SDave Airlie } 3369f453ba04SDave Airlie 3370f453ba04SDave Airlie /** 3371f453ba04SDave Airlie * drm_mode_getfb - get FB info 3372065a50edSDaniel Vetter * @dev: drm device for the ioctl 3373065a50edSDaniel Vetter * @data: data pointer for the ioctl 3374065a50edSDaniel Vetter * @file_priv: drm file for the ioctl call 3375f453ba04SDave Airlie * 3376f453ba04SDave Airlie * Lookup the FB given its ID and return info about it. 3377f453ba04SDave Airlie * 3378f453ba04SDave Airlie * Called by the user via ioctl. 3379f453ba04SDave Airlie * 3380c8e32cc1SDaniel Vetter * Returns: 33811a498633SDaniel Vetter * Zero on success, negative errno on failure. 3382f453ba04SDave Airlie */ 3383f453ba04SDave Airlie int drm_mode_getfb(struct drm_device *dev, 3384f453ba04SDave Airlie void *data, struct drm_file *file_priv) 3385f453ba04SDave Airlie { 3386f453ba04SDave Airlie struct drm_mode_fb_cmd *r = data; 3387f453ba04SDave Airlie struct drm_framebuffer *fb; 338858c0dca1SDaniel Vetter int ret; 3389f453ba04SDave Airlie 3390fb3b06c8SDave Airlie if (!drm_core_check_feature(dev, DRIVER_MODESET)) 3391fb3b06c8SDave Airlie return -EINVAL; 3392fb3b06c8SDave Airlie 3393786b99edSDaniel Vetter fb = drm_framebuffer_lookup(dev, r->fb_id); 339458c0dca1SDaniel Vetter if (!fb) 339537c4e705SVille Syrjälä return -ENOENT; 3396f453ba04SDave Airlie 3397f453ba04SDave Airlie r->height = fb->height; 3398f453ba04SDave Airlie r->width = fb->width; 3399f453ba04SDave Airlie r->depth = fb->depth; 3400f453ba04SDave Airlie r->bpp = fb->bits_per_pixel; 340101f2c773SVille Syrjälä r->pitch = fb->pitches[0]; 3402101b96f3SDavid Herrmann if (fb->funcs->create_handle) { 340309f308f7SThomas Hellstrom if (file_priv->is_master || capable(CAP_SYS_ADMIN) || 340443683057SThomas Hellstrom drm_is_control_client(file_priv)) { 3405101b96f3SDavid Herrmann ret = fb->funcs->create_handle(fb, file_priv, 3406101b96f3SDavid Herrmann &r->handle); 3407101b96f3SDavid Herrmann } else { 3408101b96f3SDavid Herrmann /* GET_FB() is an unprivileged ioctl so we must not 3409101b96f3SDavid Herrmann * return a buffer-handle to non-master processes! For 3410101b96f3SDavid Herrmann * backwards-compatibility reasons, we cannot make 3411101b96f3SDavid Herrmann * GET_FB() privileged, so just return an invalid handle 3412101b96f3SDavid Herrmann * for non-masters. */ 3413101b96f3SDavid Herrmann r->handle = 0; 3414101b96f3SDavid Herrmann ret = 0; 3415101b96f3SDavid Herrmann } 3416101b96f3SDavid Herrmann } else { 3417af26ef3bSDaniel Vetter ret = -ENODEV; 3418101b96f3SDavid Herrmann } 3419f453ba04SDave Airlie 342058c0dca1SDaniel Vetter drm_framebuffer_unreference(fb); 342158c0dca1SDaniel Vetter 3422f453ba04SDave Airlie return ret; 3423f453ba04SDave Airlie } 3424f453ba04SDave Airlie 3425c8e32cc1SDaniel Vetter /** 3426c8e32cc1SDaniel Vetter * drm_mode_dirtyfb_ioctl - flush frontbuffer rendering on an FB 3427c8e32cc1SDaniel Vetter * @dev: drm device for the ioctl 3428c8e32cc1SDaniel Vetter * @data: data pointer for the ioctl 3429c8e32cc1SDaniel Vetter * @file_priv: drm file for the ioctl call 3430c8e32cc1SDaniel Vetter * 3431c8e32cc1SDaniel Vetter * Lookup the FB and flush out the damaged area supplied by userspace as a clip 3432c8e32cc1SDaniel Vetter * rectangle list. Generic userspace which does frontbuffer rendering must call 3433c8e32cc1SDaniel Vetter * this ioctl to flush out the changes on manual-update display outputs, e.g. 3434c8e32cc1SDaniel Vetter * usb display-link, mipi manual update panels or edp panel self refresh modes. 3435c8e32cc1SDaniel Vetter * 3436c8e32cc1SDaniel Vetter * Modesetting drivers which always update the frontbuffer do not need to 3437c8e32cc1SDaniel Vetter * implement the corresponding ->dirty framebuffer callback. 3438c8e32cc1SDaniel Vetter * 3439c8e32cc1SDaniel Vetter * Called by the user via ioctl. 3440c8e32cc1SDaniel Vetter * 3441c8e32cc1SDaniel Vetter * Returns: 34421a498633SDaniel Vetter * Zero on success, negative errno on failure. 3443c8e32cc1SDaniel Vetter */ 3444884840aaSJakob Bornecrantz int drm_mode_dirtyfb_ioctl(struct drm_device *dev, 3445884840aaSJakob Bornecrantz void *data, struct drm_file *file_priv) 3446884840aaSJakob Bornecrantz { 3447884840aaSJakob Bornecrantz struct drm_clip_rect __user *clips_ptr; 3448884840aaSJakob Bornecrantz struct drm_clip_rect *clips = NULL; 3449884840aaSJakob Bornecrantz struct drm_mode_fb_dirty_cmd *r = data; 3450884840aaSJakob Bornecrantz struct drm_framebuffer *fb; 3451884840aaSJakob Bornecrantz unsigned flags; 3452884840aaSJakob Bornecrantz int num_clips; 34534a1b0714SLaurent Pinchart int ret; 3454884840aaSJakob Bornecrantz 3455fb3b06c8SDave Airlie if (!drm_core_check_feature(dev, DRIVER_MODESET)) 3456fb3b06c8SDave Airlie return -EINVAL; 3457fb3b06c8SDave Airlie 3458786b99edSDaniel Vetter fb = drm_framebuffer_lookup(dev, r->fb_id); 34594ccf097fSDaniel Vetter if (!fb) 346037c4e705SVille Syrjälä return -ENOENT; 3461884840aaSJakob Bornecrantz 3462884840aaSJakob Bornecrantz num_clips = r->num_clips; 346381f6c7f8SVille Syrjälä clips_ptr = (struct drm_clip_rect __user *)(unsigned long)r->clips_ptr; 3464884840aaSJakob Bornecrantz 3465884840aaSJakob Bornecrantz if (!num_clips != !clips_ptr) { 3466884840aaSJakob Bornecrantz ret = -EINVAL; 3467884840aaSJakob Bornecrantz goto out_err1; 3468884840aaSJakob Bornecrantz } 3469884840aaSJakob Bornecrantz 3470884840aaSJakob Bornecrantz flags = DRM_MODE_FB_DIRTY_FLAGS & r->flags; 3471884840aaSJakob Bornecrantz 3472884840aaSJakob Bornecrantz /* If userspace annotates copy, clips must come in pairs */ 3473884840aaSJakob Bornecrantz if (flags & DRM_MODE_FB_DIRTY_ANNOTATE_COPY && (num_clips % 2)) { 3474884840aaSJakob Bornecrantz ret = -EINVAL; 3475884840aaSJakob Bornecrantz goto out_err1; 3476884840aaSJakob Bornecrantz } 3477884840aaSJakob Bornecrantz 3478884840aaSJakob Bornecrantz if (num_clips && clips_ptr) { 3479a5cd3351SXi Wang if (num_clips < 0 || num_clips > DRM_MODE_FB_DIRTY_MAX_CLIPS) { 3480a5cd3351SXi Wang ret = -EINVAL; 3481a5cd3351SXi Wang goto out_err1; 3482a5cd3351SXi Wang } 3483bd3f0ff9SThierry Reding clips = kcalloc(num_clips, sizeof(*clips), GFP_KERNEL); 3484884840aaSJakob Bornecrantz if (!clips) { 3485884840aaSJakob Bornecrantz ret = -ENOMEM; 3486884840aaSJakob Bornecrantz goto out_err1; 3487884840aaSJakob Bornecrantz } 3488884840aaSJakob Bornecrantz 3489884840aaSJakob Bornecrantz ret = copy_from_user(clips, clips_ptr, 3490884840aaSJakob Bornecrantz num_clips * sizeof(*clips)); 3491e902a358SDan Carpenter if (ret) { 3492e902a358SDan Carpenter ret = -EFAULT; 3493884840aaSJakob Bornecrantz goto out_err2; 3494884840aaSJakob Bornecrantz } 3495e902a358SDan Carpenter } 3496884840aaSJakob Bornecrantz 3497884840aaSJakob Bornecrantz if (fb->funcs->dirty) { 349802b00162SThomas Hellstrom ret = fb->funcs->dirty(fb, file_priv, flags, r->color, 349902b00162SThomas Hellstrom clips, num_clips); 3500884840aaSJakob Bornecrantz } else { 3501884840aaSJakob Bornecrantz ret = -ENOSYS; 3502884840aaSJakob Bornecrantz } 3503884840aaSJakob Bornecrantz 3504884840aaSJakob Bornecrantz out_err2: 3505884840aaSJakob Bornecrantz kfree(clips); 3506884840aaSJakob Bornecrantz out_err1: 35074ccf097fSDaniel Vetter drm_framebuffer_unreference(fb); 35084ccf097fSDaniel Vetter 3509884840aaSJakob Bornecrantz return ret; 3510884840aaSJakob Bornecrantz } 3511884840aaSJakob Bornecrantz 3512884840aaSJakob Bornecrantz 3513f453ba04SDave Airlie /** 3514f453ba04SDave Airlie * drm_fb_release - remove and free the FBs on this file 3515065a50edSDaniel Vetter * @priv: drm file for the ioctl 3516f453ba04SDave Airlie * 3517f453ba04SDave Airlie * Destroy all the FBs associated with @filp. 3518f453ba04SDave Airlie * 3519f453ba04SDave Airlie * Called by the user via ioctl. 3520f453ba04SDave Airlie * 3521c8e32cc1SDaniel Vetter * Returns: 35221a498633SDaniel Vetter * Zero on success, negative errno on failure. 3523f453ba04SDave Airlie */ 3524ea39f835SKristian Høgsberg void drm_fb_release(struct drm_file *priv) 3525f453ba04SDave Airlie { 3526f453ba04SDave Airlie struct drm_framebuffer *fb, *tfb; 3527f453ba04SDave Airlie 35281b116297SDaniel Vetter /* 35291b116297SDaniel Vetter * When the file gets released that means no one else can access the fb 3530e2db726bSMartin Peres * list any more, so no need to grab fpriv->fbs_lock. And we need to 35311b116297SDaniel Vetter * avoid upsetting lockdep since the universal cursor code adds a 35321b116297SDaniel Vetter * framebuffer while holding mutex locks. 35331b116297SDaniel Vetter * 35341b116297SDaniel Vetter * Note that a real deadlock between fpriv->fbs_lock and the modeset 35351b116297SDaniel Vetter * locks is impossible here since no one else but this function can get 35361b116297SDaniel Vetter * at it any more. 35371b116297SDaniel Vetter */ 3538f453ba04SDave Airlie list_for_each_entry_safe(fb, tfb, &priv->fbs, filp_head) { 35394b096ac1SDaniel Vetter list_del_init(&fb->filp_head); 35402b677e8cSDaniel Vetter 354173f7570bSMaarten Lankhorst /* This drops the fpriv->fbs reference. */ 354213803132SMaarten Lankhorst drm_framebuffer_unreference(fb); 3543f453ba04SDave Airlie } 3544f453ba04SDave Airlie } 3545f453ba04SDave Airlie 3546c8e32cc1SDaniel Vetter /** 3547c8e32cc1SDaniel Vetter * drm_property_create - create a new property type 3548c8e32cc1SDaniel Vetter * @dev: drm device 3549c8e32cc1SDaniel Vetter * @flags: flags specifying the property type 3550c8e32cc1SDaniel Vetter * @name: name of the property 3551c8e32cc1SDaniel Vetter * @num_values: number of pre-defined values 3552c8e32cc1SDaniel Vetter * 3553c8e32cc1SDaniel Vetter * This creates a new generic drm property which can then be attached to a drm 3554c8e32cc1SDaniel Vetter * object with drm_object_attach_property. The returned property object must be 3555c8e32cc1SDaniel Vetter * freed with drm_property_destroy. 3556c8e32cc1SDaniel Vetter * 35573b5b9932SDamien Lespiau * Note that the DRM core keeps a per-device list of properties and that, if 35583b5b9932SDamien Lespiau * drm_mode_config_cleanup() is called, it will destroy all properties created 35593b5b9932SDamien Lespiau * by the driver. 35603b5b9932SDamien Lespiau * 3561c8e32cc1SDaniel Vetter * Returns: 3562c8e32cc1SDaniel Vetter * A pointer to the newly created property on success, NULL on failure. 3563c8e32cc1SDaniel Vetter */ 3564f453ba04SDave Airlie struct drm_property *drm_property_create(struct drm_device *dev, int flags, 3565f453ba04SDave Airlie const char *name, int num_values) 3566f453ba04SDave Airlie { 3567f453ba04SDave Airlie struct drm_property *property = NULL; 35686bfc56aaSVille Syrjälä int ret; 3569f453ba04SDave Airlie 3570f453ba04SDave Airlie property = kzalloc(sizeof(struct drm_property), GFP_KERNEL); 3571f453ba04SDave Airlie if (!property) 3572f453ba04SDave Airlie return NULL; 3573f453ba04SDave Airlie 357498f75de4SRob Clark property->dev = dev; 357598f75de4SRob Clark 3576f453ba04SDave Airlie if (num_values) { 3577bd3f0ff9SThierry Reding property->values = kcalloc(num_values, sizeof(uint64_t), 3578bd3f0ff9SThierry Reding GFP_KERNEL); 3579f453ba04SDave Airlie if (!property->values) 3580f453ba04SDave Airlie goto fail; 3581f453ba04SDave Airlie } 3582f453ba04SDave Airlie 35836bfc56aaSVille Syrjälä ret = drm_mode_object_get(dev, &property->base, DRM_MODE_OBJECT_PROPERTY); 35846bfc56aaSVille Syrjälä if (ret) 35856bfc56aaSVille Syrjälä goto fail; 35866bfc56aaSVille Syrjälä 3587f453ba04SDave Airlie property->flags = flags; 3588f453ba04SDave Airlie property->num_values = num_values; 35893758b341SDaniel Vetter INIT_LIST_HEAD(&property->enum_list); 3590f453ba04SDave Airlie 3591471dd2efSVinson Lee if (name) { 3592f453ba04SDave Airlie strncpy(property->name, name, DRM_PROP_NAME_LEN); 3593471dd2efSVinson Lee property->name[DRM_PROP_NAME_LEN-1] = '\0'; 3594471dd2efSVinson Lee } 3595f453ba04SDave Airlie 3596f453ba04SDave Airlie list_add_tail(&property->head, &dev->mode_config.property_list); 35975ea22f24SRob Clark 35985ea22f24SRob Clark WARN_ON(!drm_property_type_valid(property)); 35995ea22f24SRob Clark 3600f453ba04SDave Airlie return property; 3601f453ba04SDave Airlie fail: 36026bfc56aaSVille Syrjälä kfree(property->values); 3603f453ba04SDave Airlie kfree(property); 3604f453ba04SDave Airlie return NULL; 3605f453ba04SDave Airlie } 3606f453ba04SDave Airlie EXPORT_SYMBOL(drm_property_create); 3607f453ba04SDave Airlie 3608c8e32cc1SDaniel Vetter /** 36092aa9d2bcSThierry Reding * drm_property_create_enum - create a new enumeration property type 3610c8e32cc1SDaniel Vetter * @dev: drm device 3611c8e32cc1SDaniel Vetter * @flags: flags specifying the property type 3612c8e32cc1SDaniel Vetter * @name: name of the property 3613c8e32cc1SDaniel Vetter * @props: enumeration lists with property values 3614c8e32cc1SDaniel Vetter * @num_values: number of pre-defined values 3615c8e32cc1SDaniel Vetter * 3616c8e32cc1SDaniel Vetter * This creates a new generic drm property which can then be attached to a drm 3617c8e32cc1SDaniel Vetter * object with drm_object_attach_property. The returned property object must be 3618c8e32cc1SDaniel Vetter * freed with drm_property_destroy. 3619c8e32cc1SDaniel Vetter * 3620c8e32cc1SDaniel Vetter * Userspace is only allowed to set one of the predefined values for enumeration 3621c8e32cc1SDaniel Vetter * properties. 3622c8e32cc1SDaniel Vetter * 3623c8e32cc1SDaniel Vetter * Returns: 3624c8e32cc1SDaniel Vetter * A pointer to the newly created property on success, NULL on failure. 3625c8e32cc1SDaniel Vetter */ 36264a67d391SSascha Hauer struct drm_property *drm_property_create_enum(struct drm_device *dev, int flags, 36274a67d391SSascha Hauer const char *name, 36284a67d391SSascha Hauer const struct drm_prop_enum_list *props, 36294a67d391SSascha Hauer int num_values) 36304a67d391SSascha Hauer { 36314a67d391SSascha Hauer struct drm_property *property; 36324a67d391SSascha Hauer int i, ret; 36334a67d391SSascha Hauer 36344a67d391SSascha Hauer flags |= DRM_MODE_PROP_ENUM; 36354a67d391SSascha Hauer 36364a67d391SSascha Hauer property = drm_property_create(dev, flags, name, num_values); 36374a67d391SSascha Hauer if (!property) 36384a67d391SSascha Hauer return NULL; 36394a67d391SSascha Hauer 36404a67d391SSascha Hauer for (i = 0; i < num_values; i++) { 36414a67d391SSascha Hauer ret = drm_property_add_enum(property, i, 36424a67d391SSascha Hauer props[i].type, 36434a67d391SSascha Hauer props[i].name); 36444a67d391SSascha Hauer if (ret) { 36454a67d391SSascha Hauer drm_property_destroy(dev, property); 36464a67d391SSascha Hauer return NULL; 36474a67d391SSascha Hauer } 36484a67d391SSascha Hauer } 36494a67d391SSascha Hauer 36504a67d391SSascha Hauer return property; 36514a67d391SSascha Hauer } 36524a67d391SSascha Hauer EXPORT_SYMBOL(drm_property_create_enum); 36534a67d391SSascha Hauer 3654c8e32cc1SDaniel Vetter /** 36552aa9d2bcSThierry Reding * drm_property_create_bitmask - create a new bitmask property type 3656c8e32cc1SDaniel Vetter * @dev: drm device 3657c8e32cc1SDaniel Vetter * @flags: flags specifying the property type 3658c8e32cc1SDaniel Vetter * @name: name of the property 3659c8e32cc1SDaniel Vetter * @props: enumeration lists with property bitflags 3660295ee853SDaniel Vetter * @num_props: size of the @props array 3661295ee853SDaniel Vetter * @supported_bits: bitmask of all supported enumeration values 3662c8e32cc1SDaniel Vetter * 3663295ee853SDaniel Vetter * This creates a new bitmask drm property which can then be attached to a drm 3664c8e32cc1SDaniel Vetter * object with drm_object_attach_property. The returned property object must be 3665c8e32cc1SDaniel Vetter * freed with drm_property_destroy. 3666c8e32cc1SDaniel Vetter * 3667c8e32cc1SDaniel Vetter * Compared to plain enumeration properties userspace is allowed to set any 3668c8e32cc1SDaniel Vetter * or'ed together combination of the predefined property bitflag values 3669c8e32cc1SDaniel Vetter * 3670c8e32cc1SDaniel Vetter * Returns: 3671c8e32cc1SDaniel Vetter * A pointer to the newly created property on success, NULL on failure. 3672c8e32cc1SDaniel Vetter */ 367349e27545SRob Clark struct drm_property *drm_property_create_bitmask(struct drm_device *dev, 367449e27545SRob Clark int flags, const char *name, 367549e27545SRob Clark const struct drm_prop_enum_list *props, 36767689ffb3SVille Syrjälä int num_props, 36777689ffb3SVille Syrjälä uint64_t supported_bits) 367849e27545SRob Clark { 367949e27545SRob Clark struct drm_property *property; 36807689ffb3SVille Syrjälä int i, ret, index = 0; 36817689ffb3SVille Syrjälä int num_values = hweight64(supported_bits); 368249e27545SRob Clark 368349e27545SRob Clark flags |= DRM_MODE_PROP_BITMASK; 368449e27545SRob Clark 368549e27545SRob Clark property = drm_property_create(dev, flags, name, num_values); 368649e27545SRob Clark if (!property) 368749e27545SRob Clark return NULL; 36887689ffb3SVille Syrjälä for (i = 0; i < num_props; i++) { 36897689ffb3SVille Syrjälä if (!(supported_bits & (1ULL << props[i].type))) 36907689ffb3SVille Syrjälä continue; 369149e27545SRob Clark 36927689ffb3SVille Syrjälä if (WARN_ON(index >= num_values)) { 36937689ffb3SVille Syrjälä drm_property_destroy(dev, property); 36947689ffb3SVille Syrjälä return NULL; 36957689ffb3SVille Syrjälä } 36967689ffb3SVille Syrjälä 36977689ffb3SVille Syrjälä ret = drm_property_add_enum(property, index++, 369849e27545SRob Clark props[i].type, 369949e27545SRob Clark props[i].name); 370049e27545SRob Clark if (ret) { 370149e27545SRob Clark drm_property_destroy(dev, property); 370249e27545SRob Clark return NULL; 370349e27545SRob Clark } 370449e27545SRob Clark } 370549e27545SRob Clark 370649e27545SRob Clark return property; 370749e27545SRob Clark } 370849e27545SRob Clark EXPORT_SYMBOL(drm_property_create_bitmask); 370949e27545SRob Clark 3710ebc44cf3SRob Clark static struct drm_property *property_create_range(struct drm_device *dev, 3711ebc44cf3SRob Clark int flags, const char *name, 3712ebc44cf3SRob Clark uint64_t min, uint64_t max) 3713ebc44cf3SRob Clark { 3714ebc44cf3SRob Clark struct drm_property *property; 3715ebc44cf3SRob Clark 3716ebc44cf3SRob Clark property = drm_property_create(dev, flags, name, 2); 3717ebc44cf3SRob Clark if (!property) 3718ebc44cf3SRob Clark return NULL; 3719ebc44cf3SRob Clark 3720ebc44cf3SRob Clark property->values[0] = min; 3721ebc44cf3SRob Clark property->values[1] = max; 3722ebc44cf3SRob Clark 3723ebc44cf3SRob Clark return property; 3724ebc44cf3SRob Clark } 3725ebc44cf3SRob Clark 3726c8e32cc1SDaniel Vetter /** 3727960cd9d4SDaniel Vetter * drm_property_create_range - create a new unsigned ranged property type 3728c8e32cc1SDaniel Vetter * @dev: drm device 3729c8e32cc1SDaniel Vetter * @flags: flags specifying the property type 3730c8e32cc1SDaniel Vetter * @name: name of the property 3731c8e32cc1SDaniel Vetter * @min: minimum value of the property 3732c8e32cc1SDaniel Vetter * @max: maximum value of the property 3733c8e32cc1SDaniel Vetter * 3734c8e32cc1SDaniel Vetter * This creates a new generic drm property which can then be attached to a drm 3735c8e32cc1SDaniel Vetter * object with drm_object_attach_property. The returned property object must be 3736c8e32cc1SDaniel Vetter * freed with drm_property_destroy. 3737c8e32cc1SDaniel Vetter * 3738960cd9d4SDaniel Vetter * Userspace is allowed to set any unsigned integer value in the (min, max) 3739960cd9d4SDaniel Vetter * range inclusive. 3740c8e32cc1SDaniel Vetter * 3741c8e32cc1SDaniel Vetter * Returns: 3742c8e32cc1SDaniel Vetter * A pointer to the newly created property on success, NULL on failure. 3743c8e32cc1SDaniel Vetter */ 3744d9bc3c02SSascha Hauer struct drm_property *drm_property_create_range(struct drm_device *dev, int flags, 3745d9bc3c02SSascha Hauer const char *name, 3746d9bc3c02SSascha Hauer uint64_t min, uint64_t max) 3747d9bc3c02SSascha Hauer { 3748ebc44cf3SRob Clark return property_create_range(dev, DRM_MODE_PROP_RANGE | flags, 3749ebc44cf3SRob Clark name, min, max); 3750d9bc3c02SSascha Hauer } 3751d9bc3c02SSascha Hauer EXPORT_SYMBOL(drm_property_create_range); 3752d9bc3c02SSascha Hauer 3753960cd9d4SDaniel Vetter /** 3754960cd9d4SDaniel Vetter * drm_property_create_signed_range - create a new signed ranged property type 3755960cd9d4SDaniel Vetter * @dev: drm device 3756960cd9d4SDaniel Vetter * @flags: flags specifying the property type 3757960cd9d4SDaniel Vetter * @name: name of the property 3758960cd9d4SDaniel Vetter * @min: minimum value of the property 3759960cd9d4SDaniel Vetter * @max: maximum value of the property 3760960cd9d4SDaniel Vetter * 3761960cd9d4SDaniel Vetter * This creates a new generic drm property which can then be attached to a drm 3762960cd9d4SDaniel Vetter * object with drm_object_attach_property. The returned property object must be 3763960cd9d4SDaniel Vetter * freed with drm_property_destroy. 3764960cd9d4SDaniel Vetter * 3765960cd9d4SDaniel Vetter * Userspace is allowed to set any signed integer value in the (min, max) 3766960cd9d4SDaniel Vetter * range inclusive. 3767960cd9d4SDaniel Vetter * 3768960cd9d4SDaniel Vetter * Returns: 3769960cd9d4SDaniel Vetter * A pointer to the newly created property on success, NULL on failure. 3770960cd9d4SDaniel Vetter */ 3771ebc44cf3SRob Clark struct drm_property *drm_property_create_signed_range(struct drm_device *dev, 3772ebc44cf3SRob Clark int flags, const char *name, 3773ebc44cf3SRob Clark int64_t min, int64_t max) 3774ebc44cf3SRob Clark { 3775ebc44cf3SRob Clark return property_create_range(dev, DRM_MODE_PROP_SIGNED_RANGE | flags, 3776ebc44cf3SRob Clark name, I642U64(min), I642U64(max)); 3777ebc44cf3SRob Clark } 3778ebc44cf3SRob Clark EXPORT_SYMBOL(drm_property_create_signed_range); 3779ebc44cf3SRob Clark 3780960cd9d4SDaniel Vetter /** 3781960cd9d4SDaniel Vetter * drm_property_create_object - create a new object property type 3782960cd9d4SDaniel Vetter * @dev: drm device 3783960cd9d4SDaniel Vetter * @flags: flags specifying the property type 3784960cd9d4SDaniel Vetter * @name: name of the property 3785960cd9d4SDaniel Vetter * @type: object type from DRM_MODE_OBJECT_* defines 3786960cd9d4SDaniel Vetter * 3787960cd9d4SDaniel Vetter * This creates a new generic drm property which can then be attached to a drm 3788960cd9d4SDaniel Vetter * object with drm_object_attach_property. The returned property object must be 3789960cd9d4SDaniel Vetter * freed with drm_property_destroy. 3790960cd9d4SDaniel Vetter * 3791960cd9d4SDaniel Vetter * Userspace is only allowed to set this to any property value of the given 3792960cd9d4SDaniel Vetter * @type. Only useful for atomic properties, which is enforced. 3793960cd9d4SDaniel Vetter * 3794960cd9d4SDaniel Vetter * Returns: 3795960cd9d4SDaniel Vetter * A pointer to the newly created property on success, NULL on failure. 3796960cd9d4SDaniel Vetter */ 379798f75de4SRob Clark struct drm_property *drm_property_create_object(struct drm_device *dev, 379898f75de4SRob Clark int flags, const char *name, uint32_t type) 379998f75de4SRob Clark { 380098f75de4SRob Clark struct drm_property *property; 380198f75de4SRob Clark 380298f75de4SRob Clark flags |= DRM_MODE_PROP_OBJECT; 380398f75de4SRob Clark 3804960cd9d4SDaniel Vetter if (WARN_ON(!(flags & DRM_MODE_PROP_ATOMIC))) 3805960cd9d4SDaniel Vetter return NULL; 3806960cd9d4SDaniel Vetter 380798f75de4SRob Clark property = drm_property_create(dev, flags, name, 1); 380898f75de4SRob Clark if (!property) 380998f75de4SRob Clark return NULL; 381098f75de4SRob Clark 381198f75de4SRob Clark property->values[0] = type; 381298f75de4SRob Clark 381398f75de4SRob Clark return property; 381498f75de4SRob Clark } 381598f75de4SRob Clark EXPORT_SYMBOL(drm_property_create_object); 381698f75de4SRob Clark 3817c8e32cc1SDaniel Vetter /** 3818960cd9d4SDaniel Vetter * drm_property_create_bool - create a new boolean property type 3819960cd9d4SDaniel Vetter * @dev: drm device 3820960cd9d4SDaniel Vetter * @flags: flags specifying the property type 3821960cd9d4SDaniel Vetter * @name: name of the property 3822960cd9d4SDaniel Vetter * 3823960cd9d4SDaniel Vetter * This creates a new generic drm property which can then be attached to a drm 3824960cd9d4SDaniel Vetter * object with drm_object_attach_property. The returned property object must be 3825960cd9d4SDaniel Vetter * freed with drm_property_destroy. 3826960cd9d4SDaniel Vetter * 3827960cd9d4SDaniel Vetter * This is implemented as a ranged property with only {0, 1} as valid values. 3828960cd9d4SDaniel Vetter * 3829960cd9d4SDaniel Vetter * Returns: 3830960cd9d4SDaniel Vetter * A pointer to the newly created property on success, NULL on failure. 3831960cd9d4SDaniel Vetter */ 3832960cd9d4SDaniel Vetter struct drm_property *drm_property_create_bool(struct drm_device *dev, int flags, 3833960cd9d4SDaniel Vetter const char *name) 3834960cd9d4SDaniel Vetter { 3835960cd9d4SDaniel Vetter return drm_property_create_range(dev, flags, name, 0, 1); 3836960cd9d4SDaniel Vetter } 3837960cd9d4SDaniel Vetter EXPORT_SYMBOL(drm_property_create_bool); 3838960cd9d4SDaniel Vetter 3839960cd9d4SDaniel Vetter /** 3840c8e32cc1SDaniel Vetter * drm_property_add_enum - add a possible value to an enumeration property 3841c8e32cc1SDaniel Vetter * @property: enumeration property to change 3842c8e32cc1SDaniel Vetter * @index: index of the new enumeration 3843c8e32cc1SDaniel Vetter * @value: value of the new enumeration 3844c8e32cc1SDaniel Vetter * @name: symbolic name of the new enumeration 3845c8e32cc1SDaniel Vetter * 3846c8e32cc1SDaniel Vetter * This functions adds enumerations to a property. 3847c8e32cc1SDaniel Vetter * 3848c8e32cc1SDaniel Vetter * It's use is deprecated, drivers should use one of the more specific helpers 3849c8e32cc1SDaniel Vetter * to directly create the property with all enumerations already attached. 3850c8e32cc1SDaniel Vetter * 3851c8e32cc1SDaniel Vetter * Returns: 3852c8e32cc1SDaniel Vetter * Zero on success, error code on failure. 3853c8e32cc1SDaniel Vetter */ 3854f453ba04SDave Airlie int drm_property_add_enum(struct drm_property *property, int index, 3855f453ba04SDave Airlie uint64_t value, const char *name) 3856f453ba04SDave Airlie { 3857f453ba04SDave Airlie struct drm_property_enum *prop_enum; 3858f453ba04SDave Airlie 38595ea22f24SRob Clark if (!(drm_property_type_is(property, DRM_MODE_PROP_ENUM) || 38605ea22f24SRob Clark drm_property_type_is(property, DRM_MODE_PROP_BITMASK))) 386149e27545SRob Clark return -EINVAL; 386249e27545SRob Clark 386349e27545SRob Clark /* 386449e27545SRob Clark * Bitmask enum properties have the additional constraint of values 386549e27545SRob Clark * from 0 to 63 386649e27545SRob Clark */ 38675ea22f24SRob Clark if (drm_property_type_is(property, DRM_MODE_PROP_BITMASK) && 38685ea22f24SRob Clark (value > 63)) 3869f453ba04SDave Airlie return -EINVAL; 3870f453ba04SDave Airlie 38713758b341SDaniel Vetter if (!list_empty(&property->enum_list)) { 38723758b341SDaniel Vetter list_for_each_entry(prop_enum, &property->enum_list, head) { 3873f453ba04SDave Airlie if (prop_enum->value == value) { 3874f453ba04SDave Airlie strncpy(prop_enum->name, name, DRM_PROP_NAME_LEN); 3875f453ba04SDave Airlie prop_enum->name[DRM_PROP_NAME_LEN-1] = '\0'; 3876f453ba04SDave Airlie return 0; 3877f453ba04SDave Airlie } 3878f453ba04SDave Airlie } 3879f453ba04SDave Airlie } 3880f453ba04SDave Airlie 3881f453ba04SDave Airlie prop_enum = kzalloc(sizeof(struct drm_property_enum), GFP_KERNEL); 3882f453ba04SDave Airlie if (!prop_enum) 3883f453ba04SDave Airlie return -ENOMEM; 3884f453ba04SDave Airlie 3885f453ba04SDave Airlie strncpy(prop_enum->name, name, DRM_PROP_NAME_LEN); 3886f453ba04SDave Airlie prop_enum->name[DRM_PROP_NAME_LEN-1] = '\0'; 3887f453ba04SDave Airlie prop_enum->value = value; 3888f453ba04SDave Airlie 3889f453ba04SDave Airlie property->values[index] = value; 38903758b341SDaniel Vetter list_add_tail(&prop_enum->head, &property->enum_list); 3891f453ba04SDave Airlie return 0; 3892f453ba04SDave Airlie } 3893f453ba04SDave Airlie EXPORT_SYMBOL(drm_property_add_enum); 3894f453ba04SDave Airlie 3895c8e32cc1SDaniel Vetter /** 3896c8e32cc1SDaniel Vetter * drm_property_destroy - destroy a drm property 3897c8e32cc1SDaniel Vetter * @dev: drm device 3898c8e32cc1SDaniel Vetter * @property: property to destry 3899c8e32cc1SDaniel Vetter * 3900c8e32cc1SDaniel Vetter * This function frees a property including any attached resources like 3901c8e32cc1SDaniel Vetter * enumeration values. 3902c8e32cc1SDaniel Vetter */ 3903f453ba04SDave Airlie void drm_property_destroy(struct drm_device *dev, struct drm_property *property) 3904f453ba04SDave Airlie { 3905f453ba04SDave Airlie struct drm_property_enum *prop_enum, *pt; 3906f453ba04SDave Airlie 39073758b341SDaniel Vetter list_for_each_entry_safe(prop_enum, pt, &property->enum_list, head) { 3908f453ba04SDave Airlie list_del(&prop_enum->head); 3909f453ba04SDave Airlie kfree(prop_enum); 3910f453ba04SDave Airlie } 3911f453ba04SDave Airlie 3912f453ba04SDave Airlie if (property->num_values) 3913f453ba04SDave Airlie kfree(property->values); 3914f453ba04SDave Airlie drm_mode_object_put(dev, &property->base); 3915f453ba04SDave Airlie list_del(&property->head); 3916f453ba04SDave Airlie kfree(property); 3917f453ba04SDave Airlie } 3918f453ba04SDave Airlie EXPORT_SYMBOL(drm_property_destroy); 3919f453ba04SDave Airlie 3920c8e32cc1SDaniel Vetter /** 3921c8e32cc1SDaniel Vetter * drm_object_attach_property - attach a property to a modeset object 3922c8e32cc1SDaniel Vetter * @obj: drm modeset object 3923c8e32cc1SDaniel Vetter * @property: property to attach 3924c8e32cc1SDaniel Vetter * @init_val: initial value of the property 3925c8e32cc1SDaniel Vetter * 3926c8e32cc1SDaniel Vetter * This attaches the given property to the modeset object with the given initial 3927c8e32cc1SDaniel Vetter * value. Currently this function cannot fail since the properties are stored in 3928c8e32cc1SDaniel Vetter * a statically sized array. 3929c8e32cc1SDaniel Vetter */ 3930c543188aSPaulo Zanoni void drm_object_attach_property(struct drm_mode_object *obj, 3931c543188aSPaulo Zanoni struct drm_property *property, 3932c543188aSPaulo Zanoni uint64_t init_val) 3933c543188aSPaulo Zanoni { 39347f88a9beSPaulo Zanoni int count = obj->properties->count; 3935c543188aSPaulo Zanoni 39367f88a9beSPaulo Zanoni if (count == DRM_OBJECT_MAX_PROPERTY) { 39377f88a9beSPaulo Zanoni WARN(1, "Failed to attach object property (type: 0x%x). Please " 39387f88a9beSPaulo Zanoni "increase DRM_OBJECT_MAX_PROPERTY by 1 for each time " 39397f88a9beSPaulo Zanoni "you see this message on the same object type.\n", 39407f88a9beSPaulo Zanoni obj->type); 3941c543188aSPaulo Zanoni return; 3942c543188aSPaulo Zanoni } 3943c543188aSPaulo Zanoni 3944b17cd757SRob Clark obj->properties->properties[count] = property; 39457f88a9beSPaulo Zanoni obj->properties->values[count] = init_val; 39467f88a9beSPaulo Zanoni obj->properties->count++; 394788a48e29SRob Clark if (property->flags & DRM_MODE_PROP_ATOMIC) 394888a48e29SRob Clark obj->properties->atomic_count++; 3949c543188aSPaulo Zanoni } 3950c543188aSPaulo Zanoni EXPORT_SYMBOL(drm_object_attach_property); 3951c543188aSPaulo Zanoni 3952c8e32cc1SDaniel Vetter /** 3953c8e32cc1SDaniel Vetter * drm_object_property_set_value - set the value of a property 3954c8e32cc1SDaniel Vetter * @obj: drm mode object to set property value for 3955c8e32cc1SDaniel Vetter * @property: property to set 3956c8e32cc1SDaniel Vetter * @val: value the property should be set to 3957c8e32cc1SDaniel Vetter * 3958c8e32cc1SDaniel Vetter * This functions sets a given property on a given object. This function only 3959c8e32cc1SDaniel Vetter * changes the software state of the property, it does not call into the 3960c8e32cc1SDaniel Vetter * driver's ->set_property callback. 3961c8e32cc1SDaniel Vetter * 3962c8e32cc1SDaniel Vetter * Returns: 3963c8e32cc1SDaniel Vetter * Zero on success, error code on failure. 3964c8e32cc1SDaniel Vetter */ 3965c543188aSPaulo Zanoni int drm_object_property_set_value(struct drm_mode_object *obj, 3966c543188aSPaulo Zanoni struct drm_property *property, uint64_t val) 3967c543188aSPaulo Zanoni { 3968c543188aSPaulo Zanoni int i; 3969c543188aSPaulo Zanoni 39707f88a9beSPaulo Zanoni for (i = 0; i < obj->properties->count; i++) { 3971b17cd757SRob Clark if (obj->properties->properties[i] == property) { 3972c543188aSPaulo Zanoni obj->properties->values[i] = val; 3973c543188aSPaulo Zanoni return 0; 3974c543188aSPaulo Zanoni } 3975c543188aSPaulo Zanoni } 3976c543188aSPaulo Zanoni 3977c543188aSPaulo Zanoni return -EINVAL; 3978c543188aSPaulo Zanoni } 3979c543188aSPaulo Zanoni EXPORT_SYMBOL(drm_object_property_set_value); 3980c543188aSPaulo Zanoni 3981c8e32cc1SDaniel Vetter /** 3982c8e32cc1SDaniel Vetter * drm_object_property_get_value - retrieve the value of a property 3983c8e32cc1SDaniel Vetter * @obj: drm mode object to get property value from 3984c8e32cc1SDaniel Vetter * @property: property to retrieve 3985c8e32cc1SDaniel Vetter * @val: storage for the property value 3986c8e32cc1SDaniel Vetter * 3987c8e32cc1SDaniel Vetter * This function retrieves the softare state of the given property for the given 3988c8e32cc1SDaniel Vetter * property. Since there is no driver callback to retrieve the current property 3989c8e32cc1SDaniel Vetter * value this might be out of sync with the hardware, depending upon the driver 3990c8e32cc1SDaniel Vetter * and property. 3991c8e32cc1SDaniel Vetter * 3992c8e32cc1SDaniel Vetter * Returns: 3993c8e32cc1SDaniel Vetter * Zero on success, error code on failure. 3994c8e32cc1SDaniel Vetter */ 3995c543188aSPaulo Zanoni int drm_object_property_get_value(struct drm_mode_object *obj, 3996c543188aSPaulo Zanoni struct drm_property *property, uint64_t *val) 3997c543188aSPaulo Zanoni { 3998c543188aSPaulo Zanoni int i; 3999c543188aSPaulo Zanoni 400088a48e29SRob Clark /* read-only properties bypass atomic mechanism and still store 400188a48e29SRob Clark * their value in obj->properties->values[].. mostly to avoid 400288a48e29SRob Clark * having to deal w/ EDID and similar props in atomic paths: 400388a48e29SRob Clark */ 400488a48e29SRob Clark if (drm_core_check_feature(property->dev, DRIVER_ATOMIC) && 400588a48e29SRob Clark !(property->flags & DRM_MODE_PROP_IMMUTABLE)) 400688a48e29SRob Clark return drm_atomic_get_property(obj, property, val); 400788a48e29SRob Clark 40087f88a9beSPaulo Zanoni for (i = 0; i < obj->properties->count; i++) { 4009b17cd757SRob Clark if (obj->properties->properties[i] == property) { 4010c543188aSPaulo Zanoni *val = obj->properties->values[i]; 4011c543188aSPaulo Zanoni return 0; 4012c543188aSPaulo Zanoni } 4013c543188aSPaulo Zanoni } 4014c543188aSPaulo Zanoni 4015c543188aSPaulo Zanoni return -EINVAL; 4016c543188aSPaulo Zanoni } 4017c543188aSPaulo Zanoni EXPORT_SYMBOL(drm_object_property_get_value); 4018c543188aSPaulo Zanoni 4019c8e32cc1SDaniel Vetter /** 40201a498633SDaniel Vetter * drm_mode_getproperty_ioctl - get the property metadata 4021c8e32cc1SDaniel Vetter * @dev: DRM device 4022c8e32cc1SDaniel Vetter * @data: ioctl data 4023c8e32cc1SDaniel Vetter * @file_priv: DRM file info 4024c8e32cc1SDaniel Vetter * 40251a498633SDaniel Vetter * This function retrieves the metadata for a given property, like the different 40261a498633SDaniel Vetter * possible values for an enum property or the limits for a range property. 40271a498633SDaniel Vetter * 40281a498633SDaniel Vetter * Blob properties are special 4029c8e32cc1SDaniel Vetter * 4030c8e32cc1SDaniel Vetter * Called by the user via ioctl. 4031c8e32cc1SDaniel Vetter * 4032c8e32cc1SDaniel Vetter * Returns: 40331a498633SDaniel Vetter * Zero on success, negative errno on failure. 4034c8e32cc1SDaniel Vetter */ 4035f453ba04SDave Airlie int drm_mode_getproperty_ioctl(struct drm_device *dev, 4036f453ba04SDave Airlie void *data, struct drm_file *file_priv) 4037f453ba04SDave Airlie { 4038f453ba04SDave Airlie struct drm_mode_get_property *out_resp = data; 4039f453ba04SDave Airlie struct drm_property *property; 4040f453ba04SDave Airlie int enum_count = 0; 4041f453ba04SDave Airlie int value_count = 0; 4042f453ba04SDave Airlie int ret = 0, i; 4043f453ba04SDave Airlie int copied; 4044f453ba04SDave Airlie struct drm_property_enum *prop_enum; 4045f453ba04SDave Airlie struct drm_mode_property_enum __user *enum_ptr; 4046f453ba04SDave Airlie uint64_t __user *values_ptr; 4047f453ba04SDave Airlie 4048fb3b06c8SDave Airlie if (!drm_core_check_feature(dev, DRIVER_MODESET)) 4049fb3b06c8SDave Airlie return -EINVAL; 4050fb3b06c8SDave Airlie 405184849903SDaniel Vetter drm_modeset_lock_all(dev); 4052a2b34e22SRob Clark property = drm_property_find(dev, out_resp->prop_id); 4053a2b34e22SRob Clark if (!property) { 4054f27657f2SVille Syrjälä ret = -ENOENT; 4055f453ba04SDave Airlie goto done; 4056f453ba04SDave Airlie } 4057f453ba04SDave Airlie 40585ea22f24SRob Clark if (drm_property_type_is(property, DRM_MODE_PROP_ENUM) || 40595ea22f24SRob Clark drm_property_type_is(property, DRM_MODE_PROP_BITMASK)) { 40603758b341SDaniel Vetter list_for_each_entry(prop_enum, &property->enum_list, head) 4061f453ba04SDave Airlie enum_count++; 4062f453ba04SDave Airlie } 4063f453ba04SDave Airlie 4064f453ba04SDave Airlie value_count = property->num_values; 4065f453ba04SDave Airlie 4066f453ba04SDave Airlie strncpy(out_resp->name, property->name, DRM_PROP_NAME_LEN); 4067f453ba04SDave Airlie out_resp->name[DRM_PROP_NAME_LEN-1] = 0; 4068f453ba04SDave Airlie out_resp->flags = property->flags; 4069f453ba04SDave Airlie 4070f453ba04SDave Airlie if ((out_resp->count_values >= value_count) && value_count) { 407181f6c7f8SVille Syrjälä values_ptr = (uint64_t __user *)(unsigned long)out_resp->values_ptr; 4072f453ba04SDave Airlie for (i = 0; i < value_count; i++) { 4073f453ba04SDave Airlie if (copy_to_user(values_ptr + i, &property->values[i], sizeof(uint64_t))) { 4074f453ba04SDave Airlie ret = -EFAULT; 4075f453ba04SDave Airlie goto done; 4076f453ba04SDave Airlie } 4077f453ba04SDave Airlie } 4078f453ba04SDave Airlie } 4079f453ba04SDave Airlie out_resp->count_values = value_count; 4080f453ba04SDave Airlie 40815ea22f24SRob Clark if (drm_property_type_is(property, DRM_MODE_PROP_ENUM) || 40825ea22f24SRob Clark drm_property_type_is(property, DRM_MODE_PROP_BITMASK)) { 4083f453ba04SDave Airlie if ((out_resp->count_enum_blobs >= enum_count) && enum_count) { 4084f453ba04SDave Airlie copied = 0; 408581f6c7f8SVille Syrjälä enum_ptr = (struct drm_mode_property_enum __user *)(unsigned long)out_resp->enum_blob_ptr; 40863758b341SDaniel Vetter list_for_each_entry(prop_enum, &property->enum_list, head) { 4087f453ba04SDave Airlie 4088f453ba04SDave Airlie if (copy_to_user(&enum_ptr[copied].value, &prop_enum->value, sizeof(uint64_t))) { 4089f453ba04SDave Airlie ret = -EFAULT; 4090f453ba04SDave Airlie goto done; 4091f453ba04SDave Airlie } 4092f453ba04SDave Airlie 4093f453ba04SDave Airlie if (copy_to_user(&enum_ptr[copied].name, 4094f453ba04SDave Airlie &prop_enum->name, DRM_PROP_NAME_LEN)) { 4095f453ba04SDave Airlie ret = -EFAULT; 4096f453ba04SDave Airlie goto done; 4097f453ba04SDave Airlie } 4098f453ba04SDave Airlie copied++; 4099f453ba04SDave Airlie } 4100f453ba04SDave Airlie } 4101f453ba04SDave Airlie out_resp->count_enum_blobs = enum_count; 4102f453ba04SDave Airlie } 4103f453ba04SDave Airlie 41043758b341SDaniel Vetter /* 41053758b341SDaniel Vetter * NOTE: The idea seems to have been to use this to read all the blob 41063758b341SDaniel Vetter * property values. But nothing ever added them to the corresponding 41073758b341SDaniel Vetter * list, userspace always used the special-purpose get_blob ioctl to 41083758b341SDaniel Vetter * read the value for a blob property. It also doesn't make a lot of 41093758b341SDaniel Vetter * sense to return values here when everything else is just metadata for 41103758b341SDaniel Vetter * the property itself. 41113758b341SDaniel Vetter */ 41123758b341SDaniel Vetter if (drm_property_type_is(property, DRM_MODE_PROP_BLOB)) 41133758b341SDaniel Vetter out_resp->count_enum_blobs = 0; 4114f453ba04SDave Airlie done: 411584849903SDaniel Vetter drm_modeset_unlock_all(dev); 4116f453ba04SDave Airlie return ret; 4117f453ba04SDave Airlie } 4118f453ba04SDave Airlie 411999531d9bSDaniel Stone /** 412099531d9bSDaniel Stone * drm_property_create_blob - Create new blob property 412199531d9bSDaniel Stone * 412299531d9bSDaniel Stone * Creates a new blob property for a specified DRM device, optionally 412399531d9bSDaniel Stone * copying data. 412499531d9bSDaniel Stone * 412599531d9bSDaniel Stone * @dev: DRM device to create property for 412699531d9bSDaniel Stone * @length: Length to allocate for blob data 412799531d9bSDaniel Stone * @data: If specified, copies data into blob 412810e8cb7eSDaniel Stone * 412910e8cb7eSDaniel Stone * Returns: 413010e8cb7eSDaniel Stone * New blob property with a single reference on success, or an ERR_PTR 413110e8cb7eSDaniel Stone * value on failure. 413299531d9bSDaniel Stone */ 41336bcacf51SDaniel Stone struct drm_property_blob * 4134ecbbe59bSThierry Reding drm_property_create_blob(struct drm_device *dev, size_t length, 413512e6cecdSThierry Reding const void *data) 4136f453ba04SDave Airlie { 4137f453ba04SDave Airlie struct drm_property_blob *blob; 41386bfc56aaSVille Syrjälä int ret; 4139f453ba04SDave Airlie 41409ac0934bSDan Carpenter if (!length || length > ULONG_MAX - sizeof(struct drm_property_blob)) 414110e8cb7eSDaniel Stone return ERR_PTR(-EINVAL); 4142f453ba04SDave Airlie 4143f453ba04SDave Airlie blob = kzalloc(sizeof(struct drm_property_blob)+length, GFP_KERNEL); 4144f453ba04SDave Airlie if (!blob) 414510e8cb7eSDaniel Stone return ERR_PTR(-ENOMEM); 4146f453ba04SDave Airlie 4147e2f5d2eaSDaniel Stone /* This must be explicitly initialised, so we can safely call list_del 4148e2f5d2eaSDaniel Stone * on it in the removal handler, even if it isn't in a file list. */ 4149e2f5d2eaSDaniel Stone INIT_LIST_HEAD(&blob->head_file); 4150f453ba04SDave Airlie blob->length = length; 41516bcacf51SDaniel Stone blob->dev = dev; 4152f453ba04SDave Airlie 415399531d9bSDaniel Stone if (data) 4154f453ba04SDave Airlie memcpy(blob->data, data, length); 4155f453ba04SDave Airlie 41568fb6e7a5SDaniel Stone mutex_lock(&dev->mode_config.blob_lock); 41578fb6e7a5SDaniel Stone 41588fb6e7a5SDaniel Stone ret = drm_mode_object_get(dev, &blob->base, DRM_MODE_OBJECT_BLOB); 41598fb6e7a5SDaniel Stone if (ret) { 41608fb6e7a5SDaniel Stone kfree(blob); 41618fb6e7a5SDaniel Stone mutex_unlock(&dev->mode_config.blob_lock); 416210e8cb7eSDaniel Stone return ERR_PTR(-EINVAL); 41638fb6e7a5SDaniel Stone } 41648fb6e7a5SDaniel Stone 41656bcacf51SDaniel Stone kref_init(&blob->refcount); 41666bcacf51SDaniel Stone 4167e2f5d2eaSDaniel Stone list_add_tail(&blob->head_global, 4168e2f5d2eaSDaniel Stone &dev->mode_config.property_blob_list); 41698fb6e7a5SDaniel Stone 41708fb6e7a5SDaniel Stone mutex_unlock(&dev->mode_config.blob_lock); 41718fb6e7a5SDaniel Stone 4172f453ba04SDave Airlie return blob; 4173f453ba04SDave Airlie } 41746bcacf51SDaniel Stone EXPORT_SYMBOL(drm_property_create_blob); 4175f453ba04SDave Airlie 41766bcacf51SDaniel Stone /** 41776bcacf51SDaniel Stone * drm_property_free_blob - Blob property destructor 41786bcacf51SDaniel Stone * 41796bcacf51SDaniel Stone * Internal free function for blob properties; must not be used directly. 41806bcacf51SDaniel Stone * 4181f102c16eSDaniel Stone * @kref: Reference 41826bcacf51SDaniel Stone */ 41836bcacf51SDaniel Stone static void drm_property_free_blob(struct kref *kref) 4184f453ba04SDave Airlie { 41856bcacf51SDaniel Stone struct drm_property_blob *blob = 41866bcacf51SDaniel Stone container_of(kref, struct drm_property_blob, refcount); 41876bcacf51SDaniel Stone 41886bcacf51SDaniel Stone WARN_ON(!mutex_is_locked(&blob->dev->mode_config.blob_lock)); 41896bcacf51SDaniel Stone 4190e2f5d2eaSDaniel Stone list_del(&blob->head_global); 4191e2f5d2eaSDaniel Stone list_del(&blob->head_file); 41926bcacf51SDaniel Stone drm_mode_object_put(blob->dev, &blob->base); 41938fb6e7a5SDaniel Stone 4194f453ba04SDave Airlie kfree(blob); 4195f453ba04SDave Airlie } 4196f453ba04SDave Airlie 4197c8e32cc1SDaniel Vetter /** 41986bcacf51SDaniel Stone * drm_property_unreference_blob - Unreference a blob property 41996bcacf51SDaniel Stone * 42006bcacf51SDaniel Stone * Drop a reference on a blob property. May free the object. 42016bcacf51SDaniel Stone * 4202f102c16eSDaniel Stone * @blob: Pointer to blob property 42036bcacf51SDaniel Stone */ 42046bcacf51SDaniel Stone void drm_property_unreference_blob(struct drm_property_blob *blob) 42056bcacf51SDaniel Stone { 42066bcacf51SDaniel Stone struct drm_device *dev; 42076bcacf51SDaniel Stone 42086bcacf51SDaniel Stone if (!blob) 42096bcacf51SDaniel Stone return; 42106bcacf51SDaniel Stone 42116bcacf51SDaniel Stone dev = blob->dev; 42126bcacf51SDaniel Stone 42136bcacf51SDaniel Stone DRM_DEBUG("%p: blob ID: %d (%d)\n", blob, blob->base.id, atomic_read(&blob->refcount.refcount)); 42146bcacf51SDaniel Stone 42156bcacf51SDaniel Stone if (kref_put_mutex(&blob->refcount, drm_property_free_blob, 42166bcacf51SDaniel Stone &dev->mode_config.blob_lock)) 42176bcacf51SDaniel Stone mutex_unlock(&dev->mode_config.blob_lock); 42186bcacf51SDaniel Stone else 42196bcacf51SDaniel Stone might_lock(&dev->mode_config.blob_lock); 42206bcacf51SDaniel Stone } 42216bcacf51SDaniel Stone EXPORT_SYMBOL(drm_property_unreference_blob); 42226bcacf51SDaniel Stone 42236bcacf51SDaniel Stone /** 42246bcacf51SDaniel Stone * drm_property_unreference_blob_locked - Unreference a blob property with blob_lock held 42256bcacf51SDaniel Stone * 42266bcacf51SDaniel Stone * Drop a reference on a blob property. May free the object. This must be 42276bcacf51SDaniel Stone * called with blob_lock held. 42286bcacf51SDaniel Stone * 4229f102c16eSDaniel Stone * @blob: Pointer to blob property 42306bcacf51SDaniel Stone */ 42316bcacf51SDaniel Stone static void drm_property_unreference_blob_locked(struct drm_property_blob *blob) 42326bcacf51SDaniel Stone { 42336bcacf51SDaniel Stone if (!blob) 42346bcacf51SDaniel Stone return; 42356bcacf51SDaniel Stone 42366bcacf51SDaniel Stone DRM_DEBUG("%p: blob ID: %d (%d)\n", blob, blob->base.id, atomic_read(&blob->refcount.refcount)); 42376bcacf51SDaniel Stone 42386bcacf51SDaniel Stone kref_put(&blob->refcount, drm_property_free_blob); 42396bcacf51SDaniel Stone } 42406bcacf51SDaniel Stone 42416bcacf51SDaniel Stone /** 4242e2f5d2eaSDaniel Stone * drm_property_destroy_user_blobs - destroy all blobs created by this client 4243e2f5d2eaSDaniel Stone * @dev: DRM device 4244e2f5d2eaSDaniel Stone * @file_priv: destroy all blobs owned by this file handle 4245e2f5d2eaSDaniel Stone */ 4246e2f5d2eaSDaniel Stone void drm_property_destroy_user_blobs(struct drm_device *dev, 4247e2f5d2eaSDaniel Stone struct drm_file *file_priv) 4248e2f5d2eaSDaniel Stone { 4249e2f5d2eaSDaniel Stone struct drm_property_blob *blob, *bt; 4250e2f5d2eaSDaniel Stone 4251e2f5d2eaSDaniel Stone mutex_lock(&dev->mode_config.blob_lock); 4252e2f5d2eaSDaniel Stone 4253e2f5d2eaSDaniel Stone list_for_each_entry_safe(blob, bt, &file_priv->blobs, head_file) { 4254e2f5d2eaSDaniel Stone list_del_init(&blob->head_file); 4255e2f5d2eaSDaniel Stone drm_property_unreference_blob_locked(blob); 4256e2f5d2eaSDaniel Stone } 4257e2f5d2eaSDaniel Stone 4258e2f5d2eaSDaniel Stone mutex_unlock(&dev->mode_config.blob_lock); 4259e2f5d2eaSDaniel Stone } 4260e2f5d2eaSDaniel Stone 4261e2f5d2eaSDaniel Stone /** 42626bcacf51SDaniel Stone * drm_property_reference_blob - Take a reference on an existing property 42636bcacf51SDaniel Stone * 42646bcacf51SDaniel Stone * Take a new reference on an existing blob property. 42656bcacf51SDaniel Stone * 4266f102c16eSDaniel Stone * @blob: Pointer to blob property 42676bcacf51SDaniel Stone */ 42686bcacf51SDaniel Stone struct drm_property_blob *drm_property_reference_blob(struct drm_property_blob *blob) 42696bcacf51SDaniel Stone { 42706bcacf51SDaniel Stone DRM_DEBUG("%p: blob ID: %d (%d)\n", blob, blob->base.id, atomic_read(&blob->refcount.refcount)); 42716bcacf51SDaniel Stone kref_get(&blob->refcount); 42726bcacf51SDaniel Stone return blob; 42736bcacf51SDaniel Stone } 42746bcacf51SDaniel Stone EXPORT_SYMBOL(drm_property_reference_blob); 42756bcacf51SDaniel Stone 42766bcacf51SDaniel Stone /* 42776bcacf51SDaniel Stone * Like drm_property_lookup_blob, but does not return an additional reference. 42786bcacf51SDaniel Stone * Must be called with blob_lock held. 42796bcacf51SDaniel Stone */ 42806bcacf51SDaniel Stone static struct drm_property_blob *__drm_property_lookup_blob(struct drm_device *dev, 42816bcacf51SDaniel Stone uint32_t id) 42826bcacf51SDaniel Stone { 42836bcacf51SDaniel Stone struct drm_mode_object *obj = NULL; 42846bcacf51SDaniel Stone struct drm_property_blob *blob; 42856bcacf51SDaniel Stone 42866bcacf51SDaniel Stone WARN_ON(!mutex_is_locked(&dev->mode_config.blob_lock)); 42876bcacf51SDaniel Stone 42886bcacf51SDaniel Stone mutex_lock(&dev->mode_config.idr_mutex); 42896bcacf51SDaniel Stone obj = idr_find(&dev->mode_config.crtc_idr, id); 42906bcacf51SDaniel Stone if (!obj || (obj->type != DRM_MODE_OBJECT_BLOB) || (obj->id != id)) 42916bcacf51SDaniel Stone blob = NULL; 42926bcacf51SDaniel Stone else 42936bcacf51SDaniel Stone blob = obj_to_blob(obj); 42946bcacf51SDaniel Stone mutex_unlock(&dev->mode_config.idr_mutex); 42956bcacf51SDaniel Stone 4296f453ba04SDave Airlie return blob; 4297f453ba04SDave Airlie } 4298f453ba04SDave Airlie 42996bcacf51SDaniel Stone /** 43006bcacf51SDaniel Stone * drm_property_lookup_blob - look up a blob property and take a reference 43016bcacf51SDaniel Stone * @dev: drm device 43026bcacf51SDaniel Stone * @id: id of the blob property 43036bcacf51SDaniel Stone * 43046bcacf51SDaniel Stone * If successful, this takes an additional reference to the blob property. 43056bcacf51SDaniel Stone * callers need to make sure to eventually unreference the returned property 43066bcacf51SDaniel Stone * again, using @drm_property_unreference_blob. 43076bcacf51SDaniel Stone */ 43086bcacf51SDaniel Stone struct drm_property_blob *drm_property_lookup_blob(struct drm_device *dev, 43096bcacf51SDaniel Stone uint32_t id) 4310f453ba04SDave Airlie { 43116bcacf51SDaniel Stone struct drm_property_blob *blob; 43126bcacf51SDaniel Stone 43136bcacf51SDaniel Stone mutex_lock(&dev->mode_config.blob_lock); 43146bcacf51SDaniel Stone blob = __drm_property_lookup_blob(dev, id); 43156bcacf51SDaniel Stone if (blob) { 43166bcacf51SDaniel Stone if (!kref_get_unless_zero(&blob->refcount)) 43176bcacf51SDaniel Stone blob = NULL; 43186bcacf51SDaniel Stone } 43196bcacf51SDaniel Stone mutex_unlock(&dev->mode_config.blob_lock); 43206bcacf51SDaniel Stone 43216bcacf51SDaniel Stone return blob; 43226bcacf51SDaniel Stone } 43236bcacf51SDaniel Stone EXPORT_SYMBOL(drm_property_lookup_blob); 43246bcacf51SDaniel Stone 43256bcacf51SDaniel Stone /** 4326d2ed3436SDaniel Stone * drm_property_replace_global_blob - atomically replace existing blob property 4327d2ed3436SDaniel Stone * @dev: drm device 4328d2ed3436SDaniel Stone * @replace: location of blob property pointer to be replaced 4329d2ed3436SDaniel Stone * @length: length of data for new blob, or 0 for no data 4330d2ed3436SDaniel Stone * @data: content for new blob, or NULL for no data 4331d2ed3436SDaniel Stone * @obj_holds_id: optional object for property holding blob ID 4332d2ed3436SDaniel Stone * @prop_holds_id: optional property holding blob ID 4333d2ed3436SDaniel Stone * @return 0 on success or error on failure 4334d2ed3436SDaniel Stone * 4335d2ed3436SDaniel Stone * This function will atomically replace a global property in the blob list, 4336d2ed3436SDaniel Stone * optionally updating a property which holds the ID of that property. It is 4337d2ed3436SDaniel Stone * guaranteed to be atomic: no caller will be allowed to see intermediate 4338d2ed3436SDaniel Stone * results, and either the entire operation will succeed and clean up the 4339d2ed3436SDaniel Stone * previous property, or it will fail and the state will be unchanged. 4340d2ed3436SDaniel Stone * 4341d2ed3436SDaniel Stone * If length is 0 or data is NULL, no new blob will be created, and the holding 4342d2ed3436SDaniel Stone * property, if specified, will be set to 0. 4343d2ed3436SDaniel Stone * 4344d2ed3436SDaniel Stone * Access to the replace pointer is assumed to be protected by the caller, e.g. 4345d2ed3436SDaniel Stone * by holding the relevant modesetting object lock for its parent. 4346d2ed3436SDaniel Stone * 4347d2ed3436SDaniel Stone * For example, a drm_connector has a 'PATH' property, which contains the ID 4348d2ed3436SDaniel Stone * of a blob property with the value of the MST path information. Calling this 4349d2ed3436SDaniel Stone * function with replace pointing to the connector's path_blob_ptr, length and 4350d2ed3436SDaniel Stone * data set for the new path information, obj_holds_id set to the connector's 4351d2ed3436SDaniel Stone * base object, and prop_holds_id set to the path property name, will perform 4352d2ed3436SDaniel Stone * a completely atomic update. The access to path_blob_ptr is protected by the 4353d2ed3436SDaniel Stone * caller holding a lock on the connector. 4354d2ed3436SDaniel Stone */ 4355d2ed3436SDaniel Stone static int drm_property_replace_global_blob(struct drm_device *dev, 4356d2ed3436SDaniel Stone struct drm_property_blob **replace, 4357d2ed3436SDaniel Stone size_t length, 4358d2ed3436SDaniel Stone const void *data, 4359d2ed3436SDaniel Stone struct drm_mode_object *obj_holds_id, 4360d2ed3436SDaniel Stone struct drm_property *prop_holds_id) 4361d2ed3436SDaniel Stone { 4362d2ed3436SDaniel Stone struct drm_property_blob *new_blob = NULL; 4363d2ed3436SDaniel Stone struct drm_property_blob *old_blob = NULL; 4364d2ed3436SDaniel Stone int ret; 4365d2ed3436SDaniel Stone 4366d2ed3436SDaniel Stone WARN_ON(replace == NULL); 4367d2ed3436SDaniel Stone 4368d2ed3436SDaniel Stone old_blob = *replace; 4369d2ed3436SDaniel Stone 4370d2ed3436SDaniel Stone if (length && data) { 4371d2ed3436SDaniel Stone new_blob = drm_property_create_blob(dev, length, data); 437210e8cb7eSDaniel Stone if (IS_ERR(new_blob)) 437310e8cb7eSDaniel Stone return PTR_ERR(new_blob); 4374d2ed3436SDaniel Stone } 4375d2ed3436SDaniel Stone 4376d2ed3436SDaniel Stone /* This does not need to be synchronised with blob_lock, as the 4377d2ed3436SDaniel Stone * get_properties ioctl locks all modesetting objects, and 4378d2ed3436SDaniel Stone * obj_holds_id must be locked before calling here, so we cannot 4379d2ed3436SDaniel Stone * have its value out of sync with the list membership modified 4380d2ed3436SDaniel Stone * below under blob_lock. */ 4381d2ed3436SDaniel Stone if (obj_holds_id) { 4382d2ed3436SDaniel Stone ret = drm_object_property_set_value(obj_holds_id, 4383d2ed3436SDaniel Stone prop_holds_id, 4384d2ed3436SDaniel Stone new_blob ? 4385d2ed3436SDaniel Stone new_blob->base.id : 0); 4386d2ed3436SDaniel Stone if (ret != 0) 4387d2ed3436SDaniel Stone goto err_created; 4388d2ed3436SDaniel Stone } 4389d2ed3436SDaniel Stone 43906bcacf51SDaniel Stone drm_property_unreference_blob(old_blob); 4391d2ed3436SDaniel Stone *replace = new_blob; 4392d2ed3436SDaniel Stone 4393d2ed3436SDaniel Stone return 0; 4394d2ed3436SDaniel Stone 4395d2ed3436SDaniel Stone err_created: 43966bcacf51SDaniel Stone drm_property_unreference_blob(new_blob); 4397d2ed3436SDaniel Stone return ret; 4398f453ba04SDave Airlie } 4399f453ba04SDave Airlie 4400c8e32cc1SDaniel Vetter /** 4401c8e32cc1SDaniel Vetter * drm_mode_getblob_ioctl - get the contents of a blob property value 4402c8e32cc1SDaniel Vetter * @dev: DRM device 4403c8e32cc1SDaniel Vetter * @data: ioctl data 4404c8e32cc1SDaniel Vetter * @file_priv: DRM file info 4405c8e32cc1SDaniel Vetter * 4406c8e32cc1SDaniel Vetter * This function retrieves the contents of a blob property. The value stored in 4407c8e32cc1SDaniel Vetter * an object's blob property is just a normal modeset object id. 4408c8e32cc1SDaniel Vetter * 4409c8e32cc1SDaniel Vetter * Called by the user via ioctl. 4410c8e32cc1SDaniel Vetter * 4411c8e32cc1SDaniel Vetter * Returns: 44121a498633SDaniel Vetter * Zero on success, negative errno on failure. 4413c8e32cc1SDaniel Vetter */ 4414f453ba04SDave Airlie int drm_mode_getblob_ioctl(struct drm_device *dev, 4415f453ba04SDave Airlie void *data, struct drm_file *file_priv) 4416f453ba04SDave Airlie { 4417f453ba04SDave Airlie struct drm_mode_get_blob *out_resp = data; 4418f453ba04SDave Airlie struct drm_property_blob *blob; 4419f453ba04SDave Airlie int ret = 0; 442081f6c7f8SVille Syrjälä void __user *blob_ptr; 4421f453ba04SDave Airlie 4422fb3b06c8SDave Airlie if (!drm_core_check_feature(dev, DRIVER_MODESET)) 4423fb3b06c8SDave Airlie return -EINVAL; 4424fb3b06c8SDave Airlie 442584849903SDaniel Vetter drm_modeset_lock_all(dev); 44268fb6e7a5SDaniel Stone mutex_lock(&dev->mode_config.blob_lock); 44276bcacf51SDaniel Stone blob = __drm_property_lookup_blob(dev, out_resp->blob_id); 4428a2b34e22SRob Clark if (!blob) { 4429f27657f2SVille Syrjälä ret = -ENOENT; 4430f453ba04SDave Airlie goto done; 4431f453ba04SDave Airlie } 4432f453ba04SDave Airlie 4433f453ba04SDave Airlie if (out_resp->length == blob->length) { 443481f6c7f8SVille Syrjälä blob_ptr = (void __user *)(unsigned long)out_resp->data; 4435f453ba04SDave Airlie if (copy_to_user(blob_ptr, blob->data, blob->length)) { 4436f453ba04SDave Airlie ret = -EFAULT; 4437f453ba04SDave Airlie goto done; 4438f453ba04SDave Airlie } 4439f453ba04SDave Airlie } 4440f453ba04SDave Airlie out_resp->length = blob->length; 4441f453ba04SDave Airlie 4442f453ba04SDave Airlie done: 44438fb6e7a5SDaniel Stone mutex_unlock(&dev->mode_config.blob_lock); 444484849903SDaniel Vetter drm_modeset_unlock_all(dev); 4445f453ba04SDave Airlie return ret; 4446f453ba04SDave Airlie } 4447f453ba04SDave Airlie 4448cc7096fbSDave Airlie /** 4449e2f5d2eaSDaniel Stone * drm_mode_createblob_ioctl - create a new blob property 4450e2f5d2eaSDaniel Stone * @dev: DRM device 4451e2f5d2eaSDaniel Stone * @data: ioctl data 4452e2f5d2eaSDaniel Stone * @file_priv: DRM file info 4453e2f5d2eaSDaniel Stone * 4454e2f5d2eaSDaniel Stone * This function creates a new blob property with user-defined values. In order 4455e2f5d2eaSDaniel Stone * to give us sensible validation and checking when creating, rather than at 4456e2f5d2eaSDaniel Stone * every potential use, we also require a type to be provided upfront. 4457e2f5d2eaSDaniel Stone * 4458e2f5d2eaSDaniel Stone * Called by the user via ioctl. 4459e2f5d2eaSDaniel Stone * 4460e2f5d2eaSDaniel Stone * Returns: 4461e2f5d2eaSDaniel Stone * Zero on success, negative errno on failure. 4462e2f5d2eaSDaniel Stone */ 4463e2f5d2eaSDaniel Stone int drm_mode_createblob_ioctl(struct drm_device *dev, 4464e2f5d2eaSDaniel Stone void *data, struct drm_file *file_priv) 4465e2f5d2eaSDaniel Stone { 4466e2f5d2eaSDaniel Stone struct drm_mode_create_blob *out_resp = data; 4467e2f5d2eaSDaniel Stone struct drm_property_blob *blob; 4468e2f5d2eaSDaniel Stone void __user *blob_ptr; 4469e2f5d2eaSDaniel Stone int ret = 0; 4470e2f5d2eaSDaniel Stone 4471e2f5d2eaSDaniel Stone if (!drm_core_check_feature(dev, DRIVER_MODESET)) 4472e2f5d2eaSDaniel Stone return -EINVAL; 4473e2f5d2eaSDaniel Stone 4474e2f5d2eaSDaniel Stone blob = drm_property_create_blob(dev, out_resp->length, NULL); 4475e2f5d2eaSDaniel Stone if (IS_ERR(blob)) 4476e2f5d2eaSDaniel Stone return PTR_ERR(blob); 4477e2f5d2eaSDaniel Stone 4478e2f5d2eaSDaniel Stone blob_ptr = (void __user *)(unsigned long)out_resp->data; 4479e2f5d2eaSDaniel Stone if (copy_from_user(blob->data, blob_ptr, out_resp->length)) { 4480e2f5d2eaSDaniel Stone ret = -EFAULT; 4481e2f5d2eaSDaniel Stone goto out_blob; 4482e2f5d2eaSDaniel Stone } 4483e2f5d2eaSDaniel Stone 4484e2f5d2eaSDaniel Stone /* Dropping the lock between create_blob and our access here is safe 4485e2f5d2eaSDaniel Stone * as only the same file_priv can remove the blob; at this point, it is 4486e2f5d2eaSDaniel Stone * not associated with any file_priv. */ 4487e2f5d2eaSDaniel Stone mutex_lock(&dev->mode_config.blob_lock); 4488e2f5d2eaSDaniel Stone out_resp->blob_id = blob->base.id; 44898731b269SManeet Singh list_add_tail(&blob->head_file, &file_priv->blobs); 4490e2f5d2eaSDaniel Stone mutex_unlock(&dev->mode_config.blob_lock); 4491e2f5d2eaSDaniel Stone 4492e2f5d2eaSDaniel Stone return 0; 4493e2f5d2eaSDaniel Stone 4494e2f5d2eaSDaniel Stone out_blob: 4495e2f5d2eaSDaniel Stone drm_property_unreference_blob(blob); 4496e2f5d2eaSDaniel Stone return ret; 4497e2f5d2eaSDaniel Stone } 4498e2f5d2eaSDaniel Stone 4499e2f5d2eaSDaniel Stone /** 4500e2f5d2eaSDaniel Stone * drm_mode_destroyblob_ioctl - destroy a user blob property 4501e2f5d2eaSDaniel Stone * @dev: DRM device 4502e2f5d2eaSDaniel Stone * @data: ioctl data 4503e2f5d2eaSDaniel Stone * @file_priv: DRM file info 4504e2f5d2eaSDaniel Stone * 4505e2f5d2eaSDaniel Stone * Destroy an existing user-defined blob property. 4506e2f5d2eaSDaniel Stone * 4507e2f5d2eaSDaniel Stone * Called by the user via ioctl. 4508e2f5d2eaSDaniel Stone * 4509e2f5d2eaSDaniel Stone * Returns: 4510e2f5d2eaSDaniel Stone * Zero on success, negative errno on failure. 4511e2f5d2eaSDaniel Stone */ 4512e2f5d2eaSDaniel Stone int drm_mode_destroyblob_ioctl(struct drm_device *dev, 4513e2f5d2eaSDaniel Stone void *data, struct drm_file *file_priv) 4514e2f5d2eaSDaniel Stone { 4515e2f5d2eaSDaniel Stone struct drm_mode_destroy_blob *out_resp = data; 4516e2f5d2eaSDaniel Stone struct drm_property_blob *blob = NULL, *bt; 4517e2f5d2eaSDaniel Stone bool found = false; 4518e2f5d2eaSDaniel Stone int ret = 0; 4519e2f5d2eaSDaniel Stone 4520e2f5d2eaSDaniel Stone if (!drm_core_check_feature(dev, DRIVER_MODESET)) 4521e2f5d2eaSDaniel Stone return -EINVAL; 4522e2f5d2eaSDaniel Stone 4523e2f5d2eaSDaniel Stone mutex_lock(&dev->mode_config.blob_lock); 4524e2f5d2eaSDaniel Stone blob = __drm_property_lookup_blob(dev, out_resp->blob_id); 4525e2f5d2eaSDaniel Stone if (!blob) { 4526e2f5d2eaSDaniel Stone ret = -ENOENT; 4527e2f5d2eaSDaniel Stone goto err; 4528e2f5d2eaSDaniel Stone } 4529e2f5d2eaSDaniel Stone 4530e2f5d2eaSDaniel Stone /* Ensure the property was actually created by this user. */ 4531e2f5d2eaSDaniel Stone list_for_each_entry(bt, &file_priv->blobs, head_file) { 4532e2f5d2eaSDaniel Stone if (bt == blob) { 4533e2f5d2eaSDaniel Stone found = true; 4534e2f5d2eaSDaniel Stone break; 4535e2f5d2eaSDaniel Stone } 4536e2f5d2eaSDaniel Stone } 4537e2f5d2eaSDaniel Stone 4538e2f5d2eaSDaniel Stone if (!found) { 4539e2f5d2eaSDaniel Stone ret = -EPERM; 4540e2f5d2eaSDaniel Stone goto err; 4541e2f5d2eaSDaniel Stone } 4542e2f5d2eaSDaniel Stone 4543e2f5d2eaSDaniel Stone /* We must drop head_file here, because we may not be the last 4544e2f5d2eaSDaniel Stone * reference on the blob. */ 4545e2f5d2eaSDaniel Stone list_del_init(&blob->head_file); 4546e2f5d2eaSDaniel Stone drm_property_unreference_blob_locked(blob); 4547e2f5d2eaSDaniel Stone mutex_unlock(&dev->mode_config.blob_lock); 4548e2f5d2eaSDaniel Stone 4549e2f5d2eaSDaniel Stone return 0; 4550e2f5d2eaSDaniel Stone 4551e2f5d2eaSDaniel Stone err: 4552e2f5d2eaSDaniel Stone mutex_unlock(&dev->mode_config.blob_lock); 4553e2f5d2eaSDaniel Stone return ret; 4554e2f5d2eaSDaniel Stone } 4555e2f5d2eaSDaniel Stone 4556e2f5d2eaSDaniel Stone /** 4557cc7096fbSDave Airlie * drm_mode_connector_set_path_property - set tile property on connector 4558cc7096fbSDave Airlie * @connector: connector to set property on. 4559d2ed3436SDaniel Stone * @path: path to use for property; must not be NULL. 4560cc7096fbSDave Airlie * 4561cc7096fbSDave Airlie * This creates a property to expose to userspace to specify a 4562cc7096fbSDave Airlie * connector path. This is mainly used for DisplayPort MST where 4563cc7096fbSDave Airlie * connectors have a topology and we want to allow userspace to give 4564cc7096fbSDave Airlie * them more meaningful names. 4565cc7096fbSDave Airlie * 4566cc7096fbSDave Airlie * Returns: 45671a498633SDaniel Vetter * Zero on success, negative errno on failure. 4568cc7096fbSDave Airlie */ 456943aba7ebSDave Airlie int drm_mode_connector_set_path_property(struct drm_connector *connector, 457012e6cecdSThierry Reding const char *path) 457143aba7ebSDave Airlie { 457243aba7ebSDave Airlie struct drm_device *dev = connector->dev; 4573ecbbe59bSThierry Reding int ret; 457443aba7ebSDave Airlie 4575d2ed3436SDaniel Stone ret = drm_property_replace_global_blob(dev, 4576d2ed3436SDaniel Stone &connector->path_blob_ptr, 4577d2ed3436SDaniel Stone strlen(path) + 1, 4578d2ed3436SDaniel Stone path, 4579d2ed3436SDaniel Stone &connector->base, 4580d2ed3436SDaniel Stone dev->mode_config.path_property); 458143aba7ebSDave Airlie return ret; 458243aba7ebSDave Airlie } 458343aba7ebSDave Airlie EXPORT_SYMBOL(drm_mode_connector_set_path_property); 458443aba7ebSDave Airlie 4585c8e32cc1SDaniel Vetter /** 45866f134d7bSDave Airlie * drm_mode_connector_set_tile_property - set tile property on connector 45876f134d7bSDave Airlie * @connector: connector to set property on. 45886f134d7bSDave Airlie * 45896f134d7bSDave Airlie * This looks up the tile information for a connector, and creates a 45906f134d7bSDave Airlie * property for userspace to parse if it exists. The property is of 45916f134d7bSDave Airlie * the form of 8 integers using ':' as a separator. 45926f134d7bSDave Airlie * 45936f134d7bSDave Airlie * Returns: 45946f134d7bSDave Airlie * Zero on success, errno on failure. 45956f134d7bSDave Airlie */ 45966f134d7bSDave Airlie int drm_mode_connector_set_tile_property(struct drm_connector *connector) 45976f134d7bSDave Airlie { 45986f134d7bSDave Airlie struct drm_device *dev = connector->dev; 45996f134d7bSDave Airlie char tile[256]; 4600d2ed3436SDaniel Stone int ret; 46016f134d7bSDave Airlie 46026f134d7bSDave Airlie if (!connector->has_tile) { 4603d2ed3436SDaniel Stone ret = drm_property_replace_global_blob(dev, 4604d2ed3436SDaniel Stone &connector->tile_blob_ptr, 4605d2ed3436SDaniel Stone 0, 4606d2ed3436SDaniel Stone NULL, 4607d2ed3436SDaniel Stone &connector->base, 4608d2ed3436SDaniel Stone dev->mode_config.tile_property); 46096f134d7bSDave Airlie return ret; 46106f134d7bSDave Airlie } 46116f134d7bSDave Airlie 46126f134d7bSDave Airlie snprintf(tile, 256, "%d:%d:%d:%d:%d:%d:%d:%d", 46136f134d7bSDave Airlie connector->tile_group->id, connector->tile_is_single_monitor, 46146f134d7bSDave Airlie connector->num_h_tile, connector->num_v_tile, 46156f134d7bSDave Airlie connector->tile_h_loc, connector->tile_v_loc, 46166f134d7bSDave Airlie connector->tile_h_size, connector->tile_v_size); 46176f134d7bSDave Airlie 4618d2ed3436SDaniel Stone ret = drm_property_replace_global_blob(dev, 4619d2ed3436SDaniel Stone &connector->tile_blob_ptr, 4620d2ed3436SDaniel Stone strlen(tile) + 1, 4621d2ed3436SDaniel Stone tile, 4622d2ed3436SDaniel Stone &connector->base, 4623d2ed3436SDaniel Stone dev->mode_config.tile_property); 46246f134d7bSDave Airlie return ret; 46256f134d7bSDave Airlie } 46266f134d7bSDave Airlie EXPORT_SYMBOL(drm_mode_connector_set_tile_property); 46276f134d7bSDave Airlie 46286f134d7bSDave Airlie /** 4629c8e32cc1SDaniel Vetter * drm_mode_connector_update_edid_property - update the edid property of a connector 4630c8e32cc1SDaniel Vetter * @connector: drm connector 4631c8e32cc1SDaniel Vetter * @edid: new value of the edid property 4632c8e32cc1SDaniel Vetter * 4633c8e32cc1SDaniel Vetter * This function creates a new blob modeset object and assigns its id to the 4634c8e32cc1SDaniel Vetter * connector's edid property. 4635c8e32cc1SDaniel Vetter * 4636c8e32cc1SDaniel Vetter * Returns: 46371a498633SDaniel Vetter * Zero on success, negative errno on failure. 4638c8e32cc1SDaniel Vetter */ 4639f453ba04SDave Airlie int drm_mode_connector_update_edid_property(struct drm_connector *connector, 464012e6cecdSThierry Reding const struct edid *edid) 4641f453ba04SDave Airlie { 4642f453ba04SDave Airlie struct drm_device *dev = connector->dev; 4643d2ed3436SDaniel Stone size_t size = 0; 4644ecbbe59bSThierry Reding int ret; 4645f453ba04SDave Airlie 46464cf2b281SThomas Wood /* ignore requests to set edid when overridden */ 46474cf2b281SThomas Wood if (connector->override_edid) 46484cf2b281SThomas Wood return 0; 46494cf2b281SThomas Wood 4650d2ed3436SDaniel Stone if (edid) 4651e24ff467SShixin Zeng size = EDID_LENGTH * (1 + edid->extensions); 4652f453ba04SDave Airlie 4653d2ed3436SDaniel Stone ret = drm_property_replace_global_blob(dev, 4654d2ed3436SDaniel Stone &connector->edid_blob_ptr, 4655d2ed3436SDaniel Stone size, 4656d2ed3436SDaniel Stone edid, 4657d2ed3436SDaniel Stone &connector->base, 4658d2ed3436SDaniel Stone dev->mode_config.edid_property); 4659f453ba04SDave Airlie return ret; 4660f453ba04SDave Airlie } 4661f453ba04SDave Airlie EXPORT_SYMBOL(drm_mode_connector_update_edid_property); 4662f453ba04SDave Airlie 46633843e71fSRob Clark /* Some properties could refer to dynamic refcnt'd objects, or things that 46643843e71fSRob Clark * need special locking to handle lifetime issues (ie. to ensure the prop 46653843e71fSRob Clark * value doesn't become invalid part way through the property update due to 46663843e71fSRob Clark * race). The value returned by reference via 'obj' should be passed back 46673843e71fSRob Clark * to drm_property_change_valid_put() after the property is set (and the 46683843e71fSRob Clark * object to which the property is attached has a chance to take it's own 46693843e71fSRob Clark * reference). 46703843e71fSRob Clark */ 4671d34f20d6SRob Clark bool drm_property_change_valid_get(struct drm_property *property, 46723843e71fSRob Clark uint64_t value, struct drm_mode_object **ref) 467326a34815SPaulo Zanoni { 46742ca651d1SThierry Reding int i; 46752ca651d1SThierry Reding 467626a34815SPaulo Zanoni if (property->flags & DRM_MODE_PROP_IMMUTABLE) 467726a34815SPaulo Zanoni return false; 46785ea22f24SRob Clark 46793843e71fSRob Clark *ref = NULL; 46803843e71fSRob Clark 46815ea22f24SRob Clark if (drm_property_type_is(property, DRM_MODE_PROP_RANGE)) { 468226a34815SPaulo Zanoni if (value < property->values[0] || value > property->values[1]) 468326a34815SPaulo Zanoni return false; 468426a34815SPaulo Zanoni return true; 4685ebc44cf3SRob Clark } else if (drm_property_type_is(property, DRM_MODE_PROP_SIGNED_RANGE)) { 4686ebc44cf3SRob Clark int64_t svalue = U642I64(value); 46874dfd909fSThierry Reding 4688ebc44cf3SRob Clark if (svalue < U642I64(property->values[0]) || 4689ebc44cf3SRob Clark svalue > U642I64(property->values[1])) 4690ebc44cf3SRob Clark return false; 4691ebc44cf3SRob Clark return true; 46925ea22f24SRob Clark } else if (drm_property_type_is(property, DRM_MODE_PROP_BITMASK)) { 4693592c20eeSVille Syrjälä uint64_t valid_mask = 0; 46944dfd909fSThierry Reding 469549e27545SRob Clark for (i = 0; i < property->num_values; i++) 469649e27545SRob Clark valid_mask |= (1ULL << property->values[i]); 469749e27545SRob Clark return !(value & ~valid_mask); 46985ea22f24SRob Clark } else if (drm_property_type_is(property, DRM_MODE_PROP_BLOB)) { 46996bcacf51SDaniel Stone struct drm_property_blob *blob; 47006bcacf51SDaniel Stone 47016bcacf51SDaniel Stone if (value == 0) 4702c4a56750SVille Syrjälä return true; 47036bcacf51SDaniel Stone 47046bcacf51SDaniel Stone blob = drm_property_lookup_blob(property->dev, value); 47056bcacf51SDaniel Stone if (blob) { 47066bcacf51SDaniel Stone *ref = &blob->base; 47076bcacf51SDaniel Stone return true; 47086bcacf51SDaniel Stone } else { 47096bcacf51SDaniel Stone return false; 47106bcacf51SDaniel Stone } 471198f75de4SRob Clark } else if (drm_property_type_is(property, DRM_MODE_PROP_OBJECT)) { 471298f75de4SRob Clark /* a zero value for an object property translates to null: */ 471398f75de4SRob Clark if (value == 0) 471498f75de4SRob Clark return true; 47153843e71fSRob Clark 47163843e71fSRob Clark /* handle refcnt'd objects specially: */ 47173843e71fSRob Clark if (property->values[0] == DRM_MODE_OBJECT_FB) { 47183843e71fSRob Clark struct drm_framebuffer *fb; 47193843e71fSRob Clark fb = drm_framebuffer_lookup(property->dev, value); 47203843e71fSRob Clark if (fb) { 47213843e71fSRob Clark *ref = &fb->base; 47223843e71fSRob Clark return true; 47233843e71fSRob Clark } else { 47243843e71fSRob Clark return false; 47253843e71fSRob Clark } 47263843e71fSRob Clark } else { 47273843e71fSRob Clark return _object_find(property->dev, value, property->values[0]) != NULL; 47283843e71fSRob Clark } 47292ca651d1SThierry Reding } 47302ca651d1SThierry Reding 473126a34815SPaulo Zanoni for (i = 0; i < property->num_values; i++) 473226a34815SPaulo Zanoni if (property->values[i] == value) 473326a34815SPaulo Zanoni return true; 473426a34815SPaulo Zanoni return false; 473526a34815SPaulo Zanoni } 473626a34815SPaulo Zanoni 4737d34f20d6SRob Clark void drm_property_change_valid_put(struct drm_property *property, 47383843e71fSRob Clark struct drm_mode_object *ref) 47393843e71fSRob Clark { 47403843e71fSRob Clark if (!ref) 47413843e71fSRob Clark return; 47423843e71fSRob Clark 47433843e71fSRob Clark if (drm_property_type_is(property, DRM_MODE_PROP_OBJECT)) { 47443843e71fSRob Clark if (property->values[0] == DRM_MODE_OBJECT_FB) 47453843e71fSRob Clark drm_framebuffer_unreference(obj_to_fb(ref)); 4746da9b2a38SDaniel Stone } else if (drm_property_type_is(property, DRM_MODE_PROP_BLOB)) 4747da9b2a38SDaniel Stone drm_property_unreference_blob(obj_to_blob(ref)); 47483843e71fSRob Clark } 47493843e71fSRob Clark 4750c8e32cc1SDaniel Vetter /** 4751c8e32cc1SDaniel Vetter * drm_mode_connector_property_set_ioctl - set the current value of a connector property 4752c8e32cc1SDaniel Vetter * @dev: DRM device 4753c8e32cc1SDaniel Vetter * @data: ioctl data 4754c8e32cc1SDaniel Vetter * @file_priv: DRM file info 4755c8e32cc1SDaniel Vetter * 4756c8e32cc1SDaniel Vetter * This function sets the current value for a connectors's property. It also 4757c8e32cc1SDaniel Vetter * calls into a driver's ->set_property callback to update the hardware state 4758c8e32cc1SDaniel Vetter * 4759c8e32cc1SDaniel Vetter * Called by the user via ioctl. 4760c8e32cc1SDaniel Vetter * 4761c8e32cc1SDaniel Vetter * Returns: 47621a498633SDaniel Vetter * Zero on success, negative errno on failure. 4763c8e32cc1SDaniel Vetter */ 4764f453ba04SDave Airlie int drm_mode_connector_property_set_ioctl(struct drm_device *dev, 4765f453ba04SDave Airlie void *data, struct drm_file *file_priv) 4766f453ba04SDave Airlie { 47670057d8ddSPaulo Zanoni struct drm_mode_connector_set_property *conn_set_prop = data; 47680057d8ddSPaulo Zanoni struct drm_mode_obj_set_property obj_set_prop = { 47690057d8ddSPaulo Zanoni .value = conn_set_prop->value, 47700057d8ddSPaulo Zanoni .prop_id = conn_set_prop->prop_id, 47710057d8ddSPaulo Zanoni .obj_id = conn_set_prop->connector_id, 47720057d8ddSPaulo Zanoni .obj_type = DRM_MODE_OBJECT_CONNECTOR 47730057d8ddSPaulo Zanoni }; 4774f453ba04SDave Airlie 47750057d8ddSPaulo Zanoni /* It does all the locking and checking we need */ 47760057d8ddSPaulo Zanoni return drm_mode_obj_set_property_ioctl(dev, &obj_set_prop, file_priv); 4777f453ba04SDave Airlie } 4778f453ba04SDave Airlie 4779c543188aSPaulo Zanoni static int drm_mode_connector_set_obj_prop(struct drm_mode_object *obj, 4780c543188aSPaulo Zanoni struct drm_property *property, 4781c543188aSPaulo Zanoni uint64_t value) 4782c543188aSPaulo Zanoni { 4783c543188aSPaulo Zanoni int ret = -EINVAL; 4784c543188aSPaulo Zanoni struct drm_connector *connector = obj_to_connector(obj); 4785c543188aSPaulo Zanoni 4786c543188aSPaulo Zanoni /* Do DPMS ourselves */ 4787c543188aSPaulo Zanoni if (property == connector->dev->mode_config.dpms_property) { 4788c543188aSPaulo Zanoni ret = 0; 47899a69a9acSMaarten Lankhorst if (connector->funcs->dpms) 47909a69a9acSMaarten Lankhorst ret = (*connector->funcs->dpms)(connector, (int)value); 4791c543188aSPaulo Zanoni } else if (connector->funcs->set_property) 4792c543188aSPaulo Zanoni ret = connector->funcs->set_property(connector, property, value); 4793c543188aSPaulo Zanoni 4794c543188aSPaulo Zanoni /* store the property value if successful */ 4795c543188aSPaulo Zanoni if (!ret) 479658495563SRob Clark drm_object_property_set_value(&connector->base, property, value); 4797c543188aSPaulo Zanoni return ret; 4798c543188aSPaulo Zanoni } 4799c543188aSPaulo Zanoni 4800bffd9de0SPaulo Zanoni static int drm_mode_crtc_set_obj_prop(struct drm_mode_object *obj, 4801bffd9de0SPaulo Zanoni struct drm_property *property, 4802bffd9de0SPaulo Zanoni uint64_t value) 4803bffd9de0SPaulo Zanoni { 4804bffd9de0SPaulo Zanoni int ret = -EINVAL; 4805bffd9de0SPaulo Zanoni struct drm_crtc *crtc = obj_to_crtc(obj); 4806bffd9de0SPaulo Zanoni 4807bffd9de0SPaulo Zanoni if (crtc->funcs->set_property) 4808bffd9de0SPaulo Zanoni ret = crtc->funcs->set_property(crtc, property, value); 4809bffd9de0SPaulo Zanoni if (!ret) 4810bffd9de0SPaulo Zanoni drm_object_property_set_value(obj, property, value); 4811bffd9de0SPaulo Zanoni 4812bffd9de0SPaulo Zanoni return ret; 4813bffd9de0SPaulo Zanoni } 4814bffd9de0SPaulo Zanoni 48153a5f87c2SThomas Wood /** 48163a5f87c2SThomas Wood * drm_mode_plane_set_obj_prop - set the value of a property 48173a5f87c2SThomas Wood * @plane: drm plane object to set property value for 48183a5f87c2SThomas Wood * @property: property to set 48193a5f87c2SThomas Wood * @value: value the property should be set to 48203a5f87c2SThomas Wood * 48213a5f87c2SThomas Wood * This functions sets a given property on a given plane object. This function 48223a5f87c2SThomas Wood * calls the driver's ->set_property callback and changes the software state of 48233a5f87c2SThomas Wood * the property if the callback succeeds. 48243a5f87c2SThomas Wood * 48253a5f87c2SThomas Wood * Returns: 48263a5f87c2SThomas Wood * Zero on success, error code on failure. 48273a5f87c2SThomas Wood */ 48283a5f87c2SThomas Wood int drm_mode_plane_set_obj_prop(struct drm_plane *plane, 48294d93914aSRob Clark struct drm_property *property, 48304d93914aSRob Clark uint64_t value) 48314d93914aSRob Clark { 48324d93914aSRob Clark int ret = -EINVAL; 48333a5f87c2SThomas Wood struct drm_mode_object *obj = &plane->base; 48344d93914aSRob Clark 48354d93914aSRob Clark if (plane->funcs->set_property) 48364d93914aSRob Clark ret = plane->funcs->set_property(plane, property, value); 48374d93914aSRob Clark if (!ret) 48384d93914aSRob Clark drm_object_property_set_value(obj, property, value); 48394d93914aSRob Clark 48404d93914aSRob Clark return ret; 48414d93914aSRob Clark } 48423a5f87c2SThomas Wood EXPORT_SYMBOL(drm_mode_plane_set_obj_prop); 48434d93914aSRob Clark 4844c8e32cc1SDaniel Vetter /** 48451a498633SDaniel Vetter * drm_mode_obj_get_properties_ioctl - get the current value of a object's property 4846c8e32cc1SDaniel Vetter * @dev: DRM device 4847c8e32cc1SDaniel Vetter * @data: ioctl data 4848c8e32cc1SDaniel Vetter * @file_priv: DRM file info 4849c8e32cc1SDaniel Vetter * 4850c8e32cc1SDaniel Vetter * This function retrieves the current value for an object's property. Compared 4851c8e32cc1SDaniel Vetter * to the connector specific ioctl this one is extended to also work on crtc and 4852c8e32cc1SDaniel Vetter * plane objects. 4853c8e32cc1SDaniel Vetter * 4854c8e32cc1SDaniel Vetter * Called by the user via ioctl. 4855c8e32cc1SDaniel Vetter * 4856c8e32cc1SDaniel Vetter * Returns: 48571a498633SDaniel Vetter * Zero on success, negative errno on failure. 4858c8e32cc1SDaniel Vetter */ 4859c543188aSPaulo Zanoni int drm_mode_obj_get_properties_ioctl(struct drm_device *dev, void *data, 4860c543188aSPaulo Zanoni struct drm_file *file_priv) 4861c543188aSPaulo Zanoni { 4862c543188aSPaulo Zanoni struct drm_mode_obj_get_properties *arg = data; 4863c543188aSPaulo Zanoni struct drm_mode_object *obj; 4864c543188aSPaulo Zanoni int ret = 0; 4865c543188aSPaulo Zanoni 4866c543188aSPaulo Zanoni if (!drm_core_check_feature(dev, DRIVER_MODESET)) 4867c543188aSPaulo Zanoni return -EINVAL; 4868c543188aSPaulo Zanoni 486984849903SDaniel Vetter drm_modeset_lock_all(dev); 4870c543188aSPaulo Zanoni 4871c543188aSPaulo Zanoni obj = drm_mode_object_find(dev, arg->obj_id, arg->obj_type); 4872c543188aSPaulo Zanoni if (!obj) { 4873f27657f2SVille Syrjälä ret = -ENOENT; 4874c543188aSPaulo Zanoni goto out; 4875c543188aSPaulo Zanoni } 4876c543188aSPaulo Zanoni if (!obj->properties) { 4877c543188aSPaulo Zanoni ret = -EINVAL; 4878c543188aSPaulo Zanoni goto out; 4879c543188aSPaulo Zanoni } 4880c543188aSPaulo Zanoni 488188a48e29SRob Clark ret = get_properties(obj, file_priv->atomic, 488295cbf110SRob Clark (uint32_t __user *)(unsigned long)(arg->props_ptr), 488395cbf110SRob Clark (uint64_t __user *)(unsigned long)(arg->prop_values_ptr), 488495cbf110SRob Clark &arg->count_props); 4885c543188aSPaulo Zanoni 4886c543188aSPaulo Zanoni out: 488784849903SDaniel Vetter drm_modeset_unlock_all(dev); 4888c543188aSPaulo Zanoni return ret; 4889c543188aSPaulo Zanoni } 4890c543188aSPaulo Zanoni 4891c8e32cc1SDaniel Vetter /** 4892c8e32cc1SDaniel Vetter * drm_mode_obj_set_property_ioctl - set the current value of an object's property 4893c8e32cc1SDaniel Vetter * @dev: DRM device 4894c8e32cc1SDaniel Vetter * @data: ioctl data 4895c8e32cc1SDaniel Vetter * @file_priv: DRM file info 4896c8e32cc1SDaniel Vetter * 4897c8e32cc1SDaniel Vetter * This function sets the current value for an object's property. It also calls 4898c8e32cc1SDaniel Vetter * into a driver's ->set_property callback to update the hardware state. 4899c8e32cc1SDaniel Vetter * Compared to the connector specific ioctl this one is extended to also work on 4900c8e32cc1SDaniel Vetter * crtc and plane objects. 4901c8e32cc1SDaniel Vetter * 4902c8e32cc1SDaniel Vetter * Called by the user via ioctl. 4903c8e32cc1SDaniel Vetter * 4904c8e32cc1SDaniel Vetter * Returns: 49051a498633SDaniel Vetter * Zero on success, negative errno on failure. 4906c8e32cc1SDaniel Vetter */ 4907c543188aSPaulo Zanoni int drm_mode_obj_set_property_ioctl(struct drm_device *dev, void *data, 4908c543188aSPaulo Zanoni struct drm_file *file_priv) 4909c543188aSPaulo Zanoni { 4910c543188aSPaulo Zanoni struct drm_mode_obj_set_property *arg = data; 4911c543188aSPaulo Zanoni struct drm_mode_object *arg_obj; 4912c543188aSPaulo Zanoni struct drm_mode_object *prop_obj; 4913c543188aSPaulo Zanoni struct drm_property *property; 49143843e71fSRob Clark int i, ret = -EINVAL; 49153843e71fSRob Clark struct drm_mode_object *ref; 4916c543188aSPaulo Zanoni 4917c543188aSPaulo Zanoni if (!drm_core_check_feature(dev, DRIVER_MODESET)) 4918c543188aSPaulo Zanoni return -EINVAL; 4919c543188aSPaulo Zanoni 492084849903SDaniel Vetter drm_modeset_lock_all(dev); 4921c543188aSPaulo Zanoni 4922c543188aSPaulo Zanoni arg_obj = drm_mode_object_find(dev, arg->obj_id, arg->obj_type); 4923f27657f2SVille Syrjälä if (!arg_obj) { 4924f27657f2SVille Syrjälä ret = -ENOENT; 4925c543188aSPaulo Zanoni goto out; 4926f27657f2SVille Syrjälä } 4927c543188aSPaulo Zanoni if (!arg_obj->properties) 4928c543188aSPaulo Zanoni goto out; 4929c543188aSPaulo Zanoni 49307f88a9beSPaulo Zanoni for (i = 0; i < arg_obj->properties->count; i++) 4931b17cd757SRob Clark if (arg_obj->properties->properties[i]->base.id == arg->prop_id) 4932c543188aSPaulo Zanoni break; 4933c543188aSPaulo Zanoni 49347f88a9beSPaulo Zanoni if (i == arg_obj->properties->count) 4935c543188aSPaulo Zanoni goto out; 4936c543188aSPaulo Zanoni 4937c543188aSPaulo Zanoni prop_obj = drm_mode_object_find(dev, arg->prop_id, 4938c543188aSPaulo Zanoni DRM_MODE_OBJECT_PROPERTY); 4939f27657f2SVille Syrjälä if (!prop_obj) { 4940f27657f2SVille Syrjälä ret = -ENOENT; 4941c543188aSPaulo Zanoni goto out; 4942f27657f2SVille Syrjälä } 4943c543188aSPaulo Zanoni property = obj_to_property(prop_obj); 4944c543188aSPaulo Zanoni 49453843e71fSRob Clark if (!drm_property_change_valid_get(property, arg->value, &ref)) 4946c543188aSPaulo Zanoni goto out; 4947c543188aSPaulo Zanoni 4948c543188aSPaulo Zanoni switch (arg_obj->type) { 4949c543188aSPaulo Zanoni case DRM_MODE_OBJECT_CONNECTOR: 4950c543188aSPaulo Zanoni ret = drm_mode_connector_set_obj_prop(arg_obj, property, 4951c543188aSPaulo Zanoni arg->value); 4952c543188aSPaulo Zanoni break; 4953bffd9de0SPaulo Zanoni case DRM_MODE_OBJECT_CRTC: 4954bffd9de0SPaulo Zanoni ret = drm_mode_crtc_set_obj_prop(arg_obj, property, arg->value); 4955bffd9de0SPaulo Zanoni break; 49564d93914aSRob Clark case DRM_MODE_OBJECT_PLANE: 49573a5f87c2SThomas Wood ret = drm_mode_plane_set_obj_prop(obj_to_plane(arg_obj), 49583a5f87c2SThomas Wood property, arg->value); 49594d93914aSRob Clark break; 4960c543188aSPaulo Zanoni } 4961c543188aSPaulo Zanoni 49623843e71fSRob Clark drm_property_change_valid_put(property, ref); 49633843e71fSRob Clark 4964c543188aSPaulo Zanoni out: 496584849903SDaniel Vetter drm_modeset_unlock_all(dev); 4966c543188aSPaulo Zanoni return ret; 4967c543188aSPaulo Zanoni } 4968c543188aSPaulo Zanoni 4969c8e32cc1SDaniel Vetter /** 4970c8e32cc1SDaniel Vetter * drm_mode_connector_attach_encoder - attach a connector to an encoder 4971c8e32cc1SDaniel Vetter * @connector: connector to attach 4972c8e32cc1SDaniel Vetter * @encoder: encoder to attach @connector to 4973c8e32cc1SDaniel Vetter * 4974c8e32cc1SDaniel Vetter * This function links up a connector to an encoder. Note that the routing 4975c8e32cc1SDaniel Vetter * restrictions between encoders and crtcs are exposed to userspace through the 4976c8e32cc1SDaniel Vetter * possible_clones and possible_crtcs bitmasks. 4977c8e32cc1SDaniel Vetter * 4978c8e32cc1SDaniel Vetter * Returns: 49791a498633SDaniel Vetter * Zero on success, negative errno on failure. 4980c8e32cc1SDaniel Vetter */ 4981f453ba04SDave Airlie int drm_mode_connector_attach_encoder(struct drm_connector *connector, 4982f453ba04SDave Airlie struct drm_encoder *encoder) 4983f453ba04SDave Airlie { 4984f453ba04SDave Airlie int i; 4985f453ba04SDave Airlie 4986f453ba04SDave Airlie for (i = 0; i < DRM_CONNECTOR_MAX_ENCODER; i++) { 4987f453ba04SDave Airlie if (connector->encoder_ids[i] == 0) { 4988f453ba04SDave Airlie connector->encoder_ids[i] = encoder->base.id; 4989f453ba04SDave Airlie return 0; 4990f453ba04SDave Airlie } 4991f453ba04SDave Airlie } 4992f453ba04SDave Airlie return -ENOMEM; 4993f453ba04SDave Airlie } 4994f453ba04SDave Airlie EXPORT_SYMBOL(drm_mode_connector_attach_encoder); 4995f453ba04SDave Airlie 4996c8e32cc1SDaniel Vetter /** 4997c8e32cc1SDaniel Vetter * drm_mode_crtc_set_gamma_size - set the gamma table size 4998c8e32cc1SDaniel Vetter * @crtc: CRTC to set the gamma table size for 4999c8e32cc1SDaniel Vetter * @gamma_size: size of the gamma table 5000c8e32cc1SDaniel Vetter * 5001c8e32cc1SDaniel Vetter * Drivers which support gamma tables should set this to the supported gamma 5002c8e32cc1SDaniel Vetter * table size when initializing the CRTC. Currently the drm core only supports a 5003c8e32cc1SDaniel Vetter * fixed gamma table size. 5004c8e32cc1SDaniel Vetter * 5005c8e32cc1SDaniel Vetter * Returns: 50061a498633SDaniel Vetter * Zero on success, negative errno on failure. 5007c8e32cc1SDaniel Vetter */ 50084cae5b84SSascha Hauer int drm_mode_crtc_set_gamma_size(struct drm_crtc *crtc, 5009f453ba04SDave Airlie int gamma_size) 5010f453ba04SDave Airlie { 5011f453ba04SDave Airlie crtc->gamma_size = gamma_size; 5012f453ba04SDave Airlie 5013bd3f0ff9SThierry Reding crtc->gamma_store = kcalloc(gamma_size, sizeof(uint16_t) * 3, 5014bd3f0ff9SThierry Reding GFP_KERNEL); 5015f453ba04SDave Airlie if (!crtc->gamma_store) { 5016f453ba04SDave Airlie crtc->gamma_size = 0; 50174cae5b84SSascha Hauer return -ENOMEM; 5018f453ba04SDave Airlie } 5019f453ba04SDave Airlie 50204cae5b84SSascha Hauer return 0; 5021f453ba04SDave Airlie } 5022f453ba04SDave Airlie EXPORT_SYMBOL(drm_mode_crtc_set_gamma_size); 5023f453ba04SDave Airlie 5024c8e32cc1SDaniel Vetter /** 5025c8e32cc1SDaniel Vetter * drm_mode_gamma_set_ioctl - set the gamma table 5026c8e32cc1SDaniel Vetter * @dev: DRM device 5027c8e32cc1SDaniel Vetter * @data: ioctl data 5028c8e32cc1SDaniel Vetter * @file_priv: DRM file info 5029c8e32cc1SDaniel Vetter * 5030c8e32cc1SDaniel Vetter * Set the gamma table of a CRTC to the one passed in by the user. Userspace can 5031c8e32cc1SDaniel Vetter * inquire the required gamma table size through drm_mode_gamma_get_ioctl. 5032c8e32cc1SDaniel Vetter * 5033c8e32cc1SDaniel Vetter * Called by the user via ioctl. 5034c8e32cc1SDaniel Vetter * 5035c8e32cc1SDaniel Vetter * Returns: 50361a498633SDaniel Vetter * Zero on success, negative errno on failure. 5037c8e32cc1SDaniel Vetter */ 5038f453ba04SDave Airlie int drm_mode_gamma_set_ioctl(struct drm_device *dev, 5039f453ba04SDave Airlie void *data, struct drm_file *file_priv) 5040f453ba04SDave Airlie { 5041f453ba04SDave Airlie struct drm_mode_crtc_lut *crtc_lut = data; 5042f453ba04SDave Airlie struct drm_crtc *crtc; 5043f453ba04SDave Airlie void *r_base, *g_base, *b_base; 5044f453ba04SDave Airlie int size; 5045f453ba04SDave Airlie int ret = 0; 5046f453ba04SDave Airlie 5047fb3b06c8SDave Airlie if (!drm_core_check_feature(dev, DRIVER_MODESET)) 5048fb3b06c8SDave Airlie return -EINVAL; 5049fb3b06c8SDave Airlie 505084849903SDaniel Vetter drm_modeset_lock_all(dev); 5051a2b34e22SRob Clark crtc = drm_crtc_find(dev, crtc_lut->crtc_id); 5052a2b34e22SRob Clark if (!crtc) { 5053f27657f2SVille Syrjälä ret = -ENOENT; 5054f453ba04SDave Airlie goto out; 5055f453ba04SDave Airlie } 5056f453ba04SDave Airlie 5057ebe0f244SLaurent Pinchart if (crtc->funcs->gamma_set == NULL) { 5058ebe0f244SLaurent Pinchart ret = -ENOSYS; 5059ebe0f244SLaurent Pinchart goto out; 5060ebe0f244SLaurent Pinchart } 5061ebe0f244SLaurent Pinchart 5062f453ba04SDave Airlie /* memcpy into gamma store */ 5063f453ba04SDave Airlie if (crtc_lut->gamma_size != crtc->gamma_size) { 5064f453ba04SDave Airlie ret = -EINVAL; 5065f453ba04SDave Airlie goto out; 5066f453ba04SDave Airlie } 5067f453ba04SDave Airlie 5068f453ba04SDave Airlie size = crtc_lut->gamma_size * (sizeof(uint16_t)); 5069f453ba04SDave Airlie r_base = crtc->gamma_store; 5070f453ba04SDave Airlie if (copy_from_user(r_base, (void __user *)(unsigned long)crtc_lut->red, size)) { 5071f453ba04SDave Airlie ret = -EFAULT; 5072f453ba04SDave Airlie goto out; 5073f453ba04SDave Airlie } 5074f453ba04SDave Airlie 5075f453ba04SDave Airlie g_base = r_base + size; 5076f453ba04SDave Airlie if (copy_from_user(g_base, (void __user *)(unsigned long)crtc_lut->green, size)) { 5077f453ba04SDave Airlie ret = -EFAULT; 5078f453ba04SDave Airlie goto out; 5079f453ba04SDave Airlie } 5080f453ba04SDave Airlie 5081f453ba04SDave Airlie b_base = g_base + size; 5082f453ba04SDave Airlie if (copy_from_user(b_base, (void __user *)(unsigned long)crtc_lut->blue, size)) { 5083f453ba04SDave Airlie ret = -EFAULT; 5084f453ba04SDave Airlie goto out; 5085f453ba04SDave Airlie } 5086f453ba04SDave Airlie 50877203425aSJames Simmons crtc->funcs->gamma_set(crtc, r_base, g_base, b_base, 0, crtc->gamma_size); 5088f453ba04SDave Airlie 5089f453ba04SDave Airlie out: 509084849903SDaniel Vetter drm_modeset_unlock_all(dev); 5091f453ba04SDave Airlie return ret; 5092f453ba04SDave Airlie 5093f453ba04SDave Airlie } 5094f453ba04SDave Airlie 5095c8e32cc1SDaniel Vetter /** 5096c8e32cc1SDaniel Vetter * drm_mode_gamma_get_ioctl - get the gamma table 5097c8e32cc1SDaniel Vetter * @dev: DRM device 5098c8e32cc1SDaniel Vetter * @data: ioctl data 5099c8e32cc1SDaniel Vetter * @file_priv: DRM file info 5100c8e32cc1SDaniel Vetter * 5101c8e32cc1SDaniel Vetter * Copy the current gamma table into the storage provided. This also provides 5102c8e32cc1SDaniel Vetter * the gamma table size the driver expects, which can be used to size the 5103c8e32cc1SDaniel Vetter * allocated storage. 5104c8e32cc1SDaniel Vetter * 5105c8e32cc1SDaniel Vetter * Called by the user via ioctl. 5106c8e32cc1SDaniel Vetter * 5107c8e32cc1SDaniel Vetter * Returns: 51081a498633SDaniel Vetter * Zero on success, negative errno on failure. 5109c8e32cc1SDaniel Vetter */ 5110f453ba04SDave Airlie int drm_mode_gamma_get_ioctl(struct drm_device *dev, 5111f453ba04SDave Airlie void *data, struct drm_file *file_priv) 5112f453ba04SDave Airlie { 5113f453ba04SDave Airlie struct drm_mode_crtc_lut *crtc_lut = data; 5114f453ba04SDave Airlie struct drm_crtc *crtc; 5115f453ba04SDave Airlie void *r_base, *g_base, *b_base; 5116f453ba04SDave Airlie int size; 5117f453ba04SDave Airlie int ret = 0; 5118f453ba04SDave Airlie 5119fb3b06c8SDave Airlie if (!drm_core_check_feature(dev, DRIVER_MODESET)) 5120fb3b06c8SDave Airlie return -EINVAL; 5121fb3b06c8SDave Airlie 512284849903SDaniel Vetter drm_modeset_lock_all(dev); 5123a2b34e22SRob Clark crtc = drm_crtc_find(dev, crtc_lut->crtc_id); 5124a2b34e22SRob Clark if (!crtc) { 5125f27657f2SVille Syrjälä ret = -ENOENT; 5126f453ba04SDave Airlie goto out; 5127f453ba04SDave Airlie } 5128f453ba04SDave Airlie 5129f453ba04SDave Airlie /* memcpy into gamma store */ 5130f453ba04SDave Airlie if (crtc_lut->gamma_size != crtc->gamma_size) { 5131f453ba04SDave Airlie ret = -EINVAL; 5132f453ba04SDave Airlie goto out; 5133f453ba04SDave Airlie } 5134f453ba04SDave Airlie 5135f453ba04SDave Airlie size = crtc_lut->gamma_size * (sizeof(uint16_t)); 5136f453ba04SDave Airlie r_base = crtc->gamma_store; 5137f453ba04SDave Airlie if (copy_to_user((void __user *)(unsigned long)crtc_lut->red, r_base, size)) { 5138f453ba04SDave Airlie ret = -EFAULT; 5139f453ba04SDave Airlie goto out; 5140f453ba04SDave Airlie } 5141f453ba04SDave Airlie 5142f453ba04SDave Airlie g_base = r_base + size; 5143f453ba04SDave Airlie if (copy_to_user((void __user *)(unsigned long)crtc_lut->green, g_base, size)) { 5144f453ba04SDave Airlie ret = -EFAULT; 5145f453ba04SDave Airlie goto out; 5146f453ba04SDave Airlie } 5147f453ba04SDave Airlie 5148f453ba04SDave Airlie b_base = g_base + size; 5149f453ba04SDave Airlie if (copy_to_user((void __user *)(unsigned long)crtc_lut->blue, b_base, size)) { 5150f453ba04SDave Airlie ret = -EFAULT; 5151f453ba04SDave Airlie goto out; 5152f453ba04SDave Airlie } 5153f453ba04SDave Airlie out: 515484849903SDaniel Vetter drm_modeset_unlock_all(dev); 5155f453ba04SDave Airlie return ret; 5156f453ba04SDave Airlie } 5157d91d8a3fSKristian Høgsberg 5158c8e32cc1SDaniel Vetter /** 5159c8e32cc1SDaniel Vetter * drm_mode_page_flip_ioctl - schedule an asynchronous fb update 5160c8e32cc1SDaniel Vetter * @dev: DRM device 5161c8e32cc1SDaniel Vetter * @data: ioctl data 5162c8e32cc1SDaniel Vetter * @file_priv: DRM file info 5163c8e32cc1SDaniel Vetter * 5164c8e32cc1SDaniel Vetter * This schedules an asynchronous update on a given CRTC, called page flip. 5165c8e32cc1SDaniel Vetter * Optionally a drm event is generated to signal the completion of the event. 5166c8e32cc1SDaniel Vetter * Generic drivers cannot assume that a pageflip with changed framebuffer 5167c8e32cc1SDaniel Vetter * properties (including driver specific metadata like tiling layout) will work, 5168c8e32cc1SDaniel Vetter * but some drivers support e.g. pixel format changes through the pageflip 5169c8e32cc1SDaniel Vetter * ioctl. 5170c8e32cc1SDaniel Vetter * 5171c8e32cc1SDaniel Vetter * Called by the user via ioctl. 5172c8e32cc1SDaniel Vetter * 5173c8e32cc1SDaniel Vetter * Returns: 51741a498633SDaniel Vetter * Zero on success, negative errno on failure. 5175c8e32cc1SDaniel Vetter */ 5176d91d8a3fSKristian Høgsberg int drm_mode_page_flip_ioctl(struct drm_device *dev, 5177d91d8a3fSKristian Høgsberg void *data, struct drm_file *file_priv) 5178d91d8a3fSKristian Høgsberg { 5179d91d8a3fSKristian Høgsberg struct drm_mode_crtc_page_flip *page_flip = data; 5180d91d8a3fSKristian Høgsberg struct drm_crtc *crtc; 51813d30a59bSDaniel Vetter struct drm_framebuffer *fb = NULL; 5182d91d8a3fSKristian Høgsberg struct drm_pending_vblank_event *e = NULL; 5183d91d8a3fSKristian Høgsberg unsigned long flags; 5184d91d8a3fSKristian Høgsberg int ret = -EINVAL; 5185d91d8a3fSKristian Høgsberg 5186d91d8a3fSKristian Høgsberg if (page_flip->flags & ~DRM_MODE_PAGE_FLIP_FLAGS || 5187d91d8a3fSKristian Høgsberg page_flip->reserved != 0) 5188d91d8a3fSKristian Høgsberg return -EINVAL; 5189d91d8a3fSKristian Høgsberg 519062f2104fSKeith Packard if ((page_flip->flags & DRM_MODE_PAGE_FLIP_ASYNC) && !dev->mode_config.async_page_flip) 519162f2104fSKeith Packard return -EINVAL; 519262f2104fSKeith Packard 5193a2b34e22SRob Clark crtc = drm_crtc_find(dev, page_flip->crtc_id); 5194a2b34e22SRob Clark if (!crtc) 5195f27657f2SVille Syrjälä return -ENOENT; 5196d91d8a3fSKristian Høgsberg 51974d02e2deSDaniel Vetter drm_modeset_lock_crtc(crtc, crtc->primary); 5198f4510a27SMatt Roper if (crtc->primary->fb == NULL) { 519990c1efddSChris Wilson /* The framebuffer is currently unbound, presumably 520090c1efddSChris Wilson * due to a hotplug event, that userspace has not 520190c1efddSChris Wilson * yet discovered. 520290c1efddSChris Wilson */ 520390c1efddSChris Wilson ret = -EBUSY; 520490c1efddSChris Wilson goto out; 520590c1efddSChris Wilson } 520690c1efddSChris Wilson 5207d91d8a3fSKristian Høgsberg if (crtc->funcs->page_flip == NULL) 5208d91d8a3fSKristian Høgsberg goto out; 5209d91d8a3fSKristian Høgsberg 5210786b99edSDaniel Vetter fb = drm_framebuffer_lookup(dev, page_flip->fb_id); 521137c4e705SVille Syrjälä if (!fb) { 521237c4e705SVille Syrjälä ret = -ENOENT; 5213d91d8a3fSKristian Høgsberg goto out; 521437c4e705SVille Syrjälä } 5215d91d8a3fSKristian Høgsberg 52162afa701dSVille Syrjälä if (crtc->state) { 52172afa701dSVille Syrjälä const struct drm_plane_state *state = crtc->primary->state; 52182afa701dSVille Syrjälä 52192afa701dSVille Syrjälä ret = check_src_coords(state->src_x, state->src_y, 52202afa701dSVille Syrjälä state->src_w, state->src_h, fb); 52212afa701dSVille Syrjälä } else { 5222c11e9283SDamien Lespiau ret = drm_crtc_check_viewport(crtc, crtc->x, crtc->y, &crtc->mode, fb); 52232afa701dSVille Syrjälä } 5224c11e9283SDamien Lespiau if (ret) 52255f61bb42SVille Syrjälä goto out; 52265f61bb42SVille Syrjälä 5227f4510a27SMatt Roper if (crtc->primary->fb->pixel_format != fb->pixel_format) { 5228909d9cdaSLaurent Pinchart DRM_DEBUG_KMS("Page flip is not allowed to change frame buffer format.\n"); 5229909d9cdaSLaurent Pinchart ret = -EINVAL; 5230909d9cdaSLaurent Pinchart goto out; 5231909d9cdaSLaurent Pinchart } 5232909d9cdaSLaurent Pinchart 5233d91d8a3fSKristian Høgsberg if (page_flip->flags & DRM_MODE_PAGE_FLIP_EVENT) { 5234d91d8a3fSKristian Høgsberg ret = -ENOMEM; 5235d91d8a3fSKristian Høgsberg spin_lock_irqsave(&dev->event_lock, flags); 5236f76511b9SThierry Reding if (file_priv->event_space < sizeof(e->event)) { 5237d91d8a3fSKristian Høgsberg spin_unlock_irqrestore(&dev->event_lock, flags); 5238d91d8a3fSKristian Høgsberg goto out; 5239d91d8a3fSKristian Høgsberg } 5240f76511b9SThierry Reding file_priv->event_space -= sizeof(e->event); 5241d91d8a3fSKristian Høgsberg spin_unlock_irqrestore(&dev->event_lock, flags); 5242d91d8a3fSKristian Høgsberg 5243f76511b9SThierry Reding e = kzalloc(sizeof(*e), GFP_KERNEL); 5244d91d8a3fSKristian Høgsberg if (e == NULL) { 5245d91d8a3fSKristian Høgsberg spin_lock_irqsave(&dev->event_lock, flags); 5246f76511b9SThierry Reding file_priv->event_space += sizeof(e->event); 5247d91d8a3fSKristian Høgsberg spin_unlock_irqrestore(&dev->event_lock, flags); 5248d91d8a3fSKristian Høgsberg goto out; 5249d91d8a3fSKristian Høgsberg } 5250d91d8a3fSKristian Høgsberg 52517bd4d7beSJesse Barnes e->event.base.type = DRM_EVENT_FLIP_COMPLETE; 5252f76511b9SThierry Reding e->event.base.length = sizeof(e->event); 5253d91d8a3fSKristian Høgsberg e->event.user_data = page_flip->user_data; 5254d91d8a3fSKristian Høgsberg e->base.event = &e->event.base; 5255d91d8a3fSKristian Høgsberg e->base.file_priv = file_priv; 5256d91d8a3fSKristian Høgsberg e->base.destroy = 5257d91d8a3fSKristian Høgsberg (void (*) (struct drm_pending_event *)) kfree; 5258d91d8a3fSKristian Høgsberg } 5259d91d8a3fSKristian Høgsberg 52603d30a59bSDaniel Vetter crtc->primary->old_fb = crtc->primary->fb; 5261ed8d1975SKeith Packard ret = crtc->funcs->page_flip(crtc, fb, e, page_flip->flags); 5262d91d8a3fSKristian Høgsberg if (ret) { 5263aef6a7eeSJoonyoung Shim if (page_flip->flags & DRM_MODE_PAGE_FLIP_EVENT) { 5264d91d8a3fSKristian Høgsberg spin_lock_irqsave(&dev->event_lock, flags); 5265f76511b9SThierry Reding file_priv->event_space += sizeof(e->event); 5266d91d8a3fSKristian Høgsberg spin_unlock_irqrestore(&dev->event_lock, flags); 5267d91d8a3fSKristian Høgsberg kfree(e); 5268d91d8a3fSKristian Høgsberg } 5269b0d12325SDaniel Vetter /* Keep the old fb, don't unref it. */ 52703d30a59bSDaniel Vetter crtc->primary->old_fb = NULL; 5271b0d12325SDaniel Vetter } else { 52723cb43cc0SDaniel Vetter crtc->primary->fb = fb; 5273b0d12325SDaniel Vetter /* Unref only the old framebuffer. */ 5274b0d12325SDaniel Vetter fb = NULL; 5275aef6a7eeSJoonyoung Shim } 5276d91d8a3fSKristian Høgsberg 5277d91d8a3fSKristian Høgsberg out: 5278b0d12325SDaniel Vetter if (fb) 5279b0d12325SDaniel Vetter drm_framebuffer_unreference(fb); 52803d30a59bSDaniel Vetter if (crtc->primary->old_fb) 52813d30a59bSDaniel Vetter drm_framebuffer_unreference(crtc->primary->old_fb); 52823d30a59bSDaniel Vetter crtc->primary->old_fb = NULL; 5283d059f652SDaniel Vetter drm_modeset_unlock_crtc(crtc); 5284b4d5e7d1SDaniel Vetter 5285d91d8a3fSKristian Høgsberg return ret; 5286d91d8a3fSKristian Høgsberg } 5287eb033556SChris Wilson 5288c8e32cc1SDaniel Vetter /** 5289c8e32cc1SDaniel Vetter * drm_mode_config_reset - call ->reset callbacks 5290c8e32cc1SDaniel Vetter * @dev: drm device 5291c8e32cc1SDaniel Vetter * 5292c8e32cc1SDaniel Vetter * This functions calls all the crtc's, encoder's and connector's ->reset 5293c8e32cc1SDaniel Vetter * callback. Drivers can use this in e.g. their driver load or resume code to 5294c8e32cc1SDaniel Vetter * reset hardware and software state. 5295c8e32cc1SDaniel Vetter */ 5296eb033556SChris Wilson void drm_mode_config_reset(struct drm_device *dev) 5297eb033556SChris Wilson { 5298eb033556SChris Wilson struct drm_crtc *crtc; 52992a0d7cfdSDaniel Vetter struct drm_plane *plane; 5300eb033556SChris Wilson struct drm_encoder *encoder; 5301eb033556SChris Wilson struct drm_connector *connector; 5302eb033556SChris Wilson 5303e4f62546SDaniel Vetter drm_for_each_plane(plane, dev) 53042a0d7cfdSDaniel Vetter if (plane->funcs->reset) 53052a0d7cfdSDaniel Vetter plane->funcs->reset(plane); 53062a0d7cfdSDaniel Vetter 5307e4f62546SDaniel Vetter drm_for_each_crtc(crtc, dev) 5308eb033556SChris Wilson if (crtc->funcs->reset) 5309eb033556SChris Wilson crtc->funcs->reset(crtc); 5310eb033556SChris Wilson 5311e4f62546SDaniel Vetter drm_for_each_encoder(encoder, dev) 5312eb033556SChris Wilson if (encoder->funcs->reset) 5313eb033556SChris Wilson encoder->funcs->reset(encoder); 5314eb033556SChris Wilson 5315f8c2ba31SDaniel Vetter mutex_lock(&dev->mode_config.mutex); 53164eebf60bSDave Airlie drm_for_each_connector(connector, dev) 5317eb033556SChris Wilson if (connector->funcs->reset) 5318eb033556SChris Wilson connector->funcs->reset(connector); 5319f8c2ba31SDaniel Vetter mutex_unlock(&dev->mode_config.mutex); 53205e2cb2f6SDaniel Vetter } 5321eb033556SChris Wilson EXPORT_SYMBOL(drm_mode_config_reset); 5322ff72145bSDave Airlie 5323c8e32cc1SDaniel Vetter /** 5324c8e32cc1SDaniel Vetter * drm_mode_create_dumb_ioctl - create a dumb backing storage buffer 5325c8e32cc1SDaniel Vetter * @dev: DRM device 5326c8e32cc1SDaniel Vetter * @data: ioctl data 5327c8e32cc1SDaniel Vetter * @file_priv: DRM file info 5328c8e32cc1SDaniel Vetter * 5329c8e32cc1SDaniel Vetter * This creates a new dumb buffer in the driver's backing storage manager (GEM, 5330c8e32cc1SDaniel Vetter * TTM or something else entirely) and returns the resulting buffer handle. This 5331c8e32cc1SDaniel Vetter * handle can then be wrapped up into a framebuffer modeset object. 5332c8e32cc1SDaniel Vetter * 5333c8e32cc1SDaniel Vetter * Note that userspace is not allowed to use such objects for render 5334c8e32cc1SDaniel Vetter * acceleration - drivers must create their own private ioctls for such a use 5335c8e32cc1SDaniel Vetter * case. 5336c8e32cc1SDaniel Vetter * 5337c8e32cc1SDaniel Vetter * Called by the user via ioctl. 5338c8e32cc1SDaniel Vetter * 5339c8e32cc1SDaniel Vetter * Returns: 53401a498633SDaniel Vetter * Zero on success, negative errno on failure. 5341c8e32cc1SDaniel Vetter */ 5342ff72145bSDave Airlie int drm_mode_create_dumb_ioctl(struct drm_device *dev, 5343ff72145bSDave Airlie void *data, struct drm_file *file_priv) 5344ff72145bSDave Airlie { 5345ff72145bSDave Airlie struct drm_mode_create_dumb *args = data; 5346b28cd41fSDavid Herrmann u32 cpp, stride, size; 5347ff72145bSDave Airlie 5348ff72145bSDave Airlie if (!dev->driver->dumb_create) 5349ff72145bSDave Airlie return -ENOSYS; 5350b28cd41fSDavid Herrmann if (!args->width || !args->height || !args->bpp) 5351b28cd41fSDavid Herrmann return -EINVAL; 5352b28cd41fSDavid Herrmann 5353b28cd41fSDavid Herrmann /* overflow checks for 32bit size calculations */ 535400e72089SDavid Herrmann /* NOTE: DIV_ROUND_UP() can overflow */ 5355b28cd41fSDavid Herrmann cpp = DIV_ROUND_UP(args->bpp, 8); 535600e72089SDavid Herrmann if (!cpp || cpp > 0xffffffffU / args->width) 5357b28cd41fSDavid Herrmann return -EINVAL; 5358b28cd41fSDavid Herrmann stride = cpp * args->width; 5359b28cd41fSDavid Herrmann if (args->height > 0xffffffffU / stride) 5360b28cd41fSDavid Herrmann return -EINVAL; 5361b28cd41fSDavid Herrmann 5362b28cd41fSDavid Herrmann /* test for wrap-around */ 5363b28cd41fSDavid Herrmann size = args->height * stride; 5364b28cd41fSDavid Herrmann if (PAGE_ALIGN(size) == 0) 5365b28cd41fSDavid Herrmann return -EINVAL; 5366b28cd41fSDavid Herrmann 5367f6085952SThierry Reding /* 5368f6085952SThierry Reding * handle, pitch and size are output parameters. Zero them out to 5369f6085952SThierry Reding * prevent drivers from accidentally using uninitialized data. Since 5370f6085952SThierry Reding * not all existing userspace is clearing these fields properly we 5371f6085952SThierry Reding * cannot reject IOCTL with garbage in them. 5372f6085952SThierry Reding */ 5373f6085952SThierry Reding args->handle = 0; 5374f6085952SThierry Reding args->pitch = 0; 5375f6085952SThierry Reding args->size = 0; 5376f6085952SThierry Reding 5377ff72145bSDave Airlie return dev->driver->dumb_create(file_priv, dev, args); 5378ff72145bSDave Airlie } 5379ff72145bSDave Airlie 5380c8e32cc1SDaniel Vetter /** 5381c8e32cc1SDaniel Vetter * drm_mode_mmap_dumb_ioctl - create an mmap offset for a dumb backing storage buffer 5382c8e32cc1SDaniel Vetter * @dev: DRM device 5383c8e32cc1SDaniel Vetter * @data: ioctl data 5384c8e32cc1SDaniel Vetter * @file_priv: DRM file info 5385c8e32cc1SDaniel Vetter * 5386c8e32cc1SDaniel Vetter * Allocate an offset in the drm device node's address space to be able to 5387c8e32cc1SDaniel Vetter * memory map a dumb buffer. 5388c8e32cc1SDaniel Vetter * 5389c8e32cc1SDaniel Vetter * Called by the user via ioctl. 5390c8e32cc1SDaniel Vetter * 5391c8e32cc1SDaniel Vetter * Returns: 53921a498633SDaniel Vetter * Zero on success, negative errno on failure. 5393c8e32cc1SDaniel Vetter */ 5394ff72145bSDave Airlie int drm_mode_mmap_dumb_ioctl(struct drm_device *dev, 5395ff72145bSDave Airlie void *data, struct drm_file *file_priv) 5396ff72145bSDave Airlie { 5397ff72145bSDave Airlie struct drm_mode_map_dumb *args = data; 5398ff72145bSDave Airlie 5399ff72145bSDave Airlie /* call driver ioctl to get mmap offset */ 5400ff72145bSDave Airlie if (!dev->driver->dumb_map_offset) 5401ff72145bSDave Airlie return -ENOSYS; 5402ff72145bSDave Airlie 5403ff72145bSDave Airlie return dev->driver->dumb_map_offset(file_priv, dev, args->handle, &args->offset); 5404ff72145bSDave Airlie } 5405ff72145bSDave Airlie 5406c8e32cc1SDaniel Vetter /** 5407c8e32cc1SDaniel Vetter * drm_mode_destroy_dumb_ioctl - destroy a dumb backing strage buffer 5408c8e32cc1SDaniel Vetter * @dev: DRM device 5409c8e32cc1SDaniel Vetter * @data: ioctl data 5410c8e32cc1SDaniel Vetter * @file_priv: DRM file info 5411c8e32cc1SDaniel Vetter * 5412c8e32cc1SDaniel Vetter * This destroys the userspace handle for the given dumb backing storage buffer. 5413c8e32cc1SDaniel Vetter * Since buffer objects must be reference counted in the kernel a buffer object 5414c8e32cc1SDaniel Vetter * won't be immediately freed if a framebuffer modeset object still uses it. 5415c8e32cc1SDaniel Vetter * 5416c8e32cc1SDaniel Vetter * Called by the user via ioctl. 5417c8e32cc1SDaniel Vetter * 5418c8e32cc1SDaniel Vetter * Returns: 54191a498633SDaniel Vetter * Zero on success, negative errno on failure. 5420c8e32cc1SDaniel Vetter */ 5421ff72145bSDave Airlie int drm_mode_destroy_dumb_ioctl(struct drm_device *dev, 5422ff72145bSDave Airlie void *data, struct drm_file *file_priv) 5423ff72145bSDave Airlie { 5424ff72145bSDave Airlie struct drm_mode_destroy_dumb *args = data; 5425ff72145bSDave Airlie 5426ff72145bSDave Airlie if (!dev->driver->dumb_destroy) 5427ff72145bSDave Airlie return -ENOSYS; 5428ff72145bSDave Airlie 5429ff72145bSDave Airlie return dev->driver->dumb_destroy(file_priv, dev, args->handle); 5430ff72145bSDave Airlie } 5431248dbc23SDave Airlie 5432c8e32cc1SDaniel Vetter /** 5433c8e32cc1SDaniel Vetter * drm_fb_get_bpp_depth - get the bpp/depth values for format 5434c8e32cc1SDaniel Vetter * @format: pixel format (DRM_FORMAT_*) 5435c8e32cc1SDaniel Vetter * @depth: storage for the depth value 5436c8e32cc1SDaniel Vetter * @bpp: storage for the bpp value 5437c8e32cc1SDaniel Vetter * 5438c8e32cc1SDaniel Vetter * This only supports RGB formats here for compat with code that doesn't use 5439c8e32cc1SDaniel Vetter * pixel formats directly yet. 5440248dbc23SDave Airlie */ 5441248dbc23SDave Airlie void drm_fb_get_bpp_depth(uint32_t format, unsigned int *depth, 5442248dbc23SDave Airlie int *bpp) 5443248dbc23SDave Airlie { 5444248dbc23SDave Airlie switch (format) { 5445c51a6bc5SVille Syrjälä case DRM_FORMAT_C8: 544604b3924dSVille Syrjälä case DRM_FORMAT_RGB332: 544704b3924dSVille Syrjälä case DRM_FORMAT_BGR233: 5448248dbc23SDave Airlie *depth = 8; 5449248dbc23SDave Airlie *bpp = 8; 5450248dbc23SDave Airlie break; 545104b3924dSVille Syrjälä case DRM_FORMAT_XRGB1555: 545204b3924dSVille Syrjälä case DRM_FORMAT_XBGR1555: 545304b3924dSVille Syrjälä case DRM_FORMAT_RGBX5551: 545404b3924dSVille Syrjälä case DRM_FORMAT_BGRX5551: 545504b3924dSVille Syrjälä case DRM_FORMAT_ARGB1555: 545604b3924dSVille Syrjälä case DRM_FORMAT_ABGR1555: 545704b3924dSVille Syrjälä case DRM_FORMAT_RGBA5551: 545804b3924dSVille Syrjälä case DRM_FORMAT_BGRA5551: 5459248dbc23SDave Airlie *depth = 15; 5460248dbc23SDave Airlie *bpp = 16; 5461248dbc23SDave Airlie break; 546204b3924dSVille Syrjälä case DRM_FORMAT_RGB565: 546304b3924dSVille Syrjälä case DRM_FORMAT_BGR565: 5464248dbc23SDave Airlie *depth = 16; 5465248dbc23SDave Airlie *bpp = 16; 5466248dbc23SDave Airlie break; 546704b3924dSVille Syrjälä case DRM_FORMAT_RGB888: 546804b3924dSVille Syrjälä case DRM_FORMAT_BGR888: 546904b3924dSVille Syrjälä *depth = 24; 547004b3924dSVille Syrjälä *bpp = 24; 547104b3924dSVille Syrjälä break; 547204b3924dSVille Syrjälä case DRM_FORMAT_XRGB8888: 547304b3924dSVille Syrjälä case DRM_FORMAT_XBGR8888: 547404b3924dSVille Syrjälä case DRM_FORMAT_RGBX8888: 547504b3924dSVille Syrjälä case DRM_FORMAT_BGRX8888: 5476248dbc23SDave Airlie *depth = 24; 5477248dbc23SDave Airlie *bpp = 32; 5478248dbc23SDave Airlie break; 547904b3924dSVille Syrjälä case DRM_FORMAT_XRGB2101010: 548004b3924dSVille Syrjälä case DRM_FORMAT_XBGR2101010: 548104b3924dSVille Syrjälä case DRM_FORMAT_RGBX1010102: 548204b3924dSVille Syrjälä case DRM_FORMAT_BGRX1010102: 548304b3924dSVille Syrjälä case DRM_FORMAT_ARGB2101010: 548404b3924dSVille Syrjälä case DRM_FORMAT_ABGR2101010: 548504b3924dSVille Syrjälä case DRM_FORMAT_RGBA1010102: 548604b3924dSVille Syrjälä case DRM_FORMAT_BGRA1010102: 5487248dbc23SDave Airlie *depth = 30; 5488248dbc23SDave Airlie *bpp = 32; 5489248dbc23SDave Airlie break; 549004b3924dSVille Syrjälä case DRM_FORMAT_ARGB8888: 549104b3924dSVille Syrjälä case DRM_FORMAT_ABGR8888: 549204b3924dSVille Syrjälä case DRM_FORMAT_RGBA8888: 549304b3924dSVille Syrjälä case DRM_FORMAT_BGRA8888: 5494248dbc23SDave Airlie *depth = 32; 5495248dbc23SDave Airlie *bpp = 32; 5496248dbc23SDave Airlie break; 5497248dbc23SDave Airlie default: 549823c453a4SVille Syrjälä DRM_DEBUG_KMS("unsupported pixel format %s\n", 549923c453a4SVille Syrjälä drm_get_format_name(format)); 5500248dbc23SDave Airlie *depth = 0; 5501248dbc23SDave Airlie *bpp = 0; 5502248dbc23SDave Airlie break; 5503248dbc23SDave Airlie } 5504248dbc23SDave Airlie } 5505248dbc23SDave Airlie EXPORT_SYMBOL(drm_fb_get_bpp_depth); 5506141670e9SVille Syrjälä 5507141670e9SVille Syrjälä /** 5508141670e9SVille Syrjälä * drm_format_num_planes - get the number of planes for format 5509141670e9SVille Syrjälä * @format: pixel format (DRM_FORMAT_*) 5510141670e9SVille Syrjälä * 5511c8e32cc1SDaniel Vetter * Returns: 5512141670e9SVille Syrjälä * The number of planes used by the specified pixel format. 5513141670e9SVille Syrjälä */ 5514141670e9SVille Syrjälä int drm_format_num_planes(uint32_t format) 5515141670e9SVille Syrjälä { 5516141670e9SVille Syrjälä switch (format) { 5517141670e9SVille Syrjälä case DRM_FORMAT_YUV410: 5518141670e9SVille Syrjälä case DRM_FORMAT_YVU410: 5519141670e9SVille Syrjälä case DRM_FORMAT_YUV411: 5520141670e9SVille Syrjälä case DRM_FORMAT_YVU411: 5521141670e9SVille Syrjälä case DRM_FORMAT_YUV420: 5522141670e9SVille Syrjälä case DRM_FORMAT_YVU420: 5523141670e9SVille Syrjälä case DRM_FORMAT_YUV422: 5524141670e9SVille Syrjälä case DRM_FORMAT_YVU422: 5525141670e9SVille Syrjälä case DRM_FORMAT_YUV444: 5526141670e9SVille Syrjälä case DRM_FORMAT_YVU444: 5527141670e9SVille Syrjälä return 3; 5528141670e9SVille Syrjälä case DRM_FORMAT_NV12: 5529141670e9SVille Syrjälä case DRM_FORMAT_NV21: 5530141670e9SVille Syrjälä case DRM_FORMAT_NV16: 5531141670e9SVille Syrjälä case DRM_FORMAT_NV61: 5532ba623f6aSLaurent Pinchart case DRM_FORMAT_NV24: 5533ba623f6aSLaurent Pinchart case DRM_FORMAT_NV42: 5534141670e9SVille Syrjälä return 2; 5535141670e9SVille Syrjälä default: 5536141670e9SVille Syrjälä return 1; 5537141670e9SVille Syrjälä } 5538141670e9SVille Syrjälä } 5539141670e9SVille Syrjälä EXPORT_SYMBOL(drm_format_num_planes); 55405a86bd55SVille Syrjälä 55415a86bd55SVille Syrjälä /** 55425a86bd55SVille Syrjälä * drm_format_plane_cpp - determine the bytes per pixel value 55435a86bd55SVille Syrjälä * @format: pixel format (DRM_FORMAT_*) 55445a86bd55SVille Syrjälä * @plane: plane index 55455a86bd55SVille Syrjälä * 5546c8e32cc1SDaniel Vetter * Returns: 55475a86bd55SVille Syrjälä * The bytes per pixel value for the specified plane. 55485a86bd55SVille Syrjälä */ 55495a86bd55SVille Syrjälä int drm_format_plane_cpp(uint32_t format, int plane) 55505a86bd55SVille Syrjälä { 55515a86bd55SVille Syrjälä unsigned int depth; 55525a86bd55SVille Syrjälä int bpp; 55535a86bd55SVille Syrjälä 55545a86bd55SVille Syrjälä if (plane >= drm_format_num_planes(format)) 55555a86bd55SVille Syrjälä return 0; 55565a86bd55SVille Syrjälä 55575a86bd55SVille Syrjälä switch (format) { 55585a86bd55SVille Syrjälä case DRM_FORMAT_YUYV: 55595a86bd55SVille Syrjälä case DRM_FORMAT_YVYU: 55605a86bd55SVille Syrjälä case DRM_FORMAT_UYVY: 55615a86bd55SVille Syrjälä case DRM_FORMAT_VYUY: 55625a86bd55SVille Syrjälä return 2; 55635a86bd55SVille Syrjälä case DRM_FORMAT_NV12: 55645a86bd55SVille Syrjälä case DRM_FORMAT_NV21: 55655a86bd55SVille Syrjälä case DRM_FORMAT_NV16: 55665a86bd55SVille Syrjälä case DRM_FORMAT_NV61: 5567ba623f6aSLaurent Pinchart case DRM_FORMAT_NV24: 5568ba623f6aSLaurent Pinchart case DRM_FORMAT_NV42: 55695a86bd55SVille Syrjälä return plane ? 2 : 1; 55705a86bd55SVille Syrjälä case DRM_FORMAT_YUV410: 55715a86bd55SVille Syrjälä case DRM_FORMAT_YVU410: 55725a86bd55SVille Syrjälä case DRM_FORMAT_YUV411: 55735a86bd55SVille Syrjälä case DRM_FORMAT_YVU411: 55745a86bd55SVille Syrjälä case DRM_FORMAT_YUV420: 55755a86bd55SVille Syrjälä case DRM_FORMAT_YVU420: 55765a86bd55SVille Syrjälä case DRM_FORMAT_YUV422: 55775a86bd55SVille Syrjälä case DRM_FORMAT_YVU422: 55785a86bd55SVille Syrjälä case DRM_FORMAT_YUV444: 55795a86bd55SVille Syrjälä case DRM_FORMAT_YVU444: 55805a86bd55SVille Syrjälä return 1; 55815a86bd55SVille Syrjälä default: 55825a86bd55SVille Syrjälä drm_fb_get_bpp_depth(format, &depth, &bpp); 55835a86bd55SVille Syrjälä return bpp >> 3; 55845a86bd55SVille Syrjälä } 55855a86bd55SVille Syrjälä } 55865a86bd55SVille Syrjälä EXPORT_SYMBOL(drm_format_plane_cpp); 558701b68b04SVille Syrjälä 558801b68b04SVille Syrjälä /** 558901b68b04SVille Syrjälä * drm_format_horz_chroma_subsampling - get the horizontal chroma subsampling factor 559001b68b04SVille Syrjälä * @format: pixel format (DRM_FORMAT_*) 559101b68b04SVille Syrjälä * 5592c8e32cc1SDaniel Vetter * Returns: 559301b68b04SVille Syrjälä * The horizontal chroma subsampling factor for the 559401b68b04SVille Syrjälä * specified pixel format. 559501b68b04SVille Syrjälä */ 559601b68b04SVille Syrjälä int drm_format_horz_chroma_subsampling(uint32_t format) 559701b68b04SVille Syrjälä { 559801b68b04SVille Syrjälä switch (format) { 559901b68b04SVille Syrjälä case DRM_FORMAT_YUV411: 560001b68b04SVille Syrjälä case DRM_FORMAT_YVU411: 560101b68b04SVille Syrjälä case DRM_FORMAT_YUV410: 560201b68b04SVille Syrjälä case DRM_FORMAT_YVU410: 560301b68b04SVille Syrjälä return 4; 560401b68b04SVille Syrjälä case DRM_FORMAT_YUYV: 560501b68b04SVille Syrjälä case DRM_FORMAT_YVYU: 560601b68b04SVille Syrjälä case DRM_FORMAT_UYVY: 560701b68b04SVille Syrjälä case DRM_FORMAT_VYUY: 560801b68b04SVille Syrjälä case DRM_FORMAT_NV12: 560901b68b04SVille Syrjälä case DRM_FORMAT_NV21: 561001b68b04SVille Syrjälä case DRM_FORMAT_NV16: 561101b68b04SVille Syrjälä case DRM_FORMAT_NV61: 561201b68b04SVille Syrjälä case DRM_FORMAT_YUV422: 561301b68b04SVille Syrjälä case DRM_FORMAT_YVU422: 561401b68b04SVille Syrjälä case DRM_FORMAT_YUV420: 561501b68b04SVille Syrjälä case DRM_FORMAT_YVU420: 561601b68b04SVille Syrjälä return 2; 561701b68b04SVille Syrjälä default: 561801b68b04SVille Syrjälä return 1; 561901b68b04SVille Syrjälä } 562001b68b04SVille Syrjälä } 562101b68b04SVille Syrjälä EXPORT_SYMBOL(drm_format_horz_chroma_subsampling); 562201b68b04SVille Syrjälä 562301b68b04SVille Syrjälä /** 562401b68b04SVille Syrjälä * drm_format_vert_chroma_subsampling - get the vertical chroma subsampling factor 562501b68b04SVille Syrjälä * @format: pixel format (DRM_FORMAT_*) 562601b68b04SVille Syrjälä * 5627c8e32cc1SDaniel Vetter * Returns: 562801b68b04SVille Syrjälä * The vertical chroma subsampling factor for the 562901b68b04SVille Syrjälä * specified pixel format. 563001b68b04SVille Syrjälä */ 563101b68b04SVille Syrjälä int drm_format_vert_chroma_subsampling(uint32_t format) 563201b68b04SVille Syrjälä { 563301b68b04SVille Syrjälä switch (format) { 563401b68b04SVille Syrjälä case DRM_FORMAT_YUV410: 563501b68b04SVille Syrjälä case DRM_FORMAT_YVU410: 563601b68b04SVille Syrjälä return 4; 563701b68b04SVille Syrjälä case DRM_FORMAT_YUV420: 563801b68b04SVille Syrjälä case DRM_FORMAT_YVU420: 563901b68b04SVille Syrjälä case DRM_FORMAT_NV12: 564001b68b04SVille Syrjälä case DRM_FORMAT_NV21: 564101b68b04SVille Syrjälä return 2; 564201b68b04SVille Syrjälä default: 564301b68b04SVille Syrjälä return 1; 564401b68b04SVille Syrjälä } 564501b68b04SVille Syrjälä } 564601b68b04SVille Syrjälä EXPORT_SYMBOL(drm_format_vert_chroma_subsampling); 564787d24fc3SLaurent Pinchart 564887d24fc3SLaurent Pinchart /** 56493c9855f6SVille Syrjälä * drm_rotation_simplify() - Try to simplify the rotation 56503c9855f6SVille Syrjälä * @rotation: Rotation to be simplified 56513c9855f6SVille Syrjälä * @supported_rotations: Supported rotations 56523c9855f6SVille Syrjälä * 56533c9855f6SVille Syrjälä * Attempt to simplify the rotation to a form that is supported. 56543c9855f6SVille Syrjälä * Eg. if the hardware supports everything except DRM_REFLECT_X 56553c9855f6SVille Syrjälä * one could call this function like this: 56563c9855f6SVille Syrjälä * 56573c9855f6SVille Syrjälä * drm_rotation_simplify(rotation, BIT(DRM_ROTATE_0) | 56583c9855f6SVille Syrjälä * BIT(DRM_ROTATE_90) | BIT(DRM_ROTATE_180) | 56593c9855f6SVille Syrjälä * BIT(DRM_ROTATE_270) | BIT(DRM_REFLECT_Y)); 56603c9855f6SVille Syrjälä * 56613c9855f6SVille Syrjälä * to eliminate the DRM_ROTATE_X flag. Depending on what kind of 56623c9855f6SVille Syrjälä * transforms the hardware supports, this function may not 56633c9855f6SVille Syrjälä * be able to produce a supported transform, so the caller should 56643c9855f6SVille Syrjälä * check the result afterwards. 56653c9855f6SVille Syrjälä */ 56663c9855f6SVille Syrjälä unsigned int drm_rotation_simplify(unsigned int rotation, 56673c9855f6SVille Syrjälä unsigned int supported_rotations) 56683c9855f6SVille Syrjälä { 56693c9855f6SVille Syrjälä if (rotation & ~supported_rotations) { 56703c9855f6SVille Syrjälä rotation ^= BIT(DRM_REFLECT_X) | BIT(DRM_REFLECT_Y); 567114152c8dSJoonas Lahtinen rotation = (rotation & DRM_REFLECT_MASK) | 567214152c8dSJoonas Lahtinen BIT((ffs(rotation & DRM_ROTATE_MASK) + 1) % 4); 56733c9855f6SVille Syrjälä } 56743c9855f6SVille Syrjälä 56753c9855f6SVille Syrjälä return rotation; 56763c9855f6SVille Syrjälä } 56773c9855f6SVille Syrjälä EXPORT_SYMBOL(drm_rotation_simplify); 56783c9855f6SVille Syrjälä 56793c9855f6SVille Syrjälä /** 568087d24fc3SLaurent Pinchart * drm_mode_config_init - initialize DRM mode_configuration structure 568187d24fc3SLaurent Pinchart * @dev: DRM device 568287d24fc3SLaurent Pinchart * 568387d24fc3SLaurent Pinchart * Initialize @dev's mode_config structure, used for tracking the graphics 568487d24fc3SLaurent Pinchart * configuration of @dev. 568587d24fc3SLaurent Pinchart * 568687d24fc3SLaurent Pinchart * Since this initializes the modeset locks, no locking is possible. Which is no 568787d24fc3SLaurent Pinchart * problem, since this should happen single threaded at init time. It is the 568887d24fc3SLaurent Pinchart * driver's problem to ensure this guarantee. 568987d24fc3SLaurent Pinchart * 569087d24fc3SLaurent Pinchart */ 569187d24fc3SLaurent Pinchart void drm_mode_config_init(struct drm_device *dev) 569287d24fc3SLaurent Pinchart { 569387d24fc3SLaurent Pinchart mutex_init(&dev->mode_config.mutex); 569451fd371bSRob Clark drm_modeset_lock_init(&dev->mode_config.connection_mutex); 569587d24fc3SLaurent Pinchart mutex_init(&dev->mode_config.idr_mutex); 569687d24fc3SLaurent Pinchart mutex_init(&dev->mode_config.fb_lock); 56978fb6e7a5SDaniel Stone mutex_init(&dev->mode_config.blob_lock); 569887d24fc3SLaurent Pinchart INIT_LIST_HEAD(&dev->mode_config.fb_list); 569987d24fc3SLaurent Pinchart INIT_LIST_HEAD(&dev->mode_config.crtc_list); 570087d24fc3SLaurent Pinchart INIT_LIST_HEAD(&dev->mode_config.connector_list); 570187d24fc3SLaurent Pinchart INIT_LIST_HEAD(&dev->mode_config.encoder_list); 570287d24fc3SLaurent Pinchart INIT_LIST_HEAD(&dev->mode_config.property_list); 570387d24fc3SLaurent Pinchart INIT_LIST_HEAD(&dev->mode_config.property_blob_list); 570487d24fc3SLaurent Pinchart INIT_LIST_HEAD(&dev->mode_config.plane_list); 570587d24fc3SLaurent Pinchart idr_init(&dev->mode_config.crtc_idr); 5706138f9ebbSDave Airlie idr_init(&dev->mode_config.tile_idr); 570787d24fc3SLaurent Pinchart 570887d24fc3SLaurent Pinchart drm_modeset_lock_all(dev); 57096b4959f4SRob Clark drm_mode_create_standard_properties(dev); 571087d24fc3SLaurent Pinchart drm_modeset_unlock_all(dev); 571187d24fc3SLaurent Pinchart 571287d24fc3SLaurent Pinchart /* Just to be sure */ 571387d24fc3SLaurent Pinchart dev->mode_config.num_fb = 0; 571487d24fc3SLaurent Pinchart dev->mode_config.num_connector = 0; 571587d24fc3SLaurent Pinchart dev->mode_config.num_crtc = 0; 571687d24fc3SLaurent Pinchart dev->mode_config.num_encoder = 0; 5717e27dde3eSMatt Roper dev->mode_config.num_overlay_plane = 0; 5718e27dde3eSMatt Roper dev->mode_config.num_total_plane = 0; 571987d24fc3SLaurent Pinchart } 572087d24fc3SLaurent Pinchart EXPORT_SYMBOL(drm_mode_config_init); 572187d24fc3SLaurent Pinchart 572287d24fc3SLaurent Pinchart /** 572387d24fc3SLaurent Pinchart * drm_mode_config_cleanup - free up DRM mode_config info 572487d24fc3SLaurent Pinchart * @dev: DRM device 572587d24fc3SLaurent Pinchart * 572687d24fc3SLaurent Pinchart * Free up all the connectors and CRTCs associated with this DRM device, then 572787d24fc3SLaurent Pinchart * free up the framebuffers and associated buffer objects. 572887d24fc3SLaurent Pinchart * 572987d24fc3SLaurent Pinchart * Note that since this /should/ happen single-threaded at driver/device 573087d24fc3SLaurent Pinchart * teardown time, no locking is required. It's the driver's job to ensure that 573187d24fc3SLaurent Pinchart * this guarantee actually holds true. 573287d24fc3SLaurent Pinchart * 573387d24fc3SLaurent Pinchart * FIXME: cleanup any dangling user buffer objects too 573487d24fc3SLaurent Pinchart */ 573587d24fc3SLaurent Pinchart void drm_mode_config_cleanup(struct drm_device *dev) 573687d24fc3SLaurent Pinchart { 573787d24fc3SLaurent Pinchart struct drm_connector *connector, *ot; 573887d24fc3SLaurent Pinchart struct drm_crtc *crtc, *ct; 573987d24fc3SLaurent Pinchart struct drm_encoder *encoder, *enct; 574087d24fc3SLaurent Pinchart struct drm_framebuffer *fb, *fbt; 574187d24fc3SLaurent Pinchart struct drm_property *property, *pt; 574287d24fc3SLaurent Pinchart struct drm_property_blob *blob, *bt; 574387d24fc3SLaurent Pinchart struct drm_plane *plane, *plt; 574487d24fc3SLaurent Pinchart 574587d24fc3SLaurent Pinchart list_for_each_entry_safe(encoder, enct, &dev->mode_config.encoder_list, 574687d24fc3SLaurent Pinchart head) { 574787d24fc3SLaurent Pinchart encoder->funcs->destroy(encoder); 574887d24fc3SLaurent Pinchart } 574987d24fc3SLaurent Pinchart 575087d24fc3SLaurent Pinchart list_for_each_entry_safe(connector, ot, 575187d24fc3SLaurent Pinchart &dev->mode_config.connector_list, head) { 575287d24fc3SLaurent Pinchart connector->funcs->destroy(connector); 575387d24fc3SLaurent Pinchart } 575487d24fc3SLaurent Pinchart 575587d24fc3SLaurent Pinchart list_for_each_entry_safe(property, pt, &dev->mode_config.property_list, 575687d24fc3SLaurent Pinchart head) { 575787d24fc3SLaurent Pinchart drm_property_destroy(dev, property); 575887d24fc3SLaurent Pinchart } 575987d24fc3SLaurent Pinchart 576087d24fc3SLaurent Pinchart list_for_each_entry_safe(blob, bt, &dev->mode_config.property_blob_list, 5761e2f5d2eaSDaniel Stone head_global) { 57626bcacf51SDaniel Stone drm_property_unreference_blob(blob); 576387d24fc3SLaurent Pinchart } 576487d24fc3SLaurent Pinchart 576587d24fc3SLaurent Pinchart /* 576687d24fc3SLaurent Pinchart * Single-threaded teardown context, so it's not required to grab the 576787d24fc3SLaurent Pinchart * fb_lock to protect against concurrent fb_list access. Contrary, it 576887d24fc3SLaurent Pinchart * would actually deadlock with the drm_framebuffer_cleanup function. 576987d24fc3SLaurent Pinchart * 577087d24fc3SLaurent Pinchart * Also, if there are any framebuffers left, that's a driver leak now, 577187d24fc3SLaurent Pinchart * so politely WARN about this. 577287d24fc3SLaurent Pinchart */ 577387d24fc3SLaurent Pinchart WARN_ON(!list_empty(&dev->mode_config.fb_list)); 577487d24fc3SLaurent Pinchart list_for_each_entry_safe(fb, fbt, &dev->mode_config.fb_list, head) { 5775c099b55aSMaarten Lankhorst drm_framebuffer_free(&fb->refcount); 577687d24fc3SLaurent Pinchart } 577787d24fc3SLaurent Pinchart 577887d24fc3SLaurent Pinchart list_for_each_entry_safe(plane, plt, &dev->mode_config.plane_list, 577987d24fc3SLaurent Pinchart head) { 578087d24fc3SLaurent Pinchart plane->funcs->destroy(plane); 578187d24fc3SLaurent Pinchart } 578287d24fc3SLaurent Pinchart 578387d24fc3SLaurent Pinchart list_for_each_entry_safe(crtc, ct, &dev->mode_config.crtc_list, head) { 578487d24fc3SLaurent Pinchart crtc->funcs->destroy(crtc); 578587d24fc3SLaurent Pinchart } 578687d24fc3SLaurent Pinchart 5787138f9ebbSDave Airlie idr_destroy(&dev->mode_config.tile_idr); 578887d24fc3SLaurent Pinchart idr_destroy(&dev->mode_config.crtc_idr); 578951fd371bSRob Clark drm_modeset_lock_fini(&dev->mode_config.connection_mutex); 579087d24fc3SLaurent Pinchart } 579187d24fc3SLaurent Pinchart EXPORT_SYMBOL(drm_mode_config_cleanup); 5792c1df5f3cSVille Syrjälä 5793c1df5f3cSVille Syrjälä struct drm_property *drm_mode_create_rotation_property(struct drm_device *dev, 5794c1df5f3cSVille Syrjälä unsigned int supported_rotations) 5795c1df5f3cSVille Syrjälä { 5796c1df5f3cSVille Syrjälä static const struct drm_prop_enum_list props[] = { 5797c1df5f3cSVille Syrjälä { DRM_ROTATE_0, "rotate-0" }, 5798c1df5f3cSVille Syrjälä { DRM_ROTATE_90, "rotate-90" }, 5799c1df5f3cSVille Syrjälä { DRM_ROTATE_180, "rotate-180" }, 5800c1df5f3cSVille Syrjälä { DRM_ROTATE_270, "rotate-270" }, 5801c1df5f3cSVille Syrjälä { DRM_REFLECT_X, "reflect-x" }, 5802c1df5f3cSVille Syrjälä { DRM_REFLECT_Y, "reflect-y" }, 5803c1df5f3cSVille Syrjälä }; 5804c1df5f3cSVille Syrjälä 5805c1df5f3cSVille Syrjälä return drm_property_create_bitmask(dev, 0, "rotation", 5806c1df5f3cSVille Syrjälä props, ARRAY_SIZE(props), 5807c1df5f3cSVille Syrjälä supported_rotations); 5808c1df5f3cSVille Syrjälä } 5809c1df5f3cSVille Syrjälä EXPORT_SYMBOL(drm_mode_create_rotation_property); 5810138f9ebbSDave Airlie 5811138f9ebbSDave Airlie /** 5812138f9ebbSDave Airlie * DOC: Tile group 5813138f9ebbSDave Airlie * 5814138f9ebbSDave Airlie * Tile groups are used to represent tiled monitors with a unique 5815138f9ebbSDave Airlie * integer identifier. Tiled monitors using DisplayID v1.3 have 5816138f9ebbSDave Airlie * a unique 8-byte handle, we store this in a tile group, so we 5817138f9ebbSDave Airlie * have a common identifier for all tiles in a monitor group. 5818138f9ebbSDave Airlie */ 5819138f9ebbSDave Airlie static void drm_tile_group_free(struct kref *kref) 5820138f9ebbSDave Airlie { 5821138f9ebbSDave Airlie struct drm_tile_group *tg = container_of(kref, struct drm_tile_group, refcount); 5822138f9ebbSDave Airlie struct drm_device *dev = tg->dev; 5823138f9ebbSDave Airlie mutex_lock(&dev->mode_config.idr_mutex); 5824138f9ebbSDave Airlie idr_remove(&dev->mode_config.tile_idr, tg->id); 5825138f9ebbSDave Airlie mutex_unlock(&dev->mode_config.idr_mutex); 5826138f9ebbSDave Airlie kfree(tg); 5827138f9ebbSDave Airlie } 5828138f9ebbSDave Airlie 5829138f9ebbSDave Airlie /** 5830138f9ebbSDave Airlie * drm_mode_put_tile_group - drop a reference to a tile group. 5831138f9ebbSDave Airlie * @dev: DRM device 5832138f9ebbSDave Airlie * @tg: tile group to drop reference to. 5833138f9ebbSDave Airlie * 5834138f9ebbSDave Airlie * drop reference to tile group and free if 0. 5835138f9ebbSDave Airlie */ 5836138f9ebbSDave Airlie void drm_mode_put_tile_group(struct drm_device *dev, 5837138f9ebbSDave Airlie struct drm_tile_group *tg) 5838138f9ebbSDave Airlie { 5839138f9ebbSDave Airlie kref_put(&tg->refcount, drm_tile_group_free); 5840138f9ebbSDave Airlie } 5841138f9ebbSDave Airlie 5842138f9ebbSDave Airlie /** 5843138f9ebbSDave Airlie * drm_mode_get_tile_group - get a reference to an existing tile group 5844138f9ebbSDave Airlie * @dev: DRM device 5845138f9ebbSDave Airlie * @topology: 8-bytes unique per monitor. 5846138f9ebbSDave Airlie * 5847138f9ebbSDave Airlie * Use the unique bytes to get a reference to an existing tile group. 5848138f9ebbSDave Airlie * 5849138f9ebbSDave Airlie * RETURNS: 5850138f9ebbSDave Airlie * tile group or NULL if not found. 5851138f9ebbSDave Airlie */ 5852138f9ebbSDave Airlie struct drm_tile_group *drm_mode_get_tile_group(struct drm_device *dev, 5853138f9ebbSDave Airlie char topology[8]) 5854138f9ebbSDave Airlie { 5855138f9ebbSDave Airlie struct drm_tile_group *tg; 5856138f9ebbSDave Airlie int id; 5857138f9ebbSDave Airlie mutex_lock(&dev->mode_config.idr_mutex); 5858138f9ebbSDave Airlie idr_for_each_entry(&dev->mode_config.tile_idr, tg, id) { 5859138f9ebbSDave Airlie if (!memcmp(tg->group_data, topology, 8)) { 5860138f9ebbSDave Airlie if (!kref_get_unless_zero(&tg->refcount)) 5861138f9ebbSDave Airlie tg = NULL; 5862138f9ebbSDave Airlie mutex_unlock(&dev->mode_config.idr_mutex); 5863138f9ebbSDave Airlie return tg; 5864138f9ebbSDave Airlie } 5865138f9ebbSDave Airlie } 5866138f9ebbSDave Airlie mutex_unlock(&dev->mode_config.idr_mutex); 5867138f9ebbSDave Airlie return NULL; 5868138f9ebbSDave Airlie } 586981ddd1bcSRob Clark EXPORT_SYMBOL(drm_mode_get_tile_group); 5870138f9ebbSDave Airlie 5871138f9ebbSDave Airlie /** 5872138f9ebbSDave Airlie * drm_mode_create_tile_group - create a tile group from a displayid description 5873138f9ebbSDave Airlie * @dev: DRM device 5874138f9ebbSDave Airlie * @topology: 8-bytes unique per monitor. 5875138f9ebbSDave Airlie * 5876138f9ebbSDave Airlie * Create a tile group for the unique monitor, and get a unique 5877138f9ebbSDave Airlie * identifier for the tile group. 5878138f9ebbSDave Airlie * 5879138f9ebbSDave Airlie * RETURNS: 5880138f9ebbSDave Airlie * new tile group or error. 5881138f9ebbSDave Airlie */ 5882138f9ebbSDave Airlie struct drm_tile_group *drm_mode_create_tile_group(struct drm_device *dev, 5883138f9ebbSDave Airlie char topology[8]) 5884138f9ebbSDave Airlie { 5885138f9ebbSDave Airlie struct drm_tile_group *tg; 5886138f9ebbSDave Airlie int ret; 5887138f9ebbSDave Airlie 5888138f9ebbSDave Airlie tg = kzalloc(sizeof(*tg), GFP_KERNEL); 5889138f9ebbSDave Airlie if (!tg) 5890138f9ebbSDave Airlie return ERR_PTR(-ENOMEM); 5891138f9ebbSDave Airlie 5892138f9ebbSDave Airlie kref_init(&tg->refcount); 5893138f9ebbSDave Airlie memcpy(tg->group_data, topology, 8); 5894138f9ebbSDave Airlie tg->dev = dev; 5895138f9ebbSDave Airlie 5896138f9ebbSDave Airlie mutex_lock(&dev->mode_config.idr_mutex); 5897138f9ebbSDave Airlie ret = idr_alloc(&dev->mode_config.tile_idr, tg, 1, 0, GFP_KERNEL); 5898138f9ebbSDave Airlie if (ret >= 0) { 5899138f9ebbSDave Airlie tg->id = ret; 5900138f9ebbSDave Airlie } else { 5901138f9ebbSDave Airlie kfree(tg); 5902138f9ebbSDave Airlie tg = ERR_PTR(ret); 5903138f9ebbSDave Airlie } 5904138f9ebbSDave Airlie 5905138f9ebbSDave Airlie mutex_unlock(&dev->mode_config.idr_mutex); 5906138f9ebbSDave Airlie return tg; 5907138f9ebbSDave Airlie } 590881ddd1bcSRob Clark EXPORT_SYMBOL(drm_mode_create_tile_group); 5909