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> 41f453ba04SDave Airlie 428bd441b2SDaniel Vetter #include "drm_crtc_internal.h" 4367d0ec4eSDaniel Vetter #include "drm_internal.h" 448bd441b2SDaniel Vetter 45c394c2b0SMatt Roper static struct drm_framebuffer *add_framebuffer_internal(struct drm_device *dev, 46c394c2b0SMatt Roper struct drm_mode_fb_cmd2 *r, 47c394c2b0SMatt Roper struct drm_file *file_priv); 48c394c2b0SMatt Roper 49f453ba04SDave Airlie /* Avoid boilerplate. I'm tired of typing. */ 50f453ba04SDave Airlie #define DRM_ENUM_NAME_FN(fnname, list) \ 51d20d3174SVille Syrjälä const char *fnname(int val) \ 52f453ba04SDave Airlie { \ 53f453ba04SDave Airlie int i; \ 54f453ba04SDave Airlie for (i = 0; i < ARRAY_SIZE(list); i++) { \ 55f453ba04SDave Airlie if (list[i].type == val) \ 56f453ba04SDave Airlie return list[i].name; \ 57f453ba04SDave Airlie } \ 58f453ba04SDave Airlie return "(unknown)"; \ 59f453ba04SDave Airlie } 60f453ba04SDave Airlie 61f453ba04SDave Airlie /* 62f453ba04SDave Airlie * Global properties 63f453ba04SDave Airlie */ 644dfd909fSThierry Reding static const struct drm_prop_enum_list drm_dpms_enum_list[] = { 654dfd909fSThierry Reding { DRM_MODE_DPMS_ON, "On" }, 66f453ba04SDave Airlie { DRM_MODE_DPMS_STANDBY, "Standby" }, 67f453ba04SDave Airlie { DRM_MODE_DPMS_SUSPEND, "Suspend" }, 68f453ba04SDave Airlie { DRM_MODE_DPMS_OFF, "Off" } 69f453ba04SDave Airlie }; 70f453ba04SDave Airlie 71f453ba04SDave Airlie DRM_ENUM_NAME_FN(drm_get_dpms_name, drm_dpms_enum_list) 72f453ba04SDave Airlie 734dfd909fSThierry Reding static const struct drm_prop_enum_list drm_plane_type_enum_list[] = { 749922ab5aSRob Clark { DRM_PLANE_TYPE_OVERLAY, "Overlay" }, 759922ab5aSRob Clark { DRM_PLANE_TYPE_PRIMARY, "Primary" }, 769922ab5aSRob Clark { DRM_PLANE_TYPE_CURSOR, "Cursor" }, 779922ab5aSRob Clark }; 789922ab5aSRob Clark 79f453ba04SDave Airlie /* 80f453ba04SDave Airlie * Optional properties 81f453ba04SDave Airlie */ 824dfd909fSThierry Reding static const struct drm_prop_enum_list drm_scaling_mode_enum_list[] = { 8353bd8389SJesse Barnes { DRM_MODE_SCALE_NONE, "None" }, 8453bd8389SJesse Barnes { DRM_MODE_SCALE_FULLSCREEN, "Full" }, 8553bd8389SJesse Barnes { DRM_MODE_SCALE_CENTER, "Center" }, 8653bd8389SJesse Barnes { DRM_MODE_SCALE_ASPECT, "Full aspect" }, 87f453ba04SDave Airlie }; 88f453ba04SDave Airlie 89ff587e45SVandana Kannan static const struct drm_prop_enum_list drm_aspect_ratio_enum_list[] = { 90ff587e45SVandana Kannan { DRM_MODE_PICTURE_ASPECT_NONE, "Automatic" }, 91ff587e45SVandana Kannan { DRM_MODE_PICTURE_ASPECT_4_3, "4:3" }, 92ff587e45SVandana Kannan { DRM_MODE_PICTURE_ASPECT_16_9, "16:9" }, 93ff587e45SVandana Kannan }; 94ff587e45SVandana Kannan 95f453ba04SDave Airlie /* 96f453ba04SDave Airlie * Non-global properties, but "required" for certain connectors. 97f453ba04SDave Airlie */ 984dfd909fSThierry Reding static const struct drm_prop_enum_list drm_dvi_i_select_enum_list[] = { 99f453ba04SDave Airlie { DRM_MODE_SUBCONNECTOR_Automatic, "Automatic" }, /* DVI-I and TV-out */ 100f453ba04SDave Airlie { DRM_MODE_SUBCONNECTOR_DVID, "DVI-D" }, /* DVI-I */ 101f453ba04SDave Airlie { DRM_MODE_SUBCONNECTOR_DVIA, "DVI-A" }, /* DVI-I */ 102f453ba04SDave Airlie }; 103f453ba04SDave Airlie 104f453ba04SDave Airlie DRM_ENUM_NAME_FN(drm_get_dvi_i_select_name, drm_dvi_i_select_enum_list) 105f453ba04SDave Airlie 1064dfd909fSThierry Reding static const struct drm_prop_enum_list drm_dvi_i_subconnector_enum_list[] = { 107f453ba04SDave Airlie { DRM_MODE_SUBCONNECTOR_Unknown, "Unknown" }, /* DVI-I and TV-out */ 108f453ba04SDave Airlie { DRM_MODE_SUBCONNECTOR_DVID, "DVI-D" }, /* DVI-I */ 109f453ba04SDave Airlie { DRM_MODE_SUBCONNECTOR_DVIA, "DVI-A" }, /* DVI-I */ 110f453ba04SDave Airlie }; 111f453ba04SDave Airlie 112f453ba04SDave Airlie DRM_ENUM_NAME_FN(drm_get_dvi_i_subconnector_name, 113f453ba04SDave Airlie drm_dvi_i_subconnector_enum_list) 114f453ba04SDave Airlie 1154dfd909fSThierry Reding static const struct drm_prop_enum_list drm_tv_select_enum_list[] = { 116f453ba04SDave Airlie { DRM_MODE_SUBCONNECTOR_Automatic, "Automatic" }, /* DVI-I and TV-out */ 117f453ba04SDave Airlie { DRM_MODE_SUBCONNECTOR_Composite, "Composite" }, /* TV-out */ 118f453ba04SDave Airlie { DRM_MODE_SUBCONNECTOR_SVIDEO, "SVIDEO" }, /* TV-out */ 119f453ba04SDave Airlie { DRM_MODE_SUBCONNECTOR_Component, "Component" }, /* TV-out */ 120aeaa1ad3SFrancisco Jerez { DRM_MODE_SUBCONNECTOR_SCART, "SCART" }, /* TV-out */ 121f453ba04SDave Airlie }; 122f453ba04SDave Airlie 123f453ba04SDave Airlie DRM_ENUM_NAME_FN(drm_get_tv_select_name, drm_tv_select_enum_list) 124f453ba04SDave Airlie 1254dfd909fSThierry Reding static const struct drm_prop_enum_list drm_tv_subconnector_enum_list[] = { 126f453ba04SDave Airlie { DRM_MODE_SUBCONNECTOR_Unknown, "Unknown" }, /* DVI-I and TV-out */ 127f453ba04SDave Airlie { DRM_MODE_SUBCONNECTOR_Composite, "Composite" }, /* TV-out */ 128f453ba04SDave Airlie { DRM_MODE_SUBCONNECTOR_SVIDEO, "SVIDEO" }, /* TV-out */ 129f453ba04SDave Airlie { DRM_MODE_SUBCONNECTOR_Component, "Component" }, /* TV-out */ 130aeaa1ad3SFrancisco Jerez { DRM_MODE_SUBCONNECTOR_SCART, "SCART" }, /* TV-out */ 131f453ba04SDave Airlie }; 132f453ba04SDave Airlie 133f453ba04SDave Airlie DRM_ENUM_NAME_FN(drm_get_tv_subconnector_name, 134f453ba04SDave Airlie drm_tv_subconnector_enum_list) 135f453ba04SDave Airlie 136d20d3174SVille Syrjälä static const struct drm_prop_enum_list drm_dirty_info_enum_list[] = { 137884840aaSJakob Bornecrantz { DRM_MODE_DIRTY_OFF, "Off" }, 138884840aaSJakob Bornecrantz { DRM_MODE_DIRTY_ON, "On" }, 139884840aaSJakob Bornecrantz { DRM_MODE_DIRTY_ANNOTATE, "Annotate" }, 140884840aaSJakob Bornecrantz }; 141884840aaSJakob Bornecrantz 142f453ba04SDave Airlie struct drm_conn_prop_enum_list { 143f453ba04SDave Airlie int type; 144d20d3174SVille Syrjälä const char *name; 145b21e3afeSIlia Mirkin struct ida ida; 146f453ba04SDave Airlie }; 147f453ba04SDave Airlie 148f453ba04SDave Airlie /* 149f453ba04SDave Airlie * Connector and encoder types. 150f453ba04SDave Airlie */ 1514dfd909fSThierry Reding static struct drm_conn_prop_enum_list drm_connector_enum_list[] = { 1524dfd909fSThierry Reding { DRM_MODE_CONNECTOR_Unknown, "Unknown" }, 153b21e3afeSIlia Mirkin { DRM_MODE_CONNECTOR_VGA, "VGA" }, 154b21e3afeSIlia Mirkin { DRM_MODE_CONNECTOR_DVII, "DVI-I" }, 155b21e3afeSIlia Mirkin { DRM_MODE_CONNECTOR_DVID, "DVI-D" }, 156b21e3afeSIlia Mirkin { DRM_MODE_CONNECTOR_DVIA, "DVI-A" }, 157b21e3afeSIlia Mirkin { DRM_MODE_CONNECTOR_Composite, "Composite" }, 158b21e3afeSIlia Mirkin { DRM_MODE_CONNECTOR_SVIDEO, "SVIDEO" }, 159b21e3afeSIlia Mirkin { DRM_MODE_CONNECTOR_LVDS, "LVDS" }, 160b21e3afeSIlia Mirkin { DRM_MODE_CONNECTOR_Component, "Component" }, 161b21e3afeSIlia Mirkin { DRM_MODE_CONNECTOR_9PinDIN, "DIN" }, 162b21e3afeSIlia Mirkin { DRM_MODE_CONNECTOR_DisplayPort, "DP" }, 163b21e3afeSIlia Mirkin { DRM_MODE_CONNECTOR_HDMIA, "HDMI-A" }, 164b21e3afeSIlia Mirkin { DRM_MODE_CONNECTOR_HDMIB, "HDMI-B" }, 165b21e3afeSIlia Mirkin { DRM_MODE_CONNECTOR_TV, "TV" }, 166b21e3afeSIlia Mirkin { DRM_MODE_CONNECTOR_eDP, "eDP" }, 167b21e3afeSIlia Mirkin { DRM_MODE_CONNECTOR_VIRTUAL, "Virtual" }, 168b8923273SShobhit Kumar { DRM_MODE_CONNECTOR_DSI, "DSI" }, 169f453ba04SDave Airlie }; 170f453ba04SDave Airlie 1714dfd909fSThierry Reding static const struct drm_prop_enum_list drm_encoder_enum_list[] = { 1724dfd909fSThierry Reding { DRM_MODE_ENCODER_NONE, "None" }, 173f453ba04SDave Airlie { DRM_MODE_ENCODER_DAC, "DAC" }, 174f453ba04SDave Airlie { DRM_MODE_ENCODER_TMDS, "TMDS" }, 175f453ba04SDave Airlie { DRM_MODE_ENCODER_LVDS, "LVDS" }, 176f453ba04SDave Airlie { DRM_MODE_ENCODER_TVDAC, "TV" }, 177a7331e5cSThomas Hellstrom { DRM_MODE_ENCODER_VIRTUAL, "Virtual" }, 178b8923273SShobhit Kumar { DRM_MODE_ENCODER_DSI, "DSI" }, 179182407a6SDave Airlie { DRM_MODE_ENCODER_DPMST, "DP MST" }, 180f453ba04SDave Airlie }; 181f453ba04SDave Airlie 1824dfd909fSThierry Reding static const struct drm_prop_enum_list drm_subpixel_enum_list[] = { 183ac1bb36cSJesse Barnes { SubPixelUnknown, "Unknown" }, 184ac1bb36cSJesse Barnes { SubPixelHorizontalRGB, "Horizontal RGB" }, 185ac1bb36cSJesse Barnes { SubPixelHorizontalBGR, "Horizontal BGR" }, 186ac1bb36cSJesse Barnes { SubPixelVerticalRGB, "Vertical RGB" }, 187ac1bb36cSJesse Barnes { SubPixelVerticalBGR, "Vertical BGR" }, 188ac1bb36cSJesse Barnes { SubPixelNone, "None" }, 189ac1bb36cSJesse Barnes }; 190ac1bb36cSJesse Barnes 191b21e3afeSIlia Mirkin void drm_connector_ida_init(void) 192b21e3afeSIlia Mirkin { 193b21e3afeSIlia Mirkin int i; 194b21e3afeSIlia Mirkin 195b21e3afeSIlia Mirkin for (i = 0; i < ARRAY_SIZE(drm_connector_enum_list); i++) 196b21e3afeSIlia Mirkin ida_init(&drm_connector_enum_list[i].ida); 197b21e3afeSIlia Mirkin } 198b21e3afeSIlia Mirkin 199b21e3afeSIlia Mirkin void drm_connector_ida_destroy(void) 200b21e3afeSIlia Mirkin { 201b21e3afeSIlia Mirkin int i; 202b21e3afeSIlia Mirkin 203b21e3afeSIlia Mirkin for (i = 0; i < ARRAY_SIZE(drm_connector_enum_list); i++) 204b21e3afeSIlia Mirkin ida_destroy(&drm_connector_enum_list[i].ida); 205b21e3afeSIlia Mirkin } 206b21e3afeSIlia Mirkin 207c8e32cc1SDaniel Vetter /** 208c8e32cc1SDaniel Vetter * drm_get_connector_status_name - return a string for connector status 209c8e32cc1SDaniel Vetter * @status: connector status to compute name of 210c8e32cc1SDaniel Vetter * 211c8e32cc1SDaniel Vetter * In contrast to the other drm_get_*_name functions this one here returns a 212c8e32cc1SDaniel Vetter * const pointer and hence is threadsafe. 213c8e32cc1SDaniel Vetter */ 214d20d3174SVille Syrjälä const char *drm_get_connector_status_name(enum drm_connector_status status) 215f453ba04SDave Airlie { 216f453ba04SDave Airlie if (status == connector_status_connected) 217f453ba04SDave Airlie return "connected"; 218f453ba04SDave Airlie else if (status == connector_status_disconnected) 219f453ba04SDave Airlie return "disconnected"; 220f453ba04SDave Airlie else 221f453ba04SDave Airlie return "unknown"; 222f453ba04SDave Airlie } 223ed7951dcSLespiau, Damien EXPORT_SYMBOL(drm_get_connector_status_name); 224f453ba04SDave Airlie 225ac1bb36cSJesse Barnes /** 226ac1bb36cSJesse Barnes * drm_get_subpixel_order_name - return a string for a given subpixel enum 227ac1bb36cSJesse Barnes * @order: enum of subpixel_order 228ac1bb36cSJesse Barnes * 229ac1bb36cSJesse Barnes * Note you could abuse this and return something out of bounds, but that 230ac1bb36cSJesse Barnes * would be a caller error. No unscrubbed user data should make it here. 231ac1bb36cSJesse Barnes */ 232ac1bb36cSJesse Barnes const char *drm_get_subpixel_order_name(enum subpixel_order order) 233ac1bb36cSJesse Barnes { 234ac1bb36cSJesse Barnes return drm_subpixel_enum_list[order].name; 235ac1bb36cSJesse Barnes } 236ac1bb36cSJesse Barnes EXPORT_SYMBOL(drm_get_subpixel_order_name); 237ac1bb36cSJesse Barnes 2386ba6d03eSVille Syrjälä static char printable_char(int c) 2396ba6d03eSVille Syrjälä { 2406ba6d03eSVille Syrjälä return isascii(c) && isprint(c) ? c : '?'; 2416ba6d03eSVille Syrjälä } 2426ba6d03eSVille Syrjälä 243c8e32cc1SDaniel Vetter /** 244c8e32cc1SDaniel Vetter * drm_get_format_name - return a string for drm fourcc format 245c8e32cc1SDaniel Vetter * @format: format to compute name of 246c8e32cc1SDaniel Vetter * 247c8e32cc1SDaniel Vetter * Note that the buffer used by this function is globally shared and owned by 248c8e32cc1SDaniel Vetter * the function itself. 249c8e32cc1SDaniel Vetter * 250c8e32cc1SDaniel Vetter * FIXME: This isn't really multithreading safe. 251c8e32cc1SDaniel Vetter */ 252d20d3174SVille Syrjälä const char *drm_get_format_name(uint32_t format) 2536ba6d03eSVille Syrjälä { 2546ba6d03eSVille Syrjälä static char buf[32]; 2556ba6d03eSVille Syrjälä 2566ba6d03eSVille Syrjälä snprintf(buf, sizeof(buf), 2576ba6d03eSVille Syrjälä "%c%c%c%c %s-endian (0x%08x)", 2586ba6d03eSVille Syrjälä printable_char(format & 0xff), 2596ba6d03eSVille Syrjälä printable_char((format >> 8) & 0xff), 2606ba6d03eSVille Syrjälä printable_char((format >> 16) & 0xff), 2616ba6d03eSVille Syrjälä printable_char((format >> 24) & 0x7f), 2626ba6d03eSVille Syrjälä format & DRM_FORMAT_BIG_ENDIAN ? "big" : "little", 2636ba6d03eSVille Syrjälä format); 2646ba6d03eSVille Syrjälä 2656ba6d03eSVille Syrjälä return buf; 2666ba6d03eSVille Syrjälä } 2676ba6d03eSVille Syrjälä EXPORT_SYMBOL(drm_get_format_name); 2686ba6d03eSVille Syrjälä 2692ee39452SDave Airlie /* 2702ee39452SDave Airlie * Internal function to assign a slot in the object idr and optionally 2712ee39452SDave Airlie * register the object into the idr. 2722ee39452SDave Airlie */ 2732ee39452SDave Airlie static int drm_mode_object_get_reg(struct drm_device *dev, 2742ee39452SDave Airlie struct drm_mode_object *obj, 2752ee39452SDave Airlie uint32_t obj_type, 2762ee39452SDave Airlie bool register_obj) 2772ee39452SDave Airlie { 2782ee39452SDave Airlie int ret; 2792ee39452SDave Airlie 2802ee39452SDave Airlie mutex_lock(&dev->mode_config.idr_mutex); 2812ee39452SDave Airlie ret = idr_alloc(&dev->mode_config.crtc_idr, register_obj ? obj : NULL, 1, 0, GFP_KERNEL); 2822ee39452SDave Airlie if (ret >= 0) { 2832ee39452SDave Airlie /* 2842ee39452SDave Airlie * Set up the object linking under the protection of the idr 2852ee39452SDave Airlie * lock so that other users can't see inconsistent state. 2862ee39452SDave Airlie */ 2872ee39452SDave Airlie obj->id = ret; 2882ee39452SDave Airlie obj->type = obj_type; 2892ee39452SDave Airlie } 2902ee39452SDave Airlie mutex_unlock(&dev->mode_config.idr_mutex); 2912ee39452SDave Airlie 2922ee39452SDave Airlie return ret < 0 ? ret : 0; 2932ee39452SDave Airlie } 2942ee39452SDave Airlie 295f453ba04SDave Airlie /** 296065a50edSDaniel Vetter * drm_mode_object_get - allocate a new modeset identifier 297f453ba04SDave Airlie * @dev: DRM device 298065a50edSDaniel Vetter * @obj: object pointer, used to generate unique ID 299065a50edSDaniel Vetter * @obj_type: object type 300f453ba04SDave Airlie * 301f453ba04SDave Airlie * Create a unique identifier based on @ptr in @dev's identifier space. Used 302c8e32cc1SDaniel Vetter * for tracking modes, CRTCs and connectors. Note that despite the _get postfix 303c8e32cc1SDaniel Vetter * modeset identifiers are _not_ reference counted. Hence don't use this for 304c8e32cc1SDaniel Vetter * reference counted modeset objects like framebuffers. 305f453ba04SDave Airlie * 306c8e32cc1SDaniel Vetter * Returns: 307f453ba04SDave Airlie * New unique (relative to other objects in @dev) integer identifier for the 308f453ba04SDave Airlie * object. 309f453ba04SDave Airlie */ 3108bd441b2SDaniel Vetter int drm_mode_object_get(struct drm_device *dev, 311f453ba04SDave Airlie struct drm_mode_object *obj, uint32_t obj_type) 312f453ba04SDave Airlie { 3132ee39452SDave Airlie return drm_mode_object_get_reg(dev, obj, obj_type, true); 3144b096ac1SDaniel Vetter } 3154b096ac1SDaniel Vetter 3162ee39452SDave Airlie static void drm_mode_object_register(struct drm_device *dev, 3172ee39452SDave Airlie struct drm_mode_object *obj) 3182ee39452SDave Airlie { 3192ee39452SDave Airlie mutex_lock(&dev->mode_config.idr_mutex); 3202ee39452SDave Airlie idr_replace(&dev->mode_config.crtc_idr, obj, obj->id); 3212ee39452SDave Airlie mutex_unlock(&dev->mode_config.idr_mutex); 322f453ba04SDave Airlie } 323f453ba04SDave Airlie 324f453ba04SDave Airlie /** 325065a50edSDaniel Vetter * drm_mode_object_put - free a modeset identifer 326f453ba04SDave Airlie * @dev: DRM device 327065a50edSDaniel Vetter * @object: object to free 328f453ba04SDave Airlie * 329c8e32cc1SDaniel Vetter * Free @id from @dev's unique identifier pool. Note that despite the _get 330c8e32cc1SDaniel Vetter * postfix modeset identifiers are _not_ reference counted. Hence don't use this 331c8e32cc1SDaniel Vetter * for reference counted modeset objects like framebuffers. 332f453ba04SDave Airlie */ 3338bd441b2SDaniel Vetter void drm_mode_object_put(struct drm_device *dev, 334f453ba04SDave Airlie struct drm_mode_object *object) 335f453ba04SDave Airlie { 336ad2563c2SJesse Barnes mutex_lock(&dev->mode_config.idr_mutex); 337f453ba04SDave Airlie idr_remove(&dev->mode_config.crtc_idr, object->id); 338ad2563c2SJesse Barnes mutex_unlock(&dev->mode_config.idr_mutex); 339f453ba04SDave Airlie } 340f453ba04SDave Airlie 34198f75de4SRob Clark static struct drm_mode_object *_object_find(struct drm_device *dev, 34298f75de4SRob Clark uint32_t id, uint32_t type) 34398f75de4SRob Clark { 34498f75de4SRob Clark struct drm_mode_object *obj = NULL; 34598f75de4SRob Clark 34698f75de4SRob Clark mutex_lock(&dev->mode_config.idr_mutex); 34798f75de4SRob Clark obj = idr_find(&dev->mode_config.crtc_idr, id); 348168c02ecSDaniel Vetter if (obj && type != DRM_MODE_OBJECT_ANY && obj->type != type) 349168c02ecSDaniel Vetter obj = NULL; 350168c02ecSDaniel Vetter if (obj && obj->id != id) 351168c02ecSDaniel Vetter obj = NULL; 352168c02ecSDaniel Vetter /* don't leak out unref'd fb's */ 353168c02ecSDaniel Vetter if (obj && (obj->type == DRM_MODE_OBJECT_FB)) 35498f75de4SRob Clark obj = NULL; 35598f75de4SRob Clark mutex_unlock(&dev->mode_config.idr_mutex); 35698f75de4SRob Clark 35798f75de4SRob Clark return obj; 35898f75de4SRob Clark } 35998f75de4SRob Clark 360786b99edSDaniel Vetter /** 361786b99edSDaniel Vetter * drm_mode_object_find - look up a drm object with static lifetime 362786b99edSDaniel Vetter * @dev: drm device 363786b99edSDaniel Vetter * @id: id of the mode object 364786b99edSDaniel Vetter * @type: type of the mode object 365786b99edSDaniel Vetter * 366786b99edSDaniel Vetter * Note that framebuffers cannot be looked up with this functions - since those 36798f75de4SRob Clark * are reference counted, they need special treatment. Even with 36898f75de4SRob Clark * DRM_MODE_OBJECT_ANY (although that will simply return NULL 36998f75de4SRob Clark * rather than WARN_ON()). 370786b99edSDaniel Vetter */ 3717a9c9060SDaniel Vetter struct drm_mode_object *drm_mode_object_find(struct drm_device *dev, 3727a9c9060SDaniel Vetter uint32_t id, uint32_t type) 373f453ba04SDave Airlie { 374ad2563c2SJesse Barnes struct drm_mode_object *obj = NULL; 375f453ba04SDave Airlie 376786b99edSDaniel Vetter /* Framebuffers are reference counted and need their own lookup 377786b99edSDaniel Vetter * function.*/ 378786b99edSDaniel Vetter WARN_ON(type == DRM_MODE_OBJECT_FB); 37998f75de4SRob Clark obj = _object_find(dev, id, type); 380f453ba04SDave Airlie return obj; 381f453ba04SDave Airlie } 382f453ba04SDave Airlie EXPORT_SYMBOL(drm_mode_object_find); 383f453ba04SDave Airlie 384f453ba04SDave Airlie /** 385f453ba04SDave Airlie * drm_framebuffer_init - initialize a framebuffer 386f453ba04SDave Airlie * @dev: DRM device 387065a50edSDaniel Vetter * @fb: framebuffer to be initialized 388065a50edSDaniel Vetter * @funcs: ... with these functions 389f453ba04SDave Airlie * 390f453ba04SDave Airlie * Allocates an ID for the framebuffer's parent mode object, sets its mode 391f453ba04SDave Airlie * functions & device file and adds it to the master fd list. 392f453ba04SDave Airlie * 3934b096ac1SDaniel Vetter * IMPORTANT: 3944b096ac1SDaniel Vetter * This functions publishes the fb and makes it available for concurrent access 3954b096ac1SDaniel Vetter * by other users. Which means by this point the fb _must_ be fully set up - 3964b096ac1SDaniel Vetter * since all the fb attributes are invariant over its lifetime, no further 3974b096ac1SDaniel Vetter * locking but only correct reference counting is required. 3984b096ac1SDaniel Vetter * 399c8e32cc1SDaniel Vetter * Returns: 400af901ca1SAndré Goddard Rosa * Zero on success, error code on failure. 401f453ba04SDave Airlie */ 402f453ba04SDave Airlie int drm_framebuffer_init(struct drm_device *dev, struct drm_framebuffer *fb, 403f453ba04SDave Airlie const struct drm_framebuffer_funcs *funcs) 404f453ba04SDave Airlie { 405f453ba04SDave Airlie int ret; 406f453ba04SDave Airlie 4074b096ac1SDaniel Vetter mutex_lock(&dev->mode_config.fb_lock); 408f7eff60eSRob Clark kref_init(&fb->refcount); 4094b096ac1SDaniel Vetter INIT_LIST_HEAD(&fb->filp_head); 4104b096ac1SDaniel Vetter fb->dev = dev; 4114b096ac1SDaniel Vetter fb->funcs = funcs; 412f7eff60eSRob Clark 413f453ba04SDave Airlie ret = drm_mode_object_get(dev, &fb->base, DRM_MODE_OBJECT_FB); 4146bfc56aaSVille Syrjälä if (ret) 4154b096ac1SDaniel Vetter goto out; 416f453ba04SDave Airlie 417f453ba04SDave Airlie dev->mode_config.num_fb++; 418f453ba04SDave Airlie list_add(&fb->head, &dev->mode_config.fb_list); 4194b096ac1SDaniel Vetter out: 4204b096ac1SDaniel Vetter mutex_unlock(&dev->mode_config.fb_lock); 421f453ba04SDave Airlie 422f453ba04SDave Airlie return 0; 423f453ba04SDave Airlie } 424f453ba04SDave Airlie EXPORT_SYMBOL(drm_framebuffer_init); 425f453ba04SDave Airlie 42683f45fc3SDaniel Vetter /* dev->mode_config.fb_lock must be held! */ 42783f45fc3SDaniel Vetter static void __drm_framebuffer_unregister(struct drm_device *dev, 42883f45fc3SDaniel Vetter struct drm_framebuffer *fb) 42983f45fc3SDaniel Vetter { 43083f45fc3SDaniel Vetter mutex_lock(&dev->mode_config.idr_mutex); 43183f45fc3SDaniel Vetter idr_remove(&dev->mode_config.crtc_idr, fb->base.id); 43283f45fc3SDaniel Vetter mutex_unlock(&dev->mode_config.idr_mutex); 43383f45fc3SDaniel Vetter 43483f45fc3SDaniel Vetter fb->base.id = 0; 43583f45fc3SDaniel Vetter } 43683f45fc3SDaniel Vetter 437f7eff60eSRob Clark static void drm_framebuffer_free(struct kref *kref) 438f7eff60eSRob Clark { 439f7eff60eSRob Clark struct drm_framebuffer *fb = 440f7eff60eSRob Clark container_of(kref, struct drm_framebuffer, refcount); 44183f45fc3SDaniel Vetter struct drm_device *dev = fb->dev; 44283f45fc3SDaniel Vetter 44383f45fc3SDaniel Vetter /* 44483f45fc3SDaniel Vetter * The lookup idr holds a weak reference, which has not necessarily been 44583f45fc3SDaniel Vetter * removed at this point. Check for that. 44683f45fc3SDaniel Vetter */ 44783f45fc3SDaniel Vetter mutex_lock(&dev->mode_config.fb_lock); 44883f45fc3SDaniel Vetter if (fb->base.id) { 44983f45fc3SDaniel Vetter /* Mark fb as reaped and drop idr ref. */ 45083f45fc3SDaniel Vetter __drm_framebuffer_unregister(dev, fb); 45183f45fc3SDaniel Vetter } 45283f45fc3SDaniel Vetter mutex_unlock(&dev->mode_config.fb_lock); 45383f45fc3SDaniel Vetter 454f7eff60eSRob Clark fb->funcs->destroy(fb); 455f7eff60eSRob Clark } 456f7eff60eSRob Clark 4572b677e8cSDaniel Vetter static struct drm_framebuffer *__drm_framebuffer_lookup(struct drm_device *dev, 4582b677e8cSDaniel Vetter uint32_t id) 4592b677e8cSDaniel Vetter { 4602b677e8cSDaniel Vetter struct drm_mode_object *obj = NULL; 4612b677e8cSDaniel Vetter struct drm_framebuffer *fb; 4622b677e8cSDaniel Vetter 4632b677e8cSDaniel Vetter mutex_lock(&dev->mode_config.idr_mutex); 4642b677e8cSDaniel Vetter obj = idr_find(&dev->mode_config.crtc_idr, id); 4652b677e8cSDaniel Vetter if (!obj || (obj->type != DRM_MODE_OBJECT_FB) || (obj->id != id)) 4662b677e8cSDaniel Vetter fb = NULL; 4672b677e8cSDaniel Vetter else 4682b677e8cSDaniel Vetter fb = obj_to_fb(obj); 4692b677e8cSDaniel Vetter mutex_unlock(&dev->mode_config.idr_mutex); 4702b677e8cSDaniel Vetter 4712b677e8cSDaniel Vetter return fb; 4722b677e8cSDaniel Vetter } 4732b677e8cSDaniel Vetter 474f7eff60eSRob Clark /** 475786b99edSDaniel Vetter * drm_framebuffer_lookup - look up a drm framebuffer and grab a reference 476786b99edSDaniel Vetter * @dev: drm device 477786b99edSDaniel Vetter * @id: id of the fb object 478786b99edSDaniel Vetter * 479786b99edSDaniel Vetter * If successful, this grabs an additional reference to the framebuffer - 480786b99edSDaniel Vetter * callers need to make sure to eventually unreference the returned framebuffer 481c8e32cc1SDaniel Vetter * again, using @drm_framebuffer_unreference. 482786b99edSDaniel Vetter */ 483786b99edSDaniel Vetter struct drm_framebuffer *drm_framebuffer_lookup(struct drm_device *dev, 484786b99edSDaniel Vetter uint32_t id) 485786b99edSDaniel Vetter { 486786b99edSDaniel Vetter struct drm_framebuffer *fb; 487786b99edSDaniel Vetter 488786b99edSDaniel Vetter mutex_lock(&dev->mode_config.fb_lock); 4892b677e8cSDaniel Vetter fb = __drm_framebuffer_lookup(dev, id); 49083f45fc3SDaniel Vetter if (fb) { 49183f45fc3SDaniel Vetter if (!kref_get_unless_zero(&fb->refcount)) 49283f45fc3SDaniel Vetter fb = NULL; 49383f45fc3SDaniel Vetter } 494786b99edSDaniel Vetter mutex_unlock(&dev->mode_config.fb_lock); 495786b99edSDaniel Vetter 496786b99edSDaniel Vetter return fb; 497786b99edSDaniel Vetter } 498786b99edSDaniel Vetter EXPORT_SYMBOL(drm_framebuffer_lookup); 499786b99edSDaniel Vetter 500786b99edSDaniel Vetter /** 501f7eff60eSRob Clark * drm_framebuffer_unreference - unref a framebuffer 502065a50edSDaniel Vetter * @fb: framebuffer to unref 503065a50edSDaniel Vetter * 504065a50edSDaniel Vetter * This functions decrements the fb's refcount and frees it if it drops to zero. 505f7eff60eSRob Clark */ 506f7eff60eSRob Clark void drm_framebuffer_unreference(struct drm_framebuffer *fb) 507f7eff60eSRob Clark { 5088291272aSRob Clark DRM_DEBUG("%p: FB ID: %d (%d)\n", fb, fb->base.id, atomic_read(&fb->refcount.refcount)); 509f7eff60eSRob Clark kref_put(&fb->refcount, drm_framebuffer_free); 510f7eff60eSRob Clark } 511f7eff60eSRob Clark EXPORT_SYMBOL(drm_framebuffer_unreference); 512f7eff60eSRob Clark 513f7eff60eSRob Clark /** 514f7eff60eSRob Clark * drm_framebuffer_reference - incr the fb refcnt 515065a50edSDaniel Vetter * @fb: framebuffer 516c8e32cc1SDaniel Vetter * 517c8e32cc1SDaniel Vetter * This functions increments the fb's refcount. 518f7eff60eSRob Clark */ 519f7eff60eSRob Clark void drm_framebuffer_reference(struct drm_framebuffer *fb) 520f7eff60eSRob Clark { 5218291272aSRob Clark DRM_DEBUG("%p: FB ID: %d (%d)\n", fb, fb->base.id, atomic_read(&fb->refcount.refcount)); 522f7eff60eSRob Clark kref_get(&fb->refcount); 523f7eff60eSRob Clark } 524f7eff60eSRob Clark EXPORT_SYMBOL(drm_framebuffer_reference); 525f7eff60eSRob Clark 5262b677e8cSDaniel Vetter static void drm_framebuffer_free_bug(struct kref *kref) 5272b677e8cSDaniel Vetter { 5282b677e8cSDaniel Vetter BUG(); 5292b677e8cSDaniel Vetter } 5302b677e8cSDaniel Vetter 5316c2a7532SDaniel Vetter static void __drm_framebuffer_unreference(struct drm_framebuffer *fb) 5326c2a7532SDaniel Vetter { 5338291272aSRob Clark DRM_DEBUG("%p: FB ID: %d (%d)\n", fb, fb->base.id, atomic_read(&fb->refcount.refcount)); 5346c2a7532SDaniel Vetter kref_put(&fb->refcount, drm_framebuffer_free_bug); 5356c2a7532SDaniel Vetter } 5366c2a7532SDaniel Vetter 537f453ba04SDave Airlie /** 53836206361SDaniel Vetter * drm_framebuffer_unregister_private - unregister a private fb from the lookup idr 53936206361SDaniel Vetter * @fb: fb to unregister 54036206361SDaniel Vetter * 54136206361SDaniel Vetter * Drivers need to call this when cleaning up driver-private framebuffers, e.g. 54236206361SDaniel Vetter * those used for fbdev. Note that the caller must hold a reference of it's own, 54336206361SDaniel Vetter * i.e. the object may not be destroyed through this call (since it'll lead to a 54436206361SDaniel Vetter * locking inversion). 54536206361SDaniel Vetter */ 54636206361SDaniel Vetter void drm_framebuffer_unregister_private(struct drm_framebuffer *fb) 54736206361SDaniel Vetter { 5482b677e8cSDaniel Vetter struct drm_device *dev = fb->dev; 5492b677e8cSDaniel Vetter 5502b677e8cSDaniel Vetter mutex_lock(&dev->mode_config.fb_lock); 5512b677e8cSDaniel Vetter /* Mark fb as reaped and drop idr ref. */ 5522b677e8cSDaniel Vetter __drm_framebuffer_unregister(dev, fb); 5532b677e8cSDaniel Vetter mutex_unlock(&dev->mode_config.fb_lock); 55436206361SDaniel Vetter } 55536206361SDaniel Vetter EXPORT_SYMBOL(drm_framebuffer_unregister_private); 55636206361SDaniel Vetter 55736206361SDaniel Vetter /** 558f453ba04SDave Airlie * drm_framebuffer_cleanup - remove a framebuffer object 559f453ba04SDave Airlie * @fb: framebuffer to remove 560f453ba04SDave Airlie * 561c8e32cc1SDaniel Vetter * Cleanup framebuffer. This function is intended to be used from the drivers 562c8e32cc1SDaniel Vetter * ->destroy callback. It can also be used to clean up driver private 563c8e32cc1SDaniel Vetter * framebuffers embedded into a larger structure. 56436206361SDaniel Vetter * 56536206361SDaniel Vetter * Note that this function does not remove the fb from active usuage - if it is 56636206361SDaniel Vetter * still used anywhere, hilarity can ensue since userspace could call getfb on 56736206361SDaniel Vetter * the id and get back -EINVAL. Obviously no concern at driver unload time. 56836206361SDaniel Vetter * 56936206361SDaniel Vetter * Also, the framebuffer will not be removed from the lookup idr - for 57036206361SDaniel Vetter * user-created framebuffers this will happen in in the rmfb ioctl. For 57136206361SDaniel Vetter * driver-private objects (e.g. for fbdev) drivers need to explicitly call 57236206361SDaniel Vetter * drm_framebuffer_unregister_private. 573f453ba04SDave Airlie */ 574f453ba04SDave Airlie void drm_framebuffer_cleanup(struct drm_framebuffer *fb) 575f453ba04SDave Airlie { 576f453ba04SDave Airlie struct drm_device *dev = fb->dev; 5778faf6b18SDaniel Vetter 5784b096ac1SDaniel Vetter mutex_lock(&dev->mode_config.fb_lock); 579f7eff60eSRob Clark list_del(&fb->head); 580f7eff60eSRob Clark dev->mode_config.num_fb--; 5814b096ac1SDaniel Vetter mutex_unlock(&dev->mode_config.fb_lock); 582f7eff60eSRob Clark } 583f7eff60eSRob Clark EXPORT_SYMBOL(drm_framebuffer_cleanup); 584f7eff60eSRob Clark 585f7eff60eSRob Clark /** 586f7eff60eSRob Clark * drm_framebuffer_remove - remove and unreference a framebuffer object 587f7eff60eSRob Clark * @fb: framebuffer to remove 588f7eff60eSRob Clark * 589f7eff60eSRob Clark * Scans all the CRTCs and planes in @dev's mode_config. If they're 59036206361SDaniel Vetter * using @fb, removes it, setting it to NULL. Then drops the reference to the 591b62584e3SDaniel Vetter * passed-in framebuffer. Might take the modeset locks. 592b62584e3SDaniel Vetter * 593b62584e3SDaniel Vetter * Note that this function optimizes the cleanup away if the caller holds the 594b62584e3SDaniel Vetter * last reference to the framebuffer. It is also guaranteed to not take the 595b62584e3SDaniel Vetter * modeset locks in this case. 596f7eff60eSRob Clark */ 597f7eff60eSRob Clark void drm_framebuffer_remove(struct drm_framebuffer *fb) 598f7eff60eSRob Clark { 599f7eff60eSRob Clark struct drm_device *dev = fb->dev; 600f453ba04SDave Airlie struct drm_crtc *crtc; 6018cf5c917SJesse Barnes struct drm_plane *plane; 6025ef5f72fSDave Airlie struct drm_mode_set set; 6035ef5f72fSDave Airlie int ret; 604f453ba04SDave Airlie 6054b096ac1SDaniel Vetter WARN_ON(!list_empty(&fb->filp_head)); 6068faf6b18SDaniel Vetter 607b62584e3SDaniel Vetter /* 608b62584e3SDaniel Vetter * drm ABI mandates that we remove any deleted framebuffers from active 609b62584e3SDaniel Vetter * useage. But since most sane clients only remove framebuffers they no 610b62584e3SDaniel Vetter * longer need, try to optimize this away. 611b62584e3SDaniel Vetter * 612b62584e3SDaniel Vetter * Since we're holding a reference ourselves, observing a refcount of 1 613b62584e3SDaniel Vetter * means that we're the last holder and can skip it. Also, the refcount 614b62584e3SDaniel Vetter * can never increase from 1 again, so we don't need any barriers or 615b62584e3SDaniel Vetter * locks. 616b62584e3SDaniel Vetter * 617b62584e3SDaniel Vetter * Note that userspace could try to race with use and instate a new 618b62584e3SDaniel Vetter * usage _after_ we've cleared all current ones. End result will be an 619b62584e3SDaniel Vetter * in-use fb with fb-id == 0. Userspace is allowed to shoot its own foot 620b62584e3SDaniel Vetter * in this manner. 621b62584e3SDaniel Vetter */ 622b62584e3SDaniel Vetter if (atomic_read(&fb->refcount.refcount) > 1) { 623b62584e3SDaniel Vetter drm_modeset_lock_all(dev); 624f453ba04SDave Airlie /* remove from any CRTC */ 625f453ba04SDave Airlie list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { 626f4510a27SMatt Roper if (crtc->primary->fb == fb) { 6275ef5f72fSDave Airlie /* should turn off the crtc */ 6285ef5f72fSDave Airlie memset(&set, 0, sizeof(struct drm_mode_set)); 6295ef5f72fSDave Airlie set.crtc = crtc; 6305ef5f72fSDave Airlie set.fb = NULL; 6312d13b679SDaniel Vetter ret = drm_mode_set_config_internal(&set); 6325ef5f72fSDave Airlie if (ret) 6335ef5f72fSDave Airlie DRM_ERROR("failed to reset crtc %p when fb was deleted\n", crtc); 6345ef5f72fSDave Airlie } 635f453ba04SDave Airlie } 636f453ba04SDave Airlie 6378cf5c917SJesse Barnes list_for_each_entry(plane, &dev->mode_config.plane_list, head) { 6389125e618SVille Syrjälä if (plane->fb == fb) 6399125e618SVille Syrjälä drm_plane_force_disable(plane); 6408cf5c917SJesse Barnes } 641b62584e3SDaniel Vetter drm_modeset_unlock_all(dev); 642b62584e3SDaniel Vetter } 6438cf5c917SJesse Barnes 644f7eff60eSRob Clark drm_framebuffer_unreference(fb); 645f453ba04SDave Airlie } 646f7eff60eSRob Clark EXPORT_SYMBOL(drm_framebuffer_remove); 647f453ba04SDave Airlie 64851fd371bSRob Clark DEFINE_WW_CLASS(crtc_ww_class); 64951fd371bSRob Clark 650f453ba04SDave Airlie /** 651e13161afSMatt Roper * drm_crtc_init_with_planes - Initialise a new CRTC object with 652e13161afSMatt Roper * specified primary and cursor planes. 653f453ba04SDave Airlie * @dev: DRM device 654f453ba04SDave Airlie * @crtc: CRTC object to init 655e13161afSMatt Roper * @primary: Primary plane for CRTC 656e13161afSMatt Roper * @cursor: Cursor plane for CRTC 657f453ba04SDave Airlie * @funcs: callbacks for the new CRTC 658f453ba04SDave Airlie * 659ad6f5c34SVille Syrjälä * Inits a new object created as base part of a driver crtc object. 6606bfc56aaSVille Syrjälä * 661c8e32cc1SDaniel Vetter * Returns: 6626bfc56aaSVille Syrjälä * Zero on success, error code on failure. 663f453ba04SDave Airlie */ 664e13161afSMatt Roper int drm_crtc_init_with_planes(struct drm_device *dev, struct drm_crtc *crtc, 665e13161afSMatt Roper struct drm_plane *primary, 666fc1d3e44SMatt Roper struct drm_plane *cursor, 667f453ba04SDave Airlie const struct drm_crtc_funcs *funcs) 668f453ba04SDave Airlie { 66951fd371bSRob Clark struct drm_mode_config *config = &dev->mode_config; 6706bfc56aaSVille Syrjälä int ret; 6716bfc56aaSVille Syrjälä 672f453ba04SDave Airlie crtc->dev = dev; 673f453ba04SDave Airlie crtc->funcs = funcs; 6747c80e128SRob Clark crtc->invert_dimensions = false; 675f453ba04SDave Airlie 67651fd371bSRob Clark drm_modeset_lock_init(&crtc->mutex); 6776bfc56aaSVille Syrjälä ret = drm_mode_object_get(dev, &crtc->base, DRM_MODE_OBJECT_CRTC); 6786bfc56aaSVille Syrjälä if (ret) 679baf698b0SDaniel Vetter return ret; 680f453ba04SDave Airlie 681bffd9de0SPaulo Zanoni crtc->base.properties = &crtc->properties; 682bffd9de0SPaulo Zanoni 68351fd371bSRob Clark list_add_tail(&crtc->head, &config->crtc_list); 68451fd371bSRob Clark config->num_crtc++; 6856bfc56aaSVille Syrjälä 686e13161afSMatt Roper crtc->primary = primary; 687fc1d3e44SMatt Roper crtc->cursor = cursor; 688e13161afSMatt Roper if (primary) 689e13161afSMatt Roper primary->possible_crtcs = 1 << drm_crtc_index(crtc); 690fc1d3e44SMatt Roper if (cursor) 691fc1d3e44SMatt Roper cursor->possible_crtcs = 1 << drm_crtc_index(crtc); 692e13161afSMatt Roper 693baf698b0SDaniel Vetter return 0; 694f453ba04SDave Airlie } 695e13161afSMatt Roper EXPORT_SYMBOL(drm_crtc_init_with_planes); 696f453ba04SDave Airlie 697f453ba04SDave Airlie /** 698ad6f5c34SVille Syrjälä * drm_crtc_cleanup - Clean up the core crtc usage 699f453ba04SDave Airlie * @crtc: CRTC to cleanup 700f453ba04SDave Airlie * 701ad6f5c34SVille Syrjälä * This function cleans up @crtc and removes it from the DRM mode setting 702ad6f5c34SVille Syrjälä * core. Note that the function does *not* free the crtc structure itself, 703ad6f5c34SVille Syrjälä * this is the responsibility of the caller. 704f453ba04SDave Airlie */ 705f453ba04SDave Airlie void drm_crtc_cleanup(struct drm_crtc *crtc) 706f453ba04SDave Airlie { 707f453ba04SDave Airlie struct drm_device *dev = crtc->dev; 708f453ba04SDave Airlie 709f453ba04SDave Airlie kfree(crtc->gamma_store); 710f453ba04SDave Airlie crtc->gamma_store = NULL; 711f453ba04SDave Airlie 71251fd371bSRob Clark drm_modeset_lock_fini(&crtc->mutex); 71351fd371bSRob Clark 714f453ba04SDave Airlie drm_mode_object_put(dev, &crtc->base); 715f453ba04SDave Airlie list_del(&crtc->head); 716f453ba04SDave Airlie dev->mode_config.num_crtc--; 7173009c037SThierry Reding 7183009c037SThierry Reding WARN_ON(crtc->state && !crtc->funcs->atomic_destroy_state); 7193009c037SThierry Reding if (crtc->state && crtc->funcs->atomic_destroy_state) 7203009c037SThierry Reding crtc->funcs->atomic_destroy_state(crtc, crtc->state); 721a18c0af1SThierry Reding 722a18c0af1SThierry Reding memset(crtc, 0, sizeof(*crtc)); 723f453ba04SDave Airlie } 724f453ba04SDave Airlie EXPORT_SYMBOL(drm_crtc_cleanup); 725f453ba04SDave Airlie 726f453ba04SDave Airlie /** 727db5f7a6eSRussell King * drm_crtc_index - find the index of a registered CRTC 728db5f7a6eSRussell King * @crtc: CRTC to find index for 729db5f7a6eSRussell King * 730db5f7a6eSRussell King * Given a registered CRTC, return the index of that CRTC within a DRM 731db5f7a6eSRussell King * device's list of CRTCs. 732db5f7a6eSRussell King */ 733db5f7a6eSRussell King unsigned int drm_crtc_index(struct drm_crtc *crtc) 734db5f7a6eSRussell King { 735db5f7a6eSRussell King unsigned int index = 0; 736db5f7a6eSRussell King struct drm_crtc *tmp; 737db5f7a6eSRussell King 738db5f7a6eSRussell King list_for_each_entry(tmp, &crtc->dev->mode_config.crtc_list, head) { 739db5f7a6eSRussell King if (tmp == crtc) 740db5f7a6eSRussell King return index; 741db5f7a6eSRussell King 742db5f7a6eSRussell King index++; 743db5f7a6eSRussell King } 744db5f7a6eSRussell King 745db5f7a6eSRussell King BUG(); 746db5f7a6eSRussell King } 747db5f7a6eSRussell King EXPORT_SYMBOL(drm_crtc_index); 748db5f7a6eSRussell King 74986f422d5SLespiau, Damien /* 750f453ba04SDave Airlie * drm_mode_remove - remove and free a mode 751f453ba04SDave Airlie * @connector: connector list to modify 752f453ba04SDave Airlie * @mode: mode to remove 753f453ba04SDave Airlie * 754f453ba04SDave Airlie * Remove @mode from @connector's mode list, then free it. 755f453ba04SDave Airlie */ 75686f422d5SLespiau, Damien static void drm_mode_remove(struct drm_connector *connector, 757f453ba04SDave Airlie struct drm_display_mode *mode) 758f453ba04SDave Airlie { 759f453ba04SDave Airlie list_del(&mode->head); 760554f1d78SSascha Hauer drm_mode_destroy(connector->dev, mode); 761f453ba04SDave Airlie } 762f453ba04SDave Airlie 763f453ba04SDave Airlie /** 764eaf99c74SChris Wilson * drm_connector_get_cmdline_mode - reads the user's cmdline mode 765eaf99c74SChris Wilson * @connector: connector to quwery 766eaf99c74SChris Wilson * 767eaf99c74SChris Wilson * The kernel supports per-connector configration of its consoles through 768eaf99c74SChris Wilson * use of the video= parameter. This function parses that option and 769eaf99c74SChris Wilson * extracts the user's specified mode (or enable/disable status) for a 770eaf99c74SChris Wilson * particular connector. This is typically only used during the early fbdev 771eaf99c74SChris Wilson * setup. 772eaf99c74SChris Wilson */ 773eaf99c74SChris Wilson static void drm_connector_get_cmdline_mode(struct drm_connector *connector) 774eaf99c74SChris Wilson { 775eaf99c74SChris Wilson struct drm_cmdline_mode *mode = &connector->cmdline_mode; 776eaf99c74SChris Wilson char *option = NULL; 777eaf99c74SChris Wilson 778eaf99c74SChris Wilson if (fb_get_options(connector->name, &option)) 779eaf99c74SChris Wilson return; 780eaf99c74SChris Wilson 781eaf99c74SChris Wilson if (!drm_mode_parse_command_line_for_connector(option, 782eaf99c74SChris Wilson connector, 783eaf99c74SChris Wilson mode)) 784eaf99c74SChris Wilson return; 785eaf99c74SChris Wilson 786eaf99c74SChris Wilson if (mode->force) { 787eaf99c74SChris Wilson const char *s; 788eaf99c74SChris Wilson 789eaf99c74SChris Wilson switch (mode->force) { 790eaf99c74SChris Wilson case DRM_FORCE_OFF: 791eaf99c74SChris Wilson s = "OFF"; 792eaf99c74SChris Wilson break; 793eaf99c74SChris Wilson case DRM_FORCE_ON_DIGITAL: 794eaf99c74SChris Wilson s = "ON - dig"; 795eaf99c74SChris Wilson break; 796eaf99c74SChris Wilson default: 797eaf99c74SChris Wilson case DRM_FORCE_ON: 798eaf99c74SChris Wilson s = "ON"; 799eaf99c74SChris Wilson break; 800eaf99c74SChris Wilson } 801eaf99c74SChris Wilson 802eaf99c74SChris Wilson DRM_INFO("forcing %s connector %s\n", connector->name, s); 803eaf99c74SChris Wilson connector->force = mode->force; 804eaf99c74SChris Wilson } 805eaf99c74SChris Wilson 806eaf99c74SChris Wilson DRM_DEBUG_KMS("cmdline mode for connector %s %dx%d@%dHz%s%s%s\n", 807eaf99c74SChris Wilson connector->name, 808eaf99c74SChris Wilson mode->xres, mode->yres, 809eaf99c74SChris Wilson mode->refresh_specified ? mode->refresh : 60, 810eaf99c74SChris Wilson mode->rb ? " reduced blanking" : "", 811eaf99c74SChris Wilson mode->margins ? " with margins" : "", 812eaf99c74SChris Wilson mode->interlace ? " interlaced" : ""); 813eaf99c74SChris Wilson } 814eaf99c74SChris Wilson 815eaf99c74SChris Wilson /** 816f453ba04SDave Airlie * drm_connector_init - Init a preallocated connector 817f453ba04SDave Airlie * @dev: DRM device 818f453ba04SDave Airlie * @connector: the connector to init 819f453ba04SDave Airlie * @funcs: callbacks for this connector 820065a50edSDaniel Vetter * @connector_type: user visible type of the connector 821f453ba04SDave Airlie * 822f453ba04SDave Airlie * Initialises a preallocated connector. Connectors should be 823f453ba04SDave Airlie * subclassed as part of driver connector objects. 8246bfc56aaSVille Syrjälä * 825c8e32cc1SDaniel Vetter * Returns: 8266bfc56aaSVille Syrjälä * Zero on success, error code on failure. 827f453ba04SDave Airlie */ 8286bfc56aaSVille Syrjälä int drm_connector_init(struct drm_device *dev, 829f453ba04SDave Airlie struct drm_connector *connector, 830f453ba04SDave Airlie const struct drm_connector_funcs *funcs, 831f453ba04SDave Airlie int connector_type) 832f453ba04SDave Airlie { 8336bfc56aaSVille Syrjälä int ret; 834b21e3afeSIlia Mirkin struct ida *connector_ida = 835b21e3afeSIlia Mirkin &drm_connector_enum_list[connector_type].ida; 8366bfc56aaSVille Syrjälä 83784849903SDaniel Vetter drm_modeset_lock_all(dev); 838f453ba04SDave Airlie 8392ee39452SDave Airlie ret = drm_mode_object_get_reg(dev, &connector->base, DRM_MODE_OBJECT_CONNECTOR, false); 8406bfc56aaSVille Syrjälä if (ret) 8412abdd313SJani Nikula goto out_unlock; 8426bfc56aaSVille Syrjälä 8437e3bdf4aSPaulo Zanoni connector->base.properties = &connector->properties; 844f453ba04SDave Airlie connector->dev = dev; 845f453ba04SDave Airlie connector->funcs = funcs; 846f453ba04SDave Airlie connector->connector_type = connector_type; 847f453ba04SDave Airlie connector->connector_type_id = 848b21e3afeSIlia Mirkin ida_simple_get(connector_ida, 1, 0, GFP_KERNEL); 849b21e3afeSIlia Mirkin if (connector->connector_type_id < 0) { 850b21e3afeSIlia Mirkin ret = connector->connector_type_id; 8512abdd313SJani Nikula goto out_put; 852b21e3afeSIlia Mirkin } 8532abdd313SJani Nikula connector->name = 8542abdd313SJani Nikula kasprintf(GFP_KERNEL, "%s-%d", 8552abdd313SJani Nikula drm_connector_enum_list[connector_type].name, 8562abdd313SJani Nikula connector->connector_type_id); 8572abdd313SJani Nikula if (!connector->name) { 8582abdd313SJani Nikula ret = -ENOMEM; 8592abdd313SJani Nikula goto out_put; 8602abdd313SJani Nikula } 8612abdd313SJani Nikula 862f453ba04SDave Airlie INIT_LIST_HEAD(&connector->probed_modes); 863f453ba04SDave Airlie INIT_LIST_HEAD(&connector->modes); 864f453ba04SDave Airlie connector->edid_blob_ptr = NULL; 8655e2cb2f6SDaniel Vetter connector->status = connector_status_unknown; 866f453ba04SDave Airlie 867eaf99c74SChris Wilson drm_connector_get_cmdline_mode(connector); 868eaf99c74SChris Wilson 869c7eb76f4SDaniel Vetter /* We should add connectors at the end to avoid upsetting the connector 870c7eb76f4SDaniel Vetter * index too much. */ 871f453ba04SDave Airlie list_add_tail(&connector->head, &dev->mode_config.connector_list); 872f453ba04SDave Airlie dev->mode_config.num_connector++; 873f453ba04SDave Airlie 874a7331e5cSThomas Hellstrom if (connector_type != DRM_MODE_CONNECTOR_VIRTUAL) 87558495563SRob Clark drm_object_attach_property(&connector->base, 876a7331e5cSThomas Hellstrom dev->mode_config.edid_property, 877a7331e5cSThomas Hellstrom 0); 878f453ba04SDave Airlie 87958495563SRob Clark drm_object_attach_property(&connector->base, 880f453ba04SDave Airlie dev->mode_config.dpms_property, 0); 881f453ba04SDave Airlie 88230f65707SThomas Wood connector->debugfs_entry = NULL; 88330f65707SThomas Wood 8842abdd313SJani Nikula out_put: 8852abdd313SJani Nikula if (ret) 8862abdd313SJani Nikula drm_mode_object_put(dev, &connector->base); 8872abdd313SJani Nikula 8882abdd313SJani Nikula out_unlock: 88984849903SDaniel Vetter drm_modeset_unlock_all(dev); 8906bfc56aaSVille Syrjälä 8916bfc56aaSVille Syrjälä return ret; 892f453ba04SDave Airlie } 893f453ba04SDave Airlie EXPORT_SYMBOL(drm_connector_init); 894f453ba04SDave Airlie 895f453ba04SDave Airlie /** 896f453ba04SDave Airlie * drm_connector_cleanup - cleans up an initialised connector 897f453ba04SDave Airlie * @connector: connector to cleanup 898f453ba04SDave Airlie * 899f453ba04SDave Airlie * Cleans up the connector but doesn't free the object. 900f453ba04SDave Airlie */ 901f453ba04SDave Airlie void drm_connector_cleanup(struct drm_connector *connector) 902f453ba04SDave Airlie { 903f453ba04SDave Airlie struct drm_device *dev = connector->dev; 904f453ba04SDave Airlie struct drm_display_mode *mode, *t; 905f453ba04SDave Airlie 906f453ba04SDave Airlie list_for_each_entry_safe(mode, t, &connector->probed_modes, head) 907f453ba04SDave Airlie drm_mode_remove(connector, mode); 908f453ba04SDave Airlie 909f453ba04SDave Airlie list_for_each_entry_safe(mode, t, &connector->modes, head) 910f453ba04SDave Airlie drm_mode_remove(connector, mode); 911f453ba04SDave Airlie 912b21e3afeSIlia Mirkin ida_remove(&drm_connector_enum_list[connector->connector_type].ida, 913b21e3afeSIlia Mirkin connector->connector_type_id); 914b21e3afeSIlia Mirkin 915f453ba04SDave Airlie drm_mode_object_put(dev, &connector->base); 9162abdd313SJani Nikula kfree(connector->name); 9172abdd313SJani Nikula connector->name = NULL; 918f453ba04SDave Airlie list_del(&connector->head); 9196380c509SJoonyoung Shim dev->mode_config.num_connector--; 9203009c037SThierry Reding 9213009c037SThierry Reding WARN_ON(connector->state && !connector->funcs->atomic_destroy_state); 9223009c037SThierry Reding if (connector->state && connector->funcs->atomic_destroy_state) 9233009c037SThierry Reding connector->funcs->atomic_destroy_state(connector, 9243009c037SThierry Reding connector->state); 925a18c0af1SThierry Reding 926a18c0af1SThierry Reding memset(connector, 0, sizeof(*connector)); 927f453ba04SDave Airlie } 928f453ba04SDave Airlie EXPORT_SYMBOL(drm_connector_cleanup); 929f453ba04SDave Airlie 930c8e32cc1SDaniel Vetter /** 93110f637bfSDaniel Vetter * drm_connector_index - find the index of a registered connector 93210f637bfSDaniel Vetter * @connector: connector to find index for 93310f637bfSDaniel Vetter * 93410f637bfSDaniel Vetter * Given a registered connector, return the index of that connector within a DRM 93510f637bfSDaniel Vetter * device's list of connectors. 93610f637bfSDaniel Vetter */ 93710f637bfSDaniel Vetter unsigned int drm_connector_index(struct drm_connector *connector) 93810f637bfSDaniel Vetter { 93910f637bfSDaniel Vetter unsigned int index = 0; 94010f637bfSDaniel Vetter struct drm_connector *tmp; 941c7eb76f4SDaniel Vetter struct drm_mode_config *config = &connector->dev->mode_config; 942c7eb76f4SDaniel Vetter 943c7eb76f4SDaniel Vetter WARN_ON(!drm_modeset_is_locked(&config->connection_mutex)); 94410f637bfSDaniel Vetter 94510f637bfSDaniel Vetter list_for_each_entry(tmp, &connector->dev->mode_config.connector_list, head) { 94610f637bfSDaniel Vetter if (tmp == connector) 94710f637bfSDaniel Vetter return index; 94810f637bfSDaniel Vetter 94910f637bfSDaniel Vetter index++; 95010f637bfSDaniel Vetter } 95110f637bfSDaniel Vetter 95210f637bfSDaniel Vetter BUG(); 95310f637bfSDaniel Vetter } 95410f637bfSDaniel Vetter EXPORT_SYMBOL(drm_connector_index); 95510f637bfSDaniel Vetter 95610f637bfSDaniel Vetter /** 95734ea3d38SThomas Wood * drm_connector_register - register a connector 95834ea3d38SThomas Wood * @connector: the connector to register 95934ea3d38SThomas Wood * 96034ea3d38SThomas Wood * Register userspace interfaces for a connector 96134ea3d38SThomas Wood * 96234ea3d38SThomas Wood * Returns: 96334ea3d38SThomas Wood * Zero on success, error code on failure. 96434ea3d38SThomas Wood */ 96534ea3d38SThomas Wood int drm_connector_register(struct drm_connector *connector) 96634ea3d38SThomas Wood { 96730f65707SThomas Wood int ret; 96830f65707SThomas Wood 9692ee39452SDave Airlie drm_mode_object_register(connector->dev, &connector->base); 9702ee39452SDave Airlie 97130f65707SThomas Wood ret = drm_sysfs_connector_add(connector); 97230f65707SThomas Wood if (ret) 97330f65707SThomas Wood return ret; 97430f65707SThomas Wood 97530f65707SThomas Wood ret = drm_debugfs_connector_add(connector); 97630f65707SThomas Wood if (ret) { 97730f65707SThomas Wood drm_sysfs_connector_remove(connector); 97830f65707SThomas Wood return ret; 97930f65707SThomas Wood } 98030f65707SThomas Wood 98130f65707SThomas Wood return 0; 98234ea3d38SThomas Wood } 98334ea3d38SThomas Wood EXPORT_SYMBOL(drm_connector_register); 98434ea3d38SThomas Wood 98534ea3d38SThomas Wood /** 98634ea3d38SThomas Wood * drm_connector_unregister - unregister a connector 98734ea3d38SThomas Wood * @connector: the connector to unregister 98834ea3d38SThomas Wood * 98934ea3d38SThomas Wood * Unregister userspace interfaces for a connector 99034ea3d38SThomas Wood */ 99134ea3d38SThomas Wood void drm_connector_unregister(struct drm_connector *connector) 99234ea3d38SThomas Wood { 99334ea3d38SThomas Wood drm_sysfs_connector_remove(connector); 99430f65707SThomas Wood drm_debugfs_connector_remove(connector); 99534ea3d38SThomas Wood } 99634ea3d38SThomas Wood EXPORT_SYMBOL(drm_connector_unregister); 99734ea3d38SThomas Wood 99834ea3d38SThomas Wood 99934ea3d38SThomas Wood /** 1000c8e32cc1SDaniel Vetter * drm_connector_unplug_all - unregister connector userspace interfaces 1001c8e32cc1SDaniel Vetter * @dev: drm device 1002c8e32cc1SDaniel Vetter * 1003c8e32cc1SDaniel Vetter * This function unregisters all connector userspace interfaces in sysfs. Should 1004c8e32cc1SDaniel Vetter * be call when the device is disconnected, e.g. from an usb driver's 1005c8e32cc1SDaniel Vetter * ->disconnect callback. 1006c8e32cc1SDaniel Vetter */ 1007cbc7e221SDave Airlie void drm_connector_unplug_all(struct drm_device *dev) 1008cbc7e221SDave Airlie { 1009cbc7e221SDave Airlie struct drm_connector *connector; 1010cbc7e221SDave Airlie 1011cbc7e221SDave Airlie /* taking the mode config mutex ends up in a clash with sysfs */ 1012cbc7e221SDave Airlie list_for_each_entry(connector, &dev->mode_config.connector_list, head) 101334ea3d38SThomas Wood drm_connector_unregister(connector); 1014cbc7e221SDave Airlie 1015cbc7e221SDave Airlie } 1016cbc7e221SDave Airlie EXPORT_SYMBOL(drm_connector_unplug_all); 1017cbc7e221SDave Airlie 1018c8e32cc1SDaniel Vetter /** 1019c8e32cc1SDaniel Vetter * drm_bridge_init - initialize a drm transcoder/bridge 1020c8e32cc1SDaniel Vetter * @dev: drm device 1021c8e32cc1SDaniel Vetter * @bridge: transcoder/bridge to set up 1022c8e32cc1SDaniel Vetter * @funcs: bridge function table 1023c8e32cc1SDaniel Vetter * 1024c8e32cc1SDaniel Vetter * Initialises a preallocated bridge. Bridges should be 1025c8e32cc1SDaniel Vetter * subclassed as part of driver connector objects. 1026c8e32cc1SDaniel Vetter * 1027c8e32cc1SDaniel Vetter * Returns: 1028c8e32cc1SDaniel Vetter * Zero on success, error code on failure. 1029c8e32cc1SDaniel Vetter */ 10303b336ec4SSean Paul int drm_bridge_init(struct drm_device *dev, struct drm_bridge *bridge, 10313b336ec4SSean Paul const struct drm_bridge_funcs *funcs) 10323b336ec4SSean Paul { 10333b336ec4SSean Paul int ret; 10343b336ec4SSean Paul 10353b336ec4SSean Paul drm_modeset_lock_all(dev); 10363b336ec4SSean Paul 10373b336ec4SSean Paul ret = drm_mode_object_get(dev, &bridge->base, DRM_MODE_OBJECT_BRIDGE); 10383b336ec4SSean Paul if (ret) 10393b336ec4SSean Paul goto out; 10403b336ec4SSean Paul 10413b336ec4SSean Paul bridge->dev = dev; 10423b336ec4SSean Paul bridge->funcs = funcs; 10433b336ec4SSean Paul 10443b336ec4SSean Paul list_add_tail(&bridge->head, &dev->mode_config.bridge_list); 10453b336ec4SSean Paul dev->mode_config.num_bridge++; 10463b336ec4SSean Paul 10473b336ec4SSean Paul out: 10483b336ec4SSean Paul drm_modeset_unlock_all(dev); 10493b336ec4SSean Paul return ret; 10503b336ec4SSean Paul } 10513b336ec4SSean Paul EXPORT_SYMBOL(drm_bridge_init); 10523b336ec4SSean Paul 1053c8e32cc1SDaniel Vetter /** 1054c8e32cc1SDaniel Vetter * drm_bridge_cleanup - cleans up an initialised bridge 1055c8e32cc1SDaniel Vetter * @bridge: bridge to cleanup 1056c8e32cc1SDaniel Vetter * 1057c8e32cc1SDaniel Vetter * Cleans up the bridge but doesn't free the object. 1058c8e32cc1SDaniel Vetter */ 10593b336ec4SSean Paul void drm_bridge_cleanup(struct drm_bridge *bridge) 10603b336ec4SSean Paul { 10613b336ec4SSean Paul struct drm_device *dev = bridge->dev; 10623b336ec4SSean Paul 10633b336ec4SSean Paul drm_modeset_lock_all(dev); 10643b336ec4SSean Paul drm_mode_object_put(dev, &bridge->base); 10653b336ec4SSean Paul list_del(&bridge->head); 10663b336ec4SSean Paul dev->mode_config.num_bridge--; 10673b336ec4SSean Paul drm_modeset_unlock_all(dev); 1068a18c0af1SThierry Reding 1069a18c0af1SThierry Reding memset(bridge, 0, sizeof(*bridge)); 10703b336ec4SSean Paul } 10713b336ec4SSean Paul EXPORT_SYMBOL(drm_bridge_cleanup); 10723b336ec4SSean Paul 1073c8e32cc1SDaniel Vetter /** 1074c8e32cc1SDaniel Vetter * drm_encoder_init - Init a preallocated encoder 1075c8e32cc1SDaniel Vetter * @dev: drm device 1076c8e32cc1SDaniel Vetter * @encoder: the encoder to init 1077c8e32cc1SDaniel Vetter * @funcs: callbacks for this encoder 1078c8e32cc1SDaniel Vetter * @encoder_type: user visible type of the encoder 1079c8e32cc1SDaniel Vetter * 1080c8e32cc1SDaniel Vetter * Initialises a preallocated encoder. Encoder should be 1081c8e32cc1SDaniel Vetter * subclassed as part of driver encoder objects. 1082c8e32cc1SDaniel Vetter * 1083c8e32cc1SDaniel Vetter * Returns: 1084c8e32cc1SDaniel Vetter * Zero on success, error code on failure. 1085c8e32cc1SDaniel Vetter */ 10866bfc56aaSVille Syrjälä int drm_encoder_init(struct drm_device *dev, 1087f453ba04SDave Airlie struct drm_encoder *encoder, 1088f453ba04SDave Airlie const struct drm_encoder_funcs *funcs, 1089f453ba04SDave Airlie int encoder_type) 1090f453ba04SDave Airlie { 10916bfc56aaSVille Syrjälä int ret; 10926bfc56aaSVille Syrjälä 109384849903SDaniel Vetter drm_modeset_lock_all(dev); 1094f453ba04SDave Airlie 10956bfc56aaSVille Syrjälä ret = drm_mode_object_get(dev, &encoder->base, DRM_MODE_OBJECT_ENCODER); 10966bfc56aaSVille Syrjälä if (ret) 1097e5748946SJani Nikula goto out_unlock; 1098f453ba04SDave Airlie 10996bfc56aaSVille Syrjälä encoder->dev = dev; 1100f453ba04SDave Airlie encoder->encoder_type = encoder_type; 1101f453ba04SDave Airlie encoder->funcs = funcs; 1102e5748946SJani Nikula encoder->name = kasprintf(GFP_KERNEL, "%s-%d", 1103e5748946SJani Nikula drm_encoder_enum_list[encoder_type].name, 1104e5748946SJani Nikula encoder->base.id); 1105e5748946SJani Nikula if (!encoder->name) { 1106e5748946SJani Nikula ret = -ENOMEM; 1107e5748946SJani Nikula goto out_put; 1108e5748946SJani Nikula } 1109f453ba04SDave Airlie 1110f453ba04SDave Airlie list_add_tail(&encoder->head, &dev->mode_config.encoder_list); 1111f453ba04SDave Airlie dev->mode_config.num_encoder++; 1112f453ba04SDave Airlie 1113e5748946SJani Nikula out_put: 1114e5748946SJani Nikula if (ret) 1115e5748946SJani Nikula drm_mode_object_put(dev, &encoder->base); 1116e5748946SJani Nikula 1117e5748946SJani Nikula out_unlock: 111884849903SDaniel Vetter drm_modeset_unlock_all(dev); 11196bfc56aaSVille Syrjälä 11206bfc56aaSVille Syrjälä return ret; 1121f453ba04SDave Airlie } 1122f453ba04SDave Airlie EXPORT_SYMBOL(drm_encoder_init); 1123f453ba04SDave Airlie 1124c8e32cc1SDaniel Vetter /** 1125c8e32cc1SDaniel Vetter * drm_encoder_cleanup - cleans up an initialised encoder 1126c8e32cc1SDaniel Vetter * @encoder: encoder to cleanup 1127c8e32cc1SDaniel Vetter * 1128c8e32cc1SDaniel Vetter * Cleans up the encoder but doesn't free the object. 1129c8e32cc1SDaniel Vetter */ 1130f453ba04SDave Airlie void drm_encoder_cleanup(struct drm_encoder *encoder) 1131f453ba04SDave Airlie { 1132f453ba04SDave Airlie struct drm_device *dev = encoder->dev; 11334dfd909fSThierry Reding 113484849903SDaniel Vetter drm_modeset_lock_all(dev); 1135f453ba04SDave Airlie drm_mode_object_put(dev, &encoder->base); 1136e5748946SJani Nikula kfree(encoder->name); 1137f453ba04SDave Airlie list_del(&encoder->head); 11386380c509SJoonyoung Shim dev->mode_config.num_encoder--; 113984849903SDaniel Vetter drm_modeset_unlock_all(dev); 1140a18c0af1SThierry Reding 1141a18c0af1SThierry Reding memset(encoder, 0, sizeof(*encoder)); 1142f453ba04SDave Airlie } 1143f453ba04SDave Airlie EXPORT_SYMBOL(drm_encoder_cleanup); 1144f453ba04SDave Airlie 114535f2c3aeSVille Syrjälä /** 1146dc415ff9SMatt Roper * drm_universal_plane_init - Initialize a new universal plane object 114735f2c3aeSVille Syrjälä * @dev: DRM device 114835f2c3aeSVille Syrjälä * @plane: plane object to init 114935f2c3aeSVille Syrjälä * @possible_crtcs: bitmask of possible CRTCs 115035f2c3aeSVille Syrjälä * @funcs: callbacks for the new plane 115135f2c3aeSVille Syrjälä * @formats: array of supported formats (%DRM_FORMAT_*) 115235f2c3aeSVille Syrjälä * @format_count: number of elements in @formats 1153dc415ff9SMatt Roper * @type: type of plane (overlay, primary, cursor) 115435f2c3aeSVille Syrjälä * 1155dc415ff9SMatt Roper * Initializes a plane object of type @type. 115635f2c3aeSVille Syrjälä * 1157c8e32cc1SDaniel Vetter * Returns: 115835f2c3aeSVille Syrjälä * Zero on success, error code on failure. 115935f2c3aeSVille Syrjälä */ 1160dc415ff9SMatt Roper int drm_universal_plane_init(struct drm_device *dev, struct drm_plane *plane, 11618cf5c917SJesse Barnes unsigned long possible_crtcs, 11628cf5c917SJesse Barnes const struct drm_plane_funcs *funcs, 11630a7eb243SRob Clark const uint32_t *formats, uint32_t format_count, 1164dc415ff9SMatt Roper enum drm_plane_type type) 11658cf5c917SJesse Barnes { 11666bfc56aaSVille Syrjälä int ret; 11676bfc56aaSVille Syrjälä 11686bfc56aaSVille Syrjälä ret = drm_mode_object_get(dev, &plane->base, DRM_MODE_OBJECT_PLANE); 11696bfc56aaSVille Syrjälä if (ret) 1170baf698b0SDaniel Vetter return ret; 11716bfc56aaSVille Syrjälä 11724d02e2deSDaniel Vetter drm_modeset_lock_init(&plane->mutex); 11734d02e2deSDaniel Vetter 11744d93914aSRob Clark plane->base.properties = &plane->properties; 11758cf5c917SJesse Barnes plane->dev = dev; 11768cf5c917SJesse Barnes plane->funcs = funcs; 11772f6c5389SThierry Reding plane->format_types = kmalloc_array(format_count, sizeof(uint32_t), 11788cf5c917SJesse Barnes GFP_KERNEL); 11798cf5c917SJesse Barnes if (!plane->format_types) { 11808cf5c917SJesse Barnes DRM_DEBUG_KMS("out of memory when allocating plane\n"); 11818cf5c917SJesse Barnes drm_mode_object_put(dev, &plane->base); 1182baf698b0SDaniel Vetter return -ENOMEM; 11838cf5c917SJesse Barnes } 11848cf5c917SJesse Barnes 1185308e5bcbSJesse Barnes memcpy(plane->format_types, formats, format_count * sizeof(uint32_t)); 11868cf5c917SJesse Barnes plane->format_count = format_count; 11878cf5c917SJesse Barnes plane->possible_crtcs = possible_crtcs; 1188dc415ff9SMatt Roper plane->type = type; 11898cf5c917SJesse Barnes 11908cf5c917SJesse Barnes list_add_tail(&plane->head, &dev->mode_config.plane_list); 1191e27dde3eSMatt Roper dev->mode_config.num_total_plane++; 1192e27dde3eSMatt Roper if (plane->type == DRM_PLANE_TYPE_OVERLAY) 1193e27dde3eSMatt Roper dev->mode_config.num_overlay_plane++; 11948cf5c917SJesse Barnes 11959922ab5aSRob Clark drm_object_attach_property(&plane->base, 11969922ab5aSRob Clark dev->mode_config.plane_type_property, 11979922ab5aSRob Clark plane->type); 11989922ab5aSRob Clark 1199baf698b0SDaniel Vetter return 0; 12008cf5c917SJesse Barnes } 1201dc415ff9SMatt Roper EXPORT_SYMBOL(drm_universal_plane_init); 1202dc415ff9SMatt Roper 1203dc415ff9SMatt Roper /** 1204dc415ff9SMatt Roper * drm_plane_init - Initialize a legacy plane 1205dc415ff9SMatt Roper * @dev: DRM device 1206dc415ff9SMatt Roper * @plane: plane object to init 1207dc415ff9SMatt Roper * @possible_crtcs: bitmask of possible CRTCs 1208dc415ff9SMatt Roper * @funcs: callbacks for the new plane 1209dc415ff9SMatt Roper * @formats: array of supported formats (%DRM_FORMAT_*) 1210dc415ff9SMatt Roper * @format_count: number of elements in @formats 1211dc415ff9SMatt Roper * @is_primary: plane type (primary vs overlay) 1212dc415ff9SMatt Roper * 1213dc415ff9SMatt Roper * Legacy API to initialize a DRM plane. 1214dc415ff9SMatt Roper * 1215dc415ff9SMatt Roper * New drivers should call drm_universal_plane_init() instead. 1216dc415ff9SMatt Roper * 1217dc415ff9SMatt Roper * Returns: 1218dc415ff9SMatt Roper * Zero on success, error code on failure. 1219dc415ff9SMatt Roper */ 1220dc415ff9SMatt Roper int drm_plane_init(struct drm_device *dev, struct drm_plane *plane, 1221dc415ff9SMatt Roper unsigned long possible_crtcs, 1222dc415ff9SMatt Roper const struct drm_plane_funcs *funcs, 1223dc415ff9SMatt Roper const uint32_t *formats, uint32_t format_count, 1224dc415ff9SMatt Roper bool is_primary) 1225dc415ff9SMatt Roper { 1226dc415ff9SMatt Roper enum drm_plane_type type; 1227dc415ff9SMatt Roper 1228dc415ff9SMatt Roper type = is_primary ? DRM_PLANE_TYPE_PRIMARY : DRM_PLANE_TYPE_OVERLAY; 1229dc415ff9SMatt Roper return drm_universal_plane_init(dev, plane, possible_crtcs, funcs, 1230dc415ff9SMatt Roper formats, format_count, type); 1231dc415ff9SMatt Roper } 12328cf5c917SJesse Barnes EXPORT_SYMBOL(drm_plane_init); 12338cf5c917SJesse Barnes 123435f2c3aeSVille Syrjälä /** 123535f2c3aeSVille Syrjälä * drm_plane_cleanup - Clean up the core plane usage 123635f2c3aeSVille Syrjälä * @plane: plane to cleanup 123735f2c3aeSVille Syrjälä * 123835f2c3aeSVille Syrjälä * This function cleans up @plane and removes it from the DRM mode setting 123935f2c3aeSVille Syrjälä * core. Note that the function does *not* free the plane structure itself, 124035f2c3aeSVille Syrjälä * this is the responsibility of the caller. 124135f2c3aeSVille Syrjälä */ 12428cf5c917SJesse Barnes void drm_plane_cleanup(struct drm_plane *plane) 12438cf5c917SJesse Barnes { 12448cf5c917SJesse Barnes struct drm_device *dev = plane->dev; 12458cf5c917SJesse Barnes 124684849903SDaniel Vetter drm_modeset_lock_all(dev); 12478cf5c917SJesse Barnes kfree(plane->format_types); 12488cf5c917SJesse Barnes drm_mode_object_put(dev, &plane->base); 1249dc415ff9SMatt Roper 1250dc415ff9SMatt Roper BUG_ON(list_empty(&plane->head)); 1251dc415ff9SMatt Roper 12528cf5c917SJesse Barnes list_del(&plane->head); 1253e27dde3eSMatt Roper dev->mode_config.num_total_plane--; 1254e27dde3eSMatt Roper if (plane->type == DRM_PLANE_TYPE_OVERLAY) 1255e27dde3eSMatt Roper dev->mode_config.num_overlay_plane--; 125684849903SDaniel Vetter drm_modeset_unlock_all(dev); 12573009c037SThierry Reding 12583009c037SThierry Reding WARN_ON(plane->state && !plane->funcs->atomic_destroy_state); 12593009c037SThierry Reding if (plane->state && plane->funcs->atomic_destroy_state) 12603009c037SThierry Reding plane->funcs->atomic_destroy_state(plane, plane->state); 1261a18c0af1SThierry Reding 1262a18c0af1SThierry Reding memset(plane, 0, sizeof(*plane)); 12638cf5c917SJesse Barnes } 12648cf5c917SJesse Barnes EXPORT_SYMBOL(drm_plane_cleanup); 12658cf5c917SJesse Barnes 126635f2c3aeSVille Syrjälä /** 126710f637bfSDaniel Vetter * drm_plane_index - find the index of a registered plane 126810f637bfSDaniel Vetter * @plane: plane to find index for 126910f637bfSDaniel Vetter * 127010f637bfSDaniel Vetter * Given a registered plane, return the index of that CRTC within a DRM 127110f637bfSDaniel Vetter * device's list of planes. 127210f637bfSDaniel Vetter */ 127310f637bfSDaniel Vetter unsigned int drm_plane_index(struct drm_plane *plane) 127410f637bfSDaniel Vetter { 127510f637bfSDaniel Vetter unsigned int index = 0; 127610f637bfSDaniel Vetter struct drm_plane *tmp; 127710f637bfSDaniel Vetter 127810f637bfSDaniel Vetter list_for_each_entry(tmp, &plane->dev->mode_config.plane_list, head) { 127910f637bfSDaniel Vetter if (tmp == plane) 128010f637bfSDaniel Vetter return index; 128110f637bfSDaniel Vetter 128210f637bfSDaniel Vetter index++; 128310f637bfSDaniel Vetter } 128410f637bfSDaniel Vetter 128510f637bfSDaniel Vetter BUG(); 128610f637bfSDaniel Vetter } 128710f637bfSDaniel Vetter EXPORT_SYMBOL(drm_plane_index); 128810f637bfSDaniel Vetter 128910f637bfSDaniel Vetter /** 129035f2c3aeSVille Syrjälä * drm_plane_force_disable - Forcibly disable a plane 129135f2c3aeSVille Syrjälä * @plane: plane to disable 129235f2c3aeSVille Syrjälä * 129335f2c3aeSVille Syrjälä * Forces the plane to be disabled. 129435f2c3aeSVille Syrjälä * 129535f2c3aeSVille Syrjälä * Used when the plane's current framebuffer is destroyed, 129635f2c3aeSVille Syrjälä * and when restoring fbdev mode. 129735f2c3aeSVille Syrjälä */ 12989125e618SVille Syrjälä void drm_plane_force_disable(struct drm_plane *plane) 12999125e618SVille Syrjälä { 13009125e618SVille Syrjälä int ret; 13019125e618SVille Syrjälä 13023d30a59bSDaniel Vetter if (!plane->fb) 13039125e618SVille Syrjälä return; 13049125e618SVille Syrjälä 13053d30a59bSDaniel Vetter plane->old_fb = plane->fb; 13069125e618SVille Syrjälä ret = plane->funcs->disable_plane(plane); 1307731cce48SDaniel Vetter if (ret) { 13089125e618SVille Syrjälä DRM_ERROR("failed to disable plane with busy fb\n"); 13093d30a59bSDaniel Vetter plane->old_fb = NULL; 1310731cce48SDaniel Vetter return; 1311731cce48SDaniel Vetter } 13129125e618SVille Syrjälä /* disconnect the plane from the fb and crtc: */ 13133d30a59bSDaniel Vetter __drm_framebuffer_unreference(plane->old_fb); 13143d30a59bSDaniel Vetter plane->old_fb = NULL; 13159125e618SVille Syrjälä plane->fb = NULL; 13169125e618SVille Syrjälä plane->crtc = NULL; 13179125e618SVille Syrjälä } 13189125e618SVille Syrjälä EXPORT_SYMBOL(drm_plane_force_disable); 13199125e618SVille Syrjälä 1320f453ba04SDave Airlie static int drm_mode_create_standard_connector_properties(struct drm_device *dev) 1321f453ba04SDave Airlie { 1322f453ba04SDave Airlie struct drm_property *edid; 1323f453ba04SDave Airlie struct drm_property *dpms; 132443aba7ebSDave Airlie struct drm_property *dev_path; 1325f453ba04SDave Airlie 1326f453ba04SDave Airlie /* 1327f453ba04SDave Airlie * Standard properties (apply to all connectors) 1328f453ba04SDave Airlie */ 1329f453ba04SDave Airlie edid = drm_property_create(dev, DRM_MODE_PROP_BLOB | 1330f453ba04SDave Airlie DRM_MODE_PROP_IMMUTABLE, 1331f453ba04SDave Airlie "EDID", 0); 1332f453ba04SDave Airlie dev->mode_config.edid_property = edid; 1333f453ba04SDave Airlie 13344a67d391SSascha Hauer dpms = drm_property_create_enum(dev, 0, 13354a67d391SSascha Hauer "DPMS", drm_dpms_enum_list, 13364a67d391SSascha Hauer ARRAY_SIZE(drm_dpms_enum_list)); 1337f453ba04SDave Airlie dev->mode_config.dpms_property = dpms; 1338f453ba04SDave Airlie 133943aba7ebSDave Airlie dev_path = drm_property_create(dev, 134043aba7ebSDave Airlie DRM_MODE_PROP_BLOB | 134143aba7ebSDave Airlie DRM_MODE_PROP_IMMUTABLE, 134243aba7ebSDave Airlie "PATH", 0); 134343aba7ebSDave Airlie dev->mode_config.path_property = dev_path; 134443aba7ebSDave Airlie 1345f453ba04SDave Airlie return 0; 1346f453ba04SDave Airlie } 1347f453ba04SDave Airlie 13489922ab5aSRob Clark static int drm_mode_create_standard_plane_properties(struct drm_device *dev) 13499922ab5aSRob Clark { 13509922ab5aSRob Clark struct drm_property *type; 13519922ab5aSRob Clark 13529922ab5aSRob Clark /* 13539922ab5aSRob Clark * Standard properties (apply to all planes) 13549922ab5aSRob Clark */ 13559922ab5aSRob Clark type = drm_property_create_enum(dev, DRM_MODE_PROP_IMMUTABLE, 13569922ab5aSRob Clark "type", drm_plane_type_enum_list, 13579922ab5aSRob Clark ARRAY_SIZE(drm_plane_type_enum_list)); 13589922ab5aSRob Clark dev->mode_config.plane_type_property = type; 13599922ab5aSRob Clark 13609922ab5aSRob Clark return 0; 13619922ab5aSRob Clark } 13629922ab5aSRob Clark 1363f453ba04SDave Airlie /** 1364f453ba04SDave Airlie * drm_mode_create_dvi_i_properties - create DVI-I specific connector properties 1365f453ba04SDave Airlie * @dev: DRM device 1366f453ba04SDave Airlie * 1367f453ba04SDave Airlie * Called by a driver the first time a DVI-I connector is made. 1368f453ba04SDave Airlie */ 1369f453ba04SDave Airlie int drm_mode_create_dvi_i_properties(struct drm_device *dev) 1370f453ba04SDave Airlie { 1371f453ba04SDave Airlie struct drm_property *dvi_i_selector; 1372f453ba04SDave Airlie struct drm_property *dvi_i_subconnector; 1373f453ba04SDave Airlie 1374f453ba04SDave Airlie if (dev->mode_config.dvi_i_select_subconnector_property) 1375f453ba04SDave Airlie return 0; 1376f453ba04SDave Airlie 1377f453ba04SDave Airlie dvi_i_selector = 13784a67d391SSascha Hauer drm_property_create_enum(dev, 0, 1379f453ba04SDave Airlie "select subconnector", 13804a67d391SSascha Hauer drm_dvi_i_select_enum_list, 1381f453ba04SDave Airlie ARRAY_SIZE(drm_dvi_i_select_enum_list)); 1382f453ba04SDave Airlie dev->mode_config.dvi_i_select_subconnector_property = dvi_i_selector; 1383f453ba04SDave Airlie 13844a67d391SSascha Hauer dvi_i_subconnector = drm_property_create_enum(dev, DRM_MODE_PROP_IMMUTABLE, 1385f453ba04SDave Airlie "subconnector", 13864a67d391SSascha Hauer drm_dvi_i_subconnector_enum_list, 1387f453ba04SDave Airlie ARRAY_SIZE(drm_dvi_i_subconnector_enum_list)); 1388f453ba04SDave Airlie dev->mode_config.dvi_i_subconnector_property = dvi_i_subconnector; 1389f453ba04SDave Airlie 1390f453ba04SDave Airlie return 0; 1391f453ba04SDave Airlie } 1392f453ba04SDave Airlie EXPORT_SYMBOL(drm_mode_create_dvi_i_properties); 1393f453ba04SDave Airlie 1394f453ba04SDave Airlie /** 1395f453ba04SDave Airlie * drm_create_tv_properties - create TV specific connector properties 1396f453ba04SDave Airlie * @dev: DRM device 1397f453ba04SDave Airlie * @num_modes: number of different TV formats (modes) supported 1398f453ba04SDave Airlie * @modes: array of pointers to strings containing name of each format 1399f453ba04SDave Airlie * 1400f453ba04SDave Airlie * Called by a driver's TV initialization routine, this function creates 1401f453ba04SDave Airlie * the TV specific connector properties for a given device. Caller is 1402f453ba04SDave Airlie * responsible for allocating a list of format names and passing them to 1403f453ba04SDave Airlie * this routine. 1404f453ba04SDave Airlie */ 14052f763312SThierry Reding int drm_mode_create_tv_properties(struct drm_device *dev, 14062f763312SThierry Reding unsigned int num_modes, 1407f453ba04SDave Airlie char *modes[]) 1408f453ba04SDave Airlie { 1409f453ba04SDave Airlie struct drm_property *tv_selector; 1410f453ba04SDave Airlie struct drm_property *tv_subconnector; 14112f763312SThierry Reding unsigned int i; 1412f453ba04SDave Airlie 1413f453ba04SDave Airlie if (dev->mode_config.tv_select_subconnector_property) 1414f453ba04SDave Airlie return 0; 1415f453ba04SDave Airlie 1416f453ba04SDave Airlie /* 1417f453ba04SDave Airlie * Basic connector properties 1418f453ba04SDave Airlie */ 14194a67d391SSascha Hauer tv_selector = drm_property_create_enum(dev, 0, 1420f453ba04SDave Airlie "select subconnector", 14214a67d391SSascha Hauer drm_tv_select_enum_list, 1422f453ba04SDave Airlie ARRAY_SIZE(drm_tv_select_enum_list)); 1423f453ba04SDave Airlie dev->mode_config.tv_select_subconnector_property = tv_selector; 1424f453ba04SDave Airlie 1425f453ba04SDave Airlie tv_subconnector = 14264a67d391SSascha Hauer drm_property_create_enum(dev, DRM_MODE_PROP_IMMUTABLE, 14274a67d391SSascha Hauer "subconnector", 14284a67d391SSascha Hauer drm_tv_subconnector_enum_list, 1429f453ba04SDave Airlie ARRAY_SIZE(drm_tv_subconnector_enum_list)); 1430f453ba04SDave Airlie dev->mode_config.tv_subconnector_property = tv_subconnector; 1431f453ba04SDave Airlie 1432f453ba04SDave Airlie /* 1433f453ba04SDave Airlie * Other, TV specific properties: margins & TV modes. 1434f453ba04SDave Airlie */ 1435f453ba04SDave Airlie dev->mode_config.tv_left_margin_property = 1436d9bc3c02SSascha Hauer drm_property_create_range(dev, 0, "left margin", 0, 100); 1437f453ba04SDave Airlie 1438f453ba04SDave Airlie dev->mode_config.tv_right_margin_property = 1439d9bc3c02SSascha Hauer drm_property_create_range(dev, 0, "right margin", 0, 100); 1440f453ba04SDave Airlie 1441f453ba04SDave Airlie dev->mode_config.tv_top_margin_property = 1442d9bc3c02SSascha Hauer drm_property_create_range(dev, 0, "top margin", 0, 100); 1443f453ba04SDave Airlie 1444f453ba04SDave Airlie dev->mode_config.tv_bottom_margin_property = 1445d9bc3c02SSascha Hauer drm_property_create_range(dev, 0, "bottom margin", 0, 100); 1446f453ba04SDave Airlie 1447f453ba04SDave Airlie dev->mode_config.tv_mode_property = 1448f453ba04SDave Airlie drm_property_create(dev, DRM_MODE_PROP_ENUM, 1449f453ba04SDave Airlie "mode", num_modes); 1450f453ba04SDave Airlie for (i = 0; i < num_modes; i++) 1451f453ba04SDave Airlie drm_property_add_enum(dev->mode_config.tv_mode_property, i, 1452f453ba04SDave Airlie i, modes[i]); 1453f453ba04SDave Airlie 1454b6b7902eSFrancisco Jerez dev->mode_config.tv_brightness_property = 1455d9bc3c02SSascha Hauer drm_property_create_range(dev, 0, "brightness", 0, 100); 1456b6b7902eSFrancisco Jerez 1457b6b7902eSFrancisco Jerez dev->mode_config.tv_contrast_property = 1458d9bc3c02SSascha Hauer drm_property_create_range(dev, 0, "contrast", 0, 100); 1459b6b7902eSFrancisco Jerez 1460b6b7902eSFrancisco Jerez dev->mode_config.tv_flicker_reduction_property = 1461d9bc3c02SSascha Hauer drm_property_create_range(dev, 0, "flicker reduction", 0, 100); 1462b6b7902eSFrancisco Jerez 1463a75f0236SFrancisco Jerez dev->mode_config.tv_overscan_property = 1464d9bc3c02SSascha Hauer drm_property_create_range(dev, 0, "overscan", 0, 100); 1465a75f0236SFrancisco Jerez 1466a75f0236SFrancisco Jerez dev->mode_config.tv_saturation_property = 1467d9bc3c02SSascha Hauer drm_property_create_range(dev, 0, "saturation", 0, 100); 1468a75f0236SFrancisco Jerez 1469a75f0236SFrancisco Jerez dev->mode_config.tv_hue_property = 1470d9bc3c02SSascha Hauer drm_property_create_range(dev, 0, "hue", 0, 100); 1471a75f0236SFrancisco Jerez 1472f453ba04SDave Airlie return 0; 1473f453ba04SDave Airlie } 1474f453ba04SDave Airlie EXPORT_SYMBOL(drm_mode_create_tv_properties); 1475f453ba04SDave Airlie 1476f453ba04SDave Airlie /** 1477f453ba04SDave Airlie * drm_mode_create_scaling_mode_property - create scaling mode property 1478f453ba04SDave Airlie * @dev: DRM device 1479f453ba04SDave Airlie * 1480f453ba04SDave Airlie * Called by a driver the first time it's needed, must be attached to desired 1481f453ba04SDave Airlie * connectors. 1482f453ba04SDave Airlie */ 1483f453ba04SDave Airlie int drm_mode_create_scaling_mode_property(struct drm_device *dev) 1484f453ba04SDave Airlie { 1485f453ba04SDave Airlie struct drm_property *scaling_mode; 1486f453ba04SDave Airlie 1487f453ba04SDave Airlie if (dev->mode_config.scaling_mode_property) 1488f453ba04SDave Airlie return 0; 1489f453ba04SDave Airlie 1490f453ba04SDave Airlie scaling_mode = 14914a67d391SSascha Hauer drm_property_create_enum(dev, 0, "scaling mode", 14924a67d391SSascha Hauer drm_scaling_mode_enum_list, 1493f453ba04SDave Airlie ARRAY_SIZE(drm_scaling_mode_enum_list)); 1494f453ba04SDave Airlie 1495f453ba04SDave Airlie dev->mode_config.scaling_mode_property = scaling_mode; 1496f453ba04SDave Airlie 1497f453ba04SDave Airlie return 0; 1498f453ba04SDave Airlie } 1499f453ba04SDave Airlie EXPORT_SYMBOL(drm_mode_create_scaling_mode_property); 1500f453ba04SDave Airlie 1501f453ba04SDave Airlie /** 1502ff587e45SVandana Kannan * drm_mode_create_aspect_ratio_property - create aspect ratio property 1503ff587e45SVandana Kannan * @dev: DRM device 1504ff587e45SVandana Kannan * 1505ff587e45SVandana Kannan * Called by a driver the first time it's needed, must be attached to desired 1506ff587e45SVandana Kannan * connectors. 1507ff587e45SVandana Kannan * 1508ff587e45SVandana Kannan * Returns: 15091a498633SDaniel Vetter * Zero on success, negative errno on failure. 1510ff587e45SVandana Kannan */ 1511ff587e45SVandana Kannan int drm_mode_create_aspect_ratio_property(struct drm_device *dev) 1512ff587e45SVandana Kannan { 1513ff587e45SVandana Kannan if (dev->mode_config.aspect_ratio_property) 1514ff587e45SVandana Kannan return 0; 1515ff587e45SVandana Kannan 1516ff587e45SVandana Kannan dev->mode_config.aspect_ratio_property = 1517ff587e45SVandana Kannan drm_property_create_enum(dev, 0, "aspect ratio", 1518ff587e45SVandana Kannan drm_aspect_ratio_enum_list, 1519ff587e45SVandana Kannan ARRAY_SIZE(drm_aspect_ratio_enum_list)); 1520ff587e45SVandana Kannan 1521ff587e45SVandana Kannan if (dev->mode_config.aspect_ratio_property == NULL) 1522ff587e45SVandana Kannan return -ENOMEM; 1523ff587e45SVandana Kannan 1524ff587e45SVandana Kannan return 0; 1525ff587e45SVandana Kannan } 1526ff587e45SVandana Kannan EXPORT_SYMBOL(drm_mode_create_aspect_ratio_property); 1527ff587e45SVandana Kannan 1528ff587e45SVandana Kannan /** 1529884840aaSJakob Bornecrantz * drm_mode_create_dirty_property - create dirty property 1530884840aaSJakob Bornecrantz * @dev: DRM device 1531884840aaSJakob Bornecrantz * 1532884840aaSJakob Bornecrantz * Called by a driver the first time it's needed, must be attached to desired 1533884840aaSJakob Bornecrantz * connectors. 1534884840aaSJakob Bornecrantz */ 1535884840aaSJakob Bornecrantz int drm_mode_create_dirty_info_property(struct drm_device *dev) 1536884840aaSJakob Bornecrantz { 1537884840aaSJakob Bornecrantz struct drm_property *dirty_info; 1538884840aaSJakob Bornecrantz 1539884840aaSJakob Bornecrantz if (dev->mode_config.dirty_info_property) 1540884840aaSJakob Bornecrantz return 0; 1541884840aaSJakob Bornecrantz 1542884840aaSJakob Bornecrantz dirty_info = 15434a67d391SSascha Hauer drm_property_create_enum(dev, DRM_MODE_PROP_IMMUTABLE, 1544884840aaSJakob Bornecrantz "dirty", 15454a67d391SSascha Hauer drm_dirty_info_enum_list, 1546884840aaSJakob Bornecrantz ARRAY_SIZE(drm_dirty_info_enum_list)); 1547884840aaSJakob Bornecrantz dev->mode_config.dirty_info_property = dirty_info; 1548884840aaSJakob Bornecrantz 1549884840aaSJakob Bornecrantz return 0; 1550884840aaSJakob Bornecrantz } 1551884840aaSJakob Bornecrantz EXPORT_SYMBOL(drm_mode_create_dirty_info_property); 1552884840aaSJakob Bornecrantz 15535bb2bbf5SDave Airlie /** 15545bb2bbf5SDave Airlie * drm_mode_create_suggested_offset_properties - create suggests offset properties 15555bb2bbf5SDave Airlie * @dev: DRM device 15565bb2bbf5SDave Airlie * 15575bb2bbf5SDave Airlie * Create the the suggested x/y offset property for connectors. 15585bb2bbf5SDave Airlie */ 15595bb2bbf5SDave Airlie int drm_mode_create_suggested_offset_properties(struct drm_device *dev) 15605bb2bbf5SDave Airlie { 15615bb2bbf5SDave Airlie if (dev->mode_config.suggested_x_property && dev->mode_config.suggested_y_property) 15625bb2bbf5SDave Airlie return 0; 15635bb2bbf5SDave Airlie 15645bb2bbf5SDave Airlie dev->mode_config.suggested_x_property = 15655bb2bbf5SDave Airlie drm_property_create_range(dev, DRM_MODE_PROP_IMMUTABLE, "suggested X", 0, 0xffffffff); 15665bb2bbf5SDave Airlie 15675bb2bbf5SDave Airlie dev->mode_config.suggested_y_property = 15685bb2bbf5SDave Airlie drm_property_create_range(dev, DRM_MODE_PROP_IMMUTABLE, "suggested Y", 0, 0xffffffff); 15695bb2bbf5SDave Airlie 15705bb2bbf5SDave Airlie if (dev->mode_config.suggested_x_property == NULL || 15715bb2bbf5SDave Airlie dev->mode_config.suggested_y_property == NULL) 15725bb2bbf5SDave Airlie return -ENOMEM; 15735bb2bbf5SDave Airlie return 0; 15745bb2bbf5SDave Airlie } 15755bb2bbf5SDave Airlie EXPORT_SYMBOL(drm_mode_create_suggested_offset_properties); 15765bb2bbf5SDave Airlie 1577ea9cbb06SVille Syrjälä static int drm_mode_group_init(struct drm_device *dev, struct drm_mode_group *group) 1578f453ba04SDave Airlie { 1579f453ba04SDave Airlie uint32_t total_objects = 0; 1580f453ba04SDave Airlie 1581f453ba04SDave Airlie total_objects += dev->mode_config.num_crtc; 1582f453ba04SDave Airlie total_objects += dev->mode_config.num_connector; 1583f453ba04SDave Airlie total_objects += dev->mode_config.num_encoder; 15843b336ec4SSean Paul total_objects += dev->mode_config.num_bridge; 1585f453ba04SDave Airlie 1586bd3f0ff9SThierry Reding group->id_list = kcalloc(total_objects, sizeof(uint32_t), GFP_KERNEL); 1587f453ba04SDave Airlie if (!group->id_list) 1588f453ba04SDave Airlie return -ENOMEM; 1589f453ba04SDave Airlie 1590f453ba04SDave Airlie group->num_crtcs = 0; 1591f453ba04SDave Airlie group->num_connectors = 0; 1592f453ba04SDave Airlie group->num_encoders = 0; 15933b336ec4SSean Paul group->num_bridges = 0; 1594f453ba04SDave Airlie return 0; 1595f453ba04SDave Airlie } 1596f453ba04SDave Airlie 1597ad222799SDave Airlie void drm_mode_group_destroy(struct drm_mode_group *group) 1598ad222799SDave Airlie { 1599ad222799SDave Airlie kfree(group->id_list); 1600ad222799SDave Airlie group->id_list = NULL; 1601ad222799SDave Airlie } 1602ad222799SDave Airlie 1603c8e32cc1SDaniel Vetter /* 1604c8e32cc1SDaniel Vetter * NOTE: Driver's shouldn't ever call drm_mode_group_init_legacy_group - it is 1605c8e32cc1SDaniel Vetter * the drm core's responsibility to set up mode control groups. 1606c8e32cc1SDaniel Vetter */ 1607f453ba04SDave Airlie int drm_mode_group_init_legacy_group(struct drm_device *dev, 1608f453ba04SDave Airlie struct drm_mode_group *group) 1609f453ba04SDave Airlie { 1610f453ba04SDave Airlie struct drm_crtc *crtc; 1611f453ba04SDave Airlie struct drm_encoder *encoder; 1612f453ba04SDave Airlie struct drm_connector *connector; 16133b336ec4SSean Paul struct drm_bridge *bridge; 1614f453ba04SDave Airlie int ret; 1615f453ba04SDave Airlie 16160cc0b223SThierry Reding ret = drm_mode_group_init(dev, group); 16170cc0b223SThierry Reding if (ret) 1618f453ba04SDave Airlie return ret; 1619f453ba04SDave Airlie 1620f453ba04SDave Airlie list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) 1621f453ba04SDave Airlie group->id_list[group->num_crtcs++] = crtc->base.id; 1622f453ba04SDave Airlie 1623f453ba04SDave Airlie list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) 1624f453ba04SDave Airlie group->id_list[group->num_crtcs + group->num_encoders++] = 1625f453ba04SDave Airlie encoder->base.id; 1626f453ba04SDave Airlie 1627f453ba04SDave Airlie list_for_each_entry(connector, &dev->mode_config.connector_list, head) 1628f453ba04SDave Airlie group->id_list[group->num_crtcs + group->num_encoders + 1629f453ba04SDave Airlie group->num_connectors++] = connector->base.id; 1630f453ba04SDave Airlie 16313b336ec4SSean Paul list_for_each_entry(bridge, &dev->mode_config.bridge_list, head) 16323b336ec4SSean Paul group->id_list[group->num_crtcs + group->num_encoders + 16333b336ec4SSean Paul group->num_connectors + group->num_bridges++] = 16343b336ec4SSean Paul bridge->base.id; 16353b336ec4SSean Paul 1636f453ba04SDave Airlie return 0; 1637f453ba04SDave Airlie } 16389c1dfc55SDave Airlie EXPORT_SYMBOL(drm_mode_group_init_legacy_group); 1639f453ba04SDave Airlie 16402390cd11SDave Airlie void drm_reinit_primary_mode_group(struct drm_device *dev) 16412390cd11SDave Airlie { 16422390cd11SDave Airlie drm_modeset_lock_all(dev); 16432390cd11SDave Airlie drm_mode_group_destroy(&dev->primary->mode_group); 16442390cd11SDave Airlie drm_mode_group_init_legacy_group(dev, &dev->primary->mode_group); 16452390cd11SDave Airlie drm_modeset_unlock_all(dev); 16462390cd11SDave Airlie } 16472390cd11SDave Airlie EXPORT_SYMBOL(drm_reinit_primary_mode_group); 16482390cd11SDave Airlie 1649f453ba04SDave Airlie /** 1650f453ba04SDave Airlie * drm_crtc_convert_to_umode - convert a drm_display_mode into a modeinfo 1651f453ba04SDave Airlie * @out: drm_mode_modeinfo struct to return to the user 1652f453ba04SDave Airlie * @in: drm_display_mode to use 1653f453ba04SDave Airlie * 1654f453ba04SDave Airlie * Convert a drm_display_mode into a drm_mode_modeinfo structure to return to 1655f453ba04SDave Airlie * the user. 1656f453ba04SDave Airlie */ 165793bbf6dbSVille Syrjälä static void drm_crtc_convert_to_umode(struct drm_mode_modeinfo *out, 165893bbf6dbSVille Syrjälä const struct drm_display_mode *in) 1659f453ba04SDave Airlie { 1660e36fae38SVille Syrjälä WARN(in->hdisplay > USHRT_MAX || in->hsync_start > USHRT_MAX || 1661e36fae38SVille Syrjälä in->hsync_end > USHRT_MAX || in->htotal > USHRT_MAX || 1662e36fae38SVille Syrjälä in->hskew > USHRT_MAX || in->vdisplay > USHRT_MAX || 1663e36fae38SVille Syrjälä in->vsync_start > USHRT_MAX || in->vsync_end > USHRT_MAX || 1664e36fae38SVille Syrjälä in->vtotal > USHRT_MAX || in->vscan > USHRT_MAX, 1665e36fae38SVille Syrjälä "timing values too large for mode info\n"); 1666e36fae38SVille Syrjälä 1667f453ba04SDave Airlie out->clock = in->clock; 1668f453ba04SDave Airlie out->hdisplay = in->hdisplay; 1669f453ba04SDave Airlie out->hsync_start = in->hsync_start; 1670f453ba04SDave Airlie out->hsync_end = in->hsync_end; 1671f453ba04SDave Airlie out->htotal = in->htotal; 1672f453ba04SDave Airlie out->hskew = in->hskew; 1673f453ba04SDave Airlie out->vdisplay = in->vdisplay; 1674f453ba04SDave Airlie out->vsync_start = in->vsync_start; 1675f453ba04SDave Airlie out->vsync_end = in->vsync_end; 1676f453ba04SDave Airlie out->vtotal = in->vtotal; 1677f453ba04SDave Airlie out->vscan = in->vscan; 1678f453ba04SDave Airlie out->vrefresh = in->vrefresh; 1679f453ba04SDave Airlie out->flags = in->flags; 1680f453ba04SDave Airlie out->type = in->type; 1681f453ba04SDave Airlie strncpy(out->name, in->name, DRM_DISPLAY_MODE_LEN); 1682f453ba04SDave Airlie out->name[DRM_DISPLAY_MODE_LEN-1] = 0; 1683f453ba04SDave Airlie } 1684f453ba04SDave Airlie 1685f453ba04SDave Airlie /** 168674afee7dSMarc-André Lureau * drm_crtc_convert_umode - convert a modeinfo into a drm_display_mode 1687f453ba04SDave Airlie * @out: drm_display_mode to return to the user 1688f453ba04SDave Airlie * @in: drm_mode_modeinfo to use 1689f453ba04SDave Airlie * 1690f453ba04SDave Airlie * Convert a drm_mode_modeinfo into a drm_display_mode structure to return to 1691f453ba04SDave Airlie * the caller. 169290367bf6SVille Syrjälä * 1693c8e32cc1SDaniel Vetter * Returns: 16941a498633SDaniel Vetter * Zero on success, negative errno on failure. 1695f453ba04SDave Airlie */ 169693bbf6dbSVille Syrjälä static int drm_crtc_convert_umode(struct drm_display_mode *out, 169793bbf6dbSVille Syrjälä const struct drm_mode_modeinfo *in) 1698f453ba04SDave Airlie { 169990367bf6SVille Syrjälä if (in->clock > INT_MAX || in->vrefresh > INT_MAX) 170090367bf6SVille Syrjälä return -ERANGE; 170190367bf6SVille Syrjälä 17025848ad40SDamien Lespiau if ((in->flags & DRM_MODE_FLAG_3D_MASK) > DRM_MODE_FLAG_3D_MAX) 17035848ad40SDamien Lespiau return -EINVAL; 17045848ad40SDamien Lespiau 1705f453ba04SDave Airlie out->clock = in->clock; 1706f453ba04SDave Airlie out->hdisplay = in->hdisplay; 1707f453ba04SDave Airlie out->hsync_start = in->hsync_start; 1708f453ba04SDave Airlie out->hsync_end = in->hsync_end; 1709f453ba04SDave Airlie out->htotal = in->htotal; 1710f453ba04SDave Airlie out->hskew = in->hskew; 1711f453ba04SDave Airlie out->vdisplay = in->vdisplay; 1712f453ba04SDave Airlie out->vsync_start = in->vsync_start; 1713f453ba04SDave Airlie out->vsync_end = in->vsync_end; 1714f453ba04SDave Airlie out->vtotal = in->vtotal; 1715f453ba04SDave Airlie out->vscan = in->vscan; 1716f453ba04SDave Airlie out->vrefresh = in->vrefresh; 1717f453ba04SDave Airlie out->flags = in->flags; 1718f453ba04SDave Airlie out->type = in->type; 1719f453ba04SDave Airlie strncpy(out->name, in->name, DRM_DISPLAY_MODE_LEN); 1720f453ba04SDave Airlie out->name[DRM_DISPLAY_MODE_LEN-1] = 0; 172190367bf6SVille Syrjälä 172290367bf6SVille Syrjälä return 0; 1723f453ba04SDave Airlie } 1724f453ba04SDave Airlie 1725f453ba04SDave Airlie /** 1726f453ba04SDave Airlie * drm_mode_getresources - get graphics configuration 1727065a50edSDaniel Vetter * @dev: drm device for the ioctl 1728065a50edSDaniel Vetter * @data: data pointer for the ioctl 1729065a50edSDaniel Vetter * @file_priv: drm file for the ioctl call 1730f453ba04SDave Airlie * 1731f453ba04SDave Airlie * Construct a set of configuration description structures and return 1732f453ba04SDave Airlie * them to the user, including CRTC, connector and framebuffer configuration. 1733f453ba04SDave Airlie * 1734f453ba04SDave Airlie * Called by the user via ioctl. 1735f453ba04SDave Airlie * 1736c8e32cc1SDaniel Vetter * Returns: 17371a498633SDaniel Vetter * Zero on success, negative errno on failure. 1738f453ba04SDave Airlie */ 1739f453ba04SDave Airlie int drm_mode_getresources(struct drm_device *dev, void *data, 1740f453ba04SDave Airlie struct drm_file *file_priv) 1741f453ba04SDave Airlie { 1742f453ba04SDave Airlie struct drm_mode_card_res *card_res = data; 1743f453ba04SDave Airlie struct list_head *lh; 1744f453ba04SDave Airlie struct drm_framebuffer *fb; 1745f453ba04SDave Airlie struct drm_connector *connector; 1746f453ba04SDave Airlie struct drm_crtc *crtc; 1747f453ba04SDave Airlie struct drm_encoder *encoder; 1748f453ba04SDave Airlie int ret = 0; 1749f453ba04SDave Airlie int connector_count = 0; 1750f453ba04SDave Airlie int crtc_count = 0; 1751f453ba04SDave Airlie int fb_count = 0; 1752f453ba04SDave Airlie int encoder_count = 0; 1753f453ba04SDave Airlie int copied = 0, i; 1754f453ba04SDave Airlie uint32_t __user *fb_id; 1755f453ba04SDave Airlie uint32_t __user *crtc_id; 1756f453ba04SDave Airlie uint32_t __user *connector_id; 1757f453ba04SDave Airlie uint32_t __user *encoder_id; 1758f453ba04SDave Airlie struct drm_mode_group *mode_group; 1759f453ba04SDave Airlie 1760fb3b06c8SDave Airlie if (!drm_core_check_feature(dev, DRIVER_MODESET)) 1761fb3b06c8SDave Airlie return -EINVAL; 1762fb3b06c8SDave Airlie 1763f453ba04SDave Airlie 17644b096ac1SDaniel Vetter mutex_lock(&file_priv->fbs_lock); 1765f453ba04SDave Airlie /* 1766f453ba04SDave Airlie * For the non-control nodes we need to limit the list of resources 1767f453ba04SDave Airlie * by IDs in the group list for this node 1768f453ba04SDave Airlie */ 1769f453ba04SDave Airlie list_for_each(lh, &file_priv->fbs) 1770f453ba04SDave Airlie fb_count++; 1771f453ba04SDave Airlie 17724b096ac1SDaniel Vetter /* handle this in 4 parts */ 17734b096ac1SDaniel Vetter /* FBs */ 17744b096ac1SDaniel Vetter if (card_res->count_fbs >= fb_count) { 17754b096ac1SDaniel Vetter copied = 0; 17764b096ac1SDaniel Vetter fb_id = (uint32_t __user *)(unsigned long)card_res->fb_id_ptr; 17774b096ac1SDaniel Vetter list_for_each_entry(fb, &file_priv->fbs, filp_head) { 17784b096ac1SDaniel Vetter if (put_user(fb->base.id, fb_id + copied)) { 17794b096ac1SDaniel Vetter mutex_unlock(&file_priv->fbs_lock); 17804b096ac1SDaniel Vetter return -EFAULT; 17814b096ac1SDaniel Vetter } 17824b096ac1SDaniel Vetter copied++; 17834b096ac1SDaniel Vetter } 17844b096ac1SDaniel Vetter } 17854b096ac1SDaniel Vetter card_res->count_fbs = fb_count; 17864b096ac1SDaniel Vetter mutex_unlock(&file_priv->fbs_lock); 17874b096ac1SDaniel Vetter 1788fcf93f69SDaniel Vetter /* mode_config.mutex protects the connector list against e.g. DP MST 1789fcf93f69SDaniel Vetter * connector hot-adding. CRTC/Plane lists are invariant. */ 1790fcf93f69SDaniel Vetter mutex_lock(&dev->mode_config.mutex); 179143683057SThomas Hellstrom if (!drm_is_primary_client(file_priv)) { 1792f453ba04SDave Airlie 179309f308f7SThomas Hellstrom mode_group = NULL; 1794f453ba04SDave Airlie list_for_each(lh, &dev->mode_config.crtc_list) 1795f453ba04SDave Airlie crtc_count++; 1796f453ba04SDave Airlie 1797f453ba04SDave Airlie list_for_each(lh, &dev->mode_config.connector_list) 1798f453ba04SDave Airlie connector_count++; 1799f453ba04SDave Airlie 1800f453ba04SDave Airlie list_for_each(lh, &dev->mode_config.encoder_list) 1801f453ba04SDave Airlie encoder_count++; 1802f453ba04SDave Airlie } else { 1803f453ba04SDave Airlie 180409f308f7SThomas Hellstrom mode_group = &file_priv->master->minor->mode_group; 1805f453ba04SDave Airlie crtc_count = mode_group->num_crtcs; 1806f453ba04SDave Airlie connector_count = mode_group->num_connectors; 1807f453ba04SDave Airlie encoder_count = mode_group->num_encoders; 1808f453ba04SDave Airlie } 1809f453ba04SDave Airlie 1810f453ba04SDave Airlie card_res->max_height = dev->mode_config.max_height; 1811f453ba04SDave Airlie card_res->min_height = dev->mode_config.min_height; 1812f453ba04SDave Airlie card_res->max_width = dev->mode_config.max_width; 1813f453ba04SDave Airlie card_res->min_width = dev->mode_config.min_width; 1814f453ba04SDave Airlie 1815f453ba04SDave Airlie /* CRTCs */ 1816f453ba04SDave Airlie if (card_res->count_crtcs >= crtc_count) { 1817f453ba04SDave Airlie copied = 0; 1818f453ba04SDave Airlie crtc_id = (uint32_t __user *)(unsigned long)card_res->crtc_id_ptr; 181909f308f7SThomas Hellstrom if (!mode_group) { 1820f453ba04SDave Airlie list_for_each_entry(crtc, &dev->mode_config.crtc_list, 1821f453ba04SDave Airlie head) { 18229440106bSJerome Glisse DRM_DEBUG_KMS("[CRTC:%d]\n", crtc->base.id); 1823f453ba04SDave Airlie if (put_user(crtc->base.id, crtc_id + copied)) { 1824f453ba04SDave Airlie ret = -EFAULT; 1825f453ba04SDave Airlie goto out; 1826f453ba04SDave Airlie } 1827f453ba04SDave Airlie copied++; 1828f453ba04SDave Airlie } 1829f453ba04SDave Airlie } else { 1830f453ba04SDave Airlie for (i = 0; i < mode_group->num_crtcs; i++) { 1831f453ba04SDave Airlie if (put_user(mode_group->id_list[i], 1832f453ba04SDave Airlie crtc_id + copied)) { 1833f453ba04SDave Airlie ret = -EFAULT; 1834f453ba04SDave Airlie goto out; 1835f453ba04SDave Airlie } 1836f453ba04SDave Airlie copied++; 1837f453ba04SDave Airlie } 1838f453ba04SDave Airlie } 1839f453ba04SDave Airlie } 1840f453ba04SDave Airlie card_res->count_crtcs = crtc_count; 1841f453ba04SDave Airlie 1842f453ba04SDave Airlie /* Encoders */ 1843f453ba04SDave Airlie if (card_res->count_encoders >= encoder_count) { 1844f453ba04SDave Airlie copied = 0; 1845f453ba04SDave Airlie encoder_id = (uint32_t __user *)(unsigned long)card_res->encoder_id_ptr; 184609f308f7SThomas Hellstrom if (!mode_group) { 1847f453ba04SDave Airlie list_for_each_entry(encoder, 1848f453ba04SDave Airlie &dev->mode_config.encoder_list, 1849f453ba04SDave Airlie head) { 18509440106bSJerome Glisse DRM_DEBUG_KMS("[ENCODER:%d:%s]\n", encoder->base.id, 185183a8cfd3SJani Nikula encoder->name); 1852f453ba04SDave Airlie if (put_user(encoder->base.id, encoder_id + 1853f453ba04SDave Airlie copied)) { 1854f453ba04SDave Airlie ret = -EFAULT; 1855f453ba04SDave Airlie goto out; 1856f453ba04SDave Airlie } 1857f453ba04SDave Airlie copied++; 1858f453ba04SDave Airlie } 1859f453ba04SDave Airlie } else { 1860f453ba04SDave Airlie for (i = mode_group->num_crtcs; i < mode_group->num_crtcs + mode_group->num_encoders; i++) { 1861f453ba04SDave Airlie if (put_user(mode_group->id_list[i], 1862f453ba04SDave Airlie encoder_id + copied)) { 1863f453ba04SDave Airlie ret = -EFAULT; 1864f453ba04SDave Airlie goto out; 1865f453ba04SDave Airlie } 1866f453ba04SDave Airlie copied++; 1867f453ba04SDave Airlie } 1868f453ba04SDave Airlie 1869f453ba04SDave Airlie } 1870f453ba04SDave Airlie } 1871f453ba04SDave Airlie card_res->count_encoders = encoder_count; 1872f453ba04SDave Airlie 1873f453ba04SDave Airlie /* Connectors */ 1874f453ba04SDave Airlie if (card_res->count_connectors >= connector_count) { 1875f453ba04SDave Airlie copied = 0; 1876f453ba04SDave Airlie connector_id = (uint32_t __user *)(unsigned long)card_res->connector_id_ptr; 187709f308f7SThomas Hellstrom if (!mode_group) { 1878f453ba04SDave Airlie list_for_each_entry(connector, 1879f453ba04SDave Airlie &dev->mode_config.connector_list, 1880f453ba04SDave Airlie head) { 18819440106bSJerome Glisse DRM_DEBUG_KMS("[CONNECTOR:%d:%s]\n", 18829440106bSJerome Glisse connector->base.id, 188325933820SJani Nikula connector->name); 1884f453ba04SDave Airlie if (put_user(connector->base.id, 1885f453ba04SDave Airlie connector_id + copied)) { 1886f453ba04SDave Airlie ret = -EFAULT; 1887f453ba04SDave Airlie goto out; 1888f453ba04SDave Airlie } 1889f453ba04SDave Airlie copied++; 1890f453ba04SDave Airlie } 1891f453ba04SDave Airlie } else { 1892f453ba04SDave Airlie int start = mode_group->num_crtcs + 1893f453ba04SDave Airlie mode_group->num_encoders; 1894f453ba04SDave Airlie for (i = start; i < start + mode_group->num_connectors; i++) { 1895f453ba04SDave Airlie if (put_user(mode_group->id_list[i], 1896f453ba04SDave Airlie connector_id + copied)) { 1897f453ba04SDave Airlie ret = -EFAULT; 1898f453ba04SDave Airlie goto out; 1899f453ba04SDave Airlie } 1900f453ba04SDave Airlie copied++; 1901f453ba04SDave Airlie } 1902f453ba04SDave Airlie } 1903f453ba04SDave Airlie } 1904f453ba04SDave Airlie card_res->count_connectors = connector_count; 1905f453ba04SDave Airlie 19069440106bSJerome Glisse DRM_DEBUG_KMS("CRTC[%d] CONNECTORS[%d] ENCODERS[%d]\n", card_res->count_crtcs, 1907f453ba04SDave Airlie card_res->count_connectors, card_res->count_encoders); 1908f453ba04SDave Airlie 1909f453ba04SDave Airlie out: 1910fcf93f69SDaniel Vetter mutex_unlock(&dev->mode_config.mutex); 1911f453ba04SDave Airlie return ret; 1912f453ba04SDave Airlie } 1913f453ba04SDave Airlie 1914f453ba04SDave Airlie /** 1915f453ba04SDave Airlie * drm_mode_getcrtc - get CRTC configuration 1916065a50edSDaniel Vetter * @dev: drm device for the ioctl 1917065a50edSDaniel Vetter * @data: data pointer for the ioctl 1918065a50edSDaniel Vetter * @file_priv: drm file for the ioctl call 1919f453ba04SDave Airlie * 1920f453ba04SDave Airlie * Construct a CRTC configuration structure to return to the user. 1921f453ba04SDave Airlie * 1922f453ba04SDave Airlie * Called by the user via ioctl. 1923f453ba04SDave Airlie * 1924c8e32cc1SDaniel Vetter * Returns: 19251a498633SDaniel Vetter * Zero on success, negative errno on failure. 1926f453ba04SDave Airlie */ 1927f453ba04SDave Airlie int drm_mode_getcrtc(struct drm_device *dev, 1928f453ba04SDave Airlie void *data, struct drm_file *file_priv) 1929f453ba04SDave Airlie { 1930f453ba04SDave Airlie struct drm_mode_crtc *crtc_resp = data; 1931f453ba04SDave Airlie struct drm_crtc *crtc; 1932f453ba04SDave Airlie 1933fb3b06c8SDave Airlie if (!drm_core_check_feature(dev, DRIVER_MODESET)) 1934fb3b06c8SDave Airlie return -EINVAL; 1935fb3b06c8SDave Airlie 1936a2b34e22SRob Clark crtc = drm_crtc_find(dev, crtc_resp->crtc_id); 1937fcf93f69SDaniel Vetter if (!crtc) 1938fcf93f69SDaniel Vetter return -ENOENT; 1939f453ba04SDave Airlie 1940fcf93f69SDaniel Vetter drm_modeset_lock_crtc(crtc, crtc->primary); 1941f453ba04SDave Airlie crtc_resp->x = crtc->x; 1942f453ba04SDave Airlie crtc_resp->y = crtc->y; 1943f453ba04SDave Airlie crtc_resp->gamma_size = crtc->gamma_size; 1944f4510a27SMatt Roper if (crtc->primary->fb) 1945f4510a27SMatt Roper crtc_resp->fb_id = crtc->primary->fb->base.id; 1946f453ba04SDave Airlie else 1947f453ba04SDave Airlie crtc_resp->fb_id = 0; 1948f453ba04SDave Airlie 1949f453ba04SDave Airlie if (crtc->enabled) { 1950f453ba04SDave Airlie 1951f453ba04SDave Airlie drm_crtc_convert_to_umode(&crtc_resp->mode, &crtc->mode); 1952f453ba04SDave Airlie crtc_resp->mode_valid = 1; 1953f453ba04SDave Airlie 1954f453ba04SDave Airlie } else { 1955f453ba04SDave Airlie crtc_resp->mode_valid = 0; 1956f453ba04SDave Airlie } 1957fcf93f69SDaniel Vetter drm_modeset_unlock_crtc(crtc); 1958f453ba04SDave Airlie 1959baf698b0SDaniel Vetter return 0; 1960f453ba04SDave Airlie } 1961f453ba04SDave Airlie 196261d8e328SDamien Lespiau static bool drm_mode_expose_to_userspace(const struct drm_display_mode *mode, 196361d8e328SDamien Lespiau const struct drm_file *file_priv) 196461d8e328SDamien Lespiau { 196561d8e328SDamien Lespiau /* 196661d8e328SDamien Lespiau * If user-space hasn't configured the driver to expose the stereo 3D 196761d8e328SDamien Lespiau * modes, don't expose them. 196861d8e328SDamien Lespiau */ 196961d8e328SDamien Lespiau if (!file_priv->stereo_allowed && drm_mode_is_stereo(mode)) 197061d8e328SDamien Lespiau return false; 197161d8e328SDamien Lespiau 197261d8e328SDamien Lespiau return true; 197361d8e328SDamien Lespiau } 197461d8e328SDamien Lespiau 1975abd69c55SDaniel Vetter static struct drm_encoder *drm_connector_get_encoder(struct drm_connector *connector) 1976abd69c55SDaniel Vetter { 1977abd69c55SDaniel Vetter /* For atomic drivers only state objects are synchronously updated and 1978abd69c55SDaniel Vetter * protected by modeset locks, so check those first. */ 1979abd69c55SDaniel Vetter if (connector->state) 1980abd69c55SDaniel Vetter return connector->state->best_encoder; 1981abd69c55SDaniel Vetter return connector->encoder; 1982abd69c55SDaniel Vetter } 1983abd69c55SDaniel Vetter 1984f453ba04SDave Airlie /** 1985f453ba04SDave Airlie * drm_mode_getconnector - get connector configuration 1986065a50edSDaniel Vetter * @dev: drm device for the ioctl 1987065a50edSDaniel Vetter * @data: data pointer for the ioctl 1988065a50edSDaniel Vetter * @file_priv: drm file for the ioctl call 1989f453ba04SDave Airlie * 1990f453ba04SDave Airlie * Construct a connector configuration structure to return to the user. 1991f453ba04SDave Airlie * 1992f453ba04SDave Airlie * Called by the user via ioctl. 1993f453ba04SDave Airlie * 1994c8e32cc1SDaniel Vetter * Returns: 19951a498633SDaniel Vetter * Zero on success, negative errno on failure. 1996f453ba04SDave Airlie */ 1997f453ba04SDave Airlie int drm_mode_getconnector(struct drm_device *dev, void *data, 1998f453ba04SDave Airlie struct drm_file *file_priv) 1999f453ba04SDave Airlie { 2000f453ba04SDave Airlie struct drm_mode_get_connector *out_resp = data; 2001f453ba04SDave Airlie struct drm_connector *connector; 2002abd69c55SDaniel Vetter struct drm_encoder *encoder; 2003f453ba04SDave Airlie struct drm_display_mode *mode; 2004f453ba04SDave Airlie int mode_count = 0; 2005f453ba04SDave Airlie int props_count = 0; 2006f453ba04SDave Airlie int encoders_count = 0; 2007f453ba04SDave Airlie int ret = 0; 2008f453ba04SDave Airlie int copied = 0; 2009f453ba04SDave Airlie int i; 2010f453ba04SDave Airlie struct drm_mode_modeinfo u_mode; 2011f453ba04SDave Airlie struct drm_mode_modeinfo __user *mode_ptr; 2012f453ba04SDave Airlie uint32_t __user *prop_ptr; 2013f453ba04SDave Airlie uint64_t __user *prop_values; 2014f453ba04SDave Airlie uint32_t __user *encoder_ptr; 2015f453ba04SDave Airlie 2016fb3b06c8SDave Airlie if (!drm_core_check_feature(dev, DRIVER_MODESET)) 2017fb3b06c8SDave Airlie return -EINVAL; 2018fb3b06c8SDave Airlie 2019f453ba04SDave Airlie memset(&u_mode, 0, sizeof(struct drm_mode_modeinfo)); 2020f453ba04SDave Airlie 20219440106bSJerome Glisse DRM_DEBUG_KMS("[CONNECTOR:%d:?]\n", out_resp->connector_id); 2022f453ba04SDave Airlie 20237b24056bSDaniel Vetter mutex_lock(&dev->mode_config.mutex); 2024f453ba04SDave Airlie 2025a2b34e22SRob Clark connector = drm_connector_find(dev, out_resp->connector_id); 2026a2b34e22SRob Clark if (!connector) { 2027f27657f2SVille Syrjälä ret = -ENOENT; 2028f453ba04SDave Airlie goto out; 2029f453ba04SDave Airlie } 2030f453ba04SDave Airlie 20317f88a9beSPaulo Zanoni props_count = connector->properties.count; 2032f453ba04SDave Airlie 2033f453ba04SDave Airlie for (i = 0; i < DRM_CONNECTOR_MAX_ENCODER; i++) { 2034f453ba04SDave Airlie if (connector->encoder_ids[i] != 0) { 2035f453ba04SDave Airlie encoders_count++; 2036f453ba04SDave Airlie } 2037f453ba04SDave Airlie } 2038f453ba04SDave Airlie 2039f453ba04SDave Airlie if (out_resp->count_modes == 0) { 2040f453ba04SDave Airlie connector->funcs->fill_modes(connector, 2041f453ba04SDave Airlie dev->mode_config.max_width, 2042f453ba04SDave Airlie dev->mode_config.max_height); 2043f453ba04SDave Airlie } 2044f453ba04SDave Airlie 2045f453ba04SDave Airlie /* delayed so we get modes regardless of pre-fill_modes state */ 2046f453ba04SDave Airlie list_for_each_entry(mode, &connector->modes, head) 204761d8e328SDamien Lespiau if (drm_mode_expose_to_userspace(mode, file_priv)) 2048f453ba04SDave Airlie mode_count++; 2049f453ba04SDave Airlie 2050f453ba04SDave Airlie out_resp->connector_id = connector->base.id; 2051f453ba04SDave Airlie out_resp->connector_type = connector->connector_type; 2052f453ba04SDave Airlie out_resp->connector_type_id = connector->connector_type_id; 2053f453ba04SDave Airlie out_resp->mm_width = connector->display_info.width_mm; 2054f453ba04SDave Airlie out_resp->mm_height = connector->display_info.height_mm; 2055f453ba04SDave Airlie out_resp->subpixel = connector->display_info.subpixel_order; 2056f453ba04SDave Airlie out_resp->connection = connector->status; 2057832fd395SDaniel Vetter drm_modeset_lock(&dev->mode_config.connection_mutex, NULL); 2058abd69c55SDaniel Vetter 2059abd69c55SDaniel Vetter encoder = drm_connector_get_encoder(connector); 2060abd69c55SDaniel Vetter if (encoder) 2061abd69c55SDaniel Vetter out_resp->encoder_id = encoder->base.id; 2062f453ba04SDave Airlie else 2063f453ba04SDave Airlie out_resp->encoder_id = 0; 2064832fd395SDaniel Vetter drm_modeset_unlock(&dev->mode_config.connection_mutex); 2065f453ba04SDave Airlie 2066f453ba04SDave Airlie /* 2067f453ba04SDave Airlie * This ioctl is called twice, once to determine how much space is 2068f453ba04SDave Airlie * needed, and the 2nd time to fill it. 2069f453ba04SDave Airlie */ 2070f453ba04SDave Airlie if ((out_resp->count_modes >= mode_count) && mode_count) { 2071f453ba04SDave Airlie copied = 0; 207281f6c7f8SVille Syrjälä mode_ptr = (struct drm_mode_modeinfo __user *)(unsigned long)out_resp->modes_ptr; 2073f453ba04SDave Airlie list_for_each_entry(mode, &connector->modes, head) { 207461d8e328SDamien Lespiau if (!drm_mode_expose_to_userspace(mode, file_priv)) 207561d8e328SDamien Lespiau continue; 207661d8e328SDamien Lespiau 2077f453ba04SDave Airlie drm_crtc_convert_to_umode(&u_mode, mode); 2078f453ba04SDave Airlie if (copy_to_user(mode_ptr + copied, 2079f453ba04SDave Airlie &u_mode, sizeof(u_mode))) { 2080f453ba04SDave Airlie ret = -EFAULT; 2081f453ba04SDave Airlie goto out; 2082f453ba04SDave Airlie } 2083f453ba04SDave Airlie copied++; 2084f453ba04SDave Airlie } 2085f453ba04SDave Airlie } 2086f453ba04SDave Airlie out_resp->count_modes = mode_count; 2087f453ba04SDave Airlie 2088f453ba04SDave Airlie if ((out_resp->count_props >= props_count) && props_count) { 2089f453ba04SDave Airlie copied = 0; 209081f6c7f8SVille Syrjälä prop_ptr = (uint32_t __user *)(unsigned long)(out_resp->props_ptr); 209181f6c7f8SVille Syrjälä prop_values = (uint64_t __user *)(unsigned long)(out_resp->prop_values_ptr); 20927f88a9beSPaulo Zanoni for (i = 0; i < connector->properties.count; i++) { 20937e3bdf4aSPaulo Zanoni if (put_user(connector->properties.ids[i], 2094f453ba04SDave Airlie prop_ptr + copied)) { 2095f453ba04SDave Airlie ret = -EFAULT; 2096f453ba04SDave Airlie goto out; 2097f453ba04SDave Airlie } 2098f453ba04SDave Airlie 20997e3bdf4aSPaulo Zanoni if (put_user(connector->properties.values[i], 2100f453ba04SDave Airlie prop_values + copied)) { 2101f453ba04SDave Airlie ret = -EFAULT; 2102f453ba04SDave Airlie goto out; 2103f453ba04SDave Airlie } 2104f453ba04SDave Airlie copied++; 2105f453ba04SDave Airlie } 2106f453ba04SDave Airlie } 2107f453ba04SDave Airlie out_resp->count_props = props_count; 2108f453ba04SDave Airlie 2109f453ba04SDave Airlie if ((out_resp->count_encoders >= encoders_count) && encoders_count) { 2110f453ba04SDave Airlie copied = 0; 211181f6c7f8SVille Syrjälä encoder_ptr = (uint32_t __user *)(unsigned long)(out_resp->encoders_ptr); 2112f453ba04SDave Airlie for (i = 0; i < DRM_CONNECTOR_MAX_ENCODER; i++) { 2113f453ba04SDave Airlie if (connector->encoder_ids[i] != 0) { 2114f453ba04SDave Airlie if (put_user(connector->encoder_ids[i], 2115f453ba04SDave Airlie encoder_ptr + copied)) { 2116f453ba04SDave Airlie ret = -EFAULT; 2117f453ba04SDave Airlie goto out; 2118f453ba04SDave Airlie } 2119f453ba04SDave Airlie copied++; 2120f453ba04SDave Airlie } 2121f453ba04SDave Airlie } 2122f453ba04SDave Airlie } 2123f453ba04SDave Airlie out_resp->count_encoders = encoders_count; 2124f453ba04SDave Airlie 2125f453ba04SDave Airlie out: 21267b24056bSDaniel Vetter mutex_unlock(&dev->mode_config.mutex); 21277b24056bSDaniel Vetter 2128f453ba04SDave Airlie return ret; 2129f453ba04SDave Airlie } 2130f453ba04SDave Airlie 2131abd69c55SDaniel Vetter static struct drm_crtc *drm_encoder_get_crtc(struct drm_encoder *encoder) 2132abd69c55SDaniel Vetter { 2133abd69c55SDaniel Vetter struct drm_connector *connector; 2134abd69c55SDaniel Vetter struct drm_device *dev = encoder->dev; 2135abd69c55SDaniel Vetter bool uses_atomic = false; 2136abd69c55SDaniel Vetter 2137abd69c55SDaniel Vetter /* For atomic drivers only state objects are synchronously updated and 2138abd69c55SDaniel Vetter * protected by modeset locks, so check those first. */ 2139abd69c55SDaniel Vetter list_for_each_entry(connector, &dev->mode_config.connector_list, head) { 2140abd69c55SDaniel Vetter if (!connector->state) 2141abd69c55SDaniel Vetter continue; 2142abd69c55SDaniel Vetter 2143abd69c55SDaniel Vetter uses_atomic = true; 2144abd69c55SDaniel Vetter 2145abd69c55SDaniel Vetter if (connector->state->best_encoder != encoder) 2146abd69c55SDaniel Vetter continue; 2147abd69c55SDaniel Vetter 2148abd69c55SDaniel Vetter return connector->state->crtc; 2149abd69c55SDaniel Vetter } 2150abd69c55SDaniel Vetter 2151abd69c55SDaniel Vetter /* Don't return stale data (e.g. pending async disable). */ 2152abd69c55SDaniel Vetter if (uses_atomic) 2153abd69c55SDaniel Vetter return NULL; 2154abd69c55SDaniel Vetter 2155abd69c55SDaniel Vetter return encoder->crtc; 2156abd69c55SDaniel Vetter } 2157abd69c55SDaniel Vetter 2158c8e32cc1SDaniel Vetter /** 2159c8e32cc1SDaniel Vetter * drm_mode_getencoder - get encoder configuration 2160c8e32cc1SDaniel Vetter * @dev: drm device for the ioctl 2161c8e32cc1SDaniel Vetter * @data: data pointer for the ioctl 2162c8e32cc1SDaniel Vetter * @file_priv: drm file for the ioctl call 2163c8e32cc1SDaniel Vetter * 2164c8e32cc1SDaniel Vetter * Construct a encoder configuration structure to return to the user. 2165c8e32cc1SDaniel Vetter * 2166c8e32cc1SDaniel Vetter * Called by the user via ioctl. 2167c8e32cc1SDaniel Vetter * 2168c8e32cc1SDaniel Vetter * Returns: 21691a498633SDaniel Vetter * Zero on success, negative errno on failure. 2170c8e32cc1SDaniel Vetter */ 2171f453ba04SDave Airlie int drm_mode_getencoder(struct drm_device *dev, void *data, 2172f453ba04SDave Airlie struct drm_file *file_priv) 2173f453ba04SDave Airlie { 2174f453ba04SDave Airlie struct drm_mode_get_encoder *enc_resp = data; 2175f453ba04SDave Airlie struct drm_encoder *encoder; 2176abd69c55SDaniel Vetter struct drm_crtc *crtc; 2177f453ba04SDave Airlie 2178fb3b06c8SDave Airlie if (!drm_core_check_feature(dev, DRIVER_MODESET)) 2179fb3b06c8SDave Airlie return -EINVAL; 2180fb3b06c8SDave Airlie 2181a2b34e22SRob Clark encoder = drm_encoder_find(dev, enc_resp->encoder_id); 2182fcf93f69SDaniel Vetter if (!encoder) 2183fcf93f69SDaniel Vetter return -ENOENT; 2184f453ba04SDave Airlie 2185fcf93f69SDaniel Vetter drm_modeset_lock(&dev->mode_config.connection_mutex, NULL); 2186abd69c55SDaniel Vetter crtc = drm_encoder_get_crtc(encoder); 2187abd69c55SDaniel Vetter if (crtc) 2188abd69c55SDaniel Vetter enc_resp->crtc_id = crtc->base.id; 2189abd69c55SDaniel Vetter else if (encoder->crtc) 2190f453ba04SDave Airlie enc_resp->crtc_id = encoder->crtc->base.id; 2191f453ba04SDave Airlie else 2192f453ba04SDave Airlie enc_resp->crtc_id = 0; 2193fcf93f69SDaniel Vetter drm_modeset_unlock(&dev->mode_config.connection_mutex); 2194fcf93f69SDaniel Vetter 2195f453ba04SDave Airlie enc_resp->encoder_type = encoder->encoder_type; 2196f453ba04SDave Airlie enc_resp->encoder_id = encoder->base.id; 2197f453ba04SDave Airlie enc_resp->possible_crtcs = encoder->possible_crtcs; 2198f453ba04SDave Airlie enc_resp->possible_clones = encoder->possible_clones; 2199f453ba04SDave Airlie 2200baf698b0SDaniel Vetter return 0; 2201f453ba04SDave Airlie } 2202f453ba04SDave Airlie 2203f453ba04SDave Airlie /** 2204c8e32cc1SDaniel Vetter * drm_mode_getplane_res - enumerate all plane resources 22058cf5c917SJesse Barnes * @dev: DRM device 22068cf5c917SJesse Barnes * @data: ioctl data 22078cf5c917SJesse Barnes * @file_priv: DRM file info 22088cf5c917SJesse Barnes * 2209c8e32cc1SDaniel Vetter * Construct a list of plane ids to return to the user. 2210c8e32cc1SDaniel Vetter * 2211c8e32cc1SDaniel Vetter * Called by the user via ioctl. 2212c8e32cc1SDaniel Vetter * 2213c8e32cc1SDaniel Vetter * Returns: 22141a498633SDaniel Vetter * Zero on success, negative errno on failure. 22158cf5c917SJesse Barnes */ 22168cf5c917SJesse Barnes int drm_mode_getplane_res(struct drm_device *dev, void *data, 22178cf5c917SJesse Barnes struct drm_file *file_priv) 22188cf5c917SJesse Barnes { 22198cf5c917SJesse Barnes struct drm_mode_get_plane_res *plane_resp = data; 22208cf5c917SJesse Barnes struct drm_mode_config *config; 22218cf5c917SJesse Barnes struct drm_plane *plane; 22228cf5c917SJesse Barnes uint32_t __user *plane_ptr; 2223fcf93f69SDaniel Vetter int copied = 0; 2224681e7ec7SMatt Roper unsigned num_planes; 22258cf5c917SJesse Barnes 22268cf5c917SJesse Barnes if (!drm_core_check_feature(dev, DRIVER_MODESET)) 22278cf5c917SJesse Barnes return -EINVAL; 22288cf5c917SJesse Barnes 22298cf5c917SJesse Barnes config = &dev->mode_config; 22308cf5c917SJesse Barnes 2231681e7ec7SMatt Roper if (file_priv->universal_planes) 2232681e7ec7SMatt Roper num_planes = config->num_total_plane; 2233681e7ec7SMatt Roper else 2234681e7ec7SMatt Roper num_planes = config->num_overlay_plane; 2235681e7ec7SMatt Roper 22368cf5c917SJesse Barnes /* 22378cf5c917SJesse Barnes * This ioctl is called twice, once to determine how much space is 22388cf5c917SJesse Barnes * needed, and the 2nd time to fill it. 22398cf5c917SJesse Barnes */ 2240681e7ec7SMatt Roper if (num_planes && 2241681e7ec7SMatt Roper (plane_resp->count_planes >= num_planes)) { 224281f6c7f8SVille Syrjälä plane_ptr = (uint32_t __user *)(unsigned long)plane_resp->plane_id_ptr; 22438cf5c917SJesse Barnes 2244fcf93f69SDaniel Vetter /* Plane lists are invariant, no locking needed. */ 22458cf5c917SJesse Barnes list_for_each_entry(plane, &config->plane_list, head) { 2246681e7ec7SMatt Roper /* 2247681e7ec7SMatt Roper * Unless userspace set the 'universal planes' 2248681e7ec7SMatt Roper * capability bit, only advertise overlays. 2249681e7ec7SMatt Roper */ 2250681e7ec7SMatt Roper if (plane->type != DRM_PLANE_TYPE_OVERLAY && 2251681e7ec7SMatt Roper !file_priv->universal_planes) 2252e27dde3eSMatt Roper continue; 2253e27dde3eSMatt Roper 2254fcf93f69SDaniel Vetter if (put_user(plane->base.id, plane_ptr + copied)) 2255fcf93f69SDaniel Vetter return -EFAULT; 22568cf5c917SJesse Barnes copied++; 22578cf5c917SJesse Barnes } 22588cf5c917SJesse Barnes } 2259681e7ec7SMatt Roper plane_resp->count_planes = num_planes; 22608cf5c917SJesse Barnes 2261fcf93f69SDaniel Vetter return 0; 22628cf5c917SJesse Barnes } 22638cf5c917SJesse Barnes 22648cf5c917SJesse Barnes /** 2265c8e32cc1SDaniel Vetter * drm_mode_getplane - get plane configuration 22668cf5c917SJesse Barnes * @dev: DRM device 22678cf5c917SJesse Barnes * @data: ioctl data 22688cf5c917SJesse Barnes * @file_priv: DRM file info 22698cf5c917SJesse Barnes * 2270c8e32cc1SDaniel Vetter * Construct a plane configuration structure to return to the user. 2271c8e32cc1SDaniel Vetter * 2272c8e32cc1SDaniel Vetter * Called by the user via ioctl. 2273c8e32cc1SDaniel Vetter * 2274c8e32cc1SDaniel Vetter * Returns: 22751a498633SDaniel Vetter * Zero on success, negative errno on failure. 22768cf5c917SJesse Barnes */ 22778cf5c917SJesse Barnes int drm_mode_getplane(struct drm_device *dev, void *data, 22788cf5c917SJesse Barnes struct drm_file *file_priv) 22798cf5c917SJesse Barnes { 22808cf5c917SJesse Barnes struct drm_mode_get_plane *plane_resp = data; 22818cf5c917SJesse Barnes struct drm_plane *plane; 22828cf5c917SJesse Barnes uint32_t __user *format_ptr; 22838cf5c917SJesse Barnes 22848cf5c917SJesse Barnes if (!drm_core_check_feature(dev, DRIVER_MODESET)) 22858cf5c917SJesse Barnes return -EINVAL; 22868cf5c917SJesse Barnes 2287a2b34e22SRob Clark plane = drm_plane_find(dev, plane_resp->plane_id); 2288fcf93f69SDaniel Vetter if (!plane) 2289fcf93f69SDaniel Vetter return -ENOENT; 22908cf5c917SJesse Barnes 2291fcf93f69SDaniel Vetter drm_modeset_lock(&plane->mutex, NULL); 22928cf5c917SJesse Barnes if (plane->crtc) 22938cf5c917SJesse Barnes plane_resp->crtc_id = plane->crtc->base.id; 22948cf5c917SJesse Barnes else 22958cf5c917SJesse Barnes plane_resp->crtc_id = 0; 22968cf5c917SJesse Barnes 22978cf5c917SJesse Barnes if (plane->fb) 22988cf5c917SJesse Barnes plane_resp->fb_id = plane->fb->base.id; 22998cf5c917SJesse Barnes else 23008cf5c917SJesse Barnes plane_resp->fb_id = 0; 2301fcf93f69SDaniel Vetter drm_modeset_unlock(&plane->mutex); 23028cf5c917SJesse Barnes 23038cf5c917SJesse Barnes plane_resp->plane_id = plane->base.id; 23048cf5c917SJesse Barnes plane_resp->possible_crtcs = plane->possible_crtcs; 2305778ad903SVille Syrjälä plane_resp->gamma_size = 0; 23068cf5c917SJesse Barnes 23078cf5c917SJesse Barnes /* 23088cf5c917SJesse Barnes * This ioctl is called twice, once to determine how much space is 23098cf5c917SJesse Barnes * needed, and the 2nd time to fill it. 23108cf5c917SJesse Barnes */ 23118cf5c917SJesse Barnes if (plane->format_count && 23128cf5c917SJesse Barnes (plane_resp->count_format_types >= plane->format_count)) { 231381f6c7f8SVille Syrjälä format_ptr = (uint32_t __user *)(unsigned long)plane_resp->format_type_ptr; 23148cf5c917SJesse Barnes if (copy_to_user(format_ptr, 23158cf5c917SJesse Barnes plane->format_types, 23168cf5c917SJesse Barnes sizeof(uint32_t) * plane->format_count)) { 2317fcf93f69SDaniel Vetter return -EFAULT; 23188cf5c917SJesse Barnes } 23198cf5c917SJesse Barnes } 23208cf5c917SJesse Barnes plane_resp->count_format_types = plane->format_count; 23218cf5c917SJesse Barnes 2322baf698b0SDaniel Vetter return 0; 23238cf5c917SJesse Barnes } 23248cf5c917SJesse Barnes 2325b36552b3SMatt Roper /* 2326b36552b3SMatt Roper * setplane_internal - setplane handler for internal callers 23278cf5c917SJesse Barnes * 2328b36552b3SMatt Roper * Note that we assume an extra reference has already been taken on fb. If the 2329b36552b3SMatt Roper * update fails, this reference will be dropped before return; if it succeeds, 2330b36552b3SMatt Roper * the previous framebuffer (if any) will be unreferenced instead. 2331c8e32cc1SDaniel Vetter * 2332b36552b3SMatt Roper * src_{x,y,w,h} are provided in 16.16 fixed point format 23338cf5c917SJesse Barnes */ 2334f2b50c11SDaniel Vetter static int __setplane_internal(struct drm_plane *plane, 233517cfd91fSChris Wilson struct drm_crtc *crtc, 2336b36552b3SMatt Roper struct drm_framebuffer *fb, 2337b36552b3SMatt Roper int32_t crtc_x, int32_t crtc_y, 2338b36552b3SMatt Roper uint32_t crtc_w, uint32_t crtc_h, 2339b36552b3SMatt Roper /* src_{x,y,w,h} values are 16.16 fixed point */ 2340b36552b3SMatt Roper uint32_t src_x, uint32_t src_y, 2341b36552b3SMatt Roper uint32_t src_w, uint32_t src_h) 23428cf5c917SJesse Barnes { 23438cf5c917SJesse Barnes int ret = 0; 234442ef8789SVille Syrjälä unsigned int fb_width, fb_height; 23452f763312SThierry Reding unsigned int i; 23468cf5c917SJesse Barnes 23478cf5c917SJesse Barnes /* No fb means shut it down */ 2348b36552b3SMatt Roper if (!fb) { 23493d30a59bSDaniel Vetter plane->old_fb = plane->fb; 2350731cce48SDaniel Vetter ret = plane->funcs->disable_plane(plane); 2351731cce48SDaniel Vetter if (!ret) { 2352e5e3b44cSVille Syrjälä plane->crtc = NULL; 2353e5e3b44cSVille Syrjälä plane->fb = NULL; 2354731cce48SDaniel Vetter } else { 23553d30a59bSDaniel Vetter plane->old_fb = NULL; 2356731cce48SDaniel Vetter } 23578cf5c917SJesse Barnes goto out; 23588cf5c917SJesse Barnes } 23598cf5c917SJesse Barnes 23607f994f3fSMatt Roper /* Check whether this plane is usable on this CRTC */ 23617f994f3fSMatt Roper if (!(plane->possible_crtcs & drm_crtc_mask(crtc))) { 23627f994f3fSMatt Roper DRM_DEBUG_KMS("Invalid crtc for plane\n"); 23637f994f3fSMatt Roper ret = -EINVAL; 23647f994f3fSMatt Roper goto out; 23657f994f3fSMatt Roper } 23667f994f3fSMatt Roper 236762443be6SVille Syrjälä /* Check whether this plane supports the fb pixel format. */ 236862443be6SVille Syrjälä for (i = 0; i < plane->format_count; i++) 236962443be6SVille Syrjälä if (fb->pixel_format == plane->format_types[i]) 237062443be6SVille Syrjälä break; 237162443be6SVille Syrjälä if (i == plane->format_count) { 23726ba6d03eSVille Syrjälä DRM_DEBUG_KMS("Invalid pixel format %s\n", 23736ba6d03eSVille Syrjälä drm_get_format_name(fb->pixel_format)); 237462443be6SVille Syrjälä ret = -EINVAL; 237562443be6SVille Syrjälä goto out; 237662443be6SVille Syrjälä } 237762443be6SVille Syrjälä 237842ef8789SVille Syrjälä fb_width = fb->width << 16; 237942ef8789SVille Syrjälä fb_height = fb->height << 16; 238042ef8789SVille Syrjälä 238142ef8789SVille Syrjälä /* Make sure source coordinates are inside the fb. */ 2382b36552b3SMatt Roper if (src_w > fb_width || 2383b36552b3SMatt Roper src_x > fb_width - src_w || 2384b36552b3SMatt Roper src_h > fb_height || 2385b36552b3SMatt Roper src_y > fb_height - src_h) { 238642ef8789SVille Syrjälä DRM_DEBUG_KMS("Invalid source coordinates " 238742ef8789SVille Syrjälä "%u.%06ux%u.%06u+%u.%06u+%u.%06u\n", 2388b36552b3SMatt Roper src_w >> 16, ((src_w & 0xffff) * 15625) >> 10, 2389b36552b3SMatt Roper src_h >> 16, ((src_h & 0xffff) * 15625) >> 10, 2390b36552b3SMatt Roper src_x >> 16, ((src_x & 0xffff) * 15625) >> 10, 2391b36552b3SMatt Roper src_y >> 16, ((src_y & 0xffff) * 15625) >> 10); 239242ef8789SVille Syrjälä ret = -ENOSPC; 239342ef8789SVille Syrjälä goto out; 239442ef8789SVille Syrjälä } 239542ef8789SVille Syrjälä 23963d30a59bSDaniel Vetter plane->old_fb = plane->fb; 23978cf5c917SJesse Barnes ret = plane->funcs->update_plane(plane, crtc, fb, 2398b36552b3SMatt Roper crtc_x, crtc_y, crtc_w, crtc_h, 2399b36552b3SMatt Roper src_x, src_y, src_w, src_h); 24008cf5c917SJesse Barnes if (!ret) { 24018cf5c917SJesse Barnes plane->crtc = crtc; 24028cf5c917SJesse Barnes plane->fb = fb; 240335f8badcSDaniel Vetter fb = NULL; 24040fe27f06SDaniel Vetter } else { 24053d30a59bSDaniel Vetter plane->old_fb = NULL; 24068cf5c917SJesse Barnes } 24078cf5c917SJesse Barnes 24088cf5c917SJesse Barnes out: 24096c2a7532SDaniel Vetter if (fb) 24106c2a7532SDaniel Vetter drm_framebuffer_unreference(fb); 24113d30a59bSDaniel Vetter if (plane->old_fb) 24123d30a59bSDaniel Vetter drm_framebuffer_unreference(plane->old_fb); 24133d30a59bSDaniel Vetter plane->old_fb = NULL; 24148cf5c917SJesse Barnes 24158cf5c917SJesse Barnes return ret; 2416f2b50c11SDaniel Vetter } 2417b36552b3SMatt Roper 2418f2b50c11SDaniel Vetter static int setplane_internal(struct drm_plane *plane, 2419f2b50c11SDaniel Vetter struct drm_crtc *crtc, 2420f2b50c11SDaniel Vetter struct drm_framebuffer *fb, 2421f2b50c11SDaniel Vetter int32_t crtc_x, int32_t crtc_y, 2422f2b50c11SDaniel Vetter uint32_t crtc_w, uint32_t crtc_h, 2423f2b50c11SDaniel Vetter /* src_{x,y,w,h} values are 16.16 fixed point */ 2424f2b50c11SDaniel Vetter uint32_t src_x, uint32_t src_y, 2425f2b50c11SDaniel Vetter uint32_t src_w, uint32_t src_h) 2426f2b50c11SDaniel Vetter { 2427f2b50c11SDaniel Vetter int ret; 2428f2b50c11SDaniel Vetter 2429f2b50c11SDaniel Vetter drm_modeset_lock_all(plane->dev); 2430f2b50c11SDaniel Vetter ret = __setplane_internal(plane, crtc, fb, 2431f2b50c11SDaniel Vetter crtc_x, crtc_y, crtc_w, crtc_h, 2432f2b50c11SDaniel Vetter src_x, src_y, src_w, src_h); 2433f2b50c11SDaniel Vetter drm_modeset_unlock_all(plane->dev); 2434f2b50c11SDaniel Vetter 2435f2b50c11SDaniel Vetter return ret; 2436b36552b3SMatt Roper } 2437b36552b3SMatt Roper 2438b36552b3SMatt Roper /** 2439b36552b3SMatt Roper * drm_mode_setplane - configure a plane's configuration 2440b36552b3SMatt Roper * @dev: DRM device 2441b36552b3SMatt Roper * @data: ioctl data* 2442b36552b3SMatt Roper * @file_priv: DRM file info 2443b36552b3SMatt Roper * 2444b36552b3SMatt Roper * Set plane configuration, including placement, fb, scaling, and other factors. 2445b36552b3SMatt Roper * Or pass a NULL fb to disable (planes may be disabled without providing a 2446b36552b3SMatt Roper * valid crtc). 2447b36552b3SMatt Roper * 2448b36552b3SMatt Roper * Returns: 24491a498633SDaniel Vetter * Zero on success, negative errno on failure. 2450b36552b3SMatt Roper */ 2451b36552b3SMatt Roper int drm_mode_setplane(struct drm_device *dev, void *data, 2452b36552b3SMatt Roper struct drm_file *file_priv) 2453b36552b3SMatt Roper { 2454b36552b3SMatt Roper struct drm_mode_set_plane *plane_req = data; 2455b36552b3SMatt Roper struct drm_plane *plane; 2456b36552b3SMatt Roper struct drm_crtc *crtc = NULL; 2457b36552b3SMatt Roper struct drm_framebuffer *fb = NULL; 2458b36552b3SMatt Roper 2459b36552b3SMatt Roper if (!drm_core_check_feature(dev, DRIVER_MODESET)) 2460b36552b3SMatt Roper return -EINVAL; 2461b36552b3SMatt Roper 2462b36552b3SMatt Roper /* Give drivers some help against integer overflows */ 2463b36552b3SMatt Roper if (plane_req->crtc_w > INT_MAX || 2464b36552b3SMatt Roper plane_req->crtc_x > INT_MAX - (int32_t) plane_req->crtc_w || 2465b36552b3SMatt Roper plane_req->crtc_h > INT_MAX || 2466b36552b3SMatt Roper plane_req->crtc_y > INT_MAX - (int32_t) plane_req->crtc_h) { 2467b36552b3SMatt Roper DRM_DEBUG_KMS("Invalid CRTC coordinates %ux%u+%d+%d\n", 2468b36552b3SMatt Roper plane_req->crtc_w, plane_req->crtc_h, 2469b36552b3SMatt Roper plane_req->crtc_x, plane_req->crtc_y); 2470b36552b3SMatt Roper return -ERANGE; 2471b36552b3SMatt Roper } 2472b36552b3SMatt Roper 2473b36552b3SMatt Roper /* 2474b36552b3SMatt Roper * First, find the plane, crtc, and fb objects. If not available, 2475b36552b3SMatt Roper * we don't bother to call the driver. 2476b36552b3SMatt Roper */ 2477933f622fSRob Clark plane = drm_plane_find(dev, plane_req->plane_id); 2478933f622fSRob Clark if (!plane) { 2479b36552b3SMatt Roper DRM_DEBUG_KMS("Unknown plane ID %d\n", 2480b36552b3SMatt Roper plane_req->plane_id); 2481b36552b3SMatt Roper return -ENOENT; 2482b36552b3SMatt Roper } 2483b36552b3SMatt Roper 2484b36552b3SMatt Roper if (plane_req->fb_id) { 2485b36552b3SMatt Roper fb = drm_framebuffer_lookup(dev, plane_req->fb_id); 2486b36552b3SMatt Roper if (!fb) { 2487b36552b3SMatt Roper DRM_DEBUG_KMS("Unknown framebuffer ID %d\n", 2488b36552b3SMatt Roper plane_req->fb_id); 2489b36552b3SMatt Roper return -ENOENT; 2490b36552b3SMatt Roper } 2491b36552b3SMatt Roper 2492933f622fSRob Clark crtc = drm_crtc_find(dev, plane_req->crtc_id); 2493933f622fSRob Clark if (!crtc) { 2494b36552b3SMatt Roper DRM_DEBUG_KMS("Unknown crtc ID %d\n", 2495b36552b3SMatt Roper plane_req->crtc_id); 2496b36552b3SMatt Roper return -ENOENT; 2497b36552b3SMatt Roper } 2498b36552b3SMatt Roper } 2499b36552b3SMatt Roper 2500161d0dc1SMatt Roper /* 2501161d0dc1SMatt Roper * setplane_internal will take care of deref'ing either the old or new 2502161d0dc1SMatt Roper * framebuffer depending on success. 2503161d0dc1SMatt Roper */ 250417cfd91fSChris Wilson return setplane_internal(plane, crtc, fb, 2505b36552b3SMatt Roper plane_req->crtc_x, plane_req->crtc_y, 2506b36552b3SMatt Roper plane_req->crtc_w, plane_req->crtc_h, 2507b36552b3SMatt Roper plane_req->src_x, plane_req->src_y, 2508b36552b3SMatt Roper plane_req->src_w, plane_req->src_h); 25098cf5c917SJesse Barnes } 25108cf5c917SJesse Barnes 25118cf5c917SJesse Barnes /** 25122d13b679SDaniel Vetter * drm_mode_set_config_internal - helper to call ->set_config 25132d13b679SDaniel Vetter * @set: modeset config to set 25142d13b679SDaniel Vetter * 25152d13b679SDaniel Vetter * This is a little helper to wrap internal calls to the ->set_config driver 25162d13b679SDaniel Vetter * interface. The only thing it adds is correct refcounting dance. 2517c8e32cc1SDaniel Vetter * 2518c8e32cc1SDaniel Vetter * Returns: 25191a498633SDaniel Vetter * Zero on success, negative errno on failure. 25202d13b679SDaniel Vetter */ 25212d13b679SDaniel Vetter int drm_mode_set_config_internal(struct drm_mode_set *set) 25222d13b679SDaniel Vetter { 25232d13b679SDaniel Vetter struct drm_crtc *crtc = set->crtc; 25245cef29aaSDaniel Vetter struct drm_framebuffer *fb; 25255cef29aaSDaniel Vetter struct drm_crtc *tmp; 2526b0d12325SDaniel Vetter int ret; 25272d13b679SDaniel Vetter 25285cef29aaSDaniel Vetter /* 25295cef29aaSDaniel Vetter * NOTE: ->set_config can also disable other crtcs (if we steal all 25305cef29aaSDaniel Vetter * connectors from it), hence we need to refcount the fbs across all 25315cef29aaSDaniel Vetter * crtcs. Atomic modeset will have saner semantics ... 25325cef29aaSDaniel Vetter */ 25335cef29aaSDaniel Vetter list_for_each_entry(tmp, &crtc->dev->mode_config.crtc_list, head) 25343d30a59bSDaniel Vetter tmp->primary->old_fb = tmp->primary->fb; 25355cef29aaSDaniel Vetter 2536b0d12325SDaniel Vetter fb = set->fb; 2537b0d12325SDaniel Vetter 2538b0d12325SDaniel Vetter ret = crtc->funcs->set_config(set); 2539b0d12325SDaniel Vetter if (ret == 0) { 2540e13161afSMatt Roper crtc->primary->crtc = crtc; 25410fe27f06SDaniel Vetter crtc->primary->fb = fb; 25425cef29aaSDaniel Vetter } 2543cc85e121SDaniel Vetter 25445cef29aaSDaniel Vetter list_for_each_entry(tmp, &crtc->dev->mode_config.crtc_list, head) { 2545f4510a27SMatt Roper if (tmp->primary->fb) 2546f4510a27SMatt Roper drm_framebuffer_reference(tmp->primary->fb); 25473d30a59bSDaniel Vetter if (tmp->primary->old_fb) 25483d30a59bSDaniel Vetter drm_framebuffer_unreference(tmp->primary->old_fb); 25493d30a59bSDaniel Vetter tmp->primary->old_fb = NULL; 2550b0d12325SDaniel Vetter } 2551b0d12325SDaniel Vetter 2552b0d12325SDaniel Vetter return ret; 25532d13b679SDaniel Vetter } 25542d13b679SDaniel Vetter EXPORT_SYMBOL(drm_mode_set_config_internal); 25552d13b679SDaniel Vetter 2556af93629dSMatt Roper /** 2557af93629dSMatt Roper * drm_crtc_check_viewport - Checks that a framebuffer is big enough for the 2558af93629dSMatt Roper * CRTC viewport 2559af93629dSMatt Roper * @crtc: CRTC that framebuffer will be displayed on 2560af93629dSMatt Roper * @x: x panning 2561af93629dSMatt Roper * @y: y panning 2562af93629dSMatt Roper * @mode: mode that framebuffer will be displayed under 2563af93629dSMatt Roper * @fb: framebuffer to check size of 2564c11e9283SDamien Lespiau */ 2565af93629dSMatt Roper int drm_crtc_check_viewport(const struct drm_crtc *crtc, 2566c11e9283SDamien Lespiau int x, int y, 2567c11e9283SDamien Lespiau const struct drm_display_mode *mode, 2568c11e9283SDamien Lespiau const struct drm_framebuffer *fb) 2569c11e9283SDamien Lespiau 2570c11e9283SDamien Lespiau { 2571c11e9283SDamien Lespiau int hdisplay, vdisplay; 2572c11e9283SDamien Lespiau 2573c11e9283SDamien Lespiau hdisplay = mode->hdisplay; 2574c11e9283SDamien Lespiau vdisplay = mode->vdisplay; 2575c11e9283SDamien Lespiau 2576a0c1bbb0SDamien Lespiau if (drm_mode_is_stereo(mode)) { 2577a0c1bbb0SDamien Lespiau struct drm_display_mode adjusted = *mode; 2578a0c1bbb0SDamien Lespiau 2579a0c1bbb0SDamien Lespiau drm_mode_set_crtcinfo(&adjusted, CRTC_STEREO_DOUBLE); 2580a0c1bbb0SDamien Lespiau hdisplay = adjusted.crtc_hdisplay; 2581a0c1bbb0SDamien Lespiau vdisplay = adjusted.crtc_vdisplay; 2582a0c1bbb0SDamien Lespiau } 2583a0c1bbb0SDamien Lespiau 2584c11e9283SDamien Lespiau if (crtc->invert_dimensions) 2585c11e9283SDamien Lespiau swap(hdisplay, vdisplay); 2586c11e9283SDamien Lespiau 2587c11e9283SDamien Lespiau if (hdisplay > fb->width || 2588c11e9283SDamien Lespiau vdisplay > fb->height || 2589c11e9283SDamien Lespiau x > fb->width - hdisplay || 2590c11e9283SDamien Lespiau y > fb->height - vdisplay) { 2591c11e9283SDamien Lespiau DRM_DEBUG_KMS("Invalid fb size %ux%u for CRTC viewport %ux%u+%d+%d%s.\n", 2592c11e9283SDamien Lespiau fb->width, fb->height, hdisplay, vdisplay, x, y, 2593c11e9283SDamien Lespiau crtc->invert_dimensions ? " (inverted)" : ""); 2594c11e9283SDamien Lespiau return -ENOSPC; 2595c11e9283SDamien Lespiau } 2596c11e9283SDamien Lespiau 2597c11e9283SDamien Lespiau return 0; 2598c11e9283SDamien Lespiau } 2599af93629dSMatt Roper EXPORT_SYMBOL(drm_crtc_check_viewport); 2600c11e9283SDamien Lespiau 26012d13b679SDaniel Vetter /** 2602f453ba04SDave Airlie * drm_mode_setcrtc - set CRTC configuration 2603065a50edSDaniel Vetter * @dev: drm device for the ioctl 2604065a50edSDaniel Vetter * @data: data pointer for the ioctl 2605065a50edSDaniel Vetter * @file_priv: drm file for the ioctl call 2606f453ba04SDave Airlie * 2607f453ba04SDave Airlie * Build a new CRTC configuration based on user request. 2608f453ba04SDave Airlie * 2609f453ba04SDave Airlie * Called by the user via ioctl. 2610f453ba04SDave Airlie * 2611c8e32cc1SDaniel Vetter * Returns: 26121a498633SDaniel Vetter * Zero on success, negative errno on failure. 2613f453ba04SDave Airlie */ 2614f453ba04SDave Airlie int drm_mode_setcrtc(struct drm_device *dev, void *data, 2615f453ba04SDave Airlie struct drm_file *file_priv) 2616f453ba04SDave Airlie { 2617f453ba04SDave Airlie struct drm_mode_config *config = &dev->mode_config; 2618f453ba04SDave Airlie struct drm_mode_crtc *crtc_req = data; 26196653cc8dSVille Syrjälä struct drm_crtc *crtc; 2620f453ba04SDave Airlie struct drm_connector **connector_set = NULL, *connector; 2621f453ba04SDave Airlie struct drm_framebuffer *fb = NULL; 2622f453ba04SDave Airlie struct drm_display_mode *mode = NULL; 2623f453ba04SDave Airlie struct drm_mode_set set; 2624f453ba04SDave Airlie uint32_t __user *set_connectors_ptr; 26254a1b0714SLaurent Pinchart int ret; 2626f453ba04SDave Airlie int i; 2627f453ba04SDave Airlie 2628fb3b06c8SDave Airlie if (!drm_core_check_feature(dev, DRIVER_MODESET)) 2629fb3b06c8SDave Airlie return -EINVAL; 2630fb3b06c8SDave Airlie 26311d97e915SVille Syrjälä /* For some reason crtc x/y offsets are signed internally. */ 26321d97e915SVille Syrjälä if (crtc_req->x > INT_MAX || crtc_req->y > INT_MAX) 26331d97e915SVille Syrjälä return -ERANGE; 26341d97e915SVille Syrjälä 263584849903SDaniel Vetter drm_modeset_lock_all(dev); 2636a2b34e22SRob Clark crtc = drm_crtc_find(dev, crtc_req->crtc_id); 2637a2b34e22SRob Clark if (!crtc) { 263858367ed6SZhao Yakui DRM_DEBUG_KMS("Unknown CRTC ID %d\n", crtc_req->crtc_id); 2639f27657f2SVille Syrjälä ret = -ENOENT; 2640f453ba04SDave Airlie goto out; 2641f453ba04SDave Airlie } 26429440106bSJerome Glisse DRM_DEBUG_KMS("[CRTC:%d]\n", crtc->base.id); 2643f453ba04SDave Airlie 2644f453ba04SDave Airlie if (crtc_req->mode_valid) { 2645f453ba04SDave Airlie /* If we have a mode we need a framebuffer. */ 2646f453ba04SDave Airlie /* If we pass -1, set the mode with the currently bound fb */ 2647f453ba04SDave Airlie if (crtc_req->fb_id == -1) { 2648f4510a27SMatt Roper if (!crtc->primary->fb) { 26496653cc8dSVille Syrjälä DRM_DEBUG_KMS("CRTC doesn't have current FB\n"); 26506653cc8dSVille Syrjälä ret = -EINVAL; 26516653cc8dSVille Syrjälä goto out; 26526653cc8dSVille Syrjälä } 2653f4510a27SMatt Roper fb = crtc->primary->fb; 2654b0d12325SDaniel Vetter /* Make refcounting symmetric with the lookup path. */ 2655b0d12325SDaniel Vetter drm_framebuffer_reference(fb); 2656f453ba04SDave Airlie } else { 2657786b99edSDaniel Vetter fb = drm_framebuffer_lookup(dev, crtc_req->fb_id); 2658786b99edSDaniel Vetter if (!fb) { 265958367ed6SZhao Yakui DRM_DEBUG_KMS("Unknown FB ID%d\n", 266058367ed6SZhao Yakui crtc_req->fb_id); 266137c4e705SVille Syrjälä ret = -ENOENT; 2662f453ba04SDave Airlie goto out; 2663f453ba04SDave Airlie } 2664f453ba04SDave Airlie } 2665f453ba04SDave Airlie 2666f453ba04SDave Airlie mode = drm_mode_create(dev); 2667ee34ab5bSVille Syrjälä if (!mode) { 2668ee34ab5bSVille Syrjälä ret = -ENOMEM; 2669ee34ab5bSVille Syrjälä goto out; 2670ee34ab5bSVille Syrjälä } 2671ee34ab5bSVille Syrjälä 267290367bf6SVille Syrjälä ret = drm_crtc_convert_umode(mode, &crtc_req->mode); 267390367bf6SVille Syrjälä if (ret) { 267490367bf6SVille Syrjälä DRM_DEBUG_KMS("Invalid mode\n"); 267590367bf6SVille Syrjälä goto out; 267690367bf6SVille Syrjälä } 267790367bf6SVille Syrjälä 2678f453ba04SDave Airlie drm_mode_set_crtcinfo(mode, CRTC_INTERLACE_HALVE_V); 26795f61bb42SVille Syrjälä 2680c11e9283SDamien Lespiau ret = drm_crtc_check_viewport(crtc, crtc_req->x, crtc_req->y, 2681c11e9283SDamien Lespiau mode, fb); 2682c11e9283SDamien Lespiau if (ret) 26835f61bb42SVille Syrjälä goto out; 2684c11e9283SDamien Lespiau 2685f453ba04SDave Airlie } 2686f453ba04SDave Airlie 2687f453ba04SDave Airlie if (crtc_req->count_connectors == 0 && mode) { 268858367ed6SZhao Yakui DRM_DEBUG_KMS("Count connectors is 0 but mode set\n"); 2689f453ba04SDave Airlie ret = -EINVAL; 2690f453ba04SDave Airlie goto out; 2691f453ba04SDave Airlie } 2692f453ba04SDave Airlie 26937781de74SJakob Bornecrantz if (crtc_req->count_connectors > 0 && (!mode || !fb)) { 269458367ed6SZhao Yakui DRM_DEBUG_KMS("Count connectors is %d but no mode or fb set\n", 2695f453ba04SDave Airlie crtc_req->count_connectors); 2696f453ba04SDave Airlie ret = -EINVAL; 2697f453ba04SDave Airlie goto out; 2698f453ba04SDave Airlie } 2699f453ba04SDave Airlie 2700f453ba04SDave Airlie if (crtc_req->count_connectors > 0) { 2701f453ba04SDave Airlie u32 out_id; 2702f453ba04SDave Airlie 2703f453ba04SDave Airlie /* Avoid unbounded kernel memory allocation */ 2704f453ba04SDave Airlie if (crtc_req->count_connectors > config->num_connector) { 2705f453ba04SDave Airlie ret = -EINVAL; 2706f453ba04SDave Airlie goto out; 2707f453ba04SDave Airlie } 2708f453ba04SDave Airlie 27092f6c5389SThierry Reding connector_set = kmalloc_array(crtc_req->count_connectors, 2710f453ba04SDave Airlie sizeof(struct drm_connector *), 2711f453ba04SDave Airlie GFP_KERNEL); 2712f453ba04SDave Airlie if (!connector_set) { 2713f453ba04SDave Airlie ret = -ENOMEM; 2714f453ba04SDave Airlie goto out; 2715f453ba04SDave Airlie } 2716f453ba04SDave Airlie 2717f453ba04SDave Airlie for (i = 0; i < crtc_req->count_connectors; i++) { 271881f6c7f8SVille Syrjälä set_connectors_ptr = (uint32_t __user *)(unsigned long)crtc_req->set_connectors_ptr; 2719f453ba04SDave Airlie if (get_user(out_id, &set_connectors_ptr[i])) { 2720f453ba04SDave Airlie ret = -EFAULT; 2721f453ba04SDave Airlie goto out; 2722f453ba04SDave Airlie } 2723f453ba04SDave Airlie 2724a2b34e22SRob Clark connector = drm_connector_find(dev, out_id); 2725a2b34e22SRob Clark if (!connector) { 272658367ed6SZhao Yakui DRM_DEBUG_KMS("Connector id %d unknown\n", 272758367ed6SZhao Yakui out_id); 2728f27657f2SVille Syrjälä ret = -ENOENT; 2729f453ba04SDave Airlie goto out; 2730f453ba04SDave Airlie } 27319440106bSJerome Glisse DRM_DEBUG_KMS("[CONNECTOR:%d:%s]\n", 27329440106bSJerome Glisse connector->base.id, 273325933820SJani Nikula connector->name); 2734f453ba04SDave Airlie 2735f453ba04SDave Airlie connector_set[i] = connector; 2736f453ba04SDave Airlie } 2737f453ba04SDave Airlie } 2738f453ba04SDave Airlie 2739f453ba04SDave Airlie set.crtc = crtc; 2740f453ba04SDave Airlie set.x = crtc_req->x; 2741f453ba04SDave Airlie set.y = crtc_req->y; 2742f453ba04SDave Airlie set.mode = mode; 2743f453ba04SDave Airlie set.connectors = connector_set; 2744f453ba04SDave Airlie set.num_connectors = crtc_req->count_connectors; 2745f453ba04SDave Airlie set.fb = fb; 27462d13b679SDaniel Vetter ret = drm_mode_set_config_internal(&set); 2747f453ba04SDave Airlie 2748f453ba04SDave Airlie out: 2749b0d12325SDaniel Vetter if (fb) 2750b0d12325SDaniel Vetter drm_framebuffer_unreference(fb); 2751b0d12325SDaniel Vetter 2752f453ba04SDave Airlie kfree(connector_set); 2753ee34ab5bSVille Syrjälä drm_mode_destroy(dev, mode); 275484849903SDaniel Vetter drm_modeset_unlock_all(dev); 2755f453ba04SDave Airlie return ret; 2756f453ba04SDave Airlie } 2757f453ba04SDave Airlie 2758161d0dc1SMatt Roper /** 2759161d0dc1SMatt Roper * drm_mode_cursor_universal - translate legacy cursor ioctl call into a 2760161d0dc1SMatt Roper * universal plane handler call 2761161d0dc1SMatt Roper * @crtc: crtc to update cursor for 2762161d0dc1SMatt Roper * @req: data pointer for the ioctl 2763161d0dc1SMatt Roper * @file_priv: drm file for the ioctl call 2764161d0dc1SMatt Roper * 2765161d0dc1SMatt Roper * Legacy cursor ioctl's work directly with driver buffer handles. To 2766161d0dc1SMatt Roper * translate legacy ioctl calls into universal plane handler calls, we need to 2767161d0dc1SMatt Roper * wrap the native buffer handle in a drm_framebuffer. 2768161d0dc1SMatt Roper * 2769161d0dc1SMatt Roper * Note that we assume any handle passed to the legacy ioctls was a 32-bit ARGB 2770161d0dc1SMatt Roper * buffer with a pitch of 4*width; the universal plane interface should be used 2771161d0dc1SMatt Roper * directly in cases where the hardware can support other buffer settings and 2772161d0dc1SMatt Roper * userspace wants to make use of these capabilities. 2773161d0dc1SMatt Roper * 2774161d0dc1SMatt Roper * Returns: 27751a498633SDaniel Vetter * Zero on success, negative errno on failure. 2776161d0dc1SMatt Roper */ 2777161d0dc1SMatt Roper static int drm_mode_cursor_universal(struct drm_crtc *crtc, 2778161d0dc1SMatt Roper struct drm_mode_cursor2 *req, 2779161d0dc1SMatt Roper struct drm_file *file_priv) 2780161d0dc1SMatt Roper { 2781161d0dc1SMatt Roper struct drm_device *dev = crtc->dev; 2782161d0dc1SMatt Roper struct drm_framebuffer *fb = NULL; 2783161d0dc1SMatt Roper struct drm_mode_fb_cmd2 fbreq = { 2784161d0dc1SMatt Roper .width = req->width, 2785161d0dc1SMatt Roper .height = req->height, 2786161d0dc1SMatt Roper .pixel_format = DRM_FORMAT_ARGB8888, 2787161d0dc1SMatt Roper .pitches = { req->width * 4 }, 2788161d0dc1SMatt Roper .handles = { req->handle }, 2789161d0dc1SMatt Roper }; 2790161d0dc1SMatt Roper int32_t crtc_x, crtc_y; 2791161d0dc1SMatt Roper uint32_t crtc_w = 0, crtc_h = 0; 2792161d0dc1SMatt Roper uint32_t src_w = 0, src_h = 0; 2793161d0dc1SMatt Roper int ret = 0; 2794161d0dc1SMatt Roper 2795161d0dc1SMatt Roper BUG_ON(!crtc->cursor); 2796f2b50c11SDaniel Vetter WARN_ON(crtc->cursor->crtc != crtc && crtc->cursor->crtc != NULL); 2797161d0dc1SMatt Roper 2798161d0dc1SMatt Roper /* 2799161d0dc1SMatt Roper * Obtain fb we'll be using (either new or existing) and take an extra 2800161d0dc1SMatt Roper * reference to it if fb != null. setplane will take care of dropping 2801161d0dc1SMatt Roper * the reference if the plane update fails. 2802161d0dc1SMatt Roper */ 2803161d0dc1SMatt Roper if (req->flags & DRM_MODE_CURSOR_BO) { 2804161d0dc1SMatt Roper if (req->handle) { 2805161d0dc1SMatt Roper fb = add_framebuffer_internal(dev, &fbreq, file_priv); 2806161d0dc1SMatt Roper if (IS_ERR(fb)) { 2807161d0dc1SMatt Roper DRM_DEBUG_KMS("failed to wrap cursor buffer in drm framebuffer\n"); 2808161d0dc1SMatt Roper return PTR_ERR(fb); 2809161d0dc1SMatt Roper } 2810161d0dc1SMatt Roper 2811161d0dc1SMatt Roper drm_framebuffer_reference(fb); 2812161d0dc1SMatt Roper } else { 2813161d0dc1SMatt Roper fb = NULL; 2814161d0dc1SMatt Roper } 2815161d0dc1SMatt Roper } else { 2816161d0dc1SMatt Roper fb = crtc->cursor->fb; 2817161d0dc1SMatt Roper if (fb) 2818161d0dc1SMatt Roper drm_framebuffer_reference(fb); 2819161d0dc1SMatt Roper } 2820161d0dc1SMatt Roper 2821161d0dc1SMatt Roper if (req->flags & DRM_MODE_CURSOR_MOVE) { 2822161d0dc1SMatt Roper crtc_x = req->x; 2823161d0dc1SMatt Roper crtc_y = req->y; 2824161d0dc1SMatt Roper } else { 2825161d0dc1SMatt Roper crtc_x = crtc->cursor_x; 2826161d0dc1SMatt Roper crtc_y = crtc->cursor_y; 2827161d0dc1SMatt Roper } 2828161d0dc1SMatt Roper 2829161d0dc1SMatt Roper if (fb) { 2830161d0dc1SMatt Roper crtc_w = fb->width; 2831161d0dc1SMatt Roper crtc_h = fb->height; 2832161d0dc1SMatt Roper src_w = fb->width << 16; 2833161d0dc1SMatt Roper src_h = fb->height << 16; 2834161d0dc1SMatt Roper } 2835161d0dc1SMatt Roper 2836161d0dc1SMatt Roper /* 2837161d0dc1SMatt Roper * setplane_internal will take care of deref'ing either the old or new 2838161d0dc1SMatt Roper * framebuffer depending on success. 2839161d0dc1SMatt Roper */ 2840f2b50c11SDaniel Vetter ret = __setplane_internal(crtc->cursor, crtc, fb, 2841161d0dc1SMatt Roper crtc_x, crtc_y, crtc_w, crtc_h, 2842161d0dc1SMatt Roper 0, 0, src_w, src_h); 2843161d0dc1SMatt Roper 2844161d0dc1SMatt Roper /* Update successful; save new cursor position, if necessary */ 2845161d0dc1SMatt Roper if (ret == 0 && req->flags & DRM_MODE_CURSOR_MOVE) { 2846161d0dc1SMatt Roper crtc->cursor_x = req->x; 2847161d0dc1SMatt Roper crtc->cursor_y = req->y; 2848161d0dc1SMatt Roper } 2849161d0dc1SMatt Roper 2850161d0dc1SMatt Roper return ret; 2851161d0dc1SMatt Roper } 2852161d0dc1SMatt Roper 28534c813d4dSDave Airlie static int drm_mode_cursor_common(struct drm_device *dev, 28544c813d4dSDave Airlie struct drm_mode_cursor2 *req, 28554c813d4dSDave Airlie struct drm_file *file_priv) 2856f453ba04SDave Airlie { 2857f453ba04SDave Airlie struct drm_crtc *crtc; 2858f453ba04SDave Airlie int ret = 0; 2859f453ba04SDave Airlie 2860fb3b06c8SDave Airlie if (!drm_core_check_feature(dev, DRIVER_MODESET)) 2861fb3b06c8SDave Airlie return -EINVAL; 2862fb3b06c8SDave Airlie 28637c4eaca4SJakob Bornecrantz if (!req->flags || (~DRM_MODE_CURSOR_FLAGS & req->flags)) 2864f453ba04SDave Airlie return -EINVAL; 2865f453ba04SDave Airlie 2866a2b34e22SRob Clark crtc = drm_crtc_find(dev, req->crtc_id); 2867a2b34e22SRob Clark if (!crtc) { 286858367ed6SZhao Yakui DRM_DEBUG_KMS("Unknown CRTC ID %d\n", req->crtc_id); 2869f27657f2SVille Syrjälä return -ENOENT; 2870f453ba04SDave Airlie } 2871f453ba04SDave Airlie 2872161d0dc1SMatt Roper /* 2873161d0dc1SMatt Roper * If this crtc has a universal cursor plane, call that plane's update 2874161d0dc1SMatt Roper * handler rather than using legacy cursor handlers. 2875161d0dc1SMatt Roper */ 28764d02e2deSDaniel Vetter drm_modeset_lock_crtc(crtc, crtc->cursor); 2877f2b50c11SDaniel Vetter if (crtc->cursor) { 2878f2b50c11SDaniel Vetter ret = drm_mode_cursor_universal(crtc, req, file_priv); 2879f2b50c11SDaniel Vetter goto out; 2880f2b50c11SDaniel Vetter } 2881f2b50c11SDaniel Vetter 2882f453ba04SDave Airlie if (req->flags & DRM_MODE_CURSOR_BO) { 28834c813d4dSDave Airlie if (!crtc->funcs->cursor_set && !crtc->funcs->cursor_set2) { 2884f453ba04SDave Airlie ret = -ENXIO; 2885f453ba04SDave Airlie goto out; 2886f453ba04SDave Airlie } 2887f453ba04SDave Airlie /* Turns off the cursor if handle is 0 */ 28884c813d4dSDave Airlie if (crtc->funcs->cursor_set2) 28894c813d4dSDave Airlie ret = crtc->funcs->cursor_set2(crtc, file_priv, req->handle, 28904c813d4dSDave Airlie req->width, req->height, req->hot_x, req->hot_y); 28914c813d4dSDave Airlie else 2892f453ba04SDave Airlie ret = crtc->funcs->cursor_set(crtc, file_priv, req->handle, 2893f453ba04SDave Airlie req->width, req->height); 2894f453ba04SDave Airlie } 2895f453ba04SDave Airlie 2896f453ba04SDave Airlie if (req->flags & DRM_MODE_CURSOR_MOVE) { 2897f453ba04SDave Airlie if (crtc->funcs->cursor_move) { 2898f453ba04SDave Airlie ret = crtc->funcs->cursor_move(crtc, req->x, req->y); 2899f453ba04SDave Airlie } else { 2900f453ba04SDave Airlie ret = -EFAULT; 2901f453ba04SDave Airlie goto out; 2902f453ba04SDave Airlie } 2903f453ba04SDave Airlie } 2904f453ba04SDave Airlie out: 2905d059f652SDaniel Vetter drm_modeset_unlock_crtc(crtc); 2906dac35663SDaniel Vetter 2907f453ba04SDave Airlie return ret; 29084c813d4dSDave Airlie 29094c813d4dSDave Airlie } 2910c8e32cc1SDaniel Vetter 2911c8e32cc1SDaniel Vetter 2912c8e32cc1SDaniel Vetter /** 2913c8e32cc1SDaniel Vetter * drm_mode_cursor_ioctl - set CRTC's cursor configuration 2914c8e32cc1SDaniel Vetter * @dev: drm device for the ioctl 2915c8e32cc1SDaniel Vetter * @data: data pointer for the ioctl 2916c8e32cc1SDaniel Vetter * @file_priv: drm file for the ioctl call 2917c8e32cc1SDaniel Vetter * 2918c8e32cc1SDaniel Vetter * Set the cursor configuration based on user request. 2919c8e32cc1SDaniel Vetter * 2920c8e32cc1SDaniel Vetter * Called by the user via ioctl. 2921c8e32cc1SDaniel Vetter * 2922c8e32cc1SDaniel Vetter * Returns: 29231a498633SDaniel Vetter * Zero on success, negative errno on failure. 2924c8e32cc1SDaniel Vetter */ 29254c813d4dSDave Airlie int drm_mode_cursor_ioctl(struct drm_device *dev, 29264c813d4dSDave Airlie void *data, struct drm_file *file_priv) 29274c813d4dSDave Airlie { 29284c813d4dSDave Airlie struct drm_mode_cursor *req = data; 29294c813d4dSDave Airlie struct drm_mode_cursor2 new_req; 29304c813d4dSDave Airlie 29314c813d4dSDave Airlie memcpy(&new_req, req, sizeof(struct drm_mode_cursor)); 29324c813d4dSDave Airlie new_req.hot_x = new_req.hot_y = 0; 29334c813d4dSDave Airlie 29344c813d4dSDave Airlie return drm_mode_cursor_common(dev, &new_req, file_priv); 29354c813d4dSDave Airlie } 29364c813d4dSDave Airlie 2937c8e32cc1SDaniel Vetter /** 2938c8e32cc1SDaniel Vetter * drm_mode_cursor2_ioctl - set CRTC's cursor configuration 2939c8e32cc1SDaniel Vetter * @dev: drm device for the ioctl 2940c8e32cc1SDaniel Vetter * @data: data pointer for the ioctl 2941c8e32cc1SDaniel Vetter * @file_priv: drm file for the ioctl call 2942c8e32cc1SDaniel Vetter * 2943c8e32cc1SDaniel Vetter * Set the cursor configuration based on user request. This implements the 2nd 2944c8e32cc1SDaniel Vetter * version of the cursor ioctl, which allows userspace to additionally specify 2945c8e32cc1SDaniel Vetter * the hotspot of the pointer. 2946c8e32cc1SDaniel Vetter * 2947c8e32cc1SDaniel Vetter * Called by the user via ioctl. 2948c8e32cc1SDaniel Vetter * 2949c8e32cc1SDaniel Vetter * Returns: 29501a498633SDaniel Vetter * Zero on success, negative errno on failure. 2951c8e32cc1SDaniel Vetter */ 29524c813d4dSDave Airlie int drm_mode_cursor2_ioctl(struct drm_device *dev, 29534c813d4dSDave Airlie void *data, struct drm_file *file_priv) 29544c813d4dSDave Airlie { 29554c813d4dSDave Airlie struct drm_mode_cursor2 *req = data; 29564dfd909fSThierry Reding 29574c813d4dSDave Airlie return drm_mode_cursor_common(dev, req, file_priv); 2958f453ba04SDave Airlie } 2959f453ba04SDave Airlie 2960c8e32cc1SDaniel Vetter /** 2961c8e32cc1SDaniel Vetter * drm_mode_legacy_fb_format - compute drm fourcc code from legacy description 2962c8e32cc1SDaniel Vetter * @bpp: bits per pixels 2963c8e32cc1SDaniel Vetter * @depth: bit depth per pixel 2964c8e32cc1SDaniel Vetter * 2965c8e32cc1SDaniel Vetter * Computes a drm fourcc pixel format code for the given @bpp/@depth values. 2966c8e32cc1SDaniel Vetter * Useful in fbdev emulation code, since that deals in those values. 2967c8e32cc1SDaniel Vetter */ 2968308e5bcbSJesse Barnes uint32_t drm_mode_legacy_fb_format(uint32_t bpp, uint32_t depth) 2969308e5bcbSJesse Barnes { 2970308e5bcbSJesse Barnes uint32_t fmt; 2971308e5bcbSJesse Barnes 2972308e5bcbSJesse Barnes switch (bpp) { 2973308e5bcbSJesse Barnes case 8: 2974d84f031bSVille Syrjälä fmt = DRM_FORMAT_C8; 2975308e5bcbSJesse Barnes break; 2976308e5bcbSJesse Barnes case 16: 2977308e5bcbSJesse Barnes if (depth == 15) 297804b3924dSVille Syrjälä fmt = DRM_FORMAT_XRGB1555; 2979308e5bcbSJesse Barnes else 298004b3924dSVille Syrjälä fmt = DRM_FORMAT_RGB565; 2981308e5bcbSJesse Barnes break; 2982308e5bcbSJesse Barnes case 24: 298304b3924dSVille Syrjälä fmt = DRM_FORMAT_RGB888; 2984308e5bcbSJesse Barnes break; 2985308e5bcbSJesse Barnes case 32: 2986308e5bcbSJesse Barnes if (depth == 24) 298704b3924dSVille Syrjälä fmt = DRM_FORMAT_XRGB8888; 2988308e5bcbSJesse Barnes else if (depth == 30) 298904b3924dSVille Syrjälä fmt = DRM_FORMAT_XRGB2101010; 2990308e5bcbSJesse Barnes else 299104b3924dSVille Syrjälä fmt = DRM_FORMAT_ARGB8888; 2992308e5bcbSJesse Barnes break; 2993308e5bcbSJesse Barnes default: 299404b3924dSVille Syrjälä DRM_ERROR("bad bpp, assuming x8r8g8b8 pixel format\n"); 299504b3924dSVille Syrjälä fmt = DRM_FORMAT_XRGB8888; 2996308e5bcbSJesse Barnes break; 2997308e5bcbSJesse Barnes } 2998308e5bcbSJesse Barnes 2999308e5bcbSJesse Barnes return fmt; 3000308e5bcbSJesse Barnes } 3001308e5bcbSJesse Barnes EXPORT_SYMBOL(drm_mode_legacy_fb_format); 3002308e5bcbSJesse Barnes 3003f453ba04SDave Airlie /** 3004f453ba04SDave Airlie * drm_mode_addfb - add an FB to the graphics configuration 3005065a50edSDaniel Vetter * @dev: drm device for the ioctl 3006065a50edSDaniel Vetter * @data: data pointer for the ioctl 3007065a50edSDaniel Vetter * @file_priv: drm file for the ioctl call 3008f453ba04SDave Airlie * 3009c8e32cc1SDaniel Vetter * Add a new FB to the specified CRTC, given a user request. This is the 3010209f5527SChuck Ebbert * original addfb ioctl which only supported RGB formats. 3011f453ba04SDave Airlie * 3012f453ba04SDave Airlie * Called by the user via ioctl. 3013f453ba04SDave Airlie * 3014c8e32cc1SDaniel Vetter * Returns: 30151a498633SDaniel Vetter * Zero on success, negative errno on failure. 3016f453ba04SDave Airlie */ 3017f453ba04SDave Airlie int drm_mode_addfb(struct drm_device *dev, 3018f453ba04SDave Airlie void *data, struct drm_file *file_priv) 3019f453ba04SDave Airlie { 3020308e5bcbSJesse Barnes struct drm_mode_fb_cmd *or = data; 3021308e5bcbSJesse Barnes struct drm_mode_fb_cmd2 r = {}; 3022228f2cb3SChuck Ebbert int ret; 3023308e5bcbSJesse Barnes 3024228f2cb3SChuck Ebbert /* convert to new format and call new ioctl */ 3025308e5bcbSJesse Barnes r.fb_id = or->fb_id; 3026308e5bcbSJesse Barnes r.width = or->width; 3027308e5bcbSJesse Barnes r.height = or->height; 3028308e5bcbSJesse Barnes r.pitches[0] = or->pitch; 3029308e5bcbSJesse Barnes r.pixel_format = drm_mode_legacy_fb_format(or->bpp, or->depth); 3030308e5bcbSJesse Barnes r.handles[0] = or->handle; 3031308e5bcbSJesse Barnes 3032228f2cb3SChuck Ebbert ret = drm_mode_addfb2(dev, &r, file_priv); 3033228f2cb3SChuck Ebbert if (ret) 3034228f2cb3SChuck Ebbert return ret; 3035308e5bcbSJesse Barnes 3036228f2cb3SChuck Ebbert or->fb_id = r.fb_id; 30374b096ac1SDaniel Vetter 3038baf698b0SDaniel Vetter return 0; 3039308e5bcbSJesse Barnes } 3040308e5bcbSJesse Barnes 3041cff91b62SVille Syrjälä static int format_check(const struct drm_mode_fb_cmd2 *r) 3042935b5977SVille Syrjälä { 3043935b5977SVille Syrjälä uint32_t format = r->pixel_format & ~DRM_FORMAT_BIG_ENDIAN; 3044935b5977SVille Syrjälä 3045935b5977SVille Syrjälä switch (format) { 3046935b5977SVille Syrjälä case DRM_FORMAT_C8: 3047935b5977SVille Syrjälä case DRM_FORMAT_RGB332: 3048935b5977SVille Syrjälä case DRM_FORMAT_BGR233: 3049935b5977SVille Syrjälä case DRM_FORMAT_XRGB4444: 3050935b5977SVille Syrjälä case DRM_FORMAT_XBGR4444: 3051935b5977SVille Syrjälä case DRM_FORMAT_RGBX4444: 3052935b5977SVille Syrjälä case DRM_FORMAT_BGRX4444: 3053935b5977SVille Syrjälä case DRM_FORMAT_ARGB4444: 3054935b5977SVille Syrjälä case DRM_FORMAT_ABGR4444: 3055935b5977SVille Syrjälä case DRM_FORMAT_RGBA4444: 3056935b5977SVille Syrjälä case DRM_FORMAT_BGRA4444: 3057935b5977SVille Syrjälä case DRM_FORMAT_XRGB1555: 3058935b5977SVille Syrjälä case DRM_FORMAT_XBGR1555: 3059935b5977SVille Syrjälä case DRM_FORMAT_RGBX5551: 3060935b5977SVille Syrjälä case DRM_FORMAT_BGRX5551: 3061935b5977SVille Syrjälä case DRM_FORMAT_ARGB1555: 3062935b5977SVille Syrjälä case DRM_FORMAT_ABGR1555: 3063935b5977SVille Syrjälä case DRM_FORMAT_RGBA5551: 3064935b5977SVille Syrjälä case DRM_FORMAT_BGRA5551: 3065935b5977SVille Syrjälä case DRM_FORMAT_RGB565: 3066935b5977SVille Syrjälä case DRM_FORMAT_BGR565: 3067935b5977SVille Syrjälä case DRM_FORMAT_RGB888: 3068935b5977SVille Syrjälä case DRM_FORMAT_BGR888: 3069935b5977SVille Syrjälä case DRM_FORMAT_XRGB8888: 3070935b5977SVille Syrjälä case DRM_FORMAT_XBGR8888: 3071935b5977SVille Syrjälä case DRM_FORMAT_RGBX8888: 3072935b5977SVille Syrjälä case DRM_FORMAT_BGRX8888: 3073935b5977SVille Syrjälä case DRM_FORMAT_ARGB8888: 3074935b5977SVille Syrjälä case DRM_FORMAT_ABGR8888: 3075935b5977SVille Syrjälä case DRM_FORMAT_RGBA8888: 3076935b5977SVille Syrjälä case DRM_FORMAT_BGRA8888: 3077935b5977SVille Syrjälä case DRM_FORMAT_XRGB2101010: 3078935b5977SVille Syrjälä case DRM_FORMAT_XBGR2101010: 3079935b5977SVille Syrjälä case DRM_FORMAT_RGBX1010102: 3080935b5977SVille Syrjälä case DRM_FORMAT_BGRX1010102: 3081935b5977SVille Syrjälä case DRM_FORMAT_ARGB2101010: 3082935b5977SVille Syrjälä case DRM_FORMAT_ABGR2101010: 3083935b5977SVille Syrjälä case DRM_FORMAT_RGBA1010102: 3084935b5977SVille Syrjälä case DRM_FORMAT_BGRA1010102: 3085935b5977SVille Syrjälä case DRM_FORMAT_YUYV: 3086935b5977SVille Syrjälä case DRM_FORMAT_YVYU: 3087935b5977SVille Syrjälä case DRM_FORMAT_UYVY: 3088935b5977SVille Syrjälä case DRM_FORMAT_VYUY: 3089935b5977SVille Syrjälä case DRM_FORMAT_AYUV: 3090935b5977SVille Syrjälä case DRM_FORMAT_NV12: 3091935b5977SVille Syrjälä case DRM_FORMAT_NV21: 3092935b5977SVille Syrjälä case DRM_FORMAT_NV16: 3093935b5977SVille Syrjälä case DRM_FORMAT_NV61: 3094ba623f6aSLaurent Pinchart case DRM_FORMAT_NV24: 3095ba623f6aSLaurent Pinchart case DRM_FORMAT_NV42: 3096935b5977SVille Syrjälä case DRM_FORMAT_YUV410: 3097935b5977SVille Syrjälä case DRM_FORMAT_YVU410: 3098935b5977SVille Syrjälä case DRM_FORMAT_YUV411: 3099935b5977SVille Syrjälä case DRM_FORMAT_YVU411: 3100935b5977SVille Syrjälä case DRM_FORMAT_YUV420: 3101935b5977SVille Syrjälä case DRM_FORMAT_YVU420: 3102935b5977SVille Syrjälä case DRM_FORMAT_YUV422: 3103935b5977SVille Syrjälä case DRM_FORMAT_YVU422: 3104935b5977SVille Syrjälä case DRM_FORMAT_YUV444: 3105935b5977SVille Syrjälä case DRM_FORMAT_YVU444: 3106935b5977SVille Syrjälä return 0; 3107935b5977SVille Syrjälä default: 310823c453a4SVille Syrjälä DRM_DEBUG_KMS("invalid pixel format %s\n", 310923c453a4SVille Syrjälä drm_get_format_name(r->pixel_format)); 3110935b5977SVille Syrjälä return -EINVAL; 3111935b5977SVille Syrjälä } 3112935b5977SVille Syrjälä } 3113935b5977SVille Syrjälä 3114cff91b62SVille Syrjälä static int framebuffer_check(const struct drm_mode_fb_cmd2 *r) 3115d1b45d5fSVille Syrjälä { 3116d1b45d5fSVille Syrjälä int ret, hsub, vsub, num_planes, i; 3117d1b45d5fSVille Syrjälä 3118d1b45d5fSVille Syrjälä ret = format_check(r); 3119d1b45d5fSVille Syrjälä if (ret) { 31206ba6d03eSVille Syrjälä DRM_DEBUG_KMS("bad framebuffer format %s\n", 31216ba6d03eSVille Syrjälä drm_get_format_name(r->pixel_format)); 3122d1b45d5fSVille Syrjälä return ret; 3123d1b45d5fSVille Syrjälä } 3124d1b45d5fSVille Syrjälä 3125d1b45d5fSVille Syrjälä hsub = drm_format_horz_chroma_subsampling(r->pixel_format); 3126d1b45d5fSVille Syrjälä vsub = drm_format_vert_chroma_subsampling(r->pixel_format); 3127d1b45d5fSVille Syrjälä num_planes = drm_format_num_planes(r->pixel_format); 3128d1b45d5fSVille Syrjälä 3129d1b45d5fSVille Syrjälä if (r->width == 0 || r->width % hsub) { 3130209f5527SChuck Ebbert DRM_DEBUG_KMS("bad framebuffer width %u\n", r->width); 3131d1b45d5fSVille Syrjälä return -EINVAL; 3132d1b45d5fSVille Syrjälä } 3133d1b45d5fSVille Syrjälä 3134d1b45d5fSVille Syrjälä if (r->height == 0 || r->height % vsub) { 31351aa1b11cSDave Airlie DRM_DEBUG_KMS("bad framebuffer height %u\n", r->height); 3136d1b45d5fSVille Syrjälä return -EINVAL; 3137d1b45d5fSVille Syrjälä } 3138d1b45d5fSVille Syrjälä 3139d1b45d5fSVille Syrjälä for (i = 0; i < num_planes; i++) { 3140d1b45d5fSVille Syrjälä unsigned int width = r->width / (i != 0 ? hsub : 1); 3141b180b5d1SVille Syrjälä unsigned int height = r->height / (i != 0 ? vsub : 1); 3142b180b5d1SVille Syrjälä unsigned int cpp = drm_format_plane_cpp(r->pixel_format, i); 3143d1b45d5fSVille Syrjälä 3144d1b45d5fSVille Syrjälä if (!r->handles[i]) { 31451aa1b11cSDave Airlie DRM_DEBUG_KMS("no buffer object handle for plane %d\n", i); 3146d1b45d5fSVille Syrjälä return -EINVAL; 3147d1b45d5fSVille Syrjälä } 3148d1b45d5fSVille Syrjälä 3149b180b5d1SVille Syrjälä if ((uint64_t) width * cpp > UINT_MAX) 3150b180b5d1SVille Syrjälä return -ERANGE; 3151b180b5d1SVille Syrjälä 3152b180b5d1SVille Syrjälä if ((uint64_t) height * r->pitches[i] + r->offsets[i] > UINT_MAX) 3153b180b5d1SVille Syrjälä return -ERANGE; 3154b180b5d1SVille Syrjälä 3155b180b5d1SVille Syrjälä if (r->pitches[i] < width * cpp) { 31561aa1b11cSDave Airlie DRM_DEBUG_KMS("bad pitch %u for plane %d\n", r->pitches[i], i); 3157d1b45d5fSVille Syrjälä return -EINVAL; 3158d1b45d5fSVille Syrjälä } 3159d1b45d5fSVille Syrjälä } 3160d1b45d5fSVille Syrjälä 3161d1b45d5fSVille Syrjälä return 0; 3162d1b45d5fSVille Syrjälä } 3163d1b45d5fSVille Syrjälä 3164c394c2b0SMatt Roper static struct drm_framebuffer *add_framebuffer_internal(struct drm_device *dev, 3165c394c2b0SMatt Roper struct drm_mode_fb_cmd2 *r, 3166c394c2b0SMatt Roper struct drm_file *file_priv) 3167c394c2b0SMatt Roper { 3168c394c2b0SMatt Roper struct drm_mode_config *config = &dev->mode_config; 3169c394c2b0SMatt Roper struct drm_framebuffer *fb; 3170c394c2b0SMatt Roper int ret; 3171c394c2b0SMatt Roper 3172c394c2b0SMatt Roper if (r->flags & ~DRM_MODE_FB_INTERLACED) { 3173c394c2b0SMatt Roper DRM_DEBUG_KMS("bad framebuffer flags 0x%08x\n", r->flags); 3174c394c2b0SMatt Roper return ERR_PTR(-EINVAL); 3175c394c2b0SMatt Roper } 3176c394c2b0SMatt Roper 3177c394c2b0SMatt Roper if ((config->min_width > r->width) || (r->width > config->max_width)) { 3178c394c2b0SMatt Roper DRM_DEBUG_KMS("bad framebuffer width %d, should be >= %d && <= %d\n", 3179c394c2b0SMatt Roper r->width, config->min_width, config->max_width); 3180c394c2b0SMatt Roper return ERR_PTR(-EINVAL); 3181c394c2b0SMatt Roper } 3182c394c2b0SMatt Roper if ((config->min_height > r->height) || (r->height > config->max_height)) { 3183c394c2b0SMatt Roper DRM_DEBUG_KMS("bad framebuffer height %d, should be >= %d && <= %d\n", 3184c394c2b0SMatt Roper r->height, config->min_height, config->max_height); 3185c394c2b0SMatt Roper return ERR_PTR(-EINVAL); 3186c394c2b0SMatt Roper } 3187c394c2b0SMatt Roper 3188c394c2b0SMatt Roper ret = framebuffer_check(r); 3189c394c2b0SMatt Roper if (ret) 3190c394c2b0SMatt Roper return ERR_PTR(ret); 3191c394c2b0SMatt Roper 3192c394c2b0SMatt Roper fb = dev->mode_config.funcs->fb_create(dev, file_priv, r); 3193c394c2b0SMatt Roper if (IS_ERR(fb)) { 3194c394c2b0SMatt Roper DRM_DEBUG_KMS("could not create framebuffer\n"); 3195c394c2b0SMatt Roper return fb; 3196c394c2b0SMatt Roper } 3197c394c2b0SMatt Roper 3198c394c2b0SMatt Roper mutex_lock(&file_priv->fbs_lock); 3199c394c2b0SMatt Roper r->fb_id = fb->base.id; 3200c394c2b0SMatt Roper list_add(&fb->filp_head, &file_priv->fbs); 3201c394c2b0SMatt Roper DRM_DEBUG_KMS("[FB:%d]\n", fb->base.id); 3202c394c2b0SMatt Roper mutex_unlock(&file_priv->fbs_lock); 3203c394c2b0SMatt Roper 3204c394c2b0SMatt Roper return fb; 3205c394c2b0SMatt Roper } 3206c394c2b0SMatt Roper 3207308e5bcbSJesse Barnes /** 3208308e5bcbSJesse Barnes * drm_mode_addfb2 - add an FB to the graphics configuration 3209065a50edSDaniel Vetter * @dev: drm device for the ioctl 3210065a50edSDaniel Vetter * @data: data pointer for the ioctl 3211065a50edSDaniel Vetter * @file_priv: drm file for the ioctl call 3212308e5bcbSJesse Barnes * 3213c8e32cc1SDaniel Vetter * Add a new FB to the specified CRTC, given a user request with format. This is 3214c8e32cc1SDaniel Vetter * the 2nd version of the addfb ioctl, which supports multi-planar framebuffers 3215c8e32cc1SDaniel Vetter * and uses fourcc codes as pixel format specifiers. 3216308e5bcbSJesse Barnes * 3217308e5bcbSJesse Barnes * Called by the user via ioctl. 3218308e5bcbSJesse Barnes * 3219c8e32cc1SDaniel Vetter * Returns: 32201a498633SDaniel Vetter * Zero on success, negative errno on failure. 3221308e5bcbSJesse Barnes */ 3222308e5bcbSJesse Barnes int drm_mode_addfb2(struct drm_device *dev, 3223308e5bcbSJesse Barnes void *data, struct drm_file *file_priv) 3224308e5bcbSJesse Barnes { 3225f453ba04SDave Airlie struct drm_framebuffer *fb; 3226f453ba04SDave Airlie 3227fb3b06c8SDave Airlie if (!drm_core_check_feature(dev, DRIVER_MODESET)) 3228fb3b06c8SDave Airlie return -EINVAL; 3229fb3b06c8SDave Airlie 3230c394c2b0SMatt Roper fb = add_framebuffer_internal(dev, data, file_priv); 3231c394c2b0SMatt Roper if (IS_ERR(fb)) 32324b096ac1SDaniel Vetter return PTR_ERR(fb); 3233f453ba04SDave Airlie 3234c394c2b0SMatt Roper return 0; 3235f453ba04SDave Airlie } 3236f453ba04SDave Airlie 3237f453ba04SDave Airlie /** 3238f453ba04SDave Airlie * drm_mode_rmfb - remove an FB from the configuration 3239065a50edSDaniel Vetter * @dev: drm device for the ioctl 3240065a50edSDaniel Vetter * @data: data pointer for the ioctl 3241065a50edSDaniel Vetter * @file_priv: drm file for the ioctl call 3242f453ba04SDave Airlie * 3243f453ba04SDave Airlie * Remove the FB specified by the user. 3244f453ba04SDave Airlie * 3245f453ba04SDave Airlie * Called by the user via ioctl. 3246f453ba04SDave Airlie * 3247c8e32cc1SDaniel Vetter * Returns: 32481a498633SDaniel Vetter * Zero on success, negative errno on failure. 3249f453ba04SDave Airlie */ 3250f453ba04SDave Airlie int drm_mode_rmfb(struct drm_device *dev, 3251f453ba04SDave Airlie void *data, struct drm_file *file_priv) 3252f453ba04SDave Airlie { 3253f453ba04SDave Airlie struct drm_framebuffer *fb = NULL; 3254f453ba04SDave Airlie struct drm_framebuffer *fbl = NULL; 3255f453ba04SDave Airlie uint32_t *id = data; 3256f453ba04SDave Airlie int found = 0; 3257f453ba04SDave Airlie 3258fb3b06c8SDave Airlie if (!drm_core_check_feature(dev, DRIVER_MODESET)) 3259fb3b06c8SDave Airlie return -EINVAL; 3260fb3b06c8SDave Airlie 32614b096ac1SDaniel Vetter mutex_lock(&file_priv->fbs_lock); 32622b677e8cSDaniel Vetter mutex_lock(&dev->mode_config.fb_lock); 32632b677e8cSDaniel Vetter fb = __drm_framebuffer_lookup(dev, *id); 32642b677e8cSDaniel Vetter if (!fb) 32652b677e8cSDaniel Vetter goto fail_lookup; 32662b677e8cSDaniel Vetter 3267f453ba04SDave Airlie list_for_each_entry(fbl, &file_priv->fbs, filp_head) 3268f453ba04SDave Airlie if (fb == fbl) 3269f453ba04SDave Airlie found = 1; 32702b677e8cSDaniel Vetter if (!found) 32712b677e8cSDaniel Vetter goto fail_lookup; 32722b677e8cSDaniel Vetter 32732b677e8cSDaniel Vetter /* Mark fb as reaped, we still have a ref from fpriv->fbs. */ 32742b677e8cSDaniel Vetter __drm_framebuffer_unregister(dev, fb); 3275f453ba04SDave Airlie 32764b096ac1SDaniel Vetter list_del_init(&fb->filp_head); 32772b677e8cSDaniel Vetter mutex_unlock(&dev->mode_config.fb_lock); 32784b096ac1SDaniel Vetter mutex_unlock(&file_priv->fbs_lock); 3279f453ba04SDave Airlie 32804b096ac1SDaniel Vetter drm_framebuffer_remove(fb); 32814b096ac1SDaniel Vetter 32822b677e8cSDaniel Vetter return 0; 32832b677e8cSDaniel Vetter 32842b677e8cSDaniel Vetter fail_lookup: 32852b677e8cSDaniel Vetter mutex_unlock(&dev->mode_config.fb_lock); 32862b677e8cSDaniel Vetter mutex_unlock(&file_priv->fbs_lock); 32872b677e8cSDaniel Vetter 328837c4e705SVille Syrjälä return -ENOENT; 3289f453ba04SDave Airlie } 3290f453ba04SDave Airlie 3291f453ba04SDave Airlie /** 3292f453ba04SDave Airlie * drm_mode_getfb - get FB info 3293065a50edSDaniel Vetter * @dev: drm device for the ioctl 3294065a50edSDaniel Vetter * @data: data pointer for the ioctl 3295065a50edSDaniel Vetter * @file_priv: drm file for the ioctl call 3296f453ba04SDave Airlie * 3297f453ba04SDave Airlie * Lookup the FB given its ID and return info about it. 3298f453ba04SDave Airlie * 3299f453ba04SDave Airlie * Called by the user via ioctl. 3300f453ba04SDave Airlie * 3301c8e32cc1SDaniel Vetter * Returns: 33021a498633SDaniel Vetter * Zero on success, negative errno on failure. 3303f453ba04SDave Airlie */ 3304f453ba04SDave Airlie int drm_mode_getfb(struct drm_device *dev, 3305f453ba04SDave Airlie void *data, struct drm_file *file_priv) 3306f453ba04SDave Airlie { 3307f453ba04SDave Airlie struct drm_mode_fb_cmd *r = data; 3308f453ba04SDave Airlie struct drm_framebuffer *fb; 330958c0dca1SDaniel Vetter int ret; 3310f453ba04SDave Airlie 3311fb3b06c8SDave Airlie if (!drm_core_check_feature(dev, DRIVER_MODESET)) 3312fb3b06c8SDave Airlie return -EINVAL; 3313fb3b06c8SDave Airlie 3314786b99edSDaniel Vetter fb = drm_framebuffer_lookup(dev, r->fb_id); 331558c0dca1SDaniel Vetter if (!fb) 331637c4e705SVille Syrjälä return -ENOENT; 3317f453ba04SDave Airlie 3318f453ba04SDave Airlie r->height = fb->height; 3319f453ba04SDave Airlie r->width = fb->width; 3320f453ba04SDave Airlie r->depth = fb->depth; 3321f453ba04SDave Airlie r->bpp = fb->bits_per_pixel; 332201f2c773SVille Syrjälä r->pitch = fb->pitches[0]; 3323101b96f3SDavid Herrmann if (fb->funcs->create_handle) { 332409f308f7SThomas Hellstrom if (file_priv->is_master || capable(CAP_SYS_ADMIN) || 332543683057SThomas Hellstrom drm_is_control_client(file_priv)) { 3326101b96f3SDavid Herrmann ret = fb->funcs->create_handle(fb, file_priv, 3327101b96f3SDavid Herrmann &r->handle); 3328101b96f3SDavid Herrmann } else { 3329101b96f3SDavid Herrmann /* GET_FB() is an unprivileged ioctl so we must not 3330101b96f3SDavid Herrmann * return a buffer-handle to non-master processes! For 3331101b96f3SDavid Herrmann * backwards-compatibility reasons, we cannot make 3332101b96f3SDavid Herrmann * GET_FB() privileged, so just return an invalid handle 3333101b96f3SDavid Herrmann * for non-masters. */ 3334101b96f3SDavid Herrmann r->handle = 0; 3335101b96f3SDavid Herrmann ret = 0; 3336101b96f3SDavid Herrmann } 3337101b96f3SDavid Herrmann } else { 3338af26ef3bSDaniel Vetter ret = -ENODEV; 3339101b96f3SDavid Herrmann } 3340f453ba04SDave Airlie 334158c0dca1SDaniel Vetter drm_framebuffer_unreference(fb); 334258c0dca1SDaniel Vetter 3343f453ba04SDave Airlie return ret; 3344f453ba04SDave Airlie } 3345f453ba04SDave Airlie 3346c8e32cc1SDaniel Vetter /** 3347c8e32cc1SDaniel Vetter * drm_mode_dirtyfb_ioctl - flush frontbuffer rendering on an FB 3348c8e32cc1SDaniel Vetter * @dev: drm device for the ioctl 3349c8e32cc1SDaniel Vetter * @data: data pointer for the ioctl 3350c8e32cc1SDaniel Vetter * @file_priv: drm file for the ioctl call 3351c8e32cc1SDaniel Vetter * 3352c8e32cc1SDaniel Vetter * Lookup the FB and flush out the damaged area supplied by userspace as a clip 3353c8e32cc1SDaniel Vetter * rectangle list. Generic userspace which does frontbuffer rendering must call 3354c8e32cc1SDaniel Vetter * this ioctl to flush out the changes on manual-update display outputs, e.g. 3355c8e32cc1SDaniel Vetter * usb display-link, mipi manual update panels or edp panel self refresh modes. 3356c8e32cc1SDaniel Vetter * 3357c8e32cc1SDaniel Vetter * Modesetting drivers which always update the frontbuffer do not need to 3358c8e32cc1SDaniel Vetter * implement the corresponding ->dirty framebuffer callback. 3359c8e32cc1SDaniel Vetter * 3360c8e32cc1SDaniel Vetter * Called by the user via ioctl. 3361c8e32cc1SDaniel Vetter * 3362c8e32cc1SDaniel Vetter * Returns: 33631a498633SDaniel Vetter * Zero on success, negative errno on failure. 3364c8e32cc1SDaniel Vetter */ 3365884840aaSJakob Bornecrantz int drm_mode_dirtyfb_ioctl(struct drm_device *dev, 3366884840aaSJakob Bornecrantz void *data, struct drm_file *file_priv) 3367884840aaSJakob Bornecrantz { 3368884840aaSJakob Bornecrantz struct drm_clip_rect __user *clips_ptr; 3369884840aaSJakob Bornecrantz struct drm_clip_rect *clips = NULL; 3370884840aaSJakob Bornecrantz struct drm_mode_fb_dirty_cmd *r = data; 3371884840aaSJakob Bornecrantz struct drm_framebuffer *fb; 3372884840aaSJakob Bornecrantz unsigned flags; 3373884840aaSJakob Bornecrantz int num_clips; 33744a1b0714SLaurent Pinchart int ret; 3375884840aaSJakob Bornecrantz 3376fb3b06c8SDave Airlie if (!drm_core_check_feature(dev, DRIVER_MODESET)) 3377fb3b06c8SDave Airlie return -EINVAL; 3378fb3b06c8SDave Airlie 3379786b99edSDaniel Vetter fb = drm_framebuffer_lookup(dev, r->fb_id); 33804ccf097fSDaniel Vetter if (!fb) 338137c4e705SVille Syrjälä return -ENOENT; 3382884840aaSJakob Bornecrantz 3383884840aaSJakob Bornecrantz num_clips = r->num_clips; 338481f6c7f8SVille Syrjälä clips_ptr = (struct drm_clip_rect __user *)(unsigned long)r->clips_ptr; 3385884840aaSJakob Bornecrantz 3386884840aaSJakob Bornecrantz if (!num_clips != !clips_ptr) { 3387884840aaSJakob Bornecrantz ret = -EINVAL; 3388884840aaSJakob Bornecrantz goto out_err1; 3389884840aaSJakob Bornecrantz } 3390884840aaSJakob Bornecrantz 3391884840aaSJakob Bornecrantz flags = DRM_MODE_FB_DIRTY_FLAGS & r->flags; 3392884840aaSJakob Bornecrantz 3393884840aaSJakob Bornecrantz /* If userspace annotates copy, clips must come in pairs */ 3394884840aaSJakob Bornecrantz if (flags & DRM_MODE_FB_DIRTY_ANNOTATE_COPY && (num_clips % 2)) { 3395884840aaSJakob Bornecrantz ret = -EINVAL; 3396884840aaSJakob Bornecrantz goto out_err1; 3397884840aaSJakob Bornecrantz } 3398884840aaSJakob Bornecrantz 3399884840aaSJakob Bornecrantz if (num_clips && clips_ptr) { 3400a5cd3351SXi Wang if (num_clips < 0 || num_clips > DRM_MODE_FB_DIRTY_MAX_CLIPS) { 3401a5cd3351SXi Wang ret = -EINVAL; 3402a5cd3351SXi Wang goto out_err1; 3403a5cd3351SXi Wang } 3404bd3f0ff9SThierry Reding clips = kcalloc(num_clips, sizeof(*clips), GFP_KERNEL); 3405884840aaSJakob Bornecrantz if (!clips) { 3406884840aaSJakob Bornecrantz ret = -ENOMEM; 3407884840aaSJakob Bornecrantz goto out_err1; 3408884840aaSJakob Bornecrantz } 3409884840aaSJakob Bornecrantz 3410884840aaSJakob Bornecrantz ret = copy_from_user(clips, clips_ptr, 3411884840aaSJakob Bornecrantz num_clips * sizeof(*clips)); 3412e902a358SDan Carpenter if (ret) { 3413e902a358SDan Carpenter ret = -EFAULT; 3414884840aaSJakob Bornecrantz goto out_err2; 3415884840aaSJakob Bornecrantz } 3416e902a358SDan Carpenter } 3417884840aaSJakob Bornecrantz 3418884840aaSJakob Bornecrantz if (fb->funcs->dirty) { 341902b00162SThomas Hellstrom ret = fb->funcs->dirty(fb, file_priv, flags, r->color, 342002b00162SThomas Hellstrom clips, num_clips); 3421884840aaSJakob Bornecrantz } else { 3422884840aaSJakob Bornecrantz ret = -ENOSYS; 3423884840aaSJakob Bornecrantz } 3424884840aaSJakob Bornecrantz 3425884840aaSJakob Bornecrantz out_err2: 3426884840aaSJakob Bornecrantz kfree(clips); 3427884840aaSJakob Bornecrantz out_err1: 34284ccf097fSDaniel Vetter drm_framebuffer_unreference(fb); 34294ccf097fSDaniel Vetter 3430884840aaSJakob Bornecrantz return ret; 3431884840aaSJakob Bornecrantz } 3432884840aaSJakob Bornecrantz 3433884840aaSJakob Bornecrantz 3434f453ba04SDave Airlie /** 3435f453ba04SDave Airlie * drm_fb_release - remove and free the FBs on this file 3436065a50edSDaniel Vetter * @priv: drm file for the ioctl 3437f453ba04SDave Airlie * 3438f453ba04SDave Airlie * Destroy all the FBs associated with @filp. 3439f453ba04SDave Airlie * 3440f453ba04SDave Airlie * Called by the user via ioctl. 3441f453ba04SDave Airlie * 3442c8e32cc1SDaniel Vetter * Returns: 34431a498633SDaniel Vetter * Zero on success, negative errno on failure. 3444f453ba04SDave Airlie */ 3445ea39f835SKristian Høgsberg void drm_fb_release(struct drm_file *priv) 3446f453ba04SDave Airlie { 3447f453ba04SDave Airlie struct drm_device *dev = priv->minor->dev; 3448f453ba04SDave Airlie struct drm_framebuffer *fb, *tfb; 3449f453ba04SDave Airlie 34501b116297SDaniel Vetter /* 34511b116297SDaniel Vetter * When the file gets released that means no one else can access the fb 3452e2db726bSMartin Peres * list any more, so no need to grab fpriv->fbs_lock. And we need to 34531b116297SDaniel Vetter * avoid upsetting lockdep since the universal cursor code adds a 34541b116297SDaniel Vetter * framebuffer while holding mutex locks. 34551b116297SDaniel Vetter * 34561b116297SDaniel Vetter * Note that a real deadlock between fpriv->fbs_lock and the modeset 34571b116297SDaniel Vetter * locks is impossible here since no one else but this function can get 34581b116297SDaniel Vetter * at it any more. 34591b116297SDaniel Vetter */ 3460f453ba04SDave Airlie list_for_each_entry_safe(fb, tfb, &priv->fbs, filp_head) { 34612b677e8cSDaniel Vetter 34622b677e8cSDaniel Vetter mutex_lock(&dev->mode_config.fb_lock); 34632b677e8cSDaniel Vetter /* Mark fb as reaped, we still have a ref from fpriv->fbs. */ 34642b677e8cSDaniel Vetter __drm_framebuffer_unregister(dev, fb); 34652b677e8cSDaniel Vetter mutex_unlock(&dev->mode_config.fb_lock); 34662b677e8cSDaniel Vetter 34674b096ac1SDaniel Vetter list_del_init(&fb->filp_head); 34682b677e8cSDaniel Vetter 34692b677e8cSDaniel Vetter /* This will also drop the fpriv->fbs reference. */ 3470f7eff60eSRob Clark drm_framebuffer_remove(fb); 3471f453ba04SDave Airlie } 3472f453ba04SDave Airlie } 3473f453ba04SDave Airlie 3474c8e32cc1SDaniel Vetter /** 3475c8e32cc1SDaniel Vetter * drm_property_create - create a new property type 3476c8e32cc1SDaniel Vetter * @dev: drm device 3477c8e32cc1SDaniel Vetter * @flags: flags specifying the property type 3478c8e32cc1SDaniel Vetter * @name: name of the property 3479c8e32cc1SDaniel Vetter * @num_values: number of pre-defined values 3480c8e32cc1SDaniel Vetter * 3481c8e32cc1SDaniel Vetter * This creates a new generic drm property which can then be attached to a drm 3482c8e32cc1SDaniel Vetter * object with drm_object_attach_property. The returned property object must be 3483c8e32cc1SDaniel Vetter * freed with drm_property_destroy. 3484c8e32cc1SDaniel Vetter * 34853b5b9932SDamien Lespiau * Note that the DRM core keeps a per-device list of properties and that, if 34863b5b9932SDamien Lespiau * drm_mode_config_cleanup() is called, it will destroy all properties created 34873b5b9932SDamien Lespiau * by the driver. 34883b5b9932SDamien Lespiau * 3489c8e32cc1SDaniel Vetter * Returns: 3490c8e32cc1SDaniel Vetter * A pointer to the newly created property on success, NULL on failure. 3491c8e32cc1SDaniel Vetter */ 3492f453ba04SDave Airlie struct drm_property *drm_property_create(struct drm_device *dev, int flags, 3493f453ba04SDave Airlie const char *name, int num_values) 3494f453ba04SDave Airlie { 3495f453ba04SDave Airlie struct drm_property *property = NULL; 34966bfc56aaSVille Syrjälä int ret; 3497f453ba04SDave Airlie 3498f453ba04SDave Airlie property = kzalloc(sizeof(struct drm_property), GFP_KERNEL); 3499f453ba04SDave Airlie if (!property) 3500f453ba04SDave Airlie return NULL; 3501f453ba04SDave Airlie 350298f75de4SRob Clark property->dev = dev; 350398f75de4SRob Clark 3504f453ba04SDave Airlie if (num_values) { 3505bd3f0ff9SThierry Reding property->values = kcalloc(num_values, sizeof(uint64_t), 3506bd3f0ff9SThierry Reding GFP_KERNEL); 3507f453ba04SDave Airlie if (!property->values) 3508f453ba04SDave Airlie goto fail; 3509f453ba04SDave Airlie } 3510f453ba04SDave Airlie 35116bfc56aaSVille Syrjälä ret = drm_mode_object_get(dev, &property->base, DRM_MODE_OBJECT_PROPERTY); 35126bfc56aaSVille Syrjälä if (ret) 35136bfc56aaSVille Syrjälä goto fail; 35146bfc56aaSVille Syrjälä 3515f453ba04SDave Airlie property->flags = flags; 3516f453ba04SDave Airlie property->num_values = num_values; 35173758b341SDaniel Vetter INIT_LIST_HEAD(&property->enum_list); 3518f453ba04SDave Airlie 3519471dd2efSVinson Lee if (name) { 3520f453ba04SDave Airlie strncpy(property->name, name, DRM_PROP_NAME_LEN); 3521471dd2efSVinson Lee property->name[DRM_PROP_NAME_LEN-1] = '\0'; 3522471dd2efSVinson Lee } 3523f453ba04SDave Airlie 3524f453ba04SDave Airlie list_add_tail(&property->head, &dev->mode_config.property_list); 35255ea22f24SRob Clark 35265ea22f24SRob Clark WARN_ON(!drm_property_type_valid(property)); 35275ea22f24SRob Clark 3528f453ba04SDave Airlie return property; 3529f453ba04SDave Airlie fail: 35306bfc56aaSVille Syrjälä kfree(property->values); 3531f453ba04SDave Airlie kfree(property); 3532f453ba04SDave Airlie return NULL; 3533f453ba04SDave Airlie } 3534f453ba04SDave Airlie EXPORT_SYMBOL(drm_property_create); 3535f453ba04SDave Airlie 3536c8e32cc1SDaniel Vetter /** 35372aa9d2bcSThierry Reding * drm_property_create_enum - create a new enumeration property type 3538c8e32cc1SDaniel Vetter * @dev: drm device 3539c8e32cc1SDaniel Vetter * @flags: flags specifying the property type 3540c8e32cc1SDaniel Vetter * @name: name of the property 3541c8e32cc1SDaniel Vetter * @props: enumeration lists with property values 3542c8e32cc1SDaniel Vetter * @num_values: number of pre-defined values 3543c8e32cc1SDaniel Vetter * 3544c8e32cc1SDaniel Vetter * This creates a new generic drm property which can then be attached to a drm 3545c8e32cc1SDaniel Vetter * object with drm_object_attach_property. The returned property object must be 3546c8e32cc1SDaniel Vetter * freed with drm_property_destroy. 3547c8e32cc1SDaniel Vetter * 3548c8e32cc1SDaniel Vetter * Userspace is only allowed to set one of the predefined values for enumeration 3549c8e32cc1SDaniel Vetter * properties. 3550c8e32cc1SDaniel Vetter * 3551c8e32cc1SDaniel Vetter * Returns: 3552c8e32cc1SDaniel Vetter * A pointer to the newly created property on success, NULL on failure. 3553c8e32cc1SDaniel Vetter */ 35544a67d391SSascha Hauer struct drm_property *drm_property_create_enum(struct drm_device *dev, int flags, 35554a67d391SSascha Hauer const char *name, 35564a67d391SSascha Hauer const struct drm_prop_enum_list *props, 35574a67d391SSascha Hauer int num_values) 35584a67d391SSascha Hauer { 35594a67d391SSascha Hauer struct drm_property *property; 35604a67d391SSascha Hauer int i, ret; 35614a67d391SSascha Hauer 35624a67d391SSascha Hauer flags |= DRM_MODE_PROP_ENUM; 35634a67d391SSascha Hauer 35644a67d391SSascha Hauer property = drm_property_create(dev, flags, name, num_values); 35654a67d391SSascha Hauer if (!property) 35664a67d391SSascha Hauer return NULL; 35674a67d391SSascha Hauer 35684a67d391SSascha Hauer for (i = 0; i < num_values; i++) { 35694a67d391SSascha Hauer ret = drm_property_add_enum(property, i, 35704a67d391SSascha Hauer props[i].type, 35714a67d391SSascha Hauer props[i].name); 35724a67d391SSascha Hauer if (ret) { 35734a67d391SSascha Hauer drm_property_destroy(dev, property); 35744a67d391SSascha Hauer return NULL; 35754a67d391SSascha Hauer } 35764a67d391SSascha Hauer } 35774a67d391SSascha Hauer 35784a67d391SSascha Hauer return property; 35794a67d391SSascha Hauer } 35804a67d391SSascha Hauer EXPORT_SYMBOL(drm_property_create_enum); 35814a67d391SSascha Hauer 3582c8e32cc1SDaniel Vetter /** 35832aa9d2bcSThierry Reding * drm_property_create_bitmask - create a new bitmask property type 3584c8e32cc1SDaniel Vetter * @dev: drm device 3585c8e32cc1SDaniel Vetter * @flags: flags specifying the property type 3586c8e32cc1SDaniel Vetter * @name: name of the property 3587c8e32cc1SDaniel Vetter * @props: enumeration lists with property bitflags 3588295ee853SDaniel Vetter * @num_props: size of the @props array 3589295ee853SDaniel Vetter * @supported_bits: bitmask of all supported enumeration values 3590c8e32cc1SDaniel Vetter * 3591295ee853SDaniel Vetter * This creates a new bitmask drm property which can then be attached to a drm 3592c8e32cc1SDaniel Vetter * object with drm_object_attach_property. The returned property object must be 3593c8e32cc1SDaniel Vetter * freed with drm_property_destroy. 3594c8e32cc1SDaniel Vetter * 3595c8e32cc1SDaniel Vetter * Compared to plain enumeration properties userspace is allowed to set any 3596c8e32cc1SDaniel Vetter * or'ed together combination of the predefined property bitflag values 3597c8e32cc1SDaniel Vetter * 3598c8e32cc1SDaniel Vetter * Returns: 3599c8e32cc1SDaniel Vetter * A pointer to the newly created property on success, NULL on failure. 3600c8e32cc1SDaniel Vetter */ 360149e27545SRob Clark struct drm_property *drm_property_create_bitmask(struct drm_device *dev, 360249e27545SRob Clark int flags, const char *name, 360349e27545SRob Clark const struct drm_prop_enum_list *props, 36047689ffb3SVille Syrjälä int num_props, 36057689ffb3SVille Syrjälä uint64_t supported_bits) 360649e27545SRob Clark { 360749e27545SRob Clark struct drm_property *property; 36087689ffb3SVille Syrjälä int i, ret, index = 0; 36097689ffb3SVille Syrjälä int num_values = hweight64(supported_bits); 361049e27545SRob Clark 361149e27545SRob Clark flags |= DRM_MODE_PROP_BITMASK; 361249e27545SRob Clark 361349e27545SRob Clark property = drm_property_create(dev, flags, name, num_values); 361449e27545SRob Clark if (!property) 361549e27545SRob Clark return NULL; 36167689ffb3SVille Syrjälä for (i = 0; i < num_props; i++) { 36177689ffb3SVille Syrjälä if (!(supported_bits & (1ULL << props[i].type))) 36187689ffb3SVille Syrjälä continue; 361949e27545SRob Clark 36207689ffb3SVille Syrjälä if (WARN_ON(index >= num_values)) { 36217689ffb3SVille Syrjälä drm_property_destroy(dev, property); 36227689ffb3SVille Syrjälä return NULL; 36237689ffb3SVille Syrjälä } 36247689ffb3SVille Syrjälä 36257689ffb3SVille Syrjälä ret = drm_property_add_enum(property, index++, 362649e27545SRob Clark props[i].type, 362749e27545SRob Clark props[i].name); 362849e27545SRob Clark if (ret) { 362949e27545SRob Clark drm_property_destroy(dev, property); 363049e27545SRob Clark return NULL; 363149e27545SRob Clark } 363249e27545SRob Clark } 363349e27545SRob Clark 363449e27545SRob Clark return property; 363549e27545SRob Clark } 363649e27545SRob Clark EXPORT_SYMBOL(drm_property_create_bitmask); 363749e27545SRob Clark 3638ebc44cf3SRob Clark static struct drm_property *property_create_range(struct drm_device *dev, 3639ebc44cf3SRob Clark int flags, const char *name, 3640ebc44cf3SRob Clark uint64_t min, uint64_t max) 3641ebc44cf3SRob Clark { 3642ebc44cf3SRob Clark struct drm_property *property; 3643ebc44cf3SRob Clark 3644ebc44cf3SRob Clark property = drm_property_create(dev, flags, name, 2); 3645ebc44cf3SRob Clark if (!property) 3646ebc44cf3SRob Clark return NULL; 3647ebc44cf3SRob Clark 3648ebc44cf3SRob Clark property->values[0] = min; 3649ebc44cf3SRob Clark property->values[1] = max; 3650ebc44cf3SRob Clark 3651ebc44cf3SRob Clark return property; 3652ebc44cf3SRob Clark } 3653ebc44cf3SRob Clark 3654c8e32cc1SDaniel Vetter /** 36552aa9d2bcSThierry Reding * drm_property_create_range - create a new ranged property type 3656c8e32cc1SDaniel Vetter * @dev: drm device 3657c8e32cc1SDaniel Vetter * @flags: flags specifying the property type 3658c8e32cc1SDaniel Vetter * @name: name of the property 3659c8e32cc1SDaniel Vetter * @min: minimum value of the property 3660c8e32cc1SDaniel Vetter * @max: maximum value of the property 3661c8e32cc1SDaniel Vetter * 3662c8e32cc1SDaniel Vetter * This creates a new generic drm property which can then be attached to a drm 3663c8e32cc1SDaniel Vetter * object with drm_object_attach_property. The returned property object must be 3664c8e32cc1SDaniel Vetter * freed with drm_property_destroy. 3665c8e32cc1SDaniel Vetter * 366632197aabSMasanari Iida * Userspace is allowed to set any integer value in the (min, max) range 3667c8e32cc1SDaniel Vetter * inclusive. 3668c8e32cc1SDaniel Vetter * 3669c8e32cc1SDaniel Vetter * Returns: 3670c8e32cc1SDaniel Vetter * A pointer to the newly created property on success, NULL on failure. 3671c8e32cc1SDaniel Vetter */ 3672d9bc3c02SSascha Hauer struct drm_property *drm_property_create_range(struct drm_device *dev, int flags, 3673d9bc3c02SSascha Hauer const char *name, 3674d9bc3c02SSascha Hauer uint64_t min, uint64_t max) 3675d9bc3c02SSascha Hauer { 3676ebc44cf3SRob Clark return property_create_range(dev, DRM_MODE_PROP_RANGE | flags, 3677ebc44cf3SRob Clark name, min, max); 3678d9bc3c02SSascha Hauer } 3679d9bc3c02SSascha Hauer EXPORT_SYMBOL(drm_property_create_range); 3680d9bc3c02SSascha Hauer 3681ebc44cf3SRob Clark struct drm_property *drm_property_create_signed_range(struct drm_device *dev, 3682ebc44cf3SRob Clark int flags, const char *name, 3683ebc44cf3SRob Clark int64_t min, int64_t max) 3684ebc44cf3SRob Clark { 3685ebc44cf3SRob Clark return property_create_range(dev, DRM_MODE_PROP_SIGNED_RANGE | flags, 3686ebc44cf3SRob Clark name, I642U64(min), I642U64(max)); 3687ebc44cf3SRob Clark } 3688ebc44cf3SRob Clark EXPORT_SYMBOL(drm_property_create_signed_range); 3689ebc44cf3SRob Clark 369098f75de4SRob Clark struct drm_property *drm_property_create_object(struct drm_device *dev, 369198f75de4SRob Clark int flags, const char *name, uint32_t type) 369298f75de4SRob Clark { 369398f75de4SRob Clark struct drm_property *property; 369498f75de4SRob Clark 369598f75de4SRob Clark flags |= DRM_MODE_PROP_OBJECT; 369698f75de4SRob Clark 369798f75de4SRob Clark property = drm_property_create(dev, flags, name, 1); 369898f75de4SRob Clark if (!property) 369998f75de4SRob Clark return NULL; 370098f75de4SRob Clark 370198f75de4SRob Clark property->values[0] = type; 370298f75de4SRob Clark 370398f75de4SRob Clark return property; 370498f75de4SRob Clark } 370598f75de4SRob Clark EXPORT_SYMBOL(drm_property_create_object); 370698f75de4SRob Clark 3707c8e32cc1SDaniel Vetter /** 3708c8e32cc1SDaniel Vetter * drm_property_add_enum - add a possible value to an enumeration property 3709c8e32cc1SDaniel Vetter * @property: enumeration property to change 3710c8e32cc1SDaniel Vetter * @index: index of the new enumeration 3711c8e32cc1SDaniel Vetter * @value: value of the new enumeration 3712c8e32cc1SDaniel Vetter * @name: symbolic name of the new enumeration 3713c8e32cc1SDaniel Vetter * 3714c8e32cc1SDaniel Vetter * This functions adds enumerations to a property. 3715c8e32cc1SDaniel Vetter * 3716c8e32cc1SDaniel Vetter * It's use is deprecated, drivers should use one of the more specific helpers 3717c8e32cc1SDaniel Vetter * to directly create the property with all enumerations already attached. 3718c8e32cc1SDaniel Vetter * 3719c8e32cc1SDaniel Vetter * Returns: 3720c8e32cc1SDaniel Vetter * Zero on success, error code on failure. 3721c8e32cc1SDaniel Vetter */ 3722f453ba04SDave Airlie int drm_property_add_enum(struct drm_property *property, int index, 3723f453ba04SDave Airlie uint64_t value, const char *name) 3724f453ba04SDave Airlie { 3725f453ba04SDave Airlie struct drm_property_enum *prop_enum; 3726f453ba04SDave Airlie 37275ea22f24SRob Clark if (!(drm_property_type_is(property, DRM_MODE_PROP_ENUM) || 37285ea22f24SRob Clark drm_property_type_is(property, DRM_MODE_PROP_BITMASK))) 372949e27545SRob Clark return -EINVAL; 373049e27545SRob Clark 373149e27545SRob Clark /* 373249e27545SRob Clark * Bitmask enum properties have the additional constraint of values 373349e27545SRob Clark * from 0 to 63 373449e27545SRob Clark */ 37355ea22f24SRob Clark if (drm_property_type_is(property, DRM_MODE_PROP_BITMASK) && 37365ea22f24SRob Clark (value > 63)) 3737f453ba04SDave Airlie return -EINVAL; 3738f453ba04SDave Airlie 37393758b341SDaniel Vetter if (!list_empty(&property->enum_list)) { 37403758b341SDaniel Vetter list_for_each_entry(prop_enum, &property->enum_list, head) { 3741f453ba04SDave Airlie if (prop_enum->value == value) { 3742f453ba04SDave Airlie strncpy(prop_enum->name, name, DRM_PROP_NAME_LEN); 3743f453ba04SDave Airlie prop_enum->name[DRM_PROP_NAME_LEN-1] = '\0'; 3744f453ba04SDave Airlie return 0; 3745f453ba04SDave Airlie } 3746f453ba04SDave Airlie } 3747f453ba04SDave Airlie } 3748f453ba04SDave Airlie 3749f453ba04SDave Airlie prop_enum = kzalloc(sizeof(struct drm_property_enum), GFP_KERNEL); 3750f453ba04SDave Airlie if (!prop_enum) 3751f453ba04SDave Airlie return -ENOMEM; 3752f453ba04SDave Airlie 3753f453ba04SDave Airlie strncpy(prop_enum->name, name, DRM_PROP_NAME_LEN); 3754f453ba04SDave Airlie prop_enum->name[DRM_PROP_NAME_LEN-1] = '\0'; 3755f453ba04SDave Airlie prop_enum->value = value; 3756f453ba04SDave Airlie 3757f453ba04SDave Airlie property->values[index] = value; 37583758b341SDaniel Vetter list_add_tail(&prop_enum->head, &property->enum_list); 3759f453ba04SDave Airlie return 0; 3760f453ba04SDave Airlie } 3761f453ba04SDave Airlie EXPORT_SYMBOL(drm_property_add_enum); 3762f453ba04SDave Airlie 3763c8e32cc1SDaniel Vetter /** 3764c8e32cc1SDaniel Vetter * drm_property_destroy - destroy a drm property 3765c8e32cc1SDaniel Vetter * @dev: drm device 3766c8e32cc1SDaniel Vetter * @property: property to destry 3767c8e32cc1SDaniel Vetter * 3768c8e32cc1SDaniel Vetter * This function frees a property including any attached resources like 3769c8e32cc1SDaniel Vetter * enumeration values. 3770c8e32cc1SDaniel Vetter */ 3771f453ba04SDave Airlie void drm_property_destroy(struct drm_device *dev, struct drm_property *property) 3772f453ba04SDave Airlie { 3773f453ba04SDave Airlie struct drm_property_enum *prop_enum, *pt; 3774f453ba04SDave Airlie 37753758b341SDaniel Vetter list_for_each_entry_safe(prop_enum, pt, &property->enum_list, head) { 3776f453ba04SDave Airlie list_del(&prop_enum->head); 3777f453ba04SDave Airlie kfree(prop_enum); 3778f453ba04SDave Airlie } 3779f453ba04SDave Airlie 3780f453ba04SDave Airlie if (property->num_values) 3781f453ba04SDave Airlie kfree(property->values); 3782f453ba04SDave Airlie drm_mode_object_put(dev, &property->base); 3783f453ba04SDave Airlie list_del(&property->head); 3784f453ba04SDave Airlie kfree(property); 3785f453ba04SDave Airlie } 3786f453ba04SDave Airlie EXPORT_SYMBOL(drm_property_destroy); 3787f453ba04SDave Airlie 3788c8e32cc1SDaniel Vetter /** 3789c8e32cc1SDaniel Vetter * drm_object_attach_property - attach a property to a modeset object 3790c8e32cc1SDaniel Vetter * @obj: drm modeset object 3791c8e32cc1SDaniel Vetter * @property: property to attach 3792c8e32cc1SDaniel Vetter * @init_val: initial value of the property 3793c8e32cc1SDaniel Vetter * 3794c8e32cc1SDaniel Vetter * This attaches the given property to the modeset object with the given initial 3795c8e32cc1SDaniel Vetter * value. Currently this function cannot fail since the properties are stored in 3796c8e32cc1SDaniel Vetter * a statically sized array. 3797c8e32cc1SDaniel Vetter */ 3798c543188aSPaulo Zanoni void drm_object_attach_property(struct drm_mode_object *obj, 3799c543188aSPaulo Zanoni struct drm_property *property, 3800c543188aSPaulo Zanoni uint64_t init_val) 3801c543188aSPaulo Zanoni { 38027f88a9beSPaulo Zanoni int count = obj->properties->count; 3803c543188aSPaulo Zanoni 38047f88a9beSPaulo Zanoni if (count == DRM_OBJECT_MAX_PROPERTY) { 38057f88a9beSPaulo Zanoni WARN(1, "Failed to attach object property (type: 0x%x). Please " 38067f88a9beSPaulo Zanoni "increase DRM_OBJECT_MAX_PROPERTY by 1 for each time " 38077f88a9beSPaulo Zanoni "you see this message on the same object type.\n", 38087f88a9beSPaulo Zanoni obj->type); 3809c543188aSPaulo Zanoni return; 3810c543188aSPaulo Zanoni } 3811c543188aSPaulo Zanoni 38127f88a9beSPaulo Zanoni obj->properties->ids[count] = property->base.id; 38137f88a9beSPaulo Zanoni obj->properties->values[count] = init_val; 38147f88a9beSPaulo Zanoni obj->properties->count++; 3815c543188aSPaulo Zanoni } 3816c543188aSPaulo Zanoni EXPORT_SYMBOL(drm_object_attach_property); 3817c543188aSPaulo Zanoni 3818c8e32cc1SDaniel Vetter /** 3819c8e32cc1SDaniel Vetter * drm_object_property_set_value - set the value of a property 3820c8e32cc1SDaniel Vetter * @obj: drm mode object to set property value for 3821c8e32cc1SDaniel Vetter * @property: property to set 3822c8e32cc1SDaniel Vetter * @val: value the property should be set to 3823c8e32cc1SDaniel Vetter * 3824c8e32cc1SDaniel Vetter * This functions sets a given property on a given object. This function only 3825c8e32cc1SDaniel Vetter * changes the software state of the property, it does not call into the 3826c8e32cc1SDaniel Vetter * driver's ->set_property callback. 3827c8e32cc1SDaniel Vetter * 3828c8e32cc1SDaniel Vetter * Returns: 3829c8e32cc1SDaniel Vetter * Zero on success, error code on failure. 3830c8e32cc1SDaniel Vetter */ 3831c543188aSPaulo Zanoni int drm_object_property_set_value(struct drm_mode_object *obj, 3832c543188aSPaulo Zanoni struct drm_property *property, uint64_t val) 3833c543188aSPaulo Zanoni { 3834c543188aSPaulo Zanoni int i; 3835c543188aSPaulo Zanoni 38367f88a9beSPaulo Zanoni for (i = 0; i < obj->properties->count; i++) { 3837c543188aSPaulo Zanoni if (obj->properties->ids[i] == property->base.id) { 3838c543188aSPaulo Zanoni obj->properties->values[i] = val; 3839c543188aSPaulo Zanoni return 0; 3840c543188aSPaulo Zanoni } 3841c543188aSPaulo Zanoni } 3842c543188aSPaulo Zanoni 3843c543188aSPaulo Zanoni return -EINVAL; 3844c543188aSPaulo Zanoni } 3845c543188aSPaulo Zanoni EXPORT_SYMBOL(drm_object_property_set_value); 3846c543188aSPaulo Zanoni 3847c8e32cc1SDaniel Vetter /** 3848c8e32cc1SDaniel Vetter * drm_object_property_get_value - retrieve the value of a property 3849c8e32cc1SDaniel Vetter * @obj: drm mode object to get property value from 3850c8e32cc1SDaniel Vetter * @property: property to retrieve 3851c8e32cc1SDaniel Vetter * @val: storage for the property value 3852c8e32cc1SDaniel Vetter * 3853c8e32cc1SDaniel Vetter * This function retrieves the softare state of the given property for the given 3854c8e32cc1SDaniel Vetter * property. Since there is no driver callback to retrieve the current property 3855c8e32cc1SDaniel Vetter * value this might be out of sync with the hardware, depending upon the driver 3856c8e32cc1SDaniel Vetter * and property. 3857c8e32cc1SDaniel Vetter * 3858c8e32cc1SDaniel Vetter * Returns: 3859c8e32cc1SDaniel Vetter * Zero on success, error code on failure. 3860c8e32cc1SDaniel Vetter */ 3861c543188aSPaulo Zanoni int drm_object_property_get_value(struct drm_mode_object *obj, 3862c543188aSPaulo Zanoni struct drm_property *property, uint64_t *val) 3863c543188aSPaulo Zanoni { 3864c543188aSPaulo Zanoni int i; 3865c543188aSPaulo Zanoni 38667f88a9beSPaulo Zanoni for (i = 0; i < obj->properties->count; i++) { 3867c543188aSPaulo Zanoni if (obj->properties->ids[i] == property->base.id) { 3868c543188aSPaulo Zanoni *val = obj->properties->values[i]; 3869c543188aSPaulo Zanoni return 0; 3870c543188aSPaulo Zanoni } 3871c543188aSPaulo Zanoni } 3872c543188aSPaulo Zanoni 3873c543188aSPaulo Zanoni return -EINVAL; 3874c543188aSPaulo Zanoni } 3875c543188aSPaulo Zanoni EXPORT_SYMBOL(drm_object_property_get_value); 3876c543188aSPaulo Zanoni 3877c8e32cc1SDaniel Vetter /** 38781a498633SDaniel Vetter * drm_mode_getproperty_ioctl - get the property metadata 3879c8e32cc1SDaniel Vetter * @dev: DRM device 3880c8e32cc1SDaniel Vetter * @data: ioctl data 3881c8e32cc1SDaniel Vetter * @file_priv: DRM file info 3882c8e32cc1SDaniel Vetter * 38831a498633SDaniel Vetter * This function retrieves the metadata for a given property, like the different 38841a498633SDaniel Vetter * possible values for an enum property or the limits for a range property. 38851a498633SDaniel Vetter * 38861a498633SDaniel Vetter * Blob properties are special 3887c8e32cc1SDaniel Vetter * 3888c8e32cc1SDaniel Vetter * Called by the user via ioctl. 3889c8e32cc1SDaniel Vetter * 3890c8e32cc1SDaniel Vetter * Returns: 38911a498633SDaniel Vetter * Zero on success, negative errno on failure. 3892c8e32cc1SDaniel Vetter */ 3893f453ba04SDave Airlie int drm_mode_getproperty_ioctl(struct drm_device *dev, 3894f453ba04SDave Airlie void *data, struct drm_file *file_priv) 3895f453ba04SDave Airlie { 3896f453ba04SDave Airlie struct drm_mode_get_property *out_resp = data; 3897f453ba04SDave Airlie struct drm_property *property; 3898f453ba04SDave Airlie int enum_count = 0; 3899f453ba04SDave Airlie int value_count = 0; 3900f453ba04SDave Airlie int ret = 0, i; 3901f453ba04SDave Airlie int copied; 3902f453ba04SDave Airlie struct drm_property_enum *prop_enum; 3903f453ba04SDave Airlie struct drm_mode_property_enum __user *enum_ptr; 3904f453ba04SDave Airlie uint64_t __user *values_ptr; 3905f453ba04SDave Airlie 3906fb3b06c8SDave Airlie if (!drm_core_check_feature(dev, DRIVER_MODESET)) 3907fb3b06c8SDave Airlie return -EINVAL; 3908fb3b06c8SDave Airlie 390984849903SDaniel Vetter drm_modeset_lock_all(dev); 3910a2b34e22SRob Clark property = drm_property_find(dev, out_resp->prop_id); 3911a2b34e22SRob Clark if (!property) { 3912f27657f2SVille Syrjälä ret = -ENOENT; 3913f453ba04SDave Airlie goto done; 3914f453ba04SDave Airlie } 3915f453ba04SDave Airlie 39165ea22f24SRob Clark if (drm_property_type_is(property, DRM_MODE_PROP_ENUM) || 39175ea22f24SRob Clark drm_property_type_is(property, DRM_MODE_PROP_BITMASK)) { 39183758b341SDaniel Vetter list_for_each_entry(prop_enum, &property->enum_list, head) 3919f453ba04SDave Airlie enum_count++; 3920f453ba04SDave Airlie } 3921f453ba04SDave Airlie 3922f453ba04SDave Airlie value_count = property->num_values; 3923f453ba04SDave Airlie 3924f453ba04SDave Airlie strncpy(out_resp->name, property->name, DRM_PROP_NAME_LEN); 3925f453ba04SDave Airlie out_resp->name[DRM_PROP_NAME_LEN-1] = 0; 3926f453ba04SDave Airlie out_resp->flags = property->flags; 3927f453ba04SDave Airlie 3928f453ba04SDave Airlie if ((out_resp->count_values >= value_count) && value_count) { 392981f6c7f8SVille Syrjälä values_ptr = (uint64_t __user *)(unsigned long)out_resp->values_ptr; 3930f453ba04SDave Airlie for (i = 0; i < value_count; i++) { 3931f453ba04SDave Airlie if (copy_to_user(values_ptr + i, &property->values[i], sizeof(uint64_t))) { 3932f453ba04SDave Airlie ret = -EFAULT; 3933f453ba04SDave Airlie goto done; 3934f453ba04SDave Airlie } 3935f453ba04SDave Airlie } 3936f453ba04SDave Airlie } 3937f453ba04SDave Airlie out_resp->count_values = value_count; 3938f453ba04SDave Airlie 39395ea22f24SRob Clark if (drm_property_type_is(property, DRM_MODE_PROP_ENUM) || 39405ea22f24SRob Clark drm_property_type_is(property, DRM_MODE_PROP_BITMASK)) { 3941f453ba04SDave Airlie if ((out_resp->count_enum_blobs >= enum_count) && enum_count) { 3942f453ba04SDave Airlie copied = 0; 394381f6c7f8SVille Syrjälä enum_ptr = (struct drm_mode_property_enum __user *)(unsigned long)out_resp->enum_blob_ptr; 39443758b341SDaniel Vetter list_for_each_entry(prop_enum, &property->enum_list, head) { 3945f453ba04SDave Airlie 3946f453ba04SDave Airlie if (copy_to_user(&enum_ptr[copied].value, &prop_enum->value, sizeof(uint64_t))) { 3947f453ba04SDave Airlie ret = -EFAULT; 3948f453ba04SDave Airlie goto done; 3949f453ba04SDave Airlie } 3950f453ba04SDave Airlie 3951f453ba04SDave Airlie if (copy_to_user(&enum_ptr[copied].name, 3952f453ba04SDave Airlie &prop_enum->name, DRM_PROP_NAME_LEN)) { 3953f453ba04SDave Airlie ret = -EFAULT; 3954f453ba04SDave Airlie goto done; 3955f453ba04SDave Airlie } 3956f453ba04SDave Airlie copied++; 3957f453ba04SDave Airlie } 3958f453ba04SDave Airlie } 3959f453ba04SDave Airlie out_resp->count_enum_blobs = enum_count; 3960f453ba04SDave Airlie } 3961f453ba04SDave Airlie 39623758b341SDaniel Vetter /* 39633758b341SDaniel Vetter * NOTE: The idea seems to have been to use this to read all the blob 39643758b341SDaniel Vetter * property values. But nothing ever added them to the corresponding 39653758b341SDaniel Vetter * list, userspace always used the special-purpose get_blob ioctl to 39663758b341SDaniel Vetter * read the value for a blob property. It also doesn't make a lot of 39673758b341SDaniel Vetter * sense to return values here when everything else is just metadata for 39683758b341SDaniel Vetter * the property itself. 39693758b341SDaniel Vetter */ 39703758b341SDaniel Vetter if (drm_property_type_is(property, DRM_MODE_PROP_BLOB)) 39713758b341SDaniel Vetter out_resp->count_enum_blobs = 0; 3972f453ba04SDave Airlie done: 397384849903SDaniel Vetter drm_modeset_unlock_all(dev); 3974f453ba04SDave Airlie return ret; 3975f453ba04SDave Airlie } 3976f453ba04SDave Airlie 3977ecbbe59bSThierry Reding static struct drm_property_blob * 3978ecbbe59bSThierry Reding drm_property_create_blob(struct drm_device *dev, size_t length, 397912e6cecdSThierry Reding const void *data) 3980f453ba04SDave Airlie { 3981f453ba04SDave Airlie struct drm_property_blob *blob; 39826bfc56aaSVille Syrjälä int ret; 3983f453ba04SDave Airlie 3984f453ba04SDave Airlie if (!length || !data) 3985f453ba04SDave Airlie return NULL; 3986f453ba04SDave Airlie 3987f453ba04SDave Airlie blob = kzalloc(sizeof(struct drm_property_blob)+length, GFP_KERNEL); 3988f453ba04SDave Airlie if (!blob) 3989f453ba04SDave Airlie return NULL; 3990f453ba04SDave Airlie 39916bfc56aaSVille Syrjälä ret = drm_mode_object_get(dev, &blob->base, DRM_MODE_OBJECT_BLOB); 39926bfc56aaSVille Syrjälä if (ret) { 39936bfc56aaSVille Syrjälä kfree(blob); 39946bfc56aaSVille Syrjälä return NULL; 39956bfc56aaSVille Syrjälä } 39966bfc56aaSVille Syrjälä 3997f453ba04SDave Airlie blob->length = length; 3998f453ba04SDave Airlie 3999f453ba04SDave Airlie memcpy(blob->data, data, length); 4000f453ba04SDave Airlie 4001f453ba04SDave Airlie list_add_tail(&blob->head, &dev->mode_config.property_blob_list); 4002f453ba04SDave Airlie return blob; 4003f453ba04SDave Airlie } 4004f453ba04SDave Airlie 4005f453ba04SDave Airlie static void drm_property_destroy_blob(struct drm_device *dev, 4006f453ba04SDave Airlie struct drm_property_blob *blob) 4007f453ba04SDave Airlie { 4008f453ba04SDave Airlie drm_mode_object_put(dev, &blob->base); 4009f453ba04SDave Airlie list_del(&blob->head); 4010f453ba04SDave Airlie kfree(blob); 4011f453ba04SDave Airlie } 4012f453ba04SDave Airlie 4013c8e32cc1SDaniel Vetter /** 4014c8e32cc1SDaniel Vetter * drm_mode_getblob_ioctl - get the contents of a blob property value 4015c8e32cc1SDaniel Vetter * @dev: DRM device 4016c8e32cc1SDaniel Vetter * @data: ioctl data 4017c8e32cc1SDaniel Vetter * @file_priv: DRM file info 4018c8e32cc1SDaniel Vetter * 4019c8e32cc1SDaniel Vetter * This function retrieves the contents of a blob property. The value stored in 4020c8e32cc1SDaniel Vetter * an object's blob property is just a normal modeset object id. 4021c8e32cc1SDaniel Vetter * 4022c8e32cc1SDaniel Vetter * Called by the user via ioctl. 4023c8e32cc1SDaniel Vetter * 4024c8e32cc1SDaniel Vetter * Returns: 40251a498633SDaniel Vetter * Zero on success, negative errno on failure. 4026c8e32cc1SDaniel Vetter */ 4027f453ba04SDave Airlie int drm_mode_getblob_ioctl(struct drm_device *dev, 4028f453ba04SDave Airlie void *data, struct drm_file *file_priv) 4029f453ba04SDave Airlie { 4030f453ba04SDave Airlie struct drm_mode_get_blob *out_resp = data; 4031f453ba04SDave Airlie struct drm_property_blob *blob; 4032f453ba04SDave Airlie int ret = 0; 403381f6c7f8SVille Syrjälä void __user *blob_ptr; 4034f453ba04SDave Airlie 4035fb3b06c8SDave Airlie if (!drm_core_check_feature(dev, DRIVER_MODESET)) 4036fb3b06c8SDave Airlie return -EINVAL; 4037fb3b06c8SDave Airlie 403884849903SDaniel Vetter drm_modeset_lock_all(dev); 4039a2b34e22SRob Clark blob = drm_property_blob_find(dev, out_resp->blob_id); 4040a2b34e22SRob Clark if (!blob) { 4041f27657f2SVille Syrjälä ret = -ENOENT; 4042f453ba04SDave Airlie goto done; 4043f453ba04SDave Airlie } 4044f453ba04SDave Airlie 4045f453ba04SDave Airlie if (out_resp->length == blob->length) { 404681f6c7f8SVille Syrjälä blob_ptr = (void __user *)(unsigned long)out_resp->data; 4047f453ba04SDave Airlie if (copy_to_user(blob_ptr, blob->data, blob->length)) { 4048f453ba04SDave Airlie ret = -EFAULT; 4049f453ba04SDave Airlie goto done; 4050f453ba04SDave Airlie } 4051f453ba04SDave Airlie } 4052f453ba04SDave Airlie out_resp->length = blob->length; 4053f453ba04SDave Airlie 4054f453ba04SDave Airlie done: 405584849903SDaniel Vetter drm_modeset_unlock_all(dev); 4056f453ba04SDave Airlie return ret; 4057f453ba04SDave Airlie } 4058f453ba04SDave Airlie 4059cc7096fbSDave Airlie /** 4060cc7096fbSDave Airlie * drm_mode_connector_set_path_property - set tile property on connector 4061cc7096fbSDave Airlie * @connector: connector to set property on. 4062cc7096fbSDave Airlie * @path: path to use for property. 4063cc7096fbSDave Airlie * 4064cc7096fbSDave Airlie * This creates a property to expose to userspace to specify a 4065cc7096fbSDave Airlie * connector path. This is mainly used for DisplayPort MST where 4066cc7096fbSDave Airlie * connectors have a topology and we want to allow userspace to give 4067cc7096fbSDave Airlie * them more meaningful names. 4068cc7096fbSDave Airlie * 4069cc7096fbSDave Airlie * Returns: 40701a498633SDaniel Vetter * Zero on success, negative errno on failure. 4071cc7096fbSDave Airlie */ 407243aba7ebSDave Airlie int drm_mode_connector_set_path_property(struct drm_connector *connector, 407312e6cecdSThierry Reding const char *path) 407443aba7ebSDave Airlie { 407543aba7ebSDave Airlie struct drm_device *dev = connector->dev; 4076ecbbe59bSThierry Reding size_t size = strlen(path) + 1; 4077ecbbe59bSThierry Reding int ret; 407843aba7ebSDave Airlie 407943aba7ebSDave Airlie connector->path_blob_ptr = drm_property_create_blob(connector->dev, 408043aba7ebSDave Airlie size, path); 408143aba7ebSDave Airlie if (!connector->path_blob_ptr) 408243aba7ebSDave Airlie return -EINVAL; 408343aba7ebSDave Airlie 408443aba7ebSDave Airlie ret = drm_object_property_set_value(&connector->base, 408543aba7ebSDave Airlie dev->mode_config.path_property, 408643aba7ebSDave Airlie connector->path_blob_ptr->base.id); 408743aba7ebSDave Airlie return ret; 408843aba7ebSDave Airlie } 408943aba7ebSDave Airlie EXPORT_SYMBOL(drm_mode_connector_set_path_property); 409043aba7ebSDave Airlie 4091c8e32cc1SDaniel Vetter /** 4092c8e32cc1SDaniel Vetter * drm_mode_connector_update_edid_property - update the edid property of a connector 4093c8e32cc1SDaniel Vetter * @connector: drm connector 4094c8e32cc1SDaniel Vetter * @edid: new value of the edid property 4095c8e32cc1SDaniel Vetter * 4096c8e32cc1SDaniel Vetter * This function creates a new blob modeset object and assigns its id to the 4097c8e32cc1SDaniel Vetter * connector's edid property. 4098c8e32cc1SDaniel Vetter * 4099c8e32cc1SDaniel Vetter * Returns: 41001a498633SDaniel Vetter * Zero on success, negative errno on failure. 4101c8e32cc1SDaniel Vetter */ 4102f453ba04SDave Airlie int drm_mode_connector_update_edid_property(struct drm_connector *connector, 410312e6cecdSThierry Reding const struct edid *edid) 4104f453ba04SDave Airlie { 4105f453ba04SDave Airlie struct drm_device *dev = connector->dev; 4106ecbbe59bSThierry Reding size_t size; 4107ecbbe59bSThierry Reding int ret; 4108f453ba04SDave Airlie 41094cf2b281SThomas Wood /* ignore requests to set edid when overridden */ 41104cf2b281SThomas Wood if (connector->override_edid) 41114cf2b281SThomas Wood return 0; 41124cf2b281SThomas Wood 4113f453ba04SDave Airlie if (connector->edid_blob_ptr) 4114f453ba04SDave Airlie drm_property_destroy_blob(dev, connector->edid_blob_ptr); 4115f453ba04SDave Airlie 4116f453ba04SDave Airlie /* Delete edid, when there is none. */ 4117f453ba04SDave Airlie if (!edid) { 4118f453ba04SDave Airlie connector->edid_blob_ptr = NULL; 411958495563SRob Clark ret = drm_object_property_set_value(&connector->base, dev->mode_config.edid_property, 0); 4120f453ba04SDave Airlie return ret; 4121f453ba04SDave Airlie } 4122f453ba04SDave Airlie 41237466f4ccSAdam Jackson size = EDID_LENGTH * (1 + edid->extensions); 41247466f4ccSAdam Jackson connector->edid_blob_ptr = drm_property_create_blob(connector->dev, 41257466f4ccSAdam Jackson size, edid); 4126e655d122SSachin Kamat if (!connector->edid_blob_ptr) 4127e655d122SSachin Kamat return -EINVAL; 4128f453ba04SDave Airlie 412958495563SRob Clark ret = drm_object_property_set_value(&connector->base, 4130f453ba04SDave Airlie dev->mode_config.edid_property, 4131f453ba04SDave Airlie connector->edid_blob_ptr->base.id); 4132f453ba04SDave Airlie 4133f453ba04SDave Airlie return ret; 4134f453ba04SDave Airlie } 4135f453ba04SDave Airlie EXPORT_SYMBOL(drm_mode_connector_update_edid_property); 4136f453ba04SDave Airlie 413726a34815SPaulo Zanoni static bool drm_property_change_is_valid(struct drm_property *property, 4138592c20eeSVille Syrjälä uint64_t value) 413926a34815SPaulo Zanoni { 414026a34815SPaulo Zanoni if (property->flags & DRM_MODE_PROP_IMMUTABLE) 414126a34815SPaulo Zanoni return false; 41425ea22f24SRob Clark 41435ea22f24SRob Clark if (drm_property_type_is(property, DRM_MODE_PROP_RANGE)) { 414426a34815SPaulo Zanoni if (value < property->values[0] || value > property->values[1]) 414526a34815SPaulo Zanoni return false; 414626a34815SPaulo Zanoni return true; 4147ebc44cf3SRob Clark } else if (drm_property_type_is(property, DRM_MODE_PROP_SIGNED_RANGE)) { 4148ebc44cf3SRob Clark int64_t svalue = U642I64(value); 41494dfd909fSThierry Reding 4150ebc44cf3SRob Clark if (svalue < U642I64(property->values[0]) || 4151ebc44cf3SRob Clark svalue > U642I64(property->values[1])) 4152ebc44cf3SRob Clark return false; 4153ebc44cf3SRob Clark return true; 41545ea22f24SRob Clark } else if (drm_property_type_is(property, DRM_MODE_PROP_BITMASK)) { 415549e27545SRob Clark int i; 4156592c20eeSVille Syrjälä uint64_t valid_mask = 0; 41574dfd909fSThierry Reding 415849e27545SRob Clark for (i = 0; i < property->num_values; i++) 415949e27545SRob Clark valid_mask |= (1ULL << property->values[i]); 416049e27545SRob Clark return !(value & ~valid_mask); 41615ea22f24SRob Clark } else if (drm_property_type_is(property, DRM_MODE_PROP_BLOB)) { 4162c4a56750SVille Syrjälä /* Only the driver knows */ 4163c4a56750SVille Syrjälä return true; 416498f75de4SRob Clark } else if (drm_property_type_is(property, DRM_MODE_PROP_OBJECT)) { 416598f75de4SRob Clark struct drm_mode_object *obj; 41664dfd909fSThierry Reding 416798f75de4SRob Clark /* a zero value for an object property translates to null: */ 416898f75de4SRob Clark if (value == 0) 416998f75de4SRob Clark return true; 417098f75de4SRob Clark /* 417198f75de4SRob Clark * NOTE: use _object_find() directly to bypass restriction on 417298f75de4SRob Clark * looking up refcnt'd objects (ie. fb's). For a refcnt'd 417398f75de4SRob Clark * object this could race against object finalization, so it 417498f75de4SRob Clark * simply tells us that the object *was* valid. Which is good 417598f75de4SRob Clark * enough. 417698f75de4SRob Clark */ 417798f75de4SRob Clark obj = _object_find(property->dev, value, property->values[0]); 417898f75de4SRob Clark return obj != NULL; 417926a34815SPaulo Zanoni } else { 418026a34815SPaulo Zanoni int i; 418126a34815SPaulo Zanoni for (i = 0; i < property->num_values; i++) 418226a34815SPaulo Zanoni if (property->values[i] == value) 418326a34815SPaulo Zanoni return true; 418426a34815SPaulo Zanoni return false; 418526a34815SPaulo Zanoni } 418626a34815SPaulo Zanoni } 418726a34815SPaulo Zanoni 4188c8e32cc1SDaniel Vetter /** 4189c8e32cc1SDaniel Vetter * drm_mode_connector_property_set_ioctl - set the current value of a connector property 4190c8e32cc1SDaniel Vetter * @dev: DRM device 4191c8e32cc1SDaniel Vetter * @data: ioctl data 4192c8e32cc1SDaniel Vetter * @file_priv: DRM file info 4193c8e32cc1SDaniel Vetter * 4194c8e32cc1SDaniel Vetter * This function sets the current value for a connectors's property. It also 4195c8e32cc1SDaniel Vetter * calls into a driver's ->set_property callback to update the hardware state 4196c8e32cc1SDaniel Vetter * 4197c8e32cc1SDaniel Vetter * Called by the user via ioctl. 4198c8e32cc1SDaniel Vetter * 4199c8e32cc1SDaniel Vetter * Returns: 42001a498633SDaniel Vetter * Zero on success, negative errno on failure. 4201c8e32cc1SDaniel Vetter */ 4202f453ba04SDave Airlie int drm_mode_connector_property_set_ioctl(struct drm_device *dev, 4203f453ba04SDave Airlie void *data, struct drm_file *file_priv) 4204f453ba04SDave Airlie { 42050057d8ddSPaulo Zanoni struct drm_mode_connector_set_property *conn_set_prop = data; 42060057d8ddSPaulo Zanoni struct drm_mode_obj_set_property obj_set_prop = { 42070057d8ddSPaulo Zanoni .value = conn_set_prop->value, 42080057d8ddSPaulo Zanoni .prop_id = conn_set_prop->prop_id, 42090057d8ddSPaulo Zanoni .obj_id = conn_set_prop->connector_id, 42100057d8ddSPaulo Zanoni .obj_type = DRM_MODE_OBJECT_CONNECTOR 42110057d8ddSPaulo Zanoni }; 4212f453ba04SDave Airlie 42130057d8ddSPaulo Zanoni /* It does all the locking and checking we need */ 42140057d8ddSPaulo Zanoni return drm_mode_obj_set_property_ioctl(dev, &obj_set_prop, file_priv); 4215f453ba04SDave Airlie } 4216f453ba04SDave Airlie 4217c543188aSPaulo Zanoni static int drm_mode_connector_set_obj_prop(struct drm_mode_object *obj, 4218c543188aSPaulo Zanoni struct drm_property *property, 4219c543188aSPaulo Zanoni uint64_t value) 4220c543188aSPaulo Zanoni { 4221c543188aSPaulo Zanoni int ret = -EINVAL; 4222c543188aSPaulo Zanoni struct drm_connector *connector = obj_to_connector(obj); 4223c543188aSPaulo Zanoni 4224c543188aSPaulo Zanoni /* Do DPMS ourselves */ 4225c543188aSPaulo Zanoni if (property == connector->dev->mode_config.dpms_property) { 4226c543188aSPaulo Zanoni if (connector->funcs->dpms) 4227c543188aSPaulo Zanoni (*connector->funcs->dpms)(connector, (int)value); 4228c543188aSPaulo Zanoni ret = 0; 4229c543188aSPaulo Zanoni } else if (connector->funcs->set_property) 4230c543188aSPaulo Zanoni ret = connector->funcs->set_property(connector, property, value); 4231c543188aSPaulo Zanoni 4232c543188aSPaulo Zanoni /* store the property value if successful */ 4233c543188aSPaulo Zanoni if (!ret) 423458495563SRob Clark drm_object_property_set_value(&connector->base, property, value); 4235c543188aSPaulo Zanoni return ret; 4236c543188aSPaulo Zanoni } 4237c543188aSPaulo Zanoni 4238bffd9de0SPaulo Zanoni static int drm_mode_crtc_set_obj_prop(struct drm_mode_object *obj, 4239bffd9de0SPaulo Zanoni struct drm_property *property, 4240bffd9de0SPaulo Zanoni uint64_t value) 4241bffd9de0SPaulo Zanoni { 4242bffd9de0SPaulo Zanoni int ret = -EINVAL; 4243bffd9de0SPaulo Zanoni struct drm_crtc *crtc = obj_to_crtc(obj); 4244bffd9de0SPaulo Zanoni 4245bffd9de0SPaulo Zanoni if (crtc->funcs->set_property) 4246bffd9de0SPaulo Zanoni ret = crtc->funcs->set_property(crtc, property, value); 4247bffd9de0SPaulo Zanoni if (!ret) 4248bffd9de0SPaulo Zanoni drm_object_property_set_value(obj, property, value); 4249bffd9de0SPaulo Zanoni 4250bffd9de0SPaulo Zanoni return ret; 4251bffd9de0SPaulo Zanoni } 4252bffd9de0SPaulo Zanoni 42533a5f87c2SThomas Wood /** 42543a5f87c2SThomas Wood * drm_mode_plane_set_obj_prop - set the value of a property 42553a5f87c2SThomas Wood * @plane: drm plane object to set property value for 42563a5f87c2SThomas Wood * @property: property to set 42573a5f87c2SThomas Wood * @value: value the property should be set to 42583a5f87c2SThomas Wood * 42593a5f87c2SThomas Wood * This functions sets a given property on a given plane object. This function 42603a5f87c2SThomas Wood * calls the driver's ->set_property callback and changes the software state of 42613a5f87c2SThomas Wood * the property if the callback succeeds. 42623a5f87c2SThomas Wood * 42633a5f87c2SThomas Wood * Returns: 42643a5f87c2SThomas Wood * Zero on success, error code on failure. 42653a5f87c2SThomas Wood */ 42663a5f87c2SThomas Wood int drm_mode_plane_set_obj_prop(struct drm_plane *plane, 42674d93914aSRob Clark struct drm_property *property, 42684d93914aSRob Clark uint64_t value) 42694d93914aSRob Clark { 42704d93914aSRob Clark int ret = -EINVAL; 42713a5f87c2SThomas Wood struct drm_mode_object *obj = &plane->base; 42724d93914aSRob Clark 42734d93914aSRob Clark if (plane->funcs->set_property) 42744d93914aSRob Clark ret = plane->funcs->set_property(plane, property, value); 42754d93914aSRob Clark if (!ret) 42764d93914aSRob Clark drm_object_property_set_value(obj, property, value); 42774d93914aSRob Clark 42784d93914aSRob Clark return ret; 42794d93914aSRob Clark } 42803a5f87c2SThomas Wood EXPORT_SYMBOL(drm_mode_plane_set_obj_prop); 42814d93914aSRob Clark 4282c8e32cc1SDaniel Vetter /** 42831a498633SDaniel Vetter * drm_mode_obj_get_properties_ioctl - get the current value of a object's property 4284c8e32cc1SDaniel Vetter * @dev: DRM device 4285c8e32cc1SDaniel Vetter * @data: ioctl data 4286c8e32cc1SDaniel Vetter * @file_priv: DRM file info 4287c8e32cc1SDaniel Vetter * 4288c8e32cc1SDaniel Vetter * This function retrieves the current value for an object's property. Compared 4289c8e32cc1SDaniel Vetter * to the connector specific ioctl this one is extended to also work on crtc and 4290c8e32cc1SDaniel Vetter * plane objects. 4291c8e32cc1SDaniel Vetter * 4292c8e32cc1SDaniel Vetter * Called by the user via ioctl. 4293c8e32cc1SDaniel Vetter * 4294c8e32cc1SDaniel Vetter * Returns: 42951a498633SDaniel Vetter * Zero on success, negative errno on failure. 4296c8e32cc1SDaniel Vetter */ 4297c543188aSPaulo Zanoni int drm_mode_obj_get_properties_ioctl(struct drm_device *dev, void *data, 4298c543188aSPaulo Zanoni struct drm_file *file_priv) 4299c543188aSPaulo Zanoni { 4300c543188aSPaulo Zanoni struct drm_mode_obj_get_properties *arg = data; 4301c543188aSPaulo Zanoni struct drm_mode_object *obj; 4302c543188aSPaulo Zanoni int ret = 0; 4303c543188aSPaulo Zanoni int i; 4304c543188aSPaulo Zanoni int copied = 0; 4305c543188aSPaulo Zanoni int props_count = 0; 4306c543188aSPaulo Zanoni uint32_t __user *props_ptr; 4307c543188aSPaulo Zanoni uint64_t __user *prop_values_ptr; 4308c543188aSPaulo Zanoni 4309c543188aSPaulo Zanoni if (!drm_core_check_feature(dev, DRIVER_MODESET)) 4310c543188aSPaulo Zanoni return -EINVAL; 4311c543188aSPaulo Zanoni 431284849903SDaniel Vetter drm_modeset_lock_all(dev); 4313c543188aSPaulo Zanoni 4314c543188aSPaulo Zanoni obj = drm_mode_object_find(dev, arg->obj_id, arg->obj_type); 4315c543188aSPaulo Zanoni if (!obj) { 4316f27657f2SVille Syrjälä ret = -ENOENT; 4317c543188aSPaulo Zanoni goto out; 4318c543188aSPaulo Zanoni } 4319c543188aSPaulo Zanoni if (!obj->properties) { 4320c543188aSPaulo Zanoni ret = -EINVAL; 4321c543188aSPaulo Zanoni goto out; 4322c543188aSPaulo Zanoni } 4323c543188aSPaulo Zanoni 43247f88a9beSPaulo Zanoni props_count = obj->properties->count; 4325c543188aSPaulo Zanoni 4326c543188aSPaulo Zanoni /* This ioctl is called twice, once to determine how much space is 4327c543188aSPaulo Zanoni * needed, and the 2nd time to fill it. */ 4328c543188aSPaulo Zanoni if ((arg->count_props >= props_count) && props_count) { 4329c543188aSPaulo Zanoni copied = 0; 4330c543188aSPaulo Zanoni props_ptr = (uint32_t __user *)(unsigned long)(arg->props_ptr); 4331c543188aSPaulo Zanoni prop_values_ptr = (uint64_t __user *)(unsigned long) 4332c543188aSPaulo Zanoni (arg->prop_values_ptr); 4333c543188aSPaulo Zanoni for (i = 0; i < props_count; i++) { 4334c543188aSPaulo Zanoni if (put_user(obj->properties->ids[i], 4335c543188aSPaulo Zanoni props_ptr + copied)) { 4336c543188aSPaulo Zanoni ret = -EFAULT; 4337c543188aSPaulo Zanoni goto out; 4338c543188aSPaulo Zanoni } 4339c543188aSPaulo Zanoni if (put_user(obj->properties->values[i], 4340c543188aSPaulo Zanoni prop_values_ptr + copied)) { 4341c543188aSPaulo Zanoni ret = -EFAULT; 4342c543188aSPaulo Zanoni goto out; 4343c543188aSPaulo Zanoni } 4344c543188aSPaulo Zanoni copied++; 4345c543188aSPaulo Zanoni } 4346c543188aSPaulo Zanoni } 4347c543188aSPaulo Zanoni arg->count_props = props_count; 4348c543188aSPaulo Zanoni out: 434984849903SDaniel Vetter drm_modeset_unlock_all(dev); 4350c543188aSPaulo Zanoni return ret; 4351c543188aSPaulo Zanoni } 4352c543188aSPaulo Zanoni 4353c8e32cc1SDaniel Vetter /** 4354c8e32cc1SDaniel Vetter * drm_mode_obj_set_property_ioctl - set the current value of an object's property 4355c8e32cc1SDaniel Vetter * @dev: DRM device 4356c8e32cc1SDaniel Vetter * @data: ioctl data 4357c8e32cc1SDaniel Vetter * @file_priv: DRM file info 4358c8e32cc1SDaniel Vetter * 4359c8e32cc1SDaniel Vetter * This function sets the current value for an object's property. It also calls 4360c8e32cc1SDaniel Vetter * into a driver's ->set_property callback to update the hardware state. 4361c8e32cc1SDaniel Vetter * Compared to the connector specific ioctl this one is extended to also work on 4362c8e32cc1SDaniel Vetter * crtc and plane objects. 4363c8e32cc1SDaniel Vetter * 4364c8e32cc1SDaniel Vetter * Called by the user via ioctl. 4365c8e32cc1SDaniel Vetter * 4366c8e32cc1SDaniel Vetter * Returns: 43671a498633SDaniel Vetter * Zero on success, negative errno on failure. 4368c8e32cc1SDaniel Vetter */ 4369c543188aSPaulo Zanoni int drm_mode_obj_set_property_ioctl(struct drm_device *dev, void *data, 4370c543188aSPaulo Zanoni struct drm_file *file_priv) 4371c543188aSPaulo Zanoni { 4372c543188aSPaulo Zanoni struct drm_mode_obj_set_property *arg = data; 4373c543188aSPaulo Zanoni struct drm_mode_object *arg_obj; 4374c543188aSPaulo Zanoni struct drm_mode_object *prop_obj; 4375c543188aSPaulo Zanoni struct drm_property *property; 4376c543188aSPaulo Zanoni int ret = -EINVAL; 4377c543188aSPaulo Zanoni int i; 4378c543188aSPaulo Zanoni 4379c543188aSPaulo Zanoni if (!drm_core_check_feature(dev, DRIVER_MODESET)) 4380c543188aSPaulo Zanoni return -EINVAL; 4381c543188aSPaulo Zanoni 438284849903SDaniel Vetter drm_modeset_lock_all(dev); 4383c543188aSPaulo Zanoni 4384c543188aSPaulo Zanoni arg_obj = drm_mode_object_find(dev, arg->obj_id, arg->obj_type); 4385f27657f2SVille Syrjälä if (!arg_obj) { 4386f27657f2SVille Syrjälä ret = -ENOENT; 4387c543188aSPaulo Zanoni goto out; 4388f27657f2SVille Syrjälä } 4389c543188aSPaulo Zanoni if (!arg_obj->properties) 4390c543188aSPaulo Zanoni goto out; 4391c543188aSPaulo Zanoni 43927f88a9beSPaulo Zanoni for (i = 0; i < arg_obj->properties->count; i++) 4393c543188aSPaulo Zanoni if (arg_obj->properties->ids[i] == arg->prop_id) 4394c543188aSPaulo Zanoni break; 4395c543188aSPaulo Zanoni 43967f88a9beSPaulo Zanoni if (i == arg_obj->properties->count) 4397c543188aSPaulo Zanoni goto out; 4398c543188aSPaulo Zanoni 4399c543188aSPaulo Zanoni prop_obj = drm_mode_object_find(dev, arg->prop_id, 4400c543188aSPaulo Zanoni DRM_MODE_OBJECT_PROPERTY); 4401f27657f2SVille Syrjälä if (!prop_obj) { 4402f27657f2SVille Syrjälä ret = -ENOENT; 4403c543188aSPaulo Zanoni goto out; 4404f27657f2SVille Syrjälä } 4405c543188aSPaulo Zanoni property = obj_to_property(prop_obj); 4406c543188aSPaulo Zanoni 4407c543188aSPaulo Zanoni if (!drm_property_change_is_valid(property, arg->value)) 4408c543188aSPaulo Zanoni goto out; 4409c543188aSPaulo Zanoni 4410c543188aSPaulo Zanoni switch (arg_obj->type) { 4411c543188aSPaulo Zanoni case DRM_MODE_OBJECT_CONNECTOR: 4412c543188aSPaulo Zanoni ret = drm_mode_connector_set_obj_prop(arg_obj, property, 4413c543188aSPaulo Zanoni arg->value); 4414c543188aSPaulo Zanoni break; 4415bffd9de0SPaulo Zanoni case DRM_MODE_OBJECT_CRTC: 4416bffd9de0SPaulo Zanoni ret = drm_mode_crtc_set_obj_prop(arg_obj, property, arg->value); 4417bffd9de0SPaulo Zanoni break; 44184d93914aSRob Clark case DRM_MODE_OBJECT_PLANE: 44193a5f87c2SThomas Wood ret = drm_mode_plane_set_obj_prop(obj_to_plane(arg_obj), 44203a5f87c2SThomas Wood property, arg->value); 44214d93914aSRob Clark break; 4422c543188aSPaulo Zanoni } 4423c543188aSPaulo Zanoni 4424c543188aSPaulo Zanoni out: 442584849903SDaniel Vetter drm_modeset_unlock_all(dev); 4426c543188aSPaulo Zanoni return ret; 4427c543188aSPaulo Zanoni } 4428c543188aSPaulo Zanoni 4429c8e32cc1SDaniel Vetter /** 4430c8e32cc1SDaniel Vetter * drm_mode_connector_attach_encoder - attach a connector to an encoder 4431c8e32cc1SDaniel Vetter * @connector: connector to attach 4432c8e32cc1SDaniel Vetter * @encoder: encoder to attach @connector to 4433c8e32cc1SDaniel Vetter * 4434c8e32cc1SDaniel Vetter * This function links up a connector to an encoder. Note that the routing 4435c8e32cc1SDaniel Vetter * restrictions between encoders and crtcs are exposed to userspace through the 4436c8e32cc1SDaniel Vetter * possible_clones and possible_crtcs bitmasks. 4437c8e32cc1SDaniel Vetter * 4438c8e32cc1SDaniel Vetter * Returns: 44391a498633SDaniel Vetter * Zero on success, negative errno on failure. 4440c8e32cc1SDaniel Vetter */ 4441f453ba04SDave Airlie int drm_mode_connector_attach_encoder(struct drm_connector *connector, 4442f453ba04SDave Airlie struct drm_encoder *encoder) 4443f453ba04SDave Airlie { 4444f453ba04SDave Airlie int i; 4445f453ba04SDave Airlie 4446f453ba04SDave Airlie for (i = 0; i < DRM_CONNECTOR_MAX_ENCODER; i++) { 4447f453ba04SDave Airlie if (connector->encoder_ids[i] == 0) { 4448f453ba04SDave Airlie connector->encoder_ids[i] = encoder->base.id; 4449f453ba04SDave Airlie return 0; 4450f453ba04SDave Airlie } 4451f453ba04SDave Airlie } 4452f453ba04SDave Airlie return -ENOMEM; 4453f453ba04SDave Airlie } 4454f453ba04SDave Airlie EXPORT_SYMBOL(drm_mode_connector_attach_encoder); 4455f453ba04SDave Airlie 4456c8e32cc1SDaniel Vetter /** 4457c8e32cc1SDaniel Vetter * drm_mode_crtc_set_gamma_size - set the gamma table size 4458c8e32cc1SDaniel Vetter * @crtc: CRTC to set the gamma table size for 4459c8e32cc1SDaniel Vetter * @gamma_size: size of the gamma table 4460c8e32cc1SDaniel Vetter * 4461c8e32cc1SDaniel Vetter * Drivers which support gamma tables should set this to the supported gamma 4462c8e32cc1SDaniel Vetter * table size when initializing the CRTC. Currently the drm core only supports a 4463c8e32cc1SDaniel Vetter * fixed gamma table size. 4464c8e32cc1SDaniel Vetter * 4465c8e32cc1SDaniel Vetter * Returns: 44661a498633SDaniel Vetter * Zero on success, negative errno on failure. 4467c8e32cc1SDaniel Vetter */ 44684cae5b84SSascha Hauer int drm_mode_crtc_set_gamma_size(struct drm_crtc *crtc, 4469f453ba04SDave Airlie int gamma_size) 4470f453ba04SDave Airlie { 4471f453ba04SDave Airlie crtc->gamma_size = gamma_size; 4472f453ba04SDave Airlie 4473bd3f0ff9SThierry Reding crtc->gamma_store = kcalloc(gamma_size, sizeof(uint16_t) * 3, 4474bd3f0ff9SThierry Reding GFP_KERNEL); 4475f453ba04SDave Airlie if (!crtc->gamma_store) { 4476f453ba04SDave Airlie crtc->gamma_size = 0; 44774cae5b84SSascha Hauer return -ENOMEM; 4478f453ba04SDave Airlie } 4479f453ba04SDave Airlie 44804cae5b84SSascha Hauer return 0; 4481f453ba04SDave Airlie } 4482f453ba04SDave Airlie EXPORT_SYMBOL(drm_mode_crtc_set_gamma_size); 4483f453ba04SDave Airlie 4484c8e32cc1SDaniel Vetter /** 4485c8e32cc1SDaniel Vetter * drm_mode_gamma_set_ioctl - set the gamma table 4486c8e32cc1SDaniel Vetter * @dev: DRM device 4487c8e32cc1SDaniel Vetter * @data: ioctl data 4488c8e32cc1SDaniel Vetter * @file_priv: DRM file info 4489c8e32cc1SDaniel Vetter * 4490c8e32cc1SDaniel Vetter * Set the gamma table of a CRTC to the one passed in by the user. Userspace can 4491c8e32cc1SDaniel Vetter * inquire the required gamma table size through drm_mode_gamma_get_ioctl. 4492c8e32cc1SDaniel Vetter * 4493c8e32cc1SDaniel Vetter * Called by the user via ioctl. 4494c8e32cc1SDaniel Vetter * 4495c8e32cc1SDaniel Vetter * Returns: 44961a498633SDaniel Vetter * Zero on success, negative errno on failure. 4497c8e32cc1SDaniel Vetter */ 4498f453ba04SDave Airlie int drm_mode_gamma_set_ioctl(struct drm_device *dev, 4499f453ba04SDave Airlie void *data, struct drm_file *file_priv) 4500f453ba04SDave Airlie { 4501f453ba04SDave Airlie struct drm_mode_crtc_lut *crtc_lut = data; 4502f453ba04SDave Airlie struct drm_crtc *crtc; 4503f453ba04SDave Airlie void *r_base, *g_base, *b_base; 4504f453ba04SDave Airlie int size; 4505f453ba04SDave Airlie int ret = 0; 4506f453ba04SDave Airlie 4507fb3b06c8SDave Airlie if (!drm_core_check_feature(dev, DRIVER_MODESET)) 4508fb3b06c8SDave Airlie return -EINVAL; 4509fb3b06c8SDave Airlie 451084849903SDaniel Vetter drm_modeset_lock_all(dev); 4511a2b34e22SRob Clark crtc = drm_crtc_find(dev, crtc_lut->crtc_id); 4512a2b34e22SRob Clark if (!crtc) { 4513f27657f2SVille Syrjälä ret = -ENOENT; 4514f453ba04SDave Airlie goto out; 4515f453ba04SDave Airlie } 4516f453ba04SDave Airlie 4517ebe0f244SLaurent Pinchart if (crtc->funcs->gamma_set == NULL) { 4518ebe0f244SLaurent Pinchart ret = -ENOSYS; 4519ebe0f244SLaurent Pinchart goto out; 4520ebe0f244SLaurent Pinchart } 4521ebe0f244SLaurent Pinchart 4522f453ba04SDave Airlie /* memcpy into gamma store */ 4523f453ba04SDave Airlie if (crtc_lut->gamma_size != crtc->gamma_size) { 4524f453ba04SDave Airlie ret = -EINVAL; 4525f453ba04SDave Airlie goto out; 4526f453ba04SDave Airlie } 4527f453ba04SDave Airlie 4528f453ba04SDave Airlie size = crtc_lut->gamma_size * (sizeof(uint16_t)); 4529f453ba04SDave Airlie r_base = crtc->gamma_store; 4530f453ba04SDave Airlie if (copy_from_user(r_base, (void __user *)(unsigned long)crtc_lut->red, size)) { 4531f453ba04SDave Airlie ret = -EFAULT; 4532f453ba04SDave Airlie goto out; 4533f453ba04SDave Airlie } 4534f453ba04SDave Airlie 4535f453ba04SDave Airlie g_base = r_base + size; 4536f453ba04SDave Airlie if (copy_from_user(g_base, (void __user *)(unsigned long)crtc_lut->green, size)) { 4537f453ba04SDave Airlie ret = -EFAULT; 4538f453ba04SDave Airlie goto out; 4539f453ba04SDave Airlie } 4540f453ba04SDave Airlie 4541f453ba04SDave Airlie b_base = g_base + size; 4542f453ba04SDave Airlie if (copy_from_user(b_base, (void __user *)(unsigned long)crtc_lut->blue, size)) { 4543f453ba04SDave Airlie ret = -EFAULT; 4544f453ba04SDave Airlie goto out; 4545f453ba04SDave Airlie } 4546f453ba04SDave Airlie 45477203425aSJames Simmons crtc->funcs->gamma_set(crtc, r_base, g_base, b_base, 0, crtc->gamma_size); 4548f453ba04SDave Airlie 4549f453ba04SDave Airlie out: 455084849903SDaniel Vetter drm_modeset_unlock_all(dev); 4551f453ba04SDave Airlie return ret; 4552f453ba04SDave Airlie 4553f453ba04SDave Airlie } 4554f453ba04SDave Airlie 4555c8e32cc1SDaniel Vetter /** 4556c8e32cc1SDaniel Vetter * drm_mode_gamma_get_ioctl - get the gamma table 4557c8e32cc1SDaniel Vetter * @dev: DRM device 4558c8e32cc1SDaniel Vetter * @data: ioctl data 4559c8e32cc1SDaniel Vetter * @file_priv: DRM file info 4560c8e32cc1SDaniel Vetter * 4561c8e32cc1SDaniel Vetter * Copy the current gamma table into the storage provided. This also provides 4562c8e32cc1SDaniel Vetter * the gamma table size the driver expects, which can be used to size the 4563c8e32cc1SDaniel Vetter * allocated storage. 4564c8e32cc1SDaniel Vetter * 4565c8e32cc1SDaniel Vetter * Called by the user via ioctl. 4566c8e32cc1SDaniel Vetter * 4567c8e32cc1SDaniel Vetter * Returns: 45681a498633SDaniel Vetter * Zero on success, negative errno on failure. 4569c8e32cc1SDaniel Vetter */ 4570f453ba04SDave Airlie int drm_mode_gamma_get_ioctl(struct drm_device *dev, 4571f453ba04SDave Airlie void *data, struct drm_file *file_priv) 4572f453ba04SDave Airlie { 4573f453ba04SDave Airlie struct drm_mode_crtc_lut *crtc_lut = data; 4574f453ba04SDave Airlie struct drm_crtc *crtc; 4575f453ba04SDave Airlie void *r_base, *g_base, *b_base; 4576f453ba04SDave Airlie int size; 4577f453ba04SDave Airlie int ret = 0; 4578f453ba04SDave Airlie 4579fb3b06c8SDave Airlie if (!drm_core_check_feature(dev, DRIVER_MODESET)) 4580fb3b06c8SDave Airlie return -EINVAL; 4581fb3b06c8SDave Airlie 458284849903SDaniel Vetter drm_modeset_lock_all(dev); 4583a2b34e22SRob Clark crtc = drm_crtc_find(dev, crtc_lut->crtc_id); 4584a2b34e22SRob Clark if (!crtc) { 4585f27657f2SVille Syrjälä ret = -ENOENT; 4586f453ba04SDave Airlie goto out; 4587f453ba04SDave Airlie } 4588f453ba04SDave Airlie 4589f453ba04SDave Airlie /* memcpy into gamma store */ 4590f453ba04SDave Airlie if (crtc_lut->gamma_size != crtc->gamma_size) { 4591f453ba04SDave Airlie ret = -EINVAL; 4592f453ba04SDave Airlie goto out; 4593f453ba04SDave Airlie } 4594f453ba04SDave Airlie 4595f453ba04SDave Airlie size = crtc_lut->gamma_size * (sizeof(uint16_t)); 4596f453ba04SDave Airlie r_base = crtc->gamma_store; 4597f453ba04SDave Airlie if (copy_to_user((void __user *)(unsigned long)crtc_lut->red, r_base, size)) { 4598f453ba04SDave Airlie ret = -EFAULT; 4599f453ba04SDave Airlie goto out; 4600f453ba04SDave Airlie } 4601f453ba04SDave Airlie 4602f453ba04SDave Airlie g_base = r_base + size; 4603f453ba04SDave Airlie if (copy_to_user((void __user *)(unsigned long)crtc_lut->green, g_base, size)) { 4604f453ba04SDave Airlie ret = -EFAULT; 4605f453ba04SDave Airlie goto out; 4606f453ba04SDave Airlie } 4607f453ba04SDave Airlie 4608f453ba04SDave Airlie b_base = g_base + size; 4609f453ba04SDave Airlie if (copy_to_user((void __user *)(unsigned long)crtc_lut->blue, b_base, size)) { 4610f453ba04SDave Airlie ret = -EFAULT; 4611f453ba04SDave Airlie goto out; 4612f453ba04SDave Airlie } 4613f453ba04SDave Airlie out: 461484849903SDaniel Vetter drm_modeset_unlock_all(dev); 4615f453ba04SDave Airlie return ret; 4616f453ba04SDave Airlie } 4617d91d8a3fSKristian Høgsberg 4618c8e32cc1SDaniel Vetter /** 4619c8e32cc1SDaniel Vetter * drm_mode_page_flip_ioctl - schedule an asynchronous fb update 4620c8e32cc1SDaniel Vetter * @dev: DRM device 4621c8e32cc1SDaniel Vetter * @data: ioctl data 4622c8e32cc1SDaniel Vetter * @file_priv: DRM file info 4623c8e32cc1SDaniel Vetter * 4624c8e32cc1SDaniel Vetter * This schedules an asynchronous update on a given CRTC, called page flip. 4625c8e32cc1SDaniel Vetter * Optionally a drm event is generated to signal the completion of the event. 4626c8e32cc1SDaniel Vetter * Generic drivers cannot assume that a pageflip with changed framebuffer 4627c8e32cc1SDaniel Vetter * properties (including driver specific metadata like tiling layout) will work, 4628c8e32cc1SDaniel Vetter * but some drivers support e.g. pixel format changes through the pageflip 4629c8e32cc1SDaniel Vetter * ioctl. 4630c8e32cc1SDaniel Vetter * 4631c8e32cc1SDaniel Vetter * Called by the user via ioctl. 4632c8e32cc1SDaniel Vetter * 4633c8e32cc1SDaniel Vetter * Returns: 46341a498633SDaniel Vetter * Zero on success, negative errno on failure. 4635c8e32cc1SDaniel Vetter */ 4636d91d8a3fSKristian Høgsberg int drm_mode_page_flip_ioctl(struct drm_device *dev, 4637d91d8a3fSKristian Høgsberg void *data, struct drm_file *file_priv) 4638d91d8a3fSKristian Høgsberg { 4639d91d8a3fSKristian Høgsberg struct drm_mode_crtc_page_flip *page_flip = data; 4640d91d8a3fSKristian Høgsberg struct drm_crtc *crtc; 46413d30a59bSDaniel Vetter struct drm_framebuffer *fb = NULL; 4642d91d8a3fSKristian Høgsberg struct drm_pending_vblank_event *e = NULL; 4643d91d8a3fSKristian Høgsberg unsigned long flags; 4644d91d8a3fSKristian Høgsberg int ret = -EINVAL; 4645d91d8a3fSKristian Høgsberg 4646d91d8a3fSKristian Høgsberg if (page_flip->flags & ~DRM_MODE_PAGE_FLIP_FLAGS || 4647d91d8a3fSKristian Høgsberg page_flip->reserved != 0) 4648d91d8a3fSKristian Høgsberg return -EINVAL; 4649d91d8a3fSKristian Høgsberg 465062f2104fSKeith Packard if ((page_flip->flags & DRM_MODE_PAGE_FLIP_ASYNC) && !dev->mode_config.async_page_flip) 465162f2104fSKeith Packard return -EINVAL; 465262f2104fSKeith Packard 4653a2b34e22SRob Clark crtc = drm_crtc_find(dev, page_flip->crtc_id); 4654a2b34e22SRob Clark if (!crtc) 4655f27657f2SVille Syrjälä return -ENOENT; 4656d91d8a3fSKristian Høgsberg 46574d02e2deSDaniel Vetter drm_modeset_lock_crtc(crtc, crtc->primary); 4658f4510a27SMatt Roper if (crtc->primary->fb == NULL) { 465990c1efddSChris Wilson /* The framebuffer is currently unbound, presumably 466090c1efddSChris Wilson * due to a hotplug event, that userspace has not 466190c1efddSChris Wilson * yet discovered. 466290c1efddSChris Wilson */ 466390c1efddSChris Wilson ret = -EBUSY; 466490c1efddSChris Wilson goto out; 466590c1efddSChris Wilson } 466690c1efddSChris Wilson 4667d91d8a3fSKristian Høgsberg if (crtc->funcs->page_flip == NULL) 4668d91d8a3fSKristian Høgsberg goto out; 4669d91d8a3fSKristian Høgsberg 4670786b99edSDaniel Vetter fb = drm_framebuffer_lookup(dev, page_flip->fb_id); 467137c4e705SVille Syrjälä if (!fb) { 467237c4e705SVille Syrjälä ret = -ENOENT; 4673d91d8a3fSKristian Høgsberg goto out; 467437c4e705SVille Syrjälä } 4675d91d8a3fSKristian Høgsberg 4676c11e9283SDamien Lespiau ret = drm_crtc_check_viewport(crtc, crtc->x, crtc->y, &crtc->mode, fb); 4677c11e9283SDamien Lespiau if (ret) 46785f61bb42SVille Syrjälä goto out; 46795f61bb42SVille Syrjälä 4680f4510a27SMatt Roper if (crtc->primary->fb->pixel_format != fb->pixel_format) { 4681909d9cdaSLaurent Pinchart DRM_DEBUG_KMS("Page flip is not allowed to change frame buffer format.\n"); 4682909d9cdaSLaurent Pinchart ret = -EINVAL; 4683909d9cdaSLaurent Pinchart goto out; 4684909d9cdaSLaurent Pinchart } 4685909d9cdaSLaurent Pinchart 4686d91d8a3fSKristian Høgsberg if (page_flip->flags & DRM_MODE_PAGE_FLIP_EVENT) { 4687d91d8a3fSKristian Høgsberg ret = -ENOMEM; 4688d91d8a3fSKristian Høgsberg spin_lock_irqsave(&dev->event_lock, flags); 4689d91d8a3fSKristian Høgsberg if (file_priv->event_space < sizeof e->event) { 4690d91d8a3fSKristian Høgsberg spin_unlock_irqrestore(&dev->event_lock, flags); 4691d91d8a3fSKristian Høgsberg goto out; 4692d91d8a3fSKristian Høgsberg } 4693d91d8a3fSKristian Høgsberg file_priv->event_space -= sizeof e->event; 4694d91d8a3fSKristian Høgsberg spin_unlock_irqrestore(&dev->event_lock, flags); 4695d91d8a3fSKristian Høgsberg 4696d91d8a3fSKristian Høgsberg e = kzalloc(sizeof *e, GFP_KERNEL); 4697d91d8a3fSKristian Høgsberg if (e == NULL) { 4698d91d8a3fSKristian Høgsberg spin_lock_irqsave(&dev->event_lock, flags); 4699d91d8a3fSKristian Høgsberg file_priv->event_space += sizeof e->event; 4700d91d8a3fSKristian Høgsberg spin_unlock_irqrestore(&dev->event_lock, flags); 4701d91d8a3fSKristian Høgsberg goto out; 4702d91d8a3fSKristian Høgsberg } 4703d91d8a3fSKristian Høgsberg 47047bd4d7beSJesse Barnes e->event.base.type = DRM_EVENT_FLIP_COMPLETE; 4705d91d8a3fSKristian Høgsberg e->event.base.length = sizeof e->event; 4706d91d8a3fSKristian Høgsberg e->event.user_data = page_flip->user_data; 4707d91d8a3fSKristian Høgsberg e->base.event = &e->event.base; 4708d91d8a3fSKristian Høgsberg e->base.file_priv = file_priv; 4709d91d8a3fSKristian Høgsberg e->base.destroy = 4710d91d8a3fSKristian Høgsberg (void (*) (struct drm_pending_event *)) kfree; 4711d91d8a3fSKristian Høgsberg } 4712d91d8a3fSKristian Høgsberg 47133d30a59bSDaniel Vetter crtc->primary->old_fb = crtc->primary->fb; 4714ed8d1975SKeith Packard ret = crtc->funcs->page_flip(crtc, fb, e, page_flip->flags); 4715d91d8a3fSKristian Høgsberg if (ret) { 4716aef6a7eeSJoonyoung Shim if (page_flip->flags & DRM_MODE_PAGE_FLIP_EVENT) { 4717d91d8a3fSKristian Høgsberg spin_lock_irqsave(&dev->event_lock, flags); 4718d91d8a3fSKristian Høgsberg file_priv->event_space += sizeof e->event; 4719d91d8a3fSKristian Høgsberg spin_unlock_irqrestore(&dev->event_lock, flags); 4720d91d8a3fSKristian Høgsberg kfree(e); 4721d91d8a3fSKristian Høgsberg } 4722b0d12325SDaniel Vetter /* Keep the old fb, don't unref it. */ 47233d30a59bSDaniel Vetter crtc->primary->old_fb = NULL; 4724b0d12325SDaniel Vetter } else { 47258cf1e981SThierry Reding /* 47268cf1e981SThierry Reding * Warn if the driver hasn't properly updated the crtc->fb 47278cf1e981SThierry Reding * field to reflect that the new framebuffer is now used. 47288cf1e981SThierry Reding * Failing to do so will screw with the reference counting 47298cf1e981SThierry Reding * on framebuffers. 47308cf1e981SThierry Reding */ 4731f4510a27SMatt Roper WARN_ON(crtc->primary->fb != fb); 4732b0d12325SDaniel Vetter /* Unref only the old framebuffer. */ 4733b0d12325SDaniel Vetter fb = NULL; 4734aef6a7eeSJoonyoung Shim } 4735d91d8a3fSKristian Høgsberg 4736d91d8a3fSKristian Høgsberg out: 4737b0d12325SDaniel Vetter if (fb) 4738b0d12325SDaniel Vetter drm_framebuffer_unreference(fb); 47393d30a59bSDaniel Vetter if (crtc->primary->old_fb) 47403d30a59bSDaniel Vetter drm_framebuffer_unreference(crtc->primary->old_fb); 47413d30a59bSDaniel Vetter crtc->primary->old_fb = NULL; 4742d059f652SDaniel Vetter drm_modeset_unlock_crtc(crtc); 4743b4d5e7d1SDaniel Vetter 4744d91d8a3fSKristian Høgsberg return ret; 4745d91d8a3fSKristian Høgsberg } 4746eb033556SChris Wilson 4747c8e32cc1SDaniel Vetter /** 4748c8e32cc1SDaniel Vetter * drm_mode_config_reset - call ->reset callbacks 4749c8e32cc1SDaniel Vetter * @dev: drm device 4750c8e32cc1SDaniel Vetter * 4751c8e32cc1SDaniel Vetter * This functions calls all the crtc's, encoder's and connector's ->reset 4752c8e32cc1SDaniel Vetter * callback. Drivers can use this in e.g. their driver load or resume code to 4753c8e32cc1SDaniel Vetter * reset hardware and software state. 4754c8e32cc1SDaniel Vetter */ 4755eb033556SChris Wilson void drm_mode_config_reset(struct drm_device *dev) 4756eb033556SChris Wilson { 4757eb033556SChris Wilson struct drm_crtc *crtc; 47582a0d7cfdSDaniel Vetter struct drm_plane *plane; 4759eb033556SChris Wilson struct drm_encoder *encoder; 4760eb033556SChris Wilson struct drm_connector *connector; 4761eb033556SChris Wilson 47622a0d7cfdSDaniel Vetter list_for_each_entry(plane, &dev->mode_config.plane_list, head) 47632a0d7cfdSDaniel Vetter if (plane->funcs->reset) 47642a0d7cfdSDaniel Vetter plane->funcs->reset(plane); 47652a0d7cfdSDaniel Vetter 4766eb033556SChris Wilson list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) 4767eb033556SChris Wilson if (crtc->funcs->reset) 4768eb033556SChris Wilson crtc->funcs->reset(crtc); 4769eb033556SChris Wilson 4770eb033556SChris Wilson list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) 4771eb033556SChris Wilson if (encoder->funcs->reset) 4772eb033556SChris Wilson encoder->funcs->reset(encoder); 4773eb033556SChris Wilson 47745e2cb2f6SDaniel Vetter list_for_each_entry(connector, &dev->mode_config.connector_list, head) { 47755e2cb2f6SDaniel Vetter connector->status = connector_status_unknown; 47765e2cb2f6SDaniel Vetter 4777eb033556SChris Wilson if (connector->funcs->reset) 4778eb033556SChris Wilson connector->funcs->reset(connector); 4779eb033556SChris Wilson } 47805e2cb2f6SDaniel Vetter } 4781eb033556SChris Wilson EXPORT_SYMBOL(drm_mode_config_reset); 4782ff72145bSDave Airlie 4783c8e32cc1SDaniel Vetter /** 4784c8e32cc1SDaniel Vetter * drm_mode_create_dumb_ioctl - create a dumb backing storage buffer 4785c8e32cc1SDaniel Vetter * @dev: DRM device 4786c8e32cc1SDaniel Vetter * @data: ioctl data 4787c8e32cc1SDaniel Vetter * @file_priv: DRM file info 4788c8e32cc1SDaniel Vetter * 4789c8e32cc1SDaniel Vetter * This creates a new dumb buffer in the driver's backing storage manager (GEM, 4790c8e32cc1SDaniel Vetter * TTM or something else entirely) and returns the resulting buffer handle. This 4791c8e32cc1SDaniel Vetter * handle can then be wrapped up into a framebuffer modeset object. 4792c8e32cc1SDaniel Vetter * 4793c8e32cc1SDaniel Vetter * Note that userspace is not allowed to use such objects for render 4794c8e32cc1SDaniel Vetter * acceleration - drivers must create their own private ioctls for such a use 4795c8e32cc1SDaniel Vetter * case. 4796c8e32cc1SDaniel Vetter * 4797c8e32cc1SDaniel Vetter * Called by the user via ioctl. 4798c8e32cc1SDaniel Vetter * 4799c8e32cc1SDaniel Vetter * Returns: 48001a498633SDaniel Vetter * Zero on success, negative errno on failure. 4801c8e32cc1SDaniel Vetter */ 4802ff72145bSDave Airlie int drm_mode_create_dumb_ioctl(struct drm_device *dev, 4803ff72145bSDave Airlie void *data, struct drm_file *file_priv) 4804ff72145bSDave Airlie { 4805ff72145bSDave Airlie struct drm_mode_create_dumb *args = data; 4806b28cd41fSDavid Herrmann u32 cpp, stride, size; 4807ff72145bSDave Airlie 4808ff72145bSDave Airlie if (!dev->driver->dumb_create) 4809ff72145bSDave Airlie return -ENOSYS; 4810b28cd41fSDavid Herrmann if (!args->width || !args->height || !args->bpp) 4811b28cd41fSDavid Herrmann return -EINVAL; 4812b28cd41fSDavid Herrmann 4813b28cd41fSDavid Herrmann /* overflow checks for 32bit size calculations */ 481400e72089SDavid Herrmann /* NOTE: DIV_ROUND_UP() can overflow */ 4815b28cd41fSDavid Herrmann cpp = DIV_ROUND_UP(args->bpp, 8); 481600e72089SDavid Herrmann if (!cpp || cpp > 0xffffffffU / args->width) 4817b28cd41fSDavid Herrmann return -EINVAL; 4818b28cd41fSDavid Herrmann stride = cpp * args->width; 4819b28cd41fSDavid Herrmann if (args->height > 0xffffffffU / stride) 4820b28cd41fSDavid Herrmann return -EINVAL; 4821b28cd41fSDavid Herrmann 4822b28cd41fSDavid Herrmann /* test for wrap-around */ 4823b28cd41fSDavid Herrmann size = args->height * stride; 4824b28cd41fSDavid Herrmann if (PAGE_ALIGN(size) == 0) 4825b28cd41fSDavid Herrmann return -EINVAL; 4826b28cd41fSDavid Herrmann 4827f6085952SThierry Reding /* 4828f6085952SThierry Reding * handle, pitch and size are output parameters. Zero them out to 4829f6085952SThierry Reding * prevent drivers from accidentally using uninitialized data. Since 4830f6085952SThierry Reding * not all existing userspace is clearing these fields properly we 4831f6085952SThierry Reding * cannot reject IOCTL with garbage in them. 4832f6085952SThierry Reding */ 4833f6085952SThierry Reding args->handle = 0; 4834f6085952SThierry Reding args->pitch = 0; 4835f6085952SThierry Reding args->size = 0; 4836f6085952SThierry Reding 4837ff72145bSDave Airlie return dev->driver->dumb_create(file_priv, dev, args); 4838ff72145bSDave Airlie } 4839ff72145bSDave Airlie 4840c8e32cc1SDaniel Vetter /** 4841c8e32cc1SDaniel Vetter * drm_mode_mmap_dumb_ioctl - create an mmap offset for a dumb backing storage buffer 4842c8e32cc1SDaniel Vetter * @dev: DRM device 4843c8e32cc1SDaniel Vetter * @data: ioctl data 4844c8e32cc1SDaniel Vetter * @file_priv: DRM file info 4845c8e32cc1SDaniel Vetter * 4846c8e32cc1SDaniel Vetter * Allocate an offset in the drm device node's address space to be able to 4847c8e32cc1SDaniel Vetter * memory map a dumb buffer. 4848c8e32cc1SDaniel Vetter * 4849c8e32cc1SDaniel Vetter * Called by the user via ioctl. 4850c8e32cc1SDaniel Vetter * 4851c8e32cc1SDaniel Vetter * Returns: 48521a498633SDaniel Vetter * Zero on success, negative errno on failure. 4853c8e32cc1SDaniel Vetter */ 4854ff72145bSDave Airlie int drm_mode_mmap_dumb_ioctl(struct drm_device *dev, 4855ff72145bSDave Airlie void *data, struct drm_file *file_priv) 4856ff72145bSDave Airlie { 4857ff72145bSDave Airlie struct drm_mode_map_dumb *args = data; 4858ff72145bSDave Airlie 4859ff72145bSDave Airlie /* call driver ioctl to get mmap offset */ 4860ff72145bSDave Airlie if (!dev->driver->dumb_map_offset) 4861ff72145bSDave Airlie return -ENOSYS; 4862ff72145bSDave Airlie 4863ff72145bSDave Airlie return dev->driver->dumb_map_offset(file_priv, dev, args->handle, &args->offset); 4864ff72145bSDave Airlie } 4865ff72145bSDave Airlie 4866c8e32cc1SDaniel Vetter /** 4867c8e32cc1SDaniel Vetter * drm_mode_destroy_dumb_ioctl - destroy a dumb backing strage buffer 4868c8e32cc1SDaniel Vetter * @dev: DRM device 4869c8e32cc1SDaniel Vetter * @data: ioctl data 4870c8e32cc1SDaniel Vetter * @file_priv: DRM file info 4871c8e32cc1SDaniel Vetter * 4872c8e32cc1SDaniel Vetter * This destroys the userspace handle for the given dumb backing storage buffer. 4873c8e32cc1SDaniel Vetter * Since buffer objects must be reference counted in the kernel a buffer object 4874c8e32cc1SDaniel Vetter * won't be immediately freed if a framebuffer modeset object still uses it. 4875c8e32cc1SDaniel Vetter * 4876c8e32cc1SDaniel Vetter * Called by the user via ioctl. 4877c8e32cc1SDaniel Vetter * 4878c8e32cc1SDaniel Vetter * Returns: 48791a498633SDaniel Vetter * Zero on success, negative errno on failure. 4880c8e32cc1SDaniel Vetter */ 4881ff72145bSDave Airlie int drm_mode_destroy_dumb_ioctl(struct drm_device *dev, 4882ff72145bSDave Airlie void *data, struct drm_file *file_priv) 4883ff72145bSDave Airlie { 4884ff72145bSDave Airlie struct drm_mode_destroy_dumb *args = data; 4885ff72145bSDave Airlie 4886ff72145bSDave Airlie if (!dev->driver->dumb_destroy) 4887ff72145bSDave Airlie return -ENOSYS; 4888ff72145bSDave Airlie 4889ff72145bSDave Airlie return dev->driver->dumb_destroy(file_priv, dev, args->handle); 4890ff72145bSDave Airlie } 4891248dbc23SDave Airlie 4892c8e32cc1SDaniel Vetter /** 4893c8e32cc1SDaniel Vetter * drm_fb_get_bpp_depth - get the bpp/depth values for format 4894c8e32cc1SDaniel Vetter * @format: pixel format (DRM_FORMAT_*) 4895c8e32cc1SDaniel Vetter * @depth: storage for the depth value 4896c8e32cc1SDaniel Vetter * @bpp: storage for the bpp value 4897c8e32cc1SDaniel Vetter * 4898c8e32cc1SDaniel Vetter * This only supports RGB formats here for compat with code that doesn't use 4899c8e32cc1SDaniel Vetter * pixel formats directly yet. 4900248dbc23SDave Airlie */ 4901248dbc23SDave Airlie void drm_fb_get_bpp_depth(uint32_t format, unsigned int *depth, 4902248dbc23SDave Airlie int *bpp) 4903248dbc23SDave Airlie { 4904248dbc23SDave Airlie switch (format) { 4905c51a6bc5SVille Syrjälä case DRM_FORMAT_C8: 490604b3924dSVille Syrjälä case DRM_FORMAT_RGB332: 490704b3924dSVille Syrjälä case DRM_FORMAT_BGR233: 4908248dbc23SDave Airlie *depth = 8; 4909248dbc23SDave Airlie *bpp = 8; 4910248dbc23SDave Airlie break; 491104b3924dSVille Syrjälä case DRM_FORMAT_XRGB1555: 491204b3924dSVille Syrjälä case DRM_FORMAT_XBGR1555: 491304b3924dSVille Syrjälä case DRM_FORMAT_RGBX5551: 491404b3924dSVille Syrjälä case DRM_FORMAT_BGRX5551: 491504b3924dSVille Syrjälä case DRM_FORMAT_ARGB1555: 491604b3924dSVille Syrjälä case DRM_FORMAT_ABGR1555: 491704b3924dSVille Syrjälä case DRM_FORMAT_RGBA5551: 491804b3924dSVille Syrjälä case DRM_FORMAT_BGRA5551: 4919248dbc23SDave Airlie *depth = 15; 4920248dbc23SDave Airlie *bpp = 16; 4921248dbc23SDave Airlie break; 492204b3924dSVille Syrjälä case DRM_FORMAT_RGB565: 492304b3924dSVille Syrjälä case DRM_FORMAT_BGR565: 4924248dbc23SDave Airlie *depth = 16; 4925248dbc23SDave Airlie *bpp = 16; 4926248dbc23SDave Airlie break; 492704b3924dSVille Syrjälä case DRM_FORMAT_RGB888: 492804b3924dSVille Syrjälä case DRM_FORMAT_BGR888: 492904b3924dSVille Syrjälä *depth = 24; 493004b3924dSVille Syrjälä *bpp = 24; 493104b3924dSVille Syrjälä break; 493204b3924dSVille Syrjälä case DRM_FORMAT_XRGB8888: 493304b3924dSVille Syrjälä case DRM_FORMAT_XBGR8888: 493404b3924dSVille Syrjälä case DRM_FORMAT_RGBX8888: 493504b3924dSVille Syrjälä case DRM_FORMAT_BGRX8888: 4936248dbc23SDave Airlie *depth = 24; 4937248dbc23SDave Airlie *bpp = 32; 4938248dbc23SDave Airlie break; 493904b3924dSVille Syrjälä case DRM_FORMAT_XRGB2101010: 494004b3924dSVille Syrjälä case DRM_FORMAT_XBGR2101010: 494104b3924dSVille Syrjälä case DRM_FORMAT_RGBX1010102: 494204b3924dSVille Syrjälä case DRM_FORMAT_BGRX1010102: 494304b3924dSVille Syrjälä case DRM_FORMAT_ARGB2101010: 494404b3924dSVille Syrjälä case DRM_FORMAT_ABGR2101010: 494504b3924dSVille Syrjälä case DRM_FORMAT_RGBA1010102: 494604b3924dSVille Syrjälä case DRM_FORMAT_BGRA1010102: 4947248dbc23SDave Airlie *depth = 30; 4948248dbc23SDave Airlie *bpp = 32; 4949248dbc23SDave Airlie break; 495004b3924dSVille Syrjälä case DRM_FORMAT_ARGB8888: 495104b3924dSVille Syrjälä case DRM_FORMAT_ABGR8888: 495204b3924dSVille Syrjälä case DRM_FORMAT_RGBA8888: 495304b3924dSVille Syrjälä case DRM_FORMAT_BGRA8888: 4954248dbc23SDave Airlie *depth = 32; 4955248dbc23SDave Airlie *bpp = 32; 4956248dbc23SDave Airlie break; 4957248dbc23SDave Airlie default: 495823c453a4SVille Syrjälä DRM_DEBUG_KMS("unsupported pixel format %s\n", 495923c453a4SVille Syrjälä drm_get_format_name(format)); 4960248dbc23SDave Airlie *depth = 0; 4961248dbc23SDave Airlie *bpp = 0; 4962248dbc23SDave Airlie break; 4963248dbc23SDave Airlie } 4964248dbc23SDave Airlie } 4965248dbc23SDave Airlie EXPORT_SYMBOL(drm_fb_get_bpp_depth); 4966141670e9SVille Syrjälä 4967141670e9SVille Syrjälä /** 4968141670e9SVille Syrjälä * drm_format_num_planes - get the number of planes for format 4969141670e9SVille Syrjälä * @format: pixel format (DRM_FORMAT_*) 4970141670e9SVille Syrjälä * 4971c8e32cc1SDaniel Vetter * Returns: 4972141670e9SVille Syrjälä * The number of planes used by the specified pixel format. 4973141670e9SVille Syrjälä */ 4974141670e9SVille Syrjälä int drm_format_num_planes(uint32_t format) 4975141670e9SVille Syrjälä { 4976141670e9SVille Syrjälä switch (format) { 4977141670e9SVille Syrjälä case DRM_FORMAT_YUV410: 4978141670e9SVille Syrjälä case DRM_FORMAT_YVU410: 4979141670e9SVille Syrjälä case DRM_FORMAT_YUV411: 4980141670e9SVille Syrjälä case DRM_FORMAT_YVU411: 4981141670e9SVille Syrjälä case DRM_FORMAT_YUV420: 4982141670e9SVille Syrjälä case DRM_FORMAT_YVU420: 4983141670e9SVille Syrjälä case DRM_FORMAT_YUV422: 4984141670e9SVille Syrjälä case DRM_FORMAT_YVU422: 4985141670e9SVille Syrjälä case DRM_FORMAT_YUV444: 4986141670e9SVille Syrjälä case DRM_FORMAT_YVU444: 4987141670e9SVille Syrjälä return 3; 4988141670e9SVille Syrjälä case DRM_FORMAT_NV12: 4989141670e9SVille Syrjälä case DRM_FORMAT_NV21: 4990141670e9SVille Syrjälä case DRM_FORMAT_NV16: 4991141670e9SVille Syrjälä case DRM_FORMAT_NV61: 4992ba623f6aSLaurent Pinchart case DRM_FORMAT_NV24: 4993ba623f6aSLaurent Pinchart case DRM_FORMAT_NV42: 4994141670e9SVille Syrjälä return 2; 4995141670e9SVille Syrjälä default: 4996141670e9SVille Syrjälä return 1; 4997141670e9SVille Syrjälä } 4998141670e9SVille Syrjälä } 4999141670e9SVille Syrjälä EXPORT_SYMBOL(drm_format_num_planes); 50005a86bd55SVille Syrjälä 50015a86bd55SVille Syrjälä /** 50025a86bd55SVille Syrjälä * drm_format_plane_cpp - determine the bytes per pixel value 50035a86bd55SVille Syrjälä * @format: pixel format (DRM_FORMAT_*) 50045a86bd55SVille Syrjälä * @plane: plane index 50055a86bd55SVille Syrjälä * 5006c8e32cc1SDaniel Vetter * Returns: 50075a86bd55SVille Syrjälä * The bytes per pixel value for the specified plane. 50085a86bd55SVille Syrjälä */ 50095a86bd55SVille Syrjälä int drm_format_plane_cpp(uint32_t format, int plane) 50105a86bd55SVille Syrjälä { 50115a86bd55SVille Syrjälä unsigned int depth; 50125a86bd55SVille Syrjälä int bpp; 50135a86bd55SVille Syrjälä 50145a86bd55SVille Syrjälä if (plane >= drm_format_num_planes(format)) 50155a86bd55SVille Syrjälä return 0; 50165a86bd55SVille Syrjälä 50175a86bd55SVille Syrjälä switch (format) { 50185a86bd55SVille Syrjälä case DRM_FORMAT_YUYV: 50195a86bd55SVille Syrjälä case DRM_FORMAT_YVYU: 50205a86bd55SVille Syrjälä case DRM_FORMAT_UYVY: 50215a86bd55SVille Syrjälä case DRM_FORMAT_VYUY: 50225a86bd55SVille Syrjälä return 2; 50235a86bd55SVille Syrjälä case DRM_FORMAT_NV12: 50245a86bd55SVille Syrjälä case DRM_FORMAT_NV21: 50255a86bd55SVille Syrjälä case DRM_FORMAT_NV16: 50265a86bd55SVille Syrjälä case DRM_FORMAT_NV61: 5027ba623f6aSLaurent Pinchart case DRM_FORMAT_NV24: 5028ba623f6aSLaurent Pinchart case DRM_FORMAT_NV42: 50295a86bd55SVille Syrjälä return plane ? 2 : 1; 50305a86bd55SVille Syrjälä case DRM_FORMAT_YUV410: 50315a86bd55SVille Syrjälä case DRM_FORMAT_YVU410: 50325a86bd55SVille Syrjälä case DRM_FORMAT_YUV411: 50335a86bd55SVille Syrjälä case DRM_FORMAT_YVU411: 50345a86bd55SVille Syrjälä case DRM_FORMAT_YUV420: 50355a86bd55SVille Syrjälä case DRM_FORMAT_YVU420: 50365a86bd55SVille Syrjälä case DRM_FORMAT_YUV422: 50375a86bd55SVille Syrjälä case DRM_FORMAT_YVU422: 50385a86bd55SVille Syrjälä case DRM_FORMAT_YUV444: 50395a86bd55SVille Syrjälä case DRM_FORMAT_YVU444: 50405a86bd55SVille Syrjälä return 1; 50415a86bd55SVille Syrjälä default: 50425a86bd55SVille Syrjälä drm_fb_get_bpp_depth(format, &depth, &bpp); 50435a86bd55SVille Syrjälä return bpp >> 3; 50445a86bd55SVille Syrjälä } 50455a86bd55SVille Syrjälä } 50465a86bd55SVille Syrjälä EXPORT_SYMBOL(drm_format_plane_cpp); 504701b68b04SVille Syrjälä 504801b68b04SVille Syrjälä /** 504901b68b04SVille Syrjälä * drm_format_horz_chroma_subsampling - get the horizontal chroma subsampling factor 505001b68b04SVille Syrjälä * @format: pixel format (DRM_FORMAT_*) 505101b68b04SVille Syrjälä * 5052c8e32cc1SDaniel Vetter * Returns: 505301b68b04SVille Syrjälä * The horizontal chroma subsampling factor for the 505401b68b04SVille Syrjälä * specified pixel format. 505501b68b04SVille Syrjälä */ 505601b68b04SVille Syrjälä int drm_format_horz_chroma_subsampling(uint32_t format) 505701b68b04SVille Syrjälä { 505801b68b04SVille Syrjälä switch (format) { 505901b68b04SVille Syrjälä case DRM_FORMAT_YUV411: 506001b68b04SVille Syrjälä case DRM_FORMAT_YVU411: 506101b68b04SVille Syrjälä case DRM_FORMAT_YUV410: 506201b68b04SVille Syrjälä case DRM_FORMAT_YVU410: 506301b68b04SVille Syrjälä return 4; 506401b68b04SVille Syrjälä case DRM_FORMAT_YUYV: 506501b68b04SVille Syrjälä case DRM_FORMAT_YVYU: 506601b68b04SVille Syrjälä case DRM_FORMAT_UYVY: 506701b68b04SVille Syrjälä case DRM_FORMAT_VYUY: 506801b68b04SVille Syrjälä case DRM_FORMAT_NV12: 506901b68b04SVille Syrjälä case DRM_FORMAT_NV21: 507001b68b04SVille Syrjälä case DRM_FORMAT_NV16: 507101b68b04SVille Syrjälä case DRM_FORMAT_NV61: 507201b68b04SVille Syrjälä case DRM_FORMAT_YUV422: 507301b68b04SVille Syrjälä case DRM_FORMAT_YVU422: 507401b68b04SVille Syrjälä case DRM_FORMAT_YUV420: 507501b68b04SVille Syrjälä case DRM_FORMAT_YVU420: 507601b68b04SVille Syrjälä return 2; 507701b68b04SVille Syrjälä default: 507801b68b04SVille Syrjälä return 1; 507901b68b04SVille Syrjälä } 508001b68b04SVille Syrjälä } 508101b68b04SVille Syrjälä EXPORT_SYMBOL(drm_format_horz_chroma_subsampling); 508201b68b04SVille Syrjälä 508301b68b04SVille Syrjälä /** 508401b68b04SVille Syrjälä * drm_format_vert_chroma_subsampling - get the vertical chroma subsampling factor 508501b68b04SVille Syrjälä * @format: pixel format (DRM_FORMAT_*) 508601b68b04SVille Syrjälä * 5087c8e32cc1SDaniel Vetter * Returns: 508801b68b04SVille Syrjälä * The vertical chroma subsampling factor for the 508901b68b04SVille Syrjälä * specified pixel format. 509001b68b04SVille Syrjälä */ 509101b68b04SVille Syrjälä int drm_format_vert_chroma_subsampling(uint32_t format) 509201b68b04SVille Syrjälä { 509301b68b04SVille Syrjälä switch (format) { 509401b68b04SVille Syrjälä case DRM_FORMAT_YUV410: 509501b68b04SVille Syrjälä case DRM_FORMAT_YVU410: 509601b68b04SVille Syrjälä return 4; 509701b68b04SVille Syrjälä case DRM_FORMAT_YUV420: 509801b68b04SVille Syrjälä case DRM_FORMAT_YVU420: 509901b68b04SVille Syrjälä case DRM_FORMAT_NV12: 510001b68b04SVille Syrjälä case DRM_FORMAT_NV21: 510101b68b04SVille Syrjälä return 2; 510201b68b04SVille Syrjälä default: 510301b68b04SVille Syrjälä return 1; 510401b68b04SVille Syrjälä } 510501b68b04SVille Syrjälä } 510601b68b04SVille Syrjälä EXPORT_SYMBOL(drm_format_vert_chroma_subsampling); 510787d24fc3SLaurent Pinchart 510887d24fc3SLaurent Pinchart /** 51093c9855f6SVille Syrjälä * drm_rotation_simplify() - Try to simplify the rotation 51103c9855f6SVille Syrjälä * @rotation: Rotation to be simplified 51113c9855f6SVille Syrjälä * @supported_rotations: Supported rotations 51123c9855f6SVille Syrjälä * 51133c9855f6SVille Syrjälä * Attempt to simplify the rotation to a form that is supported. 51143c9855f6SVille Syrjälä * Eg. if the hardware supports everything except DRM_REFLECT_X 51153c9855f6SVille Syrjälä * one could call this function like this: 51163c9855f6SVille Syrjälä * 51173c9855f6SVille Syrjälä * drm_rotation_simplify(rotation, BIT(DRM_ROTATE_0) | 51183c9855f6SVille Syrjälä * BIT(DRM_ROTATE_90) | BIT(DRM_ROTATE_180) | 51193c9855f6SVille Syrjälä * BIT(DRM_ROTATE_270) | BIT(DRM_REFLECT_Y)); 51203c9855f6SVille Syrjälä * 51213c9855f6SVille Syrjälä * to eliminate the DRM_ROTATE_X flag. Depending on what kind of 51223c9855f6SVille Syrjälä * transforms the hardware supports, this function may not 51233c9855f6SVille Syrjälä * be able to produce a supported transform, so the caller should 51243c9855f6SVille Syrjälä * check the result afterwards. 51253c9855f6SVille Syrjälä */ 51263c9855f6SVille Syrjälä unsigned int drm_rotation_simplify(unsigned int rotation, 51273c9855f6SVille Syrjälä unsigned int supported_rotations) 51283c9855f6SVille Syrjälä { 51293c9855f6SVille Syrjälä if (rotation & ~supported_rotations) { 51303c9855f6SVille Syrjälä rotation ^= BIT(DRM_REFLECT_X) | BIT(DRM_REFLECT_Y); 51313c9855f6SVille Syrjälä rotation = (rotation & ~0xf) | BIT((ffs(rotation & 0xf) + 1) % 4); 51323c9855f6SVille Syrjälä } 51333c9855f6SVille Syrjälä 51343c9855f6SVille Syrjälä return rotation; 51353c9855f6SVille Syrjälä } 51363c9855f6SVille Syrjälä EXPORT_SYMBOL(drm_rotation_simplify); 51373c9855f6SVille Syrjälä 51383c9855f6SVille Syrjälä /** 513987d24fc3SLaurent Pinchart * drm_mode_config_init - initialize DRM mode_configuration structure 514087d24fc3SLaurent Pinchart * @dev: DRM device 514187d24fc3SLaurent Pinchart * 514287d24fc3SLaurent Pinchart * Initialize @dev's mode_config structure, used for tracking the graphics 514387d24fc3SLaurent Pinchart * configuration of @dev. 514487d24fc3SLaurent Pinchart * 514587d24fc3SLaurent Pinchart * Since this initializes the modeset locks, no locking is possible. Which is no 514687d24fc3SLaurent Pinchart * problem, since this should happen single threaded at init time. It is the 514787d24fc3SLaurent Pinchart * driver's problem to ensure this guarantee. 514887d24fc3SLaurent Pinchart * 514987d24fc3SLaurent Pinchart */ 515087d24fc3SLaurent Pinchart void drm_mode_config_init(struct drm_device *dev) 515187d24fc3SLaurent Pinchart { 515287d24fc3SLaurent Pinchart mutex_init(&dev->mode_config.mutex); 515351fd371bSRob Clark drm_modeset_lock_init(&dev->mode_config.connection_mutex); 515487d24fc3SLaurent Pinchart mutex_init(&dev->mode_config.idr_mutex); 515587d24fc3SLaurent Pinchart mutex_init(&dev->mode_config.fb_lock); 515687d24fc3SLaurent Pinchart INIT_LIST_HEAD(&dev->mode_config.fb_list); 515787d24fc3SLaurent Pinchart INIT_LIST_HEAD(&dev->mode_config.crtc_list); 515887d24fc3SLaurent Pinchart INIT_LIST_HEAD(&dev->mode_config.connector_list); 51593b336ec4SSean Paul INIT_LIST_HEAD(&dev->mode_config.bridge_list); 516087d24fc3SLaurent Pinchart INIT_LIST_HEAD(&dev->mode_config.encoder_list); 516187d24fc3SLaurent Pinchart INIT_LIST_HEAD(&dev->mode_config.property_list); 516287d24fc3SLaurent Pinchart INIT_LIST_HEAD(&dev->mode_config.property_blob_list); 516387d24fc3SLaurent Pinchart INIT_LIST_HEAD(&dev->mode_config.plane_list); 516487d24fc3SLaurent Pinchart idr_init(&dev->mode_config.crtc_idr); 516587d24fc3SLaurent Pinchart 516687d24fc3SLaurent Pinchart drm_modeset_lock_all(dev); 516787d24fc3SLaurent Pinchart drm_mode_create_standard_connector_properties(dev); 51689922ab5aSRob Clark drm_mode_create_standard_plane_properties(dev); 516987d24fc3SLaurent Pinchart drm_modeset_unlock_all(dev); 517087d24fc3SLaurent Pinchart 517187d24fc3SLaurent Pinchart /* Just to be sure */ 517287d24fc3SLaurent Pinchart dev->mode_config.num_fb = 0; 517387d24fc3SLaurent Pinchart dev->mode_config.num_connector = 0; 517487d24fc3SLaurent Pinchart dev->mode_config.num_crtc = 0; 517587d24fc3SLaurent Pinchart dev->mode_config.num_encoder = 0; 5176e27dde3eSMatt Roper dev->mode_config.num_overlay_plane = 0; 5177e27dde3eSMatt Roper dev->mode_config.num_total_plane = 0; 517887d24fc3SLaurent Pinchart } 517987d24fc3SLaurent Pinchart EXPORT_SYMBOL(drm_mode_config_init); 518087d24fc3SLaurent Pinchart 518187d24fc3SLaurent Pinchart /** 518287d24fc3SLaurent Pinchart * drm_mode_config_cleanup - free up DRM mode_config info 518387d24fc3SLaurent Pinchart * @dev: DRM device 518487d24fc3SLaurent Pinchart * 518587d24fc3SLaurent Pinchart * Free up all the connectors and CRTCs associated with this DRM device, then 518687d24fc3SLaurent Pinchart * free up the framebuffers and associated buffer objects. 518787d24fc3SLaurent Pinchart * 518887d24fc3SLaurent Pinchart * Note that since this /should/ happen single-threaded at driver/device 518987d24fc3SLaurent Pinchart * teardown time, no locking is required. It's the driver's job to ensure that 519087d24fc3SLaurent Pinchart * this guarantee actually holds true. 519187d24fc3SLaurent Pinchart * 519287d24fc3SLaurent Pinchart * FIXME: cleanup any dangling user buffer objects too 519387d24fc3SLaurent Pinchart */ 519487d24fc3SLaurent Pinchart void drm_mode_config_cleanup(struct drm_device *dev) 519587d24fc3SLaurent Pinchart { 519687d24fc3SLaurent Pinchart struct drm_connector *connector, *ot; 519787d24fc3SLaurent Pinchart struct drm_crtc *crtc, *ct; 519887d24fc3SLaurent Pinchart struct drm_encoder *encoder, *enct; 51993b336ec4SSean Paul struct drm_bridge *bridge, *brt; 520087d24fc3SLaurent Pinchart struct drm_framebuffer *fb, *fbt; 520187d24fc3SLaurent Pinchart struct drm_property *property, *pt; 520287d24fc3SLaurent Pinchart struct drm_property_blob *blob, *bt; 520387d24fc3SLaurent Pinchart struct drm_plane *plane, *plt; 520487d24fc3SLaurent Pinchart 520587d24fc3SLaurent Pinchart list_for_each_entry_safe(encoder, enct, &dev->mode_config.encoder_list, 520687d24fc3SLaurent Pinchart head) { 520787d24fc3SLaurent Pinchart encoder->funcs->destroy(encoder); 520887d24fc3SLaurent Pinchart } 520987d24fc3SLaurent Pinchart 52103b336ec4SSean Paul list_for_each_entry_safe(bridge, brt, 52113b336ec4SSean Paul &dev->mode_config.bridge_list, head) { 52123b336ec4SSean Paul bridge->funcs->destroy(bridge); 52133b336ec4SSean Paul } 52143b336ec4SSean Paul 521587d24fc3SLaurent Pinchart list_for_each_entry_safe(connector, ot, 521687d24fc3SLaurent Pinchart &dev->mode_config.connector_list, head) { 521787d24fc3SLaurent Pinchart connector->funcs->destroy(connector); 521887d24fc3SLaurent Pinchart } 521987d24fc3SLaurent Pinchart 522087d24fc3SLaurent Pinchart list_for_each_entry_safe(property, pt, &dev->mode_config.property_list, 522187d24fc3SLaurent Pinchart head) { 522287d24fc3SLaurent Pinchart drm_property_destroy(dev, property); 522387d24fc3SLaurent Pinchart } 522487d24fc3SLaurent Pinchart 522587d24fc3SLaurent Pinchart list_for_each_entry_safe(blob, bt, &dev->mode_config.property_blob_list, 522687d24fc3SLaurent Pinchart head) { 522787d24fc3SLaurent Pinchart drm_property_destroy_blob(dev, blob); 522887d24fc3SLaurent Pinchart } 522987d24fc3SLaurent Pinchart 523087d24fc3SLaurent Pinchart /* 523187d24fc3SLaurent Pinchart * Single-threaded teardown context, so it's not required to grab the 523287d24fc3SLaurent Pinchart * fb_lock to protect against concurrent fb_list access. Contrary, it 523387d24fc3SLaurent Pinchart * would actually deadlock with the drm_framebuffer_cleanup function. 523487d24fc3SLaurent Pinchart * 523587d24fc3SLaurent Pinchart * Also, if there are any framebuffers left, that's a driver leak now, 523687d24fc3SLaurent Pinchart * so politely WARN about this. 523787d24fc3SLaurent Pinchart */ 523887d24fc3SLaurent Pinchart WARN_ON(!list_empty(&dev->mode_config.fb_list)); 523987d24fc3SLaurent Pinchart list_for_each_entry_safe(fb, fbt, &dev->mode_config.fb_list, head) { 524087d24fc3SLaurent Pinchart drm_framebuffer_remove(fb); 524187d24fc3SLaurent Pinchart } 524287d24fc3SLaurent Pinchart 524387d24fc3SLaurent Pinchart list_for_each_entry_safe(plane, plt, &dev->mode_config.plane_list, 524487d24fc3SLaurent Pinchart head) { 524587d24fc3SLaurent Pinchart plane->funcs->destroy(plane); 524687d24fc3SLaurent Pinchart } 524787d24fc3SLaurent Pinchart 524887d24fc3SLaurent Pinchart list_for_each_entry_safe(crtc, ct, &dev->mode_config.crtc_list, head) { 524987d24fc3SLaurent Pinchart crtc->funcs->destroy(crtc); 525087d24fc3SLaurent Pinchart } 525187d24fc3SLaurent Pinchart 525287d24fc3SLaurent Pinchart idr_destroy(&dev->mode_config.crtc_idr); 525351fd371bSRob Clark drm_modeset_lock_fini(&dev->mode_config.connection_mutex); 525487d24fc3SLaurent Pinchart } 525587d24fc3SLaurent Pinchart EXPORT_SYMBOL(drm_mode_config_cleanup); 5256c1df5f3cSVille Syrjälä 5257c1df5f3cSVille Syrjälä struct drm_property *drm_mode_create_rotation_property(struct drm_device *dev, 5258c1df5f3cSVille Syrjälä unsigned int supported_rotations) 5259c1df5f3cSVille Syrjälä { 5260c1df5f3cSVille Syrjälä static const struct drm_prop_enum_list props[] = { 5261c1df5f3cSVille Syrjälä { DRM_ROTATE_0, "rotate-0" }, 5262c1df5f3cSVille Syrjälä { DRM_ROTATE_90, "rotate-90" }, 5263c1df5f3cSVille Syrjälä { DRM_ROTATE_180, "rotate-180" }, 5264c1df5f3cSVille Syrjälä { DRM_ROTATE_270, "rotate-270" }, 5265c1df5f3cSVille Syrjälä { DRM_REFLECT_X, "reflect-x" }, 5266c1df5f3cSVille Syrjälä { DRM_REFLECT_Y, "reflect-y" }, 5267c1df5f3cSVille Syrjälä }; 5268c1df5f3cSVille Syrjälä 5269c1df5f3cSVille Syrjälä return drm_property_create_bitmask(dev, 0, "rotation", 5270c1df5f3cSVille Syrjälä props, ARRAY_SIZE(props), 5271c1df5f3cSVille Syrjälä supported_rotations); 5272c1df5f3cSVille Syrjälä } 5273c1df5f3cSVille Syrjälä EXPORT_SYMBOL(drm_mode_create_rotation_property); 5274