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 46c394c2b0SMatt Roper static struct drm_framebuffer *add_framebuffer_internal(struct drm_device *dev, 47c394c2b0SMatt Roper struct drm_mode_fb_cmd2 *r, 48c394c2b0SMatt Roper struct drm_file *file_priv); 49c394c2b0SMatt Roper 50f453ba04SDave Airlie /* Avoid boilerplate. I'm tired of typing. */ 51f453ba04SDave Airlie #define DRM_ENUM_NAME_FN(fnname, list) \ 52d20d3174SVille Syrjälä const char *fnname(int val) \ 53f453ba04SDave Airlie { \ 54f453ba04SDave Airlie int i; \ 55f453ba04SDave Airlie for (i = 0; i < ARRAY_SIZE(list); i++) { \ 56f453ba04SDave Airlie if (list[i].type == val) \ 57f453ba04SDave Airlie return list[i].name; \ 58f453ba04SDave Airlie } \ 59f453ba04SDave Airlie return "(unknown)"; \ 60f453ba04SDave Airlie } 61f453ba04SDave Airlie 62f453ba04SDave Airlie /* 63f453ba04SDave Airlie * Global properties 64f453ba04SDave Airlie */ 654dfd909fSThierry Reding static const struct drm_prop_enum_list drm_dpms_enum_list[] = { 664dfd909fSThierry Reding { DRM_MODE_DPMS_ON, "On" }, 67f453ba04SDave Airlie { DRM_MODE_DPMS_STANDBY, "Standby" }, 68f453ba04SDave Airlie { DRM_MODE_DPMS_SUSPEND, "Suspend" }, 69f453ba04SDave Airlie { DRM_MODE_DPMS_OFF, "Off" } 70f453ba04SDave Airlie }; 71f453ba04SDave Airlie 72f453ba04SDave Airlie DRM_ENUM_NAME_FN(drm_get_dpms_name, drm_dpms_enum_list) 73f453ba04SDave Airlie 744dfd909fSThierry Reding static const struct drm_prop_enum_list drm_plane_type_enum_list[] = { 759922ab5aSRob Clark { DRM_PLANE_TYPE_OVERLAY, "Overlay" }, 769922ab5aSRob Clark { DRM_PLANE_TYPE_PRIMARY, "Primary" }, 779922ab5aSRob Clark { DRM_PLANE_TYPE_CURSOR, "Cursor" }, 789922ab5aSRob Clark }; 799922ab5aSRob Clark 80f453ba04SDave Airlie /* 81f453ba04SDave Airlie * Optional properties 82f453ba04SDave Airlie */ 834dfd909fSThierry Reding static const struct drm_prop_enum_list drm_scaling_mode_enum_list[] = { 8453bd8389SJesse Barnes { DRM_MODE_SCALE_NONE, "None" }, 8553bd8389SJesse Barnes { DRM_MODE_SCALE_FULLSCREEN, "Full" }, 8653bd8389SJesse Barnes { DRM_MODE_SCALE_CENTER, "Center" }, 8753bd8389SJesse Barnes { DRM_MODE_SCALE_ASPECT, "Full aspect" }, 88f453ba04SDave Airlie }; 89f453ba04SDave Airlie 90ff587e45SVandana Kannan static const struct drm_prop_enum_list drm_aspect_ratio_enum_list[] = { 91ff587e45SVandana Kannan { DRM_MODE_PICTURE_ASPECT_NONE, "Automatic" }, 92ff587e45SVandana Kannan { DRM_MODE_PICTURE_ASPECT_4_3, "4:3" }, 93ff587e45SVandana Kannan { DRM_MODE_PICTURE_ASPECT_16_9, "16:9" }, 94ff587e45SVandana Kannan }; 95ff587e45SVandana Kannan 96f453ba04SDave Airlie /* 97f453ba04SDave Airlie * Non-global properties, but "required" for certain connectors. 98f453ba04SDave Airlie */ 994dfd909fSThierry Reding static const struct drm_prop_enum_list drm_dvi_i_select_enum_list[] = { 100f453ba04SDave Airlie { DRM_MODE_SUBCONNECTOR_Automatic, "Automatic" }, /* DVI-I and TV-out */ 101f453ba04SDave Airlie { DRM_MODE_SUBCONNECTOR_DVID, "DVI-D" }, /* DVI-I */ 102f453ba04SDave Airlie { DRM_MODE_SUBCONNECTOR_DVIA, "DVI-A" }, /* DVI-I */ 103f453ba04SDave Airlie }; 104f453ba04SDave Airlie 105f453ba04SDave Airlie DRM_ENUM_NAME_FN(drm_get_dvi_i_select_name, drm_dvi_i_select_enum_list) 106f453ba04SDave Airlie 1074dfd909fSThierry Reding static const struct drm_prop_enum_list drm_dvi_i_subconnector_enum_list[] = { 108f453ba04SDave Airlie { DRM_MODE_SUBCONNECTOR_Unknown, "Unknown" }, /* DVI-I and TV-out */ 109f453ba04SDave Airlie { DRM_MODE_SUBCONNECTOR_DVID, "DVI-D" }, /* DVI-I */ 110f453ba04SDave Airlie { DRM_MODE_SUBCONNECTOR_DVIA, "DVI-A" }, /* DVI-I */ 111f453ba04SDave Airlie }; 112f453ba04SDave Airlie 113f453ba04SDave Airlie DRM_ENUM_NAME_FN(drm_get_dvi_i_subconnector_name, 114f453ba04SDave Airlie drm_dvi_i_subconnector_enum_list) 115f453ba04SDave Airlie 1164dfd909fSThierry Reding static const struct drm_prop_enum_list drm_tv_select_enum_list[] = { 117f453ba04SDave Airlie { DRM_MODE_SUBCONNECTOR_Automatic, "Automatic" }, /* DVI-I and TV-out */ 118f453ba04SDave Airlie { DRM_MODE_SUBCONNECTOR_Composite, "Composite" }, /* TV-out */ 119f453ba04SDave Airlie { DRM_MODE_SUBCONNECTOR_SVIDEO, "SVIDEO" }, /* TV-out */ 120f453ba04SDave Airlie { DRM_MODE_SUBCONNECTOR_Component, "Component" }, /* TV-out */ 121aeaa1ad3SFrancisco Jerez { DRM_MODE_SUBCONNECTOR_SCART, "SCART" }, /* TV-out */ 122f453ba04SDave Airlie }; 123f453ba04SDave Airlie 124f453ba04SDave Airlie DRM_ENUM_NAME_FN(drm_get_tv_select_name, drm_tv_select_enum_list) 125f453ba04SDave Airlie 1264dfd909fSThierry Reding static const struct drm_prop_enum_list drm_tv_subconnector_enum_list[] = { 127f453ba04SDave Airlie { DRM_MODE_SUBCONNECTOR_Unknown, "Unknown" }, /* DVI-I and TV-out */ 128f453ba04SDave Airlie { DRM_MODE_SUBCONNECTOR_Composite, "Composite" }, /* TV-out */ 129f453ba04SDave Airlie { DRM_MODE_SUBCONNECTOR_SVIDEO, "SVIDEO" }, /* TV-out */ 130f453ba04SDave Airlie { DRM_MODE_SUBCONNECTOR_Component, "Component" }, /* TV-out */ 131aeaa1ad3SFrancisco Jerez { DRM_MODE_SUBCONNECTOR_SCART, "SCART" }, /* TV-out */ 132f453ba04SDave Airlie }; 133f453ba04SDave Airlie 134f453ba04SDave Airlie DRM_ENUM_NAME_FN(drm_get_tv_subconnector_name, 135f453ba04SDave Airlie drm_tv_subconnector_enum_list) 136f453ba04SDave Airlie 137d20d3174SVille Syrjälä static const struct drm_prop_enum_list drm_dirty_info_enum_list[] = { 138884840aaSJakob Bornecrantz { DRM_MODE_DIRTY_OFF, "Off" }, 139884840aaSJakob Bornecrantz { DRM_MODE_DIRTY_ON, "On" }, 140884840aaSJakob Bornecrantz { DRM_MODE_DIRTY_ANNOTATE, "Annotate" }, 141884840aaSJakob Bornecrantz }; 142884840aaSJakob Bornecrantz 143f453ba04SDave Airlie struct drm_conn_prop_enum_list { 144f453ba04SDave Airlie int type; 145d20d3174SVille Syrjälä const char *name; 146b21e3afeSIlia Mirkin struct ida ida; 147f453ba04SDave Airlie }; 148f453ba04SDave Airlie 149f453ba04SDave Airlie /* 150f453ba04SDave Airlie * Connector and encoder types. 151f453ba04SDave Airlie */ 1524dfd909fSThierry Reding static struct drm_conn_prop_enum_list drm_connector_enum_list[] = { 1534dfd909fSThierry Reding { DRM_MODE_CONNECTOR_Unknown, "Unknown" }, 154b21e3afeSIlia Mirkin { DRM_MODE_CONNECTOR_VGA, "VGA" }, 155b21e3afeSIlia Mirkin { DRM_MODE_CONNECTOR_DVII, "DVI-I" }, 156b21e3afeSIlia Mirkin { DRM_MODE_CONNECTOR_DVID, "DVI-D" }, 157b21e3afeSIlia Mirkin { DRM_MODE_CONNECTOR_DVIA, "DVI-A" }, 158b21e3afeSIlia Mirkin { DRM_MODE_CONNECTOR_Composite, "Composite" }, 159b21e3afeSIlia Mirkin { DRM_MODE_CONNECTOR_SVIDEO, "SVIDEO" }, 160b21e3afeSIlia Mirkin { DRM_MODE_CONNECTOR_LVDS, "LVDS" }, 161b21e3afeSIlia Mirkin { DRM_MODE_CONNECTOR_Component, "Component" }, 162b21e3afeSIlia Mirkin { DRM_MODE_CONNECTOR_9PinDIN, "DIN" }, 163b21e3afeSIlia Mirkin { DRM_MODE_CONNECTOR_DisplayPort, "DP" }, 164b21e3afeSIlia Mirkin { DRM_MODE_CONNECTOR_HDMIA, "HDMI-A" }, 165b21e3afeSIlia Mirkin { DRM_MODE_CONNECTOR_HDMIB, "HDMI-B" }, 166b21e3afeSIlia Mirkin { DRM_MODE_CONNECTOR_TV, "TV" }, 167b21e3afeSIlia Mirkin { DRM_MODE_CONNECTOR_eDP, "eDP" }, 168b21e3afeSIlia Mirkin { DRM_MODE_CONNECTOR_VIRTUAL, "Virtual" }, 169b8923273SShobhit Kumar { DRM_MODE_CONNECTOR_DSI, "DSI" }, 170f453ba04SDave Airlie }; 171f453ba04SDave Airlie 1724dfd909fSThierry Reding static const struct drm_prop_enum_list drm_encoder_enum_list[] = { 1734dfd909fSThierry Reding { DRM_MODE_ENCODER_NONE, "None" }, 174f453ba04SDave Airlie { DRM_MODE_ENCODER_DAC, "DAC" }, 175f453ba04SDave Airlie { DRM_MODE_ENCODER_TMDS, "TMDS" }, 176f453ba04SDave Airlie { DRM_MODE_ENCODER_LVDS, "LVDS" }, 177f453ba04SDave Airlie { DRM_MODE_ENCODER_TVDAC, "TV" }, 178a7331e5cSThomas Hellstrom { DRM_MODE_ENCODER_VIRTUAL, "Virtual" }, 179b8923273SShobhit Kumar { DRM_MODE_ENCODER_DSI, "DSI" }, 180182407a6SDave Airlie { DRM_MODE_ENCODER_DPMST, "DP MST" }, 181f453ba04SDave Airlie }; 182f453ba04SDave Airlie 1834dfd909fSThierry Reding static const struct drm_prop_enum_list drm_subpixel_enum_list[] = { 184ac1bb36cSJesse Barnes { SubPixelUnknown, "Unknown" }, 185ac1bb36cSJesse Barnes { SubPixelHorizontalRGB, "Horizontal RGB" }, 186ac1bb36cSJesse Barnes { SubPixelHorizontalBGR, "Horizontal BGR" }, 187ac1bb36cSJesse Barnes { SubPixelVerticalRGB, "Vertical RGB" }, 188ac1bb36cSJesse Barnes { SubPixelVerticalBGR, "Vertical BGR" }, 189ac1bb36cSJesse Barnes { SubPixelNone, "None" }, 190ac1bb36cSJesse Barnes }; 191ac1bb36cSJesse Barnes 192b21e3afeSIlia Mirkin void drm_connector_ida_init(void) 193b21e3afeSIlia Mirkin { 194b21e3afeSIlia Mirkin int i; 195b21e3afeSIlia Mirkin 196b21e3afeSIlia Mirkin for (i = 0; i < ARRAY_SIZE(drm_connector_enum_list); i++) 197b21e3afeSIlia Mirkin ida_init(&drm_connector_enum_list[i].ida); 198b21e3afeSIlia Mirkin } 199b21e3afeSIlia Mirkin 200b21e3afeSIlia Mirkin void drm_connector_ida_destroy(void) 201b21e3afeSIlia Mirkin { 202b21e3afeSIlia Mirkin int i; 203b21e3afeSIlia Mirkin 204b21e3afeSIlia Mirkin for (i = 0; i < ARRAY_SIZE(drm_connector_enum_list); i++) 205b21e3afeSIlia Mirkin ida_destroy(&drm_connector_enum_list[i].ida); 206b21e3afeSIlia Mirkin } 207b21e3afeSIlia Mirkin 208c8e32cc1SDaniel Vetter /** 209c8e32cc1SDaniel Vetter * drm_get_connector_status_name - return a string for connector status 210c8e32cc1SDaniel Vetter * @status: connector status to compute name of 211c8e32cc1SDaniel Vetter * 212c8e32cc1SDaniel Vetter * In contrast to the other drm_get_*_name functions this one here returns a 213c8e32cc1SDaniel Vetter * const pointer and hence is threadsafe. 214c8e32cc1SDaniel Vetter */ 215d20d3174SVille Syrjälä const char *drm_get_connector_status_name(enum drm_connector_status status) 216f453ba04SDave Airlie { 217f453ba04SDave Airlie if (status == connector_status_connected) 218f453ba04SDave Airlie return "connected"; 219f453ba04SDave Airlie else if (status == connector_status_disconnected) 220f453ba04SDave Airlie return "disconnected"; 221f453ba04SDave Airlie else 222f453ba04SDave Airlie return "unknown"; 223f453ba04SDave Airlie } 224ed7951dcSLespiau, Damien EXPORT_SYMBOL(drm_get_connector_status_name); 225f453ba04SDave Airlie 226ac1bb36cSJesse Barnes /** 227ac1bb36cSJesse Barnes * drm_get_subpixel_order_name - return a string for a given subpixel enum 228ac1bb36cSJesse Barnes * @order: enum of subpixel_order 229ac1bb36cSJesse Barnes * 230ac1bb36cSJesse Barnes * Note you could abuse this and return something out of bounds, but that 231ac1bb36cSJesse Barnes * would be a caller error. No unscrubbed user data should make it here. 232ac1bb36cSJesse Barnes */ 233ac1bb36cSJesse Barnes const char *drm_get_subpixel_order_name(enum subpixel_order order) 234ac1bb36cSJesse Barnes { 235ac1bb36cSJesse Barnes return drm_subpixel_enum_list[order].name; 236ac1bb36cSJesse Barnes } 237ac1bb36cSJesse Barnes EXPORT_SYMBOL(drm_get_subpixel_order_name); 238ac1bb36cSJesse Barnes 2396ba6d03eSVille Syrjälä static char printable_char(int c) 2406ba6d03eSVille Syrjälä { 2416ba6d03eSVille Syrjälä return isascii(c) && isprint(c) ? c : '?'; 2426ba6d03eSVille Syrjälä } 2436ba6d03eSVille Syrjälä 244c8e32cc1SDaniel Vetter /** 245c8e32cc1SDaniel Vetter * drm_get_format_name - return a string for drm fourcc format 246c8e32cc1SDaniel Vetter * @format: format to compute name of 247c8e32cc1SDaniel Vetter * 248c8e32cc1SDaniel Vetter * Note that the buffer used by this function is globally shared and owned by 249c8e32cc1SDaniel Vetter * the function itself. 250c8e32cc1SDaniel Vetter * 251c8e32cc1SDaniel Vetter * FIXME: This isn't really multithreading safe. 252c8e32cc1SDaniel Vetter */ 253d20d3174SVille Syrjälä const char *drm_get_format_name(uint32_t format) 2546ba6d03eSVille Syrjälä { 2556ba6d03eSVille Syrjälä static char buf[32]; 2566ba6d03eSVille Syrjälä 2576ba6d03eSVille Syrjälä snprintf(buf, sizeof(buf), 2586ba6d03eSVille Syrjälä "%c%c%c%c %s-endian (0x%08x)", 2596ba6d03eSVille Syrjälä printable_char(format & 0xff), 2606ba6d03eSVille Syrjälä printable_char((format >> 8) & 0xff), 2616ba6d03eSVille Syrjälä printable_char((format >> 16) & 0xff), 2626ba6d03eSVille Syrjälä printable_char((format >> 24) & 0x7f), 2636ba6d03eSVille Syrjälä format & DRM_FORMAT_BIG_ENDIAN ? "big" : "little", 2646ba6d03eSVille Syrjälä format); 2656ba6d03eSVille Syrjälä 2666ba6d03eSVille Syrjälä return buf; 2676ba6d03eSVille Syrjälä } 2686ba6d03eSVille Syrjälä EXPORT_SYMBOL(drm_get_format_name); 2696ba6d03eSVille Syrjälä 2702ee39452SDave Airlie /* 2712ee39452SDave Airlie * Internal function to assign a slot in the object idr and optionally 2722ee39452SDave Airlie * register the object into the idr. 2732ee39452SDave Airlie */ 2742ee39452SDave Airlie static int drm_mode_object_get_reg(struct drm_device *dev, 2752ee39452SDave Airlie struct drm_mode_object *obj, 2762ee39452SDave Airlie uint32_t obj_type, 2772ee39452SDave Airlie bool register_obj) 2782ee39452SDave Airlie { 2792ee39452SDave Airlie int ret; 2802ee39452SDave Airlie 2812ee39452SDave Airlie mutex_lock(&dev->mode_config.idr_mutex); 2822ee39452SDave Airlie ret = idr_alloc(&dev->mode_config.crtc_idr, register_obj ? obj : NULL, 1, 0, GFP_KERNEL); 2832ee39452SDave Airlie if (ret >= 0) { 2842ee39452SDave Airlie /* 2852ee39452SDave Airlie * Set up the object linking under the protection of the idr 2862ee39452SDave Airlie * lock so that other users can't see inconsistent state. 2872ee39452SDave Airlie */ 2882ee39452SDave Airlie obj->id = ret; 2892ee39452SDave Airlie obj->type = obj_type; 2902ee39452SDave Airlie } 2912ee39452SDave Airlie mutex_unlock(&dev->mode_config.idr_mutex); 2922ee39452SDave Airlie 2932ee39452SDave Airlie return ret < 0 ? ret : 0; 2942ee39452SDave Airlie } 2952ee39452SDave Airlie 296f453ba04SDave Airlie /** 297065a50edSDaniel Vetter * drm_mode_object_get - allocate a new modeset identifier 298f453ba04SDave Airlie * @dev: DRM device 299065a50edSDaniel Vetter * @obj: object pointer, used to generate unique ID 300065a50edSDaniel Vetter * @obj_type: object type 301f453ba04SDave Airlie * 302f453ba04SDave Airlie * Create a unique identifier based on @ptr in @dev's identifier space. Used 303c8e32cc1SDaniel Vetter * for tracking modes, CRTCs and connectors. Note that despite the _get postfix 304c8e32cc1SDaniel Vetter * modeset identifiers are _not_ reference counted. Hence don't use this for 305c8e32cc1SDaniel Vetter * reference counted modeset objects like framebuffers. 306f453ba04SDave Airlie * 307c8e32cc1SDaniel Vetter * Returns: 308f453ba04SDave Airlie * New unique (relative to other objects in @dev) integer identifier for the 309f453ba04SDave Airlie * object. 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 */ 354168c02ecSDaniel Vetter if (obj && (obj->type == DRM_MODE_OBJECT_FB)) 35598f75de4SRob Clark obj = NULL; 35698f75de4SRob Clark mutex_unlock(&dev->mode_config.idr_mutex); 35798f75de4SRob Clark 35898f75de4SRob Clark return obj; 35998f75de4SRob Clark } 36098f75de4SRob Clark 361786b99edSDaniel Vetter /** 362786b99edSDaniel Vetter * drm_mode_object_find - look up a drm object with static lifetime 363786b99edSDaniel Vetter * @dev: drm device 364786b99edSDaniel Vetter * @id: id of the mode object 365786b99edSDaniel Vetter * @type: type of the mode object 366786b99edSDaniel Vetter * 367786b99edSDaniel Vetter * Note that framebuffers cannot be looked up with this functions - since those 36898f75de4SRob Clark * are reference counted, they need special treatment. Even with 36998f75de4SRob Clark * DRM_MODE_OBJECT_ANY (although that will simply return NULL 37098f75de4SRob Clark * rather than WARN_ON()). 371786b99edSDaniel Vetter */ 3727a9c9060SDaniel Vetter struct drm_mode_object *drm_mode_object_find(struct drm_device *dev, 3737a9c9060SDaniel Vetter uint32_t id, uint32_t type) 374f453ba04SDave Airlie { 375ad2563c2SJesse Barnes struct drm_mode_object *obj = NULL; 376f453ba04SDave Airlie 377786b99edSDaniel Vetter /* Framebuffers are reference counted and need their own lookup 378786b99edSDaniel Vetter * function.*/ 379786b99edSDaniel Vetter WARN_ON(type == DRM_MODE_OBJECT_FB); 38098f75de4SRob Clark obj = _object_find(dev, id, type); 381f453ba04SDave Airlie return obj; 382f453ba04SDave Airlie } 383f453ba04SDave Airlie EXPORT_SYMBOL(drm_mode_object_find); 384f453ba04SDave Airlie 385f453ba04SDave Airlie /** 386f453ba04SDave Airlie * drm_framebuffer_init - initialize a framebuffer 387f453ba04SDave Airlie * @dev: DRM device 388065a50edSDaniel Vetter * @fb: framebuffer to be initialized 389065a50edSDaniel Vetter * @funcs: ... with these functions 390f453ba04SDave Airlie * 391f453ba04SDave Airlie * Allocates an ID for the framebuffer's parent mode object, sets its mode 392f453ba04SDave Airlie * functions & device file and adds it to the master fd list. 393f453ba04SDave Airlie * 3944b096ac1SDaniel Vetter * IMPORTANT: 3954b096ac1SDaniel Vetter * This functions publishes the fb and makes it available for concurrent access 3964b096ac1SDaniel Vetter * by other users. Which means by this point the fb _must_ be fully set up - 3974b096ac1SDaniel Vetter * since all the fb attributes are invariant over its lifetime, no further 3984b096ac1SDaniel Vetter * locking but only correct reference counting is required. 3994b096ac1SDaniel Vetter * 400c8e32cc1SDaniel Vetter * Returns: 401af901ca1SAndré Goddard Rosa * Zero on success, error code on failure. 402f453ba04SDave Airlie */ 403f453ba04SDave Airlie int drm_framebuffer_init(struct drm_device *dev, struct drm_framebuffer *fb, 404f453ba04SDave Airlie const struct drm_framebuffer_funcs *funcs) 405f453ba04SDave Airlie { 406f453ba04SDave Airlie int ret; 407f453ba04SDave Airlie 4084b096ac1SDaniel Vetter mutex_lock(&dev->mode_config.fb_lock); 409f7eff60eSRob Clark kref_init(&fb->refcount); 4104b096ac1SDaniel Vetter INIT_LIST_HEAD(&fb->filp_head); 4114b096ac1SDaniel Vetter fb->dev = dev; 4124b096ac1SDaniel Vetter fb->funcs = funcs; 413f7eff60eSRob Clark 414f453ba04SDave Airlie ret = drm_mode_object_get(dev, &fb->base, DRM_MODE_OBJECT_FB); 4156bfc56aaSVille Syrjälä if (ret) 4164b096ac1SDaniel Vetter goto out; 417f453ba04SDave Airlie 418f453ba04SDave Airlie dev->mode_config.num_fb++; 419f453ba04SDave Airlie list_add(&fb->head, &dev->mode_config.fb_list); 4204b096ac1SDaniel Vetter out: 4214b096ac1SDaniel Vetter mutex_unlock(&dev->mode_config.fb_lock); 422f453ba04SDave Airlie 423f453ba04SDave Airlie return 0; 424f453ba04SDave Airlie } 425f453ba04SDave Airlie EXPORT_SYMBOL(drm_framebuffer_init); 426f453ba04SDave Airlie 42783f45fc3SDaniel Vetter /* dev->mode_config.fb_lock must be held! */ 42883f45fc3SDaniel Vetter static void __drm_framebuffer_unregister(struct drm_device *dev, 42983f45fc3SDaniel Vetter struct drm_framebuffer *fb) 43083f45fc3SDaniel Vetter { 43183f45fc3SDaniel Vetter mutex_lock(&dev->mode_config.idr_mutex); 43283f45fc3SDaniel Vetter idr_remove(&dev->mode_config.crtc_idr, fb->base.id); 43383f45fc3SDaniel Vetter mutex_unlock(&dev->mode_config.idr_mutex); 43483f45fc3SDaniel Vetter 43583f45fc3SDaniel Vetter fb->base.id = 0; 43683f45fc3SDaniel Vetter } 43783f45fc3SDaniel Vetter 438f7eff60eSRob Clark static void drm_framebuffer_free(struct kref *kref) 439f7eff60eSRob Clark { 440f7eff60eSRob Clark struct drm_framebuffer *fb = 441f7eff60eSRob Clark container_of(kref, struct drm_framebuffer, refcount); 44283f45fc3SDaniel Vetter struct drm_device *dev = fb->dev; 44383f45fc3SDaniel Vetter 44483f45fc3SDaniel Vetter /* 44583f45fc3SDaniel Vetter * The lookup idr holds a weak reference, which has not necessarily been 44683f45fc3SDaniel Vetter * removed at this point. Check for that. 44783f45fc3SDaniel Vetter */ 44883f45fc3SDaniel Vetter mutex_lock(&dev->mode_config.fb_lock); 44983f45fc3SDaniel Vetter if (fb->base.id) { 45083f45fc3SDaniel Vetter /* Mark fb as reaped and drop idr ref. */ 45183f45fc3SDaniel Vetter __drm_framebuffer_unregister(dev, fb); 45283f45fc3SDaniel Vetter } 45383f45fc3SDaniel Vetter mutex_unlock(&dev->mode_config.fb_lock); 45483f45fc3SDaniel Vetter 455f7eff60eSRob Clark fb->funcs->destroy(fb); 456f7eff60eSRob Clark } 457f7eff60eSRob Clark 4582b677e8cSDaniel Vetter static struct drm_framebuffer *__drm_framebuffer_lookup(struct drm_device *dev, 4592b677e8cSDaniel Vetter uint32_t id) 4602b677e8cSDaniel Vetter { 4612b677e8cSDaniel Vetter struct drm_mode_object *obj = NULL; 4622b677e8cSDaniel Vetter struct drm_framebuffer *fb; 4632b677e8cSDaniel Vetter 4642b677e8cSDaniel Vetter mutex_lock(&dev->mode_config.idr_mutex); 4652b677e8cSDaniel Vetter obj = idr_find(&dev->mode_config.crtc_idr, id); 4662b677e8cSDaniel Vetter if (!obj || (obj->type != DRM_MODE_OBJECT_FB) || (obj->id != id)) 4672b677e8cSDaniel Vetter fb = NULL; 4682b677e8cSDaniel Vetter else 4692b677e8cSDaniel Vetter fb = obj_to_fb(obj); 4702b677e8cSDaniel Vetter mutex_unlock(&dev->mode_config.idr_mutex); 4712b677e8cSDaniel Vetter 4722b677e8cSDaniel Vetter return fb; 4732b677e8cSDaniel Vetter } 4742b677e8cSDaniel Vetter 475f7eff60eSRob Clark /** 476786b99edSDaniel Vetter * drm_framebuffer_lookup - look up a drm framebuffer and grab a reference 477786b99edSDaniel Vetter * @dev: drm device 478786b99edSDaniel Vetter * @id: id of the fb object 479786b99edSDaniel Vetter * 480786b99edSDaniel Vetter * If successful, this grabs an additional reference to the framebuffer - 481786b99edSDaniel Vetter * callers need to make sure to eventually unreference the returned framebuffer 482c8e32cc1SDaniel Vetter * again, using @drm_framebuffer_unreference. 483786b99edSDaniel Vetter */ 484786b99edSDaniel Vetter struct drm_framebuffer *drm_framebuffer_lookup(struct drm_device *dev, 485786b99edSDaniel Vetter uint32_t id) 486786b99edSDaniel Vetter { 487786b99edSDaniel Vetter struct drm_framebuffer *fb; 488786b99edSDaniel Vetter 489786b99edSDaniel Vetter mutex_lock(&dev->mode_config.fb_lock); 4902b677e8cSDaniel Vetter fb = __drm_framebuffer_lookup(dev, id); 49183f45fc3SDaniel Vetter if (fb) { 49283f45fc3SDaniel Vetter if (!kref_get_unless_zero(&fb->refcount)) 49383f45fc3SDaniel Vetter fb = NULL; 49483f45fc3SDaniel Vetter } 495786b99edSDaniel Vetter mutex_unlock(&dev->mode_config.fb_lock); 496786b99edSDaniel Vetter 497786b99edSDaniel Vetter return fb; 498786b99edSDaniel Vetter } 499786b99edSDaniel Vetter EXPORT_SYMBOL(drm_framebuffer_lookup); 500786b99edSDaniel Vetter 501786b99edSDaniel Vetter /** 502f7eff60eSRob Clark * drm_framebuffer_unreference - unref a framebuffer 503065a50edSDaniel Vetter * @fb: framebuffer to unref 504065a50edSDaniel Vetter * 505065a50edSDaniel Vetter * This functions decrements the fb's refcount and frees it if it drops to zero. 506f7eff60eSRob Clark */ 507f7eff60eSRob Clark void drm_framebuffer_unreference(struct drm_framebuffer *fb) 508f7eff60eSRob Clark { 5098291272aSRob Clark DRM_DEBUG("%p: FB ID: %d (%d)\n", fb, fb->base.id, atomic_read(&fb->refcount.refcount)); 510f7eff60eSRob Clark kref_put(&fb->refcount, drm_framebuffer_free); 511f7eff60eSRob Clark } 512f7eff60eSRob Clark EXPORT_SYMBOL(drm_framebuffer_unreference); 513f7eff60eSRob Clark 514f7eff60eSRob Clark /** 515f7eff60eSRob Clark * drm_framebuffer_reference - incr the fb refcnt 516065a50edSDaniel Vetter * @fb: framebuffer 517c8e32cc1SDaniel Vetter * 518c8e32cc1SDaniel Vetter * This functions increments the fb's refcount. 519f7eff60eSRob Clark */ 520f7eff60eSRob Clark void drm_framebuffer_reference(struct drm_framebuffer *fb) 521f7eff60eSRob Clark { 5228291272aSRob Clark DRM_DEBUG("%p: FB ID: %d (%d)\n", fb, fb->base.id, atomic_read(&fb->refcount.refcount)); 523f7eff60eSRob Clark kref_get(&fb->refcount); 524f7eff60eSRob Clark } 525f7eff60eSRob Clark EXPORT_SYMBOL(drm_framebuffer_reference); 526f7eff60eSRob Clark 5272b677e8cSDaniel Vetter static void drm_framebuffer_free_bug(struct kref *kref) 5282b677e8cSDaniel Vetter { 5292b677e8cSDaniel Vetter BUG(); 5302b677e8cSDaniel Vetter } 5312b677e8cSDaniel Vetter 5326c2a7532SDaniel Vetter static void __drm_framebuffer_unreference(struct drm_framebuffer *fb) 5336c2a7532SDaniel Vetter { 5348291272aSRob Clark DRM_DEBUG("%p: FB ID: %d (%d)\n", fb, fb->base.id, atomic_read(&fb->refcount.refcount)); 5356c2a7532SDaniel Vetter kref_put(&fb->refcount, drm_framebuffer_free_bug); 5366c2a7532SDaniel Vetter } 5376c2a7532SDaniel Vetter 538f453ba04SDave Airlie /** 53936206361SDaniel Vetter * drm_framebuffer_unregister_private - unregister a private fb from the lookup idr 54036206361SDaniel Vetter * @fb: fb to unregister 54136206361SDaniel Vetter * 54236206361SDaniel Vetter * Drivers need to call this when cleaning up driver-private framebuffers, e.g. 54336206361SDaniel Vetter * those used for fbdev. Note that the caller must hold a reference of it's own, 54436206361SDaniel Vetter * i.e. the object may not be destroyed through this call (since it'll lead to a 54536206361SDaniel Vetter * locking inversion). 54636206361SDaniel Vetter */ 54736206361SDaniel Vetter void drm_framebuffer_unregister_private(struct drm_framebuffer *fb) 54836206361SDaniel Vetter { 5492b677e8cSDaniel Vetter struct drm_device *dev = fb->dev; 5502b677e8cSDaniel Vetter 5512b677e8cSDaniel Vetter mutex_lock(&dev->mode_config.fb_lock); 5522b677e8cSDaniel Vetter /* Mark fb as reaped and drop idr ref. */ 5532b677e8cSDaniel Vetter __drm_framebuffer_unregister(dev, fb); 5542b677e8cSDaniel Vetter mutex_unlock(&dev->mode_config.fb_lock); 55536206361SDaniel Vetter } 55636206361SDaniel Vetter EXPORT_SYMBOL(drm_framebuffer_unregister_private); 55736206361SDaniel Vetter 55836206361SDaniel Vetter /** 559f453ba04SDave Airlie * drm_framebuffer_cleanup - remove a framebuffer object 560f453ba04SDave Airlie * @fb: framebuffer to remove 561f453ba04SDave Airlie * 562c8e32cc1SDaniel Vetter * Cleanup framebuffer. This function is intended to be used from the drivers 563c8e32cc1SDaniel Vetter * ->destroy callback. It can also be used to clean up driver private 564c8e32cc1SDaniel Vetter * framebuffers embedded into a larger structure. 56536206361SDaniel Vetter * 56636206361SDaniel Vetter * Note that this function does not remove the fb from active usuage - if it is 56736206361SDaniel Vetter * still used anywhere, hilarity can ensue since userspace could call getfb on 56836206361SDaniel Vetter * the id and get back -EINVAL. Obviously no concern at driver unload time. 56936206361SDaniel Vetter * 57036206361SDaniel Vetter * Also, the framebuffer will not be removed from the lookup idr - for 57136206361SDaniel Vetter * user-created framebuffers this will happen in in the rmfb ioctl. For 57236206361SDaniel Vetter * driver-private objects (e.g. for fbdev) drivers need to explicitly call 57336206361SDaniel Vetter * drm_framebuffer_unregister_private. 574f453ba04SDave Airlie */ 575f453ba04SDave Airlie void drm_framebuffer_cleanup(struct drm_framebuffer *fb) 576f453ba04SDave Airlie { 577f453ba04SDave Airlie struct drm_device *dev = fb->dev; 5788faf6b18SDaniel Vetter 5794b096ac1SDaniel Vetter mutex_lock(&dev->mode_config.fb_lock); 580f7eff60eSRob Clark list_del(&fb->head); 581f7eff60eSRob Clark dev->mode_config.num_fb--; 5824b096ac1SDaniel Vetter mutex_unlock(&dev->mode_config.fb_lock); 583f7eff60eSRob Clark } 584f7eff60eSRob Clark EXPORT_SYMBOL(drm_framebuffer_cleanup); 585f7eff60eSRob Clark 586f7eff60eSRob Clark /** 587f7eff60eSRob Clark * drm_framebuffer_remove - remove and unreference a framebuffer object 588f7eff60eSRob Clark * @fb: framebuffer to remove 589f7eff60eSRob Clark * 590f7eff60eSRob Clark * Scans all the CRTCs and planes in @dev's mode_config. If they're 59136206361SDaniel Vetter * using @fb, removes it, setting it to NULL. Then drops the reference to the 592b62584e3SDaniel Vetter * passed-in framebuffer. Might take the modeset locks. 593b62584e3SDaniel Vetter * 594b62584e3SDaniel Vetter * Note that this function optimizes the cleanup away if the caller holds the 595b62584e3SDaniel Vetter * last reference to the framebuffer. It is also guaranteed to not take the 596b62584e3SDaniel Vetter * modeset locks in this case. 597f7eff60eSRob Clark */ 598f7eff60eSRob Clark void drm_framebuffer_remove(struct drm_framebuffer *fb) 599f7eff60eSRob Clark { 600f7eff60eSRob Clark struct drm_device *dev = fb->dev; 601f453ba04SDave Airlie struct drm_crtc *crtc; 6028cf5c917SJesse Barnes struct drm_plane *plane; 6035ef5f72fSDave Airlie struct drm_mode_set set; 6045ef5f72fSDave Airlie int ret; 605f453ba04SDave Airlie 6064b096ac1SDaniel Vetter WARN_ON(!list_empty(&fb->filp_head)); 6078faf6b18SDaniel Vetter 608b62584e3SDaniel Vetter /* 609b62584e3SDaniel Vetter * drm ABI mandates that we remove any deleted framebuffers from active 610b62584e3SDaniel Vetter * useage. But since most sane clients only remove framebuffers they no 611b62584e3SDaniel Vetter * longer need, try to optimize this away. 612b62584e3SDaniel Vetter * 613b62584e3SDaniel Vetter * Since we're holding a reference ourselves, observing a refcount of 1 614b62584e3SDaniel Vetter * means that we're the last holder and can skip it. Also, the refcount 615b62584e3SDaniel Vetter * can never increase from 1 again, so we don't need any barriers or 616b62584e3SDaniel Vetter * locks. 617b62584e3SDaniel Vetter * 618b62584e3SDaniel Vetter * Note that userspace could try to race with use and instate a new 619b62584e3SDaniel Vetter * usage _after_ we've cleared all current ones. End result will be an 620b62584e3SDaniel Vetter * in-use fb with fb-id == 0. Userspace is allowed to shoot its own foot 621b62584e3SDaniel Vetter * in this manner. 622b62584e3SDaniel Vetter */ 623b62584e3SDaniel Vetter if (atomic_read(&fb->refcount.refcount) > 1) { 624b62584e3SDaniel Vetter drm_modeset_lock_all(dev); 625f453ba04SDave Airlie /* remove from any CRTC */ 626f453ba04SDave Airlie list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { 627f4510a27SMatt Roper if (crtc->primary->fb == fb) { 6285ef5f72fSDave Airlie /* should turn off the crtc */ 6295ef5f72fSDave Airlie memset(&set, 0, sizeof(struct drm_mode_set)); 6305ef5f72fSDave Airlie set.crtc = crtc; 6315ef5f72fSDave Airlie set.fb = NULL; 6322d13b679SDaniel Vetter ret = drm_mode_set_config_internal(&set); 6335ef5f72fSDave Airlie if (ret) 6345ef5f72fSDave Airlie DRM_ERROR("failed to reset crtc %p when fb was deleted\n", crtc); 6355ef5f72fSDave Airlie } 636f453ba04SDave Airlie } 637f453ba04SDave Airlie 6388cf5c917SJesse Barnes list_for_each_entry(plane, &dev->mode_config.plane_list, head) { 6399125e618SVille Syrjälä if (plane->fb == fb) 6409125e618SVille Syrjälä drm_plane_force_disable(plane); 6418cf5c917SJesse Barnes } 642b62584e3SDaniel Vetter drm_modeset_unlock_all(dev); 643b62584e3SDaniel Vetter } 6448cf5c917SJesse Barnes 645f7eff60eSRob Clark drm_framebuffer_unreference(fb); 646f453ba04SDave Airlie } 647f7eff60eSRob Clark EXPORT_SYMBOL(drm_framebuffer_remove); 648f453ba04SDave Airlie 64951fd371bSRob Clark DEFINE_WW_CLASS(crtc_ww_class); 65051fd371bSRob Clark 651f453ba04SDave Airlie /** 652e13161afSMatt Roper * drm_crtc_init_with_planes - Initialise a new CRTC object with 653e13161afSMatt Roper * specified primary and cursor planes. 654f453ba04SDave Airlie * @dev: DRM device 655f453ba04SDave Airlie * @crtc: CRTC object to init 656e13161afSMatt Roper * @primary: Primary plane for CRTC 657e13161afSMatt Roper * @cursor: Cursor plane for CRTC 658f453ba04SDave Airlie * @funcs: callbacks for the new CRTC 659f453ba04SDave Airlie * 660ad6f5c34SVille Syrjälä * Inits a new object created as base part of a driver crtc object. 6616bfc56aaSVille Syrjälä * 662c8e32cc1SDaniel Vetter * Returns: 6636bfc56aaSVille Syrjälä * Zero on success, error code on failure. 664f453ba04SDave Airlie */ 665e13161afSMatt Roper int drm_crtc_init_with_planes(struct drm_device *dev, struct drm_crtc *crtc, 666e13161afSMatt Roper struct drm_plane *primary, 667fc1d3e44SMatt Roper struct drm_plane *cursor, 668f453ba04SDave Airlie const struct drm_crtc_funcs *funcs) 669f453ba04SDave Airlie { 67051fd371bSRob Clark struct drm_mode_config *config = &dev->mode_config; 6716bfc56aaSVille Syrjälä int ret; 6726bfc56aaSVille Syrjälä 673f453ba04SDave Airlie crtc->dev = dev; 674f453ba04SDave Airlie crtc->funcs = funcs; 6757c80e128SRob Clark crtc->invert_dimensions = false; 676f453ba04SDave Airlie 67751fd371bSRob Clark drm_modeset_lock_init(&crtc->mutex); 6786bfc56aaSVille Syrjälä ret = drm_mode_object_get(dev, &crtc->base, DRM_MODE_OBJECT_CRTC); 6796bfc56aaSVille Syrjälä if (ret) 680baf698b0SDaniel Vetter return ret; 681f453ba04SDave Airlie 682bffd9de0SPaulo Zanoni crtc->base.properties = &crtc->properties; 683bffd9de0SPaulo Zanoni 68451fd371bSRob Clark list_add_tail(&crtc->head, &config->crtc_list); 68551fd371bSRob Clark config->num_crtc++; 6866bfc56aaSVille Syrjälä 687e13161afSMatt Roper crtc->primary = primary; 688fc1d3e44SMatt Roper crtc->cursor = cursor; 689e13161afSMatt Roper if (primary) 690e13161afSMatt Roper primary->possible_crtcs = 1 << drm_crtc_index(crtc); 691fc1d3e44SMatt Roper if (cursor) 692fc1d3e44SMatt Roper cursor->possible_crtcs = 1 << drm_crtc_index(crtc); 693e13161afSMatt Roper 694eab3bbefSDaniel Vetter if (drm_core_check_feature(dev, DRIVER_ATOMIC)) { 695eab3bbefSDaniel Vetter drm_object_attach_property(&crtc->base, config->prop_active, 0); 696eab3bbefSDaniel Vetter } 697eab3bbefSDaniel Vetter 698baf698b0SDaniel Vetter return 0; 699f453ba04SDave Airlie } 700e13161afSMatt Roper EXPORT_SYMBOL(drm_crtc_init_with_planes); 701f453ba04SDave Airlie 702f453ba04SDave Airlie /** 703ad6f5c34SVille Syrjälä * drm_crtc_cleanup - Clean up the core crtc usage 704f453ba04SDave Airlie * @crtc: CRTC to cleanup 705f453ba04SDave Airlie * 706ad6f5c34SVille Syrjälä * This function cleans up @crtc and removes it from the DRM mode setting 707ad6f5c34SVille Syrjälä * core. Note that the function does *not* free the crtc structure itself, 708ad6f5c34SVille Syrjälä * this is the responsibility of the caller. 709f453ba04SDave Airlie */ 710f453ba04SDave Airlie void drm_crtc_cleanup(struct drm_crtc *crtc) 711f453ba04SDave Airlie { 712f453ba04SDave Airlie struct drm_device *dev = crtc->dev; 713f453ba04SDave Airlie 714f453ba04SDave Airlie kfree(crtc->gamma_store); 715f453ba04SDave Airlie crtc->gamma_store = NULL; 716f453ba04SDave Airlie 71751fd371bSRob Clark drm_modeset_lock_fini(&crtc->mutex); 71851fd371bSRob Clark 719f453ba04SDave Airlie drm_mode_object_put(dev, &crtc->base); 720f453ba04SDave Airlie list_del(&crtc->head); 721f453ba04SDave Airlie dev->mode_config.num_crtc--; 7223009c037SThierry Reding 7233009c037SThierry Reding WARN_ON(crtc->state && !crtc->funcs->atomic_destroy_state); 7243009c037SThierry Reding if (crtc->state && crtc->funcs->atomic_destroy_state) 7253009c037SThierry Reding crtc->funcs->atomic_destroy_state(crtc, crtc->state); 726a18c0af1SThierry Reding 727a18c0af1SThierry Reding memset(crtc, 0, sizeof(*crtc)); 728f453ba04SDave Airlie } 729f453ba04SDave Airlie EXPORT_SYMBOL(drm_crtc_cleanup); 730f453ba04SDave Airlie 731f453ba04SDave Airlie /** 732db5f7a6eSRussell King * drm_crtc_index - find the index of a registered CRTC 733db5f7a6eSRussell King * @crtc: CRTC to find index for 734db5f7a6eSRussell King * 735db5f7a6eSRussell King * Given a registered CRTC, return the index of that CRTC within a DRM 736db5f7a6eSRussell King * device's list of CRTCs. 737db5f7a6eSRussell King */ 738db5f7a6eSRussell King unsigned int drm_crtc_index(struct drm_crtc *crtc) 739db5f7a6eSRussell King { 740db5f7a6eSRussell King unsigned int index = 0; 741db5f7a6eSRussell King struct drm_crtc *tmp; 742db5f7a6eSRussell King 743db5f7a6eSRussell King list_for_each_entry(tmp, &crtc->dev->mode_config.crtc_list, head) { 744db5f7a6eSRussell King if (tmp == crtc) 745db5f7a6eSRussell King return index; 746db5f7a6eSRussell King 747db5f7a6eSRussell King index++; 748db5f7a6eSRussell King } 749db5f7a6eSRussell King 750db5f7a6eSRussell King BUG(); 751db5f7a6eSRussell King } 752db5f7a6eSRussell King EXPORT_SYMBOL(drm_crtc_index); 753db5f7a6eSRussell King 75486f422d5SLespiau, Damien /* 755f453ba04SDave Airlie * drm_mode_remove - remove and free a mode 756f453ba04SDave Airlie * @connector: connector list to modify 757f453ba04SDave Airlie * @mode: mode to remove 758f453ba04SDave Airlie * 759f453ba04SDave Airlie * Remove @mode from @connector's mode list, then free it. 760f453ba04SDave Airlie */ 76186f422d5SLespiau, Damien static void drm_mode_remove(struct drm_connector *connector, 762f453ba04SDave Airlie struct drm_display_mode *mode) 763f453ba04SDave Airlie { 764f453ba04SDave Airlie list_del(&mode->head); 765554f1d78SSascha Hauer drm_mode_destroy(connector->dev, mode); 766f453ba04SDave Airlie } 767f453ba04SDave Airlie 768f453ba04SDave Airlie /** 769b5571e9dSBoris Brezillon * drm_display_info_set_bus_formats - set the supported bus formats 770b5571e9dSBoris Brezillon * @info: display info to store bus formats in 771e37bfa1aSBoris Brezillon * @formats: array containing the supported bus formats 772e37bfa1aSBoris Brezillon * @num_formats: the number of entries in the fmts array 773b5571e9dSBoris Brezillon * 774b5571e9dSBoris Brezillon * Store the supported bus formats in display info structure. 775b5571e9dSBoris Brezillon * See MEDIA_BUS_FMT_* definitions in include/uapi/linux/media-bus-format.h for 776b5571e9dSBoris Brezillon * a full list of available formats. 777b5571e9dSBoris Brezillon */ 778b5571e9dSBoris Brezillon int drm_display_info_set_bus_formats(struct drm_display_info *info, 779b5571e9dSBoris Brezillon const u32 *formats, 780b5571e9dSBoris Brezillon unsigned int num_formats) 781b5571e9dSBoris Brezillon { 782b5571e9dSBoris Brezillon u32 *fmts = NULL; 783b5571e9dSBoris Brezillon 784b5571e9dSBoris Brezillon if (!formats && num_formats) 785b5571e9dSBoris Brezillon return -EINVAL; 786b5571e9dSBoris Brezillon 787b5571e9dSBoris Brezillon if (formats && num_formats) { 788b5571e9dSBoris Brezillon fmts = kmemdup(formats, sizeof(*formats) * num_formats, 789b5571e9dSBoris Brezillon GFP_KERNEL); 790944579c5SDan Carpenter if (!fmts) 791b5571e9dSBoris Brezillon return -ENOMEM; 792b5571e9dSBoris Brezillon } 793b5571e9dSBoris Brezillon 794b5571e9dSBoris Brezillon kfree(info->bus_formats); 795b5571e9dSBoris Brezillon info->bus_formats = fmts; 796b5571e9dSBoris Brezillon info->num_bus_formats = num_formats; 797b5571e9dSBoris Brezillon 798b5571e9dSBoris Brezillon return 0; 799b5571e9dSBoris Brezillon } 800b5571e9dSBoris Brezillon EXPORT_SYMBOL(drm_display_info_set_bus_formats); 801b5571e9dSBoris Brezillon 802b5571e9dSBoris Brezillon /** 803eaf99c74SChris Wilson * drm_connector_get_cmdline_mode - reads the user's cmdline mode 804eaf99c74SChris Wilson * @connector: connector to quwery 805eaf99c74SChris Wilson * 806eaf99c74SChris Wilson * The kernel supports per-connector configration of its consoles through 807eaf99c74SChris Wilson * use of the video= parameter. This function parses that option and 808eaf99c74SChris Wilson * extracts the user's specified mode (or enable/disable status) for a 809eaf99c74SChris Wilson * particular connector. This is typically only used during the early fbdev 810eaf99c74SChris Wilson * setup. 811eaf99c74SChris Wilson */ 812eaf99c74SChris Wilson static void drm_connector_get_cmdline_mode(struct drm_connector *connector) 813eaf99c74SChris Wilson { 814eaf99c74SChris Wilson struct drm_cmdline_mode *mode = &connector->cmdline_mode; 815eaf99c74SChris Wilson char *option = NULL; 816eaf99c74SChris Wilson 817eaf99c74SChris Wilson if (fb_get_options(connector->name, &option)) 818eaf99c74SChris Wilson return; 819eaf99c74SChris Wilson 820eaf99c74SChris Wilson if (!drm_mode_parse_command_line_for_connector(option, 821eaf99c74SChris Wilson connector, 822eaf99c74SChris Wilson mode)) 823eaf99c74SChris Wilson return; 824eaf99c74SChris Wilson 825eaf99c74SChris Wilson if (mode->force) { 826eaf99c74SChris Wilson const char *s; 827eaf99c74SChris Wilson 828eaf99c74SChris Wilson switch (mode->force) { 829eaf99c74SChris Wilson case DRM_FORCE_OFF: 830eaf99c74SChris Wilson s = "OFF"; 831eaf99c74SChris Wilson break; 832eaf99c74SChris Wilson case DRM_FORCE_ON_DIGITAL: 833eaf99c74SChris Wilson s = "ON - dig"; 834eaf99c74SChris Wilson break; 835eaf99c74SChris Wilson default: 836eaf99c74SChris Wilson case DRM_FORCE_ON: 837eaf99c74SChris Wilson s = "ON"; 838eaf99c74SChris Wilson break; 839eaf99c74SChris Wilson } 840eaf99c74SChris Wilson 841eaf99c74SChris Wilson DRM_INFO("forcing %s connector %s\n", connector->name, s); 842eaf99c74SChris Wilson connector->force = mode->force; 843eaf99c74SChris Wilson } 844eaf99c74SChris Wilson 845eaf99c74SChris Wilson DRM_DEBUG_KMS("cmdline mode for connector %s %dx%d@%dHz%s%s%s\n", 846eaf99c74SChris Wilson connector->name, 847eaf99c74SChris Wilson mode->xres, mode->yres, 848eaf99c74SChris Wilson mode->refresh_specified ? mode->refresh : 60, 849eaf99c74SChris Wilson mode->rb ? " reduced blanking" : "", 850eaf99c74SChris Wilson mode->margins ? " with margins" : "", 851eaf99c74SChris Wilson mode->interlace ? " interlaced" : ""); 852eaf99c74SChris Wilson } 853eaf99c74SChris Wilson 854eaf99c74SChris Wilson /** 855f453ba04SDave Airlie * drm_connector_init - Init a preallocated connector 856f453ba04SDave Airlie * @dev: DRM device 857f453ba04SDave Airlie * @connector: the connector to init 858f453ba04SDave Airlie * @funcs: callbacks for this connector 859065a50edSDaniel Vetter * @connector_type: user visible type of the connector 860f453ba04SDave Airlie * 861f453ba04SDave Airlie * Initialises a preallocated connector. Connectors should be 862f453ba04SDave Airlie * subclassed as part of driver connector objects. 8636bfc56aaSVille Syrjälä * 864c8e32cc1SDaniel Vetter * Returns: 8656bfc56aaSVille Syrjälä * Zero on success, error code on failure. 866f453ba04SDave Airlie */ 8676bfc56aaSVille Syrjälä int drm_connector_init(struct drm_device *dev, 868f453ba04SDave Airlie struct drm_connector *connector, 869f453ba04SDave Airlie const struct drm_connector_funcs *funcs, 870f453ba04SDave Airlie int connector_type) 871f453ba04SDave Airlie { 872ae16c597SRob Clark struct drm_mode_config *config = &dev->mode_config; 8736bfc56aaSVille Syrjälä int ret; 874b21e3afeSIlia Mirkin struct ida *connector_ida = 875b21e3afeSIlia Mirkin &drm_connector_enum_list[connector_type].ida; 8766bfc56aaSVille Syrjälä 87784849903SDaniel Vetter drm_modeset_lock_all(dev); 878f453ba04SDave Airlie 8792ee39452SDave Airlie ret = drm_mode_object_get_reg(dev, &connector->base, DRM_MODE_OBJECT_CONNECTOR, false); 8806bfc56aaSVille Syrjälä if (ret) 8812abdd313SJani Nikula goto out_unlock; 8826bfc56aaSVille Syrjälä 8837e3bdf4aSPaulo Zanoni connector->base.properties = &connector->properties; 884f453ba04SDave Airlie connector->dev = dev; 885f453ba04SDave Airlie connector->funcs = funcs; 886f453ba04SDave Airlie connector->connector_type = connector_type; 887f453ba04SDave Airlie connector->connector_type_id = 888b21e3afeSIlia Mirkin ida_simple_get(connector_ida, 1, 0, GFP_KERNEL); 889b21e3afeSIlia Mirkin if (connector->connector_type_id < 0) { 890b21e3afeSIlia Mirkin ret = connector->connector_type_id; 8912abdd313SJani Nikula goto out_put; 892b21e3afeSIlia Mirkin } 8932abdd313SJani Nikula connector->name = 8942abdd313SJani Nikula kasprintf(GFP_KERNEL, "%s-%d", 8952abdd313SJani Nikula drm_connector_enum_list[connector_type].name, 8962abdd313SJani Nikula connector->connector_type_id); 8972abdd313SJani Nikula if (!connector->name) { 8982abdd313SJani Nikula ret = -ENOMEM; 8992abdd313SJani Nikula goto out_put; 9002abdd313SJani Nikula } 9012abdd313SJani Nikula 902f453ba04SDave Airlie INIT_LIST_HEAD(&connector->probed_modes); 903f453ba04SDave Airlie INIT_LIST_HEAD(&connector->modes); 904f453ba04SDave Airlie connector->edid_blob_ptr = NULL; 9055e2cb2f6SDaniel Vetter connector->status = connector_status_unknown; 906f453ba04SDave Airlie 907eaf99c74SChris Wilson drm_connector_get_cmdline_mode(connector); 908eaf99c74SChris Wilson 909c7eb76f4SDaniel Vetter /* We should add connectors at the end to avoid upsetting the connector 910c7eb76f4SDaniel Vetter * index too much. */ 911ae16c597SRob Clark list_add_tail(&connector->head, &config->connector_list); 912ae16c597SRob Clark config->num_connector++; 913f453ba04SDave Airlie 914a7331e5cSThomas Hellstrom if (connector_type != DRM_MODE_CONNECTOR_VIRTUAL) 91558495563SRob Clark drm_object_attach_property(&connector->base, 916ae16c597SRob Clark config->edid_property, 917a7331e5cSThomas Hellstrom 0); 918f453ba04SDave Airlie 91958495563SRob Clark drm_object_attach_property(&connector->base, 920ae16c597SRob Clark config->dpms_property, 0); 921ae16c597SRob Clark 922ae16c597SRob Clark if (drm_core_check_feature(dev, DRIVER_ATOMIC)) { 923ae16c597SRob Clark drm_object_attach_property(&connector->base, config->prop_crtc_id, 0); 924ae16c597SRob Clark } 925f453ba04SDave Airlie 92630f65707SThomas Wood connector->debugfs_entry = NULL; 92730f65707SThomas Wood 9282abdd313SJani Nikula out_put: 9292abdd313SJani Nikula if (ret) 9302abdd313SJani Nikula drm_mode_object_put(dev, &connector->base); 9312abdd313SJani Nikula 9322abdd313SJani Nikula out_unlock: 93384849903SDaniel Vetter drm_modeset_unlock_all(dev); 9346bfc56aaSVille Syrjälä 9356bfc56aaSVille Syrjälä return ret; 936f453ba04SDave Airlie } 937f453ba04SDave Airlie EXPORT_SYMBOL(drm_connector_init); 938f453ba04SDave Airlie 939f453ba04SDave Airlie /** 940f453ba04SDave Airlie * drm_connector_cleanup - cleans up an initialised connector 941f453ba04SDave Airlie * @connector: connector to cleanup 942f453ba04SDave Airlie * 943f453ba04SDave Airlie * Cleans up the connector but doesn't free the object. 944f453ba04SDave Airlie */ 945f453ba04SDave Airlie void drm_connector_cleanup(struct drm_connector *connector) 946f453ba04SDave Airlie { 947f453ba04SDave Airlie struct drm_device *dev = connector->dev; 948f453ba04SDave Airlie struct drm_display_mode *mode, *t; 949f453ba04SDave Airlie 95040d9b043SDave Airlie if (connector->tile_group) { 95140d9b043SDave Airlie drm_mode_put_tile_group(dev, connector->tile_group); 95240d9b043SDave Airlie connector->tile_group = NULL; 95340d9b043SDave Airlie } 95440d9b043SDave Airlie 955f453ba04SDave Airlie list_for_each_entry_safe(mode, t, &connector->probed_modes, head) 956f453ba04SDave Airlie drm_mode_remove(connector, mode); 957f453ba04SDave Airlie 958f453ba04SDave Airlie list_for_each_entry_safe(mode, t, &connector->modes, head) 959f453ba04SDave Airlie drm_mode_remove(connector, mode); 960f453ba04SDave Airlie 961b21e3afeSIlia Mirkin ida_remove(&drm_connector_enum_list[connector->connector_type].ida, 962b21e3afeSIlia Mirkin connector->connector_type_id); 963b21e3afeSIlia Mirkin 964b5571e9dSBoris Brezillon kfree(connector->display_info.bus_formats); 965f453ba04SDave Airlie drm_mode_object_put(dev, &connector->base); 9662abdd313SJani Nikula kfree(connector->name); 9672abdd313SJani Nikula connector->name = NULL; 968f453ba04SDave Airlie list_del(&connector->head); 9696380c509SJoonyoung Shim dev->mode_config.num_connector--; 9703009c037SThierry Reding 9713009c037SThierry Reding WARN_ON(connector->state && !connector->funcs->atomic_destroy_state); 9723009c037SThierry Reding if (connector->state && connector->funcs->atomic_destroy_state) 9733009c037SThierry Reding connector->funcs->atomic_destroy_state(connector, 9743009c037SThierry Reding connector->state); 975a18c0af1SThierry Reding 976a18c0af1SThierry Reding memset(connector, 0, sizeof(*connector)); 977f453ba04SDave Airlie } 978f453ba04SDave Airlie EXPORT_SYMBOL(drm_connector_cleanup); 979f453ba04SDave Airlie 980c8e32cc1SDaniel Vetter /** 98110f637bfSDaniel Vetter * drm_connector_index - find the index of a registered connector 98210f637bfSDaniel Vetter * @connector: connector to find index for 98310f637bfSDaniel Vetter * 98410f637bfSDaniel Vetter * Given a registered connector, return the index of that connector within a DRM 98510f637bfSDaniel Vetter * device's list of connectors. 98610f637bfSDaniel Vetter */ 98710f637bfSDaniel Vetter unsigned int drm_connector_index(struct drm_connector *connector) 98810f637bfSDaniel Vetter { 98910f637bfSDaniel Vetter unsigned int index = 0; 99010f637bfSDaniel Vetter struct drm_connector *tmp; 991c7eb76f4SDaniel Vetter struct drm_mode_config *config = &connector->dev->mode_config; 992c7eb76f4SDaniel Vetter 993c7eb76f4SDaniel Vetter WARN_ON(!drm_modeset_is_locked(&config->connection_mutex)); 99410f637bfSDaniel Vetter 99510f637bfSDaniel Vetter list_for_each_entry(tmp, &connector->dev->mode_config.connector_list, head) { 99610f637bfSDaniel Vetter if (tmp == connector) 99710f637bfSDaniel Vetter return index; 99810f637bfSDaniel Vetter 99910f637bfSDaniel Vetter index++; 100010f637bfSDaniel Vetter } 100110f637bfSDaniel Vetter 100210f637bfSDaniel Vetter BUG(); 100310f637bfSDaniel Vetter } 100410f637bfSDaniel Vetter EXPORT_SYMBOL(drm_connector_index); 100510f637bfSDaniel Vetter 100610f637bfSDaniel Vetter /** 100734ea3d38SThomas Wood * drm_connector_register - register a connector 100834ea3d38SThomas Wood * @connector: the connector to register 100934ea3d38SThomas Wood * 101034ea3d38SThomas Wood * Register userspace interfaces for a connector 101134ea3d38SThomas Wood * 101234ea3d38SThomas Wood * Returns: 101334ea3d38SThomas Wood * Zero on success, error code on failure. 101434ea3d38SThomas Wood */ 101534ea3d38SThomas Wood int drm_connector_register(struct drm_connector *connector) 101634ea3d38SThomas Wood { 101730f65707SThomas Wood int ret; 101830f65707SThomas Wood 10192ee39452SDave Airlie drm_mode_object_register(connector->dev, &connector->base); 10202ee39452SDave Airlie 102130f65707SThomas Wood ret = drm_sysfs_connector_add(connector); 102230f65707SThomas Wood if (ret) 102330f65707SThomas Wood return ret; 102430f65707SThomas Wood 102530f65707SThomas Wood ret = drm_debugfs_connector_add(connector); 102630f65707SThomas Wood if (ret) { 102730f65707SThomas Wood drm_sysfs_connector_remove(connector); 102830f65707SThomas Wood return ret; 102930f65707SThomas Wood } 103030f65707SThomas Wood 103130f65707SThomas Wood return 0; 103234ea3d38SThomas Wood } 103334ea3d38SThomas Wood EXPORT_SYMBOL(drm_connector_register); 103434ea3d38SThomas Wood 103534ea3d38SThomas Wood /** 103634ea3d38SThomas Wood * drm_connector_unregister - unregister a connector 103734ea3d38SThomas Wood * @connector: the connector to unregister 103834ea3d38SThomas Wood * 103934ea3d38SThomas Wood * Unregister userspace interfaces for a connector 104034ea3d38SThomas Wood */ 104134ea3d38SThomas Wood void drm_connector_unregister(struct drm_connector *connector) 104234ea3d38SThomas Wood { 104334ea3d38SThomas Wood drm_sysfs_connector_remove(connector); 104430f65707SThomas Wood drm_debugfs_connector_remove(connector); 104534ea3d38SThomas Wood } 104634ea3d38SThomas Wood EXPORT_SYMBOL(drm_connector_unregister); 104734ea3d38SThomas Wood 104834ea3d38SThomas Wood 104934ea3d38SThomas Wood /** 1050c8e32cc1SDaniel Vetter * drm_connector_unplug_all - unregister connector userspace interfaces 1051c8e32cc1SDaniel Vetter * @dev: drm device 1052c8e32cc1SDaniel Vetter * 1053c8e32cc1SDaniel Vetter * This function unregisters all connector userspace interfaces in sysfs. Should 1054c8e32cc1SDaniel Vetter * be call when the device is disconnected, e.g. from an usb driver's 1055c8e32cc1SDaniel Vetter * ->disconnect callback. 1056c8e32cc1SDaniel Vetter */ 1057cbc7e221SDave Airlie void drm_connector_unplug_all(struct drm_device *dev) 1058cbc7e221SDave Airlie { 1059cbc7e221SDave Airlie struct drm_connector *connector; 1060cbc7e221SDave Airlie 1061cbc7e221SDave Airlie /* taking the mode config mutex ends up in a clash with sysfs */ 1062cbc7e221SDave Airlie list_for_each_entry(connector, &dev->mode_config.connector_list, head) 106334ea3d38SThomas Wood drm_connector_unregister(connector); 1064cbc7e221SDave Airlie 1065cbc7e221SDave Airlie } 1066cbc7e221SDave Airlie EXPORT_SYMBOL(drm_connector_unplug_all); 1067cbc7e221SDave Airlie 1068c8e32cc1SDaniel Vetter /** 1069c8e32cc1SDaniel Vetter * drm_encoder_init - Init a preallocated encoder 1070c8e32cc1SDaniel Vetter * @dev: drm device 1071c8e32cc1SDaniel Vetter * @encoder: the encoder to init 1072c8e32cc1SDaniel Vetter * @funcs: callbacks for this encoder 1073c8e32cc1SDaniel Vetter * @encoder_type: user visible type of the encoder 1074c8e32cc1SDaniel Vetter * 1075c8e32cc1SDaniel Vetter * Initialises a preallocated encoder. Encoder should be 1076c8e32cc1SDaniel Vetter * subclassed as part of driver encoder objects. 1077c8e32cc1SDaniel Vetter * 1078c8e32cc1SDaniel Vetter * Returns: 1079c8e32cc1SDaniel Vetter * Zero on success, error code on failure. 1080c8e32cc1SDaniel Vetter */ 10816bfc56aaSVille Syrjälä int drm_encoder_init(struct drm_device *dev, 1082f453ba04SDave Airlie struct drm_encoder *encoder, 1083f453ba04SDave Airlie const struct drm_encoder_funcs *funcs, 1084f453ba04SDave Airlie int encoder_type) 1085f453ba04SDave Airlie { 10866bfc56aaSVille Syrjälä int ret; 10876bfc56aaSVille Syrjälä 108884849903SDaniel Vetter drm_modeset_lock_all(dev); 1089f453ba04SDave Airlie 10906bfc56aaSVille Syrjälä ret = drm_mode_object_get(dev, &encoder->base, DRM_MODE_OBJECT_ENCODER); 10916bfc56aaSVille Syrjälä if (ret) 1092e5748946SJani Nikula goto out_unlock; 1093f453ba04SDave Airlie 10946bfc56aaSVille Syrjälä encoder->dev = dev; 1095f453ba04SDave Airlie encoder->encoder_type = encoder_type; 1096f453ba04SDave Airlie encoder->funcs = funcs; 1097e5748946SJani Nikula encoder->name = kasprintf(GFP_KERNEL, "%s-%d", 1098e5748946SJani Nikula drm_encoder_enum_list[encoder_type].name, 1099e5748946SJani Nikula encoder->base.id); 1100e5748946SJani Nikula if (!encoder->name) { 1101e5748946SJani Nikula ret = -ENOMEM; 1102e5748946SJani Nikula goto out_put; 1103e5748946SJani Nikula } 1104f453ba04SDave Airlie 1105f453ba04SDave Airlie list_add_tail(&encoder->head, &dev->mode_config.encoder_list); 1106f453ba04SDave Airlie dev->mode_config.num_encoder++; 1107f453ba04SDave Airlie 1108e5748946SJani Nikula out_put: 1109e5748946SJani Nikula if (ret) 1110e5748946SJani Nikula drm_mode_object_put(dev, &encoder->base); 1111e5748946SJani Nikula 1112e5748946SJani Nikula out_unlock: 111384849903SDaniel Vetter drm_modeset_unlock_all(dev); 11146bfc56aaSVille Syrjälä 11156bfc56aaSVille Syrjälä return ret; 1116f453ba04SDave Airlie } 1117f453ba04SDave Airlie EXPORT_SYMBOL(drm_encoder_init); 1118f453ba04SDave Airlie 1119c8e32cc1SDaniel Vetter /** 1120c8e32cc1SDaniel Vetter * drm_encoder_cleanup - cleans up an initialised encoder 1121c8e32cc1SDaniel Vetter * @encoder: encoder to cleanup 1122c8e32cc1SDaniel Vetter * 1123c8e32cc1SDaniel Vetter * Cleans up the encoder but doesn't free the object. 1124c8e32cc1SDaniel Vetter */ 1125f453ba04SDave Airlie void drm_encoder_cleanup(struct drm_encoder *encoder) 1126f453ba04SDave Airlie { 1127f453ba04SDave Airlie struct drm_device *dev = encoder->dev; 11284dfd909fSThierry Reding 112984849903SDaniel Vetter drm_modeset_lock_all(dev); 1130f453ba04SDave Airlie drm_mode_object_put(dev, &encoder->base); 1131e5748946SJani Nikula kfree(encoder->name); 1132f453ba04SDave Airlie list_del(&encoder->head); 11336380c509SJoonyoung Shim dev->mode_config.num_encoder--; 113484849903SDaniel Vetter drm_modeset_unlock_all(dev); 1135a18c0af1SThierry Reding 1136a18c0af1SThierry Reding memset(encoder, 0, sizeof(*encoder)); 1137f453ba04SDave Airlie } 1138f453ba04SDave Airlie EXPORT_SYMBOL(drm_encoder_cleanup); 1139f453ba04SDave Airlie 114035f2c3aeSVille Syrjälä /** 1141dc415ff9SMatt Roper * drm_universal_plane_init - Initialize a new universal plane object 114235f2c3aeSVille Syrjälä * @dev: DRM device 114335f2c3aeSVille Syrjälä * @plane: plane object to init 114435f2c3aeSVille Syrjälä * @possible_crtcs: bitmask of possible CRTCs 114535f2c3aeSVille Syrjälä * @funcs: callbacks for the new plane 114635f2c3aeSVille Syrjälä * @formats: array of supported formats (%DRM_FORMAT_*) 114735f2c3aeSVille Syrjälä * @format_count: number of elements in @formats 1148dc415ff9SMatt Roper * @type: type of plane (overlay, primary, cursor) 114935f2c3aeSVille Syrjälä * 1150dc415ff9SMatt Roper * Initializes a plane object of type @type. 115135f2c3aeSVille Syrjälä * 1152c8e32cc1SDaniel Vetter * Returns: 115335f2c3aeSVille Syrjälä * Zero on success, error code on failure. 115435f2c3aeSVille Syrjälä */ 1155dc415ff9SMatt Roper int drm_universal_plane_init(struct drm_device *dev, struct drm_plane *plane, 11568cf5c917SJesse Barnes unsigned long possible_crtcs, 11578cf5c917SJesse Barnes const struct drm_plane_funcs *funcs, 11580a7eb243SRob Clark const uint32_t *formats, uint32_t format_count, 1159dc415ff9SMatt Roper enum drm_plane_type type) 11608cf5c917SJesse Barnes { 11616b4959f4SRob Clark struct drm_mode_config *config = &dev->mode_config; 11626bfc56aaSVille Syrjälä int ret; 11636bfc56aaSVille Syrjälä 11646bfc56aaSVille Syrjälä ret = drm_mode_object_get(dev, &plane->base, DRM_MODE_OBJECT_PLANE); 11656bfc56aaSVille Syrjälä if (ret) 1166baf698b0SDaniel Vetter return ret; 11676bfc56aaSVille Syrjälä 11684d02e2deSDaniel Vetter drm_modeset_lock_init(&plane->mutex); 11694d02e2deSDaniel Vetter 11704d93914aSRob Clark plane->base.properties = &plane->properties; 11718cf5c917SJesse Barnes plane->dev = dev; 11728cf5c917SJesse Barnes plane->funcs = funcs; 11732f6c5389SThierry Reding plane->format_types = kmalloc_array(format_count, sizeof(uint32_t), 11748cf5c917SJesse Barnes GFP_KERNEL); 11758cf5c917SJesse Barnes if (!plane->format_types) { 11768cf5c917SJesse Barnes DRM_DEBUG_KMS("out of memory when allocating plane\n"); 11778cf5c917SJesse Barnes drm_mode_object_put(dev, &plane->base); 1178baf698b0SDaniel Vetter return -ENOMEM; 11798cf5c917SJesse Barnes } 11808cf5c917SJesse Barnes 1181308e5bcbSJesse Barnes memcpy(plane->format_types, formats, format_count * sizeof(uint32_t)); 11828cf5c917SJesse Barnes plane->format_count = format_count; 11838cf5c917SJesse Barnes plane->possible_crtcs = possible_crtcs; 1184dc415ff9SMatt Roper plane->type = type; 11858cf5c917SJesse Barnes 11866b4959f4SRob Clark list_add_tail(&plane->head, &config->plane_list); 11876b4959f4SRob Clark config->num_total_plane++; 1188e27dde3eSMatt Roper if (plane->type == DRM_PLANE_TYPE_OVERLAY) 11896b4959f4SRob Clark config->num_overlay_plane++; 11908cf5c917SJesse Barnes 11919922ab5aSRob Clark drm_object_attach_property(&plane->base, 11926b4959f4SRob Clark config->plane_type_property, 11939922ab5aSRob Clark plane->type); 11949922ab5aSRob Clark 11956b4959f4SRob Clark if (drm_core_check_feature(dev, DRIVER_ATOMIC)) { 11966b4959f4SRob Clark drm_object_attach_property(&plane->base, config->prop_fb_id, 0); 11976b4959f4SRob Clark drm_object_attach_property(&plane->base, config->prop_crtc_id, 0); 11986b4959f4SRob Clark drm_object_attach_property(&plane->base, config->prop_crtc_x, 0); 11996b4959f4SRob Clark drm_object_attach_property(&plane->base, config->prop_crtc_y, 0); 12006b4959f4SRob Clark drm_object_attach_property(&plane->base, config->prop_crtc_w, 0); 12016b4959f4SRob Clark drm_object_attach_property(&plane->base, config->prop_crtc_h, 0); 12026b4959f4SRob Clark drm_object_attach_property(&plane->base, config->prop_src_x, 0); 12036b4959f4SRob Clark drm_object_attach_property(&plane->base, config->prop_src_y, 0); 12046b4959f4SRob Clark drm_object_attach_property(&plane->base, config->prop_src_w, 0); 12056b4959f4SRob Clark drm_object_attach_property(&plane->base, config->prop_src_h, 0); 12066b4959f4SRob Clark } 12076b4959f4SRob Clark 1208baf698b0SDaniel Vetter return 0; 12098cf5c917SJesse Barnes } 1210dc415ff9SMatt Roper EXPORT_SYMBOL(drm_universal_plane_init); 1211dc415ff9SMatt Roper 1212dc415ff9SMatt Roper /** 1213dc415ff9SMatt Roper * drm_plane_init - Initialize a legacy plane 1214dc415ff9SMatt Roper * @dev: DRM device 1215dc415ff9SMatt Roper * @plane: plane object to init 1216dc415ff9SMatt Roper * @possible_crtcs: bitmask of possible CRTCs 1217dc415ff9SMatt Roper * @funcs: callbacks for the new plane 1218dc415ff9SMatt Roper * @formats: array of supported formats (%DRM_FORMAT_*) 1219dc415ff9SMatt Roper * @format_count: number of elements in @formats 1220dc415ff9SMatt Roper * @is_primary: plane type (primary vs overlay) 1221dc415ff9SMatt Roper * 1222dc415ff9SMatt Roper * Legacy API to initialize a DRM plane. 1223dc415ff9SMatt Roper * 1224dc415ff9SMatt Roper * New drivers should call drm_universal_plane_init() instead. 1225dc415ff9SMatt Roper * 1226dc415ff9SMatt Roper * Returns: 1227dc415ff9SMatt Roper * Zero on success, error code on failure. 1228dc415ff9SMatt Roper */ 1229dc415ff9SMatt Roper int drm_plane_init(struct drm_device *dev, struct drm_plane *plane, 1230dc415ff9SMatt Roper unsigned long possible_crtcs, 1231dc415ff9SMatt Roper const struct drm_plane_funcs *funcs, 1232dc415ff9SMatt Roper const uint32_t *formats, uint32_t format_count, 1233dc415ff9SMatt Roper bool is_primary) 1234dc415ff9SMatt Roper { 1235dc415ff9SMatt Roper enum drm_plane_type type; 1236dc415ff9SMatt Roper 1237dc415ff9SMatt Roper type = is_primary ? DRM_PLANE_TYPE_PRIMARY : DRM_PLANE_TYPE_OVERLAY; 1238dc415ff9SMatt Roper return drm_universal_plane_init(dev, plane, possible_crtcs, funcs, 1239dc415ff9SMatt Roper formats, format_count, type); 1240dc415ff9SMatt Roper } 12418cf5c917SJesse Barnes EXPORT_SYMBOL(drm_plane_init); 12428cf5c917SJesse Barnes 124335f2c3aeSVille Syrjälä /** 124435f2c3aeSVille Syrjälä * drm_plane_cleanup - Clean up the core plane usage 124535f2c3aeSVille Syrjälä * @plane: plane to cleanup 124635f2c3aeSVille Syrjälä * 124735f2c3aeSVille Syrjälä * This function cleans up @plane and removes it from the DRM mode setting 124835f2c3aeSVille Syrjälä * core. Note that the function does *not* free the plane structure itself, 124935f2c3aeSVille Syrjälä * this is the responsibility of the caller. 125035f2c3aeSVille Syrjälä */ 12518cf5c917SJesse Barnes void drm_plane_cleanup(struct drm_plane *plane) 12528cf5c917SJesse Barnes { 12538cf5c917SJesse Barnes struct drm_device *dev = plane->dev; 12548cf5c917SJesse Barnes 125584849903SDaniel Vetter drm_modeset_lock_all(dev); 12568cf5c917SJesse Barnes kfree(plane->format_types); 12578cf5c917SJesse Barnes drm_mode_object_put(dev, &plane->base); 1258dc415ff9SMatt Roper 1259dc415ff9SMatt Roper BUG_ON(list_empty(&plane->head)); 1260dc415ff9SMatt Roper 12618cf5c917SJesse Barnes list_del(&plane->head); 1262e27dde3eSMatt Roper dev->mode_config.num_total_plane--; 1263e27dde3eSMatt Roper if (plane->type == DRM_PLANE_TYPE_OVERLAY) 1264e27dde3eSMatt Roper dev->mode_config.num_overlay_plane--; 126584849903SDaniel Vetter drm_modeset_unlock_all(dev); 12663009c037SThierry Reding 12673009c037SThierry Reding WARN_ON(plane->state && !plane->funcs->atomic_destroy_state); 12683009c037SThierry Reding if (plane->state && plane->funcs->atomic_destroy_state) 12693009c037SThierry Reding plane->funcs->atomic_destroy_state(plane, plane->state); 1270a18c0af1SThierry Reding 1271a18c0af1SThierry Reding memset(plane, 0, sizeof(*plane)); 12728cf5c917SJesse Barnes } 12738cf5c917SJesse Barnes EXPORT_SYMBOL(drm_plane_cleanup); 12748cf5c917SJesse Barnes 127535f2c3aeSVille Syrjälä /** 127610f637bfSDaniel Vetter * drm_plane_index - find the index of a registered plane 127710f637bfSDaniel Vetter * @plane: plane to find index for 127810f637bfSDaniel Vetter * 127910f637bfSDaniel Vetter * Given a registered plane, return the index of that CRTC within a DRM 128010f637bfSDaniel Vetter * device's list of planes. 128110f637bfSDaniel Vetter */ 128210f637bfSDaniel Vetter unsigned int drm_plane_index(struct drm_plane *plane) 128310f637bfSDaniel Vetter { 128410f637bfSDaniel Vetter unsigned int index = 0; 128510f637bfSDaniel Vetter struct drm_plane *tmp; 128610f637bfSDaniel Vetter 128710f637bfSDaniel Vetter list_for_each_entry(tmp, &plane->dev->mode_config.plane_list, head) { 128810f637bfSDaniel Vetter if (tmp == plane) 128910f637bfSDaniel Vetter return index; 129010f637bfSDaniel Vetter 129110f637bfSDaniel Vetter index++; 129210f637bfSDaniel Vetter } 129310f637bfSDaniel Vetter 129410f637bfSDaniel Vetter BUG(); 129510f637bfSDaniel Vetter } 129610f637bfSDaniel Vetter EXPORT_SYMBOL(drm_plane_index); 129710f637bfSDaniel Vetter 129810f637bfSDaniel Vetter /** 129935f2c3aeSVille Syrjälä * drm_plane_force_disable - Forcibly disable a plane 130035f2c3aeSVille Syrjälä * @plane: plane to disable 130135f2c3aeSVille Syrjälä * 130235f2c3aeSVille Syrjälä * Forces the plane to be disabled. 130335f2c3aeSVille Syrjälä * 130435f2c3aeSVille Syrjälä * Used when the plane's current framebuffer is destroyed, 130535f2c3aeSVille Syrjälä * and when restoring fbdev mode. 130635f2c3aeSVille Syrjälä */ 13079125e618SVille Syrjälä void drm_plane_force_disable(struct drm_plane *plane) 13089125e618SVille Syrjälä { 13099125e618SVille Syrjälä int ret; 13109125e618SVille Syrjälä 13113d30a59bSDaniel Vetter if (!plane->fb) 13129125e618SVille Syrjälä return; 13139125e618SVille Syrjälä 13143d30a59bSDaniel Vetter plane->old_fb = plane->fb; 13159125e618SVille Syrjälä ret = plane->funcs->disable_plane(plane); 1316731cce48SDaniel Vetter if (ret) { 13179125e618SVille Syrjälä DRM_ERROR("failed to disable plane with busy fb\n"); 13183d30a59bSDaniel Vetter plane->old_fb = NULL; 1319731cce48SDaniel Vetter return; 1320731cce48SDaniel Vetter } 13219125e618SVille Syrjälä /* disconnect the plane from the fb and crtc: */ 13223d30a59bSDaniel Vetter __drm_framebuffer_unreference(plane->old_fb); 13233d30a59bSDaniel Vetter plane->old_fb = NULL; 13249125e618SVille Syrjälä plane->fb = NULL; 13259125e618SVille Syrjälä plane->crtc = NULL; 13269125e618SVille Syrjälä } 13279125e618SVille Syrjälä EXPORT_SYMBOL(drm_plane_force_disable); 13289125e618SVille Syrjälä 13296b4959f4SRob Clark static int drm_mode_create_standard_properties(struct drm_device *dev) 1330f453ba04SDave Airlie { 1331356af0e1SRob Clark struct drm_property *prop; 1332f453ba04SDave Airlie 1333f453ba04SDave Airlie /* 1334f453ba04SDave Airlie * Standard properties (apply to all connectors) 1335f453ba04SDave Airlie */ 1336356af0e1SRob Clark prop = drm_property_create(dev, DRM_MODE_PROP_BLOB | 1337f453ba04SDave Airlie DRM_MODE_PROP_IMMUTABLE, 1338f453ba04SDave Airlie "EDID", 0); 1339356af0e1SRob Clark if (!prop) 1340356af0e1SRob Clark return -ENOMEM; 1341356af0e1SRob Clark dev->mode_config.edid_property = prop; 1342f453ba04SDave Airlie 1343356af0e1SRob Clark prop = drm_property_create_enum(dev, 0, 13444a67d391SSascha Hauer "DPMS", drm_dpms_enum_list, 13454a67d391SSascha Hauer ARRAY_SIZE(drm_dpms_enum_list)); 1346356af0e1SRob Clark if (!prop) 1347356af0e1SRob Clark return -ENOMEM; 1348356af0e1SRob Clark dev->mode_config.dpms_property = prop; 1349f453ba04SDave Airlie 1350356af0e1SRob Clark prop = drm_property_create(dev, 135143aba7ebSDave Airlie DRM_MODE_PROP_BLOB | 135243aba7ebSDave Airlie DRM_MODE_PROP_IMMUTABLE, 135343aba7ebSDave Airlie "PATH", 0); 1354356af0e1SRob Clark if (!prop) 1355356af0e1SRob Clark return -ENOMEM; 1356356af0e1SRob Clark dev->mode_config.path_property = prop; 135743aba7ebSDave Airlie 1358356af0e1SRob Clark prop = drm_property_create(dev, 13596f134d7bSDave Airlie DRM_MODE_PROP_BLOB | 13606f134d7bSDave Airlie DRM_MODE_PROP_IMMUTABLE, 13616f134d7bSDave Airlie "TILE", 0); 1362356af0e1SRob Clark if (!prop) 1363356af0e1SRob Clark return -ENOMEM; 1364356af0e1SRob Clark dev->mode_config.tile_property = prop; 13656f134d7bSDave Airlie 13666b4959f4SRob Clark prop = drm_property_create_enum(dev, DRM_MODE_PROP_IMMUTABLE, 13679922ab5aSRob Clark "type", drm_plane_type_enum_list, 13689922ab5aSRob Clark ARRAY_SIZE(drm_plane_type_enum_list)); 13696b4959f4SRob Clark if (!prop) 13706b4959f4SRob Clark return -ENOMEM; 13716b4959f4SRob Clark dev->mode_config.plane_type_property = prop; 13726b4959f4SRob Clark 13736b4959f4SRob Clark prop = drm_property_create_range(dev, DRM_MODE_PROP_ATOMIC, 13746b4959f4SRob Clark "SRC_X", 0, UINT_MAX); 13756b4959f4SRob Clark if (!prop) 13766b4959f4SRob Clark return -ENOMEM; 13776b4959f4SRob Clark dev->mode_config.prop_src_x = prop; 13786b4959f4SRob Clark 13796b4959f4SRob Clark prop = drm_property_create_range(dev, DRM_MODE_PROP_ATOMIC, 13806b4959f4SRob Clark "SRC_Y", 0, UINT_MAX); 13816b4959f4SRob Clark if (!prop) 13826b4959f4SRob Clark return -ENOMEM; 13836b4959f4SRob Clark dev->mode_config.prop_src_y = prop; 13846b4959f4SRob Clark 13856b4959f4SRob Clark prop = drm_property_create_range(dev, DRM_MODE_PROP_ATOMIC, 13866b4959f4SRob Clark "SRC_W", 0, UINT_MAX); 13876b4959f4SRob Clark if (!prop) 13886b4959f4SRob Clark return -ENOMEM; 13896b4959f4SRob Clark dev->mode_config.prop_src_w = prop; 13906b4959f4SRob Clark 13916b4959f4SRob Clark prop = drm_property_create_range(dev, DRM_MODE_PROP_ATOMIC, 13926b4959f4SRob Clark "SRC_H", 0, UINT_MAX); 13936b4959f4SRob Clark if (!prop) 13946b4959f4SRob Clark return -ENOMEM; 13956b4959f4SRob Clark dev->mode_config.prop_src_h = prop; 13966b4959f4SRob Clark 13976b4959f4SRob Clark prop = drm_property_create_signed_range(dev, DRM_MODE_PROP_ATOMIC, 13986b4959f4SRob Clark "CRTC_X", INT_MIN, INT_MAX); 13996b4959f4SRob Clark if (!prop) 14006b4959f4SRob Clark return -ENOMEM; 14016b4959f4SRob Clark dev->mode_config.prop_crtc_x = prop; 14026b4959f4SRob Clark 14036b4959f4SRob Clark prop = drm_property_create_signed_range(dev, DRM_MODE_PROP_ATOMIC, 14046b4959f4SRob Clark "CRTC_Y", INT_MIN, INT_MAX); 14056b4959f4SRob Clark if (!prop) 14066b4959f4SRob Clark return -ENOMEM; 14076b4959f4SRob Clark dev->mode_config.prop_crtc_y = prop; 14086b4959f4SRob Clark 14096b4959f4SRob Clark prop = drm_property_create_range(dev, DRM_MODE_PROP_ATOMIC, 14106b4959f4SRob Clark "CRTC_W", 0, INT_MAX); 14116b4959f4SRob Clark if (!prop) 14126b4959f4SRob Clark return -ENOMEM; 14136b4959f4SRob Clark dev->mode_config.prop_crtc_w = prop; 14146b4959f4SRob Clark 14156b4959f4SRob Clark prop = drm_property_create_range(dev, DRM_MODE_PROP_ATOMIC, 14166b4959f4SRob Clark "CRTC_H", 0, INT_MAX); 14176b4959f4SRob Clark if (!prop) 14186b4959f4SRob Clark return -ENOMEM; 14196b4959f4SRob Clark dev->mode_config.prop_crtc_h = prop; 14206b4959f4SRob Clark 14216b4959f4SRob Clark prop = drm_property_create_object(dev, DRM_MODE_PROP_ATOMIC, 14226b4959f4SRob Clark "FB_ID", DRM_MODE_OBJECT_FB); 14236b4959f4SRob Clark if (!prop) 14246b4959f4SRob Clark return -ENOMEM; 14256b4959f4SRob Clark dev->mode_config.prop_fb_id = prop; 14266b4959f4SRob Clark 14276b4959f4SRob Clark prop = drm_property_create_object(dev, DRM_MODE_PROP_ATOMIC, 14286b4959f4SRob Clark "CRTC_ID", DRM_MODE_OBJECT_CRTC); 14296b4959f4SRob Clark if (!prop) 14306b4959f4SRob Clark return -ENOMEM; 14316b4959f4SRob Clark dev->mode_config.prop_crtc_id = prop; 14329922ab5aSRob Clark 1433eab3bbefSDaniel Vetter prop = drm_property_create_bool(dev, DRM_MODE_PROP_ATOMIC, 1434eab3bbefSDaniel Vetter "ACTIVE"); 1435eab3bbefSDaniel Vetter if (!prop) 1436eab3bbefSDaniel Vetter return -ENOMEM; 1437eab3bbefSDaniel Vetter dev->mode_config.prop_active = prop; 1438eab3bbefSDaniel Vetter 14399922ab5aSRob Clark return 0; 14409922ab5aSRob Clark } 14419922ab5aSRob Clark 1442f453ba04SDave Airlie /** 1443f453ba04SDave Airlie * drm_mode_create_dvi_i_properties - create DVI-I specific connector properties 1444f453ba04SDave Airlie * @dev: DRM device 1445f453ba04SDave Airlie * 1446f453ba04SDave Airlie * Called by a driver the first time a DVI-I connector is made. 1447f453ba04SDave Airlie */ 1448f453ba04SDave Airlie int drm_mode_create_dvi_i_properties(struct drm_device *dev) 1449f453ba04SDave Airlie { 1450f453ba04SDave Airlie struct drm_property *dvi_i_selector; 1451f453ba04SDave Airlie struct drm_property *dvi_i_subconnector; 1452f453ba04SDave Airlie 1453f453ba04SDave Airlie if (dev->mode_config.dvi_i_select_subconnector_property) 1454f453ba04SDave Airlie return 0; 1455f453ba04SDave Airlie 1456f453ba04SDave Airlie dvi_i_selector = 14574a67d391SSascha Hauer drm_property_create_enum(dev, 0, 1458f453ba04SDave Airlie "select subconnector", 14594a67d391SSascha Hauer drm_dvi_i_select_enum_list, 1460f453ba04SDave Airlie ARRAY_SIZE(drm_dvi_i_select_enum_list)); 1461f453ba04SDave Airlie dev->mode_config.dvi_i_select_subconnector_property = dvi_i_selector; 1462f453ba04SDave Airlie 14634a67d391SSascha Hauer dvi_i_subconnector = drm_property_create_enum(dev, DRM_MODE_PROP_IMMUTABLE, 1464f453ba04SDave Airlie "subconnector", 14654a67d391SSascha Hauer drm_dvi_i_subconnector_enum_list, 1466f453ba04SDave Airlie ARRAY_SIZE(drm_dvi_i_subconnector_enum_list)); 1467f453ba04SDave Airlie dev->mode_config.dvi_i_subconnector_property = dvi_i_subconnector; 1468f453ba04SDave Airlie 1469f453ba04SDave Airlie return 0; 1470f453ba04SDave Airlie } 1471f453ba04SDave Airlie EXPORT_SYMBOL(drm_mode_create_dvi_i_properties); 1472f453ba04SDave Airlie 1473f453ba04SDave Airlie /** 1474f453ba04SDave Airlie * drm_create_tv_properties - create TV specific connector properties 1475f453ba04SDave Airlie * @dev: DRM device 1476f453ba04SDave Airlie * @num_modes: number of different TV formats (modes) supported 1477f453ba04SDave Airlie * @modes: array of pointers to strings containing name of each format 1478f453ba04SDave Airlie * 1479f453ba04SDave Airlie * Called by a driver's TV initialization routine, this function creates 1480f453ba04SDave Airlie * the TV specific connector properties for a given device. Caller is 1481f453ba04SDave Airlie * responsible for allocating a list of format names and passing them to 1482f453ba04SDave Airlie * this routine. 1483f453ba04SDave Airlie */ 14842f763312SThierry Reding int drm_mode_create_tv_properties(struct drm_device *dev, 14852f763312SThierry Reding unsigned int num_modes, 1486f453ba04SDave Airlie char *modes[]) 1487f453ba04SDave Airlie { 1488f453ba04SDave Airlie struct drm_property *tv_selector; 1489f453ba04SDave Airlie struct drm_property *tv_subconnector; 14902f763312SThierry Reding unsigned int i; 1491f453ba04SDave Airlie 1492f453ba04SDave Airlie if (dev->mode_config.tv_select_subconnector_property) 1493f453ba04SDave Airlie return 0; 1494f453ba04SDave Airlie 1495f453ba04SDave Airlie /* 1496f453ba04SDave Airlie * Basic connector properties 1497f453ba04SDave Airlie */ 14984a67d391SSascha Hauer tv_selector = drm_property_create_enum(dev, 0, 1499f453ba04SDave Airlie "select subconnector", 15004a67d391SSascha Hauer drm_tv_select_enum_list, 1501f453ba04SDave Airlie ARRAY_SIZE(drm_tv_select_enum_list)); 1502f453ba04SDave Airlie dev->mode_config.tv_select_subconnector_property = tv_selector; 1503f453ba04SDave Airlie 1504f453ba04SDave Airlie tv_subconnector = 15054a67d391SSascha Hauer drm_property_create_enum(dev, DRM_MODE_PROP_IMMUTABLE, 15064a67d391SSascha Hauer "subconnector", 15074a67d391SSascha Hauer drm_tv_subconnector_enum_list, 1508f453ba04SDave Airlie ARRAY_SIZE(drm_tv_subconnector_enum_list)); 1509f453ba04SDave Airlie dev->mode_config.tv_subconnector_property = tv_subconnector; 1510f453ba04SDave Airlie 1511f453ba04SDave Airlie /* 1512f453ba04SDave Airlie * Other, TV specific properties: margins & TV modes. 1513f453ba04SDave Airlie */ 1514f453ba04SDave Airlie dev->mode_config.tv_left_margin_property = 1515d9bc3c02SSascha Hauer drm_property_create_range(dev, 0, "left margin", 0, 100); 1516f453ba04SDave Airlie 1517f453ba04SDave Airlie dev->mode_config.tv_right_margin_property = 1518d9bc3c02SSascha Hauer drm_property_create_range(dev, 0, "right margin", 0, 100); 1519f453ba04SDave Airlie 1520f453ba04SDave Airlie dev->mode_config.tv_top_margin_property = 1521d9bc3c02SSascha Hauer drm_property_create_range(dev, 0, "top margin", 0, 100); 1522f453ba04SDave Airlie 1523f453ba04SDave Airlie dev->mode_config.tv_bottom_margin_property = 1524d9bc3c02SSascha Hauer drm_property_create_range(dev, 0, "bottom margin", 0, 100); 1525f453ba04SDave Airlie 1526f453ba04SDave Airlie dev->mode_config.tv_mode_property = 1527f453ba04SDave Airlie drm_property_create(dev, DRM_MODE_PROP_ENUM, 1528f453ba04SDave Airlie "mode", num_modes); 1529f453ba04SDave Airlie for (i = 0; i < num_modes; i++) 1530f453ba04SDave Airlie drm_property_add_enum(dev->mode_config.tv_mode_property, i, 1531f453ba04SDave Airlie i, modes[i]); 1532f453ba04SDave Airlie 1533b6b7902eSFrancisco Jerez dev->mode_config.tv_brightness_property = 1534d9bc3c02SSascha Hauer drm_property_create_range(dev, 0, "brightness", 0, 100); 1535b6b7902eSFrancisco Jerez 1536b6b7902eSFrancisco Jerez dev->mode_config.tv_contrast_property = 1537d9bc3c02SSascha Hauer drm_property_create_range(dev, 0, "contrast", 0, 100); 1538b6b7902eSFrancisco Jerez 1539b6b7902eSFrancisco Jerez dev->mode_config.tv_flicker_reduction_property = 1540d9bc3c02SSascha Hauer drm_property_create_range(dev, 0, "flicker reduction", 0, 100); 1541b6b7902eSFrancisco Jerez 1542a75f0236SFrancisco Jerez dev->mode_config.tv_overscan_property = 1543d9bc3c02SSascha Hauer drm_property_create_range(dev, 0, "overscan", 0, 100); 1544a75f0236SFrancisco Jerez 1545a75f0236SFrancisco Jerez dev->mode_config.tv_saturation_property = 1546d9bc3c02SSascha Hauer drm_property_create_range(dev, 0, "saturation", 0, 100); 1547a75f0236SFrancisco Jerez 1548a75f0236SFrancisco Jerez dev->mode_config.tv_hue_property = 1549d9bc3c02SSascha Hauer drm_property_create_range(dev, 0, "hue", 0, 100); 1550a75f0236SFrancisco Jerez 1551f453ba04SDave Airlie return 0; 1552f453ba04SDave Airlie } 1553f453ba04SDave Airlie EXPORT_SYMBOL(drm_mode_create_tv_properties); 1554f453ba04SDave Airlie 1555f453ba04SDave Airlie /** 1556f453ba04SDave Airlie * drm_mode_create_scaling_mode_property - create scaling mode property 1557f453ba04SDave Airlie * @dev: DRM device 1558f453ba04SDave Airlie * 1559f453ba04SDave Airlie * Called by a driver the first time it's needed, must be attached to desired 1560f453ba04SDave Airlie * connectors. 1561f453ba04SDave Airlie */ 1562f453ba04SDave Airlie int drm_mode_create_scaling_mode_property(struct drm_device *dev) 1563f453ba04SDave Airlie { 1564f453ba04SDave Airlie struct drm_property *scaling_mode; 1565f453ba04SDave Airlie 1566f453ba04SDave Airlie if (dev->mode_config.scaling_mode_property) 1567f453ba04SDave Airlie return 0; 1568f453ba04SDave Airlie 1569f453ba04SDave Airlie scaling_mode = 15704a67d391SSascha Hauer drm_property_create_enum(dev, 0, "scaling mode", 15714a67d391SSascha Hauer drm_scaling_mode_enum_list, 1572f453ba04SDave Airlie ARRAY_SIZE(drm_scaling_mode_enum_list)); 1573f453ba04SDave Airlie 1574f453ba04SDave Airlie dev->mode_config.scaling_mode_property = scaling_mode; 1575f453ba04SDave Airlie 1576f453ba04SDave Airlie return 0; 1577f453ba04SDave Airlie } 1578f453ba04SDave Airlie EXPORT_SYMBOL(drm_mode_create_scaling_mode_property); 1579f453ba04SDave Airlie 1580f453ba04SDave Airlie /** 1581ff587e45SVandana Kannan * drm_mode_create_aspect_ratio_property - create aspect ratio property 1582ff587e45SVandana Kannan * @dev: DRM device 1583ff587e45SVandana Kannan * 1584ff587e45SVandana Kannan * Called by a driver the first time it's needed, must be attached to desired 1585ff587e45SVandana Kannan * connectors. 1586ff587e45SVandana Kannan * 1587ff587e45SVandana Kannan * Returns: 15881a498633SDaniel Vetter * Zero on success, negative errno on failure. 1589ff587e45SVandana Kannan */ 1590ff587e45SVandana Kannan int drm_mode_create_aspect_ratio_property(struct drm_device *dev) 1591ff587e45SVandana Kannan { 1592ff587e45SVandana Kannan if (dev->mode_config.aspect_ratio_property) 1593ff587e45SVandana Kannan return 0; 1594ff587e45SVandana Kannan 1595ff587e45SVandana Kannan dev->mode_config.aspect_ratio_property = 1596ff587e45SVandana Kannan drm_property_create_enum(dev, 0, "aspect ratio", 1597ff587e45SVandana Kannan drm_aspect_ratio_enum_list, 1598ff587e45SVandana Kannan ARRAY_SIZE(drm_aspect_ratio_enum_list)); 1599ff587e45SVandana Kannan 1600ff587e45SVandana Kannan if (dev->mode_config.aspect_ratio_property == NULL) 1601ff587e45SVandana Kannan return -ENOMEM; 1602ff587e45SVandana Kannan 1603ff587e45SVandana Kannan return 0; 1604ff587e45SVandana Kannan } 1605ff587e45SVandana Kannan EXPORT_SYMBOL(drm_mode_create_aspect_ratio_property); 1606ff587e45SVandana Kannan 1607ff587e45SVandana Kannan /** 1608884840aaSJakob Bornecrantz * drm_mode_create_dirty_property - create dirty property 1609884840aaSJakob Bornecrantz * @dev: DRM device 1610884840aaSJakob Bornecrantz * 1611884840aaSJakob Bornecrantz * Called by a driver the first time it's needed, must be attached to desired 1612884840aaSJakob Bornecrantz * connectors. 1613884840aaSJakob Bornecrantz */ 1614884840aaSJakob Bornecrantz int drm_mode_create_dirty_info_property(struct drm_device *dev) 1615884840aaSJakob Bornecrantz { 1616884840aaSJakob Bornecrantz struct drm_property *dirty_info; 1617884840aaSJakob Bornecrantz 1618884840aaSJakob Bornecrantz if (dev->mode_config.dirty_info_property) 1619884840aaSJakob Bornecrantz return 0; 1620884840aaSJakob Bornecrantz 1621884840aaSJakob Bornecrantz dirty_info = 16224a67d391SSascha Hauer drm_property_create_enum(dev, DRM_MODE_PROP_IMMUTABLE, 1623884840aaSJakob Bornecrantz "dirty", 16244a67d391SSascha Hauer drm_dirty_info_enum_list, 1625884840aaSJakob Bornecrantz ARRAY_SIZE(drm_dirty_info_enum_list)); 1626884840aaSJakob Bornecrantz dev->mode_config.dirty_info_property = dirty_info; 1627884840aaSJakob Bornecrantz 1628884840aaSJakob Bornecrantz return 0; 1629884840aaSJakob Bornecrantz } 1630884840aaSJakob Bornecrantz EXPORT_SYMBOL(drm_mode_create_dirty_info_property); 1631884840aaSJakob Bornecrantz 16325bb2bbf5SDave Airlie /** 16335bb2bbf5SDave Airlie * drm_mode_create_suggested_offset_properties - create suggests offset properties 16345bb2bbf5SDave Airlie * @dev: DRM device 16355bb2bbf5SDave Airlie * 16365bb2bbf5SDave Airlie * Create the the suggested x/y offset property for connectors. 16375bb2bbf5SDave Airlie */ 16385bb2bbf5SDave Airlie int drm_mode_create_suggested_offset_properties(struct drm_device *dev) 16395bb2bbf5SDave Airlie { 16405bb2bbf5SDave Airlie if (dev->mode_config.suggested_x_property && dev->mode_config.suggested_y_property) 16415bb2bbf5SDave Airlie return 0; 16425bb2bbf5SDave Airlie 16435bb2bbf5SDave Airlie dev->mode_config.suggested_x_property = 16445bb2bbf5SDave Airlie drm_property_create_range(dev, DRM_MODE_PROP_IMMUTABLE, "suggested X", 0, 0xffffffff); 16455bb2bbf5SDave Airlie 16465bb2bbf5SDave Airlie dev->mode_config.suggested_y_property = 16475bb2bbf5SDave Airlie drm_property_create_range(dev, DRM_MODE_PROP_IMMUTABLE, "suggested Y", 0, 0xffffffff); 16485bb2bbf5SDave Airlie 16495bb2bbf5SDave Airlie if (dev->mode_config.suggested_x_property == NULL || 16505bb2bbf5SDave Airlie dev->mode_config.suggested_y_property == NULL) 16515bb2bbf5SDave Airlie return -ENOMEM; 16525bb2bbf5SDave Airlie return 0; 16535bb2bbf5SDave Airlie } 16545bb2bbf5SDave Airlie EXPORT_SYMBOL(drm_mode_create_suggested_offset_properties); 16555bb2bbf5SDave Airlie 1656ea9cbb06SVille Syrjälä static int drm_mode_group_init(struct drm_device *dev, struct drm_mode_group *group) 1657f453ba04SDave Airlie { 1658f453ba04SDave Airlie uint32_t total_objects = 0; 1659f453ba04SDave Airlie 1660f453ba04SDave Airlie total_objects += dev->mode_config.num_crtc; 1661f453ba04SDave Airlie total_objects += dev->mode_config.num_connector; 1662f453ba04SDave Airlie total_objects += dev->mode_config.num_encoder; 1663f453ba04SDave Airlie 1664bd3f0ff9SThierry Reding group->id_list = kcalloc(total_objects, sizeof(uint32_t), GFP_KERNEL); 1665f453ba04SDave Airlie if (!group->id_list) 1666f453ba04SDave Airlie return -ENOMEM; 1667f453ba04SDave Airlie 1668f453ba04SDave Airlie group->num_crtcs = 0; 1669f453ba04SDave Airlie group->num_connectors = 0; 1670f453ba04SDave Airlie group->num_encoders = 0; 1671f453ba04SDave Airlie return 0; 1672f453ba04SDave Airlie } 1673f453ba04SDave Airlie 1674ad222799SDave Airlie void drm_mode_group_destroy(struct drm_mode_group *group) 1675ad222799SDave Airlie { 1676ad222799SDave Airlie kfree(group->id_list); 1677ad222799SDave Airlie group->id_list = NULL; 1678ad222799SDave Airlie } 1679ad222799SDave Airlie 1680c8e32cc1SDaniel Vetter /* 1681c8e32cc1SDaniel Vetter * NOTE: Driver's shouldn't ever call drm_mode_group_init_legacy_group - it is 1682c8e32cc1SDaniel Vetter * the drm core's responsibility to set up mode control groups. 1683c8e32cc1SDaniel Vetter */ 1684f453ba04SDave Airlie int drm_mode_group_init_legacy_group(struct drm_device *dev, 1685f453ba04SDave Airlie struct drm_mode_group *group) 1686f453ba04SDave Airlie { 1687f453ba04SDave Airlie struct drm_crtc *crtc; 1688f453ba04SDave Airlie struct drm_encoder *encoder; 1689f453ba04SDave Airlie struct drm_connector *connector; 1690f453ba04SDave Airlie int ret; 1691f453ba04SDave Airlie 16920cc0b223SThierry Reding ret = drm_mode_group_init(dev, group); 16930cc0b223SThierry Reding if (ret) 1694f453ba04SDave Airlie return ret; 1695f453ba04SDave Airlie 1696f453ba04SDave Airlie list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) 1697f453ba04SDave Airlie group->id_list[group->num_crtcs++] = crtc->base.id; 1698f453ba04SDave Airlie 1699f453ba04SDave Airlie list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) 1700f453ba04SDave Airlie group->id_list[group->num_crtcs + group->num_encoders++] = 1701f453ba04SDave Airlie encoder->base.id; 1702f453ba04SDave Airlie 1703f453ba04SDave Airlie list_for_each_entry(connector, &dev->mode_config.connector_list, head) 1704f453ba04SDave Airlie group->id_list[group->num_crtcs + group->num_encoders + 1705f453ba04SDave Airlie group->num_connectors++] = connector->base.id; 1706f453ba04SDave Airlie 1707f453ba04SDave Airlie return 0; 1708f453ba04SDave Airlie } 17099c1dfc55SDave Airlie EXPORT_SYMBOL(drm_mode_group_init_legacy_group); 1710f453ba04SDave Airlie 17112390cd11SDave Airlie void drm_reinit_primary_mode_group(struct drm_device *dev) 17122390cd11SDave Airlie { 17132390cd11SDave Airlie drm_modeset_lock_all(dev); 17142390cd11SDave Airlie drm_mode_group_destroy(&dev->primary->mode_group); 17152390cd11SDave Airlie drm_mode_group_init_legacy_group(dev, &dev->primary->mode_group); 17162390cd11SDave Airlie drm_modeset_unlock_all(dev); 17172390cd11SDave Airlie } 17182390cd11SDave Airlie EXPORT_SYMBOL(drm_reinit_primary_mode_group); 17192390cd11SDave Airlie 1720f453ba04SDave Airlie /** 1721f453ba04SDave Airlie * drm_crtc_convert_to_umode - convert a drm_display_mode into a modeinfo 1722f453ba04SDave Airlie * @out: drm_mode_modeinfo struct to return to the user 1723f453ba04SDave Airlie * @in: drm_display_mode to use 1724f453ba04SDave Airlie * 1725f453ba04SDave Airlie * Convert a drm_display_mode into a drm_mode_modeinfo structure to return to 1726f453ba04SDave Airlie * the user. 1727f453ba04SDave Airlie */ 172893bbf6dbSVille Syrjälä static void drm_crtc_convert_to_umode(struct drm_mode_modeinfo *out, 172993bbf6dbSVille Syrjälä const struct drm_display_mode *in) 1730f453ba04SDave Airlie { 1731e36fae38SVille Syrjälä WARN(in->hdisplay > USHRT_MAX || in->hsync_start > USHRT_MAX || 1732e36fae38SVille Syrjälä in->hsync_end > USHRT_MAX || in->htotal > USHRT_MAX || 1733e36fae38SVille Syrjälä in->hskew > USHRT_MAX || in->vdisplay > USHRT_MAX || 1734e36fae38SVille Syrjälä in->vsync_start > USHRT_MAX || in->vsync_end > USHRT_MAX || 1735e36fae38SVille Syrjälä in->vtotal > USHRT_MAX || in->vscan > USHRT_MAX, 1736e36fae38SVille Syrjälä "timing values too large for mode info\n"); 1737e36fae38SVille Syrjälä 1738f453ba04SDave Airlie out->clock = in->clock; 1739f453ba04SDave Airlie out->hdisplay = in->hdisplay; 1740f453ba04SDave Airlie out->hsync_start = in->hsync_start; 1741f453ba04SDave Airlie out->hsync_end = in->hsync_end; 1742f453ba04SDave Airlie out->htotal = in->htotal; 1743f453ba04SDave Airlie out->hskew = in->hskew; 1744f453ba04SDave Airlie out->vdisplay = in->vdisplay; 1745f453ba04SDave Airlie out->vsync_start = in->vsync_start; 1746f453ba04SDave Airlie out->vsync_end = in->vsync_end; 1747f453ba04SDave Airlie out->vtotal = in->vtotal; 1748f453ba04SDave Airlie out->vscan = in->vscan; 1749f453ba04SDave Airlie out->vrefresh = in->vrefresh; 1750f453ba04SDave Airlie out->flags = in->flags; 1751f453ba04SDave Airlie out->type = in->type; 1752f453ba04SDave Airlie strncpy(out->name, in->name, DRM_DISPLAY_MODE_LEN); 1753f453ba04SDave Airlie out->name[DRM_DISPLAY_MODE_LEN-1] = 0; 1754f453ba04SDave Airlie } 1755f453ba04SDave Airlie 1756f453ba04SDave Airlie /** 175774afee7dSMarc-André Lureau * drm_crtc_convert_umode - convert a modeinfo into a drm_display_mode 1758f453ba04SDave Airlie * @out: drm_display_mode to return to the user 1759f453ba04SDave Airlie * @in: drm_mode_modeinfo to use 1760f453ba04SDave Airlie * 1761f453ba04SDave Airlie * Convert a drm_mode_modeinfo into a drm_display_mode structure to return to 1762f453ba04SDave Airlie * the caller. 176390367bf6SVille Syrjälä * 1764c8e32cc1SDaniel Vetter * Returns: 17651a498633SDaniel Vetter * Zero on success, negative errno on failure. 1766f453ba04SDave Airlie */ 176793bbf6dbSVille Syrjälä static int drm_crtc_convert_umode(struct drm_display_mode *out, 176893bbf6dbSVille Syrjälä const struct drm_mode_modeinfo *in) 1769f453ba04SDave Airlie { 177090367bf6SVille Syrjälä if (in->clock > INT_MAX || in->vrefresh > INT_MAX) 177190367bf6SVille Syrjälä return -ERANGE; 177290367bf6SVille Syrjälä 17735848ad40SDamien Lespiau if ((in->flags & DRM_MODE_FLAG_3D_MASK) > DRM_MODE_FLAG_3D_MAX) 17745848ad40SDamien Lespiau return -EINVAL; 17755848ad40SDamien Lespiau 1776f453ba04SDave Airlie out->clock = in->clock; 1777f453ba04SDave Airlie out->hdisplay = in->hdisplay; 1778f453ba04SDave Airlie out->hsync_start = in->hsync_start; 1779f453ba04SDave Airlie out->hsync_end = in->hsync_end; 1780f453ba04SDave Airlie out->htotal = in->htotal; 1781f453ba04SDave Airlie out->hskew = in->hskew; 1782f453ba04SDave Airlie out->vdisplay = in->vdisplay; 1783f453ba04SDave Airlie out->vsync_start = in->vsync_start; 1784f453ba04SDave Airlie out->vsync_end = in->vsync_end; 1785f453ba04SDave Airlie out->vtotal = in->vtotal; 1786f453ba04SDave Airlie out->vscan = in->vscan; 1787f453ba04SDave Airlie out->vrefresh = in->vrefresh; 1788f453ba04SDave Airlie out->flags = in->flags; 1789f453ba04SDave Airlie out->type = in->type; 1790f453ba04SDave Airlie strncpy(out->name, in->name, DRM_DISPLAY_MODE_LEN); 1791f453ba04SDave Airlie out->name[DRM_DISPLAY_MODE_LEN-1] = 0; 179290367bf6SVille Syrjälä 179390367bf6SVille Syrjälä return 0; 1794f453ba04SDave Airlie } 1795f453ba04SDave Airlie 1796f453ba04SDave Airlie /** 1797f453ba04SDave Airlie * drm_mode_getresources - get graphics configuration 1798065a50edSDaniel Vetter * @dev: drm device for the ioctl 1799065a50edSDaniel Vetter * @data: data pointer for the ioctl 1800065a50edSDaniel Vetter * @file_priv: drm file for the ioctl call 1801f453ba04SDave Airlie * 1802f453ba04SDave Airlie * Construct a set of configuration description structures and return 1803f453ba04SDave Airlie * them to the user, including CRTC, connector and framebuffer configuration. 1804f453ba04SDave Airlie * 1805f453ba04SDave Airlie * Called by the user via ioctl. 1806f453ba04SDave Airlie * 1807c8e32cc1SDaniel Vetter * Returns: 18081a498633SDaniel Vetter * Zero on success, negative errno on failure. 1809f453ba04SDave Airlie */ 1810f453ba04SDave Airlie int drm_mode_getresources(struct drm_device *dev, void *data, 1811f453ba04SDave Airlie struct drm_file *file_priv) 1812f453ba04SDave Airlie { 1813f453ba04SDave Airlie struct drm_mode_card_res *card_res = data; 1814f453ba04SDave Airlie struct list_head *lh; 1815f453ba04SDave Airlie struct drm_framebuffer *fb; 1816f453ba04SDave Airlie struct drm_connector *connector; 1817f453ba04SDave Airlie struct drm_crtc *crtc; 1818f453ba04SDave Airlie struct drm_encoder *encoder; 1819f453ba04SDave Airlie int ret = 0; 1820f453ba04SDave Airlie int connector_count = 0; 1821f453ba04SDave Airlie int crtc_count = 0; 1822f453ba04SDave Airlie int fb_count = 0; 1823f453ba04SDave Airlie int encoder_count = 0; 1824f453ba04SDave Airlie int copied = 0, i; 1825f453ba04SDave Airlie uint32_t __user *fb_id; 1826f453ba04SDave Airlie uint32_t __user *crtc_id; 1827f453ba04SDave Airlie uint32_t __user *connector_id; 1828f453ba04SDave Airlie uint32_t __user *encoder_id; 1829f453ba04SDave Airlie struct drm_mode_group *mode_group; 1830f453ba04SDave Airlie 1831fb3b06c8SDave Airlie if (!drm_core_check_feature(dev, DRIVER_MODESET)) 1832fb3b06c8SDave Airlie return -EINVAL; 1833fb3b06c8SDave Airlie 1834f453ba04SDave Airlie 18354b096ac1SDaniel Vetter mutex_lock(&file_priv->fbs_lock); 1836f453ba04SDave Airlie /* 1837f453ba04SDave Airlie * For the non-control nodes we need to limit the list of resources 1838f453ba04SDave Airlie * by IDs in the group list for this node 1839f453ba04SDave Airlie */ 1840f453ba04SDave Airlie list_for_each(lh, &file_priv->fbs) 1841f453ba04SDave Airlie fb_count++; 1842f453ba04SDave Airlie 18434b096ac1SDaniel Vetter /* handle this in 4 parts */ 18444b096ac1SDaniel Vetter /* FBs */ 18454b096ac1SDaniel Vetter if (card_res->count_fbs >= fb_count) { 18464b096ac1SDaniel Vetter copied = 0; 18474b096ac1SDaniel Vetter fb_id = (uint32_t __user *)(unsigned long)card_res->fb_id_ptr; 18484b096ac1SDaniel Vetter list_for_each_entry(fb, &file_priv->fbs, filp_head) { 18494b096ac1SDaniel Vetter if (put_user(fb->base.id, fb_id + copied)) { 18504b096ac1SDaniel Vetter mutex_unlock(&file_priv->fbs_lock); 18514b096ac1SDaniel Vetter return -EFAULT; 18524b096ac1SDaniel Vetter } 18534b096ac1SDaniel Vetter copied++; 18544b096ac1SDaniel Vetter } 18554b096ac1SDaniel Vetter } 18564b096ac1SDaniel Vetter card_res->count_fbs = fb_count; 18574b096ac1SDaniel Vetter mutex_unlock(&file_priv->fbs_lock); 18584b096ac1SDaniel Vetter 1859fcf93f69SDaniel Vetter /* mode_config.mutex protects the connector list against e.g. DP MST 1860fcf93f69SDaniel Vetter * connector hot-adding. CRTC/Plane lists are invariant. */ 1861fcf93f69SDaniel Vetter mutex_lock(&dev->mode_config.mutex); 186243683057SThomas Hellstrom if (!drm_is_primary_client(file_priv)) { 1863f453ba04SDave Airlie 186409f308f7SThomas Hellstrom mode_group = NULL; 1865f453ba04SDave Airlie list_for_each(lh, &dev->mode_config.crtc_list) 1866f453ba04SDave Airlie crtc_count++; 1867f453ba04SDave Airlie 1868f453ba04SDave Airlie list_for_each(lh, &dev->mode_config.connector_list) 1869f453ba04SDave Airlie connector_count++; 1870f453ba04SDave Airlie 1871f453ba04SDave Airlie list_for_each(lh, &dev->mode_config.encoder_list) 1872f453ba04SDave Airlie encoder_count++; 1873f453ba04SDave Airlie } else { 1874f453ba04SDave Airlie 187509f308f7SThomas Hellstrom mode_group = &file_priv->master->minor->mode_group; 1876f453ba04SDave Airlie crtc_count = mode_group->num_crtcs; 1877f453ba04SDave Airlie connector_count = mode_group->num_connectors; 1878f453ba04SDave Airlie encoder_count = mode_group->num_encoders; 1879f453ba04SDave Airlie } 1880f453ba04SDave Airlie 1881f453ba04SDave Airlie card_res->max_height = dev->mode_config.max_height; 1882f453ba04SDave Airlie card_res->min_height = dev->mode_config.min_height; 1883f453ba04SDave Airlie card_res->max_width = dev->mode_config.max_width; 1884f453ba04SDave Airlie card_res->min_width = dev->mode_config.min_width; 1885f453ba04SDave Airlie 1886f453ba04SDave Airlie /* CRTCs */ 1887f453ba04SDave Airlie if (card_res->count_crtcs >= crtc_count) { 1888f453ba04SDave Airlie copied = 0; 1889f453ba04SDave Airlie crtc_id = (uint32_t __user *)(unsigned long)card_res->crtc_id_ptr; 189009f308f7SThomas Hellstrom if (!mode_group) { 1891f453ba04SDave Airlie list_for_each_entry(crtc, &dev->mode_config.crtc_list, 1892f453ba04SDave Airlie head) { 18939440106bSJerome Glisse DRM_DEBUG_KMS("[CRTC:%d]\n", crtc->base.id); 1894f453ba04SDave Airlie if (put_user(crtc->base.id, crtc_id + copied)) { 1895f453ba04SDave Airlie ret = -EFAULT; 1896f453ba04SDave Airlie goto out; 1897f453ba04SDave Airlie } 1898f453ba04SDave Airlie copied++; 1899f453ba04SDave Airlie } 1900f453ba04SDave Airlie } else { 1901f453ba04SDave Airlie for (i = 0; i < mode_group->num_crtcs; i++) { 1902f453ba04SDave Airlie if (put_user(mode_group->id_list[i], 1903f453ba04SDave Airlie crtc_id + copied)) { 1904f453ba04SDave Airlie ret = -EFAULT; 1905f453ba04SDave Airlie goto out; 1906f453ba04SDave Airlie } 1907f453ba04SDave Airlie copied++; 1908f453ba04SDave Airlie } 1909f453ba04SDave Airlie } 1910f453ba04SDave Airlie } 1911f453ba04SDave Airlie card_res->count_crtcs = crtc_count; 1912f453ba04SDave Airlie 1913f453ba04SDave Airlie /* Encoders */ 1914f453ba04SDave Airlie if (card_res->count_encoders >= encoder_count) { 1915f453ba04SDave Airlie copied = 0; 1916f453ba04SDave Airlie encoder_id = (uint32_t __user *)(unsigned long)card_res->encoder_id_ptr; 191709f308f7SThomas Hellstrom if (!mode_group) { 1918f453ba04SDave Airlie list_for_each_entry(encoder, 1919f453ba04SDave Airlie &dev->mode_config.encoder_list, 1920f453ba04SDave Airlie head) { 19219440106bSJerome Glisse DRM_DEBUG_KMS("[ENCODER:%d:%s]\n", encoder->base.id, 192283a8cfd3SJani Nikula encoder->name); 1923f453ba04SDave Airlie if (put_user(encoder->base.id, encoder_id + 1924f453ba04SDave Airlie copied)) { 1925f453ba04SDave Airlie ret = -EFAULT; 1926f453ba04SDave Airlie goto out; 1927f453ba04SDave Airlie } 1928f453ba04SDave Airlie copied++; 1929f453ba04SDave Airlie } 1930f453ba04SDave Airlie } else { 1931f453ba04SDave Airlie for (i = mode_group->num_crtcs; i < mode_group->num_crtcs + mode_group->num_encoders; i++) { 1932f453ba04SDave Airlie if (put_user(mode_group->id_list[i], 1933f453ba04SDave Airlie encoder_id + copied)) { 1934f453ba04SDave Airlie ret = -EFAULT; 1935f453ba04SDave Airlie goto out; 1936f453ba04SDave Airlie } 1937f453ba04SDave Airlie copied++; 1938f453ba04SDave Airlie } 1939f453ba04SDave Airlie 1940f453ba04SDave Airlie } 1941f453ba04SDave Airlie } 1942f453ba04SDave Airlie card_res->count_encoders = encoder_count; 1943f453ba04SDave Airlie 1944f453ba04SDave Airlie /* Connectors */ 1945f453ba04SDave Airlie if (card_res->count_connectors >= connector_count) { 1946f453ba04SDave Airlie copied = 0; 1947f453ba04SDave Airlie connector_id = (uint32_t __user *)(unsigned long)card_res->connector_id_ptr; 194809f308f7SThomas Hellstrom if (!mode_group) { 1949f453ba04SDave Airlie list_for_each_entry(connector, 1950f453ba04SDave Airlie &dev->mode_config.connector_list, 1951f453ba04SDave Airlie head) { 19529440106bSJerome Glisse DRM_DEBUG_KMS("[CONNECTOR:%d:%s]\n", 19539440106bSJerome Glisse connector->base.id, 195425933820SJani Nikula connector->name); 1955f453ba04SDave Airlie if (put_user(connector->base.id, 1956f453ba04SDave Airlie connector_id + copied)) { 1957f453ba04SDave Airlie ret = -EFAULT; 1958f453ba04SDave Airlie goto out; 1959f453ba04SDave Airlie } 1960f453ba04SDave Airlie copied++; 1961f453ba04SDave Airlie } 1962f453ba04SDave Airlie } else { 1963f453ba04SDave Airlie int start = mode_group->num_crtcs + 1964f453ba04SDave Airlie mode_group->num_encoders; 1965f453ba04SDave Airlie for (i = start; i < start + mode_group->num_connectors; i++) { 1966f453ba04SDave Airlie if (put_user(mode_group->id_list[i], 1967f453ba04SDave Airlie connector_id + copied)) { 1968f453ba04SDave Airlie ret = -EFAULT; 1969f453ba04SDave Airlie goto out; 1970f453ba04SDave Airlie } 1971f453ba04SDave Airlie copied++; 1972f453ba04SDave Airlie } 1973f453ba04SDave Airlie } 1974f453ba04SDave Airlie } 1975f453ba04SDave Airlie card_res->count_connectors = connector_count; 1976f453ba04SDave Airlie 19779440106bSJerome Glisse DRM_DEBUG_KMS("CRTC[%d] CONNECTORS[%d] ENCODERS[%d]\n", card_res->count_crtcs, 1978f453ba04SDave Airlie card_res->count_connectors, card_res->count_encoders); 1979f453ba04SDave Airlie 1980f453ba04SDave Airlie out: 1981fcf93f69SDaniel Vetter mutex_unlock(&dev->mode_config.mutex); 1982f453ba04SDave Airlie return ret; 1983f453ba04SDave Airlie } 1984f453ba04SDave Airlie 1985f453ba04SDave Airlie /** 1986f453ba04SDave Airlie * drm_mode_getcrtc - get CRTC configuration 1987065a50edSDaniel Vetter * @dev: drm device for the ioctl 1988065a50edSDaniel Vetter * @data: data pointer for the ioctl 1989065a50edSDaniel Vetter * @file_priv: drm file for the ioctl call 1990f453ba04SDave Airlie * 1991f453ba04SDave Airlie * Construct a CRTC configuration structure to return to the user. 1992f453ba04SDave Airlie * 1993f453ba04SDave Airlie * Called by the user via ioctl. 1994f453ba04SDave Airlie * 1995c8e32cc1SDaniel Vetter * Returns: 19961a498633SDaniel Vetter * Zero on success, negative errno on failure. 1997f453ba04SDave Airlie */ 1998f453ba04SDave Airlie int drm_mode_getcrtc(struct drm_device *dev, 1999f453ba04SDave Airlie void *data, struct drm_file *file_priv) 2000f453ba04SDave Airlie { 2001f453ba04SDave Airlie struct drm_mode_crtc *crtc_resp = data; 2002f453ba04SDave Airlie struct drm_crtc *crtc; 2003f453ba04SDave Airlie 2004fb3b06c8SDave Airlie if (!drm_core_check_feature(dev, DRIVER_MODESET)) 2005fb3b06c8SDave Airlie return -EINVAL; 2006fb3b06c8SDave Airlie 2007a2b34e22SRob Clark crtc = drm_crtc_find(dev, crtc_resp->crtc_id); 2008fcf93f69SDaniel Vetter if (!crtc) 2009fcf93f69SDaniel Vetter return -ENOENT; 2010f453ba04SDave Airlie 2011fcf93f69SDaniel Vetter drm_modeset_lock_crtc(crtc, crtc->primary); 2012f453ba04SDave Airlie crtc_resp->gamma_size = crtc->gamma_size; 2013f4510a27SMatt Roper if (crtc->primary->fb) 2014f4510a27SMatt Roper crtc_resp->fb_id = crtc->primary->fb->base.id; 2015f453ba04SDave Airlie else 2016f453ba04SDave Airlie crtc_resp->fb_id = 0; 2017f453ba04SDave Airlie 201831c946e8SDaniel Vetter if (crtc->state) { 201931c946e8SDaniel Vetter crtc_resp->x = crtc->primary->state->src_x >> 16; 202031c946e8SDaniel Vetter crtc_resp->y = crtc->primary->state->src_y >> 16; 202131c946e8SDaniel Vetter if (crtc->state->enable) { 202231c946e8SDaniel Vetter drm_crtc_convert_to_umode(&crtc_resp->mode, &crtc->state->mode); 202331c946e8SDaniel Vetter crtc_resp->mode_valid = 1; 2024f453ba04SDave Airlie 202531c946e8SDaniel Vetter } else { 202631c946e8SDaniel Vetter crtc_resp->mode_valid = 0; 202731c946e8SDaniel Vetter } 202831c946e8SDaniel Vetter } else { 202931c946e8SDaniel Vetter crtc_resp->x = crtc->x; 203031c946e8SDaniel Vetter crtc_resp->y = crtc->y; 203131c946e8SDaniel Vetter if (crtc->enabled) { 2032f453ba04SDave Airlie drm_crtc_convert_to_umode(&crtc_resp->mode, &crtc->mode); 2033f453ba04SDave Airlie crtc_resp->mode_valid = 1; 2034f453ba04SDave Airlie 2035f453ba04SDave Airlie } else { 2036f453ba04SDave Airlie crtc_resp->mode_valid = 0; 2037f453ba04SDave Airlie } 203831c946e8SDaniel Vetter } 2039fcf93f69SDaniel Vetter drm_modeset_unlock_crtc(crtc); 2040f453ba04SDave Airlie 2041baf698b0SDaniel Vetter return 0; 2042f453ba04SDave Airlie } 2043f453ba04SDave Airlie 204461d8e328SDamien Lespiau static bool drm_mode_expose_to_userspace(const struct drm_display_mode *mode, 204561d8e328SDamien Lespiau const struct drm_file *file_priv) 204661d8e328SDamien Lespiau { 204761d8e328SDamien Lespiau /* 204861d8e328SDamien Lespiau * If user-space hasn't configured the driver to expose the stereo 3D 204961d8e328SDamien Lespiau * modes, don't expose them. 205061d8e328SDamien Lespiau */ 205161d8e328SDamien Lespiau if (!file_priv->stereo_allowed && drm_mode_is_stereo(mode)) 205261d8e328SDamien Lespiau return false; 205361d8e328SDamien Lespiau 205461d8e328SDamien Lespiau return true; 205561d8e328SDamien Lespiau } 205661d8e328SDamien Lespiau 2057abd69c55SDaniel Vetter static struct drm_encoder *drm_connector_get_encoder(struct drm_connector *connector) 2058abd69c55SDaniel Vetter { 2059abd69c55SDaniel Vetter /* For atomic drivers only state objects are synchronously updated and 2060abd69c55SDaniel Vetter * protected by modeset locks, so check those first. */ 2061abd69c55SDaniel Vetter if (connector->state) 2062abd69c55SDaniel Vetter return connector->state->best_encoder; 2063abd69c55SDaniel Vetter return connector->encoder; 2064abd69c55SDaniel Vetter } 2065abd69c55SDaniel Vetter 206695cbf110SRob Clark /* helper for getconnector and getproperties ioctls */ 206788a48e29SRob Clark static int get_properties(struct drm_mode_object *obj, bool atomic, 206895cbf110SRob Clark uint32_t __user *prop_ptr, uint64_t __user *prop_values, 206995cbf110SRob Clark uint32_t *arg_count_props) 207095cbf110SRob Clark { 207188a48e29SRob Clark int props_count; 207288a48e29SRob Clark int i, ret, copied; 207388a48e29SRob Clark 207488a48e29SRob Clark props_count = obj->properties->count; 207588a48e29SRob Clark if (!atomic) 207688a48e29SRob Clark props_count -= obj->properties->atomic_count; 207795cbf110SRob Clark 207895cbf110SRob Clark if ((*arg_count_props >= props_count) && props_count) { 207988a48e29SRob Clark for (i = 0, copied = 0; copied < props_count; i++) { 208095cbf110SRob Clark struct drm_property *prop = obj->properties->properties[i]; 208195cbf110SRob Clark uint64_t val; 208295cbf110SRob Clark 208388a48e29SRob Clark if ((prop->flags & DRM_MODE_PROP_ATOMIC) && !atomic) 208488a48e29SRob Clark continue; 208588a48e29SRob Clark 208695cbf110SRob Clark ret = drm_object_property_get_value(obj, prop, &val); 208795cbf110SRob Clark if (ret) 208895cbf110SRob Clark return ret; 208995cbf110SRob Clark 209095cbf110SRob Clark if (put_user(prop->base.id, prop_ptr + copied)) 209195cbf110SRob Clark return -EFAULT; 209295cbf110SRob Clark 209395cbf110SRob Clark if (put_user(val, prop_values + copied)) 209495cbf110SRob Clark return -EFAULT; 209595cbf110SRob Clark 209695cbf110SRob Clark copied++; 209795cbf110SRob Clark } 209895cbf110SRob Clark } 209995cbf110SRob Clark *arg_count_props = props_count; 210095cbf110SRob Clark 210195cbf110SRob Clark return 0; 210295cbf110SRob Clark } 210395cbf110SRob Clark 2104f453ba04SDave Airlie /** 2105f453ba04SDave Airlie * drm_mode_getconnector - get connector configuration 2106065a50edSDaniel Vetter * @dev: drm device for the ioctl 2107065a50edSDaniel Vetter * @data: data pointer for the ioctl 2108065a50edSDaniel Vetter * @file_priv: drm file for the ioctl call 2109f453ba04SDave Airlie * 2110f453ba04SDave Airlie * Construct a connector configuration structure to return to the user. 2111f453ba04SDave Airlie * 2112f453ba04SDave Airlie * Called by the user via ioctl. 2113f453ba04SDave Airlie * 2114c8e32cc1SDaniel Vetter * Returns: 21151a498633SDaniel Vetter * Zero on success, negative errno on failure. 2116f453ba04SDave Airlie */ 2117f453ba04SDave Airlie int drm_mode_getconnector(struct drm_device *dev, void *data, 2118f453ba04SDave Airlie struct drm_file *file_priv) 2119f453ba04SDave Airlie { 2120f453ba04SDave Airlie struct drm_mode_get_connector *out_resp = data; 2121f453ba04SDave Airlie struct drm_connector *connector; 2122abd69c55SDaniel Vetter struct drm_encoder *encoder; 2123f453ba04SDave Airlie struct drm_display_mode *mode; 2124f453ba04SDave Airlie int mode_count = 0; 2125f453ba04SDave Airlie int encoders_count = 0; 2126f453ba04SDave Airlie int ret = 0; 2127f453ba04SDave Airlie int copied = 0; 2128f453ba04SDave Airlie int i; 2129f453ba04SDave Airlie struct drm_mode_modeinfo u_mode; 2130f453ba04SDave Airlie struct drm_mode_modeinfo __user *mode_ptr; 2131f453ba04SDave Airlie uint32_t __user *encoder_ptr; 2132f453ba04SDave Airlie 2133fb3b06c8SDave Airlie if (!drm_core_check_feature(dev, DRIVER_MODESET)) 2134fb3b06c8SDave Airlie return -EINVAL; 2135fb3b06c8SDave Airlie 2136f453ba04SDave Airlie memset(&u_mode, 0, sizeof(struct drm_mode_modeinfo)); 2137f453ba04SDave Airlie 21389440106bSJerome Glisse DRM_DEBUG_KMS("[CONNECTOR:%d:?]\n", out_resp->connector_id); 2139f453ba04SDave Airlie 21407b24056bSDaniel Vetter mutex_lock(&dev->mode_config.mutex); 2141ccfc0865SRob Clark drm_modeset_lock(&dev->mode_config.connection_mutex, NULL); 2142f453ba04SDave Airlie 2143a2b34e22SRob Clark connector = drm_connector_find(dev, out_resp->connector_id); 2144a2b34e22SRob Clark if (!connector) { 2145f27657f2SVille Syrjälä ret = -ENOENT; 2146f453ba04SDave Airlie goto out; 2147f453ba04SDave Airlie } 2148f453ba04SDave Airlie 214901073b08SThierry Reding for (i = 0; i < DRM_CONNECTOR_MAX_ENCODER; i++) 215001073b08SThierry Reding if (connector->encoder_ids[i] != 0) 2151f453ba04SDave Airlie encoders_count++; 2152f453ba04SDave Airlie 2153f453ba04SDave Airlie if (out_resp->count_modes == 0) { 2154f453ba04SDave Airlie connector->funcs->fill_modes(connector, 2155f453ba04SDave Airlie dev->mode_config.max_width, 2156f453ba04SDave Airlie dev->mode_config.max_height); 2157f453ba04SDave Airlie } 2158f453ba04SDave Airlie 2159f453ba04SDave Airlie /* delayed so we get modes regardless of pre-fill_modes state */ 2160f453ba04SDave Airlie list_for_each_entry(mode, &connector->modes, head) 216161d8e328SDamien Lespiau if (drm_mode_expose_to_userspace(mode, file_priv)) 2162f453ba04SDave Airlie mode_count++; 2163f453ba04SDave Airlie 2164f453ba04SDave Airlie out_resp->connector_id = connector->base.id; 2165f453ba04SDave Airlie out_resp->connector_type = connector->connector_type; 2166f453ba04SDave Airlie out_resp->connector_type_id = connector->connector_type_id; 2167f453ba04SDave Airlie out_resp->mm_width = connector->display_info.width_mm; 2168f453ba04SDave Airlie out_resp->mm_height = connector->display_info.height_mm; 2169f453ba04SDave Airlie out_resp->subpixel = connector->display_info.subpixel_order; 2170f453ba04SDave Airlie out_resp->connection = connector->status; 2171abd69c55SDaniel Vetter encoder = drm_connector_get_encoder(connector); 2172abd69c55SDaniel Vetter if (encoder) 2173abd69c55SDaniel Vetter out_resp->encoder_id = encoder->base.id; 2174f453ba04SDave Airlie else 2175f453ba04SDave Airlie out_resp->encoder_id = 0; 2176f453ba04SDave Airlie 2177f453ba04SDave Airlie /* 2178f453ba04SDave Airlie * This ioctl is called twice, once to determine how much space is 2179f453ba04SDave Airlie * needed, and the 2nd time to fill it. 2180f453ba04SDave Airlie */ 2181f453ba04SDave Airlie if ((out_resp->count_modes >= mode_count) && mode_count) { 2182f453ba04SDave Airlie copied = 0; 218381f6c7f8SVille Syrjälä mode_ptr = (struct drm_mode_modeinfo __user *)(unsigned long)out_resp->modes_ptr; 2184f453ba04SDave Airlie list_for_each_entry(mode, &connector->modes, head) { 218561d8e328SDamien Lespiau if (!drm_mode_expose_to_userspace(mode, file_priv)) 218661d8e328SDamien Lespiau continue; 218761d8e328SDamien Lespiau 2188f453ba04SDave Airlie drm_crtc_convert_to_umode(&u_mode, mode); 2189f453ba04SDave Airlie if (copy_to_user(mode_ptr + copied, 2190f453ba04SDave Airlie &u_mode, sizeof(u_mode))) { 2191f453ba04SDave Airlie ret = -EFAULT; 2192f453ba04SDave Airlie goto out; 2193f453ba04SDave Airlie } 2194f453ba04SDave Airlie copied++; 2195f453ba04SDave Airlie } 2196f453ba04SDave Airlie } 2197f453ba04SDave Airlie out_resp->count_modes = mode_count; 2198f453ba04SDave Airlie 219988a48e29SRob Clark ret = get_properties(&connector->base, file_priv->atomic, 220095cbf110SRob Clark (uint32_t __user *)(unsigned long)(out_resp->props_ptr), 220195cbf110SRob Clark (uint64_t __user *)(unsigned long)(out_resp->prop_values_ptr), 220295cbf110SRob Clark &out_resp->count_props); 220322b8b13bSRob Clark if (ret) 2204f453ba04SDave Airlie goto out; 2205f453ba04SDave Airlie 2206f453ba04SDave Airlie if ((out_resp->count_encoders >= encoders_count) && encoders_count) { 2207f453ba04SDave Airlie copied = 0; 220881f6c7f8SVille Syrjälä encoder_ptr = (uint32_t __user *)(unsigned long)(out_resp->encoders_ptr); 2209f453ba04SDave Airlie for (i = 0; i < DRM_CONNECTOR_MAX_ENCODER; i++) { 2210f453ba04SDave Airlie if (connector->encoder_ids[i] != 0) { 2211f453ba04SDave Airlie if (put_user(connector->encoder_ids[i], 2212f453ba04SDave Airlie encoder_ptr + copied)) { 2213f453ba04SDave Airlie ret = -EFAULT; 2214f453ba04SDave Airlie goto out; 2215f453ba04SDave Airlie } 2216f453ba04SDave Airlie copied++; 2217f453ba04SDave Airlie } 2218f453ba04SDave Airlie } 2219f453ba04SDave Airlie } 2220f453ba04SDave Airlie out_resp->count_encoders = encoders_count; 2221f453ba04SDave Airlie 2222f453ba04SDave Airlie out: 2223ccfc0865SRob Clark drm_modeset_unlock(&dev->mode_config.connection_mutex); 22247b24056bSDaniel Vetter mutex_unlock(&dev->mode_config.mutex); 22257b24056bSDaniel Vetter 2226f453ba04SDave Airlie return ret; 2227f453ba04SDave Airlie } 2228f453ba04SDave Airlie 2229abd69c55SDaniel Vetter static struct drm_crtc *drm_encoder_get_crtc(struct drm_encoder *encoder) 2230abd69c55SDaniel Vetter { 2231abd69c55SDaniel Vetter struct drm_connector *connector; 2232abd69c55SDaniel Vetter struct drm_device *dev = encoder->dev; 2233abd69c55SDaniel Vetter bool uses_atomic = false; 2234abd69c55SDaniel Vetter 2235abd69c55SDaniel Vetter /* For atomic drivers only state objects are synchronously updated and 2236abd69c55SDaniel Vetter * protected by modeset locks, so check those first. */ 2237abd69c55SDaniel Vetter list_for_each_entry(connector, &dev->mode_config.connector_list, head) { 2238abd69c55SDaniel Vetter if (!connector->state) 2239abd69c55SDaniel Vetter continue; 2240abd69c55SDaniel Vetter 2241abd69c55SDaniel Vetter uses_atomic = true; 2242abd69c55SDaniel Vetter 2243abd69c55SDaniel Vetter if (connector->state->best_encoder != encoder) 2244abd69c55SDaniel Vetter continue; 2245abd69c55SDaniel Vetter 2246abd69c55SDaniel Vetter return connector->state->crtc; 2247abd69c55SDaniel Vetter } 2248abd69c55SDaniel Vetter 2249abd69c55SDaniel Vetter /* Don't return stale data (e.g. pending async disable). */ 2250abd69c55SDaniel Vetter if (uses_atomic) 2251abd69c55SDaniel Vetter return NULL; 2252abd69c55SDaniel Vetter 2253abd69c55SDaniel Vetter return encoder->crtc; 2254abd69c55SDaniel Vetter } 2255abd69c55SDaniel Vetter 2256c8e32cc1SDaniel Vetter /** 2257c8e32cc1SDaniel Vetter * drm_mode_getencoder - get encoder configuration 2258c8e32cc1SDaniel Vetter * @dev: drm device for the ioctl 2259c8e32cc1SDaniel Vetter * @data: data pointer for the ioctl 2260c8e32cc1SDaniel Vetter * @file_priv: drm file for the ioctl call 2261c8e32cc1SDaniel Vetter * 2262c8e32cc1SDaniel Vetter * Construct a encoder configuration structure to return to the user. 2263c8e32cc1SDaniel Vetter * 2264c8e32cc1SDaniel Vetter * Called by the user via ioctl. 2265c8e32cc1SDaniel Vetter * 2266c8e32cc1SDaniel Vetter * Returns: 22671a498633SDaniel Vetter * Zero on success, negative errno on failure. 2268c8e32cc1SDaniel Vetter */ 2269f453ba04SDave Airlie int drm_mode_getencoder(struct drm_device *dev, void *data, 2270f453ba04SDave Airlie struct drm_file *file_priv) 2271f453ba04SDave Airlie { 2272f453ba04SDave Airlie struct drm_mode_get_encoder *enc_resp = data; 2273f453ba04SDave Airlie struct drm_encoder *encoder; 2274abd69c55SDaniel Vetter struct drm_crtc *crtc; 2275f453ba04SDave Airlie 2276fb3b06c8SDave Airlie if (!drm_core_check_feature(dev, DRIVER_MODESET)) 2277fb3b06c8SDave Airlie return -EINVAL; 2278fb3b06c8SDave Airlie 2279a2b34e22SRob Clark encoder = drm_encoder_find(dev, enc_resp->encoder_id); 2280fcf93f69SDaniel Vetter if (!encoder) 2281fcf93f69SDaniel Vetter return -ENOENT; 2282f453ba04SDave Airlie 2283fcf93f69SDaniel Vetter drm_modeset_lock(&dev->mode_config.connection_mutex, NULL); 2284abd69c55SDaniel Vetter crtc = drm_encoder_get_crtc(encoder); 2285abd69c55SDaniel Vetter if (crtc) 2286abd69c55SDaniel Vetter enc_resp->crtc_id = crtc->base.id; 2287abd69c55SDaniel Vetter else if (encoder->crtc) 2288f453ba04SDave Airlie enc_resp->crtc_id = encoder->crtc->base.id; 2289f453ba04SDave Airlie else 2290f453ba04SDave Airlie enc_resp->crtc_id = 0; 2291fcf93f69SDaniel Vetter drm_modeset_unlock(&dev->mode_config.connection_mutex); 2292fcf93f69SDaniel Vetter 2293f453ba04SDave Airlie enc_resp->encoder_type = encoder->encoder_type; 2294f453ba04SDave Airlie enc_resp->encoder_id = encoder->base.id; 2295f453ba04SDave Airlie enc_resp->possible_crtcs = encoder->possible_crtcs; 2296f453ba04SDave Airlie enc_resp->possible_clones = encoder->possible_clones; 2297f453ba04SDave Airlie 2298baf698b0SDaniel Vetter return 0; 2299f453ba04SDave Airlie } 2300f453ba04SDave Airlie 2301f453ba04SDave Airlie /** 2302c8e32cc1SDaniel Vetter * drm_mode_getplane_res - enumerate all plane resources 23038cf5c917SJesse Barnes * @dev: DRM device 23048cf5c917SJesse Barnes * @data: ioctl data 23058cf5c917SJesse Barnes * @file_priv: DRM file info 23068cf5c917SJesse Barnes * 2307c8e32cc1SDaniel Vetter * Construct a list of plane ids to return to the user. 2308c8e32cc1SDaniel Vetter * 2309c8e32cc1SDaniel Vetter * Called by the user via ioctl. 2310c8e32cc1SDaniel Vetter * 2311c8e32cc1SDaniel Vetter * Returns: 23121a498633SDaniel Vetter * Zero on success, negative errno on failure. 23138cf5c917SJesse Barnes */ 23148cf5c917SJesse Barnes int drm_mode_getplane_res(struct drm_device *dev, void *data, 23158cf5c917SJesse Barnes struct drm_file *file_priv) 23168cf5c917SJesse Barnes { 23178cf5c917SJesse Barnes struct drm_mode_get_plane_res *plane_resp = data; 23188cf5c917SJesse Barnes struct drm_mode_config *config; 23198cf5c917SJesse Barnes struct drm_plane *plane; 23208cf5c917SJesse Barnes uint32_t __user *plane_ptr; 2321fcf93f69SDaniel Vetter int copied = 0; 2322681e7ec7SMatt Roper unsigned num_planes; 23238cf5c917SJesse Barnes 23248cf5c917SJesse Barnes if (!drm_core_check_feature(dev, DRIVER_MODESET)) 23258cf5c917SJesse Barnes return -EINVAL; 23268cf5c917SJesse Barnes 23278cf5c917SJesse Barnes config = &dev->mode_config; 23288cf5c917SJesse Barnes 2329681e7ec7SMatt Roper if (file_priv->universal_planes) 2330681e7ec7SMatt Roper num_planes = config->num_total_plane; 2331681e7ec7SMatt Roper else 2332681e7ec7SMatt Roper num_planes = config->num_overlay_plane; 2333681e7ec7SMatt Roper 23348cf5c917SJesse Barnes /* 23358cf5c917SJesse Barnes * This ioctl is called twice, once to determine how much space is 23368cf5c917SJesse Barnes * needed, and the 2nd time to fill it. 23378cf5c917SJesse Barnes */ 2338681e7ec7SMatt Roper if (num_planes && 2339681e7ec7SMatt Roper (plane_resp->count_planes >= num_planes)) { 234081f6c7f8SVille Syrjälä plane_ptr = (uint32_t __user *)(unsigned long)plane_resp->plane_id_ptr; 23418cf5c917SJesse Barnes 2342fcf93f69SDaniel Vetter /* Plane lists are invariant, no locking needed. */ 23438cf5c917SJesse Barnes list_for_each_entry(plane, &config->plane_list, head) { 2344681e7ec7SMatt Roper /* 2345681e7ec7SMatt Roper * Unless userspace set the 'universal planes' 2346681e7ec7SMatt Roper * capability bit, only advertise overlays. 2347681e7ec7SMatt Roper */ 2348681e7ec7SMatt Roper if (plane->type != DRM_PLANE_TYPE_OVERLAY && 2349681e7ec7SMatt Roper !file_priv->universal_planes) 2350e27dde3eSMatt Roper continue; 2351e27dde3eSMatt Roper 2352fcf93f69SDaniel Vetter if (put_user(plane->base.id, plane_ptr + copied)) 2353fcf93f69SDaniel Vetter return -EFAULT; 23548cf5c917SJesse Barnes copied++; 23558cf5c917SJesse Barnes } 23568cf5c917SJesse Barnes } 2357681e7ec7SMatt Roper plane_resp->count_planes = num_planes; 23588cf5c917SJesse Barnes 2359fcf93f69SDaniel Vetter return 0; 23608cf5c917SJesse Barnes } 23618cf5c917SJesse Barnes 23628cf5c917SJesse Barnes /** 2363c8e32cc1SDaniel Vetter * drm_mode_getplane - get plane configuration 23648cf5c917SJesse Barnes * @dev: DRM device 23658cf5c917SJesse Barnes * @data: ioctl data 23668cf5c917SJesse Barnes * @file_priv: DRM file info 23678cf5c917SJesse Barnes * 2368c8e32cc1SDaniel Vetter * Construct a plane configuration structure to return to the user. 2369c8e32cc1SDaniel Vetter * 2370c8e32cc1SDaniel Vetter * Called by the user via ioctl. 2371c8e32cc1SDaniel Vetter * 2372c8e32cc1SDaniel Vetter * Returns: 23731a498633SDaniel Vetter * Zero on success, negative errno on failure. 23748cf5c917SJesse Barnes */ 23758cf5c917SJesse Barnes int drm_mode_getplane(struct drm_device *dev, void *data, 23768cf5c917SJesse Barnes struct drm_file *file_priv) 23778cf5c917SJesse Barnes { 23788cf5c917SJesse Barnes struct drm_mode_get_plane *plane_resp = data; 23798cf5c917SJesse Barnes struct drm_plane *plane; 23808cf5c917SJesse Barnes uint32_t __user *format_ptr; 23818cf5c917SJesse Barnes 23828cf5c917SJesse Barnes if (!drm_core_check_feature(dev, DRIVER_MODESET)) 23838cf5c917SJesse Barnes return -EINVAL; 23848cf5c917SJesse Barnes 2385a2b34e22SRob Clark plane = drm_plane_find(dev, plane_resp->plane_id); 2386fcf93f69SDaniel Vetter if (!plane) 2387fcf93f69SDaniel Vetter return -ENOENT; 23888cf5c917SJesse Barnes 2389fcf93f69SDaniel Vetter drm_modeset_lock(&plane->mutex, NULL); 23908cf5c917SJesse Barnes if (plane->crtc) 23918cf5c917SJesse Barnes plane_resp->crtc_id = plane->crtc->base.id; 23928cf5c917SJesse Barnes else 23938cf5c917SJesse Barnes plane_resp->crtc_id = 0; 23948cf5c917SJesse Barnes 23958cf5c917SJesse Barnes if (plane->fb) 23968cf5c917SJesse Barnes plane_resp->fb_id = plane->fb->base.id; 23978cf5c917SJesse Barnes else 23988cf5c917SJesse Barnes plane_resp->fb_id = 0; 2399fcf93f69SDaniel Vetter drm_modeset_unlock(&plane->mutex); 24008cf5c917SJesse Barnes 24018cf5c917SJesse Barnes plane_resp->plane_id = plane->base.id; 24028cf5c917SJesse Barnes plane_resp->possible_crtcs = plane->possible_crtcs; 2403778ad903SVille Syrjälä plane_resp->gamma_size = 0; 24048cf5c917SJesse Barnes 24058cf5c917SJesse Barnes /* 24068cf5c917SJesse Barnes * This ioctl is called twice, once to determine how much space is 24078cf5c917SJesse Barnes * needed, and the 2nd time to fill it. 24088cf5c917SJesse Barnes */ 24098cf5c917SJesse Barnes if (plane->format_count && 24108cf5c917SJesse Barnes (plane_resp->count_format_types >= plane->format_count)) { 241181f6c7f8SVille Syrjälä format_ptr = (uint32_t __user *)(unsigned long)plane_resp->format_type_ptr; 24128cf5c917SJesse Barnes if (copy_to_user(format_ptr, 24138cf5c917SJesse Barnes plane->format_types, 24148cf5c917SJesse Barnes sizeof(uint32_t) * plane->format_count)) { 2415fcf93f69SDaniel Vetter return -EFAULT; 24168cf5c917SJesse Barnes } 24178cf5c917SJesse Barnes } 24188cf5c917SJesse Barnes plane_resp->count_format_types = plane->format_count; 24198cf5c917SJesse Barnes 2420baf698b0SDaniel Vetter return 0; 24218cf5c917SJesse Barnes } 24228cf5c917SJesse Barnes 2423b36552b3SMatt Roper /* 2424b36552b3SMatt Roper * setplane_internal - setplane handler for internal callers 24258cf5c917SJesse Barnes * 2426b36552b3SMatt Roper * Note that we assume an extra reference has already been taken on fb. If the 2427b36552b3SMatt Roper * update fails, this reference will be dropped before return; if it succeeds, 2428b36552b3SMatt Roper * the previous framebuffer (if any) will be unreferenced instead. 2429c8e32cc1SDaniel Vetter * 2430b36552b3SMatt Roper * src_{x,y,w,h} are provided in 16.16 fixed point format 24318cf5c917SJesse Barnes */ 2432f2b50c11SDaniel Vetter static int __setplane_internal(struct drm_plane *plane, 243317cfd91fSChris Wilson struct drm_crtc *crtc, 2434b36552b3SMatt Roper struct drm_framebuffer *fb, 2435b36552b3SMatt Roper int32_t crtc_x, int32_t crtc_y, 2436b36552b3SMatt Roper uint32_t crtc_w, uint32_t crtc_h, 2437b36552b3SMatt Roper /* src_{x,y,w,h} values are 16.16 fixed point */ 2438b36552b3SMatt Roper uint32_t src_x, uint32_t src_y, 2439b36552b3SMatt Roper uint32_t src_w, uint32_t src_h) 24408cf5c917SJesse Barnes { 24418cf5c917SJesse Barnes int ret = 0; 244242ef8789SVille Syrjälä unsigned int fb_width, fb_height; 24432f763312SThierry Reding unsigned int i; 24448cf5c917SJesse Barnes 24458cf5c917SJesse Barnes /* No fb means shut it down */ 2446b36552b3SMatt Roper if (!fb) { 24473d30a59bSDaniel Vetter plane->old_fb = plane->fb; 2448731cce48SDaniel Vetter ret = plane->funcs->disable_plane(plane); 2449731cce48SDaniel Vetter if (!ret) { 2450e5e3b44cSVille Syrjälä plane->crtc = NULL; 2451e5e3b44cSVille Syrjälä plane->fb = NULL; 2452731cce48SDaniel Vetter } else { 24533d30a59bSDaniel Vetter plane->old_fb = NULL; 2454731cce48SDaniel Vetter } 24558cf5c917SJesse Barnes goto out; 24568cf5c917SJesse Barnes } 24578cf5c917SJesse Barnes 24587f994f3fSMatt Roper /* Check whether this plane is usable on this CRTC */ 24597f994f3fSMatt Roper if (!(plane->possible_crtcs & drm_crtc_mask(crtc))) { 24607f994f3fSMatt Roper DRM_DEBUG_KMS("Invalid crtc for plane\n"); 24617f994f3fSMatt Roper ret = -EINVAL; 24627f994f3fSMatt Roper goto out; 24637f994f3fSMatt Roper } 24647f994f3fSMatt Roper 246562443be6SVille Syrjälä /* Check whether this plane supports the fb pixel format. */ 246662443be6SVille Syrjälä for (i = 0; i < plane->format_count; i++) 246762443be6SVille Syrjälä if (fb->pixel_format == plane->format_types[i]) 246862443be6SVille Syrjälä break; 246962443be6SVille Syrjälä if (i == plane->format_count) { 24706ba6d03eSVille Syrjälä DRM_DEBUG_KMS("Invalid pixel format %s\n", 24716ba6d03eSVille Syrjälä drm_get_format_name(fb->pixel_format)); 247262443be6SVille Syrjälä ret = -EINVAL; 247362443be6SVille Syrjälä goto out; 247462443be6SVille Syrjälä } 247562443be6SVille Syrjälä 247642ef8789SVille Syrjälä fb_width = fb->width << 16; 247742ef8789SVille Syrjälä fb_height = fb->height << 16; 247842ef8789SVille Syrjälä 247942ef8789SVille Syrjälä /* Make sure source coordinates are inside the fb. */ 2480b36552b3SMatt Roper if (src_w > fb_width || 2481b36552b3SMatt Roper src_x > fb_width - src_w || 2482b36552b3SMatt Roper src_h > fb_height || 2483b36552b3SMatt Roper src_y > fb_height - src_h) { 248442ef8789SVille Syrjälä DRM_DEBUG_KMS("Invalid source coordinates " 248542ef8789SVille Syrjälä "%u.%06ux%u.%06u+%u.%06u+%u.%06u\n", 2486b36552b3SMatt Roper src_w >> 16, ((src_w & 0xffff) * 15625) >> 10, 2487b36552b3SMatt Roper src_h >> 16, ((src_h & 0xffff) * 15625) >> 10, 2488b36552b3SMatt Roper src_x >> 16, ((src_x & 0xffff) * 15625) >> 10, 2489b36552b3SMatt Roper src_y >> 16, ((src_y & 0xffff) * 15625) >> 10); 249042ef8789SVille Syrjälä ret = -ENOSPC; 249142ef8789SVille Syrjälä goto out; 249242ef8789SVille Syrjälä } 249342ef8789SVille Syrjälä 24943d30a59bSDaniel Vetter plane->old_fb = plane->fb; 24958cf5c917SJesse Barnes ret = plane->funcs->update_plane(plane, crtc, fb, 2496b36552b3SMatt Roper crtc_x, crtc_y, crtc_w, crtc_h, 2497b36552b3SMatt Roper src_x, src_y, src_w, src_h); 24988cf5c917SJesse Barnes if (!ret) { 24998cf5c917SJesse Barnes plane->crtc = crtc; 25008cf5c917SJesse Barnes plane->fb = fb; 250135f8badcSDaniel Vetter fb = NULL; 25020fe27f06SDaniel Vetter } else { 25033d30a59bSDaniel Vetter plane->old_fb = NULL; 25048cf5c917SJesse Barnes } 25058cf5c917SJesse Barnes 25068cf5c917SJesse Barnes out: 25076c2a7532SDaniel Vetter if (fb) 25086c2a7532SDaniel Vetter drm_framebuffer_unreference(fb); 25093d30a59bSDaniel Vetter if (plane->old_fb) 25103d30a59bSDaniel Vetter drm_framebuffer_unreference(plane->old_fb); 25113d30a59bSDaniel Vetter plane->old_fb = NULL; 25128cf5c917SJesse Barnes 25138cf5c917SJesse Barnes return ret; 2514f2b50c11SDaniel Vetter } 2515b36552b3SMatt Roper 2516f2b50c11SDaniel Vetter static int setplane_internal(struct drm_plane *plane, 2517f2b50c11SDaniel Vetter struct drm_crtc *crtc, 2518f2b50c11SDaniel Vetter struct drm_framebuffer *fb, 2519f2b50c11SDaniel Vetter int32_t crtc_x, int32_t crtc_y, 2520f2b50c11SDaniel Vetter uint32_t crtc_w, uint32_t crtc_h, 2521f2b50c11SDaniel Vetter /* src_{x,y,w,h} values are 16.16 fixed point */ 2522f2b50c11SDaniel Vetter uint32_t src_x, uint32_t src_y, 2523f2b50c11SDaniel Vetter uint32_t src_w, uint32_t src_h) 2524f2b50c11SDaniel Vetter { 2525f2b50c11SDaniel Vetter int ret; 2526f2b50c11SDaniel Vetter 2527f2b50c11SDaniel Vetter drm_modeset_lock_all(plane->dev); 2528f2b50c11SDaniel Vetter ret = __setplane_internal(plane, crtc, fb, 2529f2b50c11SDaniel Vetter crtc_x, crtc_y, crtc_w, crtc_h, 2530f2b50c11SDaniel Vetter src_x, src_y, src_w, src_h); 2531f2b50c11SDaniel Vetter drm_modeset_unlock_all(plane->dev); 2532f2b50c11SDaniel Vetter 2533f2b50c11SDaniel Vetter return ret; 2534b36552b3SMatt Roper } 2535b36552b3SMatt Roper 2536b36552b3SMatt Roper /** 2537b36552b3SMatt Roper * drm_mode_setplane - configure a plane's configuration 2538b36552b3SMatt Roper * @dev: DRM device 2539b36552b3SMatt Roper * @data: ioctl data* 2540b36552b3SMatt Roper * @file_priv: DRM file info 2541b36552b3SMatt Roper * 2542b36552b3SMatt Roper * Set plane configuration, including placement, fb, scaling, and other factors. 2543b36552b3SMatt Roper * Or pass a NULL fb to disable (planes may be disabled without providing a 2544b36552b3SMatt Roper * valid crtc). 2545b36552b3SMatt Roper * 2546b36552b3SMatt Roper * Returns: 25471a498633SDaniel Vetter * Zero on success, negative errno on failure. 2548b36552b3SMatt Roper */ 2549b36552b3SMatt Roper int drm_mode_setplane(struct drm_device *dev, void *data, 2550b36552b3SMatt Roper struct drm_file *file_priv) 2551b36552b3SMatt Roper { 2552b36552b3SMatt Roper struct drm_mode_set_plane *plane_req = data; 2553b36552b3SMatt Roper struct drm_plane *plane; 2554b36552b3SMatt Roper struct drm_crtc *crtc = NULL; 2555b36552b3SMatt Roper struct drm_framebuffer *fb = NULL; 2556b36552b3SMatt Roper 2557b36552b3SMatt Roper if (!drm_core_check_feature(dev, DRIVER_MODESET)) 2558b36552b3SMatt Roper return -EINVAL; 2559b36552b3SMatt Roper 2560b36552b3SMatt Roper /* Give drivers some help against integer overflows */ 2561b36552b3SMatt Roper if (plane_req->crtc_w > INT_MAX || 2562b36552b3SMatt Roper plane_req->crtc_x > INT_MAX - (int32_t) plane_req->crtc_w || 2563b36552b3SMatt Roper plane_req->crtc_h > INT_MAX || 2564b36552b3SMatt Roper plane_req->crtc_y > INT_MAX - (int32_t) plane_req->crtc_h) { 2565b36552b3SMatt Roper DRM_DEBUG_KMS("Invalid CRTC coordinates %ux%u+%d+%d\n", 2566b36552b3SMatt Roper plane_req->crtc_w, plane_req->crtc_h, 2567b36552b3SMatt Roper plane_req->crtc_x, plane_req->crtc_y); 2568b36552b3SMatt Roper return -ERANGE; 2569b36552b3SMatt Roper } 2570b36552b3SMatt Roper 2571b36552b3SMatt Roper /* 2572b36552b3SMatt Roper * First, find the plane, crtc, and fb objects. If not available, 2573b36552b3SMatt Roper * we don't bother to call the driver. 2574b36552b3SMatt Roper */ 2575933f622fSRob Clark plane = drm_plane_find(dev, plane_req->plane_id); 2576933f622fSRob Clark if (!plane) { 2577b36552b3SMatt Roper DRM_DEBUG_KMS("Unknown plane ID %d\n", 2578b36552b3SMatt Roper plane_req->plane_id); 2579b36552b3SMatt Roper return -ENOENT; 2580b36552b3SMatt Roper } 2581b36552b3SMatt Roper 2582b36552b3SMatt Roper if (plane_req->fb_id) { 2583b36552b3SMatt Roper fb = drm_framebuffer_lookup(dev, plane_req->fb_id); 2584b36552b3SMatt Roper if (!fb) { 2585b36552b3SMatt Roper DRM_DEBUG_KMS("Unknown framebuffer ID %d\n", 2586b36552b3SMatt Roper plane_req->fb_id); 2587b36552b3SMatt Roper return -ENOENT; 2588b36552b3SMatt Roper } 2589b36552b3SMatt Roper 2590933f622fSRob Clark crtc = drm_crtc_find(dev, plane_req->crtc_id); 2591933f622fSRob Clark if (!crtc) { 2592b36552b3SMatt Roper DRM_DEBUG_KMS("Unknown crtc ID %d\n", 2593b36552b3SMatt Roper plane_req->crtc_id); 2594b36552b3SMatt Roper return -ENOENT; 2595b36552b3SMatt Roper } 2596b36552b3SMatt Roper } 2597b36552b3SMatt Roper 2598161d0dc1SMatt Roper /* 2599161d0dc1SMatt Roper * setplane_internal will take care of deref'ing either the old or new 2600161d0dc1SMatt Roper * framebuffer depending on success. 2601161d0dc1SMatt Roper */ 260217cfd91fSChris Wilson return setplane_internal(plane, crtc, fb, 2603b36552b3SMatt Roper plane_req->crtc_x, plane_req->crtc_y, 2604b36552b3SMatt Roper plane_req->crtc_w, plane_req->crtc_h, 2605b36552b3SMatt Roper plane_req->src_x, plane_req->src_y, 2606b36552b3SMatt Roper plane_req->src_w, plane_req->src_h); 26078cf5c917SJesse Barnes } 26088cf5c917SJesse Barnes 26098cf5c917SJesse Barnes /** 26102d13b679SDaniel Vetter * drm_mode_set_config_internal - helper to call ->set_config 26112d13b679SDaniel Vetter * @set: modeset config to set 26122d13b679SDaniel Vetter * 26132d13b679SDaniel Vetter * This is a little helper to wrap internal calls to the ->set_config driver 26142d13b679SDaniel Vetter * interface. The only thing it adds is correct refcounting dance. 2615c8e32cc1SDaniel Vetter * 2616c8e32cc1SDaniel Vetter * Returns: 26171a498633SDaniel Vetter * Zero on success, negative errno on failure. 26182d13b679SDaniel Vetter */ 26192d13b679SDaniel Vetter int drm_mode_set_config_internal(struct drm_mode_set *set) 26202d13b679SDaniel Vetter { 26212d13b679SDaniel Vetter struct drm_crtc *crtc = set->crtc; 26225cef29aaSDaniel Vetter struct drm_framebuffer *fb; 26235cef29aaSDaniel Vetter struct drm_crtc *tmp; 2624b0d12325SDaniel Vetter int ret; 26252d13b679SDaniel Vetter 26265cef29aaSDaniel Vetter /* 26275cef29aaSDaniel Vetter * NOTE: ->set_config can also disable other crtcs (if we steal all 26285cef29aaSDaniel Vetter * connectors from it), hence we need to refcount the fbs across all 26295cef29aaSDaniel Vetter * crtcs. Atomic modeset will have saner semantics ... 26305cef29aaSDaniel Vetter */ 26315cef29aaSDaniel Vetter list_for_each_entry(tmp, &crtc->dev->mode_config.crtc_list, head) 26323d30a59bSDaniel Vetter tmp->primary->old_fb = tmp->primary->fb; 26335cef29aaSDaniel Vetter 2634b0d12325SDaniel Vetter fb = set->fb; 2635b0d12325SDaniel Vetter 2636b0d12325SDaniel Vetter ret = crtc->funcs->set_config(set); 2637b0d12325SDaniel Vetter if (ret == 0) { 2638e13161afSMatt Roper crtc->primary->crtc = crtc; 26390fe27f06SDaniel Vetter crtc->primary->fb = fb; 26405cef29aaSDaniel Vetter } 2641cc85e121SDaniel Vetter 26425cef29aaSDaniel Vetter list_for_each_entry(tmp, &crtc->dev->mode_config.crtc_list, head) { 2643f4510a27SMatt Roper if (tmp->primary->fb) 2644f4510a27SMatt Roper drm_framebuffer_reference(tmp->primary->fb); 26453d30a59bSDaniel Vetter if (tmp->primary->old_fb) 26463d30a59bSDaniel Vetter drm_framebuffer_unreference(tmp->primary->old_fb); 26473d30a59bSDaniel Vetter tmp->primary->old_fb = NULL; 2648b0d12325SDaniel Vetter } 2649b0d12325SDaniel Vetter 2650b0d12325SDaniel Vetter return ret; 26512d13b679SDaniel Vetter } 26522d13b679SDaniel Vetter EXPORT_SYMBOL(drm_mode_set_config_internal); 26532d13b679SDaniel Vetter 2654af93629dSMatt Roper /** 2655ecb7e16bSGustavo Padovan * drm_crtc_get_hv_timing - Fetches hdisplay/vdisplay for given mode 2656ecb7e16bSGustavo Padovan * @mode: mode to query 2657ecb7e16bSGustavo Padovan * @hdisplay: hdisplay value to fill in 2658ecb7e16bSGustavo Padovan * @vdisplay: vdisplay value to fill in 2659ecb7e16bSGustavo Padovan * 2660ecb7e16bSGustavo Padovan * The vdisplay value will be doubled if the specified mode is a stereo mode of 2661ecb7e16bSGustavo Padovan * the appropriate layout. 2662ecb7e16bSGustavo Padovan */ 2663ecb7e16bSGustavo Padovan void drm_crtc_get_hv_timing(const struct drm_display_mode *mode, 2664ecb7e16bSGustavo Padovan int *hdisplay, int *vdisplay) 2665ecb7e16bSGustavo Padovan { 2666ecb7e16bSGustavo Padovan struct drm_display_mode adjusted; 2667ecb7e16bSGustavo Padovan 2668ecb7e16bSGustavo Padovan drm_mode_copy(&adjusted, mode); 2669ecb7e16bSGustavo Padovan drm_mode_set_crtcinfo(&adjusted, CRTC_STEREO_DOUBLE_ONLY); 2670ecb7e16bSGustavo Padovan *hdisplay = adjusted.crtc_hdisplay; 2671ecb7e16bSGustavo Padovan *vdisplay = adjusted.crtc_vdisplay; 2672ecb7e16bSGustavo Padovan } 2673ecb7e16bSGustavo Padovan EXPORT_SYMBOL(drm_crtc_get_hv_timing); 2674ecb7e16bSGustavo Padovan 2675ecb7e16bSGustavo Padovan /** 2676af93629dSMatt Roper * drm_crtc_check_viewport - Checks that a framebuffer is big enough for the 2677af93629dSMatt Roper * CRTC viewport 2678af93629dSMatt Roper * @crtc: CRTC that framebuffer will be displayed on 2679af93629dSMatt Roper * @x: x panning 2680af93629dSMatt Roper * @y: y panning 2681af93629dSMatt Roper * @mode: mode that framebuffer will be displayed under 2682af93629dSMatt Roper * @fb: framebuffer to check size of 2683c11e9283SDamien Lespiau */ 2684af93629dSMatt Roper int drm_crtc_check_viewport(const struct drm_crtc *crtc, 2685c11e9283SDamien Lespiau int x, int y, 2686c11e9283SDamien Lespiau const struct drm_display_mode *mode, 2687c11e9283SDamien Lespiau const struct drm_framebuffer *fb) 2688c11e9283SDamien Lespiau 2689c11e9283SDamien Lespiau { 2690c11e9283SDamien Lespiau int hdisplay, vdisplay; 2691c11e9283SDamien Lespiau 2692ecb7e16bSGustavo Padovan drm_crtc_get_hv_timing(mode, &hdisplay, &vdisplay); 2693a0c1bbb0SDamien Lespiau 2694c11e9283SDamien Lespiau if (crtc->invert_dimensions) 2695c11e9283SDamien Lespiau swap(hdisplay, vdisplay); 2696c11e9283SDamien Lespiau 2697c11e9283SDamien Lespiau if (hdisplay > fb->width || 2698c11e9283SDamien Lespiau vdisplay > fb->height || 2699c11e9283SDamien Lespiau x > fb->width - hdisplay || 2700c11e9283SDamien Lespiau y > fb->height - vdisplay) { 2701c11e9283SDamien Lespiau DRM_DEBUG_KMS("Invalid fb size %ux%u for CRTC viewport %ux%u+%d+%d%s.\n", 2702c11e9283SDamien Lespiau fb->width, fb->height, hdisplay, vdisplay, x, y, 2703c11e9283SDamien Lespiau crtc->invert_dimensions ? " (inverted)" : ""); 2704c11e9283SDamien Lespiau return -ENOSPC; 2705c11e9283SDamien Lespiau } 2706c11e9283SDamien Lespiau 2707c11e9283SDamien Lespiau return 0; 2708c11e9283SDamien Lespiau } 2709af93629dSMatt Roper EXPORT_SYMBOL(drm_crtc_check_viewport); 2710c11e9283SDamien Lespiau 27112d13b679SDaniel Vetter /** 2712f453ba04SDave Airlie * drm_mode_setcrtc - set CRTC configuration 2713065a50edSDaniel Vetter * @dev: drm device for the ioctl 2714065a50edSDaniel Vetter * @data: data pointer for the ioctl 2715065a50edSDaniel Vetter * @file_priv: drm file for the ioctl call 2716f453ba04SDave Airlie * 2717f453ba04SDave Airlie * Build a new CRTC configuration based on user request. 2718f453ba04SDave Airlie * 2719f453ba04SDave Airlie * Called by the user via ioctl. 2720f453ba04SDave Airlie * 2721c8e32cc1SDaniel Vetter * Returns: 27221a498633SDaniel Vetter * Zero on success, negative errno on failure. 2723f453ba04SDave Airlie */ 2724f453ba04SDave Airlie int drm_mode_setcrtc(struct drm_device *dev, void *data, 2725f453ba04SDave Airlie struct drm_file *file_priv) 2726f453ba04SDave Airlie { 2727f453ba04SDave Airlie struct drm_mode_config *config = &dev->mode_config; 2728f453ba04SDave Airlie struct drm_mode_crtc *crtc_req = data; 27296653cc8dSVille Syrjälä struct drm_crtc *crtc; 2730f453ba04SDave Airlie struct drm_connector **connector_set = NULL, *connector; 2731f453ba04SDave Airlie struct drm_framebuffer *fb = NULL; 2732f453ba04SDave Airlie struct drm_display_mode *mode = NULL; 2733f453ba04SDave Airlie struct drm_mode_set set; 2734f453ba04SDave Airlie uint32_t __user *set_connectors_ptr; 27354a1b0714SLaurent Pinchart int ret; 2736f453ba04SDave Airlie int i; 2737f453ba04SDave Airlie 2738fb3b06c8SDave Airlie if (!drm_core_check_feature(dev, DRIVER_MODESET)) 2739fb3b06c8SDave Airlie return -EINVAL; 2740fb3b06c8SDave Airlie 27411d97e915SVille Syrjälä /* For some reason crtc x/y offsets are signed internally. */ 27421d97e915SVille Syrjälä if (crtc_req->x > INT_MAX || crtc_req->y > INT_MAX) 27431d97e915SVille Syrjälä return -ERANGE; 27441d97e915SVille Syrjälä 274584849903SDaniel Vetter drm_modeset_lock_all(dev); 2746a2b34e22SRob Clark crtc = drm_crtc_find(dev, crtc_req->crtc_id); 2747a2b34e22SRob Clark if (!crtc) { 274858367ed6SZhao Yakui DRM_DEBUG_KMS("Unknown CRTC ID %d\n", crtc_req->crtc_id); 2749f27657f2SVille Syrjälä ret = -ENOENT; 2750f453ba04SDave Airlie goto out; 2751f453ba04SDave Airlie } 27529440106bSJerome Glisse DRM_DEBUG_KMS("[CRTC:%d]\n", crtc->base.id); 2753f453ba04SDave Airlie 2754f453ba04SDave Airlie if (crtc_req->mode_valid) { 2755f453ba04SDave Airlie /* If we have a mode we need a framebuffer. */ 2756f453ba04SDave Airlie /* If we pass -1, set the mode with the currently bound fb */ 2757f453ba04SDave Airlie if (crtc_req->fb_id == -1) { 2758f4510a27SMatt Roper if (!crtc->primary->fb) { 27596653cc8dSVille Syrjälä DRM_DEBUG_KMS("CRTC doesn't have current FB\n"); 27606653cc8dSVille Syrjälä ret = -EINVAL; 27616653cc8dSVille Syrjälä goto out; 27626653cc8dSVille Syrjälä } 2763f4510a27SMatt Roper fb = crtc->primary->fb; 2764b0d12325SDaniel Vetter /* Make refcounting symmetric with the lookup path. */ 2765b0d12325SDaniel Vetter drm_framebuffer_reference(fb); 2766f453ba04SDave Airlie } else { 2767786b99edSDaniel Vetter fb = drm_framebuffer_lookup(dev, crtc_req->fb_id); 2768786b99edSDaniel Vetter if (!fb) { 276958367ed6SZhao Yakui DRM_DEBUG_KMS("Unknown FB ID%d\n", 277058367ed6SZhao Yakui crtc_req->fb_id); 277137c4e705SVille Syrjälä ret = -ENOENT; 2772f453ba04SDave Airlie goto out; 2773f453ba04SDave Airlie } 2774f453ba04SDave Airlie } 2775f453ba04SDave Airlie 2776f453ba04SDave Airlie mode = drm_mode_create(dev); 2777ee34ab5bSVille Syrjälä if (!mode) { 2778ee34ab5bSVille Syrjälä ret = -ENOMEM; 2779ee34ab5bSVille Syrjälä goto out; 2780ee34ab5bSVille Syrjälä } 2781ee34ab5bSVille Syrjälä 278290367bf6SVille Syrjälä ret = drm_crtc_convert_umode(mode, &crtc_req->mode); 278390367bf6SVille Syrjälä if (ret) { 278490367bf6SVille Syrjälä DRM_DEBUG_KMS("Invalid mode\n"); 278590367bf6SVille Syrjälä goto out; 278690367bf6SVille Syrjälä } 278790367bf6SVille Syrjälä 278823e1ce89SVille Syrjälä mode->status = drm_mode_validate_basic(mode); 278923e1ce89SVille Syrjälä if (mode->status != MODE_OK) { 279023e1ce89SVille Syrjälä ret = -EINVAL; 279123e1ce89SVille Syrjälä goto out; 279223e1ce89SVille Syrjälä } 279323e1ce89SVille Syrjälä 2794f453ba04SDave Airlie drm_mode_set_crtcinfo(mode, CRTC_INTERLACE_HALVE_V); 27955f61bb42SVille Syrjälä 2796c11e9283SDamien Lespiau ret = drm_crtc_check_viewport(crtc, crtc_req->x, crtc_req->y, 2797c11e9283SDamien Lespiau mode, fb); 2798c11e9283SDamien Lespiau if (ret) 27995f61bb42SVille Syrjälä goto out; 2800c11e9283SDamien Lespiau 2801f453ba04SDave Airlie } 2802f453ba04SDave Airlie 2803f453ba04SDave Airlie if (crtc_req->count_connectors == 0 && mode) { 280458367ed6SZhao Yakui DRM_DEBUG_KMS("Count connectors is 0 but mode set\n"); 2805f453ba04SDave Airlie ret = -EINVAL; 2806f453ba04SDave Airlie goto out; 2807f453ba04SDave Airlie } 2808f453ba04SDave Airlie 28097781de74SJakob Bornecrantz if (crtc_req->count_connectors > 0 && (!mode || !fb)) { 281058367ed6SZhao Yakui DRM_DEBUG_KMS("Count connectors is %d but no mode or fb set\n", 2811f453ba04SDave Airlie crtc_req->count_connectors); 2812f453ba04SDave Airlie ret = -EINVAL; 2813f453ba04SDave Airlie goto out; 2814f453ba04SDave Airlie } 2815f453ba04SDave Airlie 2816f453ba04SDave Airlie if (crtc_req->count_connectors > 0) { 2817f453ba04SDave Airlie u32 out_id; 2818f453ba04SDave Airlie 2819f453ba04SDave Airlie /* Avoid unbounded kernel memory allocation */ 2820f453ba04SDave Airlie if (crtc_req->count_connectors > config->num_connector) { 2821f453ba04SDave Airlie ret = -EINVAL; 2822f453ba04SDave Airlie goto out; 2823f453ba04SDave Airlie } 2824f453ba04SDave Airlie 28252f6c5389SThierry Reding connector_set = kmalloc_array(crtc_req->count_connectors, 2826f453ba04SDave Airlie sizeof(struct drm_connector *), 2827f453ba04SDave Airlie GFP_KERNEL); 2828f453ba04SDave Airlie if (!connector_set) { 2829f453ba04SDave Airlie ret = -ENOMEM; 2830f453ba04SDave Airlie goto out; 2831f453ba04SDave Airlie } 2832f453ba04SDave Airlie 2833f453ba04SDave Airlie for (i = 0; i < crtc_req->count_connectors; i++) { 283481f6c7f8SVille Syrjälä set_connectors_ptr = (uint32_t __user *)(unsigned long)crtc_req->set_connectors_ptr; 2835f453ba04SDave Airlie if (get_user(out_id, &set_connectors_ptr[i])) { 2836f453ba04SDave Airlie ret = -EFAULT; 2837f453ba04SDave Airlie goto out; 2838f453ba04SDave Airlie } 2839f453ba04SDave Airlie 2840a2b34e22SRob Clark connector = drm_connector_find(dev, out_id); 2841a2b34e22SRob Clark if (!connector) { 284258367ed6SZhao Yakui DRM_DEBUG_KMS("Connector id %d unknown\n", 284358367ed6SZhao Yakui out_id); 2844f27657f2SVille Syrjälä ret = -ENOENT; 2845f453ba04SDave Airlie goto out; 2846f453ba04SDave Airlie } 28479440106bSJerome Glisse DRM_DEBUG_KMS("[CONNECTOR:%d:%s]\n", 28489440106bSJerome Glisse connector->base.id, 284925933820SJani Nikula connector->name); 2850f453ba04SDave Airlie 2851f453ba04SDave Airlie connector_set[i] = connector; 2852f453ba04SDave Airlie } 2853f453ba04SDave Airlie } 2854f453ba04SDave Airlie 2855f453ba04SDave Airlie set.crtc = crtc; 2856f453ba04SDave Airlie set.x = crtc_req->x; 2857f453ba04SDave Airlie set.y = crtc_req->y; 2858f453ba04SDave Airlie set.mode = mode; 2859f453ba04SDave Airlie set.connectors = connector_set; 2860f453ba04SDave Airlie set.num_connectors = crtc_req->count_connectors; 2861f453ba04SDave Airlie set.fb = fb; 28622d13b679SDaniel Vetter ret = drm_mode_set_config_internal(&set); 2863f453ba04SDave Airlie 2864f453ba04SDave Airlie out: 2865b0d12325SDaniel Vetter if (fb) 2866b0d12325SDaniel Vetter drm_framebuffer_unreference(fb); 2867b0d12325SDaniel Vetter 2868f453ba04SDave Airlie kfree(connector_set); 2869ee34ab5bSVille Syrjälä drm_mode_destroy(dev, mode); 287084849903SDaniel Vetter drm_modeset_unlock_all(dev); 2871f453ba04SDave Airlie return ret; 2872f453ba04SDave Airlie } 2873f453ba04SDave Airlie 2874161d0dc1SMatt Roper /** 2875161d0dc1SMatt Roper * drm_mode_cursor_universal - translate legacy cursor ioctl call into a 2876161d0dc1SMatt Roper * universal plane handler call 2877161d0dc1SMatt Roper * @crtc: crtc to update cursor for 2878161d0dc1SMatt Roper * @req: data pointer for the ioctl 2879161d0dc1SMatt Roper * @file_priv: drm file for the ioctl call 2880161d0dc1SMatt Roper * 2881161d0dc1SMatt Roper * Legacy cursor ioctl's work directly with driver buffer handles. To 2882161d0dc1SMatt Roper * translate legacy ioctl calls into universal plane handler calls, we need to 2883161d0dc1SMatt Roper * wrap the native buffer handle in a drm_framebuffer. 2884161d0dc1SMatt Roper * 2885161d0dc1SMatt Roper * Note that we assume any handle passed to the legacy ioctls was a 32-bit ARGB 2886161d0dc1SMatt Roper * buffer with a pitch of 4*width; the universal plane interface should be used 2887161d0dc1SMatt Roper * directly in cases where the hardware can support other buffer settings and 2888161d0dc1SMatt Roper * userspace wants to make use of these capabilities. 2889161d0dc1SMatt Roper * 2890161d0dc1SMatt Roper * Returns: 28911a498633SDaniel Vetter * Zero on success, negative errno on failure. 2892161d0dc1SMatt Roper */ 2893161d0dc1SMatt Roper static int drm_mode_cursor_universal(struct drm_crtc *crtc, 2894161d0dc1SMatt Roper struct drm_mode_cursor2 *req, 2895161d0dc1SMatt Roper struct drm_file *file_priv) 2896161d0dc1SMatt Roper { 2897161d0dc1SMatt Roper struct drm_device *dev = crtc->dev; 2898161d0dc1SMatt Roper struct drm_framebuffer *fb = NULL; 2899161d0dc1SMatt Roper struct drm_mode_fb_cmd2 fbreq = { 2900161d0dc1SMatt Roper .width = req->width, 2901161d0dc1SMatt Roper .height = req->height, 2902161d0dc1SMatt Roper .pixel_format = DRM_FORMAT_ARGB8888, 2903161d0dc1SMatt Roper .pitches = { req->width * 4 }, 2904161d0dc1SMatt Roper .handles = { req->handle }, 2905161d0dc1SMatt Roper }; 2906161d0dc1SMatt Roper int32_t crtc_x, crtc_y; 2907161d0dc1SMatt Roper uint32_t crtc_w = 0, crtc_h = 0; 2908161d0dc1SMatt Roper uint32_t src_w = 0, src_h = 0; 2909161d0dc1SMatt Roper int ret = 0; 2910161d0dc1SMatt Roper 2911161d0dc1SMatt Roper BUG_ON(!crtc->cursor); 2912f2b50c11SDaniel Vetter WARN_ON(crtc->cursor->crtc != crtc && crtc->cursor->crtc != NULL); 2913161d0dc1SMatt Roper 2914161d0dc1SMatt Roper /* 2915161d0dc1SMatt Roper * Obtain fb we'll be using (either new or existing) and take an extra 2916161d0dc1SMatt Roper * reference to it if fb != null. setplane will take care of dropping 2917161d0dc1SMatt Roper * the reference if the plane update fails. 2918161d0dc1SMatt Roper */ 2919161d0dc1SMatt Roper if (req->flags & DRM_MODE_CURSOR_BO) { 2920161d0dc1SMatt Roper if (req->handle) { 2921161d0dc1SMatt Roper fb = add_framebuffer_internal(dev, &fbreq, file_priv); 2922161d0dc1SMatt Roper if (IS_ERR(fb)) { 2923161d0dc1SMatt Roper DRM_DEBUG_KMS("failed to wrap cursor buffer in drm framebuffer\n"); 2924161d0dc1SMatt Roper return PTR_ERR(fb); 2925161d0dc1SMatt Roper } 2926161d0dc1SMatt Roper 2927161d0dc1SMatt Roper drm_framebuffer_reference(fb); 2928161d0dc1SMatt Roper } else { 2929161d0dc1SMatt Roper fb = NULL; 2930161d0dc1SMatt Roper } 2931161d0dc1SMatt Roper } else { 2932161d0dc1SMatt Roper fb = crtc->cursor->fb; 2933161d0dc1SMatt Roper if (fb) 2934161d0dc1SMatt Roper drm_framebuffer_reference(fb); 2935161d0dc1SMatt Roper } 2936161d0dc1SMatt Roper 2937161d0dc1SMatt Roper if (req->flags & DRM_MODE_CURSOR_MOVE) { 2938161d0dc1SMatt Roper crtc_x = req->x; 2939161d0dc1SMatt Roper crtc_y = req->y; 2940161d0dc1SMatt Roper } else { 2941161d0dc1SMatt Roper crtc_x = crtc->cursor_x; 2942161d0dc1SMatt Roper crtc_y = crtc->cursor_y; 2943161d0dc1SMatt Roper } 2944161d0dc1SMatt Roper 2945161d0dc1SMatt Roper if (fb) { 2946161d0dc1SMatt Roper crtc_w = fb->width; 2947161d0dc1SMatt Roper crtc_h = fb->height; 2948161d0dc1SMatt Roper src_w = fb->width << 16; 2949161d0dc1SMatt Roper src_h = fb->height << 16; 2950161d0dc1SMatt Roper } 2951161d0dc1SMatt Roper 2952161d0dc1SMatt Roper /* 2953161d0dc1SMatt Roper * setplane_internal will take care of deref'ing either the old or new 2954161d0dc1SMatt Roper * framebuffer depending on success. 2955161d0dc1SMatt Roper */ 2956f2b50c11SDaniel Vetter ret = __setplane_internal(crtc->cursor, crtc, fb, 2957161d0dc1SMatt Roper crtc_x, crtc_y, crtc_w, crtc_h, 2958161d0dc1SMatt Roper 0, 0, src_w, src_h); 2959161d0dc1SMatt Roper 2960161d0dc1SMatt Roper /* Update successful; save new cursor position, if necessary */ 2961161d0dc1SMatt Roper if (ret == 0 && req->flags & DRM_MODE_CURSOR_MOVE) { 2962161d0dc1SMatt Roper crtc->cursor_x = req->x; 2963161d0dc1SMatt Roper crtc->cursor_y = req->y; 2964161d0dc1SMatt Roper } 2965161d0dc1SMatt Roper 2966161d0dc1SMatt Roper return ret; 2967161d0dc1SMatt Roper } 2968161d0dc1SMatt Roper 29694c813d4dSDave Airlie static int drm_mode_cursor_common(struct drm_device *dev, 29704c813d4dSDave Airlie struct drm_mode_cursor2 *req, 29714c813d4dSDave Airlie struct drm_file *file_priv) 2972f453ba04SDave Airlie { 2973f453ba04SDave Airlie struct drm_crtc *crtc; 2974f453ba04SDave Airlie int ret = 0; 2975f453ba04SDave Airlie 2976fb3b06c8SDave Airlie if (!drm_core_check_feature(dev, DRIVER_MODESET)) 2977fb3b06c8SDave Airlie return -EINVAL; 2978fb3b06c8SDave Airlie 29797c4eaca4SJakob Bornecrantz if (!req->flags || (~DRM_MODE_CURSOR_FLAGS & req->flags)) 2980f453ba04SDave Airlie return -EINVAL; 2981f453ba04SDave Airlie 2982a2b34e22SRob Clark crtc = drm_crtc_find(dev, req->crtc_id); 2983a2b34e22SRob Clark if (!crtc) { 298458367ed6SZhao Yakui DRM_DEBUG_KMS("Unknown CRTC ID %d\n", req->crtc_id); 2985f27657f2SVille Syrjälä return -ENOENT; 2986f453ba04SDave Airlie } 2987f453ba04SDave Airlie 2988161d0dc1SMatt Roper /* 2989161d0dc1SMatt Roper * If this crtc has a universal cursor plane, call that plane's update 2990161d0dc1SMatt Roper * handler rather than using legacy cursor handlers. 2991161d0dc1SMatt Roper */ 29924d02e2deSDaniel Vetter drm_modeset_lock_crtc(crtc, crtc->cursor); 2993f2b50c11SDaniel Vetter if (crtc->cursor) { 2994f2b50c11SDaniel Vetter ret = drm_mode_cursor_universal(crtc, req, file_priv); 2995f2b50c11SDaniel Vetter goto out; 2996f2b50c11SDaniel Vetter } 2997f2b50c11SDaniel Vetter 2998f453ba04SDave Airlie if (req->flags & DRM_MODE_CURSOR_BO) { 29994c813d4dSDave Airlie if (!crtc->funcs->cursor_set && !crtc->funcs->cursor_set2) { 3000f453ba04SDave Airlie ret = -ENXIO; 3001f453ba04SDave Airlie goto out; 3002f453ba04SDave Airlie } 3003f453ba04SDave Airlie /* Turns off the cursor if handle is 0 */ 30044c813d4dSDave Airlie if (crtc->funcs->cursor_set2) 30054c813d4dSDave Airlie ret = crtc->funcs->cursor_set2(crtc, file_priv, req->handle, 30064c813d4dSDave Airlie req->width, req->height, req->hot_x, req->hot_y); 30074c813d4dSDave Airlie else 3008f453ba04SDave Airlie ret = crtc->funcs->cursor_set(crtc, file_priv, req->handle, 3009f453ba04SDave Airlie req->width, req->height); 3010f453ba04SDave Airlie } 3011f453ba04SDave Airlie 3012f453ba04SDave Airlie if (req->flags & DRM_MODE_CURSOR_MOVE) { 3013f453ba04SDave Airlie if (crtc->funcs->cursor_move) { 3014f453ba04SDave Airlie ret = crtc->funcs->cursor_move(crtc, req->x, req->y); 3015f453ba04SDave Airlie } else { 3016f453ba04SDave Airlie ret = -EFAULT; 3017f453ba04SDave Airlie goto out; 3018f453ba04SDave Airlie } 3019f453ba04SDave Airlie } 3020f453ba04SDave Airlie out: 3021d059f652SDaniel Vetter drm_modeset_unlock_crtc(crtc); 3022dac35663SDaniel Vetter 3023f453ba04SDave Airlie return ret; 30244c813d4dSDave Airlie 30254c813d4dSDave Airlie } 3026c8e32cc1SDaniel Vetter 3027c8e32cc1SDaniel Vetter 3028c8e32cc1SDaniel Vetter /** 3029c8e32cc1SDaniel Vetter * drm_mode_cursor_ioctl - set CRTC's cursor configuration 3030c8e32cc1SDaniel Vetter * @dev: drm device for the ioctl 3031c8e32cc1SDaniel Vetter * @data: data pointer for the ioctl 3032c8e32cc1SDaniel Vetter * @file_priv: drm file for the ioctl call 3033c8e32cc1SDaniel Vetter * 3034c8e32cc1SDaniel Vetter * Set the cursor configuration based on user request. 3035c8e32cc1SDaniel Vetter * 3036c8e32cc1SDaniel Vetter * Called by the user via ioctl. 3037c8e32cc1SDaniel Vetter * 3038c8e32cc1SDaniel Vetter * Returns: 30391a498633SDaniel Vetter * Zero on success, negative errno on failure. 3040c8e32cc1SDaniel Vetter */ 30414c813d4dSDave Airlie int drm_mode_cursor_ioctl(struct drm_device *dev, 30424c813d4dSDave Airlie void *data, struct drm_file *file_priv) 30434c813d4dSDave Airlie { 30444c813d4dSDave Airlie struct drm_mode_cursor *req = data; 30454c813d4dSDave Airlie struct drm_mode_cursor2 new_req; 30464c813d4dSDave Airlie 30474c813d4dSDave Airlie memcpy(&new_req, req, sizeof(struct drm_mode_cursor)); 30484c813d4dSDave Airlie new_req.hot_x = new_req.hot_y = 0; 30494c813d4dSDave Airlie 30504c813d4dSDave Airlie return drm_mode_cursor_common(dev, &new_req, file_priv); 30514c813d4dSDave Airlie } 30524c813d4dSDave Airlie 3053c8e32cc1SDaniel Vetter /** 3054c8e32cc1SDaniel Vetter * drm_mode_cursor2_ioctl - set CRTC's cursor configuration 3055c8e32cc1SDaniel Vetter * @dev: drm device for the ioctl 3056c8e32cc1SDaniel Vetter * @data: data pointer for the ioctl 3057c8e32cc1SDaniel Vetter * @file_priv: drm file for the ioctl call 3058c8e32cc1SDaniel Vetter * 3059c8e32cc1SDaniel Vetter * Set the cursor configuration based on user request. This implements the 2nd 3060c8e32cc1SDaniel Vetter * version of the cursor ioctl, which allows userspace to additionally specify 3061c8e32cc1SDaniel Vetter * the hotspot of the pointer. 3062c8e32cc1SDaniel Vetter * 3063c8e32cc1SDaniel Vetter * Called by the user via ioctl. 3064c8e32cc1SDaniel Vetter * 3065c8e32cc1SDaniel Vetter * Returns: 30661a498633SDaniel Vetter * Zero on success, negative errno on failure. 3067c8e32cc1SDaniel Vetter */ 30684c813d4dSDave Airlie int drm_mode_cursor2_ioctl(struct drm_device *dev, 30694c813d4dSDave Airlie void *data, struct drm_file *file_priv) 30704c813d4dSDave Airlie { 30714c813d4dSDave Airlie struct drm_mode_cursor2 *req = data; 30724dfd909fSThierry Reding 30734c813d4dSDave Airlie return drm_mode_cursor_common(dev, req, file_priv); 3074f453ba04SDave Airlie } 3075f453ba04SDave Airlie 3076c8e32cc1SDaniel Vetter /** 3077c8e32cc1SDaniel Vetter * drm_mode_legacy_fb_format - compute drm fourcc code from legacy description 3078c8e32cc1SDaniel Vetter * @bpp: bits per pixels 3079c8e32cc1SDaniel Vetter * @depth: bit depth per pixel 3080c8e32cc1SDaniel Vetter * 3081c8e32cc1SDaniel Vetter * Computes a drm fourcc pixel format code for the given @bpp/@depth values. 3082c8e32cc1SDaniel Vetter * Useful in fbdev emulation code, since that deals in those values. 3083c8e32cc1SDaniel Vetter */ 3084308e5bcbSJesse Barnes uint32_t drm_mode_legacy_fb_format(uint32_t bpp, uint32_t depth) 3085308e5bcbSJesse Barnes { 3086308e5bcbSJesse Barnes uint32_t fmt; 3087308e5bcbSJesse Barnes 3088308e5bcbSJesse Barnes switch (bpp) { 3089308e5bcbSJesse Barnes case 8: 3090d84f031bSVille Syrjälä fmt = DRM_FORMAT_C8; 3091308e5bcbSJesse Barnes break; 3092308e5bcbSJesse Barnes case 16: 3093308e5bcbSJesse Barnes if (depth == 15) 309404b3924dSVille Syrjälä fmt = DRM_FORMAT_XRGB1555; 3095308e5bcbSJesse Barnes else 309604b3924dSVille Syrjälä fmt = DRM_FORMAT_RGB565; 3097308e5bcbSJesse Barnes break; 3098308e5bcbSJesse Barnes case 24: 309904b3924dSVille Syrjälä fmt = DRM_FORMAT_RGB888; 3100308e5bcbSJesse Barnes break; 3101308e5bcbSJesse Barnes case 32: 3102308e5bcbSJesse Barnes if (depth == 24) 310304b3924dSVille Syrjälä fmt = DRM_FORMAT_XRGB8888; 3104308e5bcbSJesse Barnes else if (depth == 30) 310504b3924dSVille Syrjälä fmt = DRM_FORMAT_XRGB2101010; 3106308e5bcbSJesse Barnes else 310704b3924dSVille Syrjälä fmt = DRM_FORMAT_ARGB8888; 3108308e5bcbSJesse Barnes break; 3109308e5bcbSJesse Barnes default: 311004b3924dSVille Syrjälä DRM_ERROR("bad bpp, assuming x8r8g8b8 pixel format\n"); 311104b3924dSVille Syrjälä fmt = DRM_FORMAT_XRGB8888; 3112308e5bcbSJesse Barnes break; 3113308e5bcbSJesse Barnes } 3114308e5bcbSJesse Barnes 3115308e5bcbSJesse Barnes return fmt; 3116308e5bcbSJesse Barnes } 3117308e5bcbSJesse Barnes EXPORT_SYMBOL(drm_mode_legacy_fb_format); 3118308e5bcbSJesse Barnes 3119f453ba04SDave Airlie /** 3120f453ba04SDave Airlie * drm_mode_addfb - add an FB to the graphics configuration 3121065a50edSDaniel Vetter * @dev: drm device for the ioctl 3122065a50edSDaniel Vetter * @data: data pointer for the ioctl 3123065a50edSDaniel Vetter * @file_priv: drm file for the ioctl call 3124f453ba04SDave Airlie * 3125c8e32cc1SDaniel Vetter * Add a new FB to the specified CRTC, given a user request. This is the 3126209f5527SChuck Ebbert * original addfb ioctl which only supported RGB formats. 3127f453ba04SDave Airlie * 3128f453ba04SDave Airlie * Called by the user via ioctl. 3129f453ba04SDave Airlie * 3130c8e32cc1SDaniel Vetter * Returns: 31311a498633SDaniel Vetter * Zero on success, negative errno on failure. 3132f453ba04SDave Airlie */ 3133f453ba04SDave Airlie int drm_mode_addfb(struct drm_device *dev, 3134f453ba04SDave Airlie void *data, struct drm_file *file_priv) 3135f453ba04SDave Airlie { 3136308e5bcbSJesse Barnes struct drm_mode_fb_cmd *or = data; 3137308e5bcbSJesse Barnes struct drm_mode_fb_cmd2 r = {}; 3138228f2cb3SChuck Ebbert int ret; 3139308e5bcbSJesse Barnes 3140228f2cb3SChuck Ebbert /* convert to new format and call new ioctl */ 3141308e5bcbSJesse Barnes r.fb_id = or->fb_id; 3142308e5bcbSJesse Barnes r.width = or->width; 3143308e5bcbSJesse Barnes r.height = or->height; 3144308e5bcbSJesse Barnes r.pitches[0] = or->pitch; 3145308e5bcbSJesse Barnes r.pixel_format = drm_mode_legacy_fb_format(or->bpp, or->depth); 3146308e5bcbSJesse Barnes r.handles[0] = or->handle; 3147308e5bcbSJesse Barnes 3148228f2cb3SChuck Ebbert ret = drm_mode_addfb2(dev, &r, file_priv); 3149228f2cb3SChuck Ebbert if (ret) 3150228f2cb3SChuck Ebbert return ret; 3151308e5bcbSJesse Barnes 3152228f2cb3SChuck Ebbert or->fb_id = r.fb_id; 31534b096ac1SDaniel Vetter 3154baf698b0SDaniel Vetter return 0; 3155308e5bcbSJesse Barnes } 3156308e5bcbSJesse Barnes 3157cff91b62SVille Syrjälä static int format_check(const struct drm_mode_fb_cmd2 *r) 3158935b5977SVille Syrjälä { 3159935b5977SVille Syrjälä uint32_t format = r->pixel_format & ~DRM_FORMAT_BIG_ENDIAN; 3160935b5977SVille Syrjälä 3161935b5977SVille Syrjälä switch (format) { 3162935b5977SVille Syrjälä case DRM_FORMAT_C8: 3163935b5977SVille Syrjälä case DRM_FORMAT_RGB332: 3164935b5977SVille Syrjälä case DRM_FORMAT_BGR233: 3165935b5977SVille Syrjälä case DRM_FORMAT_XRGB4444: 3166935b5977SVille Syrjälä case DRM_FORMAT_XBGR4444: 3167935b5977SVille Syrjälä case DRM_FORMAT_RGBX4444: 3168935b5977SVille Syrjälä case DRM_FORMAT_BGRX4444: 3169935b5977SVille Syrjälä case DRM_FORMAT_ARGB4444: 3170935b5977SVille Syrjälä case DRM_FORMAT_ABGR4444: 3171935b5977SVille Syrjälä case DRM_FORMAT_RGBA4444: 3172935b5977SVille Syrjälä case DRM_FORMAT_BGRA4444: 3173935b5977SVille Syrjälä case DRM_FORMAT_XRGB1555: 3174935b5977SVille Syrjälä case DRM_FORMAT_XBGR1555: 3175935b5977SVille Syrjälä case DRM_FORMAT_RGBX5551: 3176935b5977SVille Syrjälä case DRM_FORMAT_BGRX5551: 3177935b5977SVille Syrjälä case DRM_FORMAT_ARGB1555: 3178935b5977SVille Syrjälä case DRM_FORMAT_ABGR1555: 3179935b5977SVille Syrjälä case DRM_FORMAT_RGBA5551: 3180935b5977SVille Syrjälä case DRM_FORMAT_BGRA5551: 3181935b5977SVille Syrjälä case DRM_FORMAT_RGB565: 3182935b5977SVille Syrjälä case DRM_FORMAT_BGR565: 3183935b5977SVille Syrjälä case DRM_FORMAT_RGB888: 3184935b5977SVille Syrjälä case DRM_FORMAT_BGR888: 3185935b5977SVille Syrjälä case DRM_FORMAT_XRGB8888: 3186935b5977SVille Syrjälä case DRM_FORMAT_XBGR8888: 3187935b5977SVille Syrjälä case DRM_FORMAT_RGBX8888: 3188935b5977SVille Syrjälä case DRM_FORMAT_BGRX8888: 3189935b5977SVille Syrjälä case DRM_FORMAT_ARGB8888: 3190935b5977SVille Syrjälä case DRM_FORMAT_ABGR8888: 3191935b5977SVille Syrjälä case DRM_FORMAT_RGBA8888: 3192935b5977SVille Syrjälä case DRM_FORMAT_BGRA8888: 3193935b5977SVille Syrjälä case DRM_FORMAT_XRGB2101010: 3194935b5977SVille Syrjälä case DRM_FORMAT_XBGR2101010: 3195935b5977SVille Syrjälä case DRM_FORMAT_RGBX1010102: 3196935b5977SVille Syrjälä case DRM_FORMAT_BGRX1010102: 3197935b5977SVille Syrjälä case DRM_FORMAT_ARGB2101010: 3198935b5977SVille Syrjälä case DRM_FORMAT_ABGR2101010: 3199935b5977SVille Syrjälä case DRM_FORMAT_RGBA1010102: 3200935b5977SVille Syrjälä case DRM_FORMAT_BGRA1010102: 3201935b5977SVille Syrjälä case DRM_FORMAT_YUYV: 3202935b5977SVille Syrjälä case DRM_FORMAT_YVYU: 3203935b5977SVille Syrjälä case DRM_FORMAT_UYVY: 3204935b5977SVille Syrjälä case DRM_FORMAT_VYUY: 3205935b5977SVille Syrjälä case DRM_FORMAT_AYUV: 3206935b5977SVille Syrjälä case DRM_FORMAT_NV12: 3207935b5977SVille Syrjälä case DRM_FORMAT_NV21: 3208935b5977SVille Syrjälä case DRM_FORMAT_NV16: 3209935b5977SVille Syrjälä case DRM_FORMAT_NV61: 3210ba623f6aSLaurent Pinchart case DRM_FORMAT_NV24: 3211ba623f6aSLaurent Pinchart case DRM_FORMAT_NV42: 3212935b5977SVille Syrjälä case DRM_FORMAT_YUV410: 3213935b5977SVille Syrjälä case DRM_FORMAT_YVU410: 3214935b5977SVille Syrjälä case DRM_FORMAT_YUV411: 3215935b5977SVille Syrjälä case DRM_FORMAT_YVU411: 3216935b5977SVille Syrjälä case DRM_FORMAT_YUV420: 3217935b5977SVille Syrjälä case DRM_FORMAT_YVU420: 3218935b5977SVille Syrjälä case DRM_FORMAT_YUV422: 3219935b5977SVille Syrjälä case DRM_FORMAT_YVU422: 3220935b5977SVille Syrjälä case DRM_FORMAT_YUV444: 3221935b5977SVille Syrjälä case DRM_FORMAT_YVU444: 3222935b5977SVille Syrjälä return 0; 3223935b5977SVille Syrjälä default: 322423c453a4SVille Syrjälä DRM_DEBUG_KMS("invalid pixel format %s\n", 322523c453a4SVille Syrjälä drm_get_format_name(r->pixel_format)); 3226935b5977SVille Syrjälä return -EINVAL; 3227935b5977SVille Syrjälä } 3228935b5977SVille Syrjälä } 3229935b5977SVille Syrjälä 3230cff91b62SVille Syrjälä static int framebuffer_check(const struct drm_mode_fb_cmd2 *r) 3231d1b45d5fSVille Syrjälä { 3232d1b45d5fSVille Syrjälä int ret, hsub, vsub, num_planes, i; 3233d1b45d5fSVille Syrjälä 3234d1b45d5fSVille Syrjälä ret = format_check(r); 3235d1b45d5fSVille Syrjälä if (ret) { 32366ba6d03eSVille Syrjälä DRM_DEBUG_KMS("bad framebuffer format %s\n", 32376ba6d03eSVille Syrjälä drm_get_format_name(r->pixel_format)); 3238d1b45d5fSVille Syrjälä return ret; 3239d1b45d5fSVille Syrjälä } 3240d1b45d5fSVille Syrjälä 3241d1b45d5fSVille Syrjälä hsub = drm_format_horz_chroma_subsampling(r->pixel_format); 3242d1b45d5fSVille Syrjälä vsub = drm_format_vert_chroma_subsampling(r->pixel_format); 3243d1b45d5fSVille Syrjälä num_planes = drm_format_num_planes(r->pixel_format); 3244d1b45d5fSVille Syrjälä 3245d1b45d5fSVille Syrjälä if (r->width == 0 || r->width % hsub) { 3246209f5527SChuck Ebbert DRM_DEBUG_KMS("bad framebuffer width %u\n", r->width); 3247d1b45d5fSVille Syrjälä return -EINVAL; 3248d1b45d5fSVille Syrjälä } 3249d1b45d5fSVille Syrjälä 3250d1b45d5fSVille Syrjälä if (r->height == 0 || r->height % vsub) { 32511aa1b11cSDave Airlie DRM_DEBUG_KMS("bad framebuffer height %u\n", r->height); 3252d1b45d5fSVille Syrjälä return -EINVAL; 3253d1b45d5fSVille Syrjälä } 3254d1b45d5fSVille Syrjälä 3255d1b45d5fSVille Syrjälä for (i = 0; i < num_planes; i++) { 3256d1b45d5fSVille Syrjälä unsigned int width = r->width / (i != 0 ? hsub : 1); 3257b180b5d1SVille Syrjälä unsigned int height = r->height / (i != 0 ? vsub : 1); 3258b180b5d1SVille Syrjälä unsigned int cpp = drm_format_plane_cpp(r->pixel_format, i); 3259d1b45d5fSVille Syrjälä 3260d1b45d5fSVille Syrjälä if (!r->handles[i]) { 32611aa1b11cSDave Airlie DRM_DEBUG_KMS("no buffer object handle for plane %d\n", i); 3262d1b45d5fSVille Syrjälä return -EINVAL; 3263d1b45d5fSVille Syrjälä } 3264d1b45d5fSVille Syrjälä 3265b180b5d1SVille Syrjälä if ((uint64_t) width * cpp > UINT_MAX) 3266b180b5d1SVille Syrjälä return -ERANGE; 3267b180b5d1SVille Syrjälä 3268b180b5d1SVille Syrjälä if ((uint64_t) height * r->pitches[i] + r->offsets[i] > UINT_MAX) 3269b180b5d1SVille Syrjälä return -ERANGE; 3270b180b5d1SVille Syrjälä 3271b180b5d1SVille Syrjälä if (r->pitches[i] < width * cpp) { 32721aa1b11cSDave Airlie DRM_DEBUG_KMS("bad pitch %u for plane %d\n", r->pitches[i], i); 3273d1b45d5fSVille Syrjälä return -EINVAL; 3274d1b45d5fSVille Syrjälä } 3275d1b45d5fSVille Syrjälä } 3276d1b45d5fSVille Syrjälä 3277d1b45d5fSVille Syrjälä return 0; 3278d1b45d5fSVille Syrjälä } 3279d1b45d5fSVille Syrjälä 3280c394c2b0SMatt Roper static struct drm_framebuffer *add_framebuffer_internal(struct drm_device *dev, 3281c394c2b0SMatt Roper struct drm_mode_fb_cmd2 *r, 3282c394c2b0SMatt Roper struct drm_file *file_priv) 3283c394c2b0SMatt Roper { 3284c394c2b0SMatt Roper struct drm_mode_config *config = &dev->mode_config; 3285c394c2b0SMatt Roper struct drm_framebuffer *fb; 3286c394c2b0SMatt Roper int ret; 3287c394c2b0SMatt Roper 3288c394c2b0SMatt Roper if (r->flags & ~DRM_MODE_FB_INTERLACED) { 3289c394c2b0SMatt Roper DRM_DEBUG_KMS("bad framebuffer flags 0x%08x\n", r->flags); 3290c394c2b0SMatt Roper return ERR_PTR(-EINVAL); 3291c394c2b0SMatt Roper } 3292c394c2b0SMatt Roper 3293c394c2b0SMatt Roper if ((config->min_width > r->width) || (r->width > config->max_width)) { 3294c394c2b0SMatt Roper DRM_DEBUG_KMS("bad framebuffer width %d, should be >= %d && <= %d\n", 3295c394c2b0SMatt Roper r->width, config->min_width, config->max_width); 3296c394c2b0SMatt Roper return ERR_PTR(-EINVAL); 3297c394c2b0SMatt Roper } 3298c394c2b0SMatt Roper if ((config->min_height > r->height) || (r->height > config->max_height)) { 3299c394c2b0SMatt Roper DRM_DEBUG_KMS("bad framebuffer height %d, should be >= %d && <= %d\n", 3300c394c2b0SMatt Roper r->height, config->min_height, config->max_height); 3301c394c2b0SMatt Roper return ERR_PTR(-EINVAL); 3302c394c2b0SMatt Roper } 3303c394c2b0SMatt Roper 3304c394c2b0SMatt Roper ret = framebuffer_check(r); 3305c394c2b0SMatt Roper if (ret) 3306c394c2b0SMatt Roper return ERR_PTR(ret); 3307c394c2b0SMatt Roper 3308c394c2b0SMatt Roper fb = dev->mode_config.funcs->fb_create(dev, file_priv, r); 3309c394c2b0SMatt Roper if (IS_ERR(fb)) { 3310c394c2b0SMatt Roper DRM_DEBUG_KMS("could not create framebuffer\n"); 3311c394c2b0SMatt Roper return fb; 3312c394c2b0SMatt Roper } 3313c394c2b0SMatt Roper 3314c394c2b0SMatt Roper mutex_lock(&file_priv->fbs_lock); 3315c394c2b0SMatt Roper r->fb_id = fb->base.id; 3316c394c2b0SMatt Roper list_add(&fb->filp_head, &file_priv->fbs); 3317c394c2b0SMatt Roper DRM_DEBUG_KMS("[FB:%d]\n", fb->base.id); 3318c394c2b0SMatt Roper mutex_unlock(&file_priv->fbs_lock); 3319c394c2b0SMatt Roper 3320c394c2b0SMatt Roper return fb; 3321c394c2b0SMatt Roper } 3322c394c2b0SMatt Roper 3323308e5bcbSJesse Barnes /** 3324308e5bcbSJesse Barnes * drm_mode_addfb2 - add an FB to the graphics configuration 3325065a50edSDaniel Vetter * @dev: drm device for the ioctl 3326065a50edSDaniel Vetter * @data: data pointer for the ioctl 3327065a50edSDaniel Vetter * @file_priv: drm file for the ioctl call 3328308e5bcbSJesse Barnes * 3329c8e32cc1SDaniel Vetter * Add a new FB to the specified CRTC, given a user request with format. This is 3330c8e32cc1SDaniel Vetter * the 2nd version of the addfb ioctl, which supports multi-planar framebuffers 3331c8e32cc1SDaniel Vetter * and uses fourcc codes as pixel format specifiers. 3332308e5bcbSJesse Barnes * 3333308e5bcbSJesse Barnes * Called by the user via ioctl. 3334308e5bcbSJesse Barnes * 3335c8e32cc1SDaniel Vetter * Returns: 33361a498633SDaniel Vetter * Zero on success, negative errno on failure. 3337308e5bcbSJesse Barnes */ 3338308e5bcbSJesse Barnes int drm_mode_addfb2(struct drm_device *dev, 3339308e5bcbSJesse Barnes void *data, struct drm_file *file_priv) 3340308e5bcbSJesse Barnes { 3341f453ba04SDave Airlie struct drm_framebuffer *fb; 3342f453ba04SDave Airlie 3343fb3b06c8SDave Airlie if (!drm_core_check_feature(dev, DRIVER_MODESET)) 3344fb3b06c8SDave Airlie return -EINVAL; 3345fb3b06c8SDave Airlie 3346c394c2b0SMatt Roper fb = add_framebuffer_internal(dev, data, file_priv); 3347c394c2b0SMatt Roper if (IS_ERR(fb)) 33484b096ac1SDaniel Vetter return PTR_ERR(fb); 3349f453ba04SDave Airlie 3350c394c2b0SMatt Roper return 0; 3351f453ba04SDave Airlie } 3352f453ba04SDave Airlie 3353f453ba04SDave Airlie /** 3354f453ba04SDave Airlie * drm_mode_rmfb - remove an FB from the configuration 3355065a50edSDaniel Vetter * @dev: drm device for the ioctl 3356065a50edSDaniel Vetter * @data: data pointer for the ioctl 3357065a50edSDaniel Vetter * @file_priv: drm file for the ioctl call 3358f453ba04SDave Airlie * 3359f453ba04SDave Airlie * Remove the FB specified by the user. 3360f453ba04SDave Airlie * 3361f453ba04SDave Airlie * Called by the user via ioctl. 3362f453ba04SDave Airlie * 3363c8e32cc1SDaniel Vetter * Returns: 33641a498633SDaniel Vetter * Zero on success, negative errno on failure. 3365f453ba04SDave Airlie */ 3366f453ba04SDave Airlie int drm_mode_rmfb(struct drm_device *dev, 3367f453ba04SDave Airlie void *data, struct drm_file *file_priv) 3368f453ba04SDave Airlie { 3369f453ba04SDave Airlie struct drm_framebuffer *fb = NULL; 3370f453ba04SDave Airlie struct drm_framebuffer *fbl = NULL; 3371f453ba04SDave Airlie uint32_t *id = data; 3372f453ba04SDave Airlie int found = 0; 3373f453ba04SDave Airlie 3374fb3b06c8SDave Airlie if (!drm_core_check_feature(dev, DRIVER_MODESET)) 3375fb3b06c8SDave Airlie return -EINVAL; 3376fb3b06c8SDave Airlie 33774b096ac1SDaniel Vetter mutex_lock(&file_priv->fbs_lock); 33782b677e8cSDaniel Vetter mutex_lock(&dev->mode_config.fb_lock); 33792b677e8cSDaniel Vetter fb = __drm_framebuffer_lookup(dev, *id); 33802b677e8cSDaniel Vetter if (!fb) 33812b677e8cSDaniel Vetter goto fail_lookup; 33822b677e8cSDaniel Vetter 3383f453ba04SDave Airlie list_for_each_entry(fbl, &file_priv->fbs, filp_head) 3384f453ba04SDave Airlie if (fb == fbl) 3385f453ba04SDave Airlie found = 1; 33862b677e8cSDaniel Vetter if (!found) 33872b677e8cSDaniel Vetter goto fail_lookup; 33882b677e8cSDaniel Vetter 33892b677e8cSDaniel Vetter /* Mark fb as reaped, we still have a ref from fpriv->fbs. */ 33902b677e8cSDaniel Vetter __drm_framebuffer_unregister(dev, fb); 3391f453ba04SDave Airlie 33924b096ac1SDaniel Vetter list_del_init(&fb->filp_head); 33932b677e8cSDaniel Vetter mutex_unlock(&dev->mode_config.fb_lock); 33944b096ac1SDaniel Vetter mutex_unlock(&file_priv->fbs_lock); 3395f453ba04SDave Airlie 33964b096ac1SDaniel Vetter drm_framebuffer_remove(fb); 33974b096ac1SDaniel Vetter 33982b677e8cSDaniel Vetter return 0; 33992b677e8cSDaniel Vetter 34002b677e8cSDaniel Vetter fail_lookup: 34012b677e8cSDaniel Vetter mutex_unlock(&dev->mode_config.fb_lock); 34022b677e8cSDaniel Vetter mutex_unlock(&file_priv->fbs_lock); 34032b677e8cSDaniel Vetter 340437c4e705SVille Syrjälä return -ENOENT; 3405f453ba04SDave Airlie } 3406f453ba04SDave Airlie 3407f453ba04SDave Airlie /** 3408f453ba04SDave Airlie * drm_mode_getfb - get FB info 3409065a50edSDaniel Vetter * @dev: drm device for the ioctl 3410065a50edSDaniel Vetter * @data: data pointer for the ioctl 3411065a50edSDaniel Vetter * @file_priv: drm file for the ioctl call 3412f453ba04SDave Airlie * 3413f453ba04SDave Airlie * Lookup the FB given its ID and return info about it. 3414f453ba04SDave Airlie * 3415f453ba04SDave Airlie * Called by the user via ioctl. 3416f453ba04SDave Airlie * 3417c8e32cc1SDaniel Vetter * Returns: 34181a498633SDaniel Vetter * Zero on success, negative errno on failure. 3419f453ba04SDave Airlie */ 3420f453ba04SDave Airlie int drm_mode_getfb(struct drm_device *dev, 3421f453ba04SDave Airlie void *data, struct drm_file *file_priv) 3422f453ba04SDave Airlie { 3423f453ba04SDave Airlie struct drm_mode_fb_cmd *r = data; 3424f453ba04SDave Airlie struct drm_framebuffer *fb; 342558c0dca1SDaniel Vetter int ret; 3426f453ba04SDave Airlie 3427fb3b06c8SDave Airlie if (!drm_core_check_feature(dev, DRIVER_MODESET)) 3428fb3b06c8SDave Airlie return -EINVAL; 3429fb3b06c8SDave Airlie 3430786b99edSDaniel Vetter fb = drm_framebuffer_lookup(dev, r->fb_id); 343158c0dca1SDaniel Vetter if (!fb) 343237c4e705SVille Syrjälä return -ENOENT; 3433f453ba04SDave Airlie 3434f453ba04SDave Airlie r->height = fb->height; 3435f453ba04SDave Airlie r->width = fb->width; 3436f453ba04SDave Airlie r->depth = fb->depth; 3437f453ba04SDave Airlie r->bpp = fb->bits_per_pixel; 343801f2c773SVille Syrjälä r->pitch = fb->pitches[0]; 3439101b96f3SDavid Herrmann if (fb->funcs->create_handle) { 344009f308f7SThomas Hellstrom if (file_priv->is_master || capable(CAP_SYS_ADMIN) || 344143683057SThomas Hellstrom drm_is_control_client(file_priv)) { 3442101b96f3SDavid Herrmann ret = fb->funcs->create_handle(fb, file_priv, 3443101b96f3SDavid Herrmann &r->handle); 3444101b96f3SDavid Herrmann } else { 3445101b96f3SDavid Herrmann /* GET_FB() is an unprivileged ioctl so we must not 3446101b96f3SDavid Herrmann * return a buffer-handle to non-master processes! For 3447101b96f3SDavid Herrmann * backwards-compatibility reasons, we cannot make 3448101b96f3SDavid Herrmann * GET_FB() privileged, so just return an invalid handle 3449101b96f3SDavid Herrmann * for non-masters. */ 3450101b96f3SDavid Herrmann r->handle = 0; 3451101b96f3SDavid Herrmann ret = 0; 3452101b96f3SDavid Herrmann } 3453101b96f3SDavid Herrmann } else { 3454af26ef3bSDaniel Vetter ret = -ENODEV; 3455101b96f3SDavid Herrmann } 3456f453ba04SDave Airlie 345758c0dca1SDaniel Vetter drm_framebuffer_unreference(fb); 345858c0dca1SDaniel Vetter 3459f453ba04SDave Airlie return ret; 3460f453ba04SDave Airlie } 3461f453ba04SDave Airlie 3462c8e32cc1SDaniel Vetter /** 3463c8e32cc1SDaniel Vetter * drm_mode_dirtyfb_ioctl - flush frontbuffer rendering on an FB 3464c8e32cc1SDaniel Vetter * @dev: drm device for the ioctl 3465c8e32cc1SDaniel Vetter * @data: data pointer for the ioctl 3466c8e32cc1SDaniel Vetter * @file_priv: drm file for the ioctl call 3467c8e32cc1SDaniel Vetter * 3468c8e32cc1SDaniel Vetter * Lookup the FB and flush out the damaged area supplied by userspace as a clip 3469c8e32cc1SDaniel Vetter * rectangle list. Generic userspace which does frontbuffer rendering must call 3470c8e32cc1SDaniel Vetter * this ioctl to flush out the changes on manual-update display outputs, e.g. 3471c8e32cc1SDaniel Vetter * usb display-link, mipi manual update panels or edp panel self refresh modes. 3472c8e32cc1SDaniel Vetter * 3473c8e32cc1SDaniel Vetter * Modesetting drivers which always update the frontbuffer do not need to 3474c8e32cc1SDaniel Vetter * implement the corresponding ->dirty framebuffer callback. 3475c8e32cc1SDaniel Vetter * 3476c8e32cc1SDaniel Vetter * Called by the user via ioctl. 3477c8e32cc1SDaniel Vetter * 3478c8e32cc1SDaniel Vetter * Returns: 34791a498633SDaniel Vetter * Zero on success, negative errno on failure. 3480c8e32cc1SDaniel Vetter */ 3481884840aaSJakob Bornecrantz int drm_mode_dirtyfb_ioctl(struct drm_device *dev, 3482884840aaSJakob Bornecrantz void *data, struct drm_file *file_priv) 3483884840aaSJakob Bornecrantz { 3484884840aaSJakob Bornecrantz struct drm_clip_rect __user *clips_ptr; 3485884840aaSJakob Bornecrantz struct drm_clip_rect *clips = NULL; 3486884840aaSJakob Bornecrantz struct drm_mode_fb_dirty_cmd *r = data; 3487884840aaSJakob Bornecrantz struct drm_framebuffer *fb; 3488884840aaSJakob Bornecrantz unsigned flags; 3489884840aaSJakob Bornecrantz int num_clips; 34904a1b0714SLaurent Pinchart int ret; 3491884840aaSJakob Bornecrantz 3492fb3b06c8SDave Airlie if (!drm_core_check_feature(dev, DRIVER_MODESET)) 3493fb3b06c8SDave Airlie return -EINVAL; 3494fb3b06c8SDave Airlie 3495786b99edSDaniel Vetter fb = drm_framebuffer_lookup(dev, r->fb_id); 34964ccf097fSDaniel Vetter if (!fb) 349737c4e705SVille Syrjälä return -ENOENT; 3498884840aaSJakob Bornecrantz 3499884840aaSJakob Bornecrantz num_clips = r->num_clips; 350081f6c7f8SVille Syrjälä clips_ptr = (struct drm_clip_rect __user *)(unsigned long)r->clips_ptr; 3501884840aaSJakob Bornecrantz 3502884840aaSJakob Bornecrantz if (!num_clips != !clips_ptr) { 3503884840aaSJakob Bornecrantz ret = -EINVAL; 3504884840aaSJakob Bornecrantz goto out_err1; 3505884840aaSJakob Bornecrantz } 3506884840aaSJakob Bornecrantz 3507884840aaSJakob Bornecrantz flags = DRM_MODE_FB_DIRTY_FLAGS & r->flags; 3508884840aaSJakob Bornecrantz 3509884840aaSJakob Bornecrantz /* If userspace annotates copy, clips must come in pairs */ 3510884840aaSJakob Bornecrantz if (flags & DRM_MODE_FB_DIRTY_ANNOTATE_COPY && (num_clips % 2)) { 3511884840aaSJakob Bornecrantz ret = -EINVAL; 3512884840aaSJakob Bornecrantz goto out_err1; 3513884840aaSJakob Bornecrantz } 3514884840aaSJakob Bornecrantz 3515884840aaSJakob Bornecrantz if (num_clips && clips_ptr) { 3516a5cd3351SXi Wang if (num_clips < 0 || num_clips > DRM_MODE_FB_DIRTY_MAX_CLIPS) { 3517a5cd3351SXi Wang ret = -EINVAL; 3518a5cd3351SXi Wang goto out_err1; 3519a5cd3351SXi Wang } 3520bd3f0ff9SThierry Reding clips = kcalloc(num_clips, sizeof(*clips), GFP_KERNEL); 3521884840aaSJakob Bornecrantz if (!clips) { 3522884840aaSJakob Bornecrantz ret = -ENOMEM; 3523884840aaSJakob Bornecrantz goto out_err1; 3524884840aaSJakob Bornecrantz } 3525884840aaSJakob Bornecrantz 3526884840aaSJakob Bornecrantz ret = copy_from_user(clips, clips_ptr, 3527884840aaSJakob Bornecrantz num_clips * sizeof(*clips)); 3528e902a358SDan Carpenter if (ret) { 3529e902a358SDan Carpenter ret = -EFAULT; 3530884840aaSJakob Bornecrantz goto out_err2; 3531884840aaSJakob Bornecrantz } 3532e902a358SDan Carpenter } 3533884840aaSJakob Bornecrantz 3534884840aaSJakob Bornecrantz if (fb->funcs->dirty) { 353502b00162SThomas Hellstrom ret = fb->funcs->dirty(fb, file_priv, flags, r->color, 353602b00162SThomas Hellstrom clips, num_clips); 3537884840aaSJakob Bornecrantz } else { 3538884840aaSJakob Bornecrantz ret = -ENOSYS; 3539884840aaSJakob Bornecrantz } 3540884840aaSJakob Bornecrantz 3541884840aaSJakob Bornecrantz out_err2: 3542884840aaSJakob Bornecrantz kfree(clips); 3543884840aaSJakob Bornecrantz out_err1: 35444ccf097fSDaniel Vetter drm_framebuffer_unreference(fb); 35454ccf097fSDaniel Vetter 3546884840aaSJakob Bornecrantz return ret; 3547884840aaSJakob Bornecrantz } 3548884840aaSJakob Bornecrantz 3549884840aaSJakob Bornecrantz 3550f453ba04SDave Airlie /** 3551f453ba04SDave Airlie * drm_fb_release - remove and free the FBs on this file 3552065a50edSDaniel Vetter * @priv: drm file for the ioctl 3553f453ba04SDave Airlie * 3554f453ba04SDave Airlie * Destroy all the FBs associated with @filp. 3555f453ba04SDave Airlie * 3556f453ba04SDave Airlie * Called by the user via ioctl. 3557f453ba04SDave Airlie * 3558c8e32cc1SDaniel Vetter * Returns: 35591a498633SDaniel Vetter * Zero on success, negative errno on failure. 3560f453ba04SDave Airlie */ 3561ea39f835SKristian Høgsberg void drm_fb_release(struct drm_file *priv) 3562f453ba04SDave Airlie { 3563f453ba04SDave Airlie struct drm_device *dev = priv->minor->dev; 3564f453ba04SDave Airlie struct drm_framebuffer *fb, *tfb; 3565f453ba04SDave Airlie 35661b116297SDaniel Vetter /* 35671b116297SDaniel Vetter * When the file gets released that means no one else can access the fb 3568e2db726bSMartin Peres * list any more, so no need to grab fpriv->fbs_lock. And we need to 35691b116297SDaniel Vetter * avoid upsetting lockdep since the universal cursor code adds a 35701b116297SDaniel Vetter * framebuffer while holding mutex locks. 35711b116297SDaniel Vetter * 35721b116297SDaniel Vetter * Note that a real deadlock between fpriv->fbs_lock and the modeset 35731b116297SDaniel Vetter * locks is impossible here since no one else but this function can get 35741b116297SDaniel Vetter * at it any more. 35751b116297SDaniel Vetter */ 3576f453ba04SDave Airlie list_for_each_entry_safe(fb, tfb, &priv->fbs, filp_head) { 35772b677e8cSDaniel Vetter 35782b677e8cSDaniel Vetter mutex_lock(&dev->mode_config.fb_lock); 35792b677e8cSDaniel Vetter /* Mark fb as reaped, we still have a ref from fpriv->fbs. */ 35802b677e8cSDaniel Vetter __drm_framebuffer_unregister(dev, fb); 35812b677e8cSDaniel Vetter mutex_unlock(&dev->mode_config.fb_lock); 35822b677e8cSDaniel Vetter 35834b096ac1SDaniel Vetter list_del_init(&fb->filp_head); 35842b677e8cSDaniel Vetter 35852b677e8cSDaniel Vetter /* This will also drop the fpriv->fbs reference. */ 3586f7eff60eSRob Clark drm_framebuffer_remove(fb); 3587f453ba04SDave Airlie } 3588f453ba04SDave Airlie } 3589f453ba04SDave Airlie 3590c8e32cc1SDaniel Vetter /** 3591c8e32cc1SDaniel Vetter * drm_property_create - create a new property type 3592c8e32cc1SDaniel Vetter * @dev: drm device 3593c8e32cc1SDaniel Vetter * @flags: flags specifying the property type 3594c8e32cc1SDaniel Vetter * @name: name of the property 3595c8e32cc1SDaniel Vetter * @num_values: number of pre-defined values 3596c8e32cc1SDaniel Vetter * 3597c8e32cc1SDaniel Vetter * This creates a new generic drm property which can then be attached to a drm 3598c8e32cc1SDaniel Vetter * object with drm_object_attach_property. The returned property object must be 3599c8e32cc1SDaniel Vetter * freed with drm_property_destroy. 3600c8e32cc1SDaniel Vetter * 36013b5b9932SDamien Lespiau * Note that the DRM core keeps a per-device list of properties and that, if 36023b5b9932SDamien Lespiau * drm_mode_config_cleanup() is called, it will destroy all properties created 36033b5b9932SDamien Lespiau * by the driver. 36043b5b9932SDamien Lespiau * 3605c8e32cc1SDaniel Vetter * Returns: 3606c8e32cc1SDaniel Vetter * A pointer to the newly created property on success, NULL on failure. 3607c8e32cc1SDaniel Vetter */ 3608f453ba04SDave Airlie struct drm_property *drm_property_create(struct drm_device *dev, int flags, 3609f453ba04SDave Airlie const char *name, int num_values) 3610f453ba04SDave Airlie { 3611f453ba04SDave Airlie struct drm_property *property = NULL; 36126bfc56aaSVille Syrjälä int ret; 3613f453ba04SDave Airlie 3614f453ba04SDave Airlie property = kzalloc(sizeof(struct drm_property), GFP_KERNEL); 3615f453ba04SDave Airlie if (!property) 3616f453ba04SDave Airlie return NULL; 3617f453ba04SDave Airlie 361898f75de4SRob Clark property->dev = dev; 361998f75de4SRob Clark 3620f453ba04SDave Airlie if (num_values) { 3621bd3f0ff9SThierry Reding property->values = kcalloc(num_values, sizeof(uint64_t), 3622bd3f0ff9SThierry Reding GFP_KERNEL); 3623f453ba04SDave Airlie if (!property->values) 3624f453ba04SDave Airlie goto fail; 3625f453ba04SDave Airlie } 3626f453ba04SDave Airlie 36276bfc56aaSVille Syrjälä ret = drm_mode_object_get(dev, &property->base, DRM_MODE_OBJECT_PROPERTY); 36286bfc56aaSVille Syrjälä if (ret) 36296bfc56aaSVille Syrjälä goto fail; 36306bfc56aaSVille Syrjälä 3631f453ba04SDave Airlie property->flags = flags; 3632f453ba04SDave Airlie property->num_values = num_values; 36333758b341SDaniel Vetter INIT_LIST_HEAD(&property->enum_list); 3634f453ba04SDave Airlie 3635471dd2efSVinson Lee if (name) { 3636f453ba04SDave Airlie strncpy(property->name, name, DRM_PROP_NAME_LEN); 3637471dd2efSVinson Lee property->name[DRM_PROP_NAME_LEN-1] = '\0'; 3638471dd2efSVinson Lee } 3639f453ba04SDave Airlie 3640f453ba04SDave Airlie list_add_tail(&property->head, &dev->mode_config.property_list); 36415ea22f24SRob Clark 36425ea22f24SRob Clark WARN_ON(!drm_property_type_valid(property)); 36435ea22f24SRob Clark 3644f453ba04SDave Airlie return property; 3645f453ba04SDave Airlie fail: 36466bfc56aaSVille Syrjälä kfree(property->values); 3647f453ba04SDave Airlie kfree(property); 3648f453ba04SDave Airlie return NULL; 3649f453ba04SDave Airlie } 3650f453ba04SDave Airlie EXPORT_SYMBOL(drm_property_create); 3651f453ba04SDave Airlie 3652c8e32cc1SDaniel Vetter /** 36532aa9d2bcSThierry Reding * drm_property_create_enum - create a new enumeration property type 3654c8e32cc1SDaniel Vetter * @dev: drm device 3655c8e32cc1SDaniel Vetter * @flags: flags specifying the property type 3656c8e32cc1SDaniel Vetter * @name: name of the property 3657c8e32cc1SDaniel Vetter * @props: enumeration lists with property values 3658c8e32cc1SDaniel Vetter * @num_values: number of pre-defined values 3659c8e32cc1SDaniel Vetter * 3660c8e32cc1SDaniel Vetter * This creates a new generic drm property which can then be attached to a drm 3661c8e32cc1SDaniel Vetter * object with drm_object_attach_property. The returned property object must be 3662c8e32cc1SDaniel Vetter * freed with drm_property_destroy. 3663c8e32cc1SDaniel Vetter * 3664c8e32cc1SDaniel Vetter * Userspace is only allowed to set one of the predefined values for enumeration 3665c8e32cc1SDaniel Vetter * properties. 3666c8e32cc1SDaniel Vetter * 3667c8e32cc1SDaniel Vetter * Returns: 3668c8e32cc1SDaniel Vetter * A pointer to the newly created property on success, NULL on failure. 3669c8e32cc1SDaniel Vetter */ 36704a67d391SSascha Hauer struct drm_property *drm_property_create_enum(struct drm_device *dev, int flags, 36714a67d391SSascha Hauer const char *name, 36724a67d391SSascha Hauer const struct drm_prop_enum_list *props, 36734a67d391SSascha Hauer int num_values) 36744a67d391SSascha Hauer { 36754a67d391SSascha Hauer struct drm_property *property; 36764a67d391SSascha Hauer int i, ret; 36774a67d391SSascha Hauer 36784a67d391SSascha Hauer flags |= DRM_MODE_PROP_ENUM; 36794a67d391SSascha Hauer 36804a67d391SSascha Hauer property = drm_property_create(dev, flags, name, num_values); 36814a67d391SSascha Hauer if (!property) 36824a67d391SSascha Hauer return NULL; 36834a67d391SSascha Hauer 36844a67d391SSascha Hauer for (i = 0; i < num_values; i++) { 36854a67d391SSascha Hauer ret = drm_property_add_enum(property, i, 36864a67d391SSascha Hauer props[i].type, 36874a67d391SSascha Hauer props[i].name); 36884a67d391SSascha Hauer if (ret) { 36894a67d391SSascha Hauer drm_property_destroy(dev, property); 36904a67d391SSascha Hauer return NULL; 36914a67d391SSascha Hauer } 36924a67d391SSascha Hauer } 36934a67d391SSascha Hauer 36944a67d391SSascha Hauer return property; 36954a67d391SSascha Hauer } 36964a67d391SSascha Hauer EXPORT_SYMBOL(drm_property_create_enum); 36974a67d391SSascha Hauer 3698c8e32cc1SDaniel Vetter /** 36992aa9d2bcSThierry Reding * drm_property_create_bitmask - create a new bitmask property type 3700c8e32cc1SDaniel Vetter * @dev: drm device 3701c8e32cc1SDaniel Vetter * @flags: flags specifying the property type 3702c8e32cc1SDaniel Vetter * @name: name of the property 3703c8e32cc1SDaniel Vetter * @props: enumeration lists with property bitflags 3704295ee853SDaniel Vetter * @num_props: size of the @props array 3705295ee853SDaniel Vetter * @supported_bits: bitmask of all supported enumeration values 3706c8e32cc1SDaniel Vetter * 3707295ee853SDaniel Vetter * This creates a new bitmask drm property which can then be attached to a drm 3708c8e32cc1SDaniel Vetter * object with drm_object_attach_property. The returned property object must be 3709c8e32cc1SDaniel Vetter * freed with drm_property_destroy. 3710c8e32cc1SDaniel Vetter * 3711c8e32cc1SDaniel Vetter * Compared to plain enumeration properties userspace is allowed to set any 3712c8e32cc1SDaniel Vetter * or'ed together combination of the predefined property bitflag values 3713c8e32cc1SDaniel Vetter * 3714c8e32cc1SDaniel Vetter * Returns: 3715c8e32cc1SDaniel Vetter * A pointer to the newly created property on success, NULL on failure. 3716c8e32cc1SDaniel Vetter */ 371749e27545SRob Clark struct drm_property *drm_property_create_bitmask(struct drm_device *dev, 371849e27545SRob Clark int flags, const char *name, 371949e27545SRob Clark const struct drm_prop_enum_list *props, 37207689ffb3SVille Syrjälä int num_props, 37217689ffb3SVille Syrjälä uint64_t supported_bits) 372249e27545SRob Clark { 372349e27545SRob Clark struct drm_property *property; 37247689ffb3SVille Syrjälä int i, ret, index = 0; 37257689ffb3SVille Syrjälä int num_values = hweight64(supported_bits); 372649e27545SRob Clark 372749e27545SRob Clark flags |= DRM_MODE_PROP_BITMASK; 372849e27545SRob Clark 372949e27545SRob Clark property = drm_property_create(dev, flags, name, num_values); 373049e27545SRob Clark if (!property) 373149e27545SRob Clark return NULL; 37327689ffb3SVille Syrjälä for (i = 0; i < num_props; i++) { 37337689ffb3SVille Syrjälä if (!(supported_bits & (1ULL << props[i].type))) 37347689ffb3SVille Syrjälä continue; 373549e27545SRob Clark 37367689ffb3SVille Syrjälä if (WARN_ON(index >= num_values)) { 37377689ffb3SVille Syrjälä drm_property_destroy(dev, property); 37387689ffb3SVille Syrjälä return NULL; 37397689ffb3SVille Syrjälä } 37407689ffb3SVille Syrjälä 37417689ffb3SVille Syrjälä ret = drm_property_add_enum(property, index++, 374249e27545SRob Clark props[i].type, 374349e27545SRob Clark props[i].name); 374449e27545SRob Clark if (ret) { 374549e27545SRob Clark drm_property_destroy(dev, property); 374649e27545SRob Clark return NULL; 374749e27545SRob Clark } 374849e27545SRob Clark } 374949e27545SRob Clark 375049e27545SRob Clark return property; 375149e27545SRob Clark } 375249e27545SRob Clark EXPORT_SYMBOL(drm_property_create_bitmask); 375349e27545SRob Clark 3754ebc44cf3SRob Clark static struct drm_property *property_create_range(struct drm_device *dev, 3755ebc44cf3SRob Clark int flags, const char *name, 3756ebc44cf3SRob Clark uint64_t min, uint64_t max) 3757ebc44cf3SRob Clark { 3758ebc44cf3SRob Clark struct drm_property *property; 3759ebc44cf3SRob Clark 3760ebc44cf3SRob Clark property = drm_property_create(dev, flags, name, 2); 3761ebc44cf3SRob Clark if (!property) 3762ebc44cf3SRob Clark return NULL; 3763ebc44cf3SRob Clark 3764ebc44cf3SRob Clark property->values[0] = min; 3765ebc44cf3SRob Clark property->values[1] = max; 3766ebc44cf3SRob Clark 3767ebc44cf3SRob Clark return property; 3768ebc44cf3SRob Clark } 3769ebc44cf3SRob Clark 3770c8e32cc1SDaniel Vetter /** 3771960cd9d4SDaniel Vetter * drm_property_create_range - create a new unsigned ranged property type 3772c8e32cc1SDaniel Vetter * @dev: drm device 3773c8e32cc1SDaniel Vetter * @flags: flags specifying the property type 3774c8e32cc1SDaniel Vetter * @name: name of the property 3775c8e32cc1SDaniel Vetter * @min: minimum value of the property 3776c8e32cc1SDaniel Vetter * @max: maximum value of the property 3777c8e32cc1SDaniel Vetter * 3778c8e32cc1SDaniel Vetter * This creates a new generic drm property which can then be attached to a drm 3779c8e32cc1SDaniel Vetter * object with drm_object_attach_property. The returned property object must be 3780c8e32cc1SDaniel Vetter * freed with drm_property_destroy. 3781c8e32cc1SDaniel Vetter * 3782960cd9d4SDaniel Vetter * Userspace is allowed to set any unsigned integer value in the (min, max) 3783960cd9d4SDaniel Vetter * range inclusive. 3784c8e32cc1SDaniel Vetter * 3785c8e32cc1SDaniel Vetter * Returns: 3786c8e32cc1SDaniel Vetter * A pointer to the newly created property on success, NULL on failure. 3787c8e32cc1SDaniel Vetter */ 3788d9bc3c02SSascha Hauer struct drm_property *drm_property_create_range(struct drm_device *dev, int flags, 3789d9bc3c02SSascha Hauer const char *name, 3790d9bc3c02SSascha Hauer uint64_t min, uint64_t max) 3791d9bc3c02SSascha Hauer { 3792ebc44cf3SRob Clark return property_create_range(dev, DRM_MODE_PROP_RANGE | flags, 3793ebc44cf3SRob Clark name, min, max); 3794d9bc3c02SSascha Hauer } 3795d9bc3c02SSascha Hauer EXPORT_SYMBOL(drm_property_create_range); 3796d9bc3c02SSascha Hauer 3797960cd9d4SDaniel Vetter /** 3798960cd9d4SDaniel Vetter * drm_property_create_signed_range - create a new signed ranged property type 3799960cd9d4SDaniel Vetter * @dev: drm device 3800960cd9d4SDaniel Vetter * @flags: flags specifying the property type 3801960cd9d4SDaniel Vetter * @name: name of the property 3802960cd9d4SDaniel Vetter * @min: minimum value of the property 3803960cd9d4SDaniel Vetter * @max: maximum value of the property 3804960cd9d4SDaniel Vetter * 3805960cd9d4SDaniel Vetter * This creates a new generic drm property which can then be attached to a drm 3806960cd9d4SDaniel Vetter * object with drm_object_attach_property. The returned property object must be 3807960cd9d4SDaniel Vetter * freed with drm_property_destroy. 3808960cd9d4SDaniel Vetter * 3809960cd9d4SDaniel Vetter * Userspace is allowed to set any signed integer value in the (min, max) 3810960cd9d4SDaniel Vetter * range inclusive. 3811960cd9d4SDaniel Vetter * 3812960cd9d4SDaniel Vetter * Returns: 3813960cd9d4SDaniel Vetter * A pointer to the newly created property on success, NULL on failure. 3814960cd9d4SDaniel Vetter */ 3815ebc44cf3SRob Clark struct drm_property *drm_property_create_signed_range(struct drm_device *dev, 3816ebc44cf3SRob Clark int flags, const char *name, 3817ebc44cf3SRob Clark int64_t min, int64_t max) 3818ebc44cf3SRob Clark { 3819ebc44cf3SRob Clark return property_create_range(dev, DRM_MODE_PROP_SIGNED_RANGE | flags, 3820ebc44cf3SRob Clark name, I642U64(min), I642U64(max)); 3821ebc44cf3SRob Clark } 3822ebc44cf3SRob Clark EXPORT_SYMBOL(drm_property_create_signed_range); 3823ebc44cf3SRob Clark 3824960cd9d4SDaniel Vetter /** 3825960cd9d4SDaniel Vetter * drm_property_create_object - create a new object property type 3826960cd9d4SDaniel Vetter * @dev: drm device 3827960cd9d4SDaniel Vetter * @flags: flags specifying the property type 3828960cd9d4SDaniel Vetter * @name: name of the property 3829960cd9d4SDaniel Vetter * @type: object type from DRM_MODE_OBJECT_* defines 3830960cd9d4SDaniel Vetter * 3831960cd9d4SDaniel Vetter * This creates a new generic drm property which can then be attached to a drm 3832960cd9d4SDaniel Vetter * object with drm_object_attach_property. The returned property object must be 3833960cd9d4SDaniel Vetter * freed with drm_property_destroy. 3834960cd9d4SDaniel Vetter * 3835960cd9d4SDaniel Vetter * Userspace is only allowed to set this to any property value of the given 3836960cd9d4SDaniel Vetter * @type. Only useful for atomic properties, which is enforced. 3837960cd9d4SDaniel Vetter * 3838960cd9d4SDaniel Vetter * Returns: 3839960cd9d4SDaniel Vetter * A pointer to the newly created property on success, NULL on failure. 3840960cd9d4SDaniel Vetter */ 384198f75de4SRob Clark struct drm_property *drm_property_create_object(struct drm_device *dev, 384298f75de4SRob Clark int flags, const char *name, uint32_t type) 384398f75de4SRob Clark { 384498f75de4SRob Clark struct drm_property *property; 384598f75de4SRob Clark 384698f75de4SRob Clark flags |= DRM_MODE_PROP_OBJECT; 384798f75de4SRob Clark 3848960cd9d4SDaniel Vetter if (WARN_ON(!(flags & DRM_MODE_PROP_ATOMIC))) 3849960cd9d4SDaniel Vetter return NULL; 3850960cd9d4SDaniel Vetter 385198f75de4SRob Clark property = drm_property_create(dev, flags, name, 1); 385298f75de4SRob Clark if (!property) 385398f75de4SRob Clark return NULL; 385498f75de4SRob Clark 385598f75de4SRob Clark property->values[0] = type; 385698f75de4SRob Clark 385798f75de4SRob Clark return property; 385898f75de4SRob Clark } 385998f75de4SRob Clark EXPORT_SYMBOL(drm_property_create_object); 386098f75de4SRob Clark 3861c8e32cc1SDaniel Vetter /** 3862960cd9d4SDaniel Vetter * drm_property_create_bool - create a new boolean property type 3863960cd9d4SDaniel Vetter * @dev: drm device 3864960cd9d4SDaniel Vetter * @flags: flags specifying the property type 3865960cd9d4SDaniel Vetter * @name: name of the property 3866960cd9d4SDaniel Vetter * 3867960cd9d4SDaniel Vetter * This creates a new generic drm property which can then be attached to a drm 3868960cd9d4SDaniel Vetter * object with drm_object_attach_property. The returned property object must be 3869960cd9d4SDaniel Vetter * freed with drm_property_destroy. 3870960cd9d4SDaniel Vetter * 3871960cd9d4SDaniel Vetter * This is implemented as a ranged property with only {0, 1} as valid values. 3872960cd9d4SDaniel Vetter * 3873960cd9d4SDaniel Vetter * Returns: 3874960cd9d4SDaniel Vetter * A pointer to the newly created property on success, NULL on failure. 3875960cd9d4SDaniel Vetter */ 3876960cd9d4SDaniel Vetter struct drm_property *drm_property_create_bool(struct drm_device *dev, int flags, 3877960cd9d4SDaniel Vetter const char *name) 3878960cd9d4SDaniel Vetter { 3879960cd9d4SDaniel Vetter return drm_property_create_range(dev, flags, name, 0, 1); 3880960cd9d4SDaniel Vetter } 3881960cd9d4SDaniel Vetter EXPORT_SYMBOL(drm_property_create_bool); 3882960cd9d4SDaniel Vetter 3883960cd9d4SDaniel Vetter /** 3884c8e32cc1SDaniel Vetter * drm_property_add_enum - add a possible value to an enumeration property 3885c8e32cc1SDaniel Vetter * @property: enumeration property to change 3886c8e32cc1SDaniel Vetter * @index: index of the new enumeration 3887c8e32cc1SDaniel Vetter * @value: value of the new enumeration 3888c8e32cc1SDaniel Vetter * @name: symbolic name of the new enumeration 3889c8e32cc1SDaniel Vetter * 3890c8e32cc1SDaniel Vetter * This functions adds enumerations to a property. 3891c8e32cc1SDaniel Vetter * 3892c8e32cc1SDaniel Vetter * It's use is deprecated, drivers should use one of the more specific helpers 3893c8e32cc1SDaniel Vetter * to directly create the property with all enumerations already attached. 3894c8e32cc1SDaniel Vetter * 3895c8e32cc1SDaniel Vetter * Returns: 3896c8e32cc1SDaniel Vetter * Zero on success, error code on failure. 3897c8e32cc1SDaniel Vetter */ 3898f453ba04SDave Airlie int drm_property_add_enum(struct drm_property *property, int index, 3899f453ba04SDave Airlie uint64_t value, const char *name) 3900f453ba04SDave Airlie { 3901f453ba04SDave Airlie struct drm_property_enum *prop_enum; 3902f453ba04SDave Airlie 39035ea22f24SRob Clark if (!(drm_property_type_is(property, DRM_MODE_PROP_ENUM) || 39045ea22f24SRob Clark drm_property_type_is(property, DRM_MODE_PROP_BITMASK))) 390549e27545SRob Clark return -EINVAL; 390649e27545SRob Clark 390749e27545SRob Clark /* 390849e27545SRob Clark * Bitmask enum properties have the additional constraint of values 390949e27545SRob Clark * from 0 to 63 391049e27545SRob Clark */ 39115ea22f24SRob Clark if (drm_property_type_is(property, DRM_MODE_PROP_BITMASK) && 39125ea22f24SRob Clark (value > 63)) 3913f453ba04SDave Airlie return -EINVAL; 3914f453ba04SDave Airlie 39153758b341SDaniel Vetter if (!list_empty(&property->enum_list)) { 39163758b341SDaniel Vetter list_for_each_entry(prop_enum, &property->enum_list, head) { 3917f453ba04SDave Airlie if (prop_enum->value == value) { 3918f453ba04SDave Airlie strncpy(prop_enum->name, name, DRM_PROP_NAME_LEN); 3919f453ba04SDave Airlie prop_enum->name[DRM_PROP_NAME_LEN-1] = '\0'; 3920f453ba04SDave Airlie return 0; 3921f453ba04SDave Airlie } 3922f453ba04SDave Airlie } 3923f453ba04SDave Airlie } 3924f453ba04SDave Airlie 3925f453ba04SDave Airlie prop_enum = kzalloc(sizeof(struct drm_property_enum), GFP_KERNEL); 3926f453ba04SDave Airlie if (!prop_enum) 3927f453ba04SDave Airlie return -ENOMEM; 3928f453ba04SDave Airlie 3929f453ba04SDave Airlie strncpy(prop_enum->name, name, DRM_PROP_NAME_LEN); 3930f453ba04SDave Airlie prop_enum->name[DRM_PROP_NAME_LEN-1] = '\0'; 3931f453ba04SDave Airlie prop_enum->value = value; 3932f453ba04SDave Airlie 3933f453ba04SDave Airlie property->values[index] = value; 39343758b341SDaniel Vetter list_add_tail(&prop_enum->head, &property->enum_list); 3935f453ba04SDave Airlie return 0; 3936f453ba04SDave Airlie } 3937f453ba04SDave Airlie EXPORT_SYMBOL(drm_property_add_enum); 3938f453ba04SDave Airlie 3939c8e32cc1SDaniel Vetter /** 3940c8e32cc1SDaniel Vetter * drm_property_destroy - destroy a drm property 3941c8e32cc1SDaniel Vetter * @dev: drm device 3942c8e32cc1SDaniel Vetter * @property: property to destry 3943c8e32cc1SDaniel Vetter * 3944c8e32cc1SDaniel Vetter * This function frees a property including any attached resources like 3945c8e32cc1SDaniel Vetter * enumeration values. 3946c8e32cc1SDaniel Vetter */ 3947f453ba04SDave Airlie void drm_property_destroy(struct drm_device *dev, struct drm_property *property) 3948f453ba04SDave Airlie { 3949f453ba04SDave Airlie struct drm_property_enum *prop_enum, *pt; 3950f453ba04SDave Airlie 39513758b341SDaniel Vetter list_for_each_entry_safe(prop_enum, pt, &property->enum_list, head) { 3952f453ba04SDave Airlie list_del(&prop_enum->head); 3953f453ba04SDave Airlie kfree(prop_enum); 3954f453ba04SDave Airlie } 3955f453ba04SDave Airlie 3956f453ba04SDave Airlie if (property->num_values) 3957f453ba04SDave Airlie kfree(property->values); 3958f453ba04SDave Airlie drm_mode_object_put(dev, &property->base); 3959f453ba04SDave Airlie list_del(&property->head); 3960f453ba04SDave Airlie kfree(property); 3961f453ba04SDave Airlie } 3962f453ba04SDave Airlie EXPORT_SYMBOL(drm_property_destroy); 3963f453ba04SDave Airlie 3964c8e32cc1SDaniel Vetter /** 3965c8e32cc1SDaniel Vetter * drm_object_attach_property - attach a property to a modeset object 3966c8e32cc1SDaniel Vetter * @obj: drm modeset object 3967c8e32cc1SDaniel Vetter * @property: property to attach 3968c8e32cc1SDaniel Vetter * @init_val: initial value of the property 3969c8e32cc1SDaniel Vetter * 3970c8e32cc1SDaniel Vetter * This attaches the given property to the modeset object with the given initial 3971c8e32cc1SDaniel Vetter * value. Currently this function cannot fail since the properties are stored in 3972c8e32cc1SDaniel Vetter * a statically sized array. 3973c8e32cc1SDaniel Vetter */ 3974c543188aSPaulo Zanoni void drm_object_attach_property(struct drm_mode_object *obj, 3975c543188aSPaulo Zanoni struct drm_property *property, 3976c543188aSPaulo Zanoni uint64_t init_val) 3977c543188aSPaulo Zanoni { 39787f88a9beSPaulo Zanoni int count = obj->properties->count; 3979c543188aSPaulo Zanoni 39807f88a9beSPaulo Zanoni if (count == DRM_OBJECT_MAX_PROPERTY) { 39817f88a9beSPaulo Zanoni WARN(1, "Failed to attach object property (type: 0x%x). Please " 39827f88a9beSPaulo Zanoni "increase DRM_OBJECT_MAX_PROPERTY by 1 for each time " 39837f88a9beSPaulo Zanoni "you see this message on the same object type.\n", 39847f88a9beSPaulo Zanoni obj->type); 3985c543188aSPaulo Zanoni return; 3986c543188aSPaulo Zanoni } 3987c543188aSPaulo Zanoni 3988b17cd757SRob Clark obj->properties->properties[count] = property; 39897f88a9beSPaulo Zanoni obj->properties->values[count] = init_val; 39907f88a9beSPaulo Zanoni obj->properties->count++; 399188a48e29SRob Clark if (property->flags & DRM_MODE_PROP_ATOMIC) 399288a48e29SRob Clark obj->properties->atomic_count++; 3993c543188aSPaulo Zanoni } 3994c543188aSPaulo Zanoni EXPORT_SYMBOL(drm_object_attach_property); 3995c543188aSPaulo Zanoni 3996c8e32cc1SDaniel Vetter /** 3997c8e32cc1SDaniel Vetter * drm_object_property_set_value - set the value of a property 3998c8e32cc1SDaniel Vetter * @obj: drm mode object to set property value for 3999c8e32cc1SDaniel Vetter * @property: property to set 4000c8e32cc1SDaniel Vetter * @val: value the property should be set to 4001c8e32cc1SDaniel Vetter * 4002c8e32cc1SDaniel Vetter * This functions sets a given property on a given object. This function only 4003c8e32cc1SDaniel Vetter * changes the software state of the property, it does not call into the 4004c8e32cc1SDaniel Vetter * driver's ->set_property callback. 4005c8e32cc1SDaniel Vetter * 4006c8e32cc1SDaniel Vetter * Returns: 4007c8e32cc1SDaniel Vetter * Zero on success, error code on failure. 4008c8e32cc1SDaniel Vetter */ 4009c543188aSPaulo Zanoni int drm_object_property_set_value(struct drm_mode_object *obj, 4010c543188aSPaulo Zanoni struct drm_property *property, uint64_t val) 4011c543188aSPaulo Zanoni { 4012c543188aSPaulo Zanoni int i; 4013c543188aSPaulo Zanoni 40147f88a9beSPaulo Zanoni for (i = 0; i < obj->properties->count; i++) { 4015b17cd757SRob Clark if (obj->properties->properties[i] == property) { 4016c543188aSPaulo Zanoni obj->properties->values[i] = val; 4017c543188aSPaulo Zanoni return 0; 4018c543188aSPaulo Zanoni } 4019c543188aSPaulo Zanoni } 4020c543188aSPaulo Zanoni 4021c543188aSPaulo Zanoni return -EINVAL; 4022c543188aSPaulo Zanoni } 4023c543188aSPaulo Zanoni EXPORT_SYMBOL(drm_object_property_set_value); 4024c543188aSPaulo Zanoni 4025c8e32cc1SDaniel Vetter /** 4026c8e32cc1SDaniel Vetter * drm_object_property_get_value - retrieve the value of a property 4027c8e32cc1SDaniel Vetter * @obj: drm mode object to get property value from 4028c8e32cc1SDaniel Vetter * @property: property to retrieve 4029c8e32cc1SDaniel Vetter * @val: storage for the property value 4030c8e32cc1SDaniel Vetter * 4031c8e32cc1SDaniel Vetter * This function retrieves the softare state of the given property for the given 4032c8e32cc1SDaniel Vetter * property. Since there is no driver callback to retrieve the current property 4033c8e32cc1SDaniel Vetter * value this might be out of sync with the hardware, depending upon the driver 4034c8e32cc1SDaniel Vetter * and property. 4035c8e32cc1SDaniel Vetter * 4036c8e32cc1SDaniel Vetter * Returns: 4037c8e32cc1SDaniel Vetter * Zero on success, error code on failure. 4038c8e32cc1SDaniel Vetter */ 4039c543188aSPaulo Zanoni int drm_object_property_get_value(struct drm_mode_object *obj, 4040c543188aSPaulo Zanoni struct drm_property *property, uint64_t *val) 4041c543188aSPaulo Zanoni { 4042c543188aSPaulo Zanoni int i; 4043c543188aSPaulo Zanoni 404488a48e29SRob Clark /* read-only properties bypass atomic mechanism and still store 404588a48e29SRob Clark * their value in obj->properties->values[].. mostly to avoid 404688a48e29SRob Clark * having to deal w/ EDID and similar props in atomic paths: 404788a48e29SRob Clark */ 404888a48e29SRob Clark if (drm_core_check_feature(property->dev, DRIVER_ATOMIC) && 404988a48e29SRob Clark !(property->flags & DRM_MODE_PROP_IMMUTABLE)) 405088a48e29SRob Clark return drm_atomic_get_property(obj, property, val); 405188a48e29SRob Clark 40527f88a9beSPaulo Zanoni for (i = 0; i < obj->properties->count; i++) { 4053b17cd757SRob Clark if (obj->properties->properties[i] == property) { 4054c543188aSPaulo Zanoni *val = obj->properties->values[i]; 4055c543188aSPaulo Zanoni return 0; 4056c543188aSPaulo Zanoni } 4057c543188aSPaulo Zanoni } 4058c543188aSPaulo Zanoni 4059c543188aSPaulo Zanoni return -EINVAL; 4060c543188aSPaulo Zanoni } 4061c543188aSPaulo Zanoni EXPORT_SYMBOL(drm_object_property_get_value); 4062c543188aSPaulo Zanoni 4063c8e32cc1SDaniel Vetter /** 40641a498633SDaniel Vetter * drm_mode_getproperty_ioctl - get the property metadata 4065c8e32cc1SDaniel Vetter * @dev: DRM device 4066c8e32cc1SDaniel Vetter * @data: ioctl data 4067c8e32cc1SDaniel Vetter * @file_priv: DRM file info 4068c8e32cc1SDaniel Vetter * 40691a498633SDaniel Vetter * This function retrieves the metadata for a given property, like the different 40701a498633SDaniel Vetter * possible values for an enum property or the limits for a range property. 40711a498633SDaniel Vetter * 40721a498633SDaniel Vetter * Blob properties are special 4073c8e32cc1SDaniel Vetter * 4074c8e32cc1SDaniel Vetter * Called by the user via ioctl. 4075c8e32cc1SDaniel Vetter * 4076c8e32cc1SDaniel Vetter * Returns: 40771a498633SDaniel Vetter * Zero on success, negative errno on failure. 4078c8e32cc1SDaniel Vetter */ 4079f453ba04SDave Airlie int drm_mode_getproperty_ioctl(struct drm_device *dev, 4080f453ba04SDave Airlie void *data, struct drm_file *file_priv) 4081f453ba04SDave Airlie { 4082f453ba04SDave Airlie struct drm_mode_get_property *out_resp = data; 4083f453ba04SDave Airlie struct drm_property *property; 4084f453ba04SDave Airlie int enum_count = 0; 4085f453ba04SDave Airlie int value_count = 0; 4086f453ba04SDave Airlie int ret = 0, i; 4087f453ba04SDave Airlie int copied; 4088f453ba04SDave Airlie struct drm_property_enum *prop_enum; 4089f453ba04SDave Airlie struct drm_mode_property_enum __user *enum_ptr; 4090f453ba04SDave Airlie uint64_t __user *values_ptr; 4091f453ba04SDave Airlie 4092fb3b06c8SDave Airlie if (!drm_core_check_feature(dev, DRIVER_MODESET)) 4093fb3b06c8SDave Airlie return -EINVAL; 4094fb3b06c8SDave Airlie 409584849903SDaniel Vetter drm_modeset_lock_all(dev); 4096a2b34e22SRob Clark property = drm_property_find(dev, out_resp->prop_id); 4097a2b34e22SRob Clark if (!property) { 4098f27657f2SVille Syrjälä ret = -ENOENT; 4099f453ba04SDave Airlie goto done; 4100f453ba04SDave Airlie } 4101f453ba04SDave Airlie 41025ea22f24SRob Clark if (drm_property_type_is(property, DRM_MODE_PROP_ENUM) || 41035ea22f24SRob Clark drm_property_type_is(property, DRM_MODE_PROP_BITMASK)) { 41043758b341SDaniel Vetter list_for_each_entry(prop_enum, &property->enum_list, head) 4105f453ba04SDave Airlie enum_count++; 4106f453ba04SDave Airlie } 4107f453ba04SDave Airlie 4108f453ba04SDave Airlie value_count = property->num_values; 4109f453ba04SDave Airlie 4110f453ba04SDave Airlie strncpy(out_resp->name, property->name, DRM_PROP_NAME_LEN); 4111f453ba04SDave Airlie out_resp->name[DRM_PROP_NAME_LEN-1] = 0; 4112f453ba04SDave Airlie out_resp->flags = property->flags; 4113f453ba04SDave Airlie 4114f453ba04SDave Airlie if ((out_resp->count_values >= value_count) && value_count) { 411581f6c7f8SVille Syrjälä values_ptr = (uint64_t __user *)(unsigned long)out_resp->values_ptr; 4116f453ba04SDave Airlie for (i = 0; i < value_count; i++) { 4117f453ba04SDave Airlie if (copy_to_user(values_ptr + i, &property->values[i], sizeof(uint64_t))) { 4118f453ba04SDave Airlie ret = -EFAULT; 4119f453ba04SDave Airlie goto done; 4120f453ba04SDave Airlie } 4121f453ba04SDave Airlie } 4122f453ba04SDave Airlie } 4123f453ba04SDave Airlie out_resp->count_values = value_count; 4124f453ba04SDave Airlie 41255ea22f24SRob Clark if (drm_property_type_is(property, DRM_MODE_PROP_ENUM) || 41265ea22f24SRob Clark drm_property_type_is(property, DRM_MODE_PROP_BITMASK)) { 4127f453ba04SDave Airlie if ((out_resp->count_enum_blobs >= enum_count) && enum_count) { 4128f453ba04SDave Airlie copied = 0; 412981f6c7f8SVille Syrjälä enum_ptr = (struct drm_mode_property_enum __user *)(unsigned long)out_resp->enum_blob_ptr; 41303758b341SDaniel Vetter list_for_each_entry(prop_enum, &property->enum_list, head) { 4131f453ba04SDave Airlie 4132f453ba04SDave Airlie if (copy_to_user(&enum_ptr[copied].value, &prop_enum->value, sizeof(uint64_t))) { 4133f453ba04SDave Airlie ret = -EFAULT; 4134f453ba04SDave Airlie goto done; 4135f453ba04SDave Airlie } 4136f453ba04SDave Airlie 4137f453ba04SDave Airlie if (copy_to_user(&enum_ptr[copied].name, 4138f453ba04SDave Airlie &prop_enum->name, DRM_PROP_NAME_LEN)) { 4139f453ba04SDave Airlie ret = -EFAULT; 4140f453ba04SDave Airlie goto done; 4141f453ba04SDave Airlie } 4142f453ba04SDave Airlie copied++; 4143f453ba04SDave Airlie } 4144f453ba04SDave Airlie } 4145f453ba04SDave Airlie out_resp->count_enum_blobs = enum_count; 4146f453ba04SDave Airlie } 4147f453ba04SDave Airlie 41483758b341SDaniel Vetter /* 41493758b341SDaniel Vetter * NOTE: The idea seems to have been to use this to read all the blob 41503758b341SDaniel Vetter * property values. But nothing ever added them to the corresponding 41513758b341SDaniel Vetter * list, userspace always used the special-purpose get_blob ioctl to 41523758b341SDaniel Vetter * read the value for a blob property. It also doesn't make a lot of 41533758b341SDaniel Vetter * sense to return values here when everything else is just metadata for 41543758b341SDaniel Vetter * the property itself. 41553758b341SDaniel Vetter */ 41563758b341SDaniel Vetter if (drm_property_type_is(property, DRM_MODE_PROP_BLOB)) 41573758b341SDaniel Vetter out_resp->count_enum_blobs = 0; 4158f453ba04SDave Airlie done: 415984849903SDaniel Vetter drm_modeset_unlock_all(dev); 4160f453ba04SDave Airlie return ret; 4161f453ba04SDave Airlie } 4162f453ba04SDave Airlie 4163ecbbe59bSThierry Reding static struct drm_property_blob * 4164ecbbe59bSThierry Reding drm_property_create_blob(struct drm_device *dev, size_t length, 416512e6cecdSThierry Reding const void *data) 4166f453ba04SDave Airlie { 4167f453ba04SDave Airlie struct drm_property_blob *blob; 41686bfc56aaSVille Syrjälä int ret; 4169f453ba04SDave Airlie 4170f453ba04SDave Airlie if (!length || !data) 4171f453ba04SDave Airlie return NULL; 4172f453ba04SDave Airlie 4173f453ba04SDave Airlie blob = kzalloc(sizeof(struct drm_property_blob)+length, GFP_KERNEL); 4174f453ba04SDave Airlie if (!blob) 4175f453ba04SDave Airlie return NULL; 4176f453ba04SDave Airlie 41776bfc56aaSVille Syrjälä ret = drm_mode_object_get(dev, &blob->base, DRM_MODE_OBJECT_BLOB); 41786bfc56aaSVille Syrjälä if (ret) { 41796bfc56aaSVille Syrjälä kfree(blob); 41806bfc56aaSVille Syrjälä return NULL; 41816bfc56aaSVille Syrjälä } 41826bfc56aaSVille Syrjälä 4183f453ba04SDave Airlie blob->length = length; 4184f453ba04SDave Airlie 4185f453ba04SDave Airlie memcpy(blob->data, data, length); 4186f453ba04SDave Airlie 4187f453ba04SDave Airlie list_add_tail(&blob->head, &dev->mode_config.property_blob_list); 4188f453ba04SDave Airlie return blob; 4189f453ba04SDave Airlie } 4190f453ba04SDave Airlie 4191f453ba04SDave Airlie static void drm_property_destroy_blob(struct drm_device *dev, 4192f453ba04SDave Airlie struct drm_property_blob *blob) 4193f453ba04SDave Airlie { 4194f453ba04SDave Airlie drm_mode_object_put(dev, &blob->base); 4195f453ba04SDave Airlie list_del(&blob->head); 4196f453ba04SDave Airlie kfree(blob); 4197f453ba04SDave Airlie } 4198f453ba04SDave Airlie 4199c8e32cc1SDaniel Vetter /** 4200c8e32cc1SDaniel Vetter * drm_mode_getblob_ioctl - get the contents of a blob property value 4201c8e32cc1SDaniel Vetter * @dev: DRM device 4202c8e32cc1SDaniel Vetter * @data: ioctl data 4203c8e32cc1SDaniel Vetter * @file_priv: DRM file info 4204c8e32cc1SDaniel Vetter * 4205c8e32cc1SDaniel Vetter * This function retrieves the contents of a blob property. The value stored in 4206c8e32cc1SDaniel Vetter * an object's blob property is just a normal modeset object id. 4207c8e32cc1SDaniel Vetter * 4208c8e32cc1SDaniel Vetter * Called by the user via ioctl. 4209c8e32cc1SDaniel Vetter * 4210c8e32cc1SDaniel Vetter * Returns: 42111a498633SDaniel Vetter * Zero on success, negative errno on failure. 4212c8e32cc1SDaniel Vetter */ 4213f453ba04SDave Airlie int drm_mode_getblob_ioctl(struct drm_device *dev, 4214f453ba04SDave Airlie void *data, struct drm_file *file_priv) 4215f453ba04SDave Airlie { 4216f453ba04SDave Airlie struct drm_mode_get_blob *out_resp = data; 4217f453ba04SDave Airlie struct drm_property_blob *blob; 4218f453ba04SDave Airlie int ret = 0; 421981f6c7f8SVille Syrjälä void __user *blob_ptr; 4220f453ba04SDave Airlie 4221fb3b06c8SDave Airlie if (!drm_core_check_feature(dev, DRIVER_MODESET)) 4222fb3b06c8SDave Airlie return -EINVAL; 4223fb3b06c8SDave Airlie 422484849903SDaniel Vetter drm_modeset_lock_all(dev); 4225a2b34e22SRob Clark blob = drm_property_blob_find(dev, out_resp->blob_id); 4226a2b34e22SRob Clark if (!blob) { 4227f27657f2SVille Syrjälä ret = -ENOENT; 4228f453ba04SDave Airlie goto done; 4229f453ba04SDave Airlie } 4230f453ba04SDave Airlie 4231f453ba04SDave Airlie if (out_resp->length == blob->length) { 423281f6c7f8SVille Syrjälä blob_ptr = (void __user *)(unsigned long)out_resp->data; 4233f453ba04SDave Airlie if (copy_to_user(blob_ptr, blob->data, blob->length)) { 4234f453ba04SDave Airlie ret = -EFAULT; 4235f453ba04SDave Airlie goto done; 4236f453ba04SDave Airlie } 4237f453ba04SDave Airlie } 4238f453ba04SDave Airlie out_resp->length = blob->length; 4239f453ba04SDave Airlie 4240f453ba04SDave Airlie done: 424184849903SDaniel Vetter drm_modeset_unlock_all(dev); 4242f453ba04SDave Airlie return ret; 4243f453ba04SDave Airlie } 4244f453ba04SDave Airlie 4245cc7096fbSDave Airlie /** 4246cc7096fbSDave Airlie * drm_mode_connector_set_path_property - set tile property on connector 4247cc7096fbSDave Airlie * @connector: connector to set property on. 4248cc7096fbSDave Airlie * @path: path to use for property. 4249cc7096fbSDave Airlie * 4250cc7096fbSDave Airlie * This creates a property to expose to userspace to specify a 4251cc7096fbSDave Airlie * connector path. This is mainly used for DisplayPort MST where 4252cc7096fbSDave Airlie * connectors have a topology and we want to allow userspace to give 4253cc7096fbSDave Airlie * them more meaningful names. 4254cc7096fbSDave Airlie * 4255cc7096fbSDave Airlie * Returns: 42561a498633SDaniel Vetter * Zero on success, negative errno on failure. 4257cc7096fbSDave Airlie */ 425843aba7ebSDave Airlie int drm_mode_connector_set_path_property(struct drm_connector *connector, 425912e6cecdSThierry Reding const char *path) 426043aba7ebSDave Airlie { 426143aba7ebSDave Airlie struct drm_device *dev = connector->dev; 4262ecbbe59bSThierry Reding size_t size = strlen(path) + 1; 4263ecbbe59bSThierry Reding int ret; 426443aba7ebSDave Airlie 426543aba7ebSDave Airlie connector->path_blob_ptr = drm_property_create_blob(connector->dev, 426643aba7ebSDave Airlie size, path); 426743aba7ebSDave Airlie if (!connector->path_blob_ptr) 426843aba7ebSDave Airlie return -EINVAL; 426943aba7ebSDave Airlie 427043aba7ebSDave Airlie ret = drm_object_property_set_value(&connector->base, 427143aba7ebSDave Airlie dev->mode_config.path_property, 427243aba7ebSDave Airlie connector->path_blob_ptr->base.id); 427343aba7ebSDave Airlie return ret; 427443aba7ebSDave Airlie } 427543aba7ebSDave Airlie EXPORT_SYMBOL(drm_mode_connector_set_path_property); 427643aba7ebSDave Airlie 4277c8e32cc1SDaniel Vetter /** 42786f134d7bSDave Airlie * drm_mode_connector_set_tile_property - set tile property on connector 42796f134d7bSDave Airlie * @connector: connector to set property on. 42806f134d7bSDave Airlie * 42816f134d7bSDave Airlie * This looks up the tile information for a connector, and creates a 42826f134d7bSDave Airlie * property for userspace to parse if it exists. The property is of 42836f134d7bSDave Airlie * the form of 8 integers using ':' as a separator. 42846f134d7bSDave Airlie * 42856f134d7bSDave Airlie * Returns: 42866f134d7bSDave Airlie * Zero on success, errno on failure. 42876f134d7bSDave Airlie */ 42886f134d7bSDave Airlie int drm_mode_connector_set_tile_property(struct drm_connector *connector) 42896f134d7bSDave Airlie { 42906f134d7bSDave Airlie struct drm_device *dev = connector->dev; 42916f134d7bSDave Airlie int ret, size; 42926f134d7bSDave Airlie char tile[256]; 42936f134d7bSDave Airlie 42946f134d7bSDave Airlie if (connector->tile_blob_ptr) 42956f134d7bSDave Airlie drm_property_destroy_blob(dev, connector->tile_blob_ptr); 42966f134d7bSDave Airlie 42976f134d7bSDave Airlie if (!connector->has_tile) { 42986f134d7bSDave Airlie connector->tile_blob_ptr = NULL; 42996f134d7bSDave Airlie ret = drm_object_property_set_value(&connector->base, 43006f134d7bSDave Airlie dev->mode_config.tile_property, 0); 43016f134d7bSDave Airlie return ret; 43026f134d7bSDave Airlie } 43036f134d7bSDave Airlie 43046f134d7bSDave Airlie snprintf(tile, 256, "%d:%d:%d:%d:%d:%d:%d:%d", 43056f134d7bSDave Airlie connector->tile_group->id, connector->tile_is_single_monitor, 43066f134d7bSDave Airlie connector->num_h_tile, connector->num_v_tile, 43076f134d7bSDave Airlie connector->tile_h_loc, connector->tile_v_loc, 43086f134d7bSDave Airlie connector->tile_h_size, connector->tile_v_size); 43096f134d7bSDave Airlie size = strlen(tile) + 1; 43106f134d7bSDave Airlie 43116f134d7bSDave Airlie connector->tile_blob_ptr = drm_property_create_blob(connector->dev, 43126f134d7bSDave Airlie size, tile); 43136f134d7bSDave Airlie if (!connector->tile_blob_ptr) 43146f134d7bSDave Airlie return -EINVAL; 43156f134d7bSDave Airlie 43166f134d7bSDave Airlie ret = drm_object_property_set_value(&connector->base, 43176f134d7bSDave Airlie dev->mode_config.tile_property, 43186f134d7bSDave Airlie connector->tile_blob_ptr->base.id); 43196f134d7bSDave Airlie return ret; 43206f134d7bSDave Airlie } 43216f134d7bSDave Airlie EXPORT_SYMBOL(drm_mode_connector_set_tile_property); 43226f134d7bSDave Airlie 43236f134d7bSDave Airlie /** 4324c8e32cc1SDaniel Vetter * drm_mode_connector_update_edid_property - update the edid property of a connector 4325c8e32cc1SDaniel Vetter * @connector: drm connector 4326c8e32cc1SDaniel Vetter * @edid: new value of the edid property 4327c8e32cc1SDaniel Vetter * 4328c8e32cc1SDaniel Vetter * This function creates a new blob modeset object and assigns its id to the 4329c8e32cc1SDaniel Vetter * connector's edid property. 4330c8e32cc1SDaniel Vetter * 4331c8e32cc1SDaniel Vetter * Returns: 43321a498633SDaniel Vetter * Zero on success, negative errno on failure. 4333c8e32cc1SDaniel Vetter */ 4334f453ba04SDave Airlie int drm_mode_connector_update_edid_property(struct drm_connector *connector, 433512e6cecdSThierry Reding const struct edid *edid) 4336f453ba04SDave Airlie { 4337f453ba04SDave Airlie struct drm_device *dev = connector->dev; 4338ecbbe59bSThierry Reding size_t size; 4339ecbbe59bSThierry Reding int ret; 4340f453ba04SDave Airlie 43414cf2b281SThomas Wood /* ignore requests to set edid when overridden */ 43424cf2b281SThomas Wood if (connector->override_edid) 43434cf2b281SThomas Wood return 0; 43444cf2b281SThomas Wood 4345f453ba04SDave Airlie if (connector->edid_blob_ptr) 4346f453ba04SDave Airlie drm_property_destroy_blob(dev, connector->edid_blob_ptr); 4347f453ba04SDave Airlie 4348f453ba04SDave Airlie /* Delete edid, when there is none. */ 4349f453ba04SDave Airlie if (!edid) { 4350f453ba04SDave Airlie connector->edid_blob_ptr = NULL; 435158495563SRob Clark ret = drm_object_property_set_value(&connector->base, dev->mode_config.edid_property, 0); 4352f453ba04SDave Airlie return ret; 4353f453ba04SDave Airlie } 4354f453ba04SDave Airlie 43557466f4ccSAdam Jackson size = EDID_LENGTH * (1 + edid->extensions); 43567466f4ccSAdam Jackson connector->edid_blob_ptr = drm_property_create_blob(connector->dev, 43577466f4ccSAdam Jackson size, edid); 4358e655d122SSachin Kamat if (!connector->edid_blob_ptr) 4359e655d122SSachin Kamat return -EINVAL; 4360f453ba04SDave Airlie 436158495563SRob Clark ret = drm_object_property_set_value(&connector->base, 4362f453ba04SDave Airlie dev->mode_config.edid_property, 4363f453ba04SDave Airlie connector->edid_blob_ptr->base.id); 4364f453ba04SDave Airlie 4365f453ba04SDave Airlie return ret; 4366f453ba04SDave Airlie } 4367f453ba04SDave Airlie EXPORT_SYMBOL(drm_mode_connector_update_edid_property); 4368f453ba04SDave Airlie 43693843e71fSRob Clark /* Some properties could refer to dynamic refcnt'd objects, or things that 43703843e71fSRob Clark * need special locking to handle lifetime issues (ie. to ensure the prop 43713843e71fSRob Clark * value doesn't become invalid part way through the property update due to 43723843e71fSRob Clark * race). The value returned by reference via 'obj' should be passed back 43733843e71fSRob Clark * to drm_property_change_valid_put() after the property is set (and the 43743843e71fSRob Clark * object to which the property is attached has a chance to take it's own 43753843e71fSRob Clark * reference). 43763843e71fSRob Clark */ 4377d34f20d6SRob Clark bool drm_property_change_valid_get(struct drm_property *property, 43783843e71fSRob Clark uint64_t value, struct drm_mode_object **ref) 437926a34815SPaulo Zanoni { 43802ca651d1SThierry Reding int i; 43812ca651d1SThierry Reding 438226a34815SPaulo Zanoni if (property->flags & DRM_MODE_PROP_IMMUTABLE) 438326a34815SPaulo Zanoni return false; 43845ea22f24SRob Clark 43853843e71fSRob Clark *ref = NULL; 43863843e71fSRob Clark 43875ea22f24SRob Clark if (drm_property_type_is(property, DRM_MODE_PROP_RANGE)) { 438826a34815SPaulo Zanoni if (value < property->values[0] || value > property->values[1]) 438926a34815SPaulo Zanoni return false; 439026a34815SPaulo Zanoni return true; 4391ebc44cf3SRob Clark } else if (drm_property_type_is(property, DRM_MODE_PROP_SIGNED_RANGE)) { 4392ebc44cf3SRob Clark int64_t svalue = U642I64(value); 43934dfd909fSThierry Reding 4394ebc44cf3SRob Clark if (svalue < U642I64(property->values[0]) || 4395ebc44cf3SRob Clark svalue > U642I64(property->values[1])) 4396ebc44cf3SRob Clark return false; 4397ebc44cf3SRob Clark return true; 43985ea22f24SRob Clark } else if (drm_property_type_is(property, DRM_MODE_PROP_BITMASK)) { 4399592c20eeSVille Syrjälä uint64_t valid_mask = 0; 44004dfd909fSThierry Reding 440149e27545SRob Clark for (i = 0; i < property->num_values; i++) 440249e27545SRob Clark valid_mask |= (1ULL << property->values[i]); 440349e27545SRob Clark return !(value & ~valid_mask); 44045ea22f24SRob Clark } else if (drm_property_type_is(property, DRM_MODE_PROP_BLOB)) { 4405c4a56750SVille Syrjälä /* Only the driver knows */ 4406c4a56750SVille Syrjälä return true; 440798f75de4SRob Clark } else if (drm_property_type_is(property, DRM_MODE_PROP_OBJECT)) { 440898f75de4SRob Clark /* a zero value for an object property translates to null: */ 440998f75de4SRob Clark if (value == 0) 441098f75de4SRob Clark return true; 44113843e71fSRob Clark 44123843e71fSRob Clark /* handle refcnt'd objects specially: */ 44133843e71fSRob Clark if (property->values[0] == DRM_MODE_OBJECT_FB) { 44143843e71fSRob Clark struct drm_framebuffer *fb; 44153843e71fSRob Clark fb = drm_framebuffer_lookup(property->dev, value); 44163843e71fSRob Clark if (fb) { 44173843e71fSRob Clark *ref = &fb->base; 44183843e71fSRob Clark return true; 44193843e71fSRob Clark } else { 44203843e71fSRob Clark return false; 44213843e71fSRob Clark } 44223843e71fSRob Clark } else { 44233843e71fSRob Clark return _object_find(property->dev, value, property->values[0]) != NULL; 44243843e71fSRob Clark } 44252ca651d1SThierry Reding } 44262ca651d1SThierry Reding 442726a34815SPaulo Zanoni for (i = 0; i < property->num_values; i++) 442826a34815SPaulo Zanoni if (property->values[i] == value) 442926a34815SPaulo Zanoni return true; 443026a34815SPaulo Zanoni return false; 443126a34815SPaulo Zanoni } 443226a34815SPaulo Zanoni 4433d34f20d6SRob Clark void drm_property_change_valid_put(struct drm_property *property, 44343843e71fSRob Clark struct drm_mode_object *ref) 44353843e71fSRob Clark { 44363843e71fSRob Clark if (!ref) 44373843e71fSRob Clark return; 44383843e71fSRob Clark 44393843e71fSRob Clark if (drm_property_type_is(property, DRM_MODE_PROP_OBJECT)) { 44403843e71fSRob Clark if (property->values[0] == DRM_MODE_OBJECT_FB) 44413843e71fSRob Clark drm_framebuffer_unreference(obj_to_fb(ref)); 44423843e71fSRob Clark } 44433843e71fSRob Clark } 44443843e71fSRob Clark 4445c8e32cc1SDaniel Vetter /** 4446c8e32cc1SDaniel Vetter * drm_mode_connector_property_set_ioctl - set the current value of a connector property 4447c8e32cc1SDaniel Vetter * @dev: DRM device 4448c8e32cc1SDaniel Vetter * @data: ioctl data 4449c8e32cc1SDaniel Vetter * @file_priv: DRM file info 4450c8e32cc1SDaniel Vetter * 4451c8e32cc1SDaniel Vetter * This function sets the current value for a connectors's property. It also 4452c8e32cc1SDaniel Vetter * calls into a driver's ->set_property callback to update the hardware state 4453c8e32cc1SDaniel Vetter * 4454c8e32cc1SDaniel Vetter * Called by the user via ioctl. 4455c8e32cc1SDaniel Vetter * 4456c8e32cc1SDaniel Vetter * Returns: 44571a498633SDaniel Vetter * Zero on success, negative errno on failure. 4458c8e32cc1SDaniel Vetter */ 4459f453ba04SDave Airlie int drm_mode_connector_property_set_ioctl(struct drm_device *dev, 4460f453ba04SDave Airlie void *data, struct drm_file *file_priv) 4461f453ba04SDave Airlie { 44620057d8ddSPaulo Zanoni struct drm_mode_connector_set_property *conn_set_prop = data; 44630057d8ddSPaulo Zanoni struct drm_mode_obj_set_property obj_set_prop = { 44640057d8ddSPaulo Zanoni .value = conn_set_prop->value, 44650057d8ddSPaulo Zanoni .prop_id = conn_set_prop->prop_id, 44660057d8ddSPaulo Zanoni .obj_id = conn_set_prop->connector_id, 44670057d8ddSPaulo Zanoni .obj_type = DRM_MODE_OBJECT_CONNECTOR 44680057d8ddSPaulo Zanoni }; 4469f453ba04SDave Airlie 44700057d8ddSPaulo Zanoni /* It does all the locking and checking we need */ 44710057d8ddSPaulo Zanoni return drm_mode_obj_set_property_ioctl(dev, &obj_set_prop, file_priv); 4472f453ba04SDave Airlie } 4473f453ba04SDave Airlie 4474c543188aSPaulo Zanoni static int drm_mode_connector_set_obj_prop(struct drm_mode_object *obj, 4475c543188aSPaulo Zanoni struct drm_property *property, 4476c543188aSPaulo Zanoni uint64_t value) 4477c543188aSPaulo Zanoni { 4478c543188aSPaulo Zanoni int ret = -EINVAL; 4479c543188aSPaulo Zanoni struct drm_connector *connector = obj_to_connector(obj); 4480c543188aSPaulo Zanoni 4481c543188aSPaulo Zanoni /* Do DPMS ourselves */ 4482c543188aSPaulo Zanoni if (property == connector->dev->mode_config.dpms_property) { 4483c543188aSPaulo Zanoni if (connector->funcs->dpms) 4484c543188aSPaulo Zanoni (*connector->funcs->dpms)(connector, (int)value); 4485c543188aSPaulo Zanoni ret = 0; 4486c543188aSPaulo Zanoni } else if (connector->funcs->set_property) 4487c543188aSPaulo Zanoni ret = connector->funcs->set_property(connector, property, value); 4488c543188aSPaulo Zanoni 4489c543188aSPaulo Zanoni /* store the property value if successful */ 4490c543188aSPaulo Zanoni if (!ret) 449158495563SRob Clark drm_object_property_set_value(&connector->base, property, value); 4492c543188aSPaulo Zanoni return ret; 4493c543188aSPaulo Zanoni } 4494c543188aSPaulo Zanoni 4495bffd9de0SPaulo Zanoni static int drm_mode_crtc_set_obj_prop(struct drm_mode_object *obj, 4496bffd9de0SPaulo Zanoni struct drm_property *property, 4497bffd9de0SPaulo Zanoni uint64_t value) 4498bffd9de0SPaulo Zanoni { 4499bffd9de0SPaulo Zanoni int ret = -EINVAL; 4500bffd9de0SPaulo Zanoni struct drm_crtc *crtc = obj_to_crtc(obj); 4501bffd9de0SPaulo Zanoni 4502bffd9de0SPaulo Zanoni if (crtc->funcs->set_property) 4503bffd9de0SPaulo Zanoni ret = crtc->funcs->set_property(crtc, property, value); 4504bffd9de0SPaulo Zanoni if (!ret) 4505bffd9de0SPaulo Zanoni drm_object_property_set_value(obj, property, value); 4506bffd9de0SPaulo Zanoni 4507bffd9de0SPaulo Zanoni return ret; 4508bffd9de0SPaulo Zanoni } 4509bffd9de0SPaulo Zanoni 45103a5f87c2SThomas Wood /** 45113a5f87c2SThomas Wood * drm_mode_plane_set_obj_prop - set the value of a property 45123a5f87c2SThomas Wood * @plane: drm plane object to set property value for 45133a5f87c2SThomas Wood * @property: property to set 45143a5f87c2SThomas Wood * @value: value the property should be set to 45153a5f87c2SThomas Wood * 45163a5f87c2SThomas Wood * This functions sets a given property on a given plane object. This function 45173a5f87c2SThomas Wood * calls the driver's ->set_property callback and changes the software state of 45183a5f87c2SThomas Wood * the property if the callback succeeds. 45193a5f87c2SThomas Wood * 45203a5f87c2SThomas Wood * Returns: 45213a5f87c2SThomas Wood * Zero on success, error code on failure. 45223a5f87c2SThomas Wood */ 45233a5f87c2SThomas Wood int drm_mode_plane_set_obj_prop(struct drm_plane *plane, 45244d93914aSRob Clark struct drm_property *property, 45254d93914aSRob Clark uint64_t value) 45264d93914aSRob Clark { 45274d93914aSRob Clark int ret = -EINVAL; 45283a5f87c2SThomas Wood struct drm_mode_object *obj = &plane->base; 45294d93914aSRob Clark 45304d93914aSRob Clark if (plane->funcs->set_property) 45314d93914aSRob Clark ret = plane->funcs->set_property(plane, property, value); 45324d93914aSRob Clark if (!ret) 45334d93914aSRob Clark drm_object_property_set_value(obj, property, value); 45344d93914aSRob Clark 45354d93914aSRob Clark return ret; 45364d93914aSRob Clark } 45373a5f87c2SThomas Wood EXPORT_SYMBOL(drm_mode_plane_set_obj_prop); 45384d93914aSRob Clark 4539c8e32cc1SDaniel Vetter /** 45401a498633SDaniel Vetter * drm_mode_obj_get_properties_ioctl - get the current value of a object's property 4541c8e32cc1SDaniel Vetter * @dev: DRM device 4542c8e32cc1SDaniel Vetter * @data: ioctl data 4543c8e32cc1SDaniel Vetter * @file_priv: DRM file info 4544c8e32cc1SDaniel Vetter * 4545c8e32cc1SDaniel Vetter * This function retrieves the current value for an object's property. Compared 4546c8e32cc1SDaniel Vetter * to the connector specific ioctl this one is extended to also work on crtc and 4547c8e32cc1SDaniel Vetter * plane objects. 4548c8e32cc1SDaniel Vetter * 4549c8e32cc1SDaniel Vetter * Called by the user via ioctl. 4550c8e32cc1SDaniel Vetter * 4551c8e32cc1SDaniel Vetter * Returns: 45521a498633SDaniel Vetter * Zero on success, negative errno on failure. 4553c8e32cc1SDaniel Vetter */ 4554c543188aSPaulo Zanoni int drm_mode_obj_get_properties_ioctl(struct drm_device *dev, void *data, 4555c543188aSPaulo Zanoni struct drm_file *file_priv) 4556c543188aSPaulo Zanoni { 4557c543188aSPaulo Zanoni struct drm_mode_obj_get_properties *arg = data; 4558c543188aSPaulo Zanoni struct drm_mode_object *obj; 4559c543188aSPaulo Zanoni int ret = 0; 4560c543188aSPaulo Zanoni 4561c543188aSPaulo Zanoni if (!drm_core_check_feature(dev, DRIVER_MODESET)) 4562c543188aSPaulo Zanoni return -EINVAL; 4563c543188aSPaulo Zanoni 456484849903SDaniel Vetter drm_modeset_lock_all(dev); 4565c543188aSPaulo Zanoni 4566c543188aSPaulo Zanoni obj = drm_mode_object_find(dev, arg->obj_id, arg->obj_type); 4567c543188aSPaulo Zanoni if (!obj) { 4568f27657f2SVille Syrjälä ret = -ENOENT; 4569c543188aSPaulo Zanoni goto out; 4570c543188aSPaulo Zanoni } 4571c543188aSPaulo Zanoni if (!obj->properties) { 4572c543188aSPaulo Zanoni ret = -EINVAL; 4573c543188aSPaulo Zanoni goto out; 4574c543188aSPaulo Zanoni } 4575c543188aSPaulo Zanoni 457688a48e29SRob Clark ret = get_properties(obj, file_priv->atomic, 457795cbf110SRob Clark (uint32_t __user *)(unsigned long)(arg->props_ptr), 457895cbf110SRob Clark (uint64_t __user *)(unsigned long)(arg->prop_values_ptr), 457995cbf110SRob Clark &arg->count_props); 4580c543188aSPaulo Zanoni 4581c543188aSPaulo Zanoni out: 458284849903SDaniel Vetter drm_modeset_unlock_all(dev); 4583c543188aSPaulo Zanoni return ret; 4584c543188aSPaulo Zanoni } 4585c543188aSPaulo Zanoni 4586c8e32cc1SDaniel Vetter /** 4587c8e32cc1SDaniel Vetter * drm_mode_obj_set_property_ioctl - set the current value of an object's property 4588c8e32cc1SDaniel Vetter * @dev: DRM device 4589c8e32cc1SDaniel Vetter * @data: ioctl data 4590c8e32cc1SDaniel Vetter * @file_priv: DRM file info 4591c8e32cc1SDaniel Vetter * 4592c8e32cc1SDaniel Vetter * This function sets the current value for an object's property. It also calls 4593c8e32cc1SDaniel Vetter * into a driver's ->set_property callback to update the hardware state. 4594c8e32cc1SDaniel Vetter * Compared to the connector specific ioctl this one is extended to also work on 4595c8e32cc1SDaniel Vetter * crtc and plane objects. 4596c8e32cc1SDaniel Vetter * 4597c8e32cc1SDaniel Vetter * Called by the user via ioctl. 4598c8e32cc1SDaniel Vetter * 4599c8e32cc1SDaniel Vetter * Returns: 46001a498633SDaniel Vetter * Zero on success, negative errno on failure. 4601c8e32cc1SDaniel Vetter */ 4602c543188aSPaulo Zanoni int drm_mode_obj_set_property_ioctl(struct drm_device *dev, void *data, 4603c543188aSPaulo Zanoni struct drm_file *file_priv) 4604c543188aSPaulo Zanoni { 4605c543188aSPaulo Zanoni struct drm_mode_obj_set_property *arg = data; 4606c543188aSPaulo Zanoni struct drm_mode_object *arg_obj; 4607c543188aSPaulo Zanoni struct drm_mode_object *prop_obj; 4608c543188aSPaulo Zanoni struct drm_property *property; 46093843e71fSRob Clark int i, ret = -EINVAL; 46103843e71fSRob Clark struct drm_mode_object *ref; 4611c543188aSPaulo Zanoni 4612c543188aSPaulo Zanoni if (!drm_core_check_feature(dev, DRIVER_MODESET)) 4613c543188aSPaulo Zanoni return -EINVAL; 4614c543188aSPaulo Zanoni 461584849903SDaniel Vetter drm_modeset_lock_all(dev); 4616c543188aSPaulo Zanoni 4617c543188aSPaulo Zanoni arg_obj = drm_mode_object_find(dev, arg->obj_id, arg->obj_type); 4618f27657f2SVille Syrjälä if (!arg_obj) { 4619f27657f2SVille Syrjälä ret = -ENOENT; 4620c543188aSPaulo Zanoni goto out; 4621f27657f2SVille Syrjälä } 4622c543188aSPaulo Zanoni if (!arg_obj->properties) 4623c543188aSPaulo Zanoni goto out; 4624c543188aSPaulo Zanoni 46257f88a9beSPaulo Zanoni for (i = 0; i < arg_obj->properties->count; i++) 4626b17cd757SRob Clark if (arg_obj->properties->properties[i]->base.id == arg->prop_id) 4627c543188aSPaulo Zanoni break; 4628c543188aSPaulo Zanoni 46297f88a9beSPaulo Zanoni if (i == arg_obj->properties->count) 4630c543188aSPaulo Zanoni goto out; 4631c543188aSPaulo Zanoni 4632c543188aSPaulo Zanoni prop_obj = drm_mode_object_find(dev, arg->prop_id, 4633c543188aSPaulo Zanoni DRM_MODE_OBJECT_PROPERTY); 4634f27657f2SVille Syrjälä if (!prop_obj) { 4635f27657f2SVille Syrjälä ret = -ENOENT; 4636c543188aSPaulo Zanoni goto out; 4637f27657f2SVille Syrjälä } 4638c543188aSPaulo Zanoni property = obj_to_property(prop_obj); 4639c543188aSPaulo Zanoni 46403843e71fSRob Clark if (!drm_property_change_valid_get(property, arg->value, &ref)) 4641c543188aSPaulo Zanoni goto out; 4642c543188aSPaulo Zanoni 4643c543188aSPaulo Zanoni switch (arg_obj->type) { 4644c543188aSPaulo Zanoni case DRM_MODE_OBJECT_CONNECTOR: 4645c543188aSPaulo Zanoni ret = drm_mode_connector_set_obj_prop(arg_obj, property, 4646c543188aSPaulo Zanoni arg->value); 4647c543188aSPaulo Zanoni break; 4648bffd9de0SPaulo Zanoni case DRM_MODE_OBJECT_CRTC: 4649bffd9de0SPaulo Zanoni ret = drm_mode_crtc_set_obj_prop(arg_obj, property, arg->value); 4650bffd9de0SPaulo Zanoni break; 46514d93914aSRob Clark case DRM_MODE_OBJECT_PLANE: 46523a5f87c2SThomas Wood ret = drm_mode_plane_set_obj_prop(obj_to_plane(arg_obj), 46533a5f87c2SThomas Wood property, arg->value); 46544d93914aSRob Clark break; 4655c543188aSPaulo Zanoni } 4656c543188aSPaulo Zanoni 46573843e71fSRob Clark drm_property_change_valid_put(property, ref); 46583843e71fSRob Clark 4659c543188aSPaulo Zanoni out: 466084849903SDaniel Vetter drm_modeset_unlock_all(dev); 4661c543188aSPaulo Zanoni return ret; 4662c543188aSPaulo Zanoni } 4663c543188aSPaulo Zanoni 4664c8e32cc1SDaniel Vetter /** 4665c8e32cc1SDaniel Vetter * drm_mode_connector_attach_encoder - attach a connector to an encoder 4666c8e32cc1SDaniel Vetter * @connector: connector to attach 4667c8e32cc1SDaniel Vetter * @encoder: encoder to attach @connector to 4668c8e32cc1SDaniel Vetter * 4669c8e32cc1SDaniel Vetter * This function links up a connector to an encoder. Note that the routing 4670c8e32cc1SDaniel Vetter * restrictions between encoders and crtcs are exposed to userspace through the 4671c8e32cc1SDaniel Vetter * possible_clones and possible_crtcs bitmasks. 4672c8e32cc1SDaniel Vetter * 4673c8e32cc1SDaniel Vetter * Returns: 46741a498633SDaniel Vetter * Zero on success, negative errno on failure. 4675c8e32cc1SDaniel Vetter */ 4676f453ba04SDave Airlie int drm_mode_connector_attach_encoder(struct drm_connector *connector, 4677f453ba04SDave Airlie struct drm_encoder *encoder) 4678f453ba04SDave Airlie { 4679f453ba04SDave Airlie int i; 4680f453ba04SDave Airlie 4681f453ba04SDave Airlie for (i = 0; i < DRM_CONNECTOR_MAX_ENCODER; i++) { 4682f453ba04SDave Airlie if (connector->encoder_ids[i] == 0) { 4683f453ba04SDave Airlie connector->encoder_ids[i] = encoder->base.id; 4684f453ba04SDave Airlie return 0; 4685f453ba04SDave Airlie } 4686f453ba04SDave Airlie } 4687f453ba04SDave Airlie return -ENOMEM; 4688f453ba04SDave Airlie } 4689f453ba04SDave Airlie EXPORT_SYMBOL(drm_mode_connector_attach_encoder); 4690f453ba04SDave Airlie 4691c8e32cc1SDaniel Vetter /** 4692c8e32cc1SDaniel Vetter * drm_mode_crtc_set_gamma_size - set the gamma table size 4693c8e32cc1SDaniel Vetter * @crtc: CRTC to set the gamma table size for 4694c8e32cc1SDaniel Vetter * @gamma_size: size of the gamma table 4695c8e32cc1SDaniel Vetter * 4696c8e32cc1SDaniel Vetter * Drivers which support gamma tables should set this to the supported gamma 4697c8e32cc1SDaniel Vetter * table size when initializing the CRTC. Currently the drm core only supports a 4698c8e32cc1SDaniel Vetter * fixed gamma table size. 4699c8e32cc1SDaniel Vetter * 4700c8e32cc1SDaniel Vetter * Returns: 47011a498633SDaniel Vetter * Zero on success, negative errno on failure. 4702c8e32cc1SDaniel Vetter */ 47034cae5b84SSascha Hauer int drm_mode_crtc_set_gamma_size(struct drm_crtc *crtc, 4704f453ba04SDave Airlie int gamma_size) 4705f453ba04SDave Airlie { 4706f453ba04SDave Airlie crtc->gamma_size = gamma_size; 4707f453ba04SDave Airlie 4708bd3f0ff9SThierry Reding crtc->gamma_store = kcalloc(gamma_size, sizeof(uint16_t) * 3, 4709bd3f0ff9SThierry Reding GFP_KERNEL); 4710f453ba04SDave Airlie if (!crtc->gamma_store) { 4711f453ba04SDave Airlie crtc->gamma_size = 0; 47124cae5b84SSascha Hauer return -ENOMEM; 4713f453ba04SDave Airlie } 4714f453ba04SDave Airlie 47154cae5b84SSascha Hauer return 0; 4716f453ba04SDave Airlie } 4717f453ba04SDave Airlie EXPORT_SYMBOL(drm_mode_crtc_set_gamma_size); 4718f453ba04SDave Airlie 4719c8e32cc1SDaniel Vetter /** 4720c8e32cc1SDaniel Vetter * drm_mode_gamma_set_ioctl - set the gamma table 4721c8e32cc1SDaniel Vetter * @dev: DRM device 4722c8e32cc1SDaniel Vetter * @data: ioctl data 4723c8e32cc1SDaniel Vetter * @file_priv: DRM file info 4724c8e32cc1SDaniel Vetter * 4725c8e32cc1SDaniel Vetter * Set the gamma table of a CRTC to the one passed in by the user. Userspace can 4726c8e32cc1SDaniel Vetter * inquire the required gamma table size through drm_mode_gamma_get_ioctl. 4727c8e32cc1SDaniel Vetter * 4728c8e32cc1SDaniel Vetter * Called by the user via ioctl. 4729c8e32cc1SDaniel Vetter * 4730c8e32cc1SDaniel Vetter * Returns: 47311a498633SDaniel Vetter * Zero on success, negative errno on failure. 4732c8e32cc1SDaniel Vetter */ 4733f453ba04SDave Airlie int drm_mode_gamma_set_ioctl(struct drm_device *dev, 4734f453ba04SDave Airlie void *data, struct drm_file *file_priv) 4735f453ba04SDave Airlie { 4736f453ba04SDave Airlie struct drm_mode_crtc_lut *crtc_lut = data; 4737f453ba04SDave Airlie struct drm_crtc *crtc; 4738f453ba04SDave Airlie void *r_base, *g_base, *b_base; 4739f453ba04SDave Airlie int size; 4740f453ba04SDave Airlie int ret = 0; 4741f453ba04SDave Airlie 4742fb3b06c8SDave Airlie if (!drm_core_check_feature(dev, DRIVER_MODESET)) 4743fb3b06c8SDave Airlie return -EINVAL; 4744fb3b06c8SDave Airlie 474584849903SDaniel Vetter drm_modeset_lock_all(dev); 4746a2b34e22SRob Clark crtc = drm_crtc_find(dev, crtc_lut->crtc_id); 4747a2b34e22SRob Clark if (!crtc) { 4748f27657f2SVille Syrjälä ret = -ENOENT; 4749f453ba04SDave Airlie goto out; 4750f453ba04SDave Airlie } 4751f453ba04SDave Airlie 4752ebe0f244SLaurent Pinchart if (crtc->funcs->gamma_set == NULL) { 4753ebe0f244SLaurent Pinchart ret = -ENOSYS; 4754ebe0f244SLaurent Pinchart goto out; 4755ebe0f244SLaurent Pinchart } 4756ebe0f244SLaurent Pinchart 4757f453ba04SDave Airlie /* memcpy into gamma store */ 4758f453ba04SDave Airlie if (crtc_lut->gamma_size != crtc->gamma_size) { 4759f453ba04SDave Airlie ret = -EINVAL; 4760f453ba04SDave Airlie goto out; 4761f453ba04SDave Airlie } 4762f453ba04SDave Airlie 4763f453ba04SDave Airlie size = crtc_lut->gamma_size * (sizeof(uint16_t)); 4764f453ba04SDave Airlie r_base = crtc->gamma_store; 4765f453ba04SDave Airlie if (copy_from_user(r_base, (void __user *)(unsigned long)crtc_lut->red, size)) { 4766f453ba04SDave Airlie ret = -EFAULT; 4767f453ba04SDave Airlie goto out; 4768f453ba04SDave Airlie } 4769f453ba04SDave Airlie 4770f453ba04SDave Airlie g_base = r_base + size; 4771f453ba04SDave Airlie if (copy_from_user(g_base, (void __user *)(unsigned long)crtc_lut->green, size)) { 4772f453ba04SDave Airlie ret = -EFAULT; 4773f453ba04SDave Airlie goto out; 4774f453ba04SDave Airlie } 4775f453ba04SDave Airlie 4776f453ba04SDave Airlie b_base = g_base + size; 4777f453ba04SDave Airlie if (copy_from_user(b_base, (void __user *)(unsigned long)crtc_lut->blue, size)) { 4778f453ba04SDave Airlie ret = -EFAULT; 4779f453ba04SDave Airlie goto out; 4780f453ba04SDave Airlie } 4781f453ba04SDave Airlie 47827203425aSJames Simmons crtc->funcs->gamma_set(crtc, r_base, g_base, b_base, 0, crtc->gamma_size); 4783f453ba04SDave Airlie 4784f453ba04SDave Airlie out: 478584849903SDaniel Vetter drm_modeset_unlock_all(dev); 4786f453ba04SDave Airlie return ret; 4787f453ba04SDave Airlie 4788f453ba04SDave Airlie } 4789f453ba04SDave Airlie 4790c8e32cc1SDaniel Vetter /** 4791c8e32cc1SDaniel Vetter * drm_mode_gamma_get_ioctl - get the gamma table 4792c8e32cc1SDaniel Vetter * @dev: DRM device 4793c8e32cc1SDaniel Vetter * @data: ioctl data 4794c8e32cc1SDaniel Vetter * @file_priv: DRM file info 4795c8e32cc1SDaniel Vetter * 4796c8e32cc1SDaniel Vetter * Copy the current gamma table into the storage provided. This also provides 4797c8e32cc1SDaniel Vetter * the gamma table size the driver expects, which can be used to size the 4798c8e32cc1SDaniel Vetter * allocated storage. 4799c8e32cc1SDaniel Vetter * 4800c8e32cc1SDaniel Vetter * Called by the user via ioctl. 4801c8e32cc1SDaniel Vetter * 4802c8e32cc1SDaniel Vetter * Returns: 48031a498633SDaniel Vetter * Zero on success, negative errno on failure. 4804c8e32cc1SDaniel Vetter */ 4805f453ba04SDave Airlie int drm_mode_gamma_get_ioctl(struct drm_device *dev, 4806f453ba04SDave Airlie void *data, struct drm_file *file_priv) 4807f453ba04SDave Airlie { 4808f453ba04SDave Airlie struct drm_mode_crtc_lut *crtc_lut = data; 4809f453ba04SDave Airlie struct drm_crtc *crtc; 4810f453ba04SDave Airlie void *r_base, *g_base, *b_base; 4811f453ba04SDave Airlie int size; 4812f453ba04SDave Airlie int ret = 0; 4813f453ba04SDave Airlie 4814fb3b06c8SDave Airlie if (!drm_core_check_feature(dev, DRIVER_MODESET)) 4815fb3b06c8SDave Airlie return -EINVAL; 4816fb3b06c8SDave Airlie 481784849903SDaniel Vetter drm_modeset_lock_all(dev); 4818a2b34e22SRob Clark crtc = drm_crtc_find(dev, crtc_lut->crtc_id); 4819a2b34e22SRob Clark if (!crtc) { 4820f27657f2SVille Syrjälä ret = -ENOENT; 4821f453ba04SDave Airlie goto out; 4822f453ba04SDave Airlie } 4823f453ba04SDave Airlie 4824f453ba04SDave Airlie /* memcpy into gamma store */ 4825f453ba04SDave Airlie if (crtc_lut->gamma_size != crtc->gamma_size) { 4826f453ba04SDave Airlie ret = -EINVAL; 4827f453ba04SDave Airlie goto out; 4828f453ba04SDave Airlie } 4829f453ba04SDave Airlie 4830f453ba04SDave Airlie size = crtc_lut->gamma_size * (sizeof(uint16_t)); 4831f453ba04SDave Airlie r_base = crtc->gamma_store; 4832f453ba04SDave Airlie if (copy_to_user((void __user *)(unsigned long)crtc_lut->red, r_base, size)) { 4833f453ba04SDave Airlie ret = -EFAULT; 4834f453ba04SDave Airlie goto out; 4835f453ba04SDave Airlie } 4836f453ba04SDave Airlie 4837f453ba04SDave Airlie g_base = r_base + size; 4838f453ba04SDave Airlie if (copy_to_user((void __user *)(unsigned long)crtc_lut->green, g_base, size)) { 4839f453ba04SDave Airlie ret = -EFAULT; 4840f453ba04SDave Airlie goto out; 4841f453ba04SDave Airlie } 4842f453ba04SDave Airlie 4843f453ba04SDave Airlie b_base = g_base + size; 4844f453ba04SDave Airlie if (copy_to_user((void __user *)(unsigned long)crtc_lut->blue, b_base, size)) { 4845f453ba04SDave Airlie ret = -EFAULT; 4846f453ba04SDave Airlie goto out; 4847f453ba04SDave Airlie } 4848f453ba04SDave Airlie out: 484984849903SDaniel Vetter drm_modeset_unlock_all(dev); 4850f453ba04SDave Airlie return ret; 4851f453ba04SDave Airlie } 4852d91d8a3fSKristian Høgsberg 4853c8e32cc1SDaniel Vetter /** 4854c8e32cc1SDaniel Vetter * drm_mode_page_flip_ioctl - schedule an asynchronous fb update 4855c8e32cc1SDaniel Vetter * @dev: DRM device 4856c8e32cc1SDaniel Vetter * @data: ioctl data 4857c8e32cc1SDaniel Vetter * @file_priv: DRM file info 4858c8e32cc1SDaniel Vetter * 4859c8e32cc1SDaniel Vetter * This schedules an asynchronous update on a given CRTC, called page flip. 4860c8e32cc1SDaniel Vetter * Optionally a drm event is generated to signal the completion of the event. 4861c8e32cc1SDaniel Vetter * Generic drivers cannot assume that a pageflip with changed framebuffer 4862c8e32cc1SDaniel Vetter * properties (including driver specific metadata like tiling layout) will work, 4863c8e32cc1SDaniel Vetter * but some drivers support e.g. pixel format changes through the pageflip 4864c8e32cc1SDaniel Vetter * ioctl. 4865c8e32cc1SDaniel Vetter * 4866c8e32cc1SDaniel Vetter * Called by the user via ioctl. 4867c8e32cc1SDaniel Vetter * 4868c8e32cc1SDaniel Vetter * Returns: 48691a498633SDaniel Vetter * Zero on success, negative errno on failure. 4870c8e32cc1SDaniel Vetter */ 4871d91d8a3fSKristian Høgsberg int drm_mode_page_flip_ioctl(struct drm_device *dev, 4872d91d8a3fSKristian Høgsberg void *data, struct drm_file *file_priv) 4873d91d8a3fSKristian Høgsberg { 4874d91d8a3fSKristian Høgsberg struct drm_mode_crtc_page_flip *page_flip = data; 4875d91d8a3fSKristian Høgsberg struct drm_crtc *crtc; 48763d30a59bSDaniel Vetter struct drm_framebuffer *fb = NULL; 4877d91d8a3fSKristian Høgsberg struct drm_pending_vblank_event *e = NULL; 4878d91d8a3fSKristian Høgsberg unsigned long flags; 4879d91d8a3fSKristian Høgsberg int ret = -EINVAL; 4880d91d8a3fSKristian Høgsberg 4881d91d8a3fSKristian Høgsberg if (page_flip->flags & ~DRM_MODE_PAGE_FLIP_FLAGS || 4882d91d8a3fSKristian Høgsberg page_flip->reserved != 0) 4883d91d8a3fSKristian Høgsberg return -EINVAL; 4884d91d8a3fSKristian Høgsberg 488562f2104fSKeith Packard if ((page_flip->flags & DRM_MODE_PAGE_FLIP_ASYNC) && !dev->mode_config.async_page_flip) 488662f2104fSKeith Packard return -EINVAL; 488762f2104fSKeith Packard 4888a2b34e22SRob Clark crtc = drm_crtc_find(dev, page_flip->crtc_id); 4889a2b34e22SRob Clark if (!crtc) 4890f27657f2SVille Syrjälä return -ENOENT; 4891d91d8a3fSKristian Høgsberg 48924d02e2deSDaniel Vetter drm_modeset_lock_crtc(crtc, crtc->primary); 4893f4510a27SMatt Roper if (crtc->primary->fb == NULL) { 489490c1efddSChris Wilson /* The framebuffer is currently unbound, presumably 489590c1efddSChris Wilson * due to a hotplug event, that userspace has not 489690c1efddSChris Wilson * yet discovered. 489790c1efddSChris Wilson */ 489890c1efddSChris Wilson ret = -EBUSY; 489990c1efddSChris Wilson goto out; 490090c1efddSChris Wilson } 490190c1efddSChris Wilson 4902d91d8a3fSKristian Høgsberg if (crtc->funcs->page_flip == NULL) 4903d91d8a3fSKristian Høgsberg goto out; 4904d91d8a3fSKristian Høgsberg 4905786b99edSDaniel Vetter fb = drm_framebuffer_lookup(dev, page_flip->fb_id); 490637c4e705SVille Syrjälä if (!fb) { 490737c4e705SVille Syrjälä ret = -ENOENT; 4908d91d8a3fSKristian Høgsberg goto out; 490937c4e705SVille Syrjälä } 4910d91d8a3fSKristian Høgsberg 4911c11e9283SDamien Lespiau ret = drm_crtc_check_viewport(crtc, crtc->x, crtc->y, &crtc->mode, fb); 4912c11e9283SDamien Lespiau if (ret) 49135f61bb42SVille Syrjälä goto out; 49145f61bb42SVille Syrjälä 4915f4510a27SMatt Roper if (crtc->primary->fb->pixel_format != fb->pixel_format) { 4916909d9cdaSLaurent Pinchart DRM_DEBUG_KMS("Page flip is not allowed to change frame buffer format.\n"); 4917909d9cdaSLaurent Pinchart ret = -EINVAL; 4918909d9cdaSLaurent Pinchart goto out; 4919909d9cdaSLaurent Pinchart } 4920909d9cdaSLaurent Pinchart 4921d91d8a3fSKristian Høgsberg if (page_flip->flags & DRM_MODE_PAGE_FLIP_EVENT) { 4922d91d8a3fSKristian Høgsberg ret = -ENOMEM; 4923d91d8a3fSKristian Høgsberg spin_lock_irqsave(&dev->event_lock, flags); 4924f76511b9SThierry Reding if (file_priv->event_space < sizeof(e->event)) { 4925d91d8a3fSKristian Høgsberg spin_unlock_irqrestore(&dev->event_lock, flags); 4926d91d8a3fSKristian Høgsberg goto out; 4927d91d8a3fSKristian Høgsberg } 4928f76511b9SThierry Reding file_priv->event_space -= sizeof(e->event); 4929d91d8a3fSKristian Høgsberg spin_unlock_irqrestore(&dev->event_lock, flags); 4930d91d8a3fSKristian Høgsberg 4931f76511b9SThierry Reding e = kzalloc(sizeof(*e), GFP_KERNEL); 4932d91d8a3fSKristian Høgsberg if (e == NULL) { 4933d91d8a3fSKristian Høgsberg spin_lock_irqsave(&dev->event_lock, flags); 4934f76511b9SThierry Reding file_priv->event_space += sizeof(e->event); 4935d91d8a3fSKristian Høgsberg spin_unlock_irqrestore(&dev->event_lock, flags); 4936d91d8a3fSKristian Høgsberg goto out; 4937d91d8a3fSKristian Høgsberg } 4938d91d8a3fSKristian Høgsberg 49397bd4d7beSJesse Barnes e->event.base.type = DRM_EVENT_FLIP_COMPLETE; 4940f76511b9SThierry Reding e->event.base.length = sizeof(e->event); 4941d91d8a3fSKristian Høgsberg e->event.user_data = page_flip->user_data; 4942d91d8a3fSKristian Høgsberg e->base.event = &e->event.base; 4943d91d8a3fSKristian Høgsberg e->base.file_priv = file_priv; 4944d91d8a3fSKristian Høgsberg e->base.destroy = 4945d91d8a3fSKristian Høgsberg (void (*) (struct drm_pending_event *)) kfree; 4946d91d8a3fSKristian Høgsberg } 4947d91d8a3fSKristian Høgsberg 49483d30a59bSDaniel Vetter crtc->primary->old_fb = crtc->primary->fb; 4949ed8d1975SKeith Packard ret = crtc->funcs->page_flip(crtc, fb, e, page_flip->flags); 4950d91d8a3fSKristian Høgsberg if (ret) { 4951aef6a7eeSJoonyoung Shim if (page_flip->flags & DRM_MODE_PAGE_FLIP_EVENT) { 4952d91d8a3fSKristian Høgsberg spin_lock_irqsave(&dev->event_lock, flags); 4953f76511b9SThierry Reding file_priv->event_space += sizeof(e->event); 4954d91d8a3fSKristian Høgsberg spin_unlock_irqrestore(&dev->event_lock, flags); 4955d91d8a3fSKristian Høgsberg kfree(e); 4956d91d8a3fSKristian Høgsberg } 4957b0d12325SDaniel Vetter /* Keep the old fb, don't unref it. */ 49583d30a59bSDaniel Vetter crtc->primary->old_fb = NULL; 4959b0d12325SDaniel Vetter } else { 49608cf1e981SThierry Reding /* 49618cf1e981SThierry Reding * Warn if the driver hasn't properly updated the crtc->fb 49628cf1e981SThierry Reding * field to reflect that the new framebuffer is now used. 49638cf1e981SThierry Reding * Failing to do so will screw with the reference counting 49648cf1e981SThierry Reding * on framebuffers. 49658cf1e981SThierry Reding */ 4966f4510a27SMatt Roper WARN_ON(crtc->primary->fb != fb); 4967b0d12325SDaniel Vetter /* Unref only the old framebuffer. */ 4968b0d12325SDaniel Vetter fb = NULL; 4969aef6a7eeSJoonyoung Shim } 4970d91d8a3fSKristian Høgsberg 4971d91d8a3fSKristian Høgsberg out: 4972b0d12325SDaniel Vetter if (fb) 4973b0d12325SDaniel Vetter drm_framebuffer_unreference(fb); 49743d30a59bSDaniel Vetter if (crtc->primary->old_fb) 49753d30a59bSDaniel Vetter drm_framebuffer_unreference(crtc->primary->old_fb); 49763d30a59bSDaniel Vetter crtc->primary->old_fb = NULL; 4977d059f652SDaniel Vetter drm_modeset_unlock_crtc(crtc); 4978b4d5e7d1SDaniel Vetter 4979d91d8a3fSKristian Høgsberg return ret; 4980d91d8a3fSKristian Høgsberg } 4981eb033556SChris Wilson 4982c8e32cc1SDaniel Vetter /** 4983c8e32cc1SDaniel Vetter * drm_mode_config_reset - call ->reset callbacks 4984c8e32cc1SDaniel Vetter * @dev: drm device 4985c8e32cc1SDaniel Vetter * 4986c8e32cc1SDaniel Vetter * This functions calls all the crtc's, encoder's and connector's ->reset 4987c8e32cc1SDaniel Vetter * callback. Drivers can use this in e.g. their driver load or resume code to 4988c8e32cc1SDaniel Vetter * reset hardware and software state. 4989c8e32cc1SDaniel Vetter */ 4990eb033556SChris Wilson void drm_mode_config_reset(struct drm_device *dev) 4991eb033556SChris Wilson { 4992eb033556SChris Wilson struct drm_crtc *crtc; 49932a0d7cfdSDaniel Vetter struct drm_plane *plane; 4994eb033556SChris Wilson struct drm_encoder *encoder; 4995eb033556SChris Wilson struct drm_connector *connector; 4996eb033556SChris Wilson 49972a0d7cfdSDaniel Vetter list_for_each_entry(plane, &dev->mode_config.plane_list, head) 49982a0d7cfdSDaniel Vetter if (plane->funcs->reset) 49992a0d7cfdSDaniel Vetter plane->funcs->reset(plane); 50002a0d7cfdSDaniel Vetter 5001eb033556SChris Wilson list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) 5002eb033556SChris Wilson if (crtc->funcs->reset) 5003eb033556SChris Wilson crtc->funcs->reset(crtc); 5004eb033556SChris Wilson 5005eb033556SChris Wilson list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) 5006eb033556SChris Wilson if (encoder->funcs->reset) 5007eb033556SChris Wilson encoder->funcs->reset(encoder); 5008eb033556SChris Wilson 50095e2cb2f6SDaniel Vetter list_for_each_entry(connector, &dev->mode_config.connector_list, head) { 50105e2cb2f6SDaniel Vetter connector->status = connector_status_unknown; 50115e2cb2f6SDaniel Vetter 5012eb033556SChris Wilson if (connector->funcs->reset) 5013eb033556SChris Wilson connector->funcs->reset(connector); 5014eb033556SChris Wilson } 50155e2cb2f6SDaniel Vetter } 5016eb033556SChris Wilson EXPORT_SYMBOL(drm_mode_config_reset); 5017ff72145bSDave Airlie 5018c8e32cc1SDaniel Vetter /** 5019c8e32cc1SDaniel Vetter * drm_mode_create_dumb_ioctl - create a dumb backing storage buffer 5020c8e32cc1SDaniel Vetter * @dev: DRM device 5021c8e32cc1SDaniel Vetter * @data: ioctl data 5022c8e32cc1SDaniel Vetter * @file_priv: DRM file info 5023c8e32cc1SDaniel Vetter * 5024c8e32cc1SDaniel Vetter * This creates a new dumb buffer in the driver's backing storage manager (GEM, 5025c8e32cc1SDaniel Vetter * TTM or something else entirely) and returns the resulting buffer handle. This 5026c8e32cc1SDaniel Vetter * handle can then be wrapped up into a framebuffer modeset object. 5027c8e32cc1SDaniel Vetter * 5028c8e32cc1SDaniel Vetter * Note that userspace is not allowed to use such objects for render 5029c8e32cc1SDaniel Vetter * acceleration - drivers must create their own private ioctls for such a use 5030c8e32cc1SDaniel Vetter * case. 5031c8e32cc1SDaniel Vetter * 5032c8e32cc1SDaniel Vetter * Called by the user via ioctl. 5033c8e32cc1SDaniel Vetter * 5034c8e32cc1SDaniel Vetter * Returns: 50351a498633SDaniel Vetter * Zero on success, negative errno on failure. 5036c8e32cc1SDaniel Vetter */ 5037ff72145bSDave Airlie int drm_mode_create_dumb_ioctl(struct drm_device *dev, 5038ff72145bSDave Airlie void *data, struct drm_file *file_priv) 5039ff72145bSDave Airlie { 5040ff72145bSDave Airlie struct drm_mode_create_dumb *args = data; 5041b28cd41fSDavid Herrmann u32 cpp, stride, size; 5042ff72145bSDave Airlie 5043ff72145bSDave Airlie if (!dev->driver->dumb_create) 5044ff72145bSDave Airlie return -ENOSYS; 5045b28cd41fSDavid Herrmann if (!args->width || !args->height || !args->bpp) 5046b28cd41fSDavid Herrmann return -EINVAL; 5047b28cd41fSDavid Herrmann 5048b28cd41fSDavid Herrmann /* overflow checks for 32bit size calculations */ 504900e72089SDavid Herrmann /* NOTE: DIV_ROUND_UP() can overflow */ 5050b28cd41fSDavid Herrmann cpp = DIV_ROUND_UP(args->bpp, 8); 505100e72089SDavid Herrmann if (!cpp || cpp > 0xffffffffU / args->width) 5052b28cd41fSDavid Herrmann return -EINVAL; 5053b28cd41fSDavid Herrmann stride = cpp * args->width; 5054b28cd41fSDavid Herrmann if (args->height > 0xffffffffU / stride) 5055b28cd41fSDavid Herrmann return -EINVAL; 5056b28cd41fSDavid Herrmann 5057b28cd41fSDavid Herrmann /* test for wrap-around */ 5058b28cd41fSDavid Herrmann size = args->height * stride; 5059b28cd41fSDavid Herrmann if (PAGE_ALIGN(size) == 0) 5060b28cd41fSDavid Herrmann return -EINVAL; 5061b28cd41fSDavid Herrmann 5062f6085952SThierry Reding /* 5063f6085952SThierry Reding * handle, pitch and size are output parameters. Zero them out to 5064f6085952SThierry Reding * prevent drivers from accidentally using uninitialized data. Since 5065f6085952SThierry Reding * not all existing userspace is clearing these fields properly we 5066f6085952SThierry Reding * cannot reject IOCTL with garbage in them. 5067f6085952SThierry Reding */ 5068f6085952SThierry Reding args->handle = 0; 5069f6085952SThierry Reding args->pitch = 0; 5070f6085952SThierry Reding args->size = 0; 5071f6085952SThierry Reding 5072ff72145bSDave Airlie return dev->driver->dumb_create(file_priv, dev, args); 5073ff72145bSDave Airlie } 5074ff72145bSDave Airlie 5075c8e32cc1SDaniel Vetter /** 5076c8e32cc1SDaniel Vetter * drm_mode_mmap_dumb_ioctl - create an mmap offset for a dumb backing storage buffer 5077c8e32cc1SDaniel Vetter * @dev: DRM device 5078c8e32cc1SDaniel Vetter * @data: ioctl data 5079c8e32cc1SDaniel Vetter * @file_priv: DRM file info 5080c8e32cc1SDaniel Vetter * 5081c8e32cc1SDaniel Vetter * Allocate an offset in the drm device node's address space to be able to 5082c8e32cc1SDaniel Vetter * memory map a dumb buffer. 5083c8e32cc1SDaniel Vetter * 5084c8e32cc1SDaniel Vetter * Called by the user via ioctl. 5085c8e32cc1SDaniel Vetter * 5086c8e32cc1SDaniel Vetter * Returns: 50871a498633SDaniel Vetter * Zero on success, negative errno on failure. 5088c8e32cc1SDaniel Vetter */ 5089ff72145bSDave Airlie int drm_mode_mmap_dumb_ioctl(struct drm_device *dev, 5090ff72145bSDave Airlie void *data, struct drm_file *file_priv) 5091ff72145bSDave Airlie { 5092ff72145bSDave Airlie struct drm_mode_map_dumb *args = data; 5093ff72145bSDave Airlie 5094ff72145bSDave Airlie /* call driver ioctl to get mmap offset */ 5095ff72145bSDave Airlie if (!dev->driver->dumb_map_offset) 5096ff72145bSDave Airlie return -ENOSYS; 5097ff72145bSDave Airlie 5098ff72145bSDave Airlie return dev->driver->dumb_map_offset(file_priv, dev, args->handle, &args->offset); 5099ff72145bSDave Airlie } 5100ff72145bSDave Airlie 5101c8e32cc1SDaniel Vetter /** 5102c8e32cc1SDaniel Vetter * drm_mode_destroy_dumb_ioctl - destroy a dumb backing strage buffer 5103c8e32cc1SDaniel Vetter * @dev: DRM device 5104c8e32cc1SDaniel Vetter * @data: ioctl data 5105c8e32cc1SDaniel Vetter * @file_priv: DRM file info 5106c8e32cc1SDaniel Vetter * 5107c8e32cc1SDaniel Vetter * This destroys the userspace handle for the given dumb backing storage buffer. 5108c8e32cc1SDaniel Vetter * Since buffer objects must be reference counted in the kernel a buffer object 5109c8e32cc1SDaniel Vetter * won't be immediately freed if a framebuffer modeset object still uses it. 5110c8e32cc1SDaniel Vetter * 5111c8e32cc1SDaniel Vetter * Called by the user via ioctl. 5112c8e32cc1SDaniel Vetter * 5113c8e32cc1SDaniel Vetter * Returns: 51141a498633SDaniel Vetter * Zero on success, negative errno on failure. 5115c8e32cc1SDaniel Vetter */ 5116ff72145bSDave Airlie int drm_mode_destroy_dumb_ioctl(struct drm_device *dev, 5117ff72145bSDave Airlie void *data, struct drm_file *file_priv) 5118ff72145bSDave Airlie { 5119ff72145bSDave Airlie struct drm_mode_destroy_dumb *args = data; 5120ff72145bSDave Airlie 5121ff72145bSDave Airlie if (!dev->driver->dumb_destroy) 5122ff72145bSDave Airlie return -ENOSYS; 5123ff72145bSDave Airlie 5124ff72145bSDave Airlie return dev->driver->dumb_destroy(file_priv, dev, args->handle); 5125ff72145bSDave Airlie } 5126248dbc23SDave Airlie 5127c8e32cc1SDaniel Vetter /** 5128c8e32cc1SDaniel Vetter * drm_fb_get_bpp_depth - get the bpp/depth values for format 5129c8e32cc1SDaniel Vetter * @format: pixel format (DRM_FORMAT_*) 5130c8e32cc1SDaniel Vetter * @depth: storage for the depth value 5131c8e32cc1SDaniel Vetter * @bpp: storage for the bpp value 5132c8e32cc1SDaniel Vetter * 5133c8e32cc1SDaniel Vetter * This only supports RGB formats here for compat with code that doesn't use 5134c8e32cc1SDaniel Vetter * pixel formats directly yet. 5135248dbc23SDave Airlie */ 5136248dbc23SDave Airlie void drm_fb_get_bpp_depth(uint32_t format, unsigned int *depth, 5137248dbc23SDave Airlie int *bpp) 5138248dbc23SDave Airlie { 5139248dbc23SDave Airlie switch (format) { 5140c51a6bc5SVille Syrjälä case DRM_FORMAT_C8: 514104b3924dSVille Syrjälä case DRM_FORMAT_RGB332: 514204b3924dSVille Syrjälä case DRM_FORMAT_BGR233: 5143248dbc23SDave Airlie *depth = 8; 5144248dbc23SDave Airlie *bpp = 8; 5145248dbc23SDave Airlie break; 514604b3924dSVille Syrjälä case DRM_FORMAT_XRGB1555: 514704b3924dSVille Syrjälä case DRM_FORMAT_XBGR1555: 514804b3924dSVille Syrjälä case DRM_FORMAT_RGBX5551: 514904b3924dSVille Syrjälä case DRM_FORMAT_BGRX5551: 515004b3924dSVille Syrjälä case DRM_FORMAT_ARGB1555: 515104b3924dSVille Syrjälä case DRM_FORMAT_ABGR1555: 515204b3924dSVille Syrjälä case DRM_FORMAT_RGBA5551: 515304b3924dSVille Syrjälä case DRM_FORMAT_BGRA5551: 5154248dbc23SDave Airlie *depth = 15; 5155248dbc23SDave Airlie *bpp = 16; 5156248dbc23SDave Airlie break; 515704b3924dSVille Syrjälä case DRM_FORMAT_RGB565: 515804b3924dSVille Syrjälä case DRM_FORMAT_BGR565: 5159248dbc23SDave Airlie *depth = 16; 5160248dbc23SDave Airlie *bpp = 16; 5161248dbc23SDave Airlie break; 516204b3924dSVille Syrjälä case DRM_FORMAT_RGB888: 516304b3924dSVille Syrjälä case DRM_FORMAT_BGR888: 516404b3924dSVille Syrjälä *depth = 24; 516504b3924dSVille Syrjälä *bpp = 24; 516604b3924dSVille Syrjälä break; 516704b3924dSVille Syrjälä case DRM_FORMAT_XRGB8888: 516804b3924dSVille Syrjälä case DRM_FORMAT_XBGR8888: 516904b3924dSVille Syrjälä case DRM_FORMAT_RGBX8888: 517004b3924dSVille Syrjälä case DRM_FORMAT_BGRX8888: 5171248dbc23SDave Airlie *depth = 24; 5172248dbc23SDave Airlie *bpp = 32; 5173248dbc23SDave Airlie break; 517404b3924dSVille Syrjälä case DRM_FORMAT_XRGB2101010: 517504b3924dSVille Syrjälä case DRM_FORMAT_XBGR2101010: 517604b3924dSVille Syrjälä case DRM_FORMAT_RGBX1010102: 517704b3924dSVille Syrjälä case DRM_FORMAT_BGRX1010102: 517804b3924dSVille Syrjälä case DRM_FORMAT_ARGB2101010: 517904b3924dSVille Syrjälä case DRM_FORMAT_ABGR2101010: 518004b3924dSVille Syrjälä case DRM_FORMAT_RGBA1010102: 518104b3924dSVille Syrjälä case DRM_FORMAT_BGRA1010102: 5182248dbc23SDave Airlie *depth = 30; 5183248dbc23SDave Airlie *bpp = 32; 5184248dbc23SDave Airlie break; 518504b3924dSVille Syrjälä case DRM_FORMAT_ARGB8888: 518604b3924dSVille Syrjälä case DRM_FORMAT_ABGR8888: 518704b3924dSVille Syrjälä case DRM_FORMAT_RGBA8888: 518804b3924dSVille Syrjälä case DRM_FORMAT_BGRA8888: 5189248dbc23SDave Airlie *depth = 32; 5190248dbc23SDave Airlie *bpp = 32; 5191248dbc23SDave Airlie break; 5192248dbc23SDave Airlie default: 519323c453a4SVille Syrjälä DRM_DEBUG_KMS("unsupported pixel format %s\n", 519423c453a4SVille Syrjälä drm_get_format_name(format)); 5195248dbc23SDave Airlie *depth = 0; 5196248dbc23SDave Airlie *bpp = 0; 5197248dbc23SDave Airlie break; 5198248dbc23SDave Airlie } 5199248dbc23SDave Airlie } 5200248dbc23SDave Airlie EXPORT_SYMBOL(drm_fb_get_bpp_depth); 5201141670e9SVille Syrjälä 5202141670e9SVille Syrjälä /** 5203141670e9SVille Syrjälä * drm_format_num_planes - get the number of planes for format 5204141670e9SVille Syrjälä * @format: pixel format (DRM_FORMAT_*) 5205141670e9SVille Syrjälä * 5206c8e32cc1SDaniel Vetter * Returns: 5207141670e9SVille Syrjälä * The number of planes used by the specified pixel format. 5208141670e9SVille Syrjälä */ 5209141670e9SVille Syrjälä int drm_format_num_planes(uint32_t format) 5210141670e9SVille Syrjälä { 5211141670e9SVille Syrjälä switch (format) { 5212141670e9SVille Syrjälä case DRM_FORMAT_YUV410: 5213141670e9SVille Syrjälä case DRM_FORMAT_YVU410: 5214141670e9SVille Syrjälä case DRM_FORMAT_YUV411: 5215141670e9SVille Syrjälä case DRM_FORMAT_YVU411: 5216141670e9SVille Syrjälä case DRM_FORMAT_YUV420: 5217141670e9SVille Syrjälä case DRM_FORMAT_YVU420: 5218141670e9SVille Syrjälä case DRM_FORMAT_YUV422: 5219141670e9SVille Syrjälä case DRM_FORMAT_YVU422: 5220141670e9SVille Syrjälä case DRM_FORMAT_YUV444: 5221141670e9SVille Syrjälä case DRM_FORMAT_YVU444: 5222141670e9SVille Syrjälä return 3; 5223141670e9SVille Syrjälä case DRM_FORMAT_NV12: 5224141670e9SVille Syrjälä case DRM_FORMAT_NV21: 5225141670e9SVille Syrjälä case DRM_FORMAT_NV16: 5226141670e9SVille Syrjälä case DRM_FORMAT_NV61: 5227ba623f6aSLaurent Pinchart case DRM_FORMAT_NV24: 5228ba623f6aSLaurent Pinchart case DRM_FORMAT_NV42: 5229141670e9SVille Syrjälä return 2; 5230141670e9SVille Syrjälä default: 5231141670e9SVille Syrjälä return 1; 5232141670e9SVille Syrjälä } 5233141670e9SVille Syrjälä } 5234141670e9SVille Syrjälä EXPORT_SYMBOL(drm_format_num_planes); 52355a86bd55SVille Syrjälä 52365a86bd55SVille Syrjälä /** 52375a86bd55SVille Syrjälä * drm_format_plane_cpp - determine the bytes per pixel value 52385a86bd55SVille Syrjälä * @format: pixel format (DRM_FORMAT_*) 52395a86bd55SVille Syrjälä * @plane: plane index 52405a86bd55SVille Syrjälä * 5241c8e32cc1SDaniel Vetter * Returns: 52425a86bd55SVille Syrjälä * The bytes per pixel value for the specified plane. 52435a86bd55SVille Syrjälä */ 52445a86bd55SVille Syrjälä int drm_format_plane_cpp(uint32_t format, int plane) 52455a86bd55SVille Syrjälä { 52465a86bd55SVille Syrjälä unsigned int depth; 52475a86bd55SVille Syrjälä int bpp; 52485a86bd55SVille Syrjälä 52495a86bd55SVille Syrjälä if (plane >= drm_format_num_planes(format)) 52505a86bd55SVille Syrjälä return 0; 52515a86bd55SVille Syrjälä 52525a86bd55SVille Syrjälä switch (format) { 52535a86bd55SVille Syrjälä case DRM_FORMAT_YUYV: 52545a86bd55SVille Syrjälä case DRM_FORMAT_YVYU: 52555a86bd55SVille Syrjälä case DRM_FORMAT_UYVY: 52565a86bd55SVille Syrjälä case DRM_FORMAT_VYUY: 52575a86bd55SVille Syrjälä return 2; 52585a86bd55SVille Syrjälä case DRM_FORMAT_NV12: 52595a86bd55SVille Syrjälä case DRM_FORMAT_NV21: 52605a86bd55SVille Syrjälä case DRM_FORMAT_NV16: 52615a86bd55SVille Syrjälä case DRM_FORMAT_NV61: 5262ba623f6aSLaurent Pinchart case DRM_FORMAT_NV24: 5263ba623f6aSLaurent Pinchart case DRM_FORMAT_NV42: 52645a86bd55SVille Syrjälä return plane ? 2 : 1; 52655a86bd55SVille Syrjälä case DRM_FORMAT_YUV410: 52665a86bd55SVille Syrjälä case DRM_FORMAT_YVU410: 52675a86bd55SVille Syrjälä case DRM_FORMAT_YUV411: 52685a86bd55SVille Syrjälä case DRM_FORMAT_YVU411: 52695a86bd55SVille Syrjälä case DRM_FORMAT_YUV420: 52705a86bd55SVille Syrjälä case DRM_FORMAT_YVU420: 52715a86bd55SVille Syrjälä case DRM_FORMAT_YUV422: 52725a86bd55SVille Syrjälä case DRM_FORMAT_YVU422: 52735a86bd55SVille Syrjälä case DRM_FORMAT_YUV444: 52745a86bd55SVille Syrjälä case DRM_FORMAT_YVU444: 52755a86bd55SVille Syrjälä return 1; 52765a86bd55SVille Syrjälä default: 52775a86bd55SVille Syrjälä drm_fb_get_bpp_depth(format, &depth, &bpp); 52785a86bd55SVille Syrjälä return bpp >> 3; 52795a86bd55SVille Syrjälä } 52805a86bd55SVille Syrjälä } 52815a86bd55SVille Syrjälä EXPORT_SYMBOL(drm_format_plane_cpp); 528201b68b04SVille Syrjälä 528301b68b04SVille Syrjälä /** 528401b68b04SVille Syrjälä * drm_format_horz_chroma_subsampling - get the horizontal chroma subsampling factor 528501b68b04SVille Syrjälä * @format: pixel format (DRM_FORMAT_*) 528601b68b04SVille Syrjälä * 5287c8e32cc1SDaniel Vetter * Returns: 528801b68b04SVille Syrjälä * The horizontal chroma subsampling factor for the 528901b68b04SVille Syrjälä * specified pixel format. 529001b68b04SVille Syrjälä */ 529101b68b04SVille Syrjälä int drm_format_horz_chroma_subsampling(uint32_t format) 529201b68b04SVille Syrjälä { 529301b68b04SVille Syrjälä switch (format) { 529401b68b04SVille Syrjälä case DRM_FORMAT_YUV411: 529501b68b04SVille Syrjälä case DRM_FORMAT_YVU411: 529601b68b04SVille Syrjälä case DRM_FORMAT_YUV410: 529701b68b04SVille Syrjälä case DRM_FORMAT_YVU410: 529801b68b04SVille Syrjälä return 4; 529901b68b04SVille Syrjälä case DRM_FORMAT_YUYV: 530001b68b04SVille Syrjälä case DRM_FORMAT_YVYU: 530101b68b04SVille Syrjälä case DRM_FORMAT_UYVY: 530201b68b04SVille Syrjälä case DRM_FORMAT_VYUY: 530301b68b04SVille Syrjälä case DRM_FORMAT_NV12: 530401b68b04SVille Syrjälä case DRM_FORMAT_NV21: 530501b68b04SVille Syrjälä case DRM_FORMAT_NV16: 530601b68b04SVille Syrjälä case DRM_FORMAT_NV61: 530701b68b04SVille Syrjälä case DRM_FORMAT_YUV422: 530801b68b04SVille Syrjälä case DRM_FORMAT_YVU422: 530901b68b04SVille Syrjälä case DRM_FORMAT_YUV420: 531001b68b04SVille Syrjälä case DRM_FORMAT_YVU420: 531101b68b04SVille Syrjälä return 2; 531201b68b04SVille Syrjälä default: 531301b68b04SVille Syrjälä return 1; 531401b68b04SVille Syrjälä } 531501b68b04SVille Syrjälä } 531601b68b04SVille Syrjälä EXPORT_SYMBOL(drm_format_horz_chroma_subsampling); 531701b68b04SVille Syrjälä 531801b68b04SVille Syrjälä /** 531901b68b04SVille Syrjälä * drm_format_vert_chroma_subsampling - get the vertical chroma subsampling factor 532001b68b04SVille Syrjälä * @format: pixel format (DRM_FORMAT_*) 532101b68b04SVille Syrjälä * 5322c8e32cc1SDaniel Vetter * Returns: 532301b68b04SVille Syrjälä * The vertical chroma subsampling factor for the 532401b68b04SVille Syrjälä * specified pixel format. 532501b68b04SVille Syrjälä */ 532601b68b04SVille Syrjälä int drm_format_vert_chroma_subsampling(uint32_t format) 532701b68b04SVille Syrjälä { 532801b68b04SVille Syrjälä switch (format) { 532901b68b04SVille Syrjälä case DRM_FORMAT_YUV410: 533001b68b04SVille Syrjälä case DRM_FORMAT_YVU410: 533101b68b04SVille Syrjälä return 4; 533201b68b04SVille Syrjälä case DRM_FORMAT_YUV420: 533301b68b04SVille Syrjälä case DRM_FORMAT_YVU420: 533401b68b04SVille Syrjälä case DRM_FORMAT_NV12: 533501b68b04SVille Syrjälä case DRM_FORMAT_NV21: 533601b68b04SVille Syrjälä return 2; 533701b68b04SVille Syrjälä default: 533801b68b04SVille Syrjälä return 1; 533901b68b04SVille Syrjälä } 534001b68b04SVille Syrjälä } 534101b68b04SVille Syrjälä EXPORT_SYMBOL(drm_format_vert_chroma_subsampling); 534287d24fc3SLaurent Pinchart 534387d24fc3SLaurent Pinchart /** 53443c9855f6SVille Syrjälä * drm_rotation_simplify() - Try to simplify the rotation 53453c9855f6SVille Syrjälä * @rotation: Rotation to be simplified 53463c9855f6SVille Syrjälä * @supported_rotations: Supported rotations 53473c9855f6SVille Syrjälä * 53483c9855f6SVille Syrjälä * Attempt to simplify the rotation to a form that is supported. 53493c9855f6SVille Syrjälä * Eg. if the hardware supports everything except DRM_REFLECT_X 53503c9855f6SVille Syrjälä * one could call this function like this: 53513c9855f6SVille Syrjälä * 53523c9855f6SVille Syrjälä * drm_rotation_simplify(rotation, BIT(DRM_ROTATE_0) | 53533c9855f6SVille Syrjälä * BIT(DRM_ROTATE_90) | BIT(DRM_ROTATE_180) | 53543c9855f6SVille Syrjälä * BIT(DRM_ROTATE_270) | BIT(DRM_REFLECT_Y)); 53553c9855f6SVille Syrjälä * 53563c9855f6SVille Syrjälä * to eliminate the DRM_ROTATE_X flag. Depending on what kind of 53573c9855f6SVille Syrjälä * transforms the hardware supports, this function may not 53583c9855f6SVille Syrjälä * be able to produce a supported transform, so the caller should 53593c9855f6SVille Syrjälä * check the result afterwards. 53603c9855f6SVille Syrjälä */ 53613c9855f6SVille Syrjälä unsigned int drm_rotation_simplify(unsigned int rotation, 53623c9855f6SVille Syrjälä unsigned int supported_rotations) 53633c9855f6SVille Syrjälä { 53643c9855f6SVille Syrjälä if (rotation & ~supported_rotations) { 53653c9855f6SVille Syrjälä rotation ^= BIT(DRM_REFLECT_X) | BIT(DRM_REFLECT_Y); 53663c9855f6SVille Syrjälä rotation = (rotation & ~0xf) | BIT((ffs(rotation & 0xf) + 1) % 4); 53673c9855f6SVille Syrjälä } 53683c9855f6SVille Syrjälä 53693c9855f6SVille Syrjälä return rotation; 53703c9855f6SVille Syrjälä } 53713c9855f6SVille Syrjälä EXPORT_SYMBOL(drm_rotation_simplify); 53723c9855f6SVille Syrjälä 53733c9855f6SVille Syrjälä /** 537487d24fc3SLaurent Pinchart * drm_mode_config_init - initialize DRM mode_configuration structure 537587d24fc3SLaurent Pinchart * @dev: DRM device 537687d24fc3SLaurent Pinchart * 537787d24fc3SLaurent Pinchart * Initialize @dev's mode_config structure, used for tracking the graphics 537887d24fc3SLaurent Pinchart * configuration of @dev. 537987d24fc3SLaurent Pinchart * 538087d24fc3SLaurent Pinchart * Since this initializes the modeset locks, no locking is possible. Which is no 538187d24fc3SLaurent Pinchart * problem, since this should happen single threaded at init time. It is the 538287d24fc3SLaurent Pinchart * driver's problem to ensure this guarantee. 538387d24fc3SLaurent Pinchart * 538487d24fc3SLaurent Pinchart */ 538587d24fc3SLaurent Pinchart void drm_mode_config_init(struct drm_device *dev) 538687d24fc3SLaurent Pinchart { 538787d24fc3SLaurent Pinchart mutex_init(&dev->mode_config.mutex); 538851fd371bSRob Clark drm_modeset_lock_init(&dev->mode_config.connection_mutex); 538987d24fc3SLaurent Pinchart mutex_init(&dev->mode_config.idr_mutex); 539087d24fc3SLaurent Pinchart mutex_init(&dev->mode_config.fb_lock); 539187d24fc3SLaurent Pinchart INIT_LIST_HEAD(&dev->mode_config.fb_list); 539287d24fc3SLaurent Pinchart INIT_LIST_HEAD(&dev->mode_config.crtc_list); 539387d24fc3SLaurent Pinchart INIT_LIST_HEAD(&dev->mode_config.connector_list); 539487d24fc3SLaurent Pinchart INIT_LIST_HEAD(&dev->mode_config.encoder_list); 539587d24fc3SLaurent Pinchart INIT_LIST_HEAD(&dev->mode_config.property_list); 539687d24fc3SLaurent Pinchart INIT_LIST_HEAD(&dev->mode_config.property_blob_list); 539787d24fc3SLaurent Pinchart INIT_LIST_HEAD(&dev->mode_config.plane_list); 539887d24fc3SLaurent Pinchart idr_init(&dev->mode_config.crtc_idr); 5399138f9ebbSDave Airlie idr_init(&dev->mode_config.tile_idr); 540087d24fc3SLaurent Pinchart 540187d24fc3SLaurent Pinchart drm_modeset_lock_all(dev); 54026b4959f4SRob Clark drm_mode_create_standard_properties(dev); 540387d24fc3SLaurent Pinchart drm_modeset_unlock_all(dev); 540487d24fc3SLaurent Pinchart 540587d24fc3SLaurent Pinchart /* Just to be sure */ 540687d24fc3SLaurent Pinchart dev->mode_config.num_fb = 0; 540787d24fc3SLaurent Pinchart dev->mode_config.num_connector = 0; 540887d24fc3SLaurent Pinchart dev->mode_config.num_crtc = 0; 540987d24fc3SLaurent Pinchart dev->mode_config.num_encoder = 0; 5410e27dde3eSMatt Roper dev->mode_config.num_overlay_plane = 0; 5411e27dde3eSMatt Roper dev->mode_config.num_total_plane = 0; 541287d24fc3SLaurent Pinchart } 541387d24fc3SLaurent Pinchart EXPORT_SYMBOL(drm_mode_config_init); 541487d24fc3SLaurent Pinchart 541587d24fc3SLaurent Pinchart /** 541687d24fc3SLaurent Pinchart * drm_mode_config_cleanup - free up DRM mode_config info 541787d24fc3SLaurent Pinchart * @dev: DRM device 541887d24fc3SLaurent Pinchart * 541987d24fc3SLaurent Pinchart * Free up all the connectors and CRTCs associated with this DRM device, then 542087d24fc3SLaurent Pinchart * free up the framebuffers and associated buffer objects. 542187d24fc3SLaurent Pinchart * 542287d24fc3SLaurent Pinchart * Note that since this /should/ happen single-threaded at driver/device 542387d24fc3SLaurent Pinchart * teardown time, no locking is required. It's the driver's job to ensure that 542487d24fc3SLaurent Pinchart * this guarantee actually holds true. 542587d24fc3SLaurent Pinchart * 542687d24fc3SLaurent Pinchart * FIXME: cleanup any dangling user buffer objects too 542787d24fc3SLaurent Pinchart */ 542887d24fc3SLaurent Pinchart void drm_mode_config_cleanup(struct drm_device *dev) 542987d24fc3SLaurent Pinchart { 543087d24fc3SLaurent Pinchart struct drm_connector *connector, *ot; 543187d24fc3SLaurent Pinchart struct drm_crtc *crtc, *ct; 543287d24fc3SLaurent Pinchart struct drm_encoder *encoder, *enct; 543387d24fc3SLaurent Pinchart struct drm_framebuffer *fb, *fbt; 543487d24fc3SLaurent Pinchart struct drm_property *property, *pt; 543587d24fc3SLaurent Pinchart struct drm_property_blob *blob, *bt; 543687d24fc3SLaurent Pinchart struct drm_plane *plane, *plt; 543787d24fc3SLaurent Pinchart 543887d24fc3SLaurent Pinchart list_for_each_entry_safe(encoder, enct, &dev->mode_config.encoder_list, 543987d24fc3SLaurent Pinchart head) { 544087d24fc3SLaurent Pinchart encoder->funcs->destroy(encoder); 544187d24fc3SLaurent Pinchart } 544287d24fc3SLaurent Pinchart 544387d24fc3SLaurent Pinchart list_for_each_entry_safe(connector, ot, 544487d24fc3SLaurent Pinchart &dev->mode_config.connector_list, head) { 544587d24fc3SLaurent Pinchart connector->funcs->destroy(connector); 544687d24fc3SLaurent Pinchart } 544787d24fc3SLaurent Pinchart 544887d24fc3SLaurent Pinchart list_for_each_entry_safe(property, pt, &dev->mode_config.property_list, 544987d24fc3SLaurent Pinchart head) { 545087d24fc3SLaurent Pinchart drm_property_destroy(dev, property); 545187d24fc3SLaurent Pinchart } 545287d24fc3SLaurent Pinchart 545387d24fc3SLaurent Pinchart list_for_each_entry_safe(blob, bt, &dev->mode_config.property_blob_list, 545487d24fc3SLaurent Pinchart head) { 545587d24fc3SLaurent Pinchart drm_property_destroy_blob(dev, blob); 545687d24fc3SLaurent Pinchart } 545787d24fc3SLaurent Pinchart 545887d24fc3SLaurent Pinchart /* 545987d24fc3SLaurent Pinchart * Single-threaded teardown context, so it's not required to grab the 546087d24fc3SLaurent Pinchart * fb_lock to protect against concurrent fb_list access. Contrary, it 546187d24fc3SLaurent Pinchart * would actually deadlock with the drm_framebuffer_cleanup function. 546287d24fc3SLaurent Pinchart * 546387d24fc3SLaurent Pinchart * Also, if there are any framebuffers left, that's a driver leak now, 546487d24fc3SLaurent Pinchart * so politely WARN about this. 546587d24fc3SLaurent Pinchart */ 546687d24fc3SLaurent Pinchart WARN_ON(!list_empty(&dev->mode_config.fb_list)); 546787d24fc3SLaurent Pinchart list_for_each_entry_safe(fb, fbt, &dev->mode_config.fb_list, head) { 546887d24fc3SLaurent Pinchart drm_framebuffer_remove(fb); 546987d24fc3SLaurent Pinchart } 547087d24fc3SLaurent Pinchart 547187d24fc3SLaurent Pinchart list_for_each_entry_safe(plane, plt, &dev->mode_config.plane_list, 547287d24fc3SLaurent Pinchart head) { 547387d24fc3SLaurent Pinchart plane->funcs->destroy(plane); 547487d24fc3SLaurent Pinchart } 547587d24fc3SLaurent Pinchart 547687d24fc3SLaurent Pinchart list_for_each_entry_safe(crtc, ct, &dev->mode_config.crtc_list, head) { 547787d24fc3SLaurent Pinchart crtc->funcs->destroy(crtc); 547887d24fc3SLaurent Pinchart } 547987d24fc3SLaurent Pinchart 5480138f9ebbSDave Airlie idr_destroy(&dev->mode_config.tile_idr); 548187d24fc3SLaurent Pinchart idr_destroy(&dev->mode_config.crtc_idr); 548251fd371bSRob Clark drm_modeset_lock_fini(&dev->mode_config.connection_mutex); 548387d24fc3SLaurent Pinchart } 548487d24fc3SLaurent Pinchart EXPORT_SYMBOL(drm_mode_config_cleanup); 5485c1df5f3cSVille Syrjälä 5486c1df5f3cSVille Syrjälä struct drm_property *drm_mode_create_rotation_property(struct drm_device *dev, 5487c1df5f3cSVille Syrjälä unsigned int supported_rotations) 5488c1df5f3cSVille Syrjälä { 5489c1df5f3cSVille Syrjälä static const struct drm_prop_enum_list props[] = { 5490c1df5f3cSVille Syrjälä { DRM_ROTATE_0, "rotate-0" }, 5491c1df5f3cSVille Syrjälä { DRM_ROTATE_90, "rotate-90" }, 5492c1df5f3cSVille Syrjälä { DRM_ROTATE_180, "rotate-180" }, 5493c1df5f3cSVille Syrjälä { DRM_ROTATE_270, "rotate-270" }, 5494c1df5f3cSVille Syrjälä { DRM_REFLECT_X, "reflect-x" }, 5495c1df5f3cSVille Syrjälä { DRM_REFLECT_Y, "reflect-y" }, 5496c1df5f3cSVille Syrjälä }; 5497c1df5f3cSVille Syrjälä 5498c1df5f3cSVille Syrjälä return drm_property_create_bitmask(dev, 0, "rotation", 5499c1df5f3cSVille Syrjälä props, ARRAY_SIZE(props), 5500c1df5f3cSVille Syrjälä supported_rotations); 5501c1df5f3cSVille Syrjälä } 5502c1df5f3cSVille Syrjälä EXPORT_SYMBOL(drm_mode_create_rotation_property); 5503138f9ebbSDave Airlie 5504138f9ebbSDave Airlie /** 5505138f9ebbSDave Airlie * DOC: Tile group 5506138f9ebbSDave Airlie * 5507138f9ebbSDave Airlie * Tile groups are used to represent tiled monitors with a unique 5508138f9ebbSDave Airlie * integer identifier. Tiled monitors using DisplayID v1.3 have 5509138f9ebbSDave Airlie * a unique 8-byte handle, we store this in a tile group, so we 5510138f9ebbSDave Airlie * have a common identifier for all tiles in a monitor group. 5511138f9ebbSDave Airlie */ 5512138f9ebbSDave Airlie static void drm_tile_group_free(struct kref *kref) 5513138f9ebbSDave Airlie { 5514138f9ebbSDave Airlie struct drm_tile_group *tg = container_of(kref, struct drm_tile_group, refcount); 5515138f9ebbSDave Airlie struct drm_device *dev = tg->dev; 5516138f9ebbSDave Airlie mutex_lock(&dev->mode_config.idr_mutex); 5517138f9ebbSDave Airlie idr_remove(&dev->mode_config.tile_idr, tg->id); 5518138f9ebbSDave Airlie mutex_unlock(&dev->mode_config.idr_mutex); 5519138f9ebbSDave Airlie kfree(tg); 5520138f9ebbSDave Airlie } 5521138f9ebbSDave Airlie 5522138f9ebbSDave Airlie /** 5523138f9ebbSDave Airlie * drm_mode_put_tile_group - drop a reference to a tile group. 5524138f9ebbSDave Airlie * @dev: DRM device 5525138f9ebbSDave Airlie * @tg: tile group to drop reference to. 5526138f9ebbSDave Airlie * 5527138f9ebbSDave Airlie * drop reference to tile group and free if 0. 5528138f9ebbSDave Airlie */ 5529138f9ebbSDave Airlie void drm_mode_put_tile_group(struct drm_device *dev, 5530138f9ebbSDave Airlie struct drm_tile_group *tg) 5531138f9ebbSDave Airlie { 5532138f9ebbSDave Airlie kref_put(&tg->refcount, drm_tile_group_free); 5533138f9ebbSDave Airlie } 5534138f9ebbSDave Airlie 5535138f9ebbSDave Airlie /** 5536138f9ebbSDave Airlie * drm_mode_get_tile_group - get a reference to an existing tile group 5537138f9ebbSDave Airlie * @dev: DRM device 5538138f9ebbSDave Airlie * @topology: 8-bytes unique per monitor. 5539138f9ebbSDave Airlie * 5540138f9ebbSDave Airlie * Use the unique bytes to get a reference to an existing tile group. 5541138f9ebbSDave Airlie * 5542138f9ebbSDave Airlie * RETURNS: 5543138f9ebbSDave Airlie * tile group or NULL if not found. 5544138f9ebbSDave Airlie */ 5545138f9ebbSDave Airlie struct drm_tile_group *drm_mode_get_tile_group(struct drm_device *dev, 5546138f9ebbSDave Airlie char topology[8]) 5547138f9ebbSDave Airlie { 5548138f9ebbSDave Airlie struct drm_tile_group *tg; 5549138f9ebbSDave Airlie int id; 5550138f9ebbSDave Airlie mutex_lock(&dev->mode_config.idr_mutex); 5551138f9ebbSDave Airlie idr_for_each_entry(&dev->mode_config.tile_idr, tg, id) { 5552138f9ebbSDave Airlie if (!memcmp(tg->group_data, topology, 8)) { 5553138f9ebbSDave Airlie if (!kref_get_unless_zero(&tg->refcount)) 5554138f9ebbSDave Airlie tg = NULL; 5555138f9ebbSDave Airlie mutex_unlock(&dev->mode_config.idr_mutex); 5556138f9ebbSDave Airlie return tg; 5557138f9ebbSDave Airlie } 5558138f9ebbSDave Airlie } 5559138f9ebbSDave Airlie mutex_unlock(&dev->mode_config.idr_mutex); 5560138f9ebbSDave Airlie return NULL; 5561138f9ebbSDave Airlie } 5562138f9ebbSDave Airlie 5563138f9ebbSDave Airlie /** 5564138f9ebbSDave Airlie * drm_mode_create_tile_group - create a tile group from a displayid description 5565138f9ebbSDave Airlie * @dev: DRM device 5566138f9ebbSDave Airlie * @topology: 8-bytes unique per monitor. 5567138f9ebbSDave Airlie * 5568138f9ebbSDave Airlie * Create a tile group for the unique monitor, and get a unique 5569138f9ebbSDave Airlie * identifier for the tile group. 5570138f9ebbSDave Airlie * 5571138f9ebbSDave Airlie * RETURNS: 5572138f9ebbSDave Airlie * new tile group or error. 5573138f9ebbSDave Airlie */ 5574138f9ebbSDave Airlie struct drm_tile_group *drm_mode_create_tile_group(struct drm_device *dev, 5575138f9ebbSDave Airlie char topology[8]) 5576138f9ebbSDave Airlie { 5577138f9ebbSDave Airlie struct drm_tile_group *tg; 5578138f9ebbSDave Airlie int ret; 5579138f9ebbSDave Airlie 5580138f9ebbSDave Airlie tg = kzalloc(sizeof(*tg), GFP_KERNEL); 5581138f9ebbSDave Airlie if (!tg) 5582138f9ebbSDave Airlie return ERR_PTR(-ENOMEM); 5583138f9ebbSDave Airlie 5584138f9ebbSDave Airlie kref_init(&tg->refcount); 5585138f9ebbSDave Airlie memcpy(tg->group_data, topology, 8); 5586138f9ebbSDave Airlie tg->dev = dev; 5587138f9ebbSDave Airlie 5588138f9ebbSDave Airlie mutex_lock(&dev->mode_config.idr_mutex); 5589138f9ebbSDave Airlie ret = idr_alloc(&dev->mode_config.tile_idr, tg, 1, 0, GFP_KERNEL); 5590138f9ebbSDave Airlie if (ret >= 0) { 5591138f9ebbSDave Airlie tg->id = ret; 5592138f9ebbSDave Airlie } else { 5593138f9ebbSDave Airlie kfree(tg); 5594138f9ebbSDave Airlie tg = ERR_PTR(ret); 5595138f9ebbSDave Airlie } 5596138f9ebbSDave Airlie 5597138f9ebbSDave Airlie mutex_unlock(&dev->mode_config.idr_mutex); 5598138f9ebbSDave Airlie return tg; 5599138f9ebbSDave Airlie } 5600