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 */ 64d20d3174SVille Syrjälä static const struct drm_prop_enum_list drm_dpms_enum_list[] = 65f453ba04SDave Airlie { { 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 739922ab5aSRob Clark static const struct drm_prop_enum_list drm_plane_type_enum_list[] = 749922ab5aSRob Clark { 759922ab5aSRob Clark { DRM_PLANE_TYPE_OVERLAY, "Overlay" }, 769922ab5aSRob Clark { DRM_PLANE_TYPE_PRIMARY, "Primary" }, 779922ab5aSRob Clark { DRM_PLANE_TYPE_CURSOR, "Cursor" }, 789922ab5aSRob Clark }; 799922ab5aSRob Clark 80f453ba04SDave Airlie /* 81f453ba04SDave Airlie * Optional properties 82f453ba04SDave Airlie */ 83d20d3174SVille Syrjälä static const struct drm_prop_enum_list drm_scaling_mode_enum_list[] = 84f453ba04SDave Airlie { 8553bd8389SJesse Barnes { DRM_MODE_SCALE_NONE, "None" }, 8653bd8389SJesse Barnes { DRM_MODE_SCALE_FULLSCREEN, "Full" }, 8753bd8389SJesse Barnes { DRM_MODE_SCALE_CENTER, "Center" }, 8853bd8389SJesse Barnes { DRM_MODE_SCALE_ASPECT, "Full aspect" }, 89f453ba04SDave Airlie }; 90f453ba04SDave Airlie 91ff587e45SVandana Kannan static const struct drm_prop_enum_list drm_aspect_ratio_enum_list[] = { 92ff587e45SVandana Kannan { DRM_MODE_PICTURE_ASPECT_NONE, "Automatic" }, 93ff587e45SVandana Kannan { DRM_MODE_PICTURE_ASPECT_4_3, "4:3" }, 94ff587e45SVandana Kannan { DRM_MODE_PICTURE_ASPECT_16_9, "16:9" }, 95ff587e45SVandana Kannan }; 96ff587e45SVandana Kannan 97f453ba04SDave Airlie /* 98f453ba04SDave Airlie * Non-global properties, but "required" for certain connectors. 99f453ba04SDave Airlie */ 100d20d3174SVille Syrjälä static const struct drm_prop_enum_list drm_dvi_i_select_enum_list[] = 101f453ba04SDave Airlie { 102f453ba04SDave Airlie { DRM_MODE_SUBCONNECTOR_Automatic, "Automatic" }, /* DVI-I and TV-out */ 103f453ba04SDave Airlie { DRM_MODE_SUBCONNECTOR_DVID, "DVI-D" }, /* DVI-I */ 104f453ba04SDave Airlie { DRM_MODE_SUBCONNECTOR_DVIA, "DVI-A" }, /* DVI-I */ 105f453ba04SDave Airlie }; 106f453ba04SDave Airlie 107f453ba04SDave Airlie DRM_ENUM_NAME_FN(drm_get_dvi_i_select_name, drm_dvi_i_select_enum_list) 108f453ba04SDave Airlie 109d20d3174SVille Syrjälä static const struct drm_prop_enum_list drm_dvi_i_subconnector_enum_list[] = 110f453ba04SDave Airlie { 111f453ba04SDave Airlie { DRM_MODE_SUBCONNECTOR_Unknown, "Unknown" }, /* DVI-I and TV-out */ 112f453ba04SDave Airlie { DRM_MODE_SUBCONNECTOR_DVID, "DVI-D" }, /* DVI-I */ 113f453ba04SDave Airlie { DRM_MODE_SUBCONNECTOR_DVIA, "DVI-A" }, /* DVI-I */ 114f453ba04SDave Airlie }; 115f453ba04SDave Airlie 116f453ba04SDave Airlie DRM_ENUM_NAME_FN(drm_get_dvi_i_subconnector_name, 117f453ba04SDave Airlie drm_dvi_i_subconnector_enum_list) 118f453ba04SDave Airlie 119d20d3174SVille Syrjälä static const struct drm_prop_enum_list drm_tv_select_enum_list[] = 120f453ba04SDave Airlie { 121f453ba04SDave Airlie { DRM_MODE_SUBCONNECTOR_Automatic, "Automatic" }, /* DVI-I and TV-out */ 122f453ba04SDave Airlie { DRM_MODE_SUBCONNECTOR_Composite, "Composite" }, /* TV-out */ 123f453ba04SDave Airlie { DRM_MODE_SUBCONNECTOR_SVIDEO, "SVIDEO" }, /* TV-out */ 124f453ba04SDave Airlie { DRM_MODE_SUBCONNECTOR_Component, "Component" }, /* TV-out */ 125aeaa1ad3SFrancisco Jerez { DRM_MODE_SUBCONNECTOR_SCART, "SCART" }, /* TV-out */ 126f453ba04SDave Airlie }; 127f453ba04SDave Airlie 128f453ba04SDave Airlie DRM_ENUM_NAME_FN(drm_get_tv_select_name, drm_tv_select_enum_list) 129f453ba04SDave Airlie 130d20d3174SVille Syrjälä static const struct drm_prop_enum_list drm_tv_subconnector_enum_list[] = 131f453ba04SDave Airlie { 132f453ba04SDave Airlie { DRM_MODE_SUBCONNECTOR_Unknown, "Unknown" }, /* DVI-I and TV-out */ 133f453ba04SDave Airlie { DRM_MODE_SUBCONNECTOR_Composite, "Composite" }, /* TV-out */ 134f453ba04SDave Airlie { DRM_MODE_SUBCONNECTOR_SVIDEO, "SVIDEO" }, /* TV-out */ 135f453ba04SDave Airlie { DRM_MODE_SUBCONNECTOR_Component, "Component" }, /* TV-out */ 136aeaa1ad3SFrancisco Jerez { DRM_MODE_SUBCONNECTOR_SCART, "SCART" }, /* TV-out */ 137f453ba04SDave Airlie }; 138f453ba04SDave Airlie 139f453ba04SDave Airlie DRM_ENUM_NAME_FN(drm_get_tv_subconnector_name, 140f453ba04SDave Airlie drm_tv_subconnector_enum_list) 141f453ba04SDave Airlie 142d20d3174SVille Syrjälä static const struct drm_prop_enum_list drm_dirty_info_enum_list[] = { 143884840aaSJakob Bornecrantz { DRM_MODE_DIRTY_OFF, "Off" }, 144884840aaSJakob Bornecrantz { DRM_MODE_DIRTY_ON, "On" }, 145884840aaSJakob Bornecrantz { DRM_MODE_DIRTY_ANNOTATE, "Annotate" }, 146884840aaSJakob Bornecrantz }; 147884840aaSJakob Bornecrantz 148f453ba04SDave Airlie struct drm_conn_prop_enum_list { 149f453ba04SDave Airlie int type; 150d20d3174SVille Syrjälä const char *name; 151b21e3afeSIlia Mirkin struct ida ida; 152f453ba04SDave Airlie }; 153f453ba04SDave Airlie 154f453ba04SDave Airlie /* 155f453ba04SDave Airlie * Connector and encoder types. 156f453ba04SDave Airlie */ 157f453ba04SDave Airlie static struct drm_conn_prop_enum_list drm_connector_enum_list[] = 158b21e3afeSIlia Mirkin { { DRM_MODE_CONNECTOR_Unknown, "Unknown" }, 159b21e3afeSIlia Mirkin { DRM_MODE_CONNECTOR_VGA, "VGA" }, 160b21e3afeSIlia Mirkin { DRM_MODE_CONNECTOR_DVII, "DVI-I" }, 161b21e3afeSIlia Mirkin { DRM_MODE_CONNECTOR_DVID, "DVI-D" }, 162b21e3afeSIlia Mirkin { DRM_MODE_CONNECTOR_DVIA, "DVI-A" }, 163b21e3afeSIlia Mirkin { DRM_MODE_CONNECTOR_Composite, "Composite" }, 164b21e3afeSIlia Mirkin { DRM_MODE_CONNECTOR_SVIDEO, "SVIDEO" }, 165b21e3afeSIlia Mirkin { DRM_MODE_CONNECTOR_LVDS, "LVDS" }, 166b21e3afeSIlia Mirkin { DRM_MODE_CONNECTOR_Component, "Component" }, 167b21e3afeSIlia Mirkin { DRM_MODE_CONNECTOR_9PinDIN, "DIN" }, 168b21e3afeSIlia Mirkin { DRM_MODE_CONNECTOR_DisplayPort, "DP" }, 169b21e3afeSIlia Mirkin { DRM_MODE_CONNECTOR_HDMIA, "HDMI-A" }, 170b21e3afeSIlia Mirkin { DRM_MODE_CONNECTOR_HDMIB, "HDMI-B" }, 171b21e3afeSIlia Mirkin { DRM_MODE_CONNECTOR_TV, "TV" }, 172b21e3afeSIlia Mirkin { DRM_MODE_CONNECTOR_eDP, "eDP" }, 173b21e3afeSIlia Mirkin { DRM_MODE_CONNECTOR_VIRTUAL, "Virtual" }, 174b8923273SShobhit Kumar { DRM_MODE_CONNECTOR_DSI, "DSI" }, 175f453ba04SDave Airlie }; 176f453ba04SDave Airlie 177d20d3174SVille Syrjälä static const struct drm_prop_enum_list drm_encoder_enum_list[] = 178f453ba04SDave Airlie { { DRM_MODE_ENCODER_NONE, "None" }, 179f453ba04SDave Airlie { DRM_MODE_ENCODER_DAC, "DAC" }, 180f453ba04SDave Airlie { DRM_MODE_ENCODER_TMDS, "TMDS" }, 181f453ba04SDave Airlie { DRM_MODE_ENCODER_LVDS, "LVDS" }, 182f453ba04SDave Airlie { DRM_MODE_ENCODER_TVDAC, "TV" }, 183a7331e5cSThomas Hellstrom { DRM_MODE_ENCODER_VIRTUAL, "Virtual" }, 184b8923273SShobhit Kumar { DRM_MODE_ENCODER_DSI, "DSI" }, 185182407a6SDave Airlie { DRM_MODE_ENCODER_DPMST, "DP MST" }, 186f453ba04SDave Airlie }; 187f453ba04SDave Airlie 188ac1bb36cSJesse Barnes static const struct drm_prop_enum_list drm_subpixel_enum_list[] = 189ac1bb36cSJesse Barnes { 190ac1bb36cSJesse Barnes { SubPixelUnknown, "Unknown" }, 191ac1bb36cSJesse Barnes { SubPixelHorizontalRGB, "Horizontal RGB" }, 192ac1bb36cSJesse Barnes { SubPixelHorizontalBGR, "Horizontal BGR" }, 193ac1bb36cSJesse Barnes { SubPixelVerticalRGB, "Vertical RGB" }, 194ac1bb36cSJesse Barnes { SubPixelVerticalBGR, "Vertical BGR" }, 195ac1bb36cSJesse Barnes { SubPixelNone, "None" }, 196ac1bb36cSJesse Barnes }; 197ac1bb36cSJesse Barnes 198b21e3afeSIlia Mirkin void drm_connector_ida_init(void) 199b21e3afeSIlia Mirkin { 200b21e3afeSIlia Mirkin int i; 201b21e3afeSIlia Mirkin 202b21e3afeSIlia Mirkin for (i = 0; i < ARRAY_SIZE(drm_connector_enum_list); i++) 203b21e3afeSIlia Mirkin ida_init(&drm_connector_enum_list[i].ida); 204b21e3afeSIlia Mirkin } 205b21e3afeSIlia Mirkin 206b21e3afeSIlia Mirkin void drm_connector_ida_destroy(void) 207b21e3afeSIlia Mirkin { 208b21e3afeSIlia Mirkin int i; 209b21e3afeSIlia Mirkin 210b21e3afeSIlia Mirkin for (i = 0; i < ARRAY_SIZE(drm_connector_enum_list); i++) 211b21e3afeSIlia Mirkin ida_destroy(&drm_connector_enum_list[i].ida); 212b21e3afeSIlia Mirkin } 213b21e3afeSIlia Mirkin 214c8e32cc1SDaniel Vetter /** 215c8e32cc1SDaniel Vetter * drm_get_connector_status_name - return a string for connector status 216c8e32cc1SDaniel Vetter * @status: connector status to compute name of 217c8e32cc1SDaniel Vetter * 218c8e32cc1SDaniel Vetter * In contrast to the other drm_get_*_name functions this one here returns a 219c8e32cc1SDaniel Vetter * const pointer and hence is threadsafe. 220c8e32cc1SDaniel Vetter */ 221d20d3174SVille Syrjälä const char *drm_get_connector_status_name(enum drm_connector_status status) 222f453ba04SDave Airlie { 223f453ba04SDave Airlie if (status == connector_status_connected) 224f453ba04SDave Airlie return "connected"; 225f453ba04SDave Airlie else if (status == connector_status_disconnected) 226f453ba04SDave Airlie return "disconnected"; 227f453ba04SDave Airlie else 228f453ba04SDave Airlie return "unknown"; 229f453ba04SDave Airlie } 230ed7951dcSLespiau, Damien EXPORT_SYMBOL(drm_get_connector_status_name); 231f453ba04SDave Airlie 232ac1bb36cSJesse Barnes /** 233ac1bb36cSJesse Barnes * drm_get_subpixel_order_name - return a string for a given subpixel enum 234ac1bb36cSJesse Barnes * @order: enum of subpixel_order 235ac1bb36cSJesse Barnes * 236ac1bb36cSJesse Barnes * Note you could abuse this and return something out of bounds, but that 237ac1bb36cSJesse Barnes * would be a caller error. No unscrubbed user data should make it here. 238ac1bb36cSJesse Barnes */ 239ac1bb36cSJesse Barnes const char *drm_get_subpixel_order_name(enum subpixel_order order) 240ac1bb36cSJesse Barnes { 241ac1bb36cSJesse Barnes return drm_subpixel_enum_list[order].name; 242ac1bb36cSJesse Barnes } 243ac1bb36cSJesse Barnes EXPORT_SYMBOL(drm_get_subpixel_order_name); 244ac1bb36cSJesse Barnes 2456ba6d03eSVille Syrjälä static char printable_char(int c) 2466ba6d03eSVille Syrjälä { 2476ba6d03eSVille Syrjälä return isascii(c) && isprint(c) ? c : '?'; 2486ba6d03eSVille Syrjälä } 2496ba6d03eSVille Syrjälä 250c8e32cc1SDaniel Vetter /** 251c8e32cc1SDaniel Vetter * drm_get_format_name - return a string for drm fourcc format 252c8e32cc1SDaniel Vetter * @format: format to compute name of 253c8e32cc1SDaniel Vetter * 254c8e32cc1SDaniel Vetter * Note that the buffer used by this function is globally shared and owned by 255c8e32cc1SDaniel Vetter * the function itself. 256c8e32cc1SDaniel Vetter * 257c8e32cc1SDaniel Vetter * FIXME: This isn't really multithreading safe. 258c8e32cc1SDaniel Vetter */ 259d20d3174SVille Syrjälä const char *drm_get_format_name(uint32_t format) 2606ba6d03eSVille Syrjälä { 2616ba6d03eSVille Syrjälä static char buf[32]; 2626ba6d03eSVille Syrjälä 2636ba6d03eSVille Syrjälä snprintf(buf, sizeof(buf), 2646ba6d03eSVille Syrjälä "%c%c%c%c %s-endian (0x%08x)", 2656ba6d03eSVille Syrjälä printable_char(format & 0xff), 2666ba6d03eSVille Syrjälä printable_char((format >> 8) & 0xff), 2676ba6d03eSVille Syrjälä printable_char((format >> 16) & 0xff), 2686ba6d03eSVille Syrjälä printable_char((format >> 24) & 0x7f), 2696ba6d03eSVille Syrjälä format & DRM_FORMAT_BIG_ENDIAN ? "big" : "little", 2706ba6d03eSVille Syrjälä format); 2716ba6d03eSVille Syrjälä 2726ba6d03eSVille Syrjälä return buf; 2736ba6d03eSVille Syrjälä } 2746ba6d03eSVille Syrjälä EXPORT_SYMBOL(drm_get_format_name); 2756ba6d03eSVille Syrjälä 2762ee39452SDave Airlie /* 2772ee39452SDave Airlie * Internal function to assign a slot in the object idr and optionally 2782ee39452SDave Airlie * register the object into the idr. 2792ee39452SDave Airlie */ 2802ee39452SDave Airlie static int drm_mode_object_get_reg(struct drm_device *dev, 2812ee39452SDave Airlie struct drm_mode_object *obj, 2822ee39452SDave Airlie uint32_t obj_type, 2832ee39452SDave Airlie bool register_obj) 2842ee39452SDave Airlie { 2852ee39452SDave Airlie int ret; 2862ee39452SDave Airlie 2872ee39452SDave Airlie mutex_lock(&dev->mode_config.idr_mutex); 2882ee39452SDave Airlie ret = idr_alloc(&dev->mode_config.crtc_idr, register_obj ? obj : NULL, 1, 0, GFP_KERNEL); 2892ee39452SDave Airlie if (ret >= 0) { 2902ee39452SDave Airlie /* 2912ee39452SDave Airlie * Set up the object linking under the protection of the idr 2922ee39452SDave Airlie * lock so that other users can't see inconsistent state. 2932ee39452SDave Airlie */ 2942ee39452SDave Airlie obj->id = ret; 2952ee39452SDave Airlie obj->type = obj_type; 2962ee39452SDave Airlie } 2972ee39452SDave Airlie mutex_unlock(&dev->mode_config.idr_mutex); 2982ee39452SDave Airlie 2992ee39452SDave Airlie return ret < 0 ? ret : 0; 3002ee39452SDave Airlie } 3012ee39452SDave Airlie 302f453ba04SDave Airlie /** 303065a50edSDaniel Vetter * drm_mode_object_get - allocate a new modeset identifier 304f453ba04SDave Airlie * @dev: DRM device 305065a50edSDaniel Vetter * @obj: object pointer, used to generate unique ID 306065a50edSDaniel Vetter * @obj_type: object type 307f453ba04SDave Airlie * 308f453ba04SDave Airlie * Create a unique identifier based on @ptr in @dev's identifier space. Used 309c8e32cc1SDaniel Vetter * for tracking modes, CRTCs and connectors. Note that despite the _get postfix 310c8e32cc1SDaniel Vetter * modeset identifiers are _not_ reference counted. Hence don't use this for 311c8e32cc1SDaniel Vetter * reference counted modeset objects like framebuffers. 312f453ba04SDave Airlie * 313c8e32cc1SDaniel Vetter * Returns: 314f453ba04SDave Airlie * New unique (relative to other objects in @dev) integer identifier for the 315f453ba04SDave Airlie * object. 316f453ba04SDave Airlie */ 3178bd441b2SDaniel Vetter int drm_mode_object_get(struct drm_device *dev, 318f453ba04SDave Airlie struct drm_mode_object *obj, uint32_t obj_type) 319f453ba04SDave Airlie { 3202ee39452SDave Airlie return drm_mode_object_get_reg(dev, obj, obj_type, true); 3214b096ac1SDaniel Vetter } 3224b096ac1SDaniel Vetter 3232ee39452SDave Airlie static void drm_mode_object_register(struct drm_device *dev, 3242ee39452SDave Airlie struct drm_mode_object *obj) 3252ee39452SDave Airlie { 3262ee39452SDave Airlie mutex_lock(&dev->mode_config.idr_mutex); 3272ee39452SDave Airlie idr_replace(&dev->mode_config.crtc_idr, obj, obj->id); 3282ee39452SDave Airlie mutex_unlock(&dev->mode_config.idr_mutex); 329f453ba04SDave Airlie } 330f453ba04SDave Airlie 331f453ba04SDave Airlie /** 332065a50edSDaniel Vetter * drm_mode_object_put - free a modeset identifer 333f453ba04SDave Airlie * @dev: DRM device 334065a50edSDaniel Vetter * @object: object to free 335f453ba04SDave Airlie * 336c8e32cc1SDaniel Vetter * Free @id from @dev's unique identifier pool. Note that despite the _get 337c8e32cc1SDaniel Vetter * postfix modeset identifiers are _not_ reference counted. Hence don't use this 338c8e32cc1SDaniel Vetter * for reference counted modeset objects like framebuffers. 339f453ba04SDave Airlie */ 3408bd441b2SDaniel Vetter void drm_mode_object_put(struct drm_device *dev, 341f453ba04SDave Airlie struct drm_mode_object *object) 342f453ba04SDave Airlie { 343ad2563c2SJesse Barnes mutex_lock(&dev->mode_config.idr_mutex); 344f453ba04SDave Airlie idr_remove(&dev->mode_config.crtc_idr, object->id); 345ad2563c2SJesse Barnes mutex_unlock(&dev->mode_config.idr_mutex); 346f453ba04SDave Airlie } 347f453ba04SDave Airlie 34898f75de4SRob Clark static struct drm_mode_object *_object_find(struct drm_device *dev, 34998f75de4SRob Clark uint32_t id, uint32_t type) 35098f75de4SRob Clark { 35198f75de4SRob Clark struct drm_mode_object *obj = NULL; 35298f75de4SRob Clark 35398f75de4SRob Clark mutex_lock(&dev->mode_config.idr_mutex); 35498f75de4SRob Clark obj = idr_find(&dev->mode_config.crtc_idr, id); 355168c02ecSDaniel Vetter if (obj && type != DRM_MODE_OBJECT_ANY && obj->type != type) 356168c02ecSDaniel Vetter obj = NULL; 357168c02ecSDaniel Vetter if (obj && obj->id != id) 358168c02ecSDaniel Vetter obj = NULL; 359168c02ecSDaniel Vetter /* don't leak out unref'd fb's */ 360168c02ecSDaniel Vetter if (obj && (obj->type == DRM_MODE_OBJECT_FB)) 36198f75de4SRob Clark obj = NULL; 36298f75de4SRob Clark mutex_unlock(&dev->mode_config.idr_mutex); 36398f75de4SRob Clark 36498f75de4SRob Clark return obj; 36598f75de4SRob Clark } 36698f75de4SRob Clark 367786b99edSDaniel Vetter /** 368786b99edSDaniel Vetter * drm_mode_object_find - look up a drm object with static lifetime 369786b99edSDaniel Vetter * @dev: drm device 370786b99edSDaniel Vetter * @id: id of the mode object 371786b99edSDaniel Vetter * @type: type of the mode object 372786b99edSDaniel Vetter * 373786b99edSDaniel Vetter * Note that framebuffers cannot be looked up with this functions - since those 37498f75de4SRob Clark * are reference counted, they need special treatment. Even with 37598f75de4SRob Clark * DRM_MODE_OBJECT_ANY (although that will simply return NULL 37698f75de4SRob Clark * rather than WARN_ON()). 377786b99edSDaniel Vetter */ 3787a9c9060SDaniel Vetter struct drm_mode_object *drm_mode_object_find(struct drm_device *dev, 3797a9c9060SDaniel Vetter uint32_t id, uint32_t type) 380f453ba04SDave Airlie { 381ad2563c2SJesse Barnes struct drm_mode_object *obj = NULL; 382f453ba04SDave Airlie 383786b99edSDaniel Vetter /* Framebuffers are reference counted and need their own lookup 384786b99edSDaniel Vetter * function.*/ 385786b99edSDaniel Vetter WARN_ON(type == DRM_MODE_OBJECT_FB); 38698f75de4SRob Clark obj = _object_find(dev, id, type); 387f453ba04SDave Airlie return obj; 388f453ba04SDave Airlie } 389f453ba04SDave Airlie EXPORT_SYMBOL(drm_mode_object_find); 390f453ba04SDave Airlie 391f453ba04SDave Airlie /** 392f453ba04SDave Airlie * drm_framebuffer_init - initialize a framebuffer 393f453ba04SDave Airlie * @dev: DRM device 394065a50edSDaniel Vetter * @fb: framebuffer to be initialized 395065a50edSDaniel Vetter * @funcs: ... with these functions 396f453ba04SDave Airlie * 397f453ba04SDave Airlie * Allocates an ID for the framebuffer's parent mode object, sets its mode 398f453ba04SDave Airlie * functions & device file and adds it to the master fd list. 399f453ba04SDave Airlie * 4004b096ac1SDaniel Vetter * IMPORTANT: 4014b096ac1SDaniel Vetter * This functions publishes the fb and makes it available for concurrent access 4024b096ac1SDaniel Vetter * by other users. Which means by this point the fb _must_ be fully set up - 4034b096ac1SDaniel Vetter * since all the fb attributes are invariant over its lifetime, no further 4044b096ac1SDaniel Vetter * locking but only correct reference counting is required. 4054b096ac1SDaniel Vetter * 406c8e32cc1SDaniel Vetter * Returns: 407af901ca1SAndré Goddard Rosa * Zero on success, error code on failure. 408f453ba04SDave Airlie */ 409f453ba04SDave Airlie int drm_framebuffer_init(struct drm_device *dev, struct drm_framebuffer *fb, 410f453ba04SDave Airlie const struct drm_framebuffer_funcs *funcs) 411f453ba04SDave Airlie { 412f453ba04SDave Airlie int ret; 413f453ba04SDave Airlie 4144b096ac1SDaniel Vetter mutex_lock(&dev->mode_config.fb_lock); 415f7eff60eSRob Clark kref_init(&fb->refcount); 4164b096ac1SDaniel Vetter INIT_LIST_HEAD(&fb->filp_head); 4174b096ac1SDaniel Vetter fb->dev = dev; 4184b096ac1SDaniel Vetter fb->funcs = funcs; 419f7eff60eSRob Clark 420f453ba04SDave Airlie ret = drm_mode_object_get(dev, &fb->base, DRM_MODE_OBJECT_FB); 4216bfc56aaSVille Syrjälä if (ret) 4224b096ac1SDaniel Vetter goto out; 423f453ba04SDave Airlie 424f453ba04SDave Airlie dev->mode_config.num_fb++; 425f453ba04SDave Airlie list_add(&fb->head, &dev->mode_config.fb_list); 4264b096ac1SDaniel Vetter out: 4274b096ac1SDaniel Vetter mutex_unlock(&dev->mode_config.fb_lock); 428f453ba04SDave Airlie 429f453ba04SDave Airlie return 0; 430f453ba04SDave Airlie } 431f453ba04SDave Airlie EXPORT_SYMBOL(drm_framebuffer_init); 432f453ba04SDave Airlie 43383f45fc3SDaniel Vetter /* dev->mode_config.fb_lock must be held! */ 43483f45fc3SDaniel Vetter static void __drm_framebuffer_unregister(struct drm_device *dev, 43583f45fc3SDaniel Vetter struct drm_framebuffer *fb) 43683f45fc3SDaniel Vetter { 43783f45fc3SDaniel Vetter mutex_lock(&dev->mode_config.idr_mutex); 43883f45fc3SDaniel Vetter idr_remove(&dev->mode_config.crtc_idr, fb->base.id); 43983f45fc3SDaniel Vetter mutex_unlock(&dev->mode_config.idr_mutex); 44083f45fc3SDaniel Vetter 44183f45fc3SDaniel Vetter fb->base.id = 0; 44283f45fc3SDaniel Vetter } 44383f45fc3SDaniel Vetter 444f7eff60eSRob Clark static void drm_framebuffer_free(struct kref *kref) 445f7eff60eSRob Clark { 446f7eff60eSRob Clark struct drm_framebuffer *fb = 447f7eff60eSRob Clark container_of(kref, struct drm_framebuffer, refcount); 44883f45fc3SDaniel Vetter struct drm_device *dev = fb->dev; 44983f45fc3SDaniel Vetter 45083f45fc3SDaniel Vetter /* 45183f45fc3SDaniel Vetter * The lookup idr holds a weak reference, which has not necessarily been 45283f45fc3SDaniel Vetter * removed at this point. Check for that. 45383f45fc3SDaniel Vetter */ 45483f45fc3SDaniel Vetter mutex_lock(&dev->mode_config.fb_lock); 45583f45fc3SDaniel Vetter if (fb->base.id) { 45683f45fc3SDaniel Vetter /* Mark fb as reaped and drop idr ref. */ 45783f45fc3SDaniel Vetter __drm_framebuffer_unregister(dev, fb); 45883f45fc3SDaniel Vetter } 45983f45fc3SDaniel Vetter mutex_unlock(&dev->mode_config.fb_lock); 46083f45fc3SDaniel Vetter 461f7eff60eSRob Clark fb->funcs->destroy(fb); 462f7eff60eSRob Clark } 463f7eff60eSRob Clark 4642b677e8cSDaniel Vetter static struct drm_framebuffer *__drm_framebuffer_lookup(struct drm_device *dev, 4652b677e8cSDaniel Vetter uint32_t id) 4662b677e8cSDaniel Vetter { 4672b677e8cSDaniel Vetter struct drm_mode_object *obj = NULL; 4682b677e8cSDaniel Vetter struct drm_framebuffer *fb; 4692b677e8cSDaniel Vetter 4702b677e8cSDaniel Vetter mutex_lock(&dev->mode_config.idr_mutex); 4712b677e8cSDaniel Vetter obj = idr_find(&dev->mode_config.crtc_idr, id); 4722b677e8cSDaniel Vetter if (!obj || (obj->type != DRM_MODE_OBJECT_FB) || (obj->id != id)) 4732b677e8cSDaniel Vetter fb = NULL; 4742b677e8cSDaniel Vetter else 4752b677e8cSDaniel Vetter fb = obj_to_fb(obj); 4762b677e8cSDaniel Vetter mutex_unlock(&dev->mode_config.idr_mutex); 4772b677e8cSDaniel Vetter 4782b677e8cSDaniel Vetter return fb; 4792b677e8cSDaniel Vetter } 4802b677e8cSDaniel Vetter 481f7eff60eSRob Clark /** 482786b99edSDaniel Vetter * drm_framebuffer_lookup - look up a drm framebuffer and grab a reference 483786b99edSDaniel Vetter * @dev: drm device 484786b99edSDaniel Vetter * @id: id of the fb object 485786b99edSDaniel Vetter * 486786b99edSDaniel Vetter * If successful, this grabs an additional reference to the framebuffer - 487786b99edSDaniel Vetter * callers need to make sure to eventually unreference the returned framebuffer 488c8e32cc1SDaniel Vetter * again, using @drm_framebuffer_unreference. 489786b99edSDaniel Vetter */ 490786b99edSDaniel Vetter struct drm_framebuffer *drm_framebuffer_lookup(struct drm_device *dev, 491786b99edSDaniel Vetter uint32_t id) 492786b99edSDaniel Vetter { 493786b99edSDaniel Vetter struct drm_framebuffer *fb; 494786b99edSDaniel Vetter 495786b99edSDaniel Vetter mutex_lock(&dev->mode_config.fb_lock); 4962b677e8cSDaniel Vetter fb = __drm_framebuffer_lookup(dev, id); 49783f45fc3SDaniel Vetter if (fb) { 49883f45fc3SDaniel Vetter if (!kref_get_unless_zero(&fb->refcount)) 49983f45fc3SDaniel Vetter fb = NULL; 50083f45fc3SDaniel Vetter } 501786b99edSDaniel Vetter mutex_unlock(&dev->mode_config.fb_lock); 502786b99edSDaniel Vetter 503786b99edSDaniel Vetter return fb; 504786b99edSDaniel Vetter } 505786b99edSDaniel Vetter EXPORT_SYMBOL(drm_framebuffer_lookup); 506786b99edSDaniel Vetter 507786b99edSDaniel Vetter /** 508f7eff60eSRob Clark * drm_framebuffer_unreference - unref a framebuffer 509065a50edSDaniel Vetter * @fb: framebuffer to unref 510065a50edSDaniel Vetter * 511065a50edSDaniel Vetter * This functions decrements the fb's refcount and frees it if it drops to zero. 512f7eff60eSRob Clark */ 513f7eff60eSRob Clark void drm_framebuffer_unreference(struct drm_framebuffer *fb) 514f7eff60eSRob Clark { 5158291272aSRob Clark DRM_DEBUG("%p: FB ID: %d (%d)\n", fb, fb->base.id, atomic_read(&fb->refcount.refcount)); 516f7eff60eSRob Clark kref_put(&fb->refcount, drm_framebuffer_free); 517f7eff60eSRob Clark } 518f7eff60eSRob Clark EXPORT_SYMBOL(drm_framebuffer_unreference); 519f7eff60eSRob Clark 520f7eff60eSRob Clark /** 521f7eff60eSRob Clark * drm_framebuffer_reference - incr the fb refcnt 522065a50edSDaniel Vetter * @fb: framebuffer 523c8e32cc1SDaniel Vetter * 524c8e32cc1SDaniel Vetter * This functions increments the fb's refcount. 525f7eff60eSRob Clark */ 526f7eff60eSRob Clark void drm_framebuffer_reference(struct drm_framebuffer *fb) 527f7eff60eSRob Clark { 5288291272aSRob Clark DRM_DEBUG("%p: FB ID: %d (%d)\n", fb, fb->base.id, atomic_read(&fb->refcount.refcount)); 529f7eff60eSRob Clark kref_get(&fb->refcount); 530f7eff60eSRob Clark } 531f7eff60eSRob Clark EXPORT_SYMBOL(drm_framebuffer_reference); 532f7eff60eSRob Clark 5332b677e8cSDaniel Vetter static void drm_framebuffer_free_bug(struct kref *kref) 5342b677e8cSDaniel Vetter { 5352b677e8cSDaniel Vetter BUG(); 5362b677e8cSDaniel Vetter } 5372b677e8cSDaniel Vetter 5386c2a7532SDaniel Vetter static void __drm_framebuffer_unreference(struct drm_framebuffer *fb) 5396c2a7532SDaniel Vetter { 5408291272aSRob Clark DRM_DEBUG("%p: FB ID: %d (%d)\n", fb, fb->base.id, atomic_read(&fb->refcount.refcount)); 5416c2a7532SDaniel Vetter kref_put(&fb->refcount, drm_framebuffer_free_bug); 5426c2a7532SDaniel Vetter } 5436c2a7532SDaniel Vetter 544f453ba04SDave Airlie /** 54536206361SDaniel Vetter * drm_framebuffer_unregister_private - unregister a private fb from the lookup idr 54636206361SDaniel Vetter * @fb: fb to unregister 54736206361SDaniel Vetter * 54836206361SDaniel Vetter * Drivers need to call this when cleaning up driver-private framebuffers, e.g. 54936206361SDaniel Vetter * those used for fbdev. Note that the caller must hold a reference of it's own, 55036206361SDaniel Vetter * i.e. the object may not be destroyed through this call (since it'll lead to a 55136206361SDaniel Vetter * locking inversion). 55236206361SDaniel Vetter */ 55336206361SDaniel Vetter void drm_framebuffer_unregister_private(struct drm_framebuffer *fb) 55436206361SDaniel Vetter { 5552b677e8cSDaniel Vetter struct drm_device *dev = fb->dev; 5562b677e8cSDaniel Vetter 5572b677e8cSDaniel Vetter mutex_lock(&dev->mode_config.fb_lock); 5582b677e8cSDaniel Vetter /* Mark fb as reaped and drop idr ref. */ 5592b677e8cSDaniel Vetter __drm_framebuffer_unregister(dev, fb); 5602b677e8cSDaniel Vetter mutex_unlock(&dev->mode_config.fb_lock); 56136206361SDaniel Vetter } 56236206361SDaniel Vetter EXPORT_SYMBOL(drm_framebuffer_unregister_private); 56336206361SDaniel Vetter 56436206361SDaniel Vetter /** 565f453ba04SDave Airlie * drm_framebuffer_cleanup - remove a framebuffer object 566f453ba04SDave Airlie * @fb: framebuffer to remove 567f453ba04SDave Airlie * 568c8e32cc1SDaniel Vetter * Cleanup framebuffer. This function is intended to be used from the drivers 569c8e32cc1SDaniel Vetter * ->destroy callback. It can also be used to clean up driver private 570c8e32cc1SDaniel Vetter * framebuffers embedded into a larger structure. 57136206361SDaniel Vetter * 57236206361SDaniel Vetter * Note that this function does not remove the fb from active usuage - if it is 57336206361SDaniel Vetter * still used anywhere, hilarity can ensue since userspace could call getfb on 57436206361SDaniel Vetter * the id and get back -EINVAL. Obviously no concern at driver unload time. 57536206361SDaniel Vetter * 57636206361SDaniel Vetter * Also, the framebuffer will not be removed from the lookup idr - for 57736206361SDaniel Vetter * user-created framebuffers this will happen in in the rmfb ioctl. For 57836206361SDaniel Vetter * driver-private objects (e.g. for fbdev) drivers need to explicitly call 57936206361SDaniel Vetter * drm_framebuffer_unregister_private. 580f453ba04SDave Airlie */ 581f453ba04SDave Airlie void drm_framebuffer_cleanup(struct drm_framebuffer *fb) 582f453ba04SDave Airlie { 583f453ba04SDave Airlie struct drm_device *dev = fb->dev; 5848faf6b18SDaniel Vetter 5854b096ac1SDaniel Vetter mutex_lock(&dev->mode_config.fb_lock); 586f7eff60eSRob Clark list_del(&fb->head); 587f7eff60eSRob Clark dev->mode_config.num_fb--; 5884b096ac1SDaniel Vetter mutex_unlock(&dev->mode_config.fb_lock); 589f7eff60eSRob Clark } 590f7eff60eSRob Clark EXPORT_SYMBOL(drm_framebuffer_cleanup); 591f7eff60eSRob Clark 592f7eff60eSRob Clark /** 593f7eff60eSRob Clark * drm_framebuffer_remove - remove and unreference a framebuffer object 594f7eff60eSRob Clark * @fb: framebuffer to remove 595f7eff60eSRob Clark * 596f7eff60eSRob Clark * Scans all the CRTCs and planes in @dev's mode_config. If they're 59736206361SDaniel Vetter * using @fb, removes it, setting it to NULL. Then drops the reference to the 598b62584e3SDaniel Vetter * passed-in framebuffer. Might take the modeset locks. 599b62584e3SDaniel Vetter * 600b62584e3SDaniel Vetter * Note that this function optimizes the cleanup away if the caller holds the 601b62584e3SDaniel Vetter * last reference to the framebuffer. It is also guaranteed to not take the 602b62584e3SDaniel Vetter * modeset locks in this case. 603f7eff60eSRob Clark */ 604f7eff60eSRob Clark void drm_framebuffer_remove(struct drm_framebuffer *fb) 605f7eff60eSRob Clark { 606f7eff60eSRob Clark struct drm_device *dev = fb->dev; 607f453ba04SDave Airlie struct drm_crtc *crtc; 6088cf5c917SJesse Barnes struct drm_plane *plane; 6095ef5f72fSDave Airlie struct drm_mode_set set; 6105ef5f72fSDave Airlie int ret; 611f453ba04SDave Airlie 6124b096ac1SDaniel Vetter WARN_ON(!list_empty(&fb->filp_head)); 6138faf6b18SDaniel Vetter 614b62584e3SDaniel Vetter /* 615b62584e3SDaniel Vetter * drm ABI mandates that we remove any deleted framebuffers from active 616b62584e3SDaniel Vetter * useage. But since most sane clients only remove framebuffers they no 617b62584e3SDaniel Vetter * longer need, try to optimize this away. 618b62584e3SDaniel Vetter * 619b62584e3SDaniel Vetter * Since we're holding a reference ourselves, observing a refcount of 1 620b62584e3SDaniel Vetter * means that we're the last holder and can skip it. Also, the refcount 621b62584e3SDaniel Vetter * can never increase from 1 again, so we don't need any barriers or 622b62584e3SDaniel Vetter * locks. 623b62584e3SDaniel Vetter * 624b62584e3SDaniel Vetter * Note that userspace could try to race with use and instate a new 625b62584e3SDaniel Vetter * usage _after_ we've cleared all current ones. End result will be an 626b62584e3SDaniel Vetter * in-use fb with fb-id == 0. Userspace is allowed to shoot its own foot 627b62584e3SDaniel Vetter * in this manner. 628b62584e3SDaniel Vetter */ 629b62584e3SDaniel Vetter if (atomic_read(&fb->refcount.refcount) > 1) { 630b62584e3SDaniel Vetter drm_modeset_lock_all(dev); 631f453ba04SDave Airlie /* remove from any CRTC */ 632f453ba04SDave Airlie list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { 633f4510a27SMatt Roper if (crtc->primary->fb == fb) { 6345ef5f72fSDave Airlie /* should turn off the crtc */ 6355ef5f72fSDave Airlie memset(&set, 0, sizeof(struct drm_mode_set)); 6365ef5f72fSDave Airlie set.crtc = crtc; 6375ef5f72fSDave Airlie set.fb = NULL; 6382d13b679SDaniel Vetter ret = drm_mode_set_config_internal(&set); 6395ef5f72fSDave Airlie if (ret) 6405ef5f72fSDave Airlie DRM_ERROR("failed to reset crtc %p when fb was deleted\n", crtc); 6415ef5f72fSDave Airlie } 642f453ba04SDave Airlie } 643f453ba04SDave Airlie 6448cf5c917SJesse Barnes list_for_each_entry(plane, &dev->mode_config.plane_list, head) { 6459125e618SVille Syrjälä if (plane->fb == fb) 6469125e618SVille Syrjälä drm_plane_force_disable(plane); 6478cf5c917SJesse Barnes } 648b62584e3SDaniel Vetter drm_modeset_unlock_all(dev); 649b62584e3SDaniel Vetter } 6508cf5c917SJesse Barnes 651f7eff60eSRob Clark drm_framebuffer_unreference(fb); 652f453ba04SDave Airlie } 653f7eff60eSRob Clark EXPORT_SYMBOL(drm_framebuffer_remove); 654f453ba04SDave Airlie 65551fd371bSRob Clark DEFINE_WW_CLASS(crtc_ww_class); 65651fd371bSRob Clark 657f453ba04SDave Airlie /** 658e13161afSMatt Roper * drm_crtc_init_with_planes - Initialise a new CRTC object with 659e13161afSMatt Roper * specified primary and cursor planes. 660f453ba04SDave Airlie * @dev: DRM device 661f453ba04SDave Airlie * @crtc: CRTC object to init 662e13161afSMatt Roper * @primary: Primary plane for CRTC 663e13161afSMatt Roper * @cursor: Cursor plane for CRTC 664f453ba04SDave Airlie * @funcs: callbacks for the new CRTC 665f453ba04SDave Airlie * 666ad6f5c34SVille Syrjälä * Inits a new object created as base part of a driver crtc object. 6676bfc56aaSVille Syrjälä * 668c8e32cc1SDaniel Vetter * Returns: 6696bfc56aaSVille Syrjälä * Zero on success, error code on failure. 670f453ba04SDave Airlie */ 671e13161afSMatt Roper int drm_crtc_init_with_planes(struct drm_device *dev, struct drm_crtc *crtc, 672e13161afSMatt Roper struct drm_plane *primary, 673fc1d3e44SMatt Roper struct drm_plane *cursor, 674f453ba04SDave Airlie const struct drm_crtc_funcs *funcs) 675f453ba04SDave Airlie { 67651fd371bSRob Clark struct drm_mode_config *config = &dev->mode_config; 6776bfc56aaSVille Syrjälä int ret; 6786bfc56aaSVille Syrjälä 679f453ba04SDave Airlie crtc->dev = dev; 680f453ba04SDave Airlie crtc->funcs = funcs; 6817c80e128SRob Clark crtc->invert_dimensions = false; 682f453ba04SDave Airlie 68351fd371bSRob Clark drm_modeset_lock_init(&crtc->mutex); 6846bfc56aaSVille Syrjälä ret = drm_mode_object_get(dev, &crtc->base, DRM_MODE_OBJECT_CRTC); 6856bfc56aaSVille Syrjälä if (ret) 6866bfc56aaSVille Syrjälä goto out; 687f453ba04SDave Airlie 688bffd9de0SPaulo Zanoni crtc->base.properties = &crtc->properties; 689bffd9de0SPaulo Zanoni 69051fd371bSRob Clark list_add_tail(&crtc->head, &config->crtc_list); 69151fd371bSRob Clark config->num_crtc++; 6926bfc56aaSVille Syrjälä 693e13161afSMatt Roper crtc->primary = primary; 694fc1d3e44SMatt Roper crtc->cursor = cursor; 695e13161afSMatt Roper if (primary) 696e13161afSMatt Roper primary->possible_crtcs = 1 << drm_crtc_index(crtc); 697fc1d3e44SMatt Roper if (cursor) 698fc1d3e44SMatt Roper cursor->possible_crtcs = 1 << drm_crtc_index(crtc); 699e13161afSMatt Roper 7006bfc56aaSVille Syrjälä out: 7016bfc56aaSVille Syrjälä 7026bfc56aaSVille Syrjälä return ret; 703f453ba04SDave Airlie } 704e13161afSMatt Roper EXPORT_SYMBOL(drm_crtc_init_with_planes); 705f453ba04SDave Airlie 706f453ba04SDave Airlie /** 707ad6f5c34SVille Syrjälä * drm_crtc_cleanup - Clean up the core crtc usage 708f453ba04SDave Airlie * @crtc: CRTC to cleanup 709f453ba04SDave Airlie * 710ad6f5c34SVille Syrjälä * This function cleans up @crtc and removes it from the DRM mode setting 711ad6f5c34SVille Syrjälä * core. Note that the function does *not* free the crtc structure itself, 712ad6f5c34SVille Syrjälä * this is the responsibility of the caller. 713f453ba04SDave Airlie */ 714f453ba04SDave Airlie void drm_crtc_cleanup(struct drm_crtc *crtc) 715f453ba04SDave Airlie { 716f453ba04SDave Airlie struct drm_device *dev = crtc->dev; 717f453ba04SDave Airlie 718f453ba04SDave Airlie kfree(crtc->gamma_store); 719f453ba04SDave Airlie crtc->gamma_store = NULL; 720f453ba04SDave Airlie 72151fd371bSRob Clark drm_modeset_lock_fini(&crtc->mutex); 72251fd371bSRob Clark 723f453ba04SDave Airlie drm_mode_object_put(dev, &crtc->base); 724f453ba04SDave Airlie list_del(&crtc->head); 725f453ba04SDave Airlie dev->mode_config.num_crtc--; 726f453ba04SDave Airlie } 727f453ba04SDave Airlie EXPORT_SYMBOL(drm_crtc_cleanup); 728f453ba04SDave Airlie 729f453ba04SDave Airlie /** 730db5f7a6eSRussell King * drm_crtc_index - find the index of a registered CRTC 731db5f7a6eSRussell King * @crtc: CRTC to find index for 732db5f7a6eSRussell King * 733db5f7a6eSRussell King * Given a registered CRTC, return the index of that CRTC within a DRM 734db5f7a6eSRussell King * device's list of CRTCs. 735db5f7a6eSRussell King */ 736db5f7a6eSRussell King unsigned int drm_crtc_index(struct drm_crtc *crtc) 737db5f7a6eSRussell King { 738db5f7a6eSRussell King unsigned int index = 0; 739db5f7a6eSRussell King struct drm_crtc *tmp; 740db5f7a6eSRussell King 741db5f7a6eSRussell King list_for_each_entry(tmp, &crtc->dev->mode_config.crtc_list, head) { 742db5f7a6eSRussell King if (tmp == crtc) 743db5f7a6eSRussell King return index; 744db5f7a6eSRussell King 745db5f7a6eSRussell King index++; 746db5f7a6eSRussell King } 747db5f7a6eSRussell King 748db5f7a6eSRussell King BUG(); 749db5f7a6eSRussell King } 750db5f7a6eSRussell King EXPORT_SYMBOL(drm_crtc_index); 751db5f7a6eSRussell King 75286f422d5SLespiau, Damien /* 753f453ba04SDave Airlie * drm_mode_remove - remove and free a mode 754f453ba04SDave Airlie * @connector: connector list to modify 755f453ba04SDave Airlie * @mode: mode to remove 756f453ba04SDave Airlie * 757f453ba04SDave Airlie * Remove @mode from @connector's mode list, then free it. 758f453ba04SDave Airlie */ 75986f422d5SLespiau, Damien static void drm_mode_remove(struct drm_connector *connector, 760f453ba04SDave Airlie struct drm_display_mode *mode) 761f453ba04SDave Airlie { 762f453ba04SDave Airlie list_del(&mode->head); 763554f1d78SSascha Hauer drm_mode_destroy(connector->dev, mode); 764f453ba04SDave Airlie } 765f453ba04SDave Airlie 766f453ba04SDave Airlie /** 767eaf99c74SChris Wilson * drm_connector_get_cmdline_mode - reads the user's cmdline mode 768eaf99c74SChris Wilson * @connector: connector to quwery 769eaf99c74SChris Wilson * @mode: returned mode 770eaf99c74SChris Wilson * 771eaf99c74SChris Wilson * The kernel supports per-connector configration of its consoles through 772eaf99c74SChris Wilson * use of the video= parameter. This function parses that option and 773eaf99c74SChris Wilson * extracts the user's specified mode (or enable/disable status) for a 774eaf99c74SChris Wilson * particular connector. This is typically only used during the early fbdev 775eaf99c74SChris Wilson * setup. 776eaf99c74SChris Wilson */ 777eaf99c74SChris Wilson static void drm_connector_get_cmdline_mode(struct drm_connector *connector) 778eaf99c74SChris Wilson { 779eaf99c74SChris Wilson struct drm_cmdline_mode *mode = &connector->cmdline_mode; 780eaf99c74SChris Wilson char *option = NULL; 781eaf99c74SChris Wilson 782eaf99c74SChris Wilson if (fb_get_options(connector->name, &option)) 783eaf99c74SChris Wilson return; 784eaf99c74SChris Wilson 785eaf99c74SChris Wilson if (!drm_mode_parse_command_line_for_connector(option, 786eaf99c74SChris Wilson connector, 787eaf99c74SChris Wilson mode)) 788eaf99c74SChris Wilson return; 789eaf99c74SChris Wilson 790eaf99c74SChris Wilson if (mode->force) { 791eaf99c74SChris Wilson const char *s; 792eaf99c74SChris Wilson 793eaf99c74SChris Wilson switch (mode->force) { 794eaf99c74SChris Wilson case DRM_FORCE_OFF: 795eaf99c74SChris Wilson s = "OFF"; 796eaf99c74SChris Wilson break; 797eaf99c74SChris Wilson case DRM_FORCE_ON_DIGITAL: 798eaf99c74SChris Wilson s = "ON - dig"; 799eaf99c74SChris Wilson break; 800eaf99c74SChris Wilson default: 801eaf99c74SChris Wilson case DRM_FORCE_ON: 802eaf99c74SChris Wilson s = "ON"; 803eaf99c74SChris Wilson break; 804eaf99c74SChris Wilson } 805eaf99c74SChris Wilson 806eaf99c74SChris Wilson DRM_INFO("forcing %s connector %s\n", connector->name, s); 807eaf99c74SChris Wilson connector->force = mode->force; 808eaf99c74SChris Wilson } 809eaf99c74SChris Wilson 810eaf99c74SChris Wilson DRM_DEBUG_KMS("cmdline mode for connector %s %dx%d@%dHz%s%s%s\n", 811eaf99c74SChris Wilson connector->name, 812eaf99c74SChris Wilson mode->xres, mode->yres, 813eaf99c74SChris Wilson mode->refresh_specified ? mode->refresh : 60, 814eaf99c74SChris Wilson mode->rb ? " reduced blanking" : "", 815eaf99c74SChris Wilson mode->margins ? " with margins" : "", 816eaf99c74SChris Wilson mode->interlace ? " interlaced" : ""); 817eaf99c74SChris Wilson } 818eaf99c74SChris Wilson 819eaf99c74SChris Wilson /** 820f453ba04SDave Airlie * drm_connector_init - Init a preallocated connector 821f453ba04SDave Airlie * @dev: DRM device 822f453ba04SDave Airlie * @connector: the connector to init 823f453ba04SDave Airlie * @funcs: callbacks for this connector 824065a50edSDaniel Vetter * @connector_type: user visible type of the connector 825f453ba04SDave Airlie * 826f453ba04SDave Airlie * Initialises a preallocated connector. Connectors should be 827f453ba04SDave Airlie * subclassed as part of driver connector objects. 8286bfc56aaSVille Syrjälä * 829c8e32cc1SDaniel Vetter * Returns: 8306bfc56aaSVille Syrjälä * Zero on success, error code on failure. 831f453ba04SDave Airlie */ 8326bfc56aaSVille Syrjälä int drm_connector_init(struct drm_device *dev, 833f453ba04SDave Airlie struct drm_connector *connector, 834f453ba04SDave Airlie const struct drm_connector_funcs *funcs, 835f453ba04SDave Airlie int connector_type) 836f453ba04SDave Airlie { 8376bfc56aaSVille Syrjälä int ret; 838b21e3afeSIlia Mirkin struct ida *connector_ida = 839b21e3afeSIlia Mirkin &drm_connector_enum_list[connector_type].ida; 8406bfc56aaSVille Syrjälä 84184849903SDaniel Vetter drm_modeset_lock_all(dev); 842f453ba04SDave Airlie 8432ee39452SDave Airlie ret = drm_mode_object_get_reg(dev, &connector->base, DRM_MODE_OBJECT_CONNECTOR, false); 8446bfc56aaSVille Syrjälä if (ret) 8452abdd313SJani Nikula goto out_unlock; 8466bfc56aaSVille Syrjälä 8477e3bdf4aSPaulo Zanoni connector->base.properties = &connector->properties; 848f453ba04SDave Airlie connector->dev = dev; 849f453ba04SDave Airlie connector->funcs = funcs; 850f453ba04SDave Airlie connector->connector_type = connector_type; 851f453ba04SDave Airlie connector->connector_type_id = 852b21e3afeSIlia Mirkin ida_simple_get(connector_ida, 1, 0, GFP_KERNEL); 853b21e3afeSIlia Mirkin if (connector->connector_type_id < 0) { 854b21e3afeSIlia Mirkin ret = connector->connector_type_id; 8552abdd313SJani Nikula goto out_put; 856b21e3afeSIlia Mirkin } 8572abdd313SJani Nikula connector->name = 8582abdd313SJani Nikula kasprintf(GFP_KERNEL, "%s-%d", 8592abdd313SJani Nikula drm_connector_enum_list[connector_type].name, 8602abdd313SJani Nikula connector->connector_type_id); 8612abdd313SJani Nikula if (!connector->name) { 8622abdd313SJani Nikula ret = -ENOMEM; 8632abdd313SJani Nikula goto out_put; 8642abdd313SJani Nikula } 8652abdd313SJani Nikula 866f453ba04SDave Airlie INIT_LIST_HEAD(&connector->probed_modes); 867f453ba04SDave Airlie INIT_LIST_HEAD(&connector->modes); 868f453ba04SDave Airlie connector->edid_blob_ptr = NULL; 8695e2cb2f6SDaniel Vetter connector->status = connector_status_unknown; 870f453ba04SDave Airlie 871eaf99c74SChris Wilson drm_connector_get_cmdline_mode(connector); 872eaf99c74SChris Wilson 873f453ba04SDave Airlie list_add_tail(&connector->head, &dev->mode_config.connector_list); 874f453ba04SDave Airlie dev->mode_config.num_connector++; 875f453ba04SDave Airlie 876a7331e5cSThomas Hellstrom if (connector_type != DRM_MODE_CONNECTOR_VIRTUAL) 87758495563SRob Clark drm_object_attach_property(&connector->base, 878a7331e5cSThomas Hellstrom dev->mode_config.edid_property, 879a7331e5cSThomas Hellstrom 0); 880f453ba04SDave Airlie 88158495563SRob Clark drm_object_attach_property(&connector->base, 882f453ba04SDave Airlie dev->mode_config.dpms_property, 0); 883f453ba04SDave Airlie 88430f65707SThomas Wood connector->debugfs_entry = NULL; 88530f65707SThomas Wood 8862abdd313SJani Nikula out_put: 8872abdd313SJani Nikula if (ret) 8882abdd313SJani Nikula drm_mode_object_put(dev, &connector->base); 8892abdd313SJani Nikula 8902abdd313SJani Nikula out_unlock: 89184849903SDaniel Vetter drm_modeset_unlock_all(dev); 8926bfc56aaSVille Syrjälä 8936bfc56aaSVille Syrjälä return ret; 894f453ba04SDave Airlie } 895f453ba04SDave Airlie EXPORT_SYMBOL(drm_connector_init); 896f453ba04SDave Airlie 897f453ba04SDave Airlie /** 898f453ba04SDave Airlie * drm_connector_cleanup - cleans up an initialised connector 899f453ba04SDave Airlie * @connector: connector to cleanup 900f453ba04SDave Airlie * 901f453ba04SDave Airlie * Cleans up the connector but doesn't free the object. 902f453ba04SDave Airlie */ 903f453ba04SDave Airlie void drm_connector_cleanup(struct drm_connector *connector) 904f453ba04SDave Airlie { 905f453ba04SDave Airlie struct drm_device *dev = connector->dev; 906f453ba04SDave Airlie struct drm_display_mode *mode, *t; 907f453ba04SDave Airlie 908f453ba04SDave Airlie list_for_each_entry_safe(mode, t, &connector->probed_modes, head) 909f453ba04SDave Airlie drm_mode_remove(connector, mode); 910f453ba04SDave Airlie 911f453ba04SDave Airlie list_for_each_entry_safe(mode, t, &connector->modes, head) 912f453ba04SDave Airlie drm_mode_remove(connector, mode); 913f453ba04SDave Airlie 914b21e3afeSIlia Mirkin ida_remove(&drm_connector_enum_list[connector->connector_type].ida, 915b21e3afeSIlia Mirkin connector->connector_type_id); 916b21e3afeSIlia Mirkin 917f453ba04SDave Airlie drm_mode_object_put(dev, &connector->base); 9182abdd313SJani Nikula kfree(connector->name); 9192abdd313SJani Nikula connector->name = NULL; 920f453ba04SDave Airlie list_del(&connector->head); 9216380c509SJoonyoung Shim dev->mode_config.num_connector--; 922f453ba04SDave Airlie } 923f453ba04SDave Airlie EXPORT_SYMBOL(drm_connector_cleanup); 924f453ba04SDave Airlie 925c8e32cc1SDaniel Vetter /** 92610f637bfSDaniel Vetter * drm_connector_index - find the index of a registered connector 92710f637bfSDaniel Vetter * @connector: connector to find index for 92810f637bfSDaniel Vetter * 92910f637bfSDaniel Vetter * Given a registered connector, return the index of that connector within a DRM 93010f637bfSDaniel Vetter * device's list of connectors. 93110f637bfSDaniel Vetter */ 93210f637bfSDaniel Vetter unsigned int drm_connector_index(struct drm_connector *connector) 93310f637bfSDaniel Vetter { 93410f637bfSDaniel Vetter unsigned int index = 0; 93510f637bfSDaniel Vetter struct drm_connector *tmp; 93610f637bfSDaniel Vetter 93710f637bfSDaniel Vetter list_for_each_entry(tmp, &connector->dev->mode_config.connector_list, head) { 93810f637bfSDaniel Vetter if (tmp == connector) 93910f637bfSDaniel Vetter return index; 94010f637bfSDaniel Vetter 94110f637bfSDaniel Vetter index++; 94210f637bfSDaniel Vetter } 94310f637bfSDaniel Vetter 94410f637bfSDaniel Vetter BUG(); 94510f637bfSDaniel Vetter } 94610f637bfSDaniel Vetter EXPORT_SYMBOL(drm_connector_index); 94710f637bfSDaniel Vetter 94810f637bfSDaniel Vetter /** 94934ea3d38SThomas Wood * drm_connector_register - register a connector 95034ea3d38SThomas Wood * @connector: the connector to register 95134ea3d38SThomas Wood * 95234ea3d38SThomas Wood * Register userspace interfaces for a connector 95334ea3d38SThomas Wood * 95434ea3d38SThomas Wood * Returns: 95534ea3d38SThomas Wood * Zero on success, error code on failure. 95634ea3d38SThomas Wood */ 95734ea3d38SThomas Wood int drm_connector_register(struct drm_connector *connector) 95834ea3d38SThomas Wood { 95930f65707SThomas Wood int ret; 96030f65707SThomas Wood 9612ee39452SDave Airlie drm_mode_object_register(connector->dev, &connector->base); 9622ee39452SDave Airlie 96330f65707SThomas Wood ret = drm_sysfs_connector_add(connector); 96430f65707SThomas Wood if (ret) 96530f65707SThomas Wood return ret; 96630f65707SThomas Wood 96730f65707SThomas Wood ret = drm_debugfs_connector_add(connector); 96830f65707SThomas Wood if (ret) { 96930f65707SThomas Wood drm_sysfs_connector_remove(connector); 97030f65707SThomas Wood return ret; 97130f65707SThomas Wood } 97230f65707SThomas Wood 97330f65707SThomas Wood return 0; 97434ea3d38SThomas Wood } 97534ea3d38SThomas Wood EXPORT_SYMBOL(drm_connector_register); 97634ea3d38SThomas Wood 97734ea3d38SThomas Wood /** 97834ea3d38SThomas Wood * drm_connector_unregister - unregister a connector 97934ea3d38SThomas Wood * @connector: the connector to unregister 98034ea3d38SThomas Wood * 98134ea3d38SThomas Wood * Unregister userspace interfaces for a connector 98234ea3d38SThomas Wood */ 98334ea3d38SThomas Wood void drm_connector_unregister(struct drm_connector *connector) 98434ea3d38SThomas Wood { 98534ea3d38SThomas Wood drm_sysfs_connector_remove(connector); 98630f65707SThomas Wood drm_debugfs_connector_remove(connector); 98734ea3d38SThomas Wood } 98834ea3d38SThomas Wood EXPORT_SYMBOL(drm_connector_unregister); 98934ea3d38SThomas Wood 99034ea3d38SThomas Wood 99134ea3d38SThomas Wood /** 992c8e32cc1SDaniel Vetter * drm_connector_unplug_all - unregister connector userspace interfaces 993c8e32cc1SDaniel Vetter * @dev: drm device 994c8e32cc1SDaniel Vetter * 995c8e32cc1SDaniel Vetter * This function unregisters all connector userspace interfaces in sysfs. Should 996c8e32cc1SDaniel Vetter * be call when the device is disconnected, e.g. from an usb driver's 997c8e32cc1SDaniel Vetter * ->disconnect callback. 998c8e32cc1SDaniel Vetter */ 999cbc7e221SDave Airlie void drm_connector_unplug_all(struct drm_device *dev) 1000cbc7e221SDave Airlie { 1001cbc7e221SDave Airlie struct drm_connector *connector; 1002cbc7e221SDave Airlie 1003cbc7e221SDave Airlie /* taking the mode config mutex ends up in a clash with sysfs */ 1004cbc7e221SDave Airlie list_for_each_entry(connector, &dev->mode_config.connector_list, head) 100534ea3d38SThomas Wood drm_connector_unregister(connector); 1006cbc7e221SDave Airlie 1007cbc7e221SDave Airlie } 1008cbc7e221SDave Airlie EXPORT_SYMBOL(drm_connector_unplug_all); 1009cbc7e221SDave Airlie 1010c8e32cc1SDaniel Vetter /** 1011c8e32cc1SDaniel Vetter * drm_bridge_init - initialize a drm transcoder/bridge 1012c8e32cc1SDaniel Vetter * @dev: drm device 1013c8e32cc1SDaniel Vetter * @bridge: transcoder/bridge to set up 1014c8e32cc1SDaniel Vetter * @funcs: bridge function table 1015c8e32cc1SDaniel Vetter * 1016c8e32cc1SDaniel Vetter * Initialises a preallocated bridge. Bridges should be 1017c8e32cc1SDaniel Vetter * subclassed as part of driver connector objects. 1018c8e32cc1SDaniel Vetter * 1019c8e32cc1SDaniel Vetter * Returns: 1020c8e32cc1SDaniel Vetter * Zero on success, error code on failure. 1021c8e32cc1SDaniel Vetter */ 10223b336ec4SSean Paul int drm_bridge_init(struct drm_device *dev, struct drm_bridge *bridge, 10233b336ec4SSean Paul const struct drm_bridge_funcs *funcs) 10243b336ec4SSean Paul { 10253b336ec4SSean Paul int ret; 10263b336ec4SSean Paul 10273b336ec4SSean Paul drm_modeset_lock_all(dev); 10283b336ec4SSean Paul 10293b336ec4SSean Paul ret = drm_mode_object_get(dev, &bridge->base, DRM_MODE_OBJECT_BRIDGE); 10303b336ec4SSean Paul if (ret) 10313b336ec4SSean Paul goto out; 10323b336ec4SSean Paul 10333b336ec4SSean Paul bridge->dev = dev; 10343b336ec4SSean Paul bridge->funcs = funcs; 10353b336ec4SSean Paul 10363b336ec4SSean Paul list_add_tail(&bridge->head, &dev->mode_config.bridge_list); 10373b336ec4SSean Paul dev->mode_config.num_bridge++; 10383b336ec4SSean Paul 10393b336ec4SSean Paul out: 10403b336ec4SSean Paul drm_modeset_unlock_all(dev); 10413b336ec4SSean Paul return ret; 10423b336ec4SSean Paul } 10433b336ec4SSean Paul EXPORT_SYMBOL(drm_bridge_init); 10443b336ec4SSean Paul 1045c8e32cc1SDaniel Vetter /** 1046c8e32cc1SDaniel Vetter * drm_bridge_cleanup - cleans up an initialised bridge 1047c8e32cc1SDaniel Vetter * @bridge: bridge to cleanup 1048c8e32cc1SDaniel Vetter * 1049c8e32cc1SDaniel Vetter * Cleans up the bridge but doesn't free the object. 1050c8e32cc1SDaniel Vetter */ 10513b336ec4SSean Paul void drm_bridge_cleanup(struct drm_bridge *bridge) 10523b336ec4SSean Paul { 10533b336ec4SSean Paul struct drm_device *dev = bridge->dev; 10543b336ec4SSean Paul 10553b336ec4SSean Paul drm_modeset_lock_all(dev); 10563b336ec4SSean Paul drm_mode_object_put(dev, &bridge->base); 10573b336ec4SSean Paul list_del(&bridge->head); 10583b336ec4SSean Paul dev->mode_config.num_bridge--; 10593b336ec4SSean Paul drm_modeset_unlock_all(dev); 10603b336ec4SSean Paul } 10613b336ec4SSean Paul EXPORT_SYMBOL(drm_bridge_cleanup); 10623b336ec4SSean Paul 1063c8e32cc1SDaniel Vetter /** 1064c8e32cc1SDaniel Vetter * drm_encoder_init - Init a preallocated encoder 1065c8e32cc1SDaniel Vetter * @dev: drm device 1066c8e32cc1SDaniel Vetter * @encoder: the encoder to init 1067c8e32cc1SDaniel Vetter * @funcs: callbacks for this encoder 1068c8e32cc1SDaniel Vetter * @encoder_type: user visible type of the encoder 1069c8e32cc1SDaniel Vetter * 1070c8e32cc1SDaniel Vetter * Initialises a preallocated encoder. Encoder should be 1071c8e32cc1SDaniel Vetter * subclassed as part of driver encoder objects. 1072c8e32cc1SDaniel Vetter * 1073c8e32cc1SDaniel Vetter * Returns: 1074c8e32cc1SDaniel Vetter * Zero on success, error code on failure. 1075c8e32cc1SDaniel Vetter */ 10766bfc56aaSVille Syrjälä int drm_encoder_init(struct drm_device *dev, 1077f453ba04SDave Airlie struct drm_encoder *encoder, 1078f453ba04SDave Airlie const struct drm_encoder_funcs *funcs, 1079f453ba04SDave Airlie int encoder_type) 1080f453ba04SDave Airlie { 10816bfc56aaSVille Syrjälä int ret; 10826bfc56aaSVille Syrjälä 108384849903SDaniel Vetter drm_modeset_lock_all(dev); 1084f453ba04SDave Airlie 10856bfc56aaSVille Syrjälä ret = drm_mode_object_get(dev, &encoder->base, DRM_MODE_OBJECT_ENCODER); 10866bfc56aaSVille Syrjälä if (ret) 1087e5748946SJani Nikula goto out_unlock; 1088f453ba04SDave Airlie 10896bfc56aaSVille Syrjälä encoder->dev = dev; 1090f453ba04SDave Airlie encoder->encoder_type = encoder_type; 1091f453ba04SDave Airlie encoder->funcs = funcs; 1092e5748946SJani Nikula encoder->name = kasprintf(GFP_KERNEL, "%s-%d", 1093e5748946SJani Nikula drm_encoder_enum_list[encoder_type].name, 1094e5748946SJani Nikula encoder->base.id); 1095e5748946SJani Nikula if (!encoder->name) { 1096e5748946SJani Nikula ret = -ENOMEM; 1097e5748946SJani Nikula goto out_put; 1098e5748946SJani Nikula } 1099f453ba04SDave Airlie 1100f453ba04SDave Airlie list_add_tail(&encoder->head, &dev->mode_config.encoder_list); 1101f453ba04SDave Airlie dev->mode_config.num_encoder++; 1102f453ba04SDave Airlie 1103e5748946SJani Nikula out_put: 1104e5748946SJani Nikula if (ret) 1105e5748946SJani Nikula drm_mode_object_put(dev, &encoder->base); 1106e5748946SJani Nikula 1107e5748946SJani Nikula out_unlock: 110884849903SDaniel Vetter drm_modeset_unlock_all(dev); 11096bfc56aaSVille Syrjälä 11106bfc56aaSVille Syrjälä return ret; 1111f453ba04SDave Airlie } 1112f453ba04SDave Airlie EXPORT_SYMBOL(drm_encoder_init); 1113f453ba04SDave Airlie 1114c8e32cc1SDaniel Vetter /** 1115c8e32cc1SDaniel Vetter * drm_encoder_cleanup - cleans up an initialised encoder 1116c8e32cc1SDaniel Vetter * @encoder: encoder to cleanup 1117c8e32cc1SDaniel Vetter * 1118c8e32cc1SDaniel Vetter * Cleans up the encoder but doesn't free the object. 1119c8e32cc1SDaniel Vetter */ 1120f453ba04SDave Airlie void drm_encoder_cleanup(struct drm_encoder *encoder) 1121f453ba04SDave Airlie { 1122f453ba04SDave Airlie struct drm_device *dev = encoder->dev; 112384849903SDaniel Vetter drm_modeset_lock_all(dev); 1124f453ba04SDave Airlie drm_mode_object_put(dev, &encoder->base); 1125e5748946SJani Nikula kfree(encoder->name); 1126e5748946SJani Nikula encoder->name = NULL; 1127f453ba04SDave Airlie list_del(&encoder->head); 11286380c509SJoonyoung Shim dev->mode_config.num_encoder--; 112984849903SDaniel Vetter drm_modeset_unlock_all(dev); 1130f453ba04SDave Airlie } 1131f453ba04SDave Airlie EXPORT_SYMBOL(drm_encoder_cleanup); 1132f453ba04SDave Airlie 113335f2c3aeSVille Syrjälä /** 1134dc415ff9SMatt Roper * drm_universal_plane_init - Initialize a new universal plane object 113535f2c3aeSVille Syrjälä * @dev: DRM device 113635f2c3aeSVille Syrjälä * @plane: plane object to init 113735f2c3aeSVille Syrjälä * @possible_crtcs: bitmask of possible CRTCs 113835f2c3aeSVille Syrjälä * @funcs: callbacks for the new plane 113935f2c3aeSVille Syrjälä * @formats: array of supported formats (%DRM_FORMAT_*) 114035f2c3aeSVille Syrjälä * @format_count: number of elements in @formats 1141dc415ff9SMatt Roper * @type: type of plane (overlay, primary, cursor) 114235f2c3aeSVille Syrjälä * 1143dc415ff9SMatt Roper * Initializes a plane object of type @type. 114435f2c3aeSVille Syrjälä * 1145c8e32cc1SDaniel Vetter * Returns: 114635f2c3aeSVille Syrjälä * Zero on success, error code on failure. 114735f2c3aeSVille Syrjälä */ 1148dc415ff9SMatt Roper int drm_universal_plane_init(struct drm_device *dev, struct drm_plane *plane, 11498cf5c917SJesse Barnes unsigned long possible_crtcs, 11508cf5c917SJesse Barnes const struct drm_plane_funcs *funcs, 11510a7eb243SRob Clark const uint32_t *formats, uint32_t format_count, 1152dc415ff9SMatt Roper enum drm_plane_type type) 11538cf5c917SJesse Barnes { 11546bfc56aaSVille Syrjälä int ret; 11556bfc56aaSVille Syrjälä 115684849903SDaniel Vetter drm_modeset_lock_all(dev); 11578cf5c917SJesse Barnes 11586bfc56aaSVille Syrjälä ret = drm_mode_object_get(dev, &plane->base, DRM_MODE_OBJECT_PLANE); 11596bfc56aaSVille Syrjälä if (ret) 11606bfc56aaSVille Syrjälä goto out; 11616bfc56aaSVille Syrjälä 11624d93914aSRob Clark plane->base.properties = &plane->properties; 11638cf5c917SJesse Barnes plane->dev = dev; 11648cf5c917SJesse Barnes plane->funcs = funcs; 11658cf5c917SJesse Barnes plane->format_types = kmalloc(sizeof(uint32_t) * format_count, 11668cf5c917SJesse Barnes GFP_KERNEL); 11678cf5c917SJesse Barnes if (!plane->format_types) { 11688cf5c917SJesse Barnes DRM_DEBUG_KMS("out of memory when allocating plane\n"); 11698cf5c917SJesse Barnes drm_mode_object_put(dev, &plane->base); 11706bfc56aaSVille Syrjälä ret = -ENOMEM; 11716bfc56aaSVille Syrjälä goto out; 11728cf5c917SJesse Barnes } 11738cf5c917SJesse Barnes 1174308e5bcbSJesse Barnes memcpy(plane->format_types, formats, format_count * sizeof(uint32_t)); 11758cf5c917SJesse Barnes plane->format_count = format_count; 11768cf5c917SJesse Barnes plane->possible_crtcs = possible_crtcs; 1177dc415ff9SMatt Roper plane->type = type; 11788cf5c917SJesse Barnes 11798cf5c917SJesse Barnes list_add_tail(&plane->head, &dev->mode_config.plane_list); 1180e27dde3eSMatt Roper dev->mode_config.num_total_plane++; 1181e27dde3eSMatt Roper if (plane->type == DRM_PLANE_TYPE_OVERLAY) 1182e27dde3eSMatt Roper dev->mode_config.num_overlay_plane++; 11838cf5c917SJesse Barnes 11849922ab5aSRob Clark drm_object_attach_property(&plane->base, 11859922ab5aSRob Clark dev->mode_config.plane_type_property, 11869922ab5aSRob Clark plane->type); 11879922ab5aSRob Clark 11886bfc56aaSVille Syrjälä out: 118984849903SDaniel Vetter drm_modeset_unlock_all(dev); 11908cf5c917SJesse Barnes 11916bfc56aaSVille Syrjälä return ret; 11928cf5c917SJesse Barnes } 1193dc415ff9SMatt Roper EXPORT_SYMBOL(drm_universal_plane_init); 1194dc415ff9SMatt Roper 1195dc415ff9SMatt Roper /** 1196dc415ff9SMatt Roper * drm_plane_init - Initialize a legacy plane 1197dc415ff9SMatt Roper * @dev: DRM device 1198dc415ff9SMatt Roper * @plane: plane object to init 1199dc415ff9SMatt Roper * @possible_crtcs: bitmask of possible CRTCs 1200dc415ff9SMatt Roper * @funcs: callbacks for the new plane 1201dc415ff9SMatt Roper * @formats: array of supported formats (%DRM_FORMAT_*) 1202dc415ff9SMatt Roper * @format_count: number of elements in @formats 1203dc415ff9SMatt Roper * @is_primary: plane type (primary vs overlay) 1204dc415ff9SMatt Roper * 1205dc415ff9SMatt Roper * Legacy API to initialize a DRM plane. 1206dc415ff9SMatt Roper * 1207dc415ff9SMatt Roper * New drivers should call drm_universal_plane_init() instead. 1208dc415ff9SMatt Roper * 1209dc415ff9SMatt Roper * Returns: 1210dc415ff9SMatt Roper * Zero on success, error code on failure. 1211dc415ff9SMatt Roper */ 1212dc415ff9SMatt Roper int drm_plane_init(struct drm_device *dev, struct drm_plane *plane, 1213dc415ff9SMatt Roper unsigned long possible_crtcs, 1214dc415ff9SMatt Roper const struct drm_plane_funcs *funcs, 1215dc415ff9SMatt Roper const uint32_t *formats, uint32_t format_count, 1216dc415ff9SMatt Roper bool is_primary) 1217dc415ff9SMatt Roper { 1218dc415ff9SMatt Roper enum drm_plane_type type; 1219dc415ff9SMatt Roper 1220dc415ff9SMatt Roper type = is_primary ? DRM_PLANE_TYPE_PRIMARY : DRM_PLANE_TYPE_OVERLAY; 1221dc415ff9SMatt Roper return drm_universal_plane_init(dev, plane, possible_crtcs, funcs, 1222dc415ff9SMatt Roper formats, format_count, type); 1223dc415ff9SMatt Roper } 12248cf5c917SJesse Barnes EXPORT_SYMBOL(drm_plane_init); 12258cf5c917SJesse Barnes 122635f2c3aeSVille Syrjälä /** 122735f2c3aeSVille Syrjälä * drm_plane_cleanup - Clean up the core plane usage 122835f2c3aeSVille Syrjälä * @plane: plane to cleanup 122935f2c3aeSVille Syrjälä * 123035f2c3aeSVille Syrjälä * This function cleans up @plane and removes it from the DRM mode setting 123135f2c3aeSVille Syrjälä * core. Note that the function does *not* free the plane structure itself, 123235f2c3aeSVille Syrjälä * this is the responsibility of the caller. 123335f2c3aeSVille Syrjälä */ 12348cf5c917SJesse Barnes void drm_plane_cleanup(struct drm_plane *plane) 12358cf5c917SJesse Barnes { 12368cf5c917SJesse Barnes struct drm_device *dev = plane->dev; 12378cf5c917SJesse Barnes 123884849903SDaniel Vetter drm_modeset_lock_all(dev); 12398cf5c917SJesse Barnes kfree(plane->format_types); 12408cf5c917SJesse Barnes drm_mode_object_put(dev, &plane->base); 1241dc415ff9SMatt Roper 1242dc415ff9SMatt Roper BUG_ON(list_empty(&plane->head)); 1243dc415ff9SMatt Roper 12448cf5c917SJesse Barnes list_del(&plane->head); 1245e27dde3eSMatt Roper dev->mode_config.num_total_plane--; 1246e27dde3eSMatt Roper if (plane->type == DRM_PLANE_TYPE_OVERLAY) 1247e27dde3eSMatt Roper dev->mode_config.num_overlay_plane--; 124884849903SDaniel Vetter drm_modeset_unlock_all(dev); 12498cf5c917SJesse Barnes } 12508cf5c917SJesse Barnes EXPORT_SYMBOL(drm_plane_cleanup); 12518cf5c917SJesse Barnes 125235f2c3aeSVille Syrjälä /** 125310f637bfSDaniel Vetter * drm_plane_index - find the index of a registered plane 125410f637bfSDaniel Vetter * @plane: plane to find index for 125510f637bfSDaniel Vetter * 125610f637bfSDaniel Vetter * Given a registered plane, return the index of that CRTC within a DRM 125710f637bfSDaniel Vetter * device's list of planes. 125810f637bfSDaniel Vetter */ 125910f637bfSDaniel Vetter unsigned int drm_plane_index(struct drm_plane *plane) 126010f637bfSDaniel Vetter { 126110f637bfSDaniel Vetter unsigned int index = 0; 126210f637bfSDaniel Vetter struct drm_plane *tmp; 126310f637bfSDaniel Vetter 126410f637bfSDaniel Vetter list_for_each_entry(tmp, &plane->dev->mode_config.plane_list, head) { 126510f637bfSDaniel Vetter if (tmp == plane) 126610f637bfSDaniel Vetter return index; 126710f637bfSDaniel Vetter 126810f637bfSDaniel Vetter index++; 126910f637bfSDaniel Vetter } 127010f637bfSDaniel Vetter 127110f637bfSDaniel Vetter BUG(); 127210f637bfSDaniel Vetter } 127310f637bfSDaniel Vetter EXPORT_SYMBOL(drm_plane_index); 127410f637bfSDaniel Vetter 127510f637bfSDaniel Vetter /** 127635f2c3aeSVille Syrjälä * drm_plane_force_disable - Forcibly disable a plane 127735f2c3aeSVille Syrjälä * @plane: plane to disable 127835f2c3aeSVille Syrjälä * 127935f2c3aeSVille Syrjälä * Forces the plane to be disabled. 128035f2c3aeSVille Syrjälä * 128135f2c3aeSVille Syrjälä * Used when the plane's current framebuffer is destroyed, 128235f2c3aeSVille Syrjälä * and when restoring fbdev mode. 128335f2c3aeSVille Syrjälä */ 12849125e618SVille Syrjälä void drm_plane_force_disable(struct drm_plane *plane) 12859125e618SVille Syrjälä { 12869125e618SVille Syrjälä int ret; 12879125e618SVille Syrjälä 12883d30a59bSDaniel Vetter if (!plane->fb) 12899125e618SVille Syrjälä return; 12909125e618SVille Syrjälä 12913d30a59bSDaniel Vetter plane->old_fb = plane->fb; 12929125e618SVille Syrjälä ret = plane->funcs->disable_plane(plane); 1293731cce48SDaniel Vetter if (ret) { 12949125e618SVille Syrjälä DRM_ERROR("failed to disable plane with busy fb\n"); 12953d30a59bSDaniel Vetter plane->old_fb = NULL; 1296731cce48SDaniel Vetter return; 1297731cce48SDaniel Vetter } 12989125e618SVille Syrjälä /* disconnect the plane from the fb and crtc: */ 12993d30a59bSDaniel Vetter __drm_framebuffer_unreference(plane->old_fb); 13003d30a59bSDaniel Vetter plane->old_fb = NULL; 13019125e618SVille Syrjälä plane->fb = NULL; 13029125e618SVille Syrjälä plane->crtc = NULL; 13039125e618SVille Syrjälä } 13049125e618SVille Syrjälä EXPORT_SYMBOL(drm_plane_force_disable); 13059125e618SVille Syrjälä 1306f453ba04SDave Airlie static int drm_mode_create_standard_connector_properties(struct drm_device *dev) 1307f453ba04SDave Airlie { 1308f453ba04SDave Airlie struct drm_property *edid; 1309f453ba04SDave Airlie struct drm_property *dpms; 131043aba7ebSDave Airlie struct drm_property *dev_path; 1311f453ba04SDave Airlie 1312f453ba04SDave Airlie /* 1313f453ba04SDave Airlie * Standard properties (apply to all connectors) 1314f453ba04SDave Airlie */ 1315f453ba04SDave Airlie edid = drm_property_create(dev, DRM_MODE_PROP_BLOB | 1316f453ba04SDave Airlie DRM_MODE_PROP_IMMUTABLE, 1317f453ba04SDave Airlie "EDID", 0); 1318f453ba04SDave Airlie dev->mode_config.edid_property = edid; 1319f453ba04SDave Airlie 13204a67d391SSascha Hauer dpms = drm_property_create_enum(dev, 0, 13214a67d391SSascha Hauer "DPMS", drm_dpms_enum_list, 13224a67d391SSascha Hauer ARRAY_SIZE(drm_dpms_enum_list)); 1323f453ba04SDave Airlie dev->mode_config.dpms_property = dpms; 1324f453ba04SDave Airlie 132543aba7ebSDave Airlie dev_path = drm_property_create(dev, 132643aba7ebSDave Airlie DRM_MODE_PROP_BLOB | 132743aba7ebSDave Airlie DRM_MODE_PROP_IMMUTABLE, 132843aba7ebSDave Airlie "PATH", 0); 132943aba7ebSDave Airlie dev->mode_config.path_property = dev_path; 133043aba7ebSDave Airlie 1331f453ba04SDave Airlie return 0; 1332f453ba04SDave Airlie } 1333f453ba04SDave Airlie 13349922ab5aSRob Clark static int drm_mode_create_standard_plane_properties(struct drm_device *dev) 13359922ab5aSRob Clark { 13369922ab5aSRob Clark struct drm_property *type; 13379922ab5aSRob Clark 13389922ab5aSRob Clark /* 13399922ab5aSRob Clark * Standard properties (apply to all planes) 13409922ab5aSRob Clark */ 13419922ab5aSRob Clark type = drm_property_create_enum(dev, DRM_MODE_PROP_IMMUTABLE, 13429922ab5aSRob Clark "type", drm_plane_type_enum_list, 13439922ab5aSRob Clark ARRAY_SIZE(drm_plane_type_enum_list)); 13449922ab5aSRob Clark dev->mode_config.plane_type_property = type; 13459922ab5aSRob Clark 13469922ab5aSRob Clark return 0; 13479922ab5aSRob Clark } 13489922ab5aSRob Clark 1349f453ba04SDave Airlie /** 1350f453ba04SDave Airlie * drm_mode_create_dvi_i_properties - create DVI-I specific connector properties 1351f453ba04SDave Airlie * @dev: DRM device 1352f453ba04SDave Airlie * 1353f453ba04SDave Airlie * Called by a driver the first time a DVI-I connector is made. 1354f453ba04SDave Airlie */ 1355f453ba04SDave Airlie int drm_mode_create_dvi_i_properties(struct drm_device *dev) 1356f453ba04SDave Airlie { 1357f453ba04SDave Airlie struct drm_property *dvi_i_selector; 1358f453ba04SDave Airlie struct drm_property *dvi_i_subconnector; 1359f453ba04SDave Airlie 1360f453ba04SDave Airlie if (dev->mode_config.dvi_i_select_subconnector_property) 1361f453ba04SDave Airlie return 0; 1362f453ba04SDave Airlie 1363f453ba04SDave Airlie dvi_i_selector = 13644a67d391SSascha Hauer drm_property_create_enum(dev, 0, 1365f453ba04SDave Airlie "select subconnector", 13664a67d391SSascha Hauer drm_dvi_i_select_enum_list, 1367f453ba04SDave Airlie ARRAY_SIZE(drm_dvi_i_select_enum_list)); 1368f453ba04SDave Airlie dev->mode_config.dvi_i_select_subconnector_property = dvi_i_selector; 1369f453ba04SDave Airlie 13704a67d391SSascha Hauer dvi_i_subconnector = drm_property_create_enum(dev, DRM_MODE_PROP_IMMUTABLE, 1371f453ba04SDave Airlie "subconnector", 13724a67d391SSascha Hauer drm_dvi_i_subconnector_enum_list, 1373f453ba04SDave Airlie ARRAY_SIZE(drm_dvi_i_subconnector_enum_list)); 1374f453ba04SDave Airlie dev->mode_config.dvi_i_subconnector_property = dvi_i_subconnector; 1375f453ba04SDave Airlie 1376f453ba04SDave Airlie return 0; 1377f453ba04SDave Airlie } 1378f453ba04SDave Airlie EXPORT_SYMBOL(drm_mode_create_dvi_i_properties); 1379f453ba04SDave Airlie 1380f453ba04SDave Airlie /** 1381f453ba04SDave Airlie * drm_create_tv_properties - create TV specific connector properties 1382f453ba04SDave Airlie * @dev: DRM device 1383f453ba04SDave Airlie * @num_modes: number of different TV formats (modes) supported 1384f453ba04SDave Airlie * @modes: array of pointers to strings containing name of each format 1385f453ba04SDave Airlie * 1386f453ba04SDave Airlie * Called by a driver's TV initialization routine, this function creates 1387f453ba04SDave Airlie * the TV specific connector properties for a given device. Caller is 1388f453ba04SDave Airlie * responsible for allocating a list of format names and passing them to 1389f453ba04SDave Airlie * this routine. 1390f453ba04SDave Airlie */ 1391f453ba04SDave Airlie int drm_mode_create_tv_properties(struct drm_device *dev, int num_modes, 1392f453ba04SDave Airlie char *modes[]) 1393f453ba04SDave Airlie { 1394f453ba04SDave Airlie struct drm_property *tv_selector; 1395f453ba04SDave Airlie struct drm_property *tv_subconnector; 1396f453ba04SDave Airlie int i; 1397f453ba04SDave Airlie 1398f453ba04SDave Airlie if (dev->mode_config.tv_select_subconnector_property) 1399f453ba04SDave Airlie return 0; 1400f453ba04SDave Airlie 1401f453ba04SDave Airlie /* 1402f453ba04SDave Airlie * Basic connector properties 1403f453ba04SDave Airlie */ 14044a67d391SSascha Hauer tv_selector = drm_property_create_enum(dev, 0, 1405f453ba04SDave Airlie "select subconnector", 14064a67d391SSascha Hauer drm_tv_select_enum_list, 1407f453ba04SDave Airlie ARRAY_SIZE(drm_tv_select_enum_list)); 1408f453ba04SDave Airlie dev->mode_config.tv_select_subconnector_property = tv_selector; 1409f453ba04SDave Airlie 1410f453ba04SDave Airlie tv_subconnector = 14114a67d391SSascha Hauer drm_property_create_enum(dev, DRM_MODE_PROP_IMMUTABLE, 14124a67d391SSascha Hauer "subconnector", 14134a67d391SSascha Hauer drm_tv_subconnector_enum_list, 1414f453ba04SDave Airlie ARRAY_SIZE(drm_tv_subconnector_enum_list)); 1415f453ba04SDave Airlie dev->mode_config.tv_subconnector_property = tv_subconnector; 1416f453ba04SDave Airlie 1417f453ba04SDave Airlie /* 1418f453ba04SDave Airlie * Other, TV specific properties: margins & TV modes. 1419f453ba04SDave Airlie */ 1420f453ba04SDave Airlie dev->mode_config.tv_left_margin_property = 1421d9bc3c02SSascha Hauer drm_property_create_range(dev, 0, "left margin", 0, 100); 1422f453ba04SDave Airlie 1423f453ba04SDave Airlie dev->mode_config.tv_right_margin_property = 1424d9bc3c02SSascha Hauer drm_property_create_range(dev, 0, "right margin", 0, 100); 1425f453ba04SDave Airlie 1426f453ba04SDave Airlie dev->mode_config.tv_top_margin_property = 1427d9bc3c02SSascha Hauer drm_property_create_range(dev, 0, "top margin", 0, 100); 1428f453ba04SDave Airlie 1429f453ba04SDave Airlie dev->mode_config.tv_bottom_margin_property = 1430d9bc3c02SSascha Hauer drm_property_create_range(dev, 0, "bottom margin", 0, 100); 1431f453ba04SDave Airlie 1432f453ba04SDave Airlie dev->mode_config.tv_mode_property = 1433f453ba04SDave Airlie drm_property_create(dev, DRM_MODE_PROP_ENUM, 1434f453ba04SDave Airlie "mode", num_modes); 1435f453ba04SDave Airlie for (i = 0; i < num_modes; i++) 1436f453ba04SDave Airlie drm_property_add_enum(dev->mode_config.tv_mode_property, i, 1437f453ba04SDave Airlie i, modes[i]); 1438f453ba04SDave Airlie 1439b6b7902eSFrancisco Jerez dev->mode_config.tv_brightness_property = 1440d9bc3c02SSascha Hauer drm_property_create_range(dev, 0, "brightness", 0, 100); 1441b6b7902eSFrancisco Jerez 1442b6b7902eSFrancisco Jerez dev->mode_config.tv_contrast_property = 1443d9bc3c02SSascha Hauer drm_property_create_range(dev, 0, "contrast", 0, 100); 1444b6b7902eSFrancisco Jerez 1445b6b7902eSFrancisco Jerez dev->mode_config.tv_flicker_reduction_property = 1446d9bc3c02SSascha Hauer drm_property_create_range(dev, 0, "flicker reduction", 0, 100); 1447b6b7902eSFrancisco Jerez 1448a75f0236SFrancisco Jerez dev->mode_config.tv_overscan_property = 1449d9bc3c02SSascha Hauer drm_property_create_range(dev, 0, "overscan", 0, 100); 1450a75f0236SFrancisco Jerez 1451a75f0236SFrancisco Jerez dev->mode_config.tv_saturation_property = 1452d9bc3c02SSascha Hauer drm_property_create_range(dev, 0, "saturation", 0, 100); 1453a75f0236SFrancisco Jerez 1454a75f0236SFrancisco Jerez dev->mode_config.tv_hue_property = 1455d9bc3c02SSascha Hauer drm_property_create_range(dev, 0, "hue", 0, 100); 1456a75f0236SFrancisco Jerez 1457f453ba04SDave Airlie return 0; 1458f453ba04SDave Airlie } 1459f453ba04SDave Airlie EXPORT_SYMBOL(drm_mode_create_tv_properties); 1460f453ba04SDave Airlie 1461f453ba04SDave Airlie /** 1462f453ba04SDave Airlie * drm_mode_create_scaling_mode_property - create scaling mode property 1463f453ba04SDave Airlie * @dev: DRM device 1464f453ba04SDave Airlie * 1465f453ba04SDave Airlie * Called by a driver the first time it's needed, must be attached to desired 1466f453ba04SDave Airlie * connectors. 1467f453ba04SDave Airlie */ 1468f453ba04SDave Airlie int drm_mode_create_scaling_mode_property(struct drm_device *dev) 1469f453ba04SDave Airlie { 1470f453ba04SDave Airlie struct drm_property *scaling_mode; 1471f453ba04SDave Airlie 1472f453ba04SDave Airlie if (dev->mode_config.scaling_mode_property) 1473f453ba04SDave Airlie return 0; 1474f453ba04SDave Airlie 1475f453ba04SDave Airlie scaling_mode = 14764a67d391SSascha Hauer drm_property_create_enum(dev, 0, "scaling mode", 14774a67d391SSascha Hauer drm_scaling_mode_enum_list, 1478f453ba04SDave Airlie ARRAY_SIZE(drm_scaling_mode_enum_list)); 1479f453ba04SDave Airlie 1480f453ba04SDave Airlie dev->mode_config.scaling_mode_property = scaling_mode; 1481f453ba04SDave Airlie 1482f453ba04SDave Airlie return 0; 1483f453ba04SDave Airlie } 1484f453ba04SDave Airlie EXPORT_SYMBOL(drm_mode_create_scaling_mode_property); 1485f453ba04SDave Airlie 1486f453ba04SDave Airlie /** 1487ff587e45SVandana Kannan * drm_mode_create_aspect_ratio_property - create aspect ratio property 1488ff587e45SVandana Kannan * @dev: DRM device 1489ff587e45SVandana Kannan * 1490ff587e45SVandana Kannan * Called by a driver the first time it's needed, must be attached to desired 1491ff587e45SVandana Kannan * connectors. 1492ff587e45SVandana Kannan * 1493ff587e45SVandana Kannan * Returns: 1494ff587e45SVandana Kannan * Zero on success, errno on failure. 1495ff587e45SVandana Kannan */ 1496ff587e45SVandana Kannan int drm_mode_create_aspect_ratio_property(struct drm_device *dev) 1497ff587e45SVandana Kannan { 1498ff587e45SVandana Kannan if (dev->mode_config.aspect_ratio_property) 1499ff587e45SVandana Kannan return 0; 1500ff587e45SVandana Kannan 1501ff587e45SVandana Kannan dev->mode_config.aspect_ratio_property = 1502ff587e45SVandana Kannan drm_property_create_enum(dev, 0, "aspect ratio", 1503ff587e45SVandana Kannan drm_aspect_ratio_enum_list, 1504ff587e45SVandana Kannan ARRAY_SIZE(drm_aspect_ratio_enum_list)); 1505ff587e45SVandana Kannan 1506ff587e45SVandana Kannan if (dev->mode_config.aspect_ratio_property == NULL) 1507ff587e45SVandana Kannan return -ENOMEM; 1508ff587e45SVandana Kannan 1509ff587e45SVandana Kannan return 0; 1510ff587e45SVandana Kannan } 1511ff587e45SVandana Kannan EXPORT_SYMBOL(drm_mode_create_aspect_ratio_property); 1512ff587e45SVandana Kannan 1513ff587e45SVandana Kannan /** 1514884840aaSJakob Bornecrantz * drm_mode_create_dirty_property - create dirty property 1515884840aaSJakob Bornecrantz * @dev: DRM device 1516884840aaSJakob Bornecrantz * 1517884840aaSJakob Bornecrantz * Called by a driver the first time it's needed, must be attached to desired 1518884840aaSJakob Bornecrantz * connectors. 1519884840aaSJakob Bornecrantz */ 1520884840aaSJakob Bornecrantz int drm_mode_create_dirty_info_property(struct drm_device *dev) 1521884840aaSJakob Bornecrantz { 1522884840aaSJakob Bornecrantz struct drm_property *dirty_info; 1523884840aaSJakob Bornecrantz 1524884840aaSJakob Bornecrantz if (dev->mode_config.dirty_info_property) 1525884840aaSJakob Bornecrantz return 0; 1526884840aaSJakob Bornecrantz 1527884840aaSJakob Bornecrantz dirty_info = 15284a67d391SSascha Hauer drm_property_create_enum(dev, DRM_MODE_PROP_IMMUTABLE, 1529884840aaSJakob Bornecrantz "dirty", 15304a67d391SSascha Hauer drm_dirty_info_enum_list, 1531884840aaSJakob Bornecrantz ARRAY_SIZE(drm_dirty_info_enum_list)); 1532884840aaSJakob Bornecrantz dev->mode_config.dirty_info_property = dirty_info; 1533884840aaSJakob Bornecrantz 1534884840aaSJakob Bornecrantz return 0; 1535884840aaSJakob Bornecrantz } 1536884840aaSJakob Bornecrantz EXPORT_SYMBOL(drm_mode_create_dirty_info_property); 1537884840aaSJakob Bornecrantz 1538ea9cbb06SVille Syrjälä static int drm_mode_group_init(struct drm_device *dev, struct drm_mode_group *group) 1539f453ba04SDave Airlie { 1540f453ba04SDave Airlie uint32_t total_objects = 0; 1541f453ba04SDave Airlie 1542f453ba04SDave Airlie total_objects += dev->mode_config.num_crtc; 1543f453ba04SDave Airlie total_objects += dev->mode_config.num_connector; 1544f453ba04SDave Airlie total_objects += dev->mode_config.num_encoder; 15453b336ec4SSean Paul total_objects += dev->mode_config.num_bridge; 1546f453ba04SDave Airlie 1547f453ba04SDave Airlie group->id_list = kzalloc(total_objects * sizeof(uint32_t), GFP_KERNEL); 1548f453ba04SDave Airlie if (!group->id_list) 1549f453ba04SDave Airlie return -ENOMEM; 1550f453ba04SDave Airlie 1551f453ba04SDave Airlie group->num_crtcs = 0; 1552f453ba04SDave Airlie group->num_connectors = 0; 1553f453ba04SDave Airlie group->num_encoders = 0; 15543b336ec4SSean Paul group->num_bridges = 0; 1555f453ba04SDave Airlie return 0; 1556f453ba04SDave Airlie } 1557f453ba04SDave Airlie 1558ad222799SDave Airlie void drm_mode_group_destroy(struct drm_mode_group *group) 1559ad222799SDave Airlie { 1560ad222799SDave Airlie kfree(group->id_list); 1561ad222799SDave Airlie group->id_list = NULL; 1562ad222799SDave Airlie } 1563ad222799SDave Airlie 1564c8e32cc1SDaniel Vetter /* 1565c8e32cc1SDaniel Vetter * NOTE: Driver's shouldn't ever call drm_mode_group_init_legacy_group - it is 1566c8e32cc1SDaniel Vetter * the drm core's responsibility to set up mode control groups. 1567c8e32cc1SDaniel Vetter */ 1568f453ba04SDave Airlie int drm_mode_group_init_legacy_group(struct drm_device *dev, 1569f453ba04SDave Airlie struct drm_mode_group *group) 1570f453ba04SDave Airlie { 1571f453ba04SDave Airlie struct drm_crtc *crtc; 1572f453ba04SDave Airlie struct drm_encoder *encoder; 1573f453ba04SDave Airlie struct drm_connector *connector; 15743b336ec4SSean Paul struct drm_bridge *bridge; 1575f453ba04SDave Airlie int ret; 1576f453ba04SDave Airlie 1577f453ba04SDave Airlie if ((ret = drm_mode_group_init(dev, group))) 1578f453ba04SDave Airlie return ret; 1579f453ba04SDave Airlie 1580f453ba04SDave Airlie list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) 1581f453ba04SDave Airlie group->id_list[group->num_crtcs++] = crtc->base.id; 1582f453ba04SDave Airlie 1583f453ba04SDave Airlie list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) 1584f453ba04SDave Airlie group->id_list[group->num_crtcs + group->num_encoders++] = 1585f453ba04SDave Airlie encoder->base.id; 1586f453ba04SDave Airlie 1587f453ba04SDave Airlie list_for_each_entry(connector, &dev->mode_config.connector_list, head) 1588f453ba04SDave Airlie group->id_list[group->num_crtcs + group->num_encoders + 1589f453ba04SDave Airlie group->num_connectors++] = connector->base.id; 1590f453ba04SDave Airlie 15913b336ec4SSean Paul list_for_each_entry(bridge, &dev->mode_config.bridge_list, head) 15923b336ec4SSean Paul group->id_list[group->num_crtcs + group->num_encoders + 15933b336ec4SSean Paul group->num_connectors + group->num_bridges++] = 15943b336ec4SSean Paul bridge->base.id; 15953b336ec4SSean Paul 1596f453ba04SDave Airlie return 0; 1597f453ba04SDave Airlie } 15989c1dfc55SDave Airlie EXPORT_SYMBOL(drm_mode_group_init_legacy_group); 1599f453ba04SDave Airlie 16002390cd11SDave Airlie void drm_reinit_primary_mode_group(struct drm_device *dev) 16012390cd11SDave Airlie { 16022390cd11SDave Airlie drm_modeset_lock_all(dev); 16032390cd11SDave Airlie drm_mode_group_destroy(&dev->primary->mode_group); 16042390cd11SDave Airlie drm_mode_group_init_legacy_group(dev, &dev->primary->mode_group); 16052390cd11SDave Airlie drm_modeset_unlock_all(dev); 16062390cd11SDave Airlie } 16072390cd11SDave Airlie EXPORT_SYMBOL(drm_reinit_primary_mode_group); 16082390cd11SDave Airlie 1609f453ba04SDave Airlie /** 1610f453ba04SDave Airlie * drm_crtc_convert_to_umode - convert a drm_display_mode into a modeinfo 1611f453ba04SDave Airlie * @out: drm_mode_modeinfo struct to return to the user 1612f453ba04SDave Airlie * @in: drm_display_mode to use 1613f453ba04SDave Airlie * 1614f453ba04SDave Airlie * Convert a drm_display_mode into a drm_mode_modeinfo structure to return to 1615f453ba04SDave Airlie * the user. 1616f453ba04SDave Airlie */ 161793bbf6dbSVille Syrjälä static void drm_crtc_convert_to_umode(struct drm_mode_modeinfo *out, 161893bbf6dbSVille Syrjälä const struct drm_display_mode *in) 1619f453ba04SDave Airlie { 1620e36fae38SVille Syrjälä WARN(in->hdisplay > USHRT_MAX || in->hsync_start > USHRT_MAX || 1621e36fae38SVille Syrjälä in->hsync_end > USHRT_MAX || in->htotal > USHRT_MAX || 1622e36fae38SVille Syrjälä in->hskew > USHRT_MAX || in->vdisplay > USHRT_MAX || 1623e36fae38SVille Syrjälä in->vsync_start > USHRT_MAX || in->vsync_end > USHRT_MAX || 1624e36fae38SVille Syrjälä in->vtotal > USHRT_MAX || in->vscan > USHRT_MAX, 1625e36fae38SVille Syrjälä "timing values too large for mode info\n"); 1626e36fae38SVille Syrjälä 1627f453ba04SDave Airlie out->clock = in->clock; 1628f453ba04SDave Airlie out->hdisplay = in->hdisplay; 1629f453ba04SDave Airlie out->hsync_start = in->hsync_start; 1630f453ba04SDave Airlie out->hsync_end = in->hsync_end; 1631f453ba04SDave Airlie out->htotal = in->htotal; 1632f453ba04SDave Airlie out->hskew = in->hskew; 1633f453ba04SDave Airlie out->vdisplay = in->vdisplay; 1634f453ba04SDave Airlie out->vsync_start = in->vsync_start; 1635f453ba04SDave Airlie out->vsync_end = in->vsync_end; 1636f453ba04SDave Airlie out->vtotal = in->vtotal; 1637f453ba04SDave Airlie out->vscan = in->vscan; 1638f453ba04SDave Airlie out->vrefresh = in->vrefresh; 1639f453ba04SDave Airlie out->flags = in->flags; 1640f453ba04SDave Airlie out->type = in->type; 1641f453ba04SDave Airlie strncpy(out->name, in->name, DRM_DISPLAY_MODE_LEN); 1642f453ba04SDave Airlie out->name[DRM_DISPLAY_MODE_LEN-1] = 0; 1643f453ba04SDave Airlie } 1644f453ba04SDave Airlie 1645f453ba04SDave Airlie /** 164674afee7dSMarc-André Lureau * drm_crtc_convert_umode - convert a modeinfo into a drm_display_mode 1647f453ba04SDave Airlie * @out: drm_display_mode to return to the user 1648f453ba04SDave Airlie * @in: drm_mode_modeinfo to use 1649f453ba04SDave Airlie * 1650f453ba04SDave Airlie * Convert a drm_mode_modeinfo into a drm_display_mode structure to return to 1651f453ba04SDave Airlie * the caller. 165290367bf6SVille Syrjälä * 1653c8e32cc1SDaniel Vetter * Returns: 165490367bf6SVille Syrjälä * Zero on success, errno on failure. 1655f453ba04SDave Airlie */ 165693bbf6dbSVille Syrjälä static int drm_crtc_convert_umode(struct drm_display_mode *out, 165793bbf6dbSVille Syrjälä const struct drm_mode_modeinfo *in) 1658f453ba04SDave Airlie { 165990367bf6SVille Syrjälä if (in->clock > INT_MAX || in->vrefresh > INT_MAX) 166090367bf6SVille Syrjälä return -ERANGE; 166190367bf6SVille Syrjälä 16625848ad40SDamien Lespiau if ((in->flags & DRM_MODE_FLAG_3D_MASK) > DRM_MODE_FLAG_3D_MAX) 16635848ad40SDamien Lespiau return -EINVAL; 16645848ad40SDamien Lespiau 1665f453ba04SDave Airlie out->clock = in->clock; 1666f453ba04SDave Airlie out->hdisplay = in->hdisplay; 1667f453ba04SDave Airlie out->hsync_start = in->hsync_start; 1668f453ba04SDave Airlie out->hsync_end = in->hsync_end; 1669f453ba04SDave Airlie out->htotal = in->htotal; 1670f453ba04SDave Airlie out->hskew = in->hskew; 1671f453ba04SDave Airlie out->vdisplay = in->vdisplay; 1672f453ba04SDave Airlie out->vsync_start = in->vsync_start; 1673f453ba04SDave Airlie out->vsync_end = in->vsync_end; 1674f453ba04SDave Airlie out->vtotal = in->vtotal; 1675f453ba04SDave Airlie out->vscan = in->vscan; 1676f453ba04SDave Airlie out->vrefresh = in->vrefresh; 1677f453ba04SDave Airlie out->flags = in->flags; 1678f453ba04SDave Airlie out->type = in->type; 1679f453ba04SDave Airlie strncpy(out->name, in->name, DRM_DISPLAY_MODE_LEN); 1680f453ba04SDave Airlie out->name[DRM_DISPLAY_MODE_LEN-1] = 0; 168190367bf6SVille Syrjälä 168290367bf6SVille Syrjälä return 0; 1683f453ba04SDave Airlie } 1684f453ba04SDave Airlie 1685f453ba04SDave Airlie /** 1686f453ba04SDave Airlie * drm_mode_getresources - get graphics configuration 1687065a50edSDaniel Vetter * @dev: drm device for the ioctl 1688065a50edSDaniel Vetter * @data: data pointer for the ioctl 1689065a50edSDaniel Vetter * @file_priv: drm file for the ioctl call 1690f453ba04SDave Airlie * 1691f453ba04SDave Airlie * Construct a set of configuration description structures and return 1692f453ba04SDave Airlie * them to the user, including CRTC, connector and framebuffer configuration. 1693f453ba04SDave Airlie * 1694f453ba04SDave Airlie * Called by the user via ioctl. 1695f453ba04SDave Airlie * 1696c8e32cc1SDaniel Vetter * Returns: 1697f453ba04SDave Airlie * Zero on success, errno on failure. 1698f453ba04SDave Airlie */ 1699f453ba04SDave Airlie int drm_mode_getresources(struct drm_device *dev, void *data, 1700f453ba04SDave Airlie struct drm_file *file_priv) 1701f453ba04SDave Airlie { 1702f453ba04SDave Airlie struct drm_mode_card_res *card_res = data; 1703f453ba04SDave Airlie struct list_head *lh; 1704f453ba04SDave Airlie struct drm_framebuffer *fb; 1705f453ba04SDave Airlie struct drm_connector *connector; 1706f453ba04SDave Airlie struct drm_crtc *crtc; 1707f453ba04SDave Airlie struct drm_encoder *encoder; 1708f453ba04SDave Airlie int ret = 0; 1709f453ba04SDave Airlie int connector_count = 0; 1710f453ba04SDave Airlie int crtc_count = 0; 1711f453ba04SDave Airlie int fb_count = 0; 1712f453ba04SDave Airlie int encoder_count = 0; 1713f453ba04SDave Airlie int copied = 0, i; 1714f453ba04SDave Airlie uint32_t __user *fb_id; 1715f453ba04SDave Airlie uint32_t __user *crtc_id; 1716f453ba04SDave Airlie uint32_t __user *connector_id; 1717f453ba04SDave Airlie uint32_t __user *encoder_id; 1718f453ba04SDave Airlie struct drm_mode_group *mode_group; 1719f453ba04SDave Airlie 1720fb3b06c8SDave Airlie if (!drm_core_check_feature(dev, DRIVER_MODESET)) 1721fb3b06c8SDave Airlie return -EINVAL; 1722fb3b06c8SDave Airlie 1723f453ba04SDave Airlie 17244b096ac1SDaniel Vetter mutex_lock(&file_priv->fbs_lock); 1725f453ba04SDave Airlie /* 1726f453ba04SDave Airlie * For the non-control nodes we need to limit the list of resources 1727f453ba04SDave Airlie * by IDs in the group list for this node 1728f453ba04SDave Airlie */ 1729f453ba04SDave Airlie list_for_each(lh, &file_priv->fbs) 1730f453ba04SDave Airlie fb_count++; 1731f453ba04SDave Airlie 17324b096ac1SDaniel Vetter /* handle this in 4 parts */ 17334b096ac1SDaniel Vetter /* FBs */ 17344b096ac1SDaniel Vetter if (card_res->count_fbs >= fb_count) { 17354b096ac1SDaniel Vetter copied = 0; 17364b096ac1SDaniel Vetter fb_id = (uint32_t __user *)(unsigned long)card_res->fb_id_ptr; 17374b096ac1SDaniel Vetter list_for_each_entry(fb, &file_priv->fbs, filp_head) { 17384b096ac1SDaniel Vetter if (put_user(fb->base.id, fb_id + copied)) { 17394b096ac1SDaniel Vetter mutex_unlock(&file_priv->fbs_lock); 17404b096ac1SDaniel Vetter return -EFAULT; 17414b096ac1SDaniel Vetter } 17424b096ac1SDaniel Vetter copied++; 17434b096ac1SDaniel Vetter } 17444b096ac1SDaniel Vetter } 17454b096ac1SDaniel Vetter card_res->count_fbs = fb_count; 17464b096ac1SDaniel Vetter mutex_unlock(&file_priv->fbs_lock); 17474b096ac1SDaniel Vetter 17484b096ac1SDaniel Vetter drm_modeset_lock_all(dev); 174943683057SThomas Hellstrom if (!drm_is_primary_client(file_priv)) { 1750f453ba04SDave Airlie 175109f308f7SThomas Hellstrom mode_group = NULL; 1752f453ba04SDave Airlie list_for_each(lh, &dev->mode_config.crtc_list) 1753f453ba04SDave Airlie crtc_count++; 1754f453ba04SDave Airlie 1755f453ba04SDave Airlie list_for_each(lh, &dev->mode_config.connector_list) 1756f453ba04SDave Airlie connector_count++; 1757f453ba04SDave Airlie 1758f453ba04SDave Airlie list_for_each(lh, &dev->mode_config.encoder_list) 1759f453ba04SDave Airlie encoder_count++; 1760f453ba04SDave Airlie } else { 1761f453ba04SDave Airlie 176209f308f7SThomas Hellstrom mode_group = &file_priv->master->minor->mode_group; 1763f453ba04SDave Airlie crtc_count = mode_group->num_crtcs; 1764f453ba04SDave Airlie connector_count = mode_group->num_connectors; 1765f453ba04SDave Airlie encoder_count = mode_group->num_encoders; 1766f453ba04SDave Airlie } 1767f453ba04SDave Airlie 1768f453ba04SDave Airlie card_res->max_height = dev->mode_config.max_height; 1769f453ba04SDave Airlie card_res->min_height = dev->mode_config.min_height; 1770f453ba04SDave Airlie card_res->max_width = dev->mode_config.max_width; 1771f453ba04SDave Airlie card_res->min_width = dev->mode_config.min_width; 1772f453ba04SDave Airlie 1773f453ba04SDave Airlie /* CRTCs */ 1774f453ba04SDave Airlie if (card_res->count_crtcs >= crtc_count) { 1775f453ba04SDave Airlie copied = 0; 1776f453ba04SDave Airlie crtc_id = (uint32_t __user *)(unsigned long)card_res->crtc_id_ptr; 177709f308f7SThomas Hellstrom if (!mode_group) { 1778f453ba04SDave Airlie list_for_each_entry(crtc, &dev->mode_config.crtc_list, 1779f453ba04SDave Airlie head) { 17809440106bSJerome Glisse DRM_DEBUG_KMS("[CRTC:%d]\n", crtc->base.id); 1781f453ba04SDave Airlie if (put_user(crtc->base.id, crtc_id + copied)) { 1782f453ba04SDave Airlie ret = -EFAULT; 1783f453ba04SDave Airlie goto out; 1784f453ba04SDave Airlie } 1785f453ba04SDave Airlie copied++; 1786f453ba04SDave Airlie } 1787f453ba04SDave Airlie } else { 1788f453ba04SDave Airlie for (i = 0; i < mode_group->num_crtcs; i++) { 1789f453ba04SDave Airlie if (put_user(mode_group->id_list[i], 1790f453ba04SDave Airlie crtc_id + copied)) { 1791f453ba04SDave Airlie ret = -EFAULT; 1792f453ba04SDave Airlie goto out; 1793f453ba04SDave Airlie } 1794f453ba04SDave Airlie copied++; 1795f453ba04SDave Airlie } 1796f453ba04SDave Airlie } 1797f453ba04SDave Airlie } 1798f453ba04SDave Airlie card_res->count_crtcs = crtc_count; 1799f453ba04SDave Airlie 1800f453ba04SDave Airlie /* Encoders */ 1801f453ba04SDave Airlie if (card_res->count_encoders >= encoder_count) { 1802f453ba04SDave Airlie copied = 0; 1803f453ba04SDave Airlie encoder_id = (uint32_t __user *)(unsigned long)card_res->encoder_id_ptr; 180409f308f7SThomas Hellstrom if (!mode_group) { 1805f453ba04SDave Airlie list_for_each_entry(encoder, 1806f453ba04SDave Airlie &dev->mode_config.encoder_list, 1807f453ba04SDave Airlie head) { 18089440106bSJerome Glisse DRM_DEBUG_KMS("[ENCODER:%d:%s]\n", encoder->base.id, 180983a8cfd3SJani Nikula encoder->name); 1810f453ba04SDave Airlie if (put_user(encoder->base.id, encoder_id + 1811f453ba04SDave Airlie copied)) { 1812f453ba04SDave Airlie ret = -EFAULT; 1813f453ba04SDave Airlie goto out; 1814f453ba04SDave Airlie } 1815f453ba04SDave Airlie copied++; 1816f453ba04SDave Airlie } 1817f453ba04SDave Airlie } else { 1818f453ba04SDave Airlie for (i = mode_group->num_crtcs; i < mode_group->num_crtcs + mode_group->num_encoders; i++) { 1819f453ba04SDave Airlie if (put_user(mode_group->id_list[i], 1820f453ba04SDave Airlie encoder_id + copied)) { 1821f453ba04SDave Airlie ret = -EFAULT; 1822f453ba04SDave Airlie goto out; 1823f453ba04SDave Airlie } 1824f453ba04SDave Airlie copied++; 1825f453ba04SDave Airlie } 1826f453ba04SDave Airlie 1827f453ba04SDave Airlie } 1828f453ba04SDave Airlie } 1829f453ba04SDave Airlie card_res->count_encoders = encoder_count; 1830f453ba04SDave Airlie 1831f453ba04SDave Airlie /* Connectors */ 1832f453ba04SDave Airlie if (card_res->count_connectors >= connector_count) { 1833f453ba04SDave Airlie copied = 0; 1834f453ba04SDave Airlie connector_id = (uint32_t __user *)(unsigned long)card_res->connector_id_ptr; 183509f308f7SThomas Hellstrom if (!mode_group) { 1836f453ba04SDave Airlie list_for_each_entry(connector, 1837f453ba04SDave Airlie &dev->mode_config.connector_list, 1838f453ba04SDave Airlie head) { 18399440106bSJerome Glisse DRM_DEBUG_KMS("[CONNECTOR:%d:%s]\n", 18409440106bSJerome Glisse connector->base.id, 184125933820SJani Nikula connector->name); 1842f453ba04SDave Airlie if (put_user(connector->base.id, 1843f453ba04SDave Airlie connector_id + copied)) { 1844f453ba04SDave Airlie ret = -EFAULT; 1845f453ba04SDave Airlie goto out; 1846f453ba04SDave Airlie } 1847f453ba04SDave Airlie copied++; 1848f453ba04SDave Airlie } 1849f453ba04SDave Airlie } else { 1850f453ba04SDave Airlie int start = mode_group->num_crtcs + 1851f453ba04SDave Airlie mode_group->num_encoders; 1852f453ba04SDave Airlie for (i = start; i < start + mode_group->num_connectors; i++) { 1853f453ba04SDave Airlie if (put_user(mode_group->id_list[i], 1854f453ba04SDave Airlie connector_id + copied)) { 1855f453ba04SDave Airlie ret = -EFAULT; 1856f453ba04SDave Airlie goto out; 1857f453ba04SDave Airlie } 1858f453ba04SDave Airlie copied++; 1859f453ba04SDave Airlie } 1860f453ba04SDave Airlie } 1861f453ba04SDave Airlie } 1862f453ba04SDave Airlie card_res->count_connectors = connector_count; 1863f453ba04SDave Airlie 18649440106bSJerome Glisse DRM_DEBUG_KMS("CRTC[%d] CONNECTORS[%d] ENCODERS[%d]\n", card_res->count_crtcs, 1865f453ba04SDave Airlie card_res->count_connectors, card_res->count_encoders); 1866f453ba04SDave Airlie 1867f453ba04SDave Airlie out: 186884849903SDaniel Vetter drm_modeset_unlock_all(dev); 1869f453ba04SDave Airlie return ret; 1870f453ba04SDave Airlie } 1871f453ba04SDave Airlie 1872f453ba04SDave Airlie /** 1873f453ba04SDave Airlie * drm_mode_getcrtc - get CRTC configuration 1874065a50edSDaniel Vetter * @dev: drm device for the ioctl 1875065a50edSDaniel Vetter * @data: data pointer for the ioctl 1876065a50edSDaniel Vetter * @file_priv: drm file for the ioctl call 1877f453ba04SDave Airlie * 1878f453ba04SDave Airlie * Construct a CRTC configuration structure to return to the user. 1879f453ba04SDave Airlie * 1880f453ba04SDave Airlie * Called by the user via ioctl. 1881f453ba04SDave Airlie * 1882c8e32cc1SDaniel Vetter * Returns: 1883f453ba04SDave Airlie * Zero on success, errno on failure. 1884f453ba04SDave Airlie */ 1885f453ba04SDave Airlie int drm_mode_getcrtc(struct drm_device *dev, 1886f453ba04SDave Airlie void *data, struct drm_file *file_priv) 1887f453ba04SDave Airlie { 1888f453ba04SDave Airlie struct drm_mode_crtc *crtc_resp = data; 1889f453ba04SDave Airlie struct drm_crtc *crtc; 1890f453ba04SDave Airlie int ret = 0; 1891f453ba04SDave Airlie 1892fb3b06c8SDave Airlie if (!drm_core_check_feature(dev, DRIVER_MODESET)) 1893fb3b06c8SDave Airlie return -EINVAL; 1894fb3b06c8SDave Airlie 189584849903SDaniel Vetter drm_modeset_lock_all(dev); 1896f453ba04SDave Airlie 1897a2b34e22SRob Clark crtc = drm_crtc_find(dev, crtc_resp->crtc_id); 1898a2b34e22SRob Clark if (!crtc) { 1899f27657f2SVille Syrjälä ret = -ENOENT; 1900f453ba04SDave Airlie goto out; 1901f453ba04SDave Airlie } 1902f453ba04SDave Airlie 1903f453ba04SDave Airlie crtc_resp->x = crtc->x; 1904f453ba04SDave Airlie crtc_resp->y = crtc->y; 1905f453ba04SDave Airlie crtc_resp->gamma_size = crtc->gamma_size; 1906f4510a27SMatt Roper if (crtc->primary->fb) 1907f4510a27SMatt Roper crtc_resp->fb_id = crtc->primary->fb->base.id; 1908f453ba04SDave Airlie else 1909f453ba04SDave Airlie crtc_resp->fb_id = 0; 1910f453ba04SDave Airlie 1911f453ba04SDave Airlie if (crtc->enabled) { 1912f453ba04SDave Airlie 1913f453ba04SDave Airlie drm_crtc_convert_to_umode(&crtc_resp->mode, &crtc->mode); 1914f453ba04SDave Airlie crtc_resp->mode_valid = 1; 1915f453ba04SDave Airlie 1916f453ba04SDave Airlie } else { 1917f453ba04SDave Airlie crtc_resp->mode_valid = 0; 1918f453ba04SDave Airlie } 1919f453ba04SDave Airlie 1920f453ba04SDave Airlie out: 192184849903SDaniel Vetter drm_modeset_unlock_all(dev); 1922f453ba04SDave Airlie return ret; 1923f453ba04SDave Airlie } 1924f453ba04SDave Airlie 192561d8e328SDamien Lespiau static bool drm_mode_expose_to_userspace(const struct drm_display_mode *mode, 192661d8e328SDamien Lespiau const struct drm_file *file_priv) 192761d8e328SDamien Lespiau { 192861d8e328SDamien Lespiau /* 192961d8e328SDamien Lespiau * If user-space hasn't configured the driver to expose the stereo 3D 193061d8e328SDamien Lespiau * modes, don't expose them. 193161d8e328SDamien Lespiau */ 193261d8e328SDamien Lespiau if (!file_priv->stereo_allowed && drm_mode_is_stereo(mode)) 193361d8e328SDamien Lespiau return false; 193461d8e328SDamien Lespiau 193561d8e328SDamien Lespiau return true; 193661d8e328SDamien Lespiau } 193761d8e328SDamien Lespiau 1938f453ba04SDave Airlie /** 1939f453ba04SDave Airlie * drm_mode_getconnector - get connector configuration 1940065a50edSDaniel Vetter * @dev: drm device for the ioctl 1941065a50edSDaniel Vetter * @data: data pointer for the ioctl 1942065a50edSDaniel Vetter * @file_priv: drm file for the ioctl call 1943f453ba04SDave Airlie * 1944f453ba04SDave Airlie * Construct a connector configuration structure to return to the user. 1945f453ba04SDave Airlie * 1946f453ba04SDave Airlie * Called by the user via ioctl. 1947f453ba04SDave Airlie * 1948c8e32cc1SDaniel Vetter * Returns: 1949f453ba04SDave Airlie * Zero on success, errno on failure. 1950f453ba04SDave Airlie */ 1951f453ba04SDave Airlie int drm_mode_getconnector(struct drm_device *dev, void *data, 1952f453ba04SDave Airlie struct drm_file *file_priv) 1953f453ba04SDave Airlie { 1954f453ba04SDave Airlie struct drm_mode_get_connector *out_resp = data; 1955f453ba04SDave Airlie struct drm_connector *connector; 1956f453ba04SDave Airlie struct drm_display_mode *mode; 1957f453ba04SDave Airlie int mode_count = 0; 1958f453ba04SDave Airlie int props_count = 0; 1959f453ba04SDave Airlie int encoders_count = 0; 1960f453ba04SDave Airlie int ret = 0; 1961f453ba04SDave Airlie int copied = 0; 1962f453ba04SDave Airlie int i; 1963f453ba04SDave Airlie struct drm_mode_modeinfo u_mode; 1964f453ba04SDave Airlie struct drm_mode_modeinfo __user *mode_ptr; 1965f453ba04SDave Airlie uint32_t __user *prop_ptr; 1966f453ba04SDave Airlie uint64_t __user *prop_values; 1967f453ba04SDave Airlie uint32_t __user *encoder_ptr; 1968f453ba04SDave Airlie 1969fb3b06c8SDave Airlie if (!drm_core_check_feature(dev, DRIVER_MODESET)) 1970fb3b06c8SDave Airlie return -EINVAL; 1971fb3b06c8SDave Airlie 1972f453ba04SDave Airlie memset(&u_mode, 0, sizeof(struct drm_mode_modeinfo)); 1973f453ba04SDave Airlie 19749440106bSJerome Glisse DRM_DEBUG_KMS("[CONNECTOR:%d:?]\n", out_resp->connector_id); 1975f453ba04SDave Airlie 19767b24056bSDaniel Vetter mutex_lock(&dev->mode_config.mutex); 1977f453ba04SDave Airlie 1978a2b34e22SRob Clark connector = drm_connector_find(dev, out_resp->connector_id); 1979a2b34e22SRob Clark if (!connector) { 1980f27657f2SVille Syrjälä ret = -ENOENT; 1981f453ba04SDave Airlie goto out; 1982f453ba04SDave Airlie } 1983f453ba04SDave Airlie 19847f88a9beSPaulo Zanoni props_count = connector->properties.count; 1985f453ba04SDave Airlie 1986f453ba04SDave Airlie for (i = 0; i < DRM_CONNECTOR_MAX_ENCODER; i++) { 1987f453ba04SDave Airlie if (connector->encoder_ids[i] != 0) { 1988f453ba04SDave Airlie encoders_count++; 1989f453ba04SDave Airlie } 1990f453ba04SDave Airlie } 1991f453ba04SDave Airlie 1992f453ba04SDave Airlie if (out_resp->count_modes == 0) { 1993f453ba04SDave Airlie connector->funcs->fill_modes(connector, 1994f453ba04SDave Airlie dev->mode_config.max_width, 1995f453ba04SDave Airlie dev->mode_config.max_height); 1996f453ba04SDave Airlie } 1997f453ba04SDave Airlie 1998f453ba04SDave Airlie /* delayed so we get modes regardless of pre-fill_modes state */ 1999f453ba04SDave Airlie list_for_each_entry(mode, &connector->modes, head) 200061d8e328SDamien Lespiau if (drm_mode_expose_to_userspace(mode, file_priv)) 2001f453ba04SDave Airlie mode_count++; 2002f453ba04SDave Airlie 2003f453ba04SDave Airlie out_resp->connector_id = connector->base.id; 2004f453ba04SDave Airlie out_resp->connector_type = connector->connector_type; 2005f453ba04SDave Airlie out_resp->connector_type_id = connector->connector_type_id; 2006f453ba04SDave Airlie out_resp->mm_width = connector->display_info.width_mm; 2007f453ba04SDave Airlie out_resp->mm_height = connector->display_info.height_mm; 2008f453ba04SDave Airlie out_resp->subpixel = connector->display_info.subpixel_order; 2009f453ba04SDave Airlie out_resp->connection = connector->status; 2010832fd395SDaniel Vetter drm_modeset_lock(&dev->mode_config.connection_mutex, NULL); 2011f453ba04SDave Airlie if (connector->encoder) 2012f453ba04SDave Airlie out_resp->encoder_id = connector->encoder->base.id; 2013f453ba04SDave Airlie else 2014f453ba04SDave Airlie out_resp->encoder_id = 0; 2015832fd395SDaniel Vetter drm_modeset_unlock(&dev->mode_config.connection_mutex); 2016f453ba04SDave Airlie 2017f453ba04SDave Airlie /* 2018f453ba04SDave Airlie * This ioctl is called twice, once to determine how much space is 2019f453ba04SDave Airlie * needed, and the 2nd time to fill it. 2020f453ba04SDave Airlie */ 2021f453ba04SDave Airlie if ((out_resp->count_modes >= mode_count) && mode_count) { 2022f453ba04SDave Airlie copied = 0; 202381f6c7f8SVille Syrjälä mode_ptr = (struct drm_mode_modeinfo __user *)(unsigned long)out_resp->modes_ptr; 2024f453ba04SDave Airlie list_for_each_entry(mode, &connector->modes, head) { 202561d8e328SDamien Lespiau if (!drm_mode_expose_to_userspace(mode, file_priv)) 202661d8e328SDamien Lespiau continue; 202761d8e328SDamien Lespiau 2028f453ba04SDave Airlie drm_crtc_convert_to_umode(&u_mode, mode); 2029f453ba04SDave Airlie if (copy_to_user(mode_ptr + copied, 2030f453ba04SDave Airlie &u_mode, sizeof(u_mode))) { 2031f453ba04SDave Airlie ret = -EFAULT; 2032f453ba04SDave Airlie goto out; 2033f453ba04SDave Airlie } 2034f453ba04SDave Airlie copied++; 2035f453ba04SDave Airlie } 2036f453ba04SDave Airlie } 2037f453ba04SDave Airlie out_resp->count_modes = mode_count; 2038f453ba04SDave Airlie 2039f453ba04SDave Airlie if ((out_resp->count_props >= props_count) && props_count) { 2040f453ba04SDave Airlie copied = 0; 204181f6c7f8SVille Syrjälä prop_ptr = (uint32_t __user *)(unsigned long)(out_resp->props_ptr); 204281f6c7f8SVille Syrjälä prop_values = (uint64_t __user *)(unsigned long)(out_resp->prop_values_ptr); 20437f88a9beSPaulo Zanoni for (i = 0; i < connector->properties.count; i++) { 20447e3bdf4aSPaulo Zanoni if (put_user(connector->properties.ids[i], 2045f453ba04SDave Airlie prop_ptr + copied)) { 2046f453ba04SDave Airlie ret = -EFAULT; 2047f453ba04SDave Airlie goto out; 2048f453ba04SDave Airlie } 2049f453ba04SDave Airlie 20507e3bdf4aSPaulo Zanoni if (put_user(connector->properties.values[i], 2051f453ba04SDave Airlie prop_values + copied)) { 2052f453ba04SDave Airlie ret = -EFAULT; 2053f453ba04SDave Airlie goto out; 2054f453ba04SDave Airlie } 2055f453ba04SDave Airlie copied++; 2056f453ba04SDave Airlie } 2057f453ba04SDave Airlie } 2058f453ba04SDave Airlie out_resp->count_props = props_count; 2059f453ba04SDave Airlie 2060f453ba04SDave Airlie if ((out_resp->count_encoders >= encoders_count) && encoders_count) { 2061f453ba04SDave Airlie copied = 0; 206281f6c7f8SVille Syrjälä encoder_ptr = (uint32_t __user *)(unsigned long)(out_resp->encoders_ptr); 2063f453ba04SDave Airlie for (i = 0; i < DRM_CONNECTOR_MAX_ENCODER; i++) { 2064f453ba04SDave Airlie if (connector->encoder_ids[i] != 0) { 2065f453ba04SDave Airlie if (put_user(connector->encoder_ids[i], 2066f453ba04SDave Airlie encoder_ptr + copied)) { 2067f453ba04SDave Airlie ret = -EFAULT; 2068f453ba04SDave Airlie goto out; 2069f453ba04SDave Airlie } 2070f453ba04SDave Airlie copied++; 2071f453ba04SDave Airlie } 2072f453ba04SDave Airlie } 2073f453ba04SDave Airlie } 2074f453ba04SDave Airlie out_resp->count_encoders = encoders_count; 2075f453ba04SDave Airlie 2076f453ba04SDave Airlie out: 20777b24056bSDaniel Vetter mutex_unlock(&dev->mode_config.mutex); 20787b24056bSDaniel Vetter 2079f453ba04SDave Airlie return ret; 2080f453ba04SDave Airlie } 2081f453ba04SDave Airlie 2082c8e32cc1SDaniel Vetter /** 2083c8e32cc1SDaniel Vetter * drm_mode_getencoder - get encoder configuration 2084c8e32cc1SDaniel Vetter * @dev: drm device for the ioctl 2085c8e32cc1SDaniel Vetter * @data: data pointer for the ioctl 2086c8e32cc1SDaniel Vetter * @file_priv: drm file for the ioctl call 2087c8e32cc1SDaniel Vetter * 2088c8e32cc1SDaniel Vetter * Construct a encoder configuration structure to return to the user. 2089c8e32cc1SDaniel Vetter * 2090c8e32cc1SDaniel Vetter * Called by the user via ioctl. 2091c8e32cc1SDaniel Vetter * 2092c8e32cc1SDaniel Vetter * Returns: 2093c8e32cc1SDaniel Vetter * Zero on success, errno on failure. 2094c8e32cc1SDaniel Vetter */ 2095f453ba04SDave Airlie int drm_mode_getencoder(struct drm_device *dev, void *data, 2096f453ba04SDave Airlie struct drm_file *file_priv) 2097f453ba04SDave Airlie { 2098f453ba04SDave Airlie struct drm_mode_get_encoder *enc_resp = data; 2099f453ba04SDave Airlie struct drm_encoder *encoder; 2100f453ba04SDave Airlie int ret = 0; 2101f453ba04SDave Airlie 2102fb3b06c8SDave Airlie if (!drm_core_check_feature(dev, DRIVER_MODESET)) 2103fb3b06c8SDave Airlie return -EINVAL; 2104fb3b06c8SDave Airlie 210584849903SDaniel Vetter drm_modeset_lock_all(dev); 2106a2b34e22SRob Clark encoder = drm_encoder_find(dev, enc_resp->encoder_id); 2107a2b34e22SRob Clark if (!encoder) { 2108f27657f2SVille Syrjälä ret = -ENOENT; 2109f453ba04SDave Airlie goto out; 2110f453ba04SDave Airlie } 2111f453ba04SDave Airlie 2112f453ba04SDave Airlie if (encoder->crtc) 2113f453ba04SDave Airlie enc_resp->crtc_id = encoder->crtc->base.id; 2114f453ba04SDave Airlie else 2115f453ba04SDave Airlie enc_resp->crtc_id = 0; 2116f453ba04SDave Airlie enc_resp->encoder_type = encoder->encoder_type; 2117f453ba04SDave Airlie enc_resp->encoder_id = encoder->base.id; 2118f453ba04SDave Airlie enc_resp->possible_crtcs = encoder->possible_crtcs; 2119f453ba04SDave Airlie enc_resp->possible_clones = encoder->possible_clones; 2120f453ba04SDave Airlie 2121f453ba04SDave Airlie out: 212284849903SDaniel Vetter drm_modeset_unlock_all(dev); 2123f453ba04SDave Airlie return ret; 2124f453ba04SDave Airlie } 2125f453ba04SDave Airlie 2126f453ba04SDave Airlie /** 2127c8e32cc1SDaniel Vetter * drm_mode_getplane_res - enumerate all plane resources 21288cf5c917SJesse Barnes * @dev: DRM device 21298cf5c917SJesse Barnes * @data: ioctl data 21308cf5c917SJesse Barnes * @file_priv: DRM file info 21318cf5c917SJesse Barnes * 2132c8e32cc1SDaniel Vetter * Construct a list of plane ids to return to the user. 2133c8e32cc1SDaniel Vetter * 2134c8e32cc1SDaniel Vetter * Called by the user via ioctl. 2135c8e32cc1SDaniel Vetter * 2136c8e32cc1SDaniel Vetter * Returns: 2137c8e32cc1SDaniel Vetter * Zero on success, errno on failure. 21388cf5c917SJesse Barnes */ 21398cf5c917SJesse Barnes int drm_mode_getplane_res(struct drm_device *dev, void *data, 21408cf5c917SJesse Barnes struct drm_file *file_priv) 21418cf5c917SJesse Barnes { 21428cf5c917SJesse Barnes struct drm_mode_get_plane_res *plane_resp = data; 21438cf5c917SJesse Barnes struct drm_mode_config *config; 21448cf5c917SJesse Barnes struct drm_plane *plane; 21458cf5c917SJesse Barnes uint32_t __user *plane_ptr; 21468cf5c917SJesse Barnes int copied = 0, ret = 0; 2147681e7ec7SMatt Roper unsigned num_planes; 21488cf5c917SJesse Barnes 21498cf5c917SJesse Barnes if (!drm_core_check_feature(dev, DRIVER_MODESET)) 21508cf5c917SJesse Barnes return -EINVAL; 21518cf5c917SJesse Barnes 215284849903SDaniel Vetter drm_modeset_lock_all(dev); 21538cf5c917SJesse Barnes config = &dev->mode_config; 21548cf5c917SJesse Barnes 2155681e7ec7SMatt Roper if (file_priv->universal_planes) 2156681e7ec7SMatt Roper num_planes = config->num_total_plane; 2157681e7ec7SMatt Roper else 2158681e7ec7SMatt Roper num_planes = config->num_overlay_plane; 2159681e7ec7SMatt Roper 21608cf5c917SJesse Barnes /* 21618cf5c917SJesse Barnes * This ioctl is called twice, once to determine how much space is 21628cf5c917SJesse Barnes * needed, and the 2nd time to fill it. 21638cf5c917SJesse Barnes */ 2164681e7ec7SMatt Roper if (num_planes && 2165681e7ec7SMatt Roper (plane_resp->count_planes >= num_planes)) { 216681f6c7f8SVille Syrjälä plane_ptr = (uint32_t __user *)(unsigned long)plane_resp->plane_id_ptr; 21678cf5c917SJesse Barnes 21688cf5c917SJesse Barnes list_for_each_entry(plane, &config->plane_list, head) { 2169681e7ec7SMatt Roper /* 2170681e7ec7SMatt Roper * Unless userspace set the 'universal planes' 2171681e7ec7SMatt Roper * capability bit, only advertise overlays. 2172681e7ec7SMatt Roper */ 2173681e7ec7SMatt Roper if (plane->type != DRM_PLANE_TYPE_OVERLAY && 2174681e7ec7SMatt Roper !file_priv->universal_planes) 2175e27dde3eSMatt Roper continue; 2176e27dde3eSMatt Roper 21778cf5c917SJesse Barnes if (put_user(plane->base.id, plane_ptr + copied)) { 21788cf5c917SJesse Barnes ret = -EFAULT; 21798cf5c917SJesse Barnes goto out; 21808cf5c917SJesse Barnes } 21818cf5c917SJesse Barnes copied++; 21828cf5c917SJesse Barnes } 21838cf5c917SJesse Barnes } 2184681e7ec7SMatt Roper plane_resp->count_planes = num_planes; 21858cf5c917SJesse Barnes 21868cf5c917SJesse Barnes out: 218784849903SDaniel Vetter drm_modeset_unlock_all(dev); 21888cf5c917SJesse Barnes return ret; 21898cf5c917SJesse Barnes } 21908cf5c917SJesse Barnes 21918cf5c917SJesse Barnes /** 2192c8e32cc1SDaniel Vetter * drm_mode_getplane - get plane configuration 21938cf5c917SJesse Barnes * @dev: DRM device 21948cf5c917SJesse Barnes * @data: ioctl data 21958cf5c917SJesse Barnes * @file_priv: DRM file info 21968cf5c917SJesse Barnes * 2197c8e32cc1SDaniel Vetter * Construct a plane configuration structure to return to the user. 2198c8e32cc1SDaniel Vetter * 2199c8e32cc1SDaniel Vetter * Called by the user via ioctl. 2200c8e32cc1SDaniel Vetter * 2201c8e32cc1SDaniel Vetter * Returns: 2202c8e32cc1SDaniel Vetter * Zero on success, errno on failure. 22038cf5c917SJesse Barnes */ 22048cf5c917SJesse Barnes int drm_mode_getplane(struct drm_device *dev, void *data, 22058cf5c917SJesse Barnes struct drm_file *file_priv) 22068cf5c917SJesse Barnes { 22078cf5c917SJesse Barnes struct drm_mode_get_plane *plane_resp = data; 22088cf5c917SJesse Barnes struct drm_plane *plane; 22098cf5c917SJesse Barnes uint32_t __user *format_ptr; 22108cf5c917SJesse Barnes int ret = 0; 22118cf5c917SJesse Barnes 22128cf5c917SJesse Barnes if (!drm_core_check_feature(dev, DRIVER_MODESET)) 22138cf5c917SJesse Barnes return -EINVAL; 22148cf5c917SJesse Barnes 221584849903SDaniel Vetter drm_modeset_lock_all(dev); 2216a2b34e22SRob Clark plane = drm_plane_find(dev, plane_resp->plane_id); 2217a2b34e22SRob Clark if (!plane) { 22188cf5c917SJesse Barnes ret = -ENOENT; 22198cf5c917SJesse Barnes goto out; 22208cf5c917SJesse Barnes } 22218cf5c917SJesse Barnes 22228cf5c917SJesse Barnes if (plane->crtc) 22238cf5c917SJesse Barnes plane_resp->crtc_id = plane->crtc->base.id; 22248cf5c917SJesse Barnes else 22258cf5c917SJesse Barnes plane_resp->crtc_id = 0; 22268cf5c917SJesse Barnes 22278cf5c917SJesse Barnes if (plane->fb) 22288cf5c917SJesse Barnes plane_resp->fb_id = plane->fb->base.id; 22298cf5c917SJesse Barnes else 22308cf5c917SJesse Barnes plane_resp->fb_id = 0; 22318cf5c917SJesse Barnes 22328cf5c917SJesse Barnes plane_resp->plane_id = plane->base.id; 22338cf5c917SJesse Barnes plane_resp->possible_crtcs = plane->possible_crtcs; 2234778ad903SVille Syrjälä plane_resp->gamma_size = 0; 22358cf5c917SJesse Barnes 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 */ 22408cf5c917SJesse Barnes if (plane->format_count && 22418cf5c917SJesse Barnes (plane_resp->count_format_types >= plane->format_count)) { 224281f6c7f8SVille Syrjälä format_ptr = (uint32_t __user *)(unsigned long)plane_resp->format_type_ptr; 22438cf5c917SJesse Barnes if (copy_to_user(format_ptr, 22448cf5c917SJesse Barnes plane->format_types, 22458cf5c917SJesse Barnes sizeof(uint32_t) * plane->format_count)) { 22468cf5c917SJesse Barnes ret = -EFAULT; 22478cf5c917SJesse Barnes goto out; 22488cf5c917SJesse Barnes } 22498cf5c917SJesse Barnes } 22508cf5c917SJesse Barnes plane_resp->count_format_types = plane->format_count; 22518cf5c917SJesse Barnes 22528cf5c917SJesse Barnes out: 225384849903SDaniel Vetter drm_modeset_unlock_all(dev); 22548cf5c917SJesse Barnes return ret; 22558cf5c917SJesse Barnes } 22568cf5c917SJesse Barnes 2257b36552b3SMatt Roper /* 2258b36552b3SMatt Roper * setplane_internal - setplane handler for internal callers 22598cf5c917SJesse Barnes * 2260b36552b3SMatt Roper * Note that we assume an extra reference has already been taken on fb. If the 2261b36552b3SMatt Roper * update fails, this reference will be dropped before return; if it succeeds, 2262b36552b3SMatt Roper * the previous framebuffer (if any) will be unreferenced instead. 2263c8e32cc1SDaniel Vetter * 2264b36552b3SMatt Roper * src_{x,y,w,h} are provided in 16.16 fixed point format 22658cf5c917SJesse Barnes */ 2266f2b50c11SDaniel Vetter static int __setplane_internal(struct drm_plane *plane, 226717cfd91fSChris Wilson struct drm_crtc *crtc, 2268b36552b3SMatt Roper struct drm_framebuffer *fb, 2269b36552b3SMatt Roper int32_t crtc_x, int32_t crtc_y, 2270b36552b3SMatt Roper uint32_t crtc_w, uint32_t crtc_h, 2271b36552b3SMatt Roper /* src_{x,y,w,h} values are 16.16 fixed point */ 2272b36552b3SMatt Roper uint32_t src_x, uint32_t src_y, 2273b36552b3SMatt Roper uint32_t src_w, uint32_t src_h) 22748cf5c917SJesse Barnes { 22758cf5c917SJesse Barnes int ret = 0; 227642ef8789SVille Syrjälä unsigned int fb_width, fb_height; 227762443be6SVille Syrjälä int i; 22788cf5c917SJesse Barnes 22798cf5c917SJesse Barnes /* No fb means shut it down */ 2280b36552b3SMatt Roper if (!fb) { 22813d30a59bSDaniel Vetter plane->old_fb = plane->fb; 2282731cce48SDaniel Vetter ret = plane->funcs->disable_plane(plane); 2283731cce48SDaniel Vetter if (!ret) { 2284e5e3b44cSVille Syrjälä plane->crtc = NULL; 2285e5e3b44cSVille Syrjälä plane->fb = NULL; 2286731cce48SDaniel Vetter } else { 22873d30a59bSDaniel Vetter plane->old_fb = NULL; 2288731cce48SDaniel Vetter } 22898cf5c917SJesse Barnes goto out; 22908cf5c917SJesse Barnes } 22918cf5c917SJesse Barnes 22927f994f3fSMatt Roper /* Check whether this plane is usable on this CRTC */ 22937f994f3fSMatt Roper if (!(plane->possible_crtcs & drm_crtc_mask(crtc))) { 22947f994f3fSMatt Roper DRM_DEBUG_KMS("Invalid crtc for plane\n"); 22957f994f3fSMatt Roper ret = -EINVAL; 22967f994f3fSMatt Roper goto out; 22977f994f3fSMatt Roper } 22987f994f3fSMatt Roper 229962443be6SVille Syrjälä /* Check whether this plane supports the fb pixel format. */ 230062443be6SVille Syrjälä for (i = 0; i < plane->format_count; i++) 230162443be6SVille Syrjälä if (fb->pixel_format == plane->format_types[i]) 230262443be6SVille Syrjälä break; 230362443be6SVille Syrjälä if (i == plane->format_count) { 23046ba6d03eSVille Syrjälä DRM_DEBUG_KMS("Invalid pixel format %s\n", 23056ba6d03eSVille Syrjälä drm_get_format_name(fb->pixel_format)); 230662443be6SVille Syrjälä ret = -EINVAL; 230762443be6SVille Syrjälä goto out; 230862443be6SVille Syrjälä } 230962443be6SVille Syrjälä 231042ef8789SVille Syrjälä fb_width = fb->width << 16; 231142ef8789SVille Syrjälä fb_height = fb->height << 16; 231242ef8789SVille Syrjälä 231342ef8789SVille Syrjälä /* Make sure source coordinates are inside the fb. */ 2314b36552b3SMatt Roper if (src_w > fb_width || 2315b36552b3SMatt Roper src_x > fb_width - src_w || 2316b36552b3SMatt Roper src_h > fb_height || 2317b36552b3SMatt Roper src_y > fb_height - src_h) { 231842ef8789SVille Syrjälä DRM_DEBUG_KMS("Invalid source coordinates " 231942ef8789SVille Syrjälä "%u.%06ux%u.%06u+%u.%06u+%u.%06u\n", 2320b36552b3SMatt Roper src_w >> 16, ((src_w & 0xffff) * 15625) >> 10, 2321b36552b3SMatt Roper src_h >> 16, ((src_h & 0xffff) * 15625) >> 10, 2322b36552b3SMatt Roper src_x >> 16, ((src_x & 0xffff) * 15625) >> 10, 2323b36552b3SMatt Roper src_y >> 16, ((src_y & 0xffff) * 15625) >> 10); 232442ef8789SVille Syrjälä ret = -ENOSPC; 232542ef8789SVille Syrjälä goto out; 232642ef8789SVille Syrjälä } 232742ef8789SVille Syrjälä 23283d30a59bSDaniel Vetter plane->old_fb = plane->fb; 23298cf5c917SJesse Barnes ret = plane->funcs->update_plane(plane, crtc, fb, 2330b36552b3SMatt Roper crtc_x, crtc_y, crtc_w, crtc_h, 2331b36552b3SMatt Roper src_x, src_y, src_w, src_h); 23328cf5c917SJesse Barnes if (!ret) { 23338cf5c917SJesse Barnes plane->crtc = crtc; 23348cf5c917SJesse Barnes plane->fb = fb; 233535f8badcSDaniel Vetter fb = NULL; 23360fe27f06SDaniel Vetter } else { 23373d30a59bSDaniel Vetter plane->old_fb = NULL; 23388cf5c917SJesse Barnes } 23398cf5c917SJesse Barnes 23408cf5c917SJesse Barnes out: 23416c2a7532SDaniel Vetter if (fb) 23426c2a7532SDaniel Vetter drm_framebuffer_unreference(fb); 23433d30a59bSDaniel Vetter if (plane->old_fb) 23443d30a59bSDaniel Vetter drm_framebuffer_unreference(plane->old_fb); 23453d30a59bSDaniel Vetter plane->old_fb = NULL; 23468cf5c917SJesse Barnes 23478cf5c917SJesse Barnes return ret; 2348f2b50c11SDaniel Vetter } 2349b36552b3SMatt Roper 2350f2b50c11SDaniel Vetter static int setplane_internal(struct drm_plane *plane, 2351f2b50c11SDaniel Vetter struct drm_crtc *crtc, 2352f2b50c11SDaniel Vetter struct drm_framebuffer *fb, 2353f2b50c11SDaniel Vetter int32_t crtc_x, int32_t crtc_y, 2354f2b50c11SDaniel Vetter uint32_t crtc_w, uint32_t crtc_h, 2355f2b50c11SDaniel Vetter /* src_{x,y,w,h} values are 16.16 fixed point */ 2356f2b50c11SDaniel Vetter uint32_t src_x, uint32_t src_y, 2357f2b50c11SDaniel Vetter uint32_t src_w, uint32_t src_h) 2358f2b50c11SDaniel Vetter { 2359f2b50c11SDaniel Vetter int ret; 2360f2b50c11SDaniel Vetter 2361f2b50c11SDaniel Vetter drm_modeset_lock_all(plane->dev); 2362f2b50c11SDaniel Vetter ret = __setplane_internal(plane, crtc, fb, 2363f2b50c11SDaniel Vetter crtc_x, crtc_y, crtc_w, crtc_h, 2364f2b50c11SDaniel Vetter src_x, src_y, src_w, src_h); 2365f2b50c11SDaniel Vetter drm_modeset_unlock_all(plane->dev); 2366f2b50c11SDaniel Vetter 2367f2b50c11SDaniel Vetter return ret; 2368b36552b3SMatt Roper } 2369b36552b3SMatt Roper 2370b36552b3SMatt Roper /** 2371b36552b3SMatt Roper * drm_mode_setplane - configure a plane's configuration 2372b36552b3SMatt Roper * @dev: DRM device 2373b36552b3SMatt Roper * @data: ioctl data* 2374b36552b3SMatt Roper * @file_priv: DRM file info 2375b36552b3SMatt Roper * 2376b36552b3SMatt Roper * Set plane configuration, including placement, fb, scaling, and other factors. 2377b36552b3SMatt Roper * Or pass a NULL fb to disable (planes may be disabled without providing a 2378b36552b3SMatt Roper * valid crtc). 2379b36552b3SMatt Roper * 2380b36552b3SMatt Roper * Returns: 2381b36552b3SMatt Roper * Zero on success, errno on failure. 2382b36552b3SMatt Roper */ 2383b36552b3SMatt Roper int drm_mode_setplane(struct drm_device *dev, void *data, 2384b36552b3SMatt Roper struct drm_file *file_priv) 2385b36552b3SMatt Roper { 2386b36552b3SMatt Roper struct drm_mode_set_plane *plane_req = data; 2387b36552b3SMatt Roper struct drm_mode_object *obj; 2388b36552b3SMatt Roper struct drm_plane *plane; 2389b36552b3SMatt Roper struct drm_crtc *crtc = NULL; 2390b36552b3SMatt Roper struct drm_framebuffer *fb = NULL; 2391b36552b3SMatt Roper 2392b36552b3SMatt Roper if (!drm_core_check_feature(dev, DRIVER_MODESET)) 2393b36552b3SMatt Roper return -EINVAL; 2394b36552b3SMatt Roper 2395b36552b3SMatt Roper /* Give drivers some help against integer overflows */ 2396b36552b3SMatt Roper if (plane_req->crtc_w > INT_MAX || 2397b36552b3SMatt Roper plane_req->crtc_x > INT_MAX - (int32_t) plane_req->crtc_w || 2398b36552b3SMatt Roper plane_req->crtc_h > INT_MAX || 2399b36552b3SMatt Roper plane_req->crtc_y > INT_MAX - (int32_t) plane_req->crtc_h) { 2400b36552b3SMatt Roper DRM_DEBUG_KMS("Invalid CRTC coordinates %ux%u+%d+%d\n", 2401b36552b3SMatt Roper plane_req->crtc_w, plane_req->crtc_h, 2402b36552b3SMatt Roper plane_req->crtc_x, plane_req->crtc_y); 2403b36552b3SMatt Roper return -ERANGE; 2404b36552b3SMatt Roper } 2405b36552b3SMatt Roper 2406b36552b3SMatt Roper /* 2407b36552b3SMatt Roper * First, find the plane, crtc, and fb objects. If not available, 2408b36552b3SMatt Roper * we don't bother to call the driver. 2409b36552b3SMatt Roper */ 2410b36552b3SMatt Roper obj = drm_mode_object_find(dev, plane_req->plane_id, 2411b36552b3SMatt Roper DRM_MODE_OBJECT_PLANE); 2412b36552b3SMatt Roper if (!obj) { 2413b36552b3SMatt Roper DRM_DEBUG_KMS("Unknown plane ID %d\n", 2414b36552b3SMatt Roper plane_req->plane_id); 2415b36552b3SMatt Roper return -ENOENT; 2416b36552b3SMatt Roper } 2417b36552b3SMatt Roper plane = obj_to_plane(obj); 2418b36552b3SMatt Roper 2419b36552b3SMatt Roper if (plane_req->fb_id) { 2420b36552b3SMatt Roper fb = drm_framebuffer_lookup(dev, plane_req->fb_id); 2421b36552b3SMatt Roper if (!fb) { 2422b36552b3SMatt Roper DRM_DEBUG_KMS("Unknown framebuffer ID %d\n", 2423b36552b3SMatt Roper plane_req->fb_id); 2424b36552b3SMatt Roper return -ENOENT; 2425b36552b3SMatt Roper } 2426b36552b3SMatt Roper 2427b36552b3SMatt Roper obj = drm_mode_object_find(dev, plane_req->crtc_id, 2428b36552b3SMatt Roper DRM_MODE_OBJECT_CRTC); 2429b36552b3SMatt Roper if (!obj) { 2430b36552b3SMatt Roper DRM_DEBUG_KMS("Unknown crtc ID %d\n", 2431b36552b3SMatt Roper plane_req->crtc_id); 2432b36552b3SMatt Roper return -ENOENT; 2433b36552b3SMatt Roper } 2434b36552b3SMatt Roper crtc = obj_to_crtc(obj); 2435b36552b3SMatt Roper } 2436b36552b3SMatt Roper 2437161d0dc1SMatt Roper /* 2438161d0dc1SMatt Roper * setplane_internal will take care of deref'ing either the old or new 2439161d0dc1SMatt Roper * framebuffer depending on success. 2440161d0dc1SMatt Roper */ 244117cfd91fSChris Wilson return setplane_internal(plane, crtc, fb, 2442b36552b3SMatt Roper plane_req->crtc_x, plane_req->crtc_y, 2443b36552b3SMatt Roper plane_req->crtc_w, plane_req->crtc_h, 2444b36552b3SMatt Roper plane_req->src_x, plane_req->src_y, 2445b36552b3SMatt Roper plane_req->src_w, plane_req->src_h); 24468cf5c917SJesse Barnes } 24478cf5c917SJesse Barnes 24488cf5c917SJesse Barnes /** 24492d13b679SDaniel Vetter * drm_mode_set_config_internal - helper to call ->set_config 24502d13b679SDaniel Vetter * @set: modeset config to set 24512d13b679SDaniel Vetter * 24522d13b679SDaniel Vetter * This is a little helper to wrap internal calls to the ->set_config driver 24532d13b679SDaniel Vetter * interface. The only thing it adds is correct refcounting dance. 2454c8e32cc1SDaniel Vetter * 2455c8e32cc1SDaniel Vetter * Returns: 2456c8e32cc1SDaniel Vetter * Zero on success, errno on failure. 24572d13b679SDaniel Vetter */ 24582d13b679SDaniel Vetter int drm_mode_set_config_internal(struct drm_mode_set *set) 24592d13b679SDaniel Vetter { 24602d13b679SDaniel Vetter struct drm_crtc *crtc = set->crtc; 24615cef29aaSDaniel Vetter struct drm_framebuffer *fb; 24625cef29aaSDaniel Vetter struct drm_crtc *tmp; 2463b0d12325SDaniel Vetter int ret; 24642d13b679SDaniel Vetter 24655cef29aaSDaniel Vetter /* 24665cef29aaSDaniel Vetter * NOTE: ->set_config can also disable other crtcs (if we steal all 24675cef29aaSDaniel Vetter * connectors from it), hence we need to refcount the fbs across all 24685cef29aaSDaniel Vetter * crtcs. Atomic modeset will have saner semantics ... 24695cef29aaSDaniel Vetter */ 24705cef29aaSDaniel Vetter list_for_each_entry(tmp, &crtc->dev->mode_config.crtc_list, head) 24713d30a59bSDaniel Vetter tmp->primary->old_fb = tmp->primary->fb; 24725cef29aaSDaniel Vetter 2473b0d12325SDaniel Vetter fb = set->fb; 2474b0d12325SDaniel Vetter 2475b0d12325SDaniel Vetter ret = crtc->funcs->set_config(set); 2476b0d12325SDaniel Vetter if (ret == 0) { 2477e13161afSMatt Roper crtc->primary->crtc = crtc; 24780fe27f06SDaniel Vetter crtc->primary->fb = fb; 24795cef29aaSDaniel Vetter } 2480cc85e121SDaniel Vetter 24815cef29aaSDaniel Vetter list_for_each_entry(tmp, &crtc->dev->mode_config.crtc_list, head) { 2482f4510a27SMatt Roper if (tmp->primary->fb) 2483f4510a27SMatt Roper drm_framebuffer_reference(tmp->primary->fb); 24843d30a59bSDaniel Vetter if (tmp->primary->old_fb) 24853d30a59bSDaniel Vetter drm_framebuffer_unreference(tmp->primary->old_fb); 24863d30a59bSDaniel Vetter tmp->primary->old_fb = NULL; 2487b0d12325SDaniel Vetter } 2488b0d12325SDaniel Vetter 2489b0d12325SDaniel Vetter return ret; 24902d13b679SDaniel Vetter } 24912d13b679SDaniel Vetter EXPORT_SYMBOL(drm_mode_set_config_internal); 24922d13b679SDaniel Vetter 2493af93629dSMatt Roper /** 2494af93629dSMatt Roper * drm_crtc_check_viewport - Checks that a framebuffer is big enough for the 2495af93629dSMatt Roper * CRTC viewport 2496af93629dSMatt Roper * @crtc: CRTC that framebuffer will be displayed on 2497af93629dSMatt Roper * @x: x panning 2498af93629dSMatt Roper * @y: y panning 2499af93629dSMatt Roper * @mode: mode that framebuffer will be displayed under 2500af93629dSMatt Roper * @fb: framebuffer to check size of 2501c11e9283SDamien Lespiau */ 2502af93629dSMatt Roper int drm_crtc_check_viewport(const struct drm_crtc *crtc, 2503c11e9283SDamien Lespiau int x, int y, 2504c11e9283SDamien Lespiau const struct drm_display_mode *mode, 2505c11e9283SDamien Lespiau const struct drm_framebuffer *fb) 2506c11e9283SDamien Lespiau 2507c11e9283SDamien Lespiau { 2508c11e9283SDamien Lespiau int hdisplay, vdisplay; 2509c11e9283SDamien Lespiau 2510c11e9283SDamien Lespiau hdisplay = mode->hdisplay; 2511c11e9283SDamien Lespiau vdisplay = mode->vdisplay; 2512c11e9283SDamien Lespiau 2513a0c1bbb0SDamien Lespiau if (drm_mode_is_stereo(mode)) { 2514a0c1bbb0SDamien Lespiau struct drm_display_mode adjusted = *mode; 2515a0c1bbb0SDamien Lespiau 2516a0c1bbb0SDamien Lespiau drm_mode_set_crtcinfo(&adjusted, CRTC_STEREO_DOUBLE); 2517a0c1bbb0SDamien Lespiau hdisplay = adjusted.crtc_hdisplay; 2518a0c1bbb0SDamien Lespiau vdisplay = adjusted.crtc_vdisplay; 2519a0c1bbb0SDamien Lespiau } 2520a0c1bbb0SDamien Lespiau 2521c11e9283SDamien Lespiau if (crtc->invert_dimensions) 2522c11e9283SDamien Lespiau swap(hdisplay, vdisplay); 2523c11e9283SDamien Lespiau 2524c11e9283SDamien Lespiau if (hdisplay > fb->width || 2525c11e9283SDamien Lespiau vdisplay > fb->height || 2526c11e9283SDamien Lespiau x > fb->width - hdisplay || 2527c11e9283SDamien Lespiau y > fb->height - vdisplay) { 2528c11e9283SDamien Lespiau DRM_DEBUG_KMS("Invalid fb size %ux%u for CRTC viewport %ux%u+%d+%d%s.\n", 2529c11e9283SDamien Lespiau fb->width, fb->height, hdisplay, vdisplay, x, y, 2530c11e9283SDamien Lespiau crtc->invert_dimensions ? " (inverted)" : ""); 2531c11e9283SDamien Lespiau return -ENOSPC; 2532c11e9283SDamien Lespiau } 2533c11e9283SDamien Lespiau 2534c11e9283SDamien Lespiau return 0; 2535c11e9283SDamien Lespiau } 2536af93629dSMatt Roper EXPORT_SYMBOL(drm_crtc_check_viewport); 2537c11e9283SDamien Lespiau 25382d13b679SDaniel Vetter /** 2539f453ba04SDave Airlie * drm_mode_setcrtc - set CRTC configuration 2540065a50edSDaniel Vetter * @dev: drm device for the ioctl 2541065a50edSDaniel Vetter * @data: data pointer for the ioctl 2542065a50edSDaniel Vetter * @file_priv: drm file for the ioctl call 2543f453ba04SDave Airlie * 2544f453ba04SDave Airlie * Build a new CRTC configuration based on user request. 2545f453ba04SDave Airlie * 2546f453ba04SDave Airlie * Called by the user via ioctl. 2547f453ba04SDave Airlie * 2548c8e32cc1SDaniel Vetter * Returns: 2549f453ba04SDave Airlie * Zero on success, errno on failure. 2550f453ba04SDave Airlie */ 2551f453ba04SDave Airlie int drm_mode_setcrtc(struct drm_device *dev, void *data, 2552f453ba04SDave Airlie struct drm_file *file_priv) 2553f453ba04SDave Airlie { 2554f453ba04SDave Airlie struct drm_mode_config *config = &dev->mode_config; 2555f453ba04SDave Airlie struct drm_mode_crtc *crtc_req = data; 25566653cc8dSVille Syrjälä struct drm_crtc *crtc; 2557f453ba04SDave Airlie struct drm_connector **connector_set = NULL, *connector; 2558f453ba04SDave Airlie struct drm_framebuffer *fb = NULL; 2559f453ba04SDave Airlie struct drm_display_mode *mode = NULL; 2560f453ba04SDave Airlie struct drm_mode_set set; 2561f453ba04SDave Airlie uint32_t __user *set_connectors_ptr; 25624a1b0714SLaurent Pinchart int ret; 2563f453ba04SDave Airlie int i; 2564f453ba04SDave Airlie 2565fb3b06c8SDave Airlie if (!drm_core_check_feature(dev, DRIVER_MODESET)) 2566fb3b06c8SDave Airlie return -EINVAL; 2567fb3b06c8SDave Airlie 25681d97e915SVille Syrjälä /* For some reason crtc x/y offsets are signed internally. */ 25691d97e915SVille Syrjälä if (crtc_req->x > INT_MAX || crtc_req->y > INT_MAX) 25701d97e915SVille Syrjälä return -ERANGE; 25711d97e915SVille Syrjälä 257284849903SDaniel Vetter drm_modeset_lock_all(dev); 2573a2b34e22SRob Clark crtc = drm_crtc_find(dev, crtc_req->crtc_id); 2574a2b34e22SRob Clark if (!crtc) { 257558367ed6SZhao Yakui DRM_DEBUG_KMS("Unknown CRTC ID %d\n", crtc_req->crtc_id); 2576f27657f2SVille Syrjälä ret = -ENOENT; 2577f453ba04SDave Airlie goto out; 2578f453ba04SDave Airlie } 25799440106bSJerome Glisse DRM_DEBUG_KMS("[CRTC:%d]\n", crtc->base.id); 2580f453ba04SDave Airlie 2581f453ba04SDave Airlie if (crtc_req->mode_valid) { 2582f453ba04SDave Airlie /* If we have a mode we need a framebuffer. */ 2583f453ba04SDave Airlie /* If we pass -1, set the mode with the currently bound fb */ 2584f453ba04SDave Airlie if (crtc_req->fb_id == -1) { 2585f4510a27SMatt Roper if (!crtc->primary->fb) { 25866653cc8dSVille Syrjälä DRM_DEBUG_KMS("CRTC doesn't have current FB\n"); 25876653cc8dSVille Syrjälä ret = -EINVAL; 25886653cc8dSVille Syrjälä goto out; 25896653cc8dSVille Syrjälä } 2590f4510a27SMatt Roper fb = crtc->primary->fb; 2591b0d12325SDaniel Vetter /* Make refcounting symmetric with the lookup path. */ 2592b0d12325SDaniel Vetter drm_framebuffer_reference(fb); 2593f453ba04SDave Airlie } else { 2594786b99edSDaniel Vetter fb = drm_framebuffer_lookup(dev, crtc_req->fb_id); 2595786b99edSDaniel Vetter if (!fb) { 259658367ed6SZhao Yakui DRM_DEBUG_KMS("Unknown FB ID%d\n", 259758367ed6SZhao Yakui crtc_req->fb_id); 259837c4e705SVille Syrjälä ret = -ENOENT; 2599f453ba04SDave Airlie goto out; 2600f453ba04SDave Airlie } 2601f453ba04SDave Airlie } 2602f453ba04SDave Airlie 2603f453ba04SDave Airlie mode = drm_mode_create(dev); 2604ee34ab5bSVille Syrjälä if (!mode) { 2605ee34ab5bSVille Syrjälä ret = -ENOMEM; 2606ee34ab5bSVille Syrjälä goto out; 2607ee34ab5bSVille Syrjälä } 2608ee34ab5bSVille Syrjälä 260990367bf6SVille Syrjälä ret = drm_crtc_convert_umode(mode, &crtc_req->mode); 261090367bf6SVille Syrjälä if (ret) { 261190367bf6SVille Syrjälä DRM_DEBUG_KMS("Invalid mode\n"); 261290367bf6SVille Syrjälä goto out; 261390367bf6SVille Syrjälä } 261490367bf6SVille Syrjälä 2615f453ba04SDave Airlie drm_mode_set_crtcinfo(mode, CRTC_INTERLACE_HALVE_V); 26165f61bb42SVille Syrjälä 2617c11e9283SDamien Lespiau ret = drm_crtc_check_viewport(crtc, crtc_req->x, crtc_req->y, 2618c11e9283SDamien Lespiau mode, fb); 2619c11e9283SDamien Lespiau if (ret) 26205f61bb42SVille Syrjälä goto out; 2621c11e9283SDamien Lespiau 2622f453ba04SDave Airlie } 2623f453ba04SDave Airlie 2624f453ba04SDave Airlie if (crtc_req->count_connectors == 0 && mode) { 262558367ed6SZhao Yakui DRM_DEBUG_KMS("Count connectors is 0 but mode set\n"); 2626f453ba04SDave Airlie ret = -EINVAL; 2627f453ba04SDave Airlie goto out; 2628f453ba04SDave Airlie } 2629f453ba04SDave Airlie 26307781de74SJakob Bornecrantz if (crtc_req->count_connectors > 0 && (!mode || !fb)) { 263158367ed6SZhao Yakui DRM_DEBUG_KMS("Count connectors is %d but no mode or fb set\n", 2632f453ba04SDave Airlie crtc_req->count_connectors); 2633f453ba04SDave Airlie ret = -EINVAL; 2634f453ba04SDave Airlie goto out; 2635f453ba04SDave Airlie } 2636f453ba04SDave Airlie 2637f453ba04SDave Airlie if (crtc_req->count_connectors > 0) { 2638f453ba04SDave Airlie u32 out_id; 2639f453ba04SDave Airlie 2640f453ba04SDave Airlie /* Avoid unbounded kernel memory allocation */ 2641f453ba04SDave Airlie if (crtc_req->count_connectors > config->num_connector) { 2642f453ba04SDave Airlie ret = -EINVAL; 2643f453ba04SDave Airlie goto out; 2644f453ba04SDave Airlie } 2645f453ba04SDave Airlie 2646f453ba04SDave Airlie connector_set = kmalloc(crtc_req->count_connectors * 2647f453ba04SDave Airlie sizeof(struct drm_connector *), 2648f453ba04SDave Airlie GFP_KERNEL); 2649f453ba04SDave Airlie if (!connector_set) { 2650f453ba04SDave Airlie ret = -ENOMEM; 2651f453ba04SDave Airlie goto out; 2652f453ba04SDave Airlie } 2653f453ba04SDave Airlie 2654f453ba04SDave Airlie for (i = 0; i < crtc_req->count_connectors; i++) { 265581f6c7f8SVille Syrjälä set_connectors_ptr = (uint32_t __user *)(unsigned long)crtc_req->set_connectors_ptr; 2656f453ba04SDave Airlie if (get_user(out_id, &set_connectors_ptr[i])) { 2657f453ba04SDave Airlie ret = -EFAULT; 2658f453ba04SDave Airlie goto out; 2659f453ba04SDave Airlie } 2660f453ba04SDave Airlie 2661a2b34e22SRob Clark connector = drm_connector_find(dev, out_id); 2662a2b34e22SRob Clark if (!connector) { 266358367ed6SZhao Yakui DRM_DEBUG_KMS("Connector id %d unknown\n", 266458367ed6SZhao Yakui out_id); 2665f27657f2SVille Syrjälä ret = -ENOENT; 2666f453ba04SDave Airlie goto out; 2667f453ba04SDave Airlie } 26689440106bSJerome Glisse DRM_DEBUG_KMS("[CONNECTOR:%d:%s]\n", 26699440106bSJerome Glisse connector->base.id, 267025933820SJani Nikula connector->name); 2671f453ba04SDave Airlie 2672f453ba04SDave Airlie connector_set[i] = connector; 2673f453ba04SDave Airlie } 2674f453ba04SDave Airlie } 2675f453ba04SDave Airlie 2676f453ba04SDave Airlie set.crtc = crtc; 2677f453ba04SDave Airlie set.x = crtc_req->x; 2678f453ba04SDave Airlie set.y = crtc_req->y; 2679f453ba04SDave Airlie set.mode = mode; 2680f453ba04SDave Airlie set.connectors = connector_set; 2681f453ba04SDave Airlie set.num_connectors = crtc_req->count_connectors; 2682f453ba04SDave Airlie set.fb = fb; 26832d13b679SDaniel Vetter ret = drm_mode_set_config_internal(&set); 2684f453ba04SDave Airlie 2685f453ba04SDave Airlie out: 2686b0d12325SDaniel Vetter if (fb) 2687b0d12325SDaniel Vetter drm_framebuffer_unreference(fb); 2688b0d12325SDaniel Vetter 2689f453ba04SDave Airlie kfree(connector_set); 2690ee34ab5bSVille Syrjälä drm_mode_destroy(dev, mode); 269184849903SDaniel Vetter drm_modeset_unlock_all(dev); 2692f453ba04SDave Airlie return ret; 2693f453ba04SDave Airlie } 2694f453ba04SDave Airlie 2695161d0dc1SMatt Roper /** 2696161d0dc1SMatt Roper * drm_mode_cursor_universal - translate legacy cursor ioctl call into a 2697161d0dc1SMatt Roper * universal plane handler call 2698161d0dc1SMatt Roper * @crtc: crtc to update cursor for 2699161d0dc1SMatt Roper * @req: data pointer for the ioctl 2700161d0dc1SMatt Roper * @file_priv: drm file for the ioctl call 2701161d0dc1SMatt Roper * 2702161d0dc1SMatt Roper * Legacy cursor ioctl's work directly with driver buffer handles. To 2703161d0dc1SMatt Roper * translate legacy ioctl calls into universal plane handler calls, we need to 2704161d0dc1SMatt Roper * wrap the native buffer handle in a drm_framebuffer. 2705161d0dc1SMatt Roper * 2706161d0dc1SMatt Roper * Note that we assume any handle passed to the legacy ioctls was a 32-bit ARGB 2707161d0dc1SMatt Roper * buffer with a pitch of 4*width; the universal plane interface should be used 2708161d0dc1SMatt Roper * directly in cases where the hardware can support other buffer settings and 2709161d0dc1SMatt Roper * userspace wants to make use of these capabilities. 2710161d0dc1SMatt Roper * 2711161d0dc1SMatt Roper * Returns: 2712161d0dc1SMatt Roper * Zero on success, errno on failure. 2713161d0dc1SMatt Roper */ 2714161d0dc1SMatt Roper static int drm_mode_cursor_universal(struct drm_crtc *crtc, 2715161d0dc1SMatt Roper struct drm_mode_cursor2 *req, 2716161d0dc1SMatt Roper struct drm_file *file_priv) 2717161d0dc1SMatt Roper { 2718161d0dc1SMatt Roper struct drm_device *dev = crtc->dev; 2719161d0dc1SMatt Roper struct drm_framebuffer *fb = NULL; 2720161d0dc1SMatt Roper struct drm_mode_fb_cmd2 fbreq = { 2721161d0dc1SMatt Roper .width = req->width, 2722161d0dc1SMatt Roper .height = req->height, 2723161d0dc1SMatt Roper .pixel_format = DRM_FORMAT_ARGB8888, 2724161d0dc1SMatt Roper .pitches = { req->width * 4 }, 2725161d0dc1SMatt Roper .handles = { req->handle }, 2726161d0dc1SMatt Roper }; 2727161d0dc1SMatt Roper int32_t crtc_x, crtc_y; 2728161d0dc1SMatt Roper uint32_t crtc_w = 0, crtc_h = 0; 2729161d0dc1SMatt Roper uint32_t src_w = 0, src_h = 0; 2730161d0dc1SMatt Roper int ret = 0; 2731161d0dc1SMatt Roper 2732161d0dc1SMatt Roper BUG_ON(!crtc->cursor); 2733f2b50c11SDaniel Vetter WARN_ON(crtc->cursor->crtc != crtc && crtc->cursor->crtc != NULL); 2734161d0dc1SMatt Roper 2735161d0dc1SMatt Roper /* 2736161d0dc1SMatt Roper * Obtain fb we'll be using (either new or existing) and take an extra 2737161d0dc1SMatt Roper * reference to it if fb != null. setplane will take care of dropping 2738161d0dc1SMatt Roper * the reference if the plane update fails. 2739161d0dc1SMatt Roper */ 2740161d0dc1SMatt Roper if (req->flags & DRM_MODE_CURSOR_BO) { 2741161d0dc1SMatt Roper if (req->handle) { 2742161d0dc1SMatt Roper fb = add_framebuffer_internal(dev, &fbreq, file_priv); 2743161d0dc1SMatt Roper if (IS_ERR(fb)) { 2744161d0dc1SMatt Roper DRM_DEBUG_KMS("failed to wrap cursor buffer in drm framebuffer\n"); 2745161d0dc1SMatt Roper return PTR_ERR(fb); 2746161d0dc1SMatt Roper } 2747161d0dc1SMatt Roper 2748161d0dc1SMatt Roper drm_framebuffer_reference(fb); 2749161d0dc1SMatt Roper } else { 2750161d0dc1SMatt Roper fb = NULL; 2751161d0dc1SMatt Roper } 2752161d0dc1SMatt Roper } else { 2753161d0dc1SMatt Roper fb = crtc->cursor->fb; 2754161d0dc1SMatt Roper if (fb) 2755161d0dc1SMatt Roper drm_framebuffer_reference(fb); 2756161d0dc1SMatt Roper } 2757161d0dc1SMatt Roper 2758161d0dc1SMatt Roper if (req->flags & DRM_MODE_CURSOR_MOVE) { 2759161d0dc1SMatt Roper crtc_x = req->x; 2760161d0dc1SMatt Roper crtc_y = req->y; 2761161d0dc1SMatt Roper } else { 2762161d0dc1SMatt Roper crtc_x = crtc->cursor_x; 2763161d0dc1SMatt Roper crtc_y = crtc->cursor_y; 2764161d0dc1SMatt Roper } 2765161d0dc1SMatt Roper 2766161d0dc1SMatt Roper if (fb) { 2767161d0dc1SMatt Roper crtc_w = fb->width; 2768161d0dc1SMatt Roper crtc_h = fb->height; 2769161d0dc1SMatt Roper src_w = fb->width << 16; 2770161d0dc1SMatt Roper src_h = fb->height << 16; 2771161d0dc1SMatt Roper } 2772161d0dc1SMatt Roper 2773161d0dc1SMatt Roper /* 2774161d0dc1SMatt Roper * setplane_internal will take care of deref'ing either the old or new 2775161d0dc1SMatt Roper * framebuffer depending on success. 2776161d0dc1SMatt Roper */ 2777f2b50c11SDaniel Vetter ret = __setplane_internal(crtc->cursor, crtc, fb, 2778161d0dc1SMatt Roper crtc_x, crtc_y, crtc_w, crtc_h, 2779161d0dc1SMatt Roper 0, 0, src_w, src_h); 2780161d0dc1SMatt Roper 2781161d0dc1SMatt Roper /* Update successful; save new cursor position, if necessary */ 2782161d0dc1SMatt Roper if (ret == 0 && req->flags & DRM_MODE_CURSOR_MOVE) { 2783161d0dc1SMatt Roper crtc->cursor_x = req->x; 2784161d0dc1SMatt Roper crtc->cursor_y = req->y; 2785161d0dc1SMatt Roper } 2786161d0dc1SMatt Roper 2787161d0dc1SMatt Roper return ret; 2788161d0dc1SMatt Roper } 2789161d0dc1SMatt Roper 27904c813d4dSDave Airlie static int drm_mode_cursor_common(struct drm_device *dev, 27914c813d4dSDave Airlie struct drm_mode_cursor2 *req, 27924c813d4dSDave Airlie struct drm_file *file_priv) 2793f453ba04SDave Airlie { 2794f453ba04SDave Airlie struct drm_crtc *crtc; 2795f453ba04SDave Airlie int ret = 0; 2796f453ba04SDave Airlie 2797fb3b06c8SDave Airlie if (!drm_core_check_feature(dev, DRIVER_MODESET)) 2798fb3b06c8SDave Airlie return -EINVAL; 2799fb3b06c8SDave Airlie 28007c4eaca4SJakob Bornecrantz if (!req->flags || (~DRM_MODE_CURSOR_FLAGS & req->flags)) 2801f453ba04SDave Airlie return -EINVAL; 2802f453ba04SDave Airlie 2803a2b34e22SRob Clark crtc = drm_crtc_find(dev, req->crtc_id); 2804a2b34e22SRob Clark if (!crtc) { 280558367ed6SZhao Yakui DRM_DEBUG_KMS("Unknown CRTC ID %d\n", req->crtc_id); 2806f27657f2SVille Syrjälä return -ENOENT; 2807f453ba04SDave Airlie } 2808f453ba04SDave Airlie 2809161d0dc1SMatt Roper /* 2810161d0dc1SMatt Roper * If this crtc has a universal cursor plane, call that plane's update 2811161d0dc1SMatt Roper * handler rather than using legacy cursor handlers. 2812161d0dc1SMatt Roper */ 2813d059f652SDaniel Vetter drm_modeset_lock_crtc(crtc); 2814f2b50c11SDaniel Vetter if (crtc->cursor) { 2815f2b50c11SDaniel Vetter ret = drm_mode_cursor_universal(crtc, req, file_priv); 2816f2b50c11SDaniel Vetter goto out; 2817f2b50c11SDaniel Vetter } 2818f2b50c11SDaniel Vetter 2819f453ba04SDave Airlie if (req->flags & DRM_MODE_CURSOR_BO) { 28204c813d4dSDave Airlie if (!crtc->funcs->cursor_set && !crtc->funcs->cursor_set2) { 2821f453ba04SDave Airlie ret = -ENXIO; 2822f453ba04SDave Airlie goto out; 2823f453ba04SDave Airlie } 2824f453ba04SDave Airlie /* Turns off the cursor if handle is 0 */ 28254c813d4dSDave Airlie if (crtc->funcs->cursor_set2) 28264c813d4dSDave Airlie ret = crtc->funcs->cursor_set2(crtc, file_priv, req->handle, 28274c813d4dSDave Airlie req->width, req->height, req->hot_x, req->hot_y); 28284c813d4dSDave Airlie else 2829f453ba04SDave Airlie ret = crtc->funcs->cursor_set(crtc, file_priv, req->handle, 2830f453ba04SDave Airlie req->width, req->height); 2831f453ba04SDave Airlie } 2832f453ba04SDave Airlie 2833f453ba04SDave Airlie if (req->flags & DRM_MODE_CURSOR_MOVE) { 2834f453ba04SDave Airlie if (crtc->funcs->cursor_move) { 2835f453ba04SDave Airlie ret = crtc->funcs->cursor_move(crtc, req->x, req->y); 2836f453ba04SDave Airlie } else { 2837f453ba04SDave Airlie ret = -EFAULT; 2838f453ba04SDave Airlie goto out; 2839f453ba04SDave Airlie } 2840f453ba04SDave Airlie } 2841f453ba04SDave Airlie out: 2842d059f652SDaniel Vetter drm_modeset_unlock_crtc(crtc); 2843dac35663SDaniel Vetter 2844f453ba04SDave Airlie return ret; 28454c813d4dSDave Airlie 28464c813d4dSDave Airlie } 2847c8e32cc1SDaniel Vetter 2848c8e32cc1SDaniel Vetter 2849c8e32cc1SDaniel Vetter /** 2850c8e32cc1SDaniel Vetter * drm_mode_cursor_ioctl - set CRTC's cursor configuration 2851c8e32cc1SDaniel Vetter * @dev: drm device for the ioctl 2852c8e32cc1SDaniel Vetter * @data: data pointer for the ioctl 2853c8e32cc1SDaniel Vetter * @file_priv: drm file for the ioctl call 2854c8e32cc1SDaniel Vetter * 2855c8e32cc1SDaniel Vetter * Set the cursor configuration based on user request. 2856c8e32cc1SDaniel Vetter * 2857c8e32cc1SDaniel Vetter * Called by the user via ioctl. 2858c8e32cc1SDaniel Vetter * 2859c8e32cc1SDaniel Vetter * Returns: 2860c8e32cc1SDaniel Vetter * Zero on success, errno on failure. 2861c8e32cc1SDaniel Vetter */ 28624c813d4dSDave Airlie int drm_mode_cursor_ioctl(struct drm_device *dev, 28634c813d4dSDave Airlie void *data, struct drm_file *file_priv) 28644c813d4dSDave Airlie { 28654c813d4dSDave Airlie struct drm_mode_cursor *req = data; 28664c813d4dSDave Airlie struct drm_mode_cursor2 new_req; 28674c813d4dSDave Airlie 28684c813d4dSDave Airlie memcpy(&new_req, req, sizeof(struct drm_mode_cursor)); 28694c813d4dSDave Airlie new_req.hot_x = new_req.hot_y = 0; 28704c813d4dSDave Airlie 28714c813d4dSDave Airlie return drm_mode_cursor_common(dev, &new_req, file_priv); 28724c813d4dSDave Airlie } 28734c813d4dSDave Airlie 2874c8e32cc1SDaniel Vetter /** 2875c8e32cc1SDaniel Vetter * drm_mode_cursor2_ioctl - set CRTC's cursor configuration 2876c8e32cc1SDaniel Vetter * @dev: drm device for the ioctl 2877c8e32cc1SDaniel Vetter * @data: data pointer for the ioctl 2878c8e32cc1SDaniel Vetter * @file_priv: drm file for the ioctl call 2879c8e32cc1SDaniel Vetter * 2880c8e32cc1SDaniel Vetter * Set the cursor configuration based on user request. This implements the 2nd 2881c8e32cc1SDaniel Vetter * version of the cursor ioctl, which allows userspace to additionally specify 2882c8e32cc1SDaniel Vetter * the hotspot of the pointer. 2883c8e32cc1SDaniel Vetter * 2884c8e32cc1SDaniel Vetter * Called by the user via ioctl. 2885c8e32cc1SDaniel Vetter * 2886c8e32cc1SDaniel Vetter * Returns: 2887c8e32cc1SDaniel Vetter * Zero on success, errno on failure. 2888c8e32cc1SDaniel Vetter */ 28894c813d4dSDave Airlie int drm_mode_cursor2_ioctl(struct drm_device *dev, 28904c813d4dSDave Airlie void *data, struct drm_file *file_priv) 28914c813d4dSDave Airlie { 28924c813d4dSDave Airlie struct drm_mode_cursor2 *req = data; 28934c813d4dSDave Airlie return drm_mode_cursor_common(dev, req, file_priv); 2894f453ba04SDave Airlie } 2895f453ba04SDave Airlie 2896c8e32cc1SDaniel Vetter /** 2897c8e32cc1SDaniel Vetter * drm_mode_legacy_fb_format - compute drm fourcc code from legacy description 2898c8e32cc1SDaniel Vetter * @bpp: bits per pixels 2899c8e32cc1SDaniel Vetter * @depth: bit depth per pixel 2900c8e32cc1SDaniel Vetter * 2901c8e32cc1SDaniel Vetter * Computes a drm fourcc pixel format code for the given @bpp/@depth values. 2902c8e32cc1SDaniel Vetter * Useful in fbdev emulation code, since that deals in those values. 2903c8e32cc1SDaniel Vetter */ 2904308e5bcbSJesse Barnes uint32_t drm_mode_legacy_fb_format(uint32_t bpp, uint32_t depth) 2905308e5bcbSJesse Barnes { 2906308e5bcbSJesse Barnes uint32_t fmt; 2907308e5bcbSJesse Barnes 2908308e5bcbSJesse Barnes switch (bpp) { 2909308e5bcbSJesse Barnes case 8: 2910d84f031bSVille Syrjälä fmt = DRM_FORMAT_C8; 2911308e5bcbSJesse Barnes break; 2912308e5bcbSJesse Barnes case 16: 2913308e5bcbSJesse Barnes if (depth == 15) 291404b3924dSVille Syrjälä fmt = DRM_FORMAT_XRGB1555; 2915308e5bcbSJesse Barnes else 291604b3924dSVille Syrjälä fmt = DRM_FORMAT_RGB565; 2917308e5bcbSJesse Barnes break; 2918308e5bcbSJesse Barnes case 24: 291904b3924dSVille Syrjälä fmt = DRM_FORMAT_RGB888; 2920308e5bcbSJesse Barnes break; 2921308e5bcbSJesse Barnes case 32: 2922308e5bcbSJesse Barnes if (depth == 24) 292304b3924dSVille Syrjälä fmt = DRM_FORMAT_XRGB8888; 2924308e5bcbSJesse Barnes else if (depth == 30) 292504b3924dSVille Syrjälä fmt = DRM_FORMAT_XRGB2101010; 2926308e5bcbSJesse Barnes else 292704b3924dSVille Syrjälä fmt = DRM_FORMAT_ARGB8888; 2928308e5bcbSJesse Barnes break; 2929308e5bcbSJesse Barnes default: 293004b3924dSVille Syrjälä DRM_ERROR("bad bpp, assuming x8r8g8b8 pixel format\n"); 293104b3924dSVille Syrjälä fmt = DRM_FORMAT_XRGB8888; 2932308e5bcbSJesse Barnes break; 2933308e5bcbSJesse Barnes } 2934308e5bcbSJesse Barnes 2935308e5bcbSJesse Barnes return fmt; 2936308e5bcbSJesse Barnes } 2937308e5bcbSJesse Barnes EXPORT_SYMBOL(drm_mode_legacy_fb_format); 2938308e5bcbSJesse Barnes 2939f453ba04SDave Airlie /** 2940f453ba04SDave Airlie * drm_mode_addfb - add an FB to the graphics configuration 2941065a50edSDaniel Vetter * @dev: drm device for the ioctl 2942065a50edSDaniel Vetter * @data: data pointer for the ioctl 2943065a50edSDaniel Vetter * @file_priv: drm file for the ioctl call 2944f453ba04SDave Airlie * 2945c8e32cc1SDaniel Vetter * Add a new FB to the specified CRTC, given a user request. This is the 2946c8e32cc1SDaniel Vetter * original addfb ioclt which only supported RGB formats. 2947f453ba04SDave Airlie * 2948f453ba04SDave Airlie * Called by the user via ioctl. 2949f453ba04SDave Airlie * 2950c8e32cc1SDaniel Vetter * Returns: 2951f453ba04SDave Airlie * Zero on success, errno on failure. 2952f453ba04SDave Airlie */ 2953f453ba04SDave Airlie int drm_mode_addfb(struct drm_device *dev, 2954f453ba04SDave Airlie void *data, struct drm_file *file_priv) 2955f453ba04SDave Airlie { 2956308e5bcbSJesse Barnes struct drm_mode_fb_cmd *or = data; 2957308e5bcbSJesse Barnes struct drm_mode_fb_cmd2 r = {}; 2958308e5bcbSJesse Barnes struct drm_mode_config *config = &dev->mode_config; 2959308e5bcbSJesse Barnes struct drm_framebuffer *fb; 2960308e5bcbSJesse Barnes int ret = 0; 2961308e5bcbSJesse Barnes 2962308e5bcbSJesse Barnes /* Use new struct with format internally */ 2963308e5bcbSJesse Barnes r.fb_id = or->fb_id; 2964308e5bcbSJesse Barnes r.width = or->width; 2965308e5bcbSJesse Barnes r.height = or->height; 2966308e5bcbSJesse Barnes r.pitches[0] = or->pitch; 2967308e5bcbSJesse Barnes r.pixel_format = drm_mode_legacy_fb_format(or->bpp, or->depth); 2968308e5bcbSJesse Barnes r.handles[0] = or->handle; 2969308e5bcbSJesse Barnes 2970308e5bcbSJesse Barnes if (!drm_core_check_feature(dev, DRIVER_MODESET)) 2971308e5bcbSJesse Barnes return -EINVAL; 2972308e5bcbSJesse Barnes 2973acb4b992SJesse Barnes if ((config->min_width > r.width) || (r.width > config->max_width)) 2974308e5bcbSJesse Barnes return -EINVAL; 2975acb4b992SJesse Barnes 2976acb4b992SJesse Barnes if ((config->min_height > r.height) || (r.height > config->max_height)) 2977308e5bcbSJesse Barnes return -EINVAL; 2978308e5bcbSJesse Barnes 2979308e5bcbSJesse Barnes fb = dev->mode_config.funcs->fb_create(dev, file_priv, &r); 2980308e5bcbSJesse Barnes if (IS_ERR(fb)) { 29811aa1b11cSDave Airlie DRM_DEBUG_KMS("could not create framebuffer\n"); 29824b096ac1SDaniel Vetter return PTR_ERR(fb); 2983308e5bcbSJesse Barnes } 2984308e5bcbSJesse Barnes 29854b096ac1SDaniel Vetter mutex_lock(&file_priv->fbs_lock); 2986308e5bcbSJesse Barnes or->fb_id = fb->base.id; 2987308e5bcbSJesse Barnes list_add(&fb->filp_head, &file_priv->fbs); 2988308e5bcbSJesse Barnes DRM_DEBUG_KMS("[FB:%d]\n", fb->base.id); 29894b096ac1SDaniel Vetter mutex_unlock(&file_priv->fbs_lock); 29904b096ac1SDaniel Vetter 2991308e5bcbSJesse Barnes return ret; 2992308e5bcbSJesse Barnes } 2993308e5bcbSJesse Barnes 2994cff91b62SVille Syrjälä static int format_check(const struct drm_mode_fb_cmd2 *r) 2995935b5977SVille Syrjälä { 2996935b5977SVille Syrjälä uint32_t format = r->pixel_format & ~DRM_FORMAT_BIG_ENDIAN; 2997935b5977SVille Syrjälä 2998935b5977SVille Syrjälä switch (format) { 2999935b5977SVille Syrjälä case DRM_FORMAT_C8: 3000935b5977SVille Syrjälä case DRM_FORMAT_RGB332: 3001935b5977SVille Syrjälä case DRM_FORMAT_BGR233: 3002935b5977SVille Syrjälä case DRM_FORMAT_XRGB4444: 3003935b5977SVille Syrjälä case DRM_FORMAT_XBGR4444: 3004935b5977SVille Syrjälä case DRM_FORMAT_RGBX4444: 3005935b5977SVille Syrjälä case DRM_FORMAT_BGRX4444: 3006935b5977SVille Syrjälä case DRM_FORMAT_ARGB4444: 3007935b5977SVille Syrjälä case DRM_FORMAT_ABGR4444: 3008935b5977SVille Syrjälä case DRM_FORMAT_RGBA4444: 3009935b5977SVille Syrjälä case DRM_FORMAT_BGRA4444: 3010935b5977SVille Syrjälä case DRM_FORMAT_XRGB1555: 3011935b5977SVille Syrjälä case DRM_FORMAT_XBGR1555: 3012935b5977SVille Syrjälä case DRM_FORMAT_RGBX5551: 3013935b5977SVille Syrjälä case DRM_FORMAT_BGRX5551: 3014935b5977SVille Syrjälä case DRM_FORMAT_ARGB1555: 3015935b5977SVille Syrjälä case DRM_FORMAT_ABGR1555: 3016935b5977SVille Syrjälä case DRM_FORMAT_RGBA5551: 3017935b5977SVille Syrjälä case DRM_FORMAT_BGRA5551: 3018935b5977SVille Syrjälä case DRM_FORMAT_RGB565: 3019935b5977SVille Syrjälä case DRM_FORMAT_BGR565: 3020935b5977SVille Syrjälä case DRM_FORMAT_RGB888: 3021935b5977SVille Syrjälä case DRM_FORMAT_BGR888: 3022935b5977SVille Syrjälä case DRM_FORMAT_XRGB8888: 3023935b5977SVille Syrjälä case DRM_FORMAT_XBGR8888: 3024935b5977SVille Syrjälä case DRM_FORMAT_RGBX8888: 3025935b5977SVille Syrjälä case DRM_FORMAT_BGRX8888: 3026935b5977SVille Syrjälä case DRM_FORMAT_ARGB8888: 3027935b5977SVille Syrjälä case DRM_FORMAT_ABGR8888: 3028935b5977SVille Syrjälä case DRM_FORMAT_RGBA8888: 3029935b5977SVille Syrjälä case DRM_FORMAT_BGRA8888: 3030935b5977SVille Syrjälä case DRM_FORMAT_XRGB2101010: 3031935b5977SVille Syrjälä case DRM_FORMAT_XBGR2101010: 3032935b5977SVille Syrjälä case DRM_FORMAT_RGBX1010102: 3033935b5977SVille Syrjälä case DRM_FORMAT_BGRX1010102: 3034935b5977SVille Syrjälä case DRM_FORMAT_ARGB2101010: 3035935b5977SVille Syrjälä case DRM_FORMAT_ABGR2101010: 3036935b5977SVille Syrjälä case DRM_FORMAT_RGBA1010102: 3037935b5977SVille Syrjälä case DRM_FORMAT_BGRA1010102: 3038935b5977SVille Syrjälä case DRM_FORMAT_YUYV: 3039935b5977SVille Syrjälä case DRM_FORMAT_YVYU: 3040935b5977SVille Syrjälä case DRM_FORMAT_UYVY: 3041935b5977SVille Syrjälä case DRM_FORMAT_VYUY: 3042935b5977SVille Syrjälä case DRM_FORMAT_AYUV: 3043935b5977SVille Syrjälä case DRM_FORMAT_NV12: 3044935b5977SVille Syrjälä case DRM_FORMAT_NV21: 3045935b5977SVille Syrjälä case DRM_FORMAT_NV16: 3046935b5977SVille Syrjälä case DRM_FORMAT_NV61: 3047ba623f6aSLaurent Pinchart case DRM_FORMAT_NV24: 3048ba623f6aSLaurent Pinchart case DRM_FORMAT_NV42: 3049935b5977SVille Syrjälä case DRM_FORMAT_YUV410: 3050935b5977SVille Syrjälä case DRM_FORMAT_YVU410: 3051935b5977SVille Syrjälä case DRM_FORMAT_YUV411: 3052935b5977SVille Syrjälä case DRM_FORMAT_YVU411: 3053935b5977SVille Syrjälä case DRM_FORMAT_YUV420: 3054935b5977SVille Syrjälä case DRM_FORMAT_YVU420: 3055935b5977SVille Syrjälä case DRM_FORMAT_YUV422: 3056935b5977SVille Syrjälä case DRM_FORMAT_YVU422: 3057935b5977SVille Syrjälä case DRM_FORMAT_YUV444: 3058935b5977SVille Syrjälä case DRM_FORMAT_YVU444: 3059935b5977SVille Syrjälä return 0; 3060935b5977SVille Syrjälä default: 306123c453a4SVille Syrjälä DRM_DEBUG_KMS("invalid pixel format %s\n", 306223c453a4SVille Syrjälä drm_get_format_name(r->pixel_format)); 3063935b5977SVille Syrjälä return -EINVAL; 3064935b5977SVille Syrjälä } 3065935b5977SVille Syrjälä } 3066935b5977SVille Syrjälä 3067cff91b62SVille Syrjälä static int framebuffer_check(const struct drm_mode_fb_cmd2 *r) 3068d1b45d5fSVille Syrjälä { 3069d1b45d5fSVille Syrjälä int ret, hsub, vsub, num_planes, i; 3070d1b45d5fSVille Syrjälä 3071d1b45d5fSVille Syrjälä ret = format_check(r); 3072d1b45d5fSVille Syrjälä if (ret) { 30736ba6d03eSVille Syrjälä DRM_DEBUG_KMS("bad framebuffer format %s\n", 30746ba6d03eSVille Syrjälä drm_get_format_name(r->pixel_format)); 3075d1b45d5fSVille Syrjälä return ret; 3076d1b45d5fSVille Syrjälä } 3077d1b45d5fSVille Syrjälä 3078d1b45d5fSVille Syrjälä hsub = drm_format_horz_chroma_subsampling(r->pixel_format); 3079d1b45d5fSVille Syrjälä vsub = drm_format_vert_chroma_subsampling(r->pixel_format); 3080d1b45d5fSVille Syrjälä num_planes = drm_format_num_planes(r->pixel_format); 3081d1b45d5fSVille Syrjälä 3082d1b45d5fSVille Syrjälä if (r->width == 0 || r->width % hsub) { 30831aa1b11cSDave Airlie DRM_DEBUG_KMS("bad framebuffer width %u\n", r->height); 3084d1b45d5fSVille Syrjälä return -EINVAL; 3085d1b45d5fSVille Syrjälä } 3086d1b45d5fSVille Syrjälä 3087d1b45d5fSVille Syrjälä if (r->height == 0 || r->height % vsub) { 30881aa1b11cSDave Airlie DRM_DEBUG_KMS("bad framebuffer height %u\n", r->height); 3089d1b45d5fSVille Syrjälä return -EINVAL; 3090d1b45d5fSVille Syrjälä } 3091d1b45d5fSVille Syrjälä 3092d1b45d5fSVille Syrjälä for (i = 0; i < num_planes; i++) { 3093d1b45d5fSVille Syrjälä unsigned int width = r->width / (i != 0 ? hsub : 1); 3094b180b5d1SVille Syrjälä unsigned int height = r->height / (i != 0 ? vsub : 1); 3095b180b5d1SVille Syrjälä unsigned int cpp = drm_format_plane_cpp(r->pixel_format, i); 3096d1b45d5fSVille Syrjälä 3097d1b45d5fSVille Syrjälä if (!r->handles[i]) { 30981aa1b11cSDave Airlie DRM_DEBUG_KMS("no buffer object handle for plane %d\n", i); 3099d1b45d5fSVille Syrjälä return -EINVAL; 3100d1b45d5fSVille Syrjälä } 3101d1b45d5fSVille Syrjälä 3102b180b5d1SVille Syrjälä if ((uint64_t) width * cpp > UINT_MAX) 3103b180b5d1SVille Syrjälä return -ERANGE; 3104b180b5d1SVille Syrjälä 3105b180b5d1SVille Syrjälä if ((uint64_t) height * r->pitches[i] + r->offsets[i] > UINT_MAX) 3106b180b5d1SVille Syrjälä return -ERANGE; 3107b180b5d1SVille Syrjälä 3108b180b5d1SVille Syrjälä if (r->pitches[i] < width * cpp) { 31091aa1b11cSDave Airlie DRM_DEBUG_KMS("bad pitch %u for plane %d\n", r->pitches[i], i); 3110d1b45d5fSVille Syrjälä return -EINVAL; 3111d1b45d5fSVille Syrjälä } 3112d1b45d5fSVille Syrjälä } 3113d1b45d5fSVille Syrjälä 3114d1b45d5fSVille Syrjälä return 0; 3115d1b45d5fSVille Syrjälä } 3116d1b45d5fSVille Syrjälä 3117c394c2b0SMatt Roper static struct drm_framebuffer *add_framebuffer_internal(struct drm_device *dev, 3118c394c2b0SMatt Roper struct drm_mode_fb_cmd2 *r, 3119c394c2b0SMatt Roper struct drm_file *file_priv) 3120c394c2b0SMatt Roper { 3121c394c2b0SMatt Roper struct drm_mode_config *config = &dev->mode_config; 3122c394c2b0SMatt Roper struct drm_framebuffer *fb; 3123c394c2b0SMatt Roper int ret; 3124c394c2b0SMatt Roper 3125c394c2b0SMatt Roper if (r->flags & ~DRM_MODE_FB_INTERLACED) { 3126c394c2b0SMatt Roper DRM_DEBUG_KMS("bad framebuffer flags 0x%08x\n", r->flags); 3127c394c2b0SMatt Roper return ERR_PTR(-EINVAL); 3128c394c2b0SMatt Roper } 3129c394c2b0SMatt Roper 3130c394c2b0SMatt Roper if ((config->min_width > r->width) || (r->width > config->max_width)) { 3131c394c2b0SMatt Roper DRM_DEBUG_KMS("bad framebuffer width %d, should be >= %d && <= %d\n", 3132c394c2b0SMatt Roper r->width, config->min_width, config->max_width); 3133c394c2b0SMatt Roper return ERR_PTR(-EINVAL); 3134c394c2b0SMatt Roper } 3135c394c2b0SMatt Roper if ((config->min_height > r->height) || (r->height > config->max_height)) { 3136c394c2b0SMatt Roper DRM_DEBUG_KMS("bad framebuffer height %d, should be >= %d && <= %d\n", 3137c394c2b0SMatt Roper r->height, config->min_height, config->max_height); 3138c394c2b0SMatt Roper return ERR_PTR(-EINVAL); 3139c394c2b0SMatt Roper } 3140c394c2b0SMatt Roper 3141c394c2b0SMatt Roper ret = framebuffer_check(r); 3142c394c2b0SMatt Roper if (ret) 3143c394c2b0SMatt Roper return ERR_PTR(ret); 3144c394c2b0SMatt Roper 3145c394c2b0SMatt Roper fb = dev->mode_config.funcs->fb_create(dev, file_priv, r); 3146c394c2b0SMatt Roper if (IS_ERR(fb)) { 3147c394c2b0SMatt Roper DRM_DEBUG_KMS("could not create framebuffer\n"); 3148c394c2b0SMatt Roper return fb; 3149c394c2b0SMatt Roper } 3150c394c2b0SMatt Roper 3151c394c2b0SMatt Roper mutex_lock(&file_priv->fbs_lock); 3152c394c2b0SMatt Roper r->fb_id = fb->base.id; 3153c394c2b0SMatt Roper list_add(&fb->filp_head, &file_priv->fbs); 3154c394c2b0SMatt Roper DRM_DEBUG_KMS("[FB:%d]\n", fb->base.id); 3155c394c2b0SMatt Roper mutex_unlock(&file_priv->fbs_lock); 3156c394c2b0SMatt Roper 3157c394c2b0SMatt Roper return fb; 3158c394c2b0SMatt Roper } 3159c394c2b0SMatt Roper 3160308e5bcbSJesse Barnes /** 3161308e5bcbSJesse Barnes * drm_mode_addfb2 - add an FB to the graphics configuration 3162065a50edSDaniel Vetter * @dev: drm device for the ioctl 3163065a50edSDaniel Vetter * @data: data pointer for the ioctl 3164065a50edSDaniel Vetter * @file_priv: drm file for the ioctl call 3165308e5bcbSJesse Barnes * 3166c8e32cc1SDaniel Vetter * Add a new FB to the specified CRTC, given a user request with format. This is 3167c8e32cc1SDaniel Vetter * the 2nd version of the addfb ioctl, which supports multi-planar framebuffers 3168c8e32cc1SDaniel Vetter * and uses fourcc codes as pixel format specifiers. 3169308e5bcbSJesse Barnes * 3170308e5bcbSJesse Barnes * Called by the user via ioctl. 3171308e5bcbSJesse Barnes * 3172c8e32cc1SDaniel Vetter * Returns: 3173308e5bcbSJesse Barnes * Zero on success, errno on failure. 3174308e5bcbSJesse Barnes */ 3175308e5bcbSJesse Barnes int drm_mode_addfb2(struct drm_device *dev, 3176308e5bcbSJesse Barnes void *data, struct drm_file *file_priv) 3177308e5bcbSJesse Barnes { 3178f453ba04SDave Airlie struct drm_framebuffer *fb; 3179f453ba04SDave Airlie 3180fb3b06c8SDave Airlie if (!drm_core_check_feature(dev, DRIVER_MODESET)) 3181fb3b06c8SDave Airlie return -EINVAL; 3182fb3b06c8SDave Airlie 3183c394c2b0SMatt Roper fb = add_framebuffer_internal(dev, data, file_priv); 3184c394c2b0SMatt Roper if (IS_ERR(fb)) 31854b096ac1SDaniel Vetter return PTR_ERR(fb); 3186f453ba04SDave Airlie 3187c394c2b0SMatt Roper return 0; 3188f453ba04SDave Airlie } 3189f453ba04SDave Airlie 3190f453ba04SDave Airlie /** 3191f453ba04SDave Airlie * drm_mode_rmfb - remove an FB from the configuration 3192065a50edSDaniel Vetter * @dev: drm device for the ioctl 3193065a50edSDaniel Vetter * @data: data pointer for the ioctl 3194065a50edSDaniel Vetter * @file_priv: drm file for the ioctl call 3195f453ba04SDave Airlie * 3196f453ba04SDave Airlie * Remove the FB specified by the user. 3197f453ba04SDave Airlie * 3198f453ba04SDave Airlie * Called by the user via ioctl. 3199f453ba04SDave Airlie * 3200c8e32cc1SDaniel Vetter * Returns: 3201f453ba04SDave Airlie * Zero on success, errno on failure. 3202f453ba04SDave Airlie */ 3203f453ba04SDave Airlie int drm_mode_rmfb(struct drm_device *dev, 3204f453ba04SDave Airlie void *data, struct drm_file *file_priv) 3205f453ba04SDave Airlie { 3206f453ba04SDave Airlie struct drm_framebuffer *fb = NULL; 3207f453ba04SDave Airlie struct drm_framebuffer *fbl = NULL; 3208f453ba04SDave Airlie uint32_t *id = data; 3209f453ba04SDave Airlie int found = 0; 3210f453ba04SDave Airlie 3211fb3b06c8SDave Airlie if (!drm_core_check_feature(dev, DRIVER_MODESET)) 3212fb3b06c8SDave Airlie return -EINVAL; 3213fb3b06c8SDave Airlie 32144b096ac1SDaniel Vetter mutex_lock(&file_priv->fbs_lock); 32152b677e8cSDaniel Vetter mutex_lock(&dev->mode_config.fb_lock); 32162b677e8cSDaniel Vetter fb = __drm_framebuffer_lookup(dev, *id); 32172b677e8cSDaniel Vetter if (!fb) 32182b677e8cSDaniel Vetter goto fail_lookup; 32192b677e8cSDaniel Vetter 3220f453ba04SDave Airlie list_for_each_entry(fbl, &file_priv->fbs, filp_head) 3221f453ba04SDave Airlie if (fb == fbl) 3222f453ba04SDave Airlie found = 1; 32232b677e8cSDaniel Vetter if (!found) 32242b677e8cSDaniel Vetter goto fail_lookup; 32252b677e8cSDaniel Vetter 32262b677e8cSDaniel Vetter /* Mark fb as reaped, we still have a ref from fpriv->fbs. */ 32272b677e8cSDaniel Vetter __drm_framebuffer_unregister(dev, fb); 3228f453ba04SDave Airlie 32294b096ac1SDaniel Vetter list_del_init(&fb->filp_head); 32302b677e8cSDaniel Vetter mutex_unlock(&dev->mode_config.fb_lock); 32314b096ac1SDaniel Vetter mutex_unlock(&file_priv->fbs_lock); 3232f453ba04SDave Airlie 32334b096ac1SDaniel Vetter drm_framebuffer_remove(fb); 32344b096ac1SDaniel Vetter 32352b677e8cSDaniel Vetter return 0; 32362b677e8cSDaniel Vetter 32372b677e8cSDaniel Vetter fail_lookup: 32382b677e8cSDaniel Vetter mutex_unlock(&dev->mode_config.fb_lock); 32392b677e8cSDaniel Vetter mutex_unlock(&file_priv->fbs_lock); 32402b677e8cSDaniel Vetter 324137c4e705SVille Syrjälä return -ENOENT; 3242f453ba04SDave Airlie } 3243f453ba04SDave Airlie 3244f453ba04SDave Airlie /** 3245f453ba04SDave Airlie * drm_mode_getfb - get FB info 3246065a50edSDaniel Vetter * @dev: drm device for the ioctl 3247065a50edSDaniel Vetter * @data: data pointer for the ioctl 3248065a50edSDaniel Vetter * @file_priv: drm file for the ioctl call 3249f453ba04SDave Airlie * 3250f453ba04SDave Airlie * Lookup the FB given its ID and return info about it. 3251f453ba04SDave Airlie * 3252f453ba04SDave Airlie * Called by the user via ioctl. 3253f453ba04SDave Airlie * 3254c8e32cc1SDaniel Vetter * Returns: 3255f453ba04SDave Airlie * Zero on success, errno on failure. 3256f453ba04SDave Airlie */ 3257f453ba04SDave Airlie int drm_mode_getfb(struct drm_device *dev, 3258f453ba04SDave Airlie void *data, struct drm_file *file_priv) 3259f453ba04SDave Airlie { 3260f453ba04SDave Airlie struct drm_mode_fb_cmd *r = data; 3261f453ba04SDave Airlie struct drm_framebuffer *fb; 326258c0dca1SDaniel Vetter int ret; 3263f453ba04SDave Airlie 3264fb3b06c8SDave Airlie if (!drm_core_check_feature(dev, DRIVER_MODESET)) 3265fb3b06c8SDave Airlie return -EINVAL; 3266fb3b06c8SDave Airlie 3267786b99edSDaniel Vetter fb = drm_framebuffer_lookup(dev, r->fb_id); 326858c0dca1SDaniel Vetter if (!fb) 326937c4e705SVille Syrjälä return -ENOENT; 3270f453ba04SDave Airlie 3271f453ba04SDave Airlie r->height = fb->height; 3272f453ba04SDave Airlie r->width = fb->width; 3273f453ba04SDave Airlie r->depth = fb->depth; 3274f453ba04SDave Airlie r->bpp = fb->bits_per_pixel; 327501f2c773SVille Syrjälä r->pitch = fb->pitches[0]; 3276101b96f3SDavid Herrmann if (fb->funcs->create_handle) { 327709f308f7SThomas Hellstrom if (file_priv->is_master || capable(CAP_SYS_ADMIN) || 327843683057SThomas Hellstrom drm_is_control_client(file_priv)) { 3279101b96f3SDavid Herrmann ret = fb->funcs->create_handle(fb, file_priv, 3280101b96f3SDavid Herrmann &r->handle); 3281101b96f3SDavid Herrmann } else { 3282101b96f3SDavid Herrmann /* GET_FB() is an unprivileged ioctl so we must not 3283101b96f3SDavid Herrmann * return a buffer-handle to non-master processes! For 3284101b96f3SDavid Herrmann * backwards-compatibility reasons, we cannot make 3285101b96f3SDavid Herrmann * GET_FB() privileged, so just return an invalid handle 3286101b96f3SDavid Herrmann * for non-masters. */ 3287101b96f3SDavid Herrmann r->handle = 0; 3288101b96f3SDavid Herrmann ret = 0; 3289101b96f3SDavid Herrmann } 3290101b96f3SDavid Herrmann } else { 3291af26ef3bSDaniel Vetter ret = -ENODEV; 3292101b96f3SDavid Herrmann } 3293f453ba04SDave Airlie 329458c0dca1SDaniel Vetter drm_framebuffer_unreference(fb); 329558c0dca1SDaniel Vetter 3296f453ba04SDave Airlie return ret; 3297f453ba04SDave Airlie } 3298f453ba04SDave Airlie 3299c8e32cc1SDaniel Vetter /** 3300c8e32cc1SDaniel Vetter * drm_mode_dirtyfb_ioctl - flush frontbuffer rendering on an FB 3301c8e32cc1SDaniel Vetter * @dev: drm device for the ioctl 3302c8e32cc1SDaniel Vetter * @data: data pointer for the ioctl 3303c8e32cc1SDaniel Vetter * @file_priv: drm file for the ioctl call 3304c8e32cc1SDaniel Vetter * 3305c8e32cc1SDaniel Vetter * Lookup the FB and flush out the damaged area supplied by userspace as a clip 3306c8e32cc1SDaniel Vetter * rectangle list. Generic userspace which does frontbuffer rendering must call 3307c8e32cc1SDaniel Vetter * this ioctl to flush out the changes on manual-update display outputs, e.g. 3308c8e32cc1SDaniel Vetter * usb display-link, mipi manual update panels or edp panel self refresh modes. 3309c8e32cc1SDaniel Vetter * 3310c8e32cc1SDaniel Vetter * Modesetting drivers which always update the frontbuffer do not need to 3311c8e32cc1SDaniel Vetter * implement the corresponding ->dirty framebuffer callback. 3312c8e32cc1SDaniel Vetter * 3313c8e32cc1SDaniel Vetter * Called by the user via ioctl. 3314c8e32cc1SDaniel Vetter * 3315c8e32cc1SDaniel Vetter * Returns: 3316c8e32cc1SDaniel Vetter * Zero on success, errno on failure. 3317c8e32cc1SDaniel Vetter */ 3318884840aaSJakob Bornecrantz int drm_mode_dirtyfb_ioctl(struct drm_device *dev, 3319884840aaSJakob Bornecrantz void *data, struct drm_file *file_priv) 3320884840aaSJakob Bornecrantz { 3321884840aaSJakob Bornecrantz struct drm_clip_rect __user *clips_ptr; 3322884840aaSJakob Bornecrantz struct drm_clip_rect *clips = NULL; 3323884840aaSJakob Bornecrantz struct drm_mode_fb_dirty_cmd *r = data; 3324884840aaSJakob Bornecrantz struct drm_framebuffer *fb; 3325884840aaSJakob Bornecrantz unsigned flags; 3326884840aaSJakob Bornecrantz int num_clips; 33274a1b0714SLaurent Pinchart int ret; 3328884840aaSJakob Bornecrantz 3329fb3b06c8SDave Airlie if (!drm_core_check_feature(dev, DRIVER_MODESET)) 3330fb3b06c8SDave Airlie return -EINVAL; 3331fb3b06c8SDave Airlie 3332786b99edSDaniel Vetter fb = drm_framebuffer_lookup(dev, r->fb_id); 33334ccf097fSDaniel Vetter if (!fb) 333437c4e705SVille Syrjälä return -ENOENT; 3335884840aaSJakob Bornecrantz 3336884840aaSJakob Bornecrantz num_clips = r->num_clips; 333781f6c7f8SVille Syrjälä clips_ptr = (struct drm_clip_rect __user *)(unsigned long)r->clips_ptr; 3338884840aaSJakob Bornecrantz 3339884840aaSJakob Bornecrantz if (!num_clips != !clips_ptr) { 3340884840aaSJakob Bornecrantz ret = -EINVAL; 3341884840aaSJakob Bornecrantz goto out_err1; 3342884840aaSJakob Bornecrantz } 3343884840aaSJakob Bornecrantz 3344884840aaSJakob Bornecrantz flags = DRM_MODE_FB_DIRTY_FLAGS & r->flags; 3345884840aaSJakob Bornecrantz 3346884840aaSJakob Bornecrantz /* If userspace annotates copy, clips must come in pairs */ 3347884840aaSJakob Bornecrantz if (flags & DRM_MODE_FB_DIRTY_ANNOTATE_COPY && (num_clips % 2)) { 3348884840aaSJakob Bornecrantz ret = -EINVAL; 3349884840aaSJakob Bornecrantz goto out_err1; 3350884840aaSJakob Bornecrantz } 3351884840aaSJakob Bornecrantz 3352884840aaSJakob Bornecrantz if (num_clips && clips_ptr) { 3353a5cd3351SXi Wang if (num_clips < 0 || num_clips > DRM_MODE_FB_DIRTY_MAX_CLIPS) { 3354a5cd3351SXi Wang ret = -EINVAL; 3355a5cd3351SXi Wang goto out_err1; 3356a5cd3351SXi Wang } 3357884840aaSJakob Bornecrantz clips = kzalloc(num_clips * sizeof(*clips), GFP_KERNEL); 3358884840aaSJakob Bornecrantz if (!clips) { 3359884840aaSJakob Bornecrantz ret = -ENOMEM; 3360884840aaSJakob Bornecrantz goto out_err1; 3361884840aaSJakob Bornecrantz } 3362884840aaSJakob Bornecrantz 3363884840aaSJakob Bornecrantz ret = copy_from_user(clips, clips_ptr, 3364884840aaSJakob Bornecrantz num_clips * sizeof(*clips)); 3365e902a358SDan Carpenter if (ret) { 3366e902a358SDan Carpenter ret = -EFAULT; 3367884840aaSJakob Bornecrantz goto out_err2; 3368884840aaSJakob Bornecrantz } 3369e902a358SDan Carpenter } 3370884840aaSJakob Bornecrantz 3371884840aaSJakob Bornecrantz if (fb->funcs->dirty) { 337202b00162SThomas Hellstrom ret = fb->funcs->dirty(fb, file_priv, flags, r->color, 337302b00162SThomas Hellstrom clips, num_clips); 3374884840aaSJakob Bornecrantz } else { 3375884840aaSJakob Bornecrantz ret = -ENOSYS; 3376884840aaSJakob Bornecrantz } 3377884840aaSJakob Bornecrantz 3378884840aaSJakob Bornecrantz out_err2: 3379884840aaSJakob Bornecrantz kfree(clips); 3380884840aaSJakob Bornecrantz out_err1: 33814ccf097fSDaniel Vetter drm_framebuffer_unreference(fb); 33824ccf097fSDaniel Vetter 3383884840aaSJakob Bornecrantz return ret; 3384884840aaSJakob Bornecrantz } 3385884840aaSJakob Bornecrantz 3386884840aaSJakob Bornecrantz 3387f453ba04SDave Airlie /** 3388f453ba04SDave Airlie * drm_fb_release - remove and free the FBs on this file 3389065a50edSDaniel Vetter * @priv: drm file for the ioctl 3390f453ba04SDave Airlie * 3391f453ba04SDave Airlie * Destroy all the FBs associated with @filp. 3392f453ba04SDave Airlie * 3393f453ba04SDave Airlie * Called by the user via ioctl. 3394f453ba04SDave Airlie * 3395c8e32cc1SDaniel Vetter * Returns: 3396f453ba04SDave Airlie * Zero on success, errno on failure. 3397f453ba04SDave Airlie */ 3398ea39f835SKristian Høgsberg void drm_fb_release(struct drm_file *priv) 3399f453ba04SDave Airlie { 3400f453ba04SDave Airlie struct drm_device *dev = priv->minor->dev; 3401f453ba04SDave Airlie struct drm_framebuffer *fb, *tfb; 3402f453ba04SDave Airlie 34031b116297SDaniel Vetter /* 34041b116297SDaniel Vetter * When the file gets released that means no one else can access the fb 34051b116297SDaniel Vetter * list any more, so no need to grab fpriv->fbs_lock. And we need to to 34061b116297SDaniel Vetter * avoid upsetting lockdep since the universal cursor code adds a 34071b116297SDaniel Vetter * framebuffer while holding mutex locks. 34081b116297SDaniel Vetter * 34091b116297SDaniel Vetter * Note that a real deadlock between fpriv->fbs_lock and the modeset 34101b116297SDaniel Vetter * locks is impossible here since no one else but this function can get 34111b116297SDaniel Vetter * at it any more. 34121b116297SDaniel Vetter */ 3413f453ba04SDave Airlie list_for_each_entry_safe(fb, tfb, &priv->fbs, filp_head) { 34142b677e8cSDaniel Vetter 34152b677e8cSDaniel Vetter mutex_lock(&dev->mode_config.fb_lock); 34162b677e8cSDaniel Vetter /* Mark fb as reaped, we still have a ref from fpriv->fbs. */ 34172b677e8cSDaniel Vetter __drm_framebuffer_unregister(dev, fb); 34182b677e8cSDaniel Vetter mutex_unlock(&dev->mode_config.fb_lock); 34192b677e8cSDaniel Vetter 34204b096ac1SDaniel Vetter list_del_init(&fb->filp_head); 34212b677e8cSDaniel Vetter 34222b677e8cSDaniel Vetter /* This will also drop the fpriv->fbs reference. */ 3423f7eff60eSRob Clark drm_framebuffer_remove(fb); 3424f453ba04SDave Airlie } 3425f453ba04SDave Airlie } 3426f453ba04SDave Airlie 3427c8e32cc1SDaniel Vetter /** 3428c8e32cc1SDaniel Vetter * drm_property_create - create a new property type 3429c8e32cc1SDaniel Vetter * @dev: drm device 3430c8e32cc1SDaniel Vetter * @flags: flags specifying the property type 3431c8e32cc1SDaniel Vetter * @name: name of the property 3432c8e32cc1SDaniel Vetter * @num_values: number of pre-defined values 3433c8e32cc1SDaniel Vetter * 3434c8e32cc1SDaniel Vetter * This creates a new generic drm property which can then be attached to a drm 3435c8e32cc1SDaniel Vetter * object with drm_object_attach_property. The returned property object must be 3436c8e32cc1SDaniel Vetter * freed with drm_property_destroy. 3437c8e32cc1SDaniel Vetter * 3438c8e32cc1SDaniel Vetter * Returns: 3439c8e32cc1SDaniel Vetter * A pointer to the newly created property on success, NULL on failure. 3440c8e32cc1SDaniel Vetter */ 3441f453ba04SDave Airlie struct drm_property *drm_property_create(struct drm_device *dev, int flags, 3442f453ba04SDave Airlie const char *name, int num_values) 3443f453ba04SDave Airlie { 3444f453ba04SDave Airlie struct drm_property *property = NULL; 34456bfc56aaSVille Syrjälä int ret; 3446f453ba04SDave Airlie 3447f453ba04SDave Airlie property = kzalloc(sizeof(struct drm_property), GFP_KERNEL); 3448f453ba04SDave Airlie if (!property) 3449f453ba04SDave Airlie return NULL; 3450f453ba04SDave Airlie 345198f75de4SRob Clark property->dev = dev; 345298f75de4SRob Clark 3453f453ba04SDave Airlie if (num_values) { 3454f453ba04SDave Airlie property->values = kzalloc(sizeof(uint64_t)*num_values, GFP_KERNEL); 3455f453ba04SDave Airlie if (!property->values) 3456f453ba04SDave Airlie goto fail; 3457f453ba04SDave Airlie } 3458f453ba04SDave Airlie 34596bfc56aaSVille Syrjälä ret = drm_mode_object_get(dev, &property->base, DRM_MODE_OBJECT_PROPERTY); 34606bfc56aaSVille Syrjälä if (ret) 34616bfc56aaSVille Syrjälä goto fail; 34626bfc56aaSVille Syrjälä 3463f453ba04SDave Airlie property->flags = flags; 3464f453ba04SDave Airlie property->num_values = num_values; 3465f453ba04SDave Airlie INIT_LIST_HEAD(&property->enum_blob_list); 3466f453ba04SDave Airlie 3467471dd2efSVinson Lee if (name) { 3468f453ba04SDave Airlie strncpy(property->name, name, DRM_PROP_NAME_LEN); 3469471dd2efSVinson Lee property->name[DRM_PROP_NAME_LEN-1] = '\0'; 3470471dd2efSVinson Lee } 3471f453ba04SDave Airlie 3472f453ba04SDave Airlie list_add_tail(&property->head, &dev->mode_config.property_list); 34735ea22f24SRob Clark 34745ea22f24SRob Clark WARN_ON(!drm_property_type_valid(property)); 34755ea22f24SRob Clark 3476f453ba04SDave Airlie return property; 3477f453ba04SDave Airlie fail: 34786bfc56aaSVille Syrjälä kfree(property->values); 3479f453ba04SDave Airlie kfree(property); 3480f453ba04SDave Airlie return NULL; 3481f453ba04SDave Airlie } 3482f453ba04SDave Airlie EXPORT_SYMBOL(drm_property_create); 3483f453ba04SDave Airlie 3484c8e32cc1SDaniel Vetter /** 34852aa9d2bcSThierry Reding * drm_property_create_enum - create a new enumeration property type 3486c8e32cc1SDaniel Vetter * @dev: drm device 3487c8e32cc1SDaniel Vetter * @flags: flags specifying the property type 3488c8e32cc1SDaniel Vetter * @name: name of the property 3489c8e32cc1SDaniel Vetter * @props: enumeration lists with property values 3490c8e32cc1SDaniel Vetter * @num_values: number of pre-defined values 3491c8e32cc1SDaniel Vetter * 3492c8e32cc1SDaniel Vetter * This creates a new generic drm property which can then be attached to a drm 3493c8e32cc1SDaniel Vetter * object with drm_object_attach_property. The returned property object must be 3494c8e32cc1SDaniel Vetter * freed with drm_property_destroy. 3495c8e32cc1SDaniel Vetter * 3496c8e32cc1SDaniel Vetter * Userspace is only allowed to set one of the predefined values for enumeration 3497c8e32cc1SDaniel Vetter * properties. 3498c8e32cc1SDaniel Vetter * 3499c8e32cc1SDaniel Vetter * Returns: 3500c8e32cc1SDaniel Vetter * A pointer to the newly created property on success, NULL on failure. 3501c8e32cc1SDaniel Vetter */ 35024a67d391SSascha Hauer struct drm_property *drm_property_create_enum(struct drm_device *dev, int flags, 35034a67d391SSascha Hauer const char *name, 35044a67d391SSascha Hauer const struct drm_prop_enum_list *props, 35054a67d391SSascha Hauer int num_values) 35064a67d391SSascha Hauer { 35074a67d391SSascha Hauer struct drm_property *property; 35084a67d391SSascha Hauer int i, ret; 35094a67d391SSascha Hauer 35104a67d391SSascha Hauer flags |= DRM_MODE_PROP_ENUM; 35114a67d391SSascha Hauer 35124a67d391SSascha Hauer property = drm_property_create(dev, flags, name, num_values); 35134a67d391SSascha Hauer if (!property) 35144a67d391SSascha Hauer return NULL; 35154a67d391SSascha Hauer 35164a67d391SSascha Hauer for (i = 0; i < num_values; i++) { 35174a67d391SSascha Hauer ret = drm_property_add_enum(property, i, 35184a67d391SSascha Hauer props[i].type, 35194a67d391SSascha Hauer props[i].name); 35204a67d391SSascha Hauer if (ret) { 35214a67d391SSascha Hauer drm_property_destroy(dev, property); 35224a67d391SSascha Hauer return NULL; 35234a67d391SSascha Hauer } 35244a67d391SSascha Hauer } 35254a67d391SSascha Hauer 35264a67d391SSascha Hauer return property; 35274a67d391SSascha Hauer } 35284a67d391SSascha Hauer EXPORT_SYMBOL(drm_property_create_enum); 35294a67d391SSascha Hauer 3530c8e32cc1SDaniel Vetter /** 35312aa9d2bcSThierry Reding * drm_property_create_bitmask - create a new bitmask property type 3532c8e32cc1SDaniel Vetter * @dev: drm device 3533c8e32cc1SDaniel Vetter * @flags: flags specifying the property type 3534c8e32cc1SDaniel Vetter * @name: name of the property 3535c8e32cc1SDaniel Vetter * @props: enumeration lists with property bitflags 3536295ee853SDaniel Vetter * @num_props: size of the @props array 3537295ee853SDaniel Vetter * @supported_bits: bitmask of all supported enumeration values 3538c8e32cc1SDaniel Vetter * 3539295ee853SDaniel Vetter * This creates a new bitmask drm property which can then be attached to a drm 3540c8e32cc1SDaniel Vetter * object with drm_object_attach_property. The returned property object must be 3541c8e32cc1SDaniel Vetter * freed with drm_property_destroy. 3542c8e32cc1SDaniel Vetter * 3543c8e32cc1SDaniel Vetter * Compared to plain enumeration properties userspace is allowed to set any 3544c8e32cc1SDaniel Vetter * or'ed together combination of the predefined property bitflag values 3545c8e32cc1SDaniel Vetter * 3546c8e32cc1SDaniel Vetter * Returns: 3547c8e32cc1SDaniel Vetter * A pointer to the newly created property on success, NULL on failure. 3548c8e32cc1SDaniel Vetter */ 354949e27545SRob Clark struct drm_property *drm_property_create_bitmask(struct drm_device *dev, 355049e27545SRob Clark int flags, const char *name, 355149e27545SRob Clark const struct drm_prop_enum_list *props, 35527689ffb3SVille Syrjälä int num_props, 35537689ffb3SVille Syrjälä uint64_t supported_bits) 355449e27545SRob Clark { 355549e27545SRob Clark struct drm_property *property; 35567689ffb3SVille Syrjälä int i, ret, index = 0; 35577689ffb3SVille Syrjälä int num_values = hweight64(supported_bits); 355849e27545SRob Clark 355949e27545SRob Clark flags |= DRM_MODE_PROP_BITMASK; 356049e27545SRob Clark 356149e27545SRob Clark property = drm_property_create(dev, flags, name, num_values); 356249e27545SRob Clark if (!property) 356349e27545SRob Clark return NULL; 35647689ffb3SVille Syrjälä for (i = 0; i < num_props; i++) { 35657689ffb3SVille Syrjälä if (!(supported_bits & (1ULL << props[i].type))) 35667689ffb3SVille Syrjälä continue; 356749e27545SRob Clark 35687689ffb3SVille Syrjälä if (WARN_ON(index >= num_values)) { 35697689ffb3SVille Syrjälä drm_property_destroy(dev, property); 35707689ffb3SVille Syrjälä return NULL; 35717689ffb3SVille Syrjälä } 35727689ffb3SVille Syrjälä 35737689ffb3SVille Syrjälä ret = drm_property_add_enum(property, index++, 357449e27545SRob Clark props[i].type, 357549e27545SRob Clark props[i].name); 357649e27545SRob Clark if (ret) { 357749e27545SRob Clark drm_property_destroy(dev, property); 357849e27545SRob Clark return NULL; 357949e27545SRob Clark } 358049e27545SRob Clark } 358149e27545SRob Clark 358249e27545SRob Clark return property; 358349e27545SRob Clark } 358449e27545SRob Clark EXPORT_SYMBOL(drm_property_create_bitmask); 358549e27545SRob Clark 3586ebc44cf3SRob Clark static struct drm_property *property_create_range(struct drm_device *dev, 3587ebc44cf3SRob Clark int flags, const char *name, 3588ebc44cf3SRob Clark uint64_t min, uint64_t max) 3589ebc44cf3SRob Clark { 3590ebc44cf3SRob Clark struct drm_property *property; 3591ebc44cf3SRob Clark 3592ebc44cf3SRob Clark property = drm_property_create(dev, flags, name, 2); 3593ebc44cf3SRob Clark if (!property) 3594ebc44cf3SRob Clark return NULL; 3595ebc44cf3SRob Clark 3596ebc44cf3SRob Clark property->values[0] = min; 3597ebc44cf3SRob Clark property->values[1] = max; 3598ebc44cf3SRob Clark 3599ebc44cf3SRob Clark return property; 3600ebc44cf3SRob Clark } 3601ebc44cf3SRob Clark 3602c8e32cc1SDaniel Vetter /** 36032aa9d2bcSThierry Reding * drm_property_create_range - create a new ranged property type 3604c8e32cc1SDaniel Vetter * @dev: drm device 3605c8e32cc1SDaniel Vetter * @flags: flags specifying the property type 3606c8e32cc1SDaniel Vetter * @name: name of the property 3607c8e32cc1SDaniel Vetter * @min: minimum value of the property 3608c8e32cc1SDaniel Vetter * @max: maximum value of the property 3609c8e32cc1SDaniel Vetter * 3610c8e32cc1SDaniel Vetter * This creates a new generic drm property which can then be attached to a drm 3611c8e32cc1SDaniel Vetter * object with drm_object_attach_property. The returned property object must be 3612c8e32cc1SDaniel Vetter * freed with drm_property_destroy. 3613c8e32cc1SDaniel Vetter * 361432197aabSMasanari Iida * Userspace is allowed to set any integer value in the (min, max) range 3615c8e32cc1SDaniel Vetter * inclusive. 3616c8e32cc1SDaniel Vetter * 3617c8e32cc1SDaniel Vetter * Returns: 3618c8e32cc1SDaniel Vetter * A pointer to the newly created property on success, NULL on failure. 3619c8e32cc1SDaniel Vetter */ 3620d9bc3c02SSascha Hauer struct drm_property *drm_property_create_range(struct drm_device *dev, int flags, 3621d9bc3c02SSascha Hauer const char *name, 3622d9bc3c02SSascha Hauer uint64_t min, uint64_t max) 3623d9bc3c02SSascha Hauer { 3624ebc44cf3SRob Clark return property_create_range(dev, DRM_MODE_PROP_RANGE | flags, 3625ebc44cf3SRob Clark name, min, max); 3626d9bc3c02SSascha Hauer } 3627d9bc3c02SSascha Hauer EXPORT_SYMBOL(drm_property_create_range); 3628d9bc3c02SSascha Hauer 3629ebc44cf3SRob Clark struct drm_property *drm_property_create_signed_range(struct drm_device *dev, 3630ebc44cf3SRob Clark int flags, const char *name, 3631ebc44cf3SRob Clark int64_t min, int64_t max) 3632ebc44cf3SRob Clark { 3633ebc44cf3SRob Clark return property_create_range(dev, DRM_MODE_PROP_SIGNED_RANGE | flags, 3634ebc44cf3SRob Clark name, I642U64(min), I642U64(max)); 3635ebc44cf3SRob Clark } 3636ebc44cf3SRob Clark EXPORT_SYMBOL(drm_property_create_signed_range); 3637ebc44cf3SRob Clark 363898f75de4SRob Clark struct drm_property *drm_property_create_object(struct drm_device *dev, 363998f75de4SRob Clark int flags, const char *name, uint32_t type) 364098f75de4SRob Clark { 364198f75de4SRob Clark struct drm_property *property; 364298f75de4SRob Clark 364398f75de4SRob Clark flags |= DRM_MODE_PROP_OBJECT; 364498f75de4SRob Clark 364598f75de4SRob Clark property = drm_property_create(dev, flags, name, 1); 364698f75de4SRob Clark if (!property) 364798f75de4SRob Clark return NULL; 364898f75de4SRob Clark 364998f75de4SRob Clark property->values[0] = type; 365098f75de4SRob Clark 365198f75de4SRob Clark return property; 365298f75de4SRob Clark } 365398f75de4SRob Clark EXPORT_SYMBOL(drm_property_create_object); 365498f75de4SRob Clark 3655c8e32cc1SDaniel Vetter /** 3656c8e32cc1SDaniel Vetter * drm_property_add_enum - add a possible value to an enumeration property 3657c8e32cc1SDaniel Vetter * @property: enumeration property to change 3658c8e32cc1SDaniel Vetter * @index: index of the new enumeration 3659c8e32cc1SDaniel Vetter * @value: value of the new enumeration 3660c8e32cc1SDaniel Vetter * @name: symbolic name of the new enumeration 3661c8e32cc1SDaniel Vetter * 3662c8e32cc1SDaniel Vetter * This functions adds enumerations to a property. 3663c8e32cc1SDaniel Vetter * 3664c8e32cc1SDaniel Vetter * It's use is deprecated, drivers should use one of the more specific helpers 3665c8e32cc1SDaniel Vetter * to directly create the property with all enumerations already attached. 3666c8e32cc1SDaniel Vetter * 3667c8e32cc1SDaniel Vetter * Returns: 3668c8e32cc1SDaniel Vetter * Zero on success, error code on failure. 3669c8e32cc1SDaniel Vetter */ 3670f453ba04SDave Airlie int drm_property_add_enum(struct drm_property *property, int index, 3671f453ba04SDave Airlie uint64_t value, const char *name) 3672f453ba04SDave Airlie { 3673f453ba04SDave Airlie struct drm_property_enum *prop_enum; 3674f453ba04SDave Airlie 36755ea22f24SRob Clark if (!(drm_property_type_is(property, DRM_MODE_PROP_ENUM) || 36765ea22f24SRob Clark drm_property_type_is(property, DRM_MODE_PROP_BITMASK))) 367749e27545SRob Clark return -EINVAL; 367849e27545SRob Clark 367949e27545SRob Clark /* 368049e27545SRob Clark * Bitmask enum properties have the additional constraint of values 368149e27545SRob Clark * from 0 to 63 368249e27545SRob Clark */ 36835ea22f24SRob Clark if (drm_property_type_is(property, DRM_MODE_PROP_BITMASK) && 36845ea22f24SRob Clark (value > 63)) 3685f453ba04SDave Airlie return -EINVAL; 3686f453ba04SDave Airlie 3687f453ba04SDave Airlie if (!list_empty(&property->enum_blob_list)) { 3688f453ba04SDave Airlie list_for_each_entry(prop_enum, &property->enum_blob_list, head) { 3689f453ba04SDave Airlie if (prop_enum->value == value) { 3690f453ba04SDave Airlie strncpy(prop_enum->name, name, DRM_PROP_NAME_LEN); 3691f453ba04SDave Airlie prop_enum->name[DRM_PROP_NAME_LEN-1] = '\0'; 3692f453ba04SDave Airlie return 0; 3693f453ba04SDave Airlie } 3694f453ba04SDave Airlie } 3695f453ba04SDave Airlie } 3696f453ba04SDave Airlie 3697f453ba04SDave Airlie prop_enum = kzalloc(sizeof(struct drm_property_enum), GFP_KERNEL); 3698f453ba04SDave Airlie if (!prop_enum) 3699f453ba04SDave Airlie return -ENOMEM; 3700f453ba04SDave Airlie 3701f453ba04SDave Airlie strncpy(prop_enum->name, name, DRM_PROP_NAME_LEN); 3702f453ba04SDave Airlie prop_enum->name[DRM_PROP_NAME_LEN-1] = '\0'; 3703f453ba04SDave Airlie prop_enum->value = value; 3704f453ba04SDave Airlie 3705f453ba04SDave Airlie property->values[index] = value; 3706f453ba04SDave Airlie list_add_tail(&prop_enum->head, &property->enum_blob_list); 3707f453ba04SDave Airlie return 0; 3708f453ba04SDave Airlie } 3709f453ba04SDave Airlie EXPORT_SYMBOL(drm_property_add_enum); 3710f453ba04SDave Airlie 3711c8e32cc1SDaniel Vetter /** 3712c8e32cc1SDaniel Vetter * drm_property_destroy - destroy a drm property 3713c8e32cc1SDaniel Vetter * @dev: drm device 3714c8e32cc1SDaniel Vetter * @property: property to destry 3715c8e32cc1SDaniel Vetter * 3716c8e32cc1SDaniel Vetter * This function frees a property including any attached resources like 3717c8e32cc1SDaniel Vetter * enumeration values. 3718c8e32cc1SDaniel Vetter */ 3719f453ba04SDave Airlie void drm_property_destroy(struct drm_device *dev, struct drm_property *property) 3720f453ba04SDave Airlie { 3721f453ba04SDave Airlie struct drm_property_enum *prop_enum, *pt; 3722f453ba04SDave Airlie 3723f453ba04SDave Airlie list_for_each_entry_safe(prop_enum, pt, &property->enum_blob_list, head) { 3724f453ba04SDave Airlie list_del(&prop_enum->head); 3725f453ba04SDave Airlie kfree(prop_enum); 3726f453ba04SDave Airlie } 3727f453ba04SDave Airlie 3728f453ba04SDave Airlie if (property->num_values) 3729f453ba04SDave Airlie kfree(property->values); 3730f453ba04SDave Airlie drm_mode_object_put(dev, &property->base); 3731f453ba04SDave Airlie list_del(&property->head); 3732f453ba04SDave Airlie kfree(property); 3733f453ba04SDave Airlie } 3734f453ba04SDave Airlie EXPORT_SYMBOL(drm_property_destroy); 3735f453ba04SDave Airlie 3736c8e32cc1SDaniel Vetter /** 3737c8e32cc1SDaniel Vetter * drm_object_attach_property - attach a property to a modeset object 3738c8e32cc1SDaniel Vetter * @obj: drm modeset object 3739c8e32cc1SDaniel Vetter * @property: property to attach 3740c8e32cc1SDaniel Vetter * @init_val: initial value of the property 3741c8e32cc1SDaniel Vetter * 3742c8e32cc1SDaniel Vetter * This attaches the given property to the modeset object with the given initial 3743c8e32cc1SDaniel Vetter * value. Currently this function cannot fail since the properties are stored in 3744c8e32cc1SDaniel Vetter * a statically sized array. 3745c8e32cc1SDaniel Vetter */ 3746c543188aSPaulo Zanoni void drm_object_attach_property(struct drm_mode_object *obj, 3747c543188aSPaulo Zanoni struct drm_property *property, 3748c543188aSPaulo Zanoni uint64_t init_val) 3749c543188aSPaulo Zanoni { 37507f88a9beSPaulo Zanoni int count = obj->properties->count; 3751c543188aSPaulo Zanoni 37527f88a9beSPaulo Zanoni if (count == DRM_OBJECT_MAX_PROPERTY) { 37537f88a9beSPaulo Zanoni WARN(1, "Failed to attach object property (type: 0x%x). Please " 37547f88a9beSPaulo Zanoni "increase DRM_OBJECT_MAX_PROPERTY by 1 for each time " 37557f88a9beSPaulo Zanoni "you see this message on the same object type.\n", 37567f88a9beSPaulo Zanoni obj->type); 3757c543188aSPaulo Zanoni return; 3758c543188aSPaulo Zanoni } 3759c543188aSPaulo Zanoni 37607f88a9beSPaulo Zanoni obj->properties->ids[count] = property->base.id; 37617f88a9beSPaulo Zanoni obj->properties->values[count] = init_val; 37627f88a9beSPaulo Zanoni obj->properties->count++; 3763c543188aSPaulo Zanoni } 3764c543188aSPaulo Zanoni EXPORT_SYMBOL(drm_object_attach_property); 3765c543188aSPaulo Zanoni 3766c8e32cc1SDaniel Vetter /** 3767c8e32cc1SDaniel Vetter * drm_object_property_set_value - set the value of a property 3768c8e32cc1SDaniel Vetter * @obj: drm mode object to set property value for 3769c8e32cc1SDaniel Vetter * @property: property to set 3770c8e32cc1SDaniel Vetter * @val: value the property should be set to 3771c8e32cc1SDaniel Vetter * 3772c8e32cc1SDaniel Vetter * This functions sets a given property on a given object. This function only 3773c8e32cc1SDaniel Vetter * changes the software state of the property, it does not call into the 3774c8e32cc1SDaniel Vetter * driver's ->set_property callback. 3775c8e32cc1SDaniel Vetter * 3776c8e32cc1SDaniel Vetter * Returns: 3777c8e32cc1SDaniel Vetter * Zero on success, error code on failure. 3778c8e32cc1SDaniel Vetter */ 3779c543188aSPaulo Zanoni int drm_object_property_set_value(struct drm_mode_object *obj, 3780c543188aSPaulo Zanoni struct drm_property *property, uint64_t val) 3781c543188aSPaulo Zanoni { 3782c543188aSPaulo Zanoni int i; 3783c543188aSPaulo Zanoni 37847f88a9beSPaulo Zanoni for (i = 0; i < obj->properties->count; i++) { 3785c543188aSPaulo Zanoni if (obj->properties->ids[i] == property->base.id) { 3786c543188aSPaulo Zanoni obj->properties->values[i] = val; 3787c543188aSPaulo Zanoni return 0; 3788c543188aSPaulo Zanoni } 3789c543188aSPaulo Zanoni } 3790c543188aSPaulo Zanoni 3791c543188aSPaulo Zanoni return -EINVAL; 3792c543188aSPaulo Zanoni } 3793c543188aSPaulo Zanoni EXPORT_SYMBOL(drm_object_property_set_value); 3794c543188aSPaulo Zanoni 3795c8e32cc1SDaniel Vetter /** 3796c8e32cc1SDaniel Vetter * drm_object_property_get_value - retrieve the value of a property 3797c8e32cc1SDaniel Vetter * @obj: drm mode object to get property value from 3798c8e32cc1SDaniel Vetter * @property: property to retrieve 3799c8e32cc1SDaniel Vetter * @val: storage for the property value 3800c8e32cc1SDaniel Vetter * 3801c8e32cc1SDaniel Vetter * This function retrieves the softare state of the given property for the given 3802c8e32cc1SDaniel Vetter * property. Since there is no driver callback to retrieve the current property 3803c8e32cc1SDaniel Vetter * value this might be out of sync with the hardware, depending upon the driver 3804c8e32cc1SDaniel Vetter * and property. 3805c8e32cc1SDaniel Vetter * 3806c8e32cc1SDaniel Vetter * Returns: 3807c8e32cc1SDaniel Vetter * Zero on success, error code on failure. 3808c8e32cc1SDaniel Vetter */ 3809c543188aSPaulo Zanoni int drm_object_property_get_value(struct drm_mode_object *obj, 3810c543188aSPaulo Zanoni struct drm_property *property, uint64_t *val) 3811c543188aSPaulo Zanoni { 3812c543188aSPaulo Zanoni int i; 3813c543188aSPaulo Zanoni 38147f88a9beSPaulo Zanoni for (i = 0; i < obj->properties->count; i++) { 3815c543188aSPaulo Zanoni if (obj->properties->ids[i] == property->base.id) { 3816c543188aSPaulo Zanoni *val = obj->properties->values[i]; 3817c543188aSPaulo Zanoni return 0; 3818c543188aSPaulo Zanoni } 3819c543188aSPaulo Zanoni } 3820c543188aSPaulo Zanoni 3821c543188aSPaulo Zanoni return -EINVAL; 3822c543188aSPaulo Zanoni } 3823c543188aSPaulo Zanoni EXPORT_SYMBOL(drm_object_property_get_value); 3824c543188aSPaulo Zanoni 3825c8e32cc1SDaniel Vetter /** 3826c8e32cc1SDaniel Vetter * drm_mode_getproperty_ioctl - get the current value of a connector's property 3827c8e32cc1SDaniel Vetter * @dev: DRM device 3828c8e32cc1SDaniel Vetter * @data: ioctl data 3829c8e32cc1SDaniel Vetter * @file_priv: DRM file info 3830c8e32cc1SDaniel Vetter * 3831c8e32cc1SDaniel Vetter * This function retrieves the current value for an connectors's property. 3832c8e32cc1SDaniel Vetter * 3833c8e32cc1SDaniel Vetter * Called by the user via ioctl. 3834c8e32cc1SDaniel Vetter * 3835c8e32cc1SDaniel Vetter * Returns: 3836c8e32cc1SDaniel Vetter * Zero on success, errno on failure. 3837c8e32cc1SDaniel Vetter */ 3838f453ba04SDave Airlie int drm_mode_getproperty_ioctl(struct drm_device *dev, 3839f453ba04SDave Airlie void *data, struct drm_file *file_priv) 3840f453ba04SDave Airlie { 3841f453ba04SDave Airlie struct drm_mode_get_property *out_resp = data; 3842f453ba04SDave Airlie struct drm_property *property; 3843f453ba04SDave Airlie int enum_count = 0; 3844f453ba04SDave Airlie int blob_count = 0; 3845f453ba04SDave Airlie int value_count = 0; 3846f453ba04SDave Airlie int ret = 0, i; 3847f453ba04SDave Airlie int copied; 3848f453ba04SDave Airlie struct drm_property_enum *prop_enum; 3849f453ba04SDave Airlie struct drm_mode_property_enum __user *enum_ptr; 3850f453ba04SDave Airlie struct drm_property_blob *prop_blob; 385181f6c7f8SVille Syrjälä uint32_t __user *blob_id_ptr; 3852f453ba04SDave Airlie uint64_t __user *values_ptr; 3853f453ba04SDave Airlie uint32_t __user *blob_length_ptr; 3854f453ba04SDave Airlie 3855fb3b06c8SDave Airlie if (!drm_core_check_feature(dev, DRIVER_MODESET)) 3856fb3b06c8SDave Airlie return -EINVAL; 3857fb3b06c8SDave Airlie 385884849903SDaniel Vetter drm_modeset_lock_all(dev); 3859a2b34e22SRob Clark property = drm_property_find(dev, out_resp->prop_id); 3860a2b34e22SRob Clark if (!property) { 3861f27657f2SVille Syrjälä ret = -ENOENT; 3862f453ba04SDave Airlie goto done; 3863f453ba04SDave Airlie } 3864f453ba04SDave Airlie 38655ea22f24SRob Clark if (drm_property_type_is(property, DRM_MODE_PROP_ENUM) || 38665ea22f24SRob Clark drm_property_type_is(property, DRM_MODE_PROP_BITMASK)) { 3867f453ba04SDave Airlie list_for_each_entry(prop_enum, &property->enum_blob_list, head) 3868f453ba04SDave Airlie enum_count++; 38695ea22f24SRob Clark } else if (drm_property_type_is(property, DRM_MODE_PROP_BLOB)) { 3870f453ba04SDave Airlie list_for_each_entry(prop_blob, &property->enum_blob_list, head) 3871f453ba04SDave Airlie blob_count++; 3872f453ba04SDave Airlie } 3873f453ba04SDave Airlie 3874f453ba04SDave Airlie value_count = property->num_values; 3875f453ba04SDave Airlie 3876f453ba04SDave Airlie strncpy(out_resp->name, property->name, DRM_PROP_NAME_LEN); 3877f453ba04SDave Airlie out_resp->name[DRM_PROP_NAME_LEN-1] = 0; 3878f453ba04SDave Airlie out_resp->flags = property->flags; 3879f453ba04SDave Airlie 3880f453ba04SDave Airlie if ((out_resp->count_values >= value_count) && value_count) { 388181f6c7f8SVille Syrjälä values_ptr = (uint64_t __user *)(unsigned long)out_resp->values_ptr; 3882f453ba04SDave Airlie for (i = 0; i < value_count; i++) { 3883f453ba04SDave Airlie if (copy_to_user(values_ptr + i, &property->values[i], sizeof(uint64_t))) { 3884f453ba04SDave Airlie ret = -EFAULT; 3885f453ba04SDave Airlie goto done; 3886f453ba04SDave Airlie } 3887f453ba04SDave Airlie } 3888f453ba04SDave Airlie } 3889f453ba04SDave Airlie out_resp->count_values = value_count; 3890f453ba04SDave Airlie 38915ea22f24SRob Clark if (drm_property_type_is(property, DRM_MODE_PROP_ENUM) || 38925ea22f24SRob Clark drm_property_type_is(property, DRM_MODE_PROP_BITMASK)) { 3893f453ba04SDave Airlie if ((out_resp->count_enum_blobs >= enum_count) && enum_count) { 3894f453ba04SDave Airlie copied = 0; 389581f6c7f8SVille Syrjälä enum_ptr = (struct drm_mode_property_enum __user *)(unsigned long)out_resp->enum_blob_ptr; 3896f453ba04SDave Airlie list_for_each_entry(prop_enum, &property->enum_blob_list, head) { 3897f453ba04SDave Airlie 3898f453ba04SDave Airlie if (copy_to_user(&enum_ptr[copied].value, &prop_enum->value, sizeof(uint64_t))) { 3899f453ba04SDave Airlie ret = -EFAULT; 3900f453ba04SDave Airlie goto done; 3901f453ba04SDave Airlie } 3902f453ba04SDave Airlie 3903f453ba04SDave Airlie if (copy_to_user(&enum_ptr[copied].name, 3904f453ba04SDave Airlie &prop_enum->name, DRM_PROP_NAME_LEN)) { 3905f453ba04SDave Airlie ret = -EFAULT; 3906f453ba04SDave Airlie goto done; 3907f453ba04SDave Airlie } 3908f453ba04SDave Airlie copied++; 3909f453ba04SDave Airlie } 3910f453ba04SDave Airlie } 3911f453ba04SDave Airlie out_resp->count_enum_blobs = enum_count; 3912f453ba04SDave Airlie } 3913f453ba04SDave Airlie 39145ea22f24SRob Clark if (drm_property_type_is(property, DRM_MODE_PROP_BLOB)) { 3915f453ba04SDave Airlie if ((out_resp->count_enum_blobs >= blob_count) && blob_count) { 3916f453ba04SDave Airlie copied = 0; 391781f6c7f8SVille Syrjälä blob_id_ptr = (uint32_t __user *)(unsigned long)out_resp->enum_blob_ptr; 391881f6c7f8SVille Syrjälä blob_length_ptr = (uint32_t __user *)(unsigned long)out_resp->values_ptr; 3919f453ba04SDave Airlie 3920f453ba04SDave Airlie list_for_each_entry(prop_blob, &property->enum_blob_list, head) { 3921f453ba04SDave Airlie if (put_user(prop_blob->base.id, blob_id_ptr + copied)) { 3922f453ba04SDave Airlie ret = -EFAULT; 3923f453ba04SDave Airlie goto done; 3924f453ba04SDave Airlie } 3925f453ba04SDave Airlie 3926f453ba04SDave Airlie if (put_user(prop_blob->length, blob_length_ptr + copied)) { 3927f453ba04SDave Airlie ret = -EFAULT; 3928f453ba04SDave Airlie goto done; 3929f453ba04SDave Airlie } 3930f453ba04SDave Airlie 3931f453ba04SDave Airlie copied++; 3932f453ba04SDave Airlie } 3933f453ba04SDave Airlie } 3934f453ba04SDave Airlie out_resp->count_enum_blobs = blob_count; 3935f453ba04SDave Airlie } 3936f453ba04SDave Airlie done: 393784849903SDaniel Vetter drm_modeset_unlock_all(dev); 3938f453ba04SDave Airlie return ret; 3939f453ba04SDave Airlie } 3940f453ba04SDave Airlie 3941f453ba04SDave Airlie static struct drm_property_blob *drm_property_create_blob(struct drm_device *dev, int length, 3942f453ba04SDave Airlie void *data) 3943f453ba04SDave Airlie { 3944f453ba04SDave Airlie struct drm_property_blob *blob; 39456bfc56aaSVille Syrjälä int ret; 3946f453ba04SDave Airlie 3947f453ba04SDave Airlie if (!length || !data) 3948f453ba04SDave Airlie return NULL; 3949f453ba04SDave Airlie 3950f453ba04SDave Airlie blob = kzalloc(sizeof(struct drm_property_blob)+length, GFP_KERNEL); 3951f453ba04SDave Airlie if (!blob) 3952f453ba04SDave Airlie return NULL; 3953f453ba04SDave Airlie 39546bfc56aaSVille Syrjälä ret = drm_mode_object_get(dev, &blob->base, DRM_MODE_OBJECT_BLOB); 39556bfc56aaSVille Syrjälä if (ret) { 39566bfc56aaSVille Syrjälä kfree(blob); 39576bfc56aaSVille Syrjälä return NULL; 39586bfc56aaSVille Syrjälä } 39596bfc56aaSVille Syrjälä 3960f453ba04SDave Airlie blob->length = length; 3961f453ba04SDave Airlie 3962f453ba04SDave Airlie memcpy(blob->data, data, length); 3963f453ba04SDave Airlie 3964f453ba04SDave Airlie list_add_tail(&blob->head, &dev->mode_config.property_blob_list); 3965f453ba04SDave Airlie return blob; 3966f453ba04SDave Airlie } 3967f453ba04SDave Airlie 3968f453ba04SDave Airlie static void drm_property_destroy_blob(struct drm_device *dev, 3969f453ba04SDave Airlie struct drm_property_blob *blob) 3970f453ba04SDave Airlie { 3971f453ba04SDave Airlie drm_mode_object_put(dev, &blob->base); 3972f453ba04SDave Airlie list_del(&blob->head); 3973f453ba04SDave Airlie kfree(blob); 3974f453ba04SDave Airlie } 3975f453ba04SDave Airlie 3976c8e32cc1SDaniel Vetter /** 3977c8e32cc1SDaniel Vetter * drm_mode_getblob_ioctl - get the contents of a blob property value 3978c8e32cc1SDaniel Vetter * @dev: DRM device 3979c8e32cc1SDaniel Vetter * @data: ioctl data 3980c8e32cc1SDaniel Vetter * @file_priv: DRM file info 3981c8e32cc1SDaniel Vetter * 3982c8e32cc1SDaniel Vetter * This function retrieves the contents of a blob property. The value stored in 3983c8e32cc1SDaniel Vetter * an object's blob property is just a normal modeset object id. 3984c8e32cc1SDaniel Vetter * 3985c8e32cc1SDaniel Vetter * Called by the user via ioctl. 3986c8e32cc1SDaniel Vetter * 3987c8e32cc1SDaniel Vetter * Returns: 3988c8e32cc1SDaniel Vetter * Zero on success, errno on failure. 3989c8e32cc1SDaniel Vetter */ 3990f453ba04SDave Airlie int drm_mode_getblob_ioctl(struct drm_device *dev, 3991f453ba04SDave Airlie void *data, struct drm_file *file_priv) 3992f453ba04SDave Airlie { 3993f453ba04SDave Airlie struct drm_mode_get_blob *out_resp = data; 3994f453ba04SDave Airlie struct drm_property_blob *blob; 3995f453ba04SDave Airlie int ret = 0; 399681f6c7f8SVille Syrjälä void __user *blob_ptr; 3997f453ba04SDave Airlie 3998fb3b06c8SDave Airlie if (!drm_core_check_feature(dev, DRIVER_MODESET)) 3999fb3b06c8SDave Airlie return -EINVAL; 4000fb3b06c8SDave Airlie 400184849903SDaniel Vetter drm_modeset_lock_all(dev); 4002a2b34e22SRob Clark blob = drm_property_blob_find(dev, out_resp->blob_id); 4003a2b34e22SRob Clark if (!blob) { 4004f27657f2SVille Syrjälä ret = -ENOENT; 4005f453ba04SDave Airlie goto done; 4006f453ba04SDave Airlie } 4007f453ba04SDave Airlie 4008f453ba04SDave Airlie if (out_resp->length == blob->length) { 400981f6c7f8SVille Syrjälä blob_ptr = (void __user *)(unsigned long)out_resp->data; 4010f453ba04SDave Airlie if (copy_to_user(blob_ptr, blob->data, blob->length)){ 4011f453ba04SDave Airlie ret = -EFAULT; 4012f453ba04SDave Airlie goto done; 4013f453ba04SDave Airlie } 4014f453ba04SDave Airlie } 4015f453ba04SDave Airlie out_resp->length = blob->length; 4016f453ba04SDave Airlie 4017f453ba04SDave Airlie done: 401884849903SDaniel Vetter drm_modeset_unlock_all(dev); 4019f453ba04SDave Airlie return ret; 4020f453ba04SDave Airlie } 4021f453ba04SDave Airlie 402243aba7ebSDave Airlie int drm_mode_connector_set_path_property(struct drm_connector *connector, 402343aba7ebSDave Airlie char *path) 402443aba7ebSDave Airlie { 402543aba7ebSDave Airlie struct drm_device *dev = connector->dev; 402643aba7ebSDave Airlie int ret, size; 402743aba7ebSDave Airlie size = strlen(path) + 1; 402843aba7ebSDave Airlie 402943aba7ebSDave Airlie connector->path_blob_ptr = drm_property_create_blob(connector->dev, 403043aba7ebSDave Airlie size, path); 403143aba7ebSDave Airlie if (!connector->path_blob_ptr) 403243aba7ebSDave Airlie return -EINVAL; 403343aba7ebSDave Airlie 403443aba7ebSDave Airlie ret = drm_object_property_set_value(&connector->base, 403543aba7ebSDave Airlie dev->mode_config.path_property, 403643aba7ebSDave Airlie connector->path_blob_ptr->base.id); 403743aba7ebSDave Airlie return ret; 403843aba7ebSDave Airlie } 403943aba7ebSDave Airlie EXPORT_SYMBOL(drm_mode_connector_set_path_property); 404043aba7ebSDave Airlie 4041c8e32cc1SDaniel Vetter /** 4042c8e32cc1SDaniel Vetter * drm_mode_connector_update_edid_property - update the edid property of a connector 4043c8e32cc1SDaniel Vetter * @connector: drm connector 4044c8e32cc1SDaniel Vetter * @edid: new value of the edid property 4045c8e32cc1SDaniel Vetter * 4046c8e32cc1SDaniel Vetter * This function creates a new blob modeset object and assigns its id to the 4047c8e32cc1SDaniel Vetter * connector's edid property. 4048c8e32cc1SDaniel Vetter * 4049c8e32cc1SDaniel Vetter * Returns: 4050c8e32cc1SDaniel Vetter * Zero on success, errno on failure. 4051c8e32cc1SDaniel Vetter */ 4052f453ba04SDave Airlie int drm_mode_connector_update_edid_property(struct drm_connector *connector, 4053f453ba04SDave Airlie struct edid *edid) 4054f453ba04SDave Airlie { 4055f453ba04SDave Airlie struct drm_device *dev = connector->dev; 40564a1b0714SLaurent Pinchart int ret, size; 4057f453ba04SDave Airlie 40584cf2b281SThomas Wood /* ignore requests to set edid when overridden */ 40594cf2b281SThomas Wood if (connector->override_edid) 40604cf2b281SThomas Wood return 0; 40614cf2b281SThomas Wood 4062f453ba04SDave Airlie if (connector->edid_blob_ptr) 4063f453ba04SDave Airlie drm_property_destroy_blob(dev, connector->edid_blob_ptr); 4064f453ba04SDave Airlie 4065f453ba04SDave Airlie /* Delete edid, when there is none. */ 4066f453ba04SDave Airlie if (!edid) { 4067f453ba04SDave Airlie connector->edid_blob_ptr = NULL; 406858495563SRob Clark ret = drm_object_property_set_value(&connector->base, dev->mode_config.edid_property, 0); 4069f453ba04SDave Airlie return ret; 4070f453ba04SDave Airlie } 4071f453ba04SDave Airlie 40727466f4ccSAdam Jackson size = EDID_LENGTH * (1 + edid->extensions); 40737466f4ccSAdam Jackson connector->edid_blob_ptr = drm_property_create_blob(connector->dev, 40747466f4ccSAdam Jackson size, edid); 4075e655d122SSachin Kamat if (!connector->edid_blob_ptr) 4076e655d122SSachin Kamat return -EINVAL; 4077f453ba04SDave Airlie 407858495563SRob Clark ret = drm_object_property_set_value(&connector->base, 4079f453ba04SDave Airlie dev->mode_config.edid_property, 4080f453ba04SDave Airlie connector->edid_blob_ptr->base.id); 4081f453ba04SDave Airlie 4082f453ba04SDave Airlie return ret; 4083f453ba04SDave Airlie } 4084f453ba04SDave Airlie EXPORT_SYMBOL(drm_mode_connector_update_edid_property); 4085f453ba04SDave Airlie 408626a34815SPaulo Zanoni static bool drm_property_change_is_valid(struct drm_property *property, 4087592c20eeSVille Syrjälä uint64_t value) 408826a34815SPaulo Zanoni { 408926a34815SPaulo Zanoni if (property->flags & DRM_MODE_PROP_IMMUTABLE) 409026a34815SPaulo Zanoni return false; 40915ea22f24SRob Clark 40925ea22f24SRob Clark if (drm_property_type_is(property, DRM_MODE_PROP_RANGE)) { 409326a34815SPaulo Zanoni if (value < property->values[0] || value > property->values[1]) 409426a34815SPaulo Zanoni return false; 409526a34815SPaulo Zanoni return true; 4096ebc44cf3SRob Clark } else if (drm_property_type_is(property, DRM_MODE_PROP_SIGNED_RANGE)) { 4097ebc44cf3SRob Clark int64_t svalue = U642I64(value); 4098ebc44cf3SRob Clark if (svalue < U642I64(property->values[0]) || 4099ebc44cf3SRob Clark svalue > U642I64(property->values[1])) 4100ebc44cf3SRob Clark return false; 4101ebc44cf3SRob Clark return true; 41025ea22f24SRob Clark } else if (drm_property_type_is(property, DRM_MODE_PROP_BITMASK)) { 410349e27545SRob Clark int i; 4104592c20eeSVille Syrjälä uint64_t valid_mask = 0; 410549e27545SRob Clark for (i = 0; i < property->num_values; i++) 410649e27545SRob Clark valid_mask |= (1ULL << property->values[i]); 410749e27545SRob Clark return !(value & ~valid_mask); 41085ea22f24SRob Clark } else if (drm_property_type_is(property, DRM_MODE_PROP_BLOB)) { 4109c4a56750SVille Syrjälä /* Only the driver knows */ 4110c4a56750SVille Syrjälä return true; 411198f75de4SRob Clark } else if (drm_property_type_is(property, DRM_MODE_PROP_OBJECT)) { 411298f75de4SRob Clark struct drm_mode_object *obj; 411398f75de4SRob Clark /* a zero value for an object property translates to null: */ 411498f75de4SRob Clark if (value == 0) 411598f75de4SRob Clark return true; 411698f75de4SRob Clark /* 411798f75de4SRob Clark * NOTE: use _object_find() directly to bypass restriction on 411898f75de4SRob Clark * looking up refcnt'd objects (ie. fb's). For a refcnt'd 411998f75de4SRob Clark * object this could race against object finalization, so it 412098f75de4SRob Clark * simply tells us that the object *was* valid. Which is good 412198f75de4SRob Clark * enough. 412298f75de4SRob Clark */ 412398f75de4SRob Clark obj = _object_find(property->dev, value, property->values[0]); 412498f75de4SRob Clark return obj != NULL; 412526a34815SPaulo Zanoni } else { 412626a34815SPaulo Zanoni int i; 412726a34815SPaulo Zanoni for (i = 0; i < property->num_values; i++) 412826a34815SPaulo Zanoni if (property->values[i] == value) 412926a34815SPaulo Zanoni return true; 413026a34815SPaulo Zanoni return false; 413126a34815SPaulo Zanoni } 413226a34815SPaulo Zanoni } 413326a34815SPaulo Zanoni 4134c8e32cc1SDaniel Vetter /** 4135c8e32cc1SDaniel Vetter * drm_mode_connector_property_set_ioctl - set the current value of a connector property 4136c8e32cc1SDaniel Vetter * @dev: DRM device 4137c8e32cc1SDaniel Vetter * @data: ioctl data 4138c8e32cc1SDaniel Vetter * @file_priv: DRM file info 4139c8e32cc1SDaniel Vetter * 4140c8e32cc1SDaniel Vetter * This function sets the current value for a connectors's property. It also 4141c8e32cc1SDaniel Vetter * calls into a driver's ->set_property callback to update the hardware state 4142c8e32cc1SDaniel Vetter * 4143c8e32cc1SDaniel Vetter * Called by the user via ioctl. 4144c8e32cc1SDaniel Vetter * 4145c8e32cc1SDaniel Vetter * Returns: 4146c8e32cc1SDaniel Vetter * Zero on success, errno on failure. 4147c8e32cc1SDaniel Vetter */ 4148f453ba04SDave Airlie int drm_mode_connector_property_set_ioctl(struct drm_device *dev, 4149f453ba04SDave Airlie void *data, struct drm_file *file_priv) 4150f453ba04SDave Airlie { 41510057d8ddSPaulo Zanoni struct drm_mode_connector_set_property *conn_set_prop = data; 41520057d8ddSPaulo Zanoni struct drm_mode_obj_set_property obj_set_prop = { 41530057d8ddSPaulo Zanoni .value = conn_set_prop->value, 41540057d8ddSPaulo Zanoni .prop_id = conn_set_prop->prop_id, 41550057d8ddSPaulo Zanoni .obj_id = conn_set_prop->connector_id, 41560057d8ddSPaulo Zanoni .obj_type = DRM_MODE_OBJECT_CONNECTOR 41570057d8ddSPaulo Zanoni }; 4158f453ba04SDave Airlie 41590057d8ddSPaulo Zanoni /* It does all the locking and checking we need */ 41600057d8ddSPaulo Zanoni return drm_mode_obj_set_property_ioctl(dev, &obj_set_prop, file_priv); 4161f453ba04SDave Airlie } 4162f453ba04SDave Airlie 4163c543188aSPaulo Zanoni static int drm_mode_connector_set_obj_prop(struct drm_mode_object *obj, 4164c543188aSPaulo Zanoni struct drm_property *property, 4165c543188aSPaulo Zanoni uint64_t value) 4166c543188aSPaulo Zanoni { 4167c543188aSPaulo Zanoni int ret = -EINVAL; 4168c543188aSPaulo Zanoni struct drm_connector *connector = obj_to_connector(obj); 4169c543188aSPaulo Zanoni 4170c543188aSPaulo Zanoni /* Do DPMS ourselves */ 4171c543188aSPaulo Zanoni if (property == connector->dev->mode_config.dpms_property) { 4172c543188aSPaulo Zanoni if (connector->funcs->dpms) 4173c543188aSPaulo Zanoni (*connector->funcs->dpms)(connector, (int)value); 4174c543188aSPaulo Zanoni ret = 0; 4175c543188aSPaulo Zanoni } else if (connector->funcs->set_property) 4176c543188aSPaulo Zanoni ret = connector->funcs->set_property(connector, property, value); 4177c543188aSPaulo Zanoni 4178c543188aSPaulo Zanoni /* store the property value if successful */ 4179c543188aSPaulo Zanoni if (!ret) 418058495563SRob Clark drm_object_property_set_value(&connector->base, property, value); 4181c543188aSPaulo Zanoni return ret; 4182c543188aSPaulo Zanoni } 4183c543188aSPaulo Zanoni 4184bffd9de0SPaulo Zanoni static int drm_mode_crtc_set_obj_prop(struct drm_mode_object *obj, 4185bffd9de0SPaulo Zanoni struct drm_property *property, 4186bffd9de0SPaulo Zanoni uint64_t value) 4187bffd9de0SPaulo Zanoni { 4188bffd9de0SPaulo Zanoni int ret = -EINVAL; 4189bffd9de0SPaulo Zanoni struct drm_crtc *crtc = obj_to_crtc(obj); 4190bffd9de0SPaulo Zanoni 4191bffd9de0SPaulo Zanoni if (crtc->funcs->set_property) 4192bffd9de0SPaulo Zanoni ret = crtc->funcs->set_property(crtc, property, value); 4193bffd9de0SPaulo Zanoni if (!ret) 4194bffd9de0SPaulo Zanoni drm_object_property_set_value(obj, property, value); 4195bffd9de0SPaulo Zanoni 4196bffd9de0SPaulo Zanoni return ret; 4197bffd9de0SPaulo Zanoni } 4198bffd9de0SPaulo Zanoni 41993a5f87c2SThomas Wood /** 42003a5f87c2SThomas Wood * drm_mode_plane_set_obj_prop - set the value of a property 42013a5f87c2SThomas Wood * @plane: drm plane object to set property value for 42023a5f87c2SThomas Wood * @property: property to set 42033a5f87c2SThomas Wood * @value: value the property should be set to 42043a5f87c2SThomas Wood * 42053a5f87c2SThomas Wood * This functions sets a given property on a given plane object. This function 42063a5f87c2SThomas Wood * calls the driver's ->set_property callback and changes the software state of 42073a5f87c2SThomas Wood * the property if the callback succeeds. 42083a5f87c2SThomas Wood * 42093a5f87c2SThomas Wood * Returns: 42103a5f87c2SThomas Wood * Zero on success, error code on failure. 42113a5f87c2SThomas Wood */ 42123a5f87c2SThomas Wood int drm_mode_plane_set_obj_prop(struct drm_plane *plane, 42134d93914aSRob Clark struct drm_property *property, 42144d93914aSRob Clark uint64_t value) 42154d93914aSRob Clark { 42164d93914aSRob Clark int ret = -EINVAL; 42173a5f87c2SThomas Wood struct drm_mode_object *obj = &plane->base; 42184d93914aSRob Clark 42194d93914aSRob Clark if (plane->funcs->set_property) 42204d93914aSRob Clark ret = plane->funcs->set_property(plane, property, value); 42214d93914aSRob Clark if (!ret) 42224d93914aSRob Clark drm_object_property_set_value(obj, property, value); 42234d93914aSRob Clark 42244d93914aSRob Clark return ret; 42254d93914aSRob Clark } 42263a5f87c2SThomas Wood EXPORT_SYMBOL(drm_mode_plane_set_obj_prop); 42274d93914aSRob Clark 4228c8e32cc1SDaniel Vetter /** 4229c8e32cc1SDaniel Vetter * drm_mode_getproperty_ioctl - get the current value of a object's property 4230c8e32cc1SDaniel Vetter * @dev: DRM device 4231c8e32cc1SDaniel Vetter * @data: ioctl data 4232c8e32cc1SDaniel Vetter * @file_priv: DRM file info 4233c8e32cc1SDaniel Vetter * 4234c8e32cc1SDaniel Vetter * This function retrieves the current value for an object's property. Compared 4235c8e32cc1SDaniel Vetter * to the connector specific ioctl this one is extended to also work on crtc and 4236c8e32cc1SDaniel Vetter * plane objects. 4237c8e32cc1SDaniel Vetter * 4238c8e32cc1SDaniel Vetter * Called by the user via ioctl. 4239c8e32cc1SDaniel Vetter * 4240c8e32cc1SDaniel Vetter * Returns: 4241c8e32cc1SDaniel Vetter * Zero on success, errno on failure. 4242c8e32cc1SDaniel Vetter */ 4243c543188aSPaulo Zanoni int drm_mode_obj_get_properties_ioctl(struct drm_device *dev, void *data, 4244c543188aSPaulo Zanoni struct drm_file *file_priv) 4245c543188aSPaulo Zanoni { 4246c543188aSPaulo Zanoni struct drm_mode_obj_get_properties *arg = data; 4247c543188aSPaulo Zanoni struct drm_mode_object *obj; 4248c543188aSPaulo Zanoni int ret = 0; 4249c543188aSPaulo Zanoni int i; 4250c543188aSPaulo Zanoni int copied = 0; 4251c543188aSPaulo Zanoni int props_count = 0; 4252c543188aSPaulo Zanoni uint32_t __user *props_ptr; 4253c543188aSPaulo Zanoni uint64_t __user *prop_values_ptr; 4254c543188aSPaulo Zanoni 4255c543188aSPaulo Zanoni if (!drm_core_check_feature(dev, DRIVER_MODESET)) 4256c543188aSPaulo Zanoni return -EINVAL; 4257c543188aSPaulo Zanoni 425884849903SDaniel Vetter drm_modeset_lock_all(dev); 4259c543188aSPaulo Zanoni 4260c543188aSPaulo Zanoni obj = drm_mode_object_find(dev, arg->obj_id, arg->obj_type); 4261c543188aSPaulo Zanoni if (!obj) { 4262f27657f2SVille Syrjälä ret = -ENOENT; 4263c543188aSPaulo Zanoni goto out; 4264c543188aSPaulo Zanoni } 4265c543188aSPaulo Zanoni if (!obj->properties) { 4266c543188aSPaulo Zanoni ret = -EINVAL; 4267c543188aSPaulo Zanoni goto out; 4268c543188aSPaulo Zanoni } 4269c543188aSPaulo Zanoni 42707f88a9beSPaulo Zanoni props_count = obj->properties->count; 4271c543188aSPaulo Zanoni 4272c543188aSPaulo Zanoni /* This ioctl is called twice, once to determine how much space is 4273c543188aSPaulo Zanoni * needed, and the 2nd time to fill it. */ 4274c543188aSPaulo Zanoni if ((arg->count_props >= props_count) && props_count) { 4275c543188aSPaulo Zanoni copied = 0; 4276c543188aSPaulo Zanoni props_ptr = (uint32_t __user *)(unsigned long)(arg->props_ptr); 4277c543188aSPaulo Zanoni prop_values_ptr = (uint64_t __user *)(unsigned long) 4278c543188aSPaulo Zanoni (arg->prop_values_ptr); 4279c543188aSPaulo Zanoni for (i = 0; i < props_count; i++) { 4280c543188aSPaulo Zanoni if (put_user(obj->properties->ids[i], 4281c543188aSPaulo Zanoni props_ptr + copied)) { 4282c543188aSPaulo Zanoni ret = -EFAULT; 4283c543188aSPaulo Zanoni goto out; 4284c543188aSPaulo Zanoni } 4285c543188aSPaulo Zanoni if (put_user(obj->properties->values[i], 4286c543188aSPaulo Zanoni prop_values_ptr + copied)) { 4287c543188aSPaulo Zanoni ret = -EFAULT; 4288c543188aSPaulo Zanoni goto out; 4289c543188aSPaulo Zanoni } 4290c543188aSPaulo Zanoni copied++; 4291c543188aSPaulo Zanoni } 4292c543188aSPaulo Zanoni } 4293c543188aSPaulo Zanoni arg->count_props = props_count; 4294c543188aSPaulo Zanoni out: 429584849903SDaniel Vetter drm_modeset_unlock_all(dev); 4296c543188aSPaulo Zanoni return ret; 4297c543188aSPaulo Zanoni } 4298c543188aSPaulo Zanoni 4299c8e32cc1SDaniel Vetter /** 4300c8e32cc1SDaniel Vetter * drm_mode_obj_set_property_ioctl - set the current value of an object's property 4301c8e32cc1SDaniel Vetter * @dev: DRM device 4302c8e32cc1SDaniel Vetter * @data: ioctl data 4303c8e32cc1SDaniel Vetter * @file_priv: DRM file info 4304c8e32cc1SDaniel Vetter * 4305c8e32cc1SDaniel Vetter * This function sets the current value for an object's property. It also calls 4306c8e32cc1SDaniel Vetter * into a driver's ->set_property callback to update the hardware state. 4307c8e32cc1SDaniel Vetter * Compared to the connector specific ioctl this one is extended to also work on 4308c8e32cc1SDaniel Vetter * crtc and plane objects. 4309c8e32cc1SDaniel Vetter * 4310c8e32cc1SDaniel Vetter * Called by the user via ioctl. 4311c8e32cc1SDaniel Vetter * 4312c8e32cc1SDaniel Vetter * Returns: 4313c8e32cc1SDaniel Vetter * Zero on success, errno on failure. 4314c8e32cc1SDaniel Vetter */ 4315c543188aSPaulo Zanoni int drm_mode_obj_set_property_ioctl(struct drm_device *dev, void *data, 4316c543188aSPaulo Zanoni struct drm_file *file_priv) 4317c543188aSPaulo Zanoni { 4318c543188aSPaulo Zanoni struct drm_mode_obj_set_property *arg = data; 4319c543188aSPaulo Zanoni struct drm_mode_object *arg_obj; 4320c543188aSPaulo Zanoni struct drm_mode_object *prop_obj; 4321c543188aSPaulo Zanoni struct drm_property *property; 4322c543188aSPaulo Zanoni int ret = -EINVAL; 4323c543188aSPaulo Zanoni int i; 4324c543188aSPaulo Zanoni 4325c543188aSPaulo Zanoni if (!drm_core_check_feature(dev, DRIVER_MODESET)) 4326c543188aSPaulo Zanoni return -EINVAL; 4327c543188aSPaulo Zanoni 432884849903SDaniel Vetter drm_modeset_lock_all(dev); 4329c543188aSPaulo Zanoni 4330c543188aSPaulo Zanoni arg_obj = drm_mode_object_find(dev, arg->obj_id, arg->obj_type); 4331f27657f2SVille Syrjälä if (!arg_obj) { 4332f27657f2SVille Syrjälä ret = -ENOENT; 4333c543188aSPaulo Zanoni goto out; 4334f27657f2SVille Syrjälä } 4335c543188aSPaulo Zanoni if (!arg_obj->properties) 4336c543188aSPaulo Zanoni goto out; 4337c543188aSPaulo Zanoni 43387f88a9beSPaulo Zanoni for (i = 0; i < arg_obj->properties->count; i++) 4339c543188aSPaulo Zanoni if (arg_obj->properties->ids[i] == arg->prop_id) 4340c543188aSPaulo Zanoni break; 4341c543188aSPaulo Zanoni 43427f88a9beSPaulo Zanoni if (i == arg_obj->properties->count) 4343c543188aSPaulo Zanoni goto out; 4344c543188aSPaulo Zanoni 4345c543188aSPaulo Zanoni prop_obj = drm_mode_object_find(dev, arg->prop_id, 4346c543188aSPaulo Zanoni DRM_MODE_OBJECT_PROPERTY); 4347f27657f2SVille Syrjälä if (!prop_obj) { 4348f27657f2SVille Syrjälä ret = -ENOENT; 4349c543188aSPaulo Zanoni goto out; 4350f27657f2SVille Syrjälä } 4351c543188aSPaulo Zanoni property = obj_to_property(prop_obj); 4352c543188aSPaulo Zanoni 4353c543188aSPaulo Zanoni if (!drm_property_change_is_valid(property, arg->value)) 4354c543188aSPaulo Zanoni goto out; 4355c543188aSPaulo Zanoni 4356c543188aSPaulo Zanoni switch (arg_obj->type) { 4357c543188aSPaulo Zanoni case DRM_MODE_OBJECT_CONNECTOR: 4358c543188aSPaulo Zanoni ret = drm_mode_connector_set_obj_prop(arg_obj, property, 4359c543188aSPaulo Zanoni arg->value); 4360c543188aSPaulo Zanoni break; 4361bffd9de0SPaulo Zanoni case DRM_MODE_OBJECT_CRTC: 4362bffd9de0SPaulo Zanoni ret = drm_mode_crtc_set_obj_prop(arg_obj, property, arg->value); 4363bffd9de0SPaulo Zanoni break; 43644d93914aSRob Clark case DRM_MODE_OBJECT_PLANE: 43653a5f87c2SThomas Wood ret = drm_mode_plane_set_obj_prop(obj_to_plane(arg_obj), 43663a5f87c2SThomas Wood property, arg->value); 43674d93914aSRob Clark break; 4368c543188aSPaulo Zanoni } 4369c543188aSPaulo Zanoni 4370c543188aSPaulo Zanoni out: 437184849903SDaniel Vetter drm_modeset_unlock_all(dev); 4372c543188aSPaulo Zanoni return ret; 4373c543188aSPaulo Zanoni } 4374c543188aSPaulo Zanoni 4375c8e32cc1SDaniel Vetter /** 4376c8e32cc1SDaniel Vetter * drm_mode_connector_attach_encoder - attach a connector to an encoder 4377c8e32cc1SDaniel Vetter * @connector: connector to attach 4378c8e32cc1SDaniel Vetter * @encoder: encoder to attach @connector to 4379c8e32cc1SDaniel Vetter * 4380c8e32cc1SDaniel Vetter * This function links up a connector to an encoder. Note that the routing 4381c8e32cc1SDaniel Vetter * restrictions between encoders and crtcs are exposed to userspace through the 4382c8e32cc1SDaniel Vetter * possible_clones and possible_crtcs bitmasks. 4383c8e32cc1SDaniel Vetter * 4384c8e32cc1SDaniel Vetter * Returns: 4385c8e32cc1SDaniel Vetter * Zero on success, errno on failure. 4386c8e32cc1SDaniel Vetter */ 4387f453ba04SDave Airlie int drm_mode_connector_attach_encoder(struct drm_connector *connector, 4388f453ba04SDave Airlie struct drm_encoder *encoder) 4389f453ba04SDave Airlie { 4390f453ba04SDave Airlie int i; 4391f453ba04SDave Airlie 4392f453ba04SDave Airlie for (i = 0; i < DRM_CONNECTOR_MAX_ENCODER; i++) { 4393f453ba04SDave Airlie if (connector->encoder_ids[i] == 0) { 4394f453ba04SDave Airlie connector->encoder_ids[i] = encoder->base.id; 4395f453ba04SDave Airlie return 0; 4396f453ba04SDave Airlie } 4397f453ba04SDave Airlie } 4398f453ba04SDave Airlie return -ENOMEM; 4399f453ba04SDave Airlie } 4400f453ba04SDave Airlie EXPORT_SYMBOL(drm_mode_connector_attach_encoder); 4401f453ba04SDave Airlie 4402c8e32cc1SDaniel Vetter /** 4403c8e32cc1SDaniel Vetter * drm_mode_crtc_set_gamma_size - set the gamma table size 4404c8e32cc1SDaniel Vetter * @crtc: CRTC to set the gamma table size for 4405c8e32cc1SDaniel Vetter * @gamma_size: size of the gamma table 4406c8e32cc1SDaniel Vetter * 4407c8e32cc1SDaniel Vetter * Drivers which support gamma tables should set this to the supported gamma 4408c8e32cc1SDaniel Vetter * table size when initializing the CRTC. Currently the drm core only supports a 4409c8e32cc1SDaniel Vetter * fixed gamma table size. 4410c8e32cc1SDaniel Vetter * 4411c8e32cc1SDaniel Vetter * Returns: 4412c8e32cc1SDaniel Vetter * Zero on success, errno on failure. 4413c8e32cc1SDaniel Vetter */ 44144cae5b84SSascha Hauer int drm_mode_crtc_set_gamma_size(struct drm_crtc *crtc, 4415f453ba04SDave Airlie int gamma_size) 4416f453ba04SDave Airlie { 4417f453ba04SDave Airlie crtc->gamma_size = gamma_size; 4418f453ba04SDave Airlie 4419f453ba04SDave Airlie crtc->gamma_store = kzalloc(gamma_size * sizeof(uint16_t) * 3, GFP_KERNEL); 4420f453ba04SDave Airlie if (!crtc->gamma_store) { 4421f453ba04SDave Airlie crtc->gamma_size = 0; 44224cae5b84SSascha Hauer return -ENOMEM; 4423f453ba04SDave Airlie } 4424f453ba04SDave Airlie 44254cae5b84SSascha Hauer return 0; 4426f453ba04SDave Airlie } 4427f453ba04SDave Airlie EXPORT_SYMBOL(drm_mode_crtc_set_gamma_size); 4428f453ba04SDave Airlie 4429c8e32cc1SDaniel Vetter /** 4430c8e32cc1SDaniel Vetter * drm_mode_gamma_set_ioctl - set the gamma table 4431c8e32cc1SDaniel Vetter * @dev: DRM device 4432c8e32cc1SDaniel Vetter * @data: ioctl data 4433c8e32cc1SDaniel Vetter * @file_priv: DRM file info 4434c8e32cc1SDaniel Vetter * 4435c8e32cc1SDaniel Vetter * Set the gamma table of a CRTC to the one passed in by the user. Userspace can 4436c8e32cc1SDaniel Vetter * inquire the required gamma table size through drm_mode_gamma_get_ioctl. 4437c8e32cc1SDaniel Vetter * 4438c8e32cc1SDaniel Vetter * Called by the user via ioctl. 4439c8e32cc1SDaniel Vetter * 4440c8e32cc1SDaniel Vetter * Returns: 4441c8e32cc1SDaniel Vetter * Zero on success, errno on failure. 4442c8e32cc1SDaniel Vetter */ 4443f453ba04SDave Airlie int drm_mode_gamma_set_ioctl(struct drm_device *dev, 4444f453ba04SDave Airlie void *data, struct drm_file *file_priv) 4445f453ba04SDave Airlie { 4446f453ba04SDave Airlie struct drm_mode_crtc_lut *crtc_lut = data; 4447f453ba04SDave Airlie struct drm_crtc *crtc; 4448f453ba04SDave Airlie void *r_base, *g_base, *b_base; 4449f453ba04SDave Airlie int size; 4450f453ba04SDave Airlie int ret = 0; 4451f453ba04SDave Airlie 4452fb3b06c8SDave Airlie if (!drm_core_check_feature(dev, DRIVER_MODESET)) 4453fb3b06c8SDave Airlie return -EINVAL; 4454fb3b06c8SDave Airlie 445584849903SDaniel Vetter drm_modeset_lock_all(dev); 4456a2b34e22SRob Clark crtc = drm_crtc_find(dev, crtc_lut->crtc_id); 4457a2b34e22SRob Clark if (!crtc) { 4458f27657f2SVille Syrjälä ret = -ENOENT; 4459f453ba04SDave Airlie goto out; 4460f453ba04SDave Airlie } 4461f453ba04SDave Airlie 4462ebe0f244SLaurent Pinchart if (crtc->funcs->gamma_set == NULL) { 4463ebe0f244SLaurent Pinchart ret = -ENOSYS; 4464ebe0f244SLaurent Pinchart goto out; 4465ebe0f244SLaurent Pinchart } 4466ebe0f244SLaurent Pinchart 4467f453ba04SDave Airlie /* memcpy into gamma store */ 4468f453ba04SDave Airlie if (crtc_lut->gamma_size != crtc->gamma_size) { 4469f453ba04SDave Airlie ret = -EINVAL; 4470f453ba04SDave Airlie goto out; 4471f453ba04SDave Airlie } 4472f453ba04SDave Airlie 4473f453ba04SDave Airlie size = crtc_lut->gamma_size * (sizeof(uint16_t)); 4474f453ba04SDave Airlie r_base = crtc->gamma_store; 4475f453ba04SDave Airlie if (copy_from_user(r_base, (void __user *)(unsigned long)crtc_lut->red, size)) { 4476f453ba04SDave Airlie ret = -EFAULT; 4477f453ba04SDave Airlie goto out; 4478f453ba04SDave Airlie } 4479f453ba04SDave Airlie 4480f453ba04SDave Airlie g_base = r_base + size; 4481f453ba04SDave Airlie if (copy_from_user(g_base, (void __user *)(unsigned long)crtc_lut->green, size)) { 4482f453ba04SDave Airlie ret = -EFAULT; 4483f453ba04SDave Airlie goto out; 4484f453ba04SDave Airlie } 4485f453ba04SDave Airlie 4486f453ba04SDave Airlie b_base = g_base + size; 4487f453ba04SDave Airlie if (copy_from_user(b_base, (void __user *)(unsigned long)crtc_lut->blue, size)) { 4488f453ba04SDave Airlie ret = -EFAULT; 4489f453ba04SDave Airlie goto out; 4490f453ba04SDave Airlie } 4491f453ba04SDave Airlie 44927203425aSJames Simmons crtc->funcs->gamma_set(crtc, r_base, g_base, b_base, 0, crtc->gamma_size); 4493f453ba04SDave Airlie 4494f453ba04SDave Airlie out: 449584849903SDaniel Vetter drm_modeset_unlock_all(dev); 4496f453ba04SDave Airlie return ret; 4497f453ba04SDave Airlie 4498f453ba04SDave Airlie } 4499f453ba04SDave Airlie 4500c8e32cc1SDaniel Vetter /** 4501c8e32cc1SDaniel Vetter * drm_mode_gamma_get_ioctl - get the gamma table 4502c8e32cc1SDaniel Vetter * @dev: DRM device 4503c8e32cc1SDaniel Vetter * @data: ioctl data 4504c8e32cc1SDaniel Vetter * @file_priv: DRM file info 4505c8e32cc1SDaniel Vetter * 4506c8e32cc1SDaniel Vetter * Copy the current gamma table into the storage provided. This also provides 4507c8e32cc1SDaniel Vetter * the gamma table size the driver expects, which can be used to size the 4508c8e32cc1SDaniel Vetter * allocated storage. 4509c8e32cc1SDaniel Vetter * 4510c8e32cc1SDaniel Vetter * Called by the user via ioctl. 4511c8e32cc1SDaniel Vetter * 4512c8e32cc1SDaniel Vetter * Returns: 4513c8e32cc1SDaniel Vetter * Zero on success, errno on failure. 4514c8e32cc1SDaniel Vetter */ 4515f453ba04SDave Airlie int drm_mode_gamma_get_ioctl(struct drm_device *dev, 4516f453ba04SDave Airlie void *data, struct drm_file *file_priv) 4517f453ba04SDave Airlie { 4518f453ba04SDave Airlie struct drm_mode_crtc_lut *crtc_lut = data; 4519f453ba04SDave Airlie struct drm_crtc *crtc; 4520f453ba04SDave Airlie void *r_base, *g_base, *b_base; 4521f453ba04SDave Airlie int size; 4522f453ba04SDave Airlie int ret = 0; 4523f453ba04SDave Airlie 4524fb3b06c8SDave Airlie if (!drm_core_check_feature(dev, DRIVER_MODESET)) 4525fb3b06c8SDave Airlie return -EINVAL; 4526fb3b06c8SDave Airlie 452784849903SDaniel Vetter drm_modeset_lock_all(dev); 4528a2b34e22SRob Clark crtc = drm_crtc_find(dev, crtc_lut->crtc_id); 4529a2b34e22SRob Clark if (!crtc) { 4530f27657f2SVille Syrjälä ret = -ENOENT; 4531f453ba04SDave Airlie goto out; 4532f453ba04SDave Airlie } 4533f453ba04SDave Airlie 4534f453ba04SDave Airlie /* memcpy into gamma store */ 4535f453ba04SDave Airlie if (crtc_lut->gamma_size != crtc->gamma_size) { 4536f453ba04SDave Airlie ret = -EINVAL; 4537f453ba04SDave Airlie goto out; 4538f453ba04SDave Airlie } 4539f453ba04SDave Airlie 4540f453ba04SDave Airlie size = crtc_lut->gamma_size * (sizeof(uint16_t)); 4541f453ba04SDave Airlie r_base = crtc->gamma_store; 4542f453ba04SDave Airlie if (copy_to_user((void __user *)(unsigned long)crtc_lut->red, r_base, size)) { 4543f453ba04SDave Airlie ret = -EFAULT; 4544f453ba04SDave Airlie goto out; 4545f453ba04SDave Airlie } 4546f453ba04SDave Airlie 4547f453ba04SDave Airlie g_base = r_base + size; 4548f453ba04SDave Airlie if (copy_to_user((void __user *)(unsigned long)crtc_lut->green, g_base, size)) { 4549f453ba04SDave Airlie ret = -EFAULT; 4550f453ba04SDave Airlie goto out; 4551f453ba04SDave Airlie } 4552f453ba04SDave Airlie 4553f453ba04SDave Airlie b_base = g_base + size; 4554f453ba04SDave Airlie if (copy_to_user((void __user *)(unsigned long)crtc_lut->blue, b_base, size)) { 4555f453ba04SDave Airlie ret = -EFAULT; 4556f453ba04SDave Airlie goto out; 4557f453ba04SDave Airlie } 4558f453ba04SDave Airlie out: 455984849903SDaniel Vetter drm_modeset_unlock_all(dev); 4560f453ba04SDave Airlie return ret; 4561f453ba04SDave Airlie } 4562d91d8a3fSKristian Høgsberg 4563c8e32cc1SDaniel Vetter /** 4564c8e32cc1SDaniel Vetter * drm_mode_page_flip_ioctl - schedule an asynchronous fb update 4565c8e32cc1SDaniel Vetter * @dev: DRM device 4566c8e32cc1SDaniel Vetter * @data: ioctl data 4567c8e32cc1SDaniel Vetter * @file_priv: DRM file info 4568c8e32cc1SDaniel Vetter * 4569c8e32cc1SDaniel Vetter * This schedules an asynchronous update on a given CRTC, called page flip. 4570c8e32cc1SDaniel Vetter * Optionally a drm event is generated to signal the completion of the event. 4571c8e32cc1SDaniel Vetter * Generic drivers cannot assume that a pageflip with changed framebuffer 4572c8e32cc1SDaniel Vetter * properties (including driver specific metadata like tiling layout) will work, 4573c8e32cc1SDaniel Vetter * but some drivers support e.g. pixel format changes through the pageflip 4574c8e32cc1SDaniel Vetter * ioctl. 4575c8e32cc1SDaniel Vetter * 4576c8e32cc1SDaniel Vetter * Called by the user via ioctl. 4577c8e32cc1SDaniel Vetter * 4578c8e32cc1SDaniel Vetter * Returns: 4579c8e32cc1SDaniel Vetter * Zero on success, errno on failure. 4580c8e32cc1SDaniel Vetter */ 4581d91d8a3fSKristian Høgsberg int drm_mode_page_flip_ioctl(struct drm_device *dev, 4582d91d8a3fSKristian Høgsberg void *data, struct drm_file *file_priv) 4583d91d8a3fSKristian Høgsberg { 4584d91d8a3fSKristian Høgsberg struct drm_mode_crtc_page_flip *page_flip = data; 4585d91d8a3fSKristian Høgsberg struct drm_crtc *crtc; 45863d30a59bSDaniel Vetter struct drm_framebuffer *fb = NULL; 4587d91d8a3fSKristian Høgsberg struct drm_pending_vblank_event *e = NULL; 4588d91d8a3fSKristian Høgsberg unsigned long flags; 4589d91d8a3fSKristian Høgsberg int ret = -EINVAL; 4590d91d8a3fSKristian Høgsberg 4591d91d8a3fSKristian Høgsberg if (page_flip->flags & ~DRM_MODE_PAGE_FLIP_FLAGS || 4592d91d8a3fSKristian Høgsberg page_flip->reserved != 0) 4593d91d8a3fSKristian Høgsberg return -EINVAL; 4594d91d8a3fSKristian Høgsberg 459562f2104fSKeith Packard if ((page_flip->flags & DRM_MODE_PAGE_FLIP_ASYNC) && !dev->mode_config.async_page_flip) 459662f2104fSKeith Packard return -EINVAL; 459762f2104fSKeith Packard 4598a2b34e22SRob Clark crtc = drm_crtc_find(dev, page_flip->crtc_id); 4599a2b34e22SRob Clark if (!crtc) 4600f27657f2SVille Syrjälä return -ENOENT; 4601d91d8a3fSKristian Høgsberg 4602d059f652SDaniel Vetter drm_modeset_lock_crtc(crtc); 4603f4510a27SMatt Roper if (crtc->primary->fb == NULL) { 460490c1efddSChris Wilson /* The framebuffer is currently unbound, presumably 460590c1efddSChris Wilson * due to a hotplug event, that userspace has not 460690c1efddSChris Wilson * yet discovered. 460790c1efddSChris Wilson */ 460890c1efddSChris Wilson ret = -EBUSY; 460990c1efddSChris Wilson goto out; 461090c1efddSChris Wilson } 461190c1efddSChris Wilson 4612d91d8a3fSKristian Høgsberg if (crtc->funcs->page_flip == NULL) 4613d91d8a3fSKristian Høgsberg goto out; 4614d91d8a3fSKristian Høgsberg 4615786b99edSDaniel Vetter fb = drm_framebuffer_lookup(dev, page_flip->fb_id); 461637c4e705SVille Syrjälä if (!fb) { 461737c4e705SVille Syrjälä ret = -ENOENT; 4618d91d8a3fSKristian Høgsberg goto out; 461937c4e705SVille Syrjälä } 4620d91d8a3fSKristian Høgsberg 4621c11e9283SDamien Lespiau ret = drm_crtc_check_viewport(crtc, crtc->x, crtc->y, &crtc->mode, fb); 4622c11e9283SDamien Lespiau if (ret) 46235f61bb42SVille Syrjälä goto out; 46245f61bb42SVille Syrjälä 4625f4510a27SMatt Roper if (crtc->primary->fb->pixel_format != fb->pixel_format) { 4626909d9cdaSLaurent Pinchart DRM_DEBUG_KMS("Page flip is not allowed to change frame buffer format.\n"); 4627909d9cdaSLaurent Pinchart ret = -EINVAL; 4628909d9cdaSLaurent Pinchart goto out; 4629909d9cdaSLaurent Pinchart } 4630909d9cdaSLaurent Pinchart 4631d91d8a3fSKristian Høgsberg if (page_flip->flags & DRM_MODE_PAGE_FLIP_EVENT) { 4632d91d8a3fSKristian Høgsberg ret = -ENOMEM; 4633d91d8a3fSKristian Høgsberg spin_lock_irqsave(&dev->event_lock, flags); 4634d91d8a3fSKristian Høgsberg if (file_priv->event_space < sizeof e->event) { 4635d91d8a3fSKristian Høgsberg spin_unlock_irqrestore(&dev->event_lock, flags); 4636d91d8a3fSKristian Høgsberg goto out; 4637d91d8a3fSKristian Høgsberg } 4638d91d8a3fSKristian Høgsberg file_priv->event_space -= sizeof e->event; 4639d91d8a3fSKristian Høgsberg spin_unlock_irqrestore(&dev->event_lock, flags); 4640d91d8a3fSKristian Høgsberg 4641d91d8a3fSKristian Høgsberg e = kzalloc(sizeof *e, GFP_KERNEL); 4642d91d8a3fSKristian Høgsberg if (e == NULL) { 4643d91d8a3fSKristian Høgsberg spin_lock_irqsave(&dev->event_lock, flags); 4644d91d8a3fSKristian Høgsberg file_priv->event_space += sizeof e->event; 4645d91d8a3fSKristian Høgsberg spin_unlock_irqrestore(&dev->event_lock, flags); 4646d91d8a3fSKristian Høgsberg goto out; 4647d91d8a3fSKristian Høgsberg } 4648d91d8a3fSKristian Høgsberg 46497bd4d7beSJesse Barnes e->event.base.type = DRM_EVENT_FLIP_COMPLETE; 4650d91d8a3fSKristian Høgsberg e->event.base.length = sizeof e->event; 4651d91d8a3fSKristian Høgsberg e->event.user_data = page_flip->user_data; 4652d91d8a3fSKristian Høgsberg e->base.event = &e->event.base; 4653d91d8a3fSKristian Høgsberg e->base.file_priv = file_priv; 4654d91d8a3fSKristian Høgsberg e->base.destroy = 4655d91d8a3fSKristian Høgsberg (void (*) (struct drm_pending_event *)) kfree; 4656d91d8a3fSKristian Høgsberg } 4657d91d8a3fSKristian Høgsberg 46583d30a59bSDaniel Vetter crtc->primary->old_fb = crtc->primary->fb; 4659ed8d1975SKeith Packard ret = crtc->funcs->page_flip(crtc, fb, e, page_flip->flags); 4660d91d8a3fSKristian Høgsberg if (ret) { 4661aef6a7eeSJoonyoung Shim if (page_flip->flags & DRM_MODE_PAGE_FLIP_EVENT) { 4662d91d8a3fSKristian Høgsberg spin_lock_irqsave(&dev->event_lock, flags); 4663d91d8a3fSKristian Høgsberg file_priv->event_space += sizeof e->event; 4664d91d8a3fSKristian Høgsberg spin_unlock_irqrestore(&dev->event_lock, flags); 4665d91d8a3fSKristian Høgsberg kfree(e); 4666d91d8a3fSKristian Høgsberg } 4667b0d12325SDaniel Vetter /* Keep the old fb, don't unref it. */ 46683d30a59bSDaniel Vetter crtc->primary->old_fb = NULL; 4669b0d12325SDaniel Vetter } else { 46708cf1e981SThierry Reding /* 46718cf1e981SThierry Reding * Warn if the driver hasn't properly updated the crtc->fb 46728cf1e981SThierry Reding * field to reflect that the new framebuffer is now used. 46738cf1e981SThierry Reding * Failing to do so will screw with the reference counting 46748cf1e981SThierry Reding * on framebuffers. 46758cf1e981SThierry Reding */ 4676f4510a27SMatt Roper WARN_ON(crtc->primary->fb != fb); 4677b0d12325SDaniel Vetter /* Unref only the old framebuffer. */ 4678b0d12325SDaniel Vetter fb = NULL; 4679aef6a7eeSJoonyoung Shim } 4680d91d8a3fSKristian Høgsberg 4681d91d8a3fSKristian Høgsberg out: 4682b0d12325SDaniel Vetter if (fb) 4683b0d12325SDaniel Vetter drm_framebuffer_unreference(fb); 46843d30a59bSDaniel Vetter if (crtc->primary->old_fb) 46853d30a59bSDaniel Vetter drm_framebuffer_unreference(crtc->primary->old_fb); 46863d30a59bSDaniel Vetter crtc->primary->old_fb = NULL; 4687d059f652SDaniel Vetter drm_modeset_unlock_crtc(crtc); 4688b4d5e7d1SDaniel Vetter 4689d91d8a3fSKristian Høgsberg return ret; 4690d91d8a3fSKristian Høgsberg } 4691eb033556SChris Wilson 4692c8e32cc1SDaniel Vetter /** 4693c8e32cc1SDaniel Vetter * drm_mode_config_reset - call ->reset callbacks 4694c8e32cc1SDaniel Vetter * @dev: drm device 4695c8e32cc1SDaniel Vetter * 4696c8e32cc1SDaniel Vetter * This functions calls all the crtc's, encoder's and connector's ->reset 4697c8e32cc1SDaniel Vetter * callback. Drivers can use this in e.g. their driver load or resume code to 4698c8e32cc1SDaniel Vetter * reset hardware and software state. 4699c8e32cc1SDaniel Vetter */ 4700eb033556SChris Wilson void drm_mode_config_reset(struct drm_device *dev) 4701eb033556SChris Wilson { 4702eb033556SChris Wilson struct drm_crtc *crtc; 47032a0d7cfdSDaniel Vetter struct drm_plane *plane; 4704eb033556SChris Wilson struct drm_encoder *encoder; 4705eb033556SChris Wilson struct drm_connector *connector; 4706eb033556SChris Wilson 47072a0d7cfdSDaniel Vetter list_for_each_entry(plane, &dev->mode_config.plane_list, head) 47082a0d7cfdSDaniel Vetter if (plane->funcs->reset) 47092a0d7cfdSDaniel Vetter plane->funcs->reset(plane); 47102a0d7cfdSDaniel Vetter 4711eb033556SChris Wilson list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) 4712eb033556SChris Wilson if (crtc->funcs->reset) 4713eb033556SChris Wilson crtc->funcs->reset(crtc); 4714eb033556SChris Wilson 4715eb033556SChris Wilson list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) 4716eb033556SChris Wilson if (encoder->funcs->reset) 4717eb033556SChris Wilson encoder->funcs->reset(encoder); 4718eb033556SChris Wilson 47195e2cb2f6SDaniel Vetter list_for_each_entry(connector, &dev->mode_config.connector_list, head) { 47205e2cb2f6SDaniel Vetter connector->status = connector_status_unknown; 47215e2cb2f6SDaniel Vetter 4722eb033556SChris Wilson if (connector->funcs->reset) 4723eb033556SChris Wilson connector->funcs->reset(connector); 4724eb033556SChris Wilson } 47255e2cb2f6SDaniel Vetter } 4726eb033556SChris Wilson EXPORT_SYMBOL(drm_mode_config_reset); 4727ff72145bSDave Airlie 4728c8e32cc1SDaniel Vetter /** 4729c8e32cc1SDaniel Vetter * drm_mode_create_dumb_ioctl - create a dumb backing storage buffer 4730c8e32cc1SDaniel Vetter * @dev: DRM device 4731c8e32cc1SDaniel Vetter * @data: ioctl data 4732c8e32cc1SDaniel Vetter * @file_priv: DRM file info 4733c8e32cc1SDaniel Vetter * 4734c8e32cc1SDaniel Vetter * This creates a new dumb buffer in the driver's backing storage manager (GEM, 4735c8e32cc1SDaniel Vetter * TTM or something else entirely) and returns the resulting buffer handle. This 4736c8e32cc1SDaniel Vetter * handle can then be wrapped up into a framebuffer modeset object. 4737c8e32cc1SDaniel Vetter * 4738c8e32cc1SDaniel Vetter * Note that userspace is not allowed to use such objects for render 4739c8e32cc1SDaniel Vetter * acceleration - drivers must create their own private ioctls for such a use 4740c8e32cc1SDaniel Vetter * case. 4741c8e32cc1SDaniel Vetter * 4742c8e32cc1SDaniel Vetter * Called by the user via ioctl. 4743c8e32cc1SDaniel Vetter * 4744c8e32cc1SDaniel Vetter * Returns: 4745c8e32cc1SDaniel Vetter * Zero on success, errno on failure. 4746c8e32cc1SDaniel Vetter */ 4747ff72145bSDave Airlie int drm_mode_create_dumb_ioctl(struct drm_device *dev, 4748ff72145bSDave Airlie void *data, struct drm_file *file_priv) 4749ff72145bSDave Airlie { 4750ff72145bSDave Airlie struct drm_mode_create_dumb *args = data; 4751b28cd41fSDavid Herrmann u32 cpp, stride, size; 4752ff72145bSDave Airlie 4753ff72145bSDave Airlie if (!dev->driver->dumb_create) 4754ff72145bSDave Airlie return -ENOSYS; 4755b28cd41fSDavid Herrmann if (!args->width || !args->height || !args->bpp) 4756b28cd41fSDavid Herrmann return -EINVAL; 4757b28cd41fSDavid Herrmann 4758b28cd41fSDavid Herrmann /* overflow checks for 32bit size calculations */ 475900e72089SDavid Herrmann /* NOTE: DIV_ROUND_UP() can overflow */ 4760b28cd41fSDavid Herrmann cpp = DIV_ROUND_UP(args->bpp, 8); 476100e72089SDavid Herrmann if (!cpp || cpp > 0xffffffffU / args->width) 4762b28cd41fSDavid Herrmann return -EINVAL; 4763b28cd41fSDavid Herrmann stride = cpp * args->width; 4764b28cd41fSDavid Herrmann if (args->height > 0xffffffffU / stride) 4765b28cd41fSDavid Herrmann return -EINVAL; 4766b28cd41fSDavid Herrmann 4767b28cd41fSDavid Herrmann /* test for wrap-around */ 4768b28cd41fSDavid Herrmann size = args->height * stride; 4769b28cd41fSDavid Herrmann if (PAGE_ALIGN(size) == 0) 4770b28cd41fSDavid Herrmann return -EINVAL; 4771b28cd41fSDavid Herrmann 4772ff72145bSDave Airlie return dev->driver->dumb_create(file_priv, dev, args); 4773ff72145bSDave Airlie } 4774ff72145bSDave Airlie 4775c8e32cc1SDaniel Vetter /** 4776c8e32cc1SDaniel Vetter * drm_mode_mmap_dumb_ioctl - create an mmap offset for a dumb backing storage buffer 4777c8e32cc1SDaniel Vetter * @dev: DRM device 4778c8e32cc1SDaniel Vetter * @data: ioctl data 4779c8e32cc1SDaniel Vetter * @file_priv: DRM file info 4780c8e32cc1SDaniel Vetter * 4781c8e32cc1SDaniel Vetter * Allocate an offset in the drm device node's address space to be able to 4782c8e32cc1SDaniel Vetter * memory map a dumb buffer. 4783c8e32cc1SDaniel Vetter * 4784c8e32cc1SDaniel Vetter * Called by the user via ioctl. 4785c8e32cc1SDaniel Vetter * 4786c8e32cc1SDaniel Vetter * Returns: 4787c8e32cc1SDaniel Vetter * Zero on success, errno on failure. 4788c8e32cc1SDaniel Vetter */ 4789ff72145bSDave Airlie int drm_mode_mmap_dumb_ioctl(struct drm_device *dev, 4790ff72145bSDave Airlie void *data, struct drm_file *file_priv) 4791ff72145bSDave Airlie { 4792ff72145bSDave Airlie struct drm_mode_map_dumb *args = data; 4793ff72145bSDave Airlie 4794ff72145bSDave Airlie /* call driver ioctl to get mmap offset */ 4795ff72145bSDave Airlie if (!dev->driver->dumb_map_offset) 4796ff72145bSDave Airlie return -ENOSYS; 4797ff72145bSDave Airlie 4798ff72145bSDave Airlie return dev->driver->dumb_map_offset(file_priv, dev, args->handle, &args->offset); 4799ff72145bSDave Airlie } 4800ff72145bSDave Airlie 4801c8e32cc1SDaniel Vetter /** 4802c8e32cc1SDaniel Vetter * drm_mode_destroy_dumb_ioctl - destroy a dumb backing strage buffer 4803c8e32cc1SDaniel Vetter * @dev: DRM device 4804c8e32cc1SDaniel Vetter * @data: ioctl data 4805c8e32cc1SDaniel Vetter * @file_priv: DRM file info 4806c8e32cc1SDaniel Vetter * 4807c8e32cc1SDaniel Vetter * This destroys the userspace handle for the given dumb backing storage buffer. 4808c8e32cc1SDaniel Vetter * Since buffer objects must be reference counted in the kernel a buffer object 4809c8e32cc1SDaniel Vetter * won't be immediately freed if a framebuffer modeset object still uses it. 4810c8e32cc1SDaniel Vetter * 4811c8e32cc1SDaniel Vetter * Called by the user via ioctl. 4812c8e32cc1SDaniel Vetter * 4813c8e32cc1SDaniel Vetter * Returns: 4814c8e32cc1SDaniel Vetter * Zero on success, errno on failure. 4815c8e32cc1SDaniel Vetter */ 4816ff72145bSDave Airlie int drm_mode_destroy_dumb_ioctl(struct drm_device *dev, 4817ff72145bSDave Airlie void *data, struct drm_file *file_priv) 4818ff72145bSDave Airlie { 4819ff72145bSDave Airlie struct drm_mode_destroy_dumb *args = data; 4820ff72145bSDave Airlie 4821ff72145bSDave Airlie if (!dev->driver->dumb_destroy) 4822ff72145bSDave Airlie return -ENOSYS; 4823ff72145bSDave Airlie 4824ff72145bSDave Airlie return dev->driver->dumb_destroy(file_priv, dev, args->handle); 4825ff72145bSDave Airlie } 4826248dbc23SDave Airlie 4827c8e32cc1SDaniel Vetter /** 4828c8e32cc1SDaniel Vetter * drm_fb_get_bpp_depth - get the bpp/depth values for format 4829c8e32cc1SDaniel Vetter * @format: pixel format (DRM_FORMAT_*) 4830c8e32cc1SDaniel Vetter * @depth: storage for the depth value 4831c8e32cc1SDaniel Vetter * @bpp: storage for the bpp value 4832c8e32cc1SDaniel Vetter * 4833c8e32cc1SDaniel Vetter * This only supports RGB formats here for compat with code that doesn't use 4834c8e32cc1SDaniel Vetter * pixel formats directly yet. 4835248dbc23SDave Airlie */ 4836248dbc23SDave Airlie void drm_fb_get_bpp_depth(uint32_t format, unsigned int *depth, 4837248dbc23SDave Airlie int *bpp) 4838248dbc23SDave Airlie { 4839248dbc23SDave Airlie switch (format) { 4840c51a6bc5SVille Syrjälä case DRM_FORMAT_C8: 484104b3924dSVille Syrjälä case DRM_FORMAT_RGB332: 484204b3924dSVille Syrjälä case DRM_FORMAT_BGR233: 4843248dbc23SDave Airlie *depth = 8; 4844248dbc23SDave Airlie *bpp = 8; 4845248dbc23SDave Airlie break; 484604b3924dSVille Syrjälä case DRM_FORMAT_XRGB1555: 484704b3924dSVille Syrjälä case DRM_FORMAT_XBGR1555: 484804b3924dSVille Syrjälä case DRM_FORMAT_RGBX5551: 484904b3924dSVille Syrjälä case DRM_FORMAT_BGRX5551: 485004b3924dSVille Syrjälä case DRM_FORMAT_ARGB1555: 485104b3924dSVille Syrjälä case DRM_FORMAT_ABGR1555: 485204b3924dSVille Syrjälä case DRM_FORMAT_RGBA5551: 485304b3924dSVille Syrjälä case DRM_FORMAT_BGRA5551: 4854248dbc23SDave Airlie *depth = 15; 4855248dbc23SDave Airlie *bpp = 16; 4856248dbc23SDave Airlie break; 485704b3924dSVille Syrjälä case DRM_FORMAT_RGB565: 485804b3924dSVille Syrjälä case DRM_FORMAT_BGR565: 4859248dbc23SDave Airlie *depth = 16; 4860248dbc23SDave Airlie *bpp = 16; 4861248dbc23SDave Airlie break; 486204b3924dSVille Syrjälä case DRM_FORMAT_RGB888: 486304b3924dSVille Syrjälä case DRM_FORMAT_BGR888: 486404b3924dSVille Syrjälä *depth = 24; 486504b3924dSVille Syrjälä *bpp = 24; 486604b3924dSVille Syrjälä break; 486704b3924dSVille Syrjälä case DRM_FORMAT_XRGB8888: 486804b3924dSVille Syrjälä case DRM_FORMAT_XBGR8888: 486904b3924dSVille Syrjälä case DRM_FORMAT_RGBX8888: 487004b3924dSVille Syrjälä case DRM_FORMAT_BGRX8888: 4871248dbc23SDave Airlie *depth = 24; 4872248dbc23SDave Airlie *bpp = 32; 4873248dbc23SDave Airlie break; 487404b3924dSVille Syrjälä case DRM_FORMAT_XRGB2101010: 487504b3924dSVille Syrjälä case DRM_FORMAT_XBGR2101010: 487604b3924dSVille Syrjälä case DRM_FORMAT_RGBX1010102: 487704b3924dSVille Syrjälä case DRM_FORMAT_BGRX1010102: 487804b3924dSVille Syrjälä case DRM_FORMAT_ARGB2101010: 487904b3924dSVille Syrjälä case DRM_FORMAT_ABGR2101010: 488004b3924dSVille Syrjälä case DRM_FORMAT_RGBA1010102: 488104b3924dSVille Syrjälä case DRM_FORMAT_BGRA1010102: 4882248dbc23SDave Airlie *depth = 30; 4883248dbc23SDave Airlie *bpp = 32; 4884248dbc23SDave Airlie break; 488504b3924dSVille Syrjälä case DRM_FORMAT_ARGB8888: 488604b3924dSVille Syrjälä case DRM_FORMAT_ABGR8888: 488704b3924dSVille Syrjälä case DRM_FORMAT_RGBA8888: 488804b3924dSVille Syrjälä case DRM_FORMAT_BGRA8888: 4889248dbc23SDave Airlie *depth = 32; 4890248dbc23SDave Airlie *bpp = 32; 4891248dbc23SDave Airlie break; 4892248dbc23SDave Airlie default: 489323c453a4SVille Syrjälä DRM_DEBUG_KMS("unsupported pixel format %s\n", 489423c453a4SVille Syrjälä drm_get_format_name(format)); 4895248dbc23SDave Airlie *depth = 0; 4896248dbc23SDave Airlie *bpp = 0; 4897248dbc23SDave Airlie break; 4898248dbc23SDave Airlie } 4899248dbc23SDave Airlie } 4900248dbc23SDave Airlie EXPORT_SYMBOL(drm_fb_get_bpp_depth); 4901141670e9SVille Syrjälä 4902141670e9SVille Syrjälä /** 4903141670e9SVille Syrjälä * drm_format_num_planes - get the number of planes for format 4904141670e9SVille Syrjälä * @format: pixel format (DRM_FORMAT_*) 4905141670e9SVille Syrjälä * 4906c8e32cc1SDaniel Vetter * Returns: 4907141670e9SVille Syrjälä * The number of planes used by the specified pixel format. 4908141670e9SVille Syrjälä */ 4909141670e9SVille Syrjälä int drm_format_num_planes(uint32_t format) 4910141670e9SVille Syrjälä { 4911141670e9SVille Syrjälä switch (format) { 4912141670e9SVille Syrjälä case DRM_FORMAT_YUV410: 4913141670e9SVille Syrjälä case DRM_FORMAT_YVU410: 4914141670e9SVille Syrjälä case DRM_FORMAT_YUV411: 4915141670e9SVille Syrjälä case DRM_FORMAT_YVU411: 4916141670e9SVille Syrjälä case DRM_FORMAT_YUV420: 4917141670e9SVille Syrjälä case DRM_FORMAT_YVU420: 4918141670e9SVille Syrjälä case DRM_FORMAT_YUV422: 4919141670e9SVille Syrjälä case DRM_FORMAT_YVU422: 4920141670e9SVille Syrjälä case DRM_FORMAT_YUV444: 4921141670e9SVille Syrjälä case DRM_FORMAT_YVU444: 4922141670e9SVille Syrjälä return 3; 4923141670e9SVille Syrjälä case DRM_FORMAT_NV12: 4924141670e9SVille Syrjälä case DRM_FORMAT_NV21: 4925141670e9SVille Syrjälä case DRM_FORMAT_NV16: 4926141670e9SVille Syrjälä case DRM_FORMAT_NV61: 4927ba623f6aSLaurent Pinchart case DRM_FORMAT_NV24: 4928ba623f6aSLaurent Pinchart case DRM_FORMAT_NV42: 4929141670e9SVille Syrjälä return 2; 4930141670e9SVille Syrjälä default: 4931141670e9SVille Syrjälä return 1; 4932141670e9SVille Syrjälä } 4933141670e9SVille Syrjälä } 4934141670e9SVille Syrjälä EXPORT_SYMBOL(drm_format_num_planes); 49355a86bd55SVille Syrjälä 49365a86bd55SVille Syrjälä /** 49375a86bd55SVille Syrjälä * drm_format_plane_cpp - determine the bytes per pixel value 49385a86bd55SVille Syrjälä * @format: pixel format (DRM_FORMAT_*) 49395a86bd55SVille Syrjälä * @plane: plane index 49405a86bd55SVille Syrjälä * 4941c8e32cc1SDaniel Vetter * Returns: 49425a86bd55SVille Syrjälä * The bytes per pixel value for the specified plane. 49435a86bd55SVille Syrjälä */ 49445a86bd55SVille Syrjälä int drm_format_plane_cpp(uint32_t format, int plane) 49455a86bd55SVille Syrjälä { 49465a86bd55SVille Syrjälä unsigned int depth; 49475a86bd55SVille Syrjälä int bpp; 49485a86bd55SVille Syrjälä 49495a86bd55SVille Syrjälä if (plane >= drm_format_num_planes(format)) 49505a86bd55SVille Syrjälä return 0; 49515a86bd55SVille Syrjälä 49525a86bd55SVille Syrjälä switch (format) { 49535a86bd55SVille Syrjälä case DRM_FORMAT_YUYV: 49545a86bd55SVille Syrjälä case DRM_FORMAT_YVYU: 49555a86bd55SVille Syrjälä case DRM_FORMAT_UYVY: 49565a86bd55SVille Syrjälä case DRM_FORMAT_VYUY: 49575a86bd55SVille Syrjälä return 2; 49585a86bd55SVille Syrjälä case DRM_FORMAT_NV12: 49595a86bd55SVille Syrjälä case DRM_FORMAT_NV21: 49605a86bd55SVille Syrjälä case DRM_FORMAT_NV16: 49615a86bd55SVille Syrjälä case DRM_FORMAT_NV61: 4962ba623f6aSLaurent Pinchart case DRM_FORMAT_NV24: 4963ba623f6aSLaurent Pinchart case DRM_FORMAT_NV42: 49645a86bd55SVille Syrjälä return plane ? 2 : 1; 49655a86bd55SVille Syrjälä case DRM_FORMAT_YUV410: 49665a86bd55SVille Syrjälä case DRM_FORMAT_YVU410: 49675a86bd55SVille Syrjälä case DRM_FORMAT_YUV411: 49685a86bd55SVille Syrjälä case DRM_FORMAT_YVU411: 49695a86bd55SVille Syrjälä case DRM_FORMAT_YUV420: 49705a86bd55SVille Syrjälä case DRM_FORMAT_YVU420: 49715a86bd55SVille Syrjälä case DRM_FORMAT_YUV422: 49725a86bd55SVille Syrjälä case DRM_FORMAT_YVU422: 49735a86bd55SVille Syrjälä case DRM_FORMAT_YUV444: 49745a86bd55SVille Syrjälä case DRM_FORMAT_YVU444: 49755a86bd55SVille Syrjälä return 1; 49765a86bd55SVille Syrjälä default: 49775a86bd55SVille Syrjälä drm_fb_get_bpp_depth(format, &depth, &bpp); 49785a86bd55SVille Syrjälä return bpp >> 3; 49795a86bd55SVille Syrjälä } 49805a86bd55SVille Syrjälä } 49815a86bd55SVille Syrjälä EXPORT_SYMBOL(drm_format_plane_cpp); 498201b68b04SVille Syrjälä 498301b68b04SVille Syrjälä /** 498401b68b04SVille Syrjälä * drm_format_horz_chroma_subsampling - get the horizontal chroma subsampling factor 498501b68b04SVille Syrjälä * @format: pixel format (DRM_FORMAT_*) 498601b68b04SVille Syrjälä * 4987c8e32cc1SDaniel Vetter * Returns: 498801b68b04SVille Syrjälä * The horizontal chroma subsampling factor for the 498901b68b04SVille Syrjälä * specified pixel format. 499001b68b04SVille Syrjälä */ 499101b68b04SVille Syrjälä int drm_format_horz_chroma_subsampling(uint32_t format) 499201b68b04SVille Syrjälä { 499301b68b04SVille Syrjälä switch (format) { 499401b68b04SVille Syrjälä case DRM_FORMAT_YUV411: 499501b68b04SVille Syrjälä case DRM_FORMAT_YVU411: 499601b68b04SVille Syrjälä case DRM_FORMAT_YUV410: 499701b68b04SVille Syrjälä case DRM_FORMAT_YVU410: 499801b68b04SVille Syrjälä return 4; 499901b68b04SVille Syrjälä case DRM_FORMAT_YUYV: 500001b68b04SVille Syrjälä case DRM_FORMAT_YVYU: 500101b68b04SVille Syrjälä case DRM_FORMAT_UYVY: 500201b68b04SVille Syrjälä case DRM_FORMAT_VYUY: 500301b68b04SVille Syrjälä case DRM_FORMAT_NV12: 500401b68b04SVille Syrjälä case DRM_FORMAT_NV21: 500501b68b04SVille Syrjälä case DRM_FORMAT_NV16: 500601b68b04SVille Syrjälä case DRM_FORMAT_NV61: 500701b68b04SVille Syrjälä case DRM_FORMAT_YUV422: 500801b68b04SVille Syrjälä case DRM_FORMAT_YVU422: 500901b68b04SVille Syrjälä case DRM_FORMAT_YUV420: 501001b68b04SVille Syrjälä case DRM_FORMAT_YVU420: 501101b68b04SVille Syrjälä return 2; 501201b68b04SVille Syrjälä default: 501301b68b04SVille Syrjälä return 1; 501401b68b04SVille Syrjälä } 501501b68b04SVille Syrjälä } 501601b68b04SVille Syrjälä EXPORT_SYMBOL(drm_format_horz_chroma_subsampling); 501701b68b04SVille Syrjälä 501801b68b04SVille Syrjälä /** 501901b68b04SVille Syrjälä * drm_format_vert_chroma_subsampling - get the vertical chroma subsampling factor 502001b68b04SVille Syrjälä * @format: pixel format (DRM_FORMAT_*) 502101b68b04SVille Syrjälä * 5022c8e32cc1SDaniel Vetter * Returns: 502301b68b04SVille Syrjälä * The vertical chroma subsampling factor for the 502401b68b04SVille Syrjälä * specified pixel format. 502501b68b04SVille Syrjälä */ 502601b68b04SVille Syrjälä int drm_format_vert_chroma_subsampling(uint32_t format) 502701b68b04SVille Syrjälä { 502801b68b04SVille Syrjälä switch (format) { 502901b68b04SVille Syrjälä case DRM_FORMAT_YUV410: 503001b68b04SVille Syrjälä case DRM_FORMAT_YVU410: 503101b68b04SVille Syrjälä return 4; 503201b68b04SVille Syrjälä case DRM_FORMAT_YUV420: 503301b68b04SVille Syrjälä case DRM_FORMAT_YVU420: 503401b68b04SVille Syrjälä case DRM_FORMAT_NV12: 503501b68b04SVille Syrjälä case DRM_FORMAT_NV21: 503601b68b04SVille Syrjälä return 2; 503701b68b04SVille Syrjälä default: 503801b68b04SVille Syrjälä return 1; 503901b68b04SVille Syrjälä } 504001b68b04SVille Syrjälä } 504101b68b04SVille Syrjälä EXPORT_SYMBOL(drm_format_vert_chroma_subsampling); 504287d24fc3SLaurent Pinchart 504387d24fc3SLaurent Pinchart /** 50443c9855f6SVille Syrjälä * drm_rotation_simplify() - Try to simplify the rotation 50453c9855f6SVille Syrjälä * @rotation: Rotation to be simplified 50463c9855f6SVille Syrjälä * @supported_rotations: Supported rotations 50473c9855f6SVille Syrjälä * 50483c9855f6SVille Syrjälä * Attempt to simplify the rotation to a form that is supported. 50493c9855f6SVille Syrjälä * Eg. if the hardware supports everything except DRM_REFLECT_X 50503c9855f6SVille Syrjälä * one could call this function like this: 50513c9855f6SVille Syrjälä * 50523c9855f6SVille Syrjälä * drm_rotation_simplify(rotation, BIT(DRM_ROTATE_0) | 50533c9855f6SVille Syrjälä * BIT(DRM_ROTATE_90) | BIT(DRM_ROTATE_180) | 50543c9855f6SVille Syrjälä * BIT(DRM_ROTATE_270) | BIT(DRM_REFLECT_Y)); 50553c9855f6SVille Syrjälä * 50563c9855f6SVille Syrjälä * to eliminate the DRM_ROTATE_X flag. Depending on what kind of 50573c9855f6SVille Syrjälä * transforms the hardware supports, this function may not 50583c9855f6SVille Syrjälä * be able to produce a supported transform, so the caller should 50593c9855f6SVille Syrjälä * check the result afterwards. 50603c9855f6SVille Syrjälä */ 50613c9855f6SVille Syrjälä unsigned int drm_rotation_simplify(unsigned int rotation, 50623c9855f6SVille Syrjälä unsigned int supported_rotations) 50633c9855f6SVille Syrjälä { 50643c9855f6SVille Syrjälä if (rotation & ~supported_rotations) { 50653c9855f6SVille Syrjälä rotation ^= BIT(DRM_REFLECT_X) | BIT(DRM_REFLECT_Y); 50663c9855f6SVille Syrjälä rotation = (rotation & ~0xf) | BIT((ffs(rotation & 0xf) + 1) % 4); 50673c9855f6SVille Syrjälä } 50683c9855f6SVille Syrjälä 50693c9855f6SVille Syrjälä return rotation; 50703c9855f6SVille Syrjälä } 50713c9855f6SVille Syrjälä EXPORT_SYMBOL(drm_rotation_simplify); 50723c9855f6SVille Syrjälä 50733c9855f6SVille Syrjälä /** 507487d24fc3SLaurent Pinchart * drm_mode_config_init - initialize DRM mode_configuration structure 507587d24fc3SLaurent Pinchart * @dev: DRM device 507687d24fc3SLaurent Pinchart * 507787d24fc3SLaurent Pinchart * Initialize @dev's mode_config structure, used for tracking the graphics 507887d24fc3SLaurent Pinchart * configuration of @dev. 507987d24fc3SLaurent Pinchart * 508087d24fc3SLaurent Pinchart * Since this initializes the modeset locks, no locking is possible. Which is no 508187d24fc3SLaurent Pinchart * problem, since this should happen single threaded at init time. It is the 508287d24fc3SLaurent Pinchart * driver's problem to ensure this guarantee. 508387d24fc3SLaurent Pinchart * 508487d24fc3SLaurent Pinchart */ 508587d24fc3SLaurent Pinchart void drm_mode_config_init(struct drm_device *dev) 508687d24fc3SLaurent Pinchart { 508787d24fc3SLaurent Pinchart mutex_init(&dev->mode_config.mutex); 508851fd371bSRob Clark drm_modeset_lock_init(&dev->mode_config.connection_mutex); 508987d24fc3SLaurent Pinchart mutex_init(&dev->mode_config.idr_mutex); 509087d24fc3SLaurent Pinchart mutex_init(&dev->mode_config.fb_lock); 509187d24fc3SLaurent Pinchart INIT_LIST_HEAD(&dev->mode_config.fb_list); 509287d24fc3SLaurent Pinchart INIT_LIST_HEAD(&dev->mode_config.crtc_list); 509387d24fc3SLaurent Pinchart INIT_LIST_HEAD(&dev->mode_config.connector_list); 50943b336ec4SSean Paul INIT_LIST_HEAD(&dev->mode_config.bridge_list); 509587d24fc3SLaurent Pinchart INIT_LIST_HEAD(&dev->mode_config.encoder_list); 509687d24fc3SLaurent Pinchart INIT_LIST_HEAD(&dev->mode_config.property_list); 509787d24fc3SLaurent Pinchart INIT_LIST_HEAD(&dev->mode_config.property_blob_list); 509887d24fc3SLaurent Pinchart INIT_LIST_HEAD(&dev->mode_config.plane_list); 509987d24fc3SLaurent Pinchart idr_init(&dev->mode_config.crtc_idr); 510087d24fc3SLaurent Pinchart 510187d24fc3SLaurent Pinchart drm_modeset_lock_all(dev); 510287d24fc3SLaurent Pinchart drm_mode_create_standard_connector_properties(dev); 51039922ab5aSRob Clark drm_mode_create_standard_plane_properties(dev); 510487d24fc3SLaurent Pinchart drm_modeset_unlock_all(dev); 510587d24fc3SLaurent Pinchart 510687d24fc3SLaurent Pinchart /* Just to be sure */ 510787d24fc3SLaurent Pinchart dev->mode_config.num_fb = 0; 510887d24fc3SLaurent Pinchart dev->mode_config.num_connector = 0; 510987d24fc3SLaurent Pinchart dev->mode_config.num_crtc = 0; 511087d24fc3SLaurent Pinchart dev->mode_config.num_encoder = 0; 5111e27dde3eSMatt Roper dev->mode_config.num_overlay_plane = 0; 5112e27dde3eSMatt Roper dev->mode_config.num_total_plane = 0; 511387d24fc3SLaurent Pinchart } 511487d24fc3SLaurent Pinchart EXPORT_SYMBOL(drm_mode_config_init); 511587d24fc3SLaurent Pinchart 511687d24fc3SLaurent Pinchart /** 511787d24fc3SLaurent Pinchart * drm_mode_config_cleanup - free up DRM mode_config info 511887d24fc3SLaurent Pinchart * @dev: DRM device 511987d24fc3SLaurent Pinchart * 512087d24fc3SLaurent Pinchart * Free up all the connectors and CRTCs associated with this DRM device, then 512187d24fc3SLaurent Pinchart * free up the framebuffers and associated buffer objects. 512287d24fc3SLaurent Pinchart * 512387d24fc3SLaurent Pinchart * Note that since this /should/ happen single-threaded at driver/device 512487d24fc3SLaurent Pinchart * teardown time, no locking is required. It's the driver's job to ensure that 512587d24fc3SLaurent Pinchart * this guarantee actually holds true. 512687d24fc3SLaurent Pinchart * 512787d24fc3SLaurent Pinchart * FIXME: cleanup any dangling user buffer objects too 512887d24fc3SLaurent Pinchart */ 512987d24fc3SLaurent Pinchart void drm_mode_config_cleanup(struct drm_device *dev) 513087d24fc3SLaurent Pinchart { 513187d24fc3SLaurent Pinchart struct drm_connector *connector, *ot; 513287d24fc3SLaurent Pinchart struct drm_crtc *crtc, *ct; 513387d24fc3SLaurent Pinchart struct drm_encoder *encoder, *enct; 51343b336ec4SSean Paul struct drm_bridge *bridge, *brt; 513587d24fc3SLaurent Pinchart struct drm_framebuffer *fb, *fbt; 513687d24fc3SLaurent Pinchart struct drm_property *property, *pt; 513787d24fc3SLaurent Pinchart struct drm_property_blob *blob, *bt; 513887d24fc3SLaurent Pinchart struct drm_plane *plane, *plt; 513987d24fc3SLaurent Pinchart 514087d24fc3SLaurent Pinchart list_for_each_entry_safe(encoder, enct, &dev->mode_config.encoder_list, 514187d24fc3SLaurent Pinchart head) { 514287d24fc3SLaurent Pinchart encoder->funcs->destroy(encoder); 514387d24fc3SLaurent Pinchart } 514487d24fc3SLaurent Pinchart 51453b336ec4SSean Paul list_for_each_entry_safe(bridge, brt, 51463b336ec4SSean Paul &dev->mode_config.bridge_list, head) { 51473b336ec4SSean Paul bridge->funcs->destroy(bridge); 51483b336ec4SSean Paul } 51493b336ec4SSean Paul 515087d24fc3SLaurent Pinchart list_for_each_entry_safe(connector, ot, 515187d24fc3SLaurent Pinchart &dev->mode_config.connector_list, head) { 515287d24fc3SLaurent Pinchart connector->funcs->destroy(connector); 515387d24fc3SLaurent Pinchart } 515487d24fc3SLaurent Pinchart 515587d24fc3SLaurent Pinchart list_for_each_entry_safe(property, pt, &dev->mode_config.property_list, 515687d24fc3SLaurent Pinchart head) { 515787d24fc3SLaurent Pinchart drm_property_destroy(dev, property); 515887d24fc3SLaurent Pinchart } 515987d24fc3SLaurent Pinchart 516087d24fc3SLaurent Pinchart list_for_each_entry_safe(blob, bt, &dev->mode_config.property_blob_list, 516187d24fc3SLaurent Pinchart head) { 516287d24fc3SLaurent Pinchart drm_property_destroy_blob(dev, blob); 516387d24fc3SLaurent Pinchart } 516487d24fc3SLaurent Pinchart 516587d24fc3SLaurent Pinchart /* 516687d24fc3SLaurent Pinchart * Single-threaded teardown context, so it's not required to grab the 516787d24fc3SLaurent Pinchart * fb_lock to protect against concurrent fb_list access. Contrary, it 516887d24fc3SLaurent Pinchart * would actually deadlock with the drm_framebuffer_cleanup function. 516987d24fc3SLaurent Pinchart * 517087d24fc3SLaurent Pinchart * Also, if there are any framebuffers left, that's a driver leak now, 517187d24fc3SLaurent Pinchart * so politely WARN about this. 517287d24fc3SLaurent Pinchart */ 517387d24fc3SLaurent Pinchart WARN_ON(!list_empty(&dev->mode_config.fb_list)); 517487d24fc3SLaurent Pinchart list_for_each_entry_safe(fb, fbt, &dev->mode_config.fb_list, head) { 517587d24fc3SLaurent Pinchart drm_framebuffer_remove(fb); 517687d24fc3SLaurent Pinchart } 517787d24fc3SLaurent Pinchart 517887d24fc3SLaurent Pinchart list_for_each_entry_safe(plane, plt, &dev->mode_config.plane_list, 517987d24fc3SLaurent Pinchart head) { 518087d24fc3SLaurent Pinchart plane->funcs->destroy(plane); 518187d24fc3SLaurent Pinchart } 518287d24fc3SLaurent Pinchart 518387d24fc3SLaurent Pinchart list_for_each_entry_safe(crtc, ct, &dev->mode_config.crtc_list, head) { 518487d24fc3SLaurent Pinchart crtc->funcs->destroy(crtc); 518587d24fc3SLaurent Pinchart } 518687d24fc3SLaurent Pinchart 518787d24fc3SLaurent Pinchart idr_destroy(&dev->mode_config.crtc_idr); 518851fd371bSRob Clark drm_modeset_lock_fini(&dev->mode_config.connection_mutex); 518987d24fc3SLaurent Pinchart } 519087d24fc3SLaurent Pinchart EXPORT_SYMBOL(drm_mode_config_cleanup); 5191c1df5f3cSVille Syrjälä 5192c1df5f3cSVille Syrjälä struct drm_property *drm_mode_create_rotation_property(struct drm_device *dev, 5193c1df5f3cSVille Syrjälä unsigned int supported_rotations) 5194c1df5f3cSVille Syrjälä { 5195c1df5f3cSVille Syrjälä static const struct drm_prop_enum_list props[] = { 5196c1df5f3cSVille Syrjälä { DRM_ROTATE_0, "rotate-0" }, 5197c1df5f3cSVille Syrjälä { DRM_ROTATE_90, "rotate-90" }, 5198c1df5f3cSVille Syrjälä { DRM_ROTATE_180, "rotate-180" }, 5199c1df5f3cSVille Syrjälä { DRM_ROTATE_270, "rotate-270" }, 5200c1df5f3cSVille Syrjälä { DRM_REFLECT_X, "reflect-x" }, 5201c1df5f3cSVille Syrjälä { DRM_REFLECT_Y, "reflect-y" }, 5202c1df5f3cSVille Syrjälä }; 5203c1df5f3cSVille Syrjälä 5204c1df5f3cSVille Syrjälä return drm_property_create_bitmask(dev, 0, "rotation", 5205c1df5f3cSVille Syrjälä props, ARRAY_SIZE(props), 5206c1df5f3cSVille Syrjälä supported_rotations); 5207c1df5f3cSVille Syrjälä } 5208c1df5f3cSVille Syrjälä EXPORT_SYMBOL(drm_mode_create_rotation_property); 5209