1f453ba04SDave Airlie /* 2f453ba04SDave Airlie * Copyright (c) 2006-2008 Intel Corporation 3f453ba04SDave Airlie * Copyright (c) 2007 Dave Airlie <airlied@linux.ie> 4f453ba04SDave Airlie * Copyright (c) 2008 Red Hat Inc. 5f453ba04SDave Airlie * 6f453ba04SDave Airlie * DRM core CRTC related functions 7f453ba04SDave Airlie * 8f453ba04SDave Airlie * Permission to use, copy, modify, distribute, and sell this software and its 9f453ba04SDave Airlie * documentation for any purpose is hereby granted without fee, provided that 10f453ba04SDave Airlie * the above copyright notice appear in all copies and that both that copyright 11f453ba04SDave Airlie * notice and this permission notice appear in supporting documentation, and 12f453ba04SDave Airlie * that the name of the copyright holders not be used in advertising or 13f453ba04SDave Airlie * publicity pertaining to distribution of the software without specific, 14f453ba04SDave Airlie * written prior permission. The copyright holders make no representations 15f453ba04SDave Airlie * about the suitability of this software for any purpose. It is provided "as 16f453ba04SDave Airlie * is" without express or implied warranty. 17f453ba04SDave Airlie * 18f453ba04SDave Airlie * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, 19f453ba04SDave Airlie * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO 20f453ba04SDave Airlie * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR 21f453ba04SDave Airlie * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, 22f453ba04SDave Airlie * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER 23f453ba04SDave Airlie * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE 24f453ba04SDave Airlie * OF THIS SOFTWARE. 25f453ba04SDave Airlie * 26f453ba04SDave Airlie * Authors: 27f453ba04SDave Airlie * Keith Packard 28f453ba04SDave Airlie * Eric Anholt <eric@anholt.net> 29f453ba04SDave Airlie * Dave Airlie <airlied@linux.ie> 30f453ba04SDave Airlie * Jesse Barnes <jesse.barnes@intel.com> 31f453ba04SDave Airlie */ 326ba6d03eSVille Syrjälä #include <linux/ctype.h> 33f453ba04SDave Airlie #include <linux/list.h> 345a0e3ad6STejun Heo #include <linux/slab.h> 352d1a8a48SPaul Gortmaker #include <linux/export.h> 36760285e7SDavid Howells #include <drm/drmP.h> 37760285e7SDavid Howells #include <drm/drm_crtc.h> 38760285e7SDavid Howells #include <drm/drm_edid.h> 39760285e7SDavid Howells #include <drm/drm_fourcc.h> 4051fd371bSRob Clark #include <drm/drm_modeset_lock.h> 4188a48e29SRob Clark #include <drm/drm_atomic.h> 42f453ba04SDave Airlie 438bd441b2SDaniel Vetter #include "drm_crtc_internal.h" 4467d0ec4eSDaniel Vetter #include "drm_internal.h" 458bd441b2SDaniel Vetter 469a6f5130SChris Wilson static struct drm_framebuffer * 479a6f5130SChris Wilson internal_framebuffer_create(struct drm_device *dev, 481eb83451SVille Syrjälä const struct drm_mode_fb_cmd2 *r, 49c394c2b0SMatt Roper struct drm_file *file_priv); 50c394c2b0SMatt Roper 51f453ba04SDave Airlie /* Avoid boilerplate. I'm tired of typing. */ 52f453ba04SDave Airlie #define DRM_ENUM_NAME_FN(fnname, list) \ 53d20d3174SVille Syrjälä const char *fnname(int val) \ 54f453ba04SDave Airlie { \ 55f453ba04SDave Airlie int i; \ 56f453ba04SDave Airlie for (i = 0; i < ARRAY_SIZE(list); i++) { \ 57f453ba04SDave Airlie if (list[i].type == val) \ 58f453ba04SDave Airlie return list[i].name; \ 59f453ba04SDave Airlie } \ 60f453ba04SDave Airlie return "(unknown)"; \ 61f453ba04SDave Airlie } 62f453ba04SDave Airlie 63f453ba04SDave Airlie /* 64f453ba04SDave Airlie * Global properties 65f453ba04SDave Airlie */ 664dfd909fSThierry Reding static const struct drm_prop_enum_list drm_dpms_enum_list[] = { 674dfd909fSThierry Reding { DRM_MODE_DPMS_ON, "On" }, 68f453ba04SDave Airlie { DRM_MODE_DPMS_STANDBY, "Standby" }, 69f453ba04SDave Airlie { DRM_MODE_DPMS_SUSPEND, "Suspend" }, 70f453ba04SDave Airlie { DRM_MODE_DPMS_OFF, "Off" } 71f453ba04SDave Airlie }; 72f453ba04SDave Airlie 73f453ba04SDave Airlie DRM_ENUM_NAME_FN(drm_get_dpms_name, drm_dpms_enum_list) 74f453ba04SDave Airlie 754dfd909fSThierry Reding static const struct drm_prop_enum_list drm_plane_type_enum_list[] = { 769922ab5aSRob Clark { DRM_PLANE_TYPE_OVERLAY, "Overlay" }, 779922ab5aSRob Clark { DRM_PLANE_TYPE_PRIMARY, "Primary" }, 789922ab5aSRob Clark { DRM_PLANE_TYPE_CURSOR, "Cursor" }, 799922ab5aSRob Clark }; 809922ab5aSRob Clark 81f453ba04SDave Airlie /* 82f453ba04SDave Airlie * Optional properties 83f453ba04SDave Airlie */ 844dfd909fSThierry Reding static const struct drm_prop_enum_list drm_scaling_mode_enum_list[] = { 8553bd8389SJesse Barnes { DRM_MODE_SCALE_NONE, "None" }, 8653bd8389SJesse Barnes { DRM_MODE_SCALE_FULLSCREEN, "Full" }, 8753bd8389SJesse Barnes { DRM_MODE_SCALE_CENTER, "Center" }, 8853bd8389SJesse Barnes { DRM_MODE_SCALE_ASPECT, "Full aspect" }, 89f453ba04SDave Airlie }; 90f453ba04SDave Airlie 91ff587e45SVandana Kannan static const struct drm_prop_enum_list drm_aspect_ratio_enum_list[] = { 92ff587e45SVandana Kannan { DRM_MODE_PICTURE_ASPECT_NONE, "Automatic" }, 93ff587e45SVandana Kannan { DRM_MODE_PICTURE_ASPECT_4_3, "4:3" }, 94ff587e45SVandana Kannan { DRM_MODE_PICTURE_ASPECT_16_9, "16:9" }, 95ff587e45SVandana Kannan }; 96ff587e45SVandana Kannan 97f453ba04SDave Airlie /* 98f453ba04SDave Airlie * Non-global properties, but "required" for certain connectors. 99f453ba04SDave Airlie */ 1004dfd909fSThierry Reding static const struct drm_prop_enum_list drm_dvi_i_select_enum_list[] = { 101f453ba04SDave Airlie { DRM_MODE_SUBCONNECTOR_Automatic, "Automatic" }, /* DVI-I and TV-out */ 102f453ba04SDave Airlie { DRM_MODE_SUBCONNECTOR_DVID, "DVI-D" }, /* DVI-I */ 103f453ba04SDave Airlie { DRM_MODE_SUBCONNECTOR_DVIA, "DVI-A" }, /* DVI-I */ 104f453ba04SDave Airlie }; 105f453ba04SDave Airlie 106f453ba04SDave Airlie DRM_ENUM_NAME_FN(drm_get_dvi_i_select_name, drm_dvi_i_select_enum_list) 107f453ba04SDave Airlie 1084dfd909fSThierry Reding static const struct drm_prop_enum_list drm_dvi_i_subconnector_enum_list[] = { 109f453ba04SDave Airlie { DRM_MODE_SUBCONNECTOR_Unknown, "Unknown" }, /* DVI-I and TV-out */ 110f453ba04SDave Airlie { DRM_MODE_SUBCONNECTOR_DVID, "DVI-D" }, /* DVI-I */ 111f453ba04SDave Airlie { DRM_MODE_SUBCONNECTOR_DVIA, "DVI-A" }, /* DVI-I */ 112f453ba04SDave Airlie }; 113f453ba04SDave Airlie 114f453ba04SDave Airlie DRM_ENUM_NAME_FN(drm_get_dvi_i_subconnector_name, 115f453ba04SDave Airlie drm_dvi_i_subconnector_enum_list) 116f453ba04SDave Airlie 1174dfd909fSThierry Reding static const struct drm_prop_enum_list drm_tv_select_enum_list[] = { 118f453ba04SDave Airlie { DRM_MODE_SUBCONNECTOR_Automatic, "Automatic" }, /* DVI-I and TV-out */ 119f453ba04SDave Airlie { DRM_MODE_SUBCONNECTOR_Composite, "Composite" }, /* TV-out */ 120f453ba04SDave Airlie { DRM_MODE_SUBCONNECTOR_SVIDEO, "SVIDEO" }, /* TV-out */ 121f453ba04SDave Airlie { DRM_MODE_SUBCONNECTOR_Component, "Component" }, /* TV-out */ 122aeaa1ad3SFrancisco Jerez { DRM_MODE_SUBCONNECTOR_SCART, "SCART" }, /* TV-out */ 123f453ba04SDave Airlie }; 124f453ba04SDave Airlie 125f453ba04SDave Airlie DRM_ENUM_NAME_FN(drm_get_tv_select_name, drm_tv_select_enum_list) 126f453ba04SDave Airlie 1274dfd909fSThierry Reding static const struct drm_prop_enum_list drm_tv_subconnector_enum_list[] = { 128f453ba04SDave Airlie { DRM_MODE_SUBCONNECTOR_Unknown, "Unknown" }, /* DVI-I and TV-out */ 129f453ba04SDave Airlie { DRM_MODE_SUBCONNECTOR_Composite, "Composite" }, /* TV-out */ 130f453ba04SDave Airlie { DRM_MODE_SUBCONNECTOR_SVIDEO, "SVIDEO" }, /* TV-out */ 131f453ba04SDave Airlie { DRM_MODE_SUBCONNECTOR_Component, "Component" }, /* TV-out */ 132aeaa1ad3SFrancisco Jerez { DRM_MODE_SUBCONNECTOR_SCART, "SCART" }, /* TV-out */ 133f453ba04SDave Airlie }; 134f453ba04SDave Airlie 135f453ba04SDave Airlie DRM_ENUM_NAME_FN(drm_get_tv_subconnector_name, 136f453ba04SDave Airlie drm_tv_subconnector_enum_list) 137f453ba04SDave Airlie 138d20d3174SVille Syrjälä static const struct drm_prop_enum_list drm_dirty_info_enum_list[] = { 139884840aaSJakob Bornecrantz { DRM_MODE_DIRTY_OFF, "Off" }, 140884840aaSJakob Bornecrantz { DRM_MODE_DIRTY_ON, "On" }, 141884840aaSJakob Bornecrantz { DRM_MODE_DIRTY_ANNOTATE, "Annotate" }, 142884840aaSJakob Bornecrantz }; 143884840aaSJakob Bornecrantz 144f453ba04SDave Airlie struct drm_conn_prop_enum_list { 145f453ba04SDave Airlie int type; 146d20d3174SVille Syrjälä const char *name; 147b21e3afeSIlia Mirkin struct ida ida; 148f453ba04SDave Airlie }; 149f453ba04SDave Airlie 150f453ba04SDave Airlie /* 151f453ba04SDave Airlie * Connector and encoder types. 152f453ba04SDave Airlie */ 1534dfd909fSThierry Reding static struct drm_conn_prop_enum_list drm_connector_enum_list[] = { 1544dfd909fSThierry Reding { DRM_MODE_CONNECTOR_Unknown, "Unknown" }, 155b21e3afeSIlia Mirkin { DRM_MODE_CONNECTOR_VGA, "VGA" }, 156b21e3afeSIlia Mirkin { DRM_MODE_CONNECTOR_DVII, "DVI-I" }, 157b21e3afeSIlia Mirkin { DRM_MODE_CONNECTOR_DVID, "DVI-D" }, 158b21e3afeSIlia Mirkin { DRM_MODE_CONNECTOR_DVIA, "DVI-A" }, 159b21e3afeSIlia Mirkin { DRM_MODE_CONNECTOR_Composite, "Composite" }, 160b21e3afeSIlia Mirkin { DRM_MODE_CONNECTOR_SVIDEO, "SVIDEO" }, 161b21e3afeSIlia Mirkin { DRM_MODE_CONNECTOR_LVDS, "LVDS" }, 162b21e3afeSIlia Mirkin { DRM_MODE_CONNECTOR_Component, "Component" }, 163b21e3afeSIlia Mirkin { DRM_MODE_CONNECTOR_9PinDIN, "DIN" }, 164b21e3afeSIlia Mirkin { DRM_MODE_CONNECTOR_DisplayPort, "DP" }, 165b21e3afeSIlia Mirkin { DRM_MODE_CONNECTOR_HDMIA, "HDMI-A" }, 166b21e3afeSIlia Mirkin { DRM_MODE_CONNECTOR_HDMIB, "HDMI-B" }, 167b21e3afeSIlia Mirkin { DRM_MODE_CONNECTOR_TV, "TV" }, 168b21e3afeSIlia Mirkin { DRM_MODE_CONNECTOR_eDP, "eDP" }, 169b21e3afeSIlia Mirkin { DRM_MODE_CONNECTOR_VIRTUAL, "Virtual" }, 170b8923273SShobhit Kumar { DRM_MODE_CONNECTOR_DSI, "DSI" }, 1710b27c02aSEric Anholt { DRM_MODE_CONNECTOR_DPI, "DPI" }, 172f453ba04SDave Airlie }; 173f453ba04SDave Airlie 1744dfd909fSThierry Reding static const struct drm_prop_enum_list drm_encoder_enum_list[] = { 1754dfd909fSThierry Reding { DRM_MODE_ENCODER_NONE, "None" }, 176f453ba04SDave Airlie { DRM_MODE_ENCODER_DAC, "DAC" }, 177f453ba04SDave Airlie { DRM_MODE_ENCODER_TMDS, "TMDS" }, 178f453ba04SDave Airlie { DRM_MODE_ENCODER_LVDS, "LVDS" }, 179f453ba04SDave Airlie { DRM_MODE_ENCODER_TVDAC, "TV" }, 180a7331e5cSThomas Hellstrom { DRM_MODE_ENCODER_VIRTUAL, "Virtual" }, 181b8923273SShobhit Kumar { DRM_MODE_ENCODER_DSI, "DSI" }, 182182407a6SDave Airlie { DRM_MODE_ENCODER_DPMST, "DP MST" }, 1830b27c02aSEric Anholt { DRM_MODE_ENCODER_DPI, "DPI" }, 184f453ba04SDave Airlie }; 185f453ba04SDave Airlie 1864dfd909fSThierry Reding static const struct drm_prop_enum_list drm_subpixel_enum_list[] = { 187ac1bb36cSJesse Barnes { SubPixelUnknown, "Unknown" }, 188ac1bb36cSJesse Barnes { SubPixelHorizontalRGB, "Horizontal RGB" }, 189ac1bb36cSJesse Barnes { SubPixelHorizontalBGR, "Horizontal BGR" }, 190ac1bb36cSJesse Barnes { SubPixelVerticalRGB, "Vertical RGB" }, 191ac1bb36cSJesse Barnes { SubPixelVerticalBGR, "Vertical BGR" }, 192ac1bb36cSJesse Barnes { SubPixelNone, "None" }, 193ac1bb36cSJesse Barnes }; 194ac1bb36cSJesse Barnes 195b21e3afeSIlia Mirkin void drm_connector_ida_init(void) 196b21e3afeSIlia Mirkin { 197b21e3afeSIlia Mirkin int i; 198b21e3afeSIlia Mirkin 199b21e3afeSIlia Mirkin for (i = 0; i < ARRAY_SIZE(drm_connector_enum_list); i++) 200b21e3afeSIlia Mirkin ida_init(&drm_connector_enum_list[i].ida); 201b21e3afeSIlia Mirkin } 202b21e3afeSIlia Mirkin 203b21e3afeSIlia Mirkin void drm_connector_ida_destroy(void) 204b21e3afeSIlia Mirkin { 205b21e3afeSIlia Mirkin int i; 206b21e3afeSIlia Mirkin 207b21e3afeSIlia Mirkin for (i = 0; i < ARRAY_SIZE(drm_connector_enum_list); i++) 208b21e3afeSIlia Mirkin ida_destroy(&drm_connector_enum_list[i].ida); 209b21e3afeSIlia Mirkin } 210b21e3afeSIlia Mirkin 211c8e32cc1SDaniel Vetter /** 212c8e32cc1SDaniel Vetter * drm_get_connector_status_name - return a string for connector status 213c8e32cc1SDaniel Vetter * @status: connector status to compute name of 214c8e32cc1SDaniel Vetter * 215c8e32cc1SDaniel Vetter * In contrast to the other drm_get_*_name functions this one here returns a 216c8e32cc1SDaniel Vetter * const pointer and hence is threadsafe. 217c8e32cc1SDaniel Vetter */ 218d20d3174SVille Syrjälä const char *drm_get_connector_status_name(enum drm_connector_status status) 219f453ba04SDave Airlie { 220f453ba04SDave Airlie if (status == connector_status_connected) 221f453ba04SDave Airlie return "connected"; 222f453ba04SDave Airlie else if (status == connector_status_disconnected) 223f453ba04SDave Airlie return "disconnected"; 224f453ba04SDave Airlie else 225f453ba04SDave Airlie return "unknown"; 226f453ba04SDave Airlie } 227ed7951dcSLespiau, Damien EXPORT_SYMBOL(drm_get_connector_status_name); 228f453ba04SDave Airlie 229ac1bb36cSJesse Barnes /** 230ac1bb36cSJesse Barnes * drm_get_subpixel_order_name - return a string for a given subpixel enum 231ac1bb36cSJesse Barnes * @order: enum of subpixel_order 232ac1bb36cSJesse Barnes * 233ac1bb36cSJesse Barnes * Note you could abuse this and return something out of bounds, but that 234ac1bb36cSJesse Barnes * would be a caller error. No unscrubbed user data should make it here. 235ac1bb36cSJesse Barnes */ 236ac1bb36cSJesse Barnes const char *drm_get_subpixel_order_name(enum subpixel_order order) 237ac1bb36cSJesse Barnes { 238ac1bb36cSJesse Barnes return drm_subpixel_enum_list[order].name; 239ac1bb36cSJesse Barnes } 240ac1bb36cSJesse Barnes EXPORT_SYMBOL(drm_get_subpixel_order_name); 241ac1bb36cSJesse Barnes 2422ee39452SDave Airlie /* 2432ee39452SDave Airlie * Internal function to assign a slot in the object idr and optionally 2442ee39452SDave Airlie * register the object into the idr. 2452ee39452SDave Airlie */ 2462ee39452SDave Airlie static int drm_mode_object_get_reg(struct drm_device *dev, 2472ee39452SDave Airlie struct drm_mode_object *obj, 2482ee39452SDave Airlie uint32_t obj_type, 249d0f37cf6SDave Airlie bool register_obj, 250d0f37cf6SDave Airlie void (*obj_free_cb)(struct kref *kref)) 2512ee39452SDave Airlie { 2522ee39452SDave Airlie int ret; 2532ee39452SDave Airlie 2542ee39452SDave Airlie mutex_lock(&dev->mode_config.idr_mutex); 2552ee39452SDave Airlie ret = idr_alloc(&dev->mode_config.crtc_idr, register_obj ? obj : NULL, 1, 0, GFP_KERNEL); 2562ee39452SDave Airlie if (ret >= 0) { 2572ee39452SDave Airlie /* 2582ee39452SDave Airlie * Set up the object linking under the protection of the idr 2592ee39452SDave Airlie * lock so that other users can't see inconsistent state. 2602ee39452SDave Airlie */ 2612ee39452SDave Airlie obj->id = ret; 2622ee39452SDave Airlie obj->type = obj_type; 263d0f37cf6SDave Airlie if (obj_free_cb) { 264d0f37cf6SDave Airlie obj->free_cb = obj_free_cb; 265d0f37cf6SDave Airlie kref_init(&obj->refcount); 266d0f37cf6SDave Airlie } 2672ee39452SDave Airlie } 2682ee39452SDave Airlie mutex_unlock(&dev->mode_config.idr_mutex); 2692ee39452SDave Airlie 2702ee39452SDave Airlie return ret < 0 ? ret : 0; 2712ee39452SDave Airlie } 2722ee39452SDave Airlie 273f453ba04SDave Airlie /** 274065a50edSDaniel Vetter * drm_mode_object_get - allocate a new modeset identifier 275f453ba04SDave Airlie * @dev: DRM device 276065a50edSDaniel Vetter * @obj: object pointer, used to generate unique ID 277065a50edSDaniel Vetter * @obj_type: object type 278f453ba04SDave Airlie * 279f453ba04SDave Airlie * Create a unique identifier based on @ptr in @dev's identifier space. Used 280c8e32cc1SDaniel Vetter * for tracking modes, CRTCs and connectors. Note that despite the _get postfix 281c8e32cc1SDaniel Vetter * modeset identifiers are _not_ reference counted. Hence don't use this for 282c8e32cc1SDaniel Vetter * reference counted modeset objects like framebuffers. 283f453ba04SDave Airlie * 284c8e32cc1SDaniel Vetter * Returns: 2853c67d839SLukas Wunner * Zero on success, error code on failure. 286f453ba04SDave Airlie */ 2878bd441b2SDaniel Vetter int drm_mode_object_get(struct drm_device *dev, 288f453ba04SDave Airlie struct drm_mode_object *obj, uint32_t obj_type) 289f453ba04SDave Airlie { 290d0f37cf6SDave Airlie return drm_mode_object_get_reg(dev, obj, obj_type, true, NULL); 2914b096ac1SDaniel Vetter } 2924b096ac1SDaniel Vetter 2932ee39452SDave Airlie static void drm_mode_object_register(struct drm_device *dev, 2942ee39452SDave Airlie struct drm_mode_object *obj) 2952ee39452SDave Airlie { 2962ee39452SDave Airlie mutex_lock(&dev->mode_config.idr_mutex); 2972ee39452SDave Airlie idr_replace(&dev->mode_config.crtc_idr, obj, obj->id); 2982ee39452SDave Airlie mutex_unlock(&dev->mode_config.idr_mutex); 299f453ba04SDave Airlie } 300f453ba04SDave Airlie 301f453ba04SDave Airlie /** 3027c8f6d25SDave Airlie * drm_mode_object_unregister - free a modeset identifer 303f453ba04SDave Airlie * @dev: DRM device 304065a50edSDaniel Vetter * @object: object to free 305f453ba04SDave Airlie * 3067c8f6d25SDave Airlie * Free @id from @dev's unique identifier pool. 3077c8f6d25SDave Airlie * This function can be called multiple times, and guards against 3087c8f6d25SDave Airlie * multiple removals. 3097c8f6d25SDave Airlie * These modeset identifiers are _not_ reference counted. Hence don't use this 310c8e32cc1SDaniel Vetter * for reference counted modeset objects like framebuffers. 311f453ba04SDave Airlie */ 3127c8f6d25SDave Airlie void drm_mode_object_unregister(struct drm_device *dev, 313f453ba04SDave Airlie struct drm_mode_object *object) 314f453ba04SDave Airlie { 315ad2563c2SJesse Barnes mutex_lock(&dev->mode_config.idr_mutex); 3167c8f6d25SDave Airlie if (object->id) { 317f453ba04SDave Airlie idr_remove(&dev->mode_config.crtc_idr, object->id); 3187c8f6d25SDave Airlie object->id = 0; 3197c8f6d25SDave Airlie } 320ad2563c2SJesse Barnes mutex_unlock(&dev->mode_config.idr_mutex); 321f453ba04SDave Airlie } 322f453ba04SDave Airlie 32398f75de4SRob Clark static struct drm_mode_object *_object_find(struct drm_device *dev, 32498f75de4SRob Clark uint32_t id, uint32_t type) 32598f75de4SRob Clark { 32698f75de4SRob Clark struct drm_mode_object *obj = NULL; 32798f75de4SRob Clark 32898f75de4SRob Clark mutex_lock(&dev->mode_config.idr_mutex); 32998f75de4SRob Clark obj = idr_find(&dev->mode_config.crtc_idr, id); 330168c02ecSDaniel Vetter if (obj && type != DRM_MODE_OBJECT_ANY && obj->type != type) 331168c02ecSDaniel Vetter obj = NULL; 332168c02ecSDaniel Vetter if (obj && obj->id != id) 333168c02ecSDaniel Vetter obj = NULL; 33472fe90b8SDave Airlie 33572fe90b8SDave Airlie if (obj && obj->free_cb) { 33672fe90b8SDave Airlie if (!kref_get_unless_zero(&obj->refcount)) 33772fe90b8SDave Airlie obj = NULL; 33872fe90b8SDave Airlie } 33998f75de4SRob Clark mutex_unlock(&dev->mode_config.idr_mutex); 34098f75de4SRob Clark 34198f75de4SRob Clark return obj; 34298f75de4SRob Clark } 34398f75de4SRob Clark 344786b99edSDaniel Vetter /** 345786b99edSDaniel Vetter * drm_mode_object_find - look up a drm object with static lifetime 346786b99edSDaniel Vetter * @dev: drm device 347786b99edSDaniel Vetter * @id: id of the mode object 348786b99edSDaniel Vetter * @type: type of the mode object 349786b99edSDaniel Vetter * 35005981422SDaniel Vetter * This function is used to look up a modeset object. It will acquire a 35105981422SDaniel Vetter * reference for reference counted objects. This reference must be dropped again 35205981422SDaniel Vetter * by callind drm_mode_object_unreference(). 353786b99edSDaniel Vetter */ 3547a9c9060SDaniel Vetter struct drm_mode_object *drm_mode_object_find(struct drm_device *dev, 3557a9c9060SDaniel Vetter uint32_t id, uint32_t type) 356f453ba04SDave Airlie { 357ad2563c2SJesse Barnes struct drm_mode_object *obj = NULL; 358f453ba04SDave Airlie 35998f75de4SRob Clark obj = _object_find(dev, id, type); 360f453ba04SDave Airlie return obj; 361f453ba04SDave Airlie } 362f453ba04SDave Airlie EXPORT_SYMBOL(drm_mode_object_find); 363f453ba04SDave Airlie 36405981422SDaniel Vetter /** 36505981422SDaniel Vetter * drm_mode_object_unreference - decr the object refcnt 36605981422SDaniel Vetter * @obj: mode_object 36705981422SDaniel Vetter * 36805981422SDaniel Vetter * This functions decrements the object's refcount if it is a refcounted modeset 36905981422SDaniel Vetter * object. It is a no-op on any other object. This is used to drop references 37005981422SDaniel Vetter * acquired with drm_mode_object_reference(). 37105981422SDaniel Vetter */ 372d0f37cf6SDave Airlie void drm_mode_object_unreference(struct drm_mode_object *obj) 373d0f37cf6SDave Airlie { 374d0f37cf6SDave Airlie if (obj->free_cb) { 375d0f37cf6SDave Airlie DRM_DEBUG("OBJ ID: %d (%d)\n", obj->id, atomic_read(&obj->refcount.refcount)); 376d0f37cf6SDave Airlie kref_put(&obj->refcount, obj->free_cb); 377d0f37cf6SDave Airlie } 378d0f37cf6SDave Airlie } 379d0f37cf6SDave Airlie EXPORT_SYMBOL(drm_mode_object_unreference); 380d0f37cf6SDave Airlie 381d0f37cf6SDave Airlie /** 38205981422SDaniel Vetter * drm_mode_object_reference - incr the object refcnt 383d0f37cf6SDave Airlie * @obj: mode_object 384d0f37cf6SDave Airlie * 38505981422SDaniel Vetter * This functions increments the object's refcount if it is a refcounted modeset 38605981422SDaniel Vetter * object. It is a no-op on any other object. References should be dropped again 38705981422SDaniel Vetter * by calling drm_mode_object_unreference(). 388d0f37cf6SDave Airlie */ 389d0f37cf6SDave Airlie void drm_mode_object_reference(struct drm_mode_object *obj) 390d0f37cf6SDave Airlie { 391d0f37cf6SDave Airlie if (obj->free_cb) { 392d0f37cf6SDave Airlie DRM_DEBUG("OBJ ID: %d (%d)\n", obj->id, atomic_read(&obj->refcount.refcount)); 393d0f37cf6SDave Airlie kref_get(&obj->refcount); 394d0f37cf6SDave Airlie } 395d0f37cf6SDave Airlie } 396d0f37cf6SDave Airlie EXPORT_SYMBOL(drm_mode_object_reference); 397d0f37cf6SDave Airlie 398f55f1f91SDave Airlie static void drm_framebuffer_free(struct kref *kref) 399f55f1f91SDave Airlie { 400f55f1f91SDave Airlie struct drm_framebuffer *fb = 401d0f37cf6SDave Airlie container_of(kref, struct drm_framebuffer, base.refcount); 402f55f1f91SDave Airlie struct drm_device *dev = fb->dev; 403f55f1f91SDave Airlie 404f55f1f91SDave Airlie /* 405f55f1f91SDave Airlie * The lookup idr holds a weak reference, which has not necessarily been 406f55f1f91SDave Airlie * removed at this point. Check for that. 407f55f1f91SDave Airlie */ 40819ab3f8bSDave Airlie drm_mode_object_unregister(dev, &fb->base); 409f55f1f91SDave Airlie 410f55f1f91SDave Airlie fb->funcs->destroy(fb); 411f55f1f91SDave Airlie } 412f55f1f91SDave Airlie 413f453ba04SDave Airlie /** 414f453ba04SDave Airlie * drm_framebuffer_init - initialize a framebuffer 415f453ba04SDave Airlie * @dev: DRM device 416065a50edSDaniel Vetter * @fb: framebuffer to be initialized 417065a50edSDaniel Vetter * @funcs: ... with these functions 418f453ba04SDave Airlie * 419f453ba04SDave Airlie * Allocates an ID for the framebuffer's parent mode object, sets its mode 420f453ba04SDave Airlie * functions & device file and adds it to the master fd list. 421f453ba04SDave Airlie * 4224b096ac1SDaniel Vetter * IMPORTANT: 4234b096ac1SDaniel Vetter * This functions publishes the fb and makes it available for concurrent access 4244b096ac1SDaniel Vetter * by other users. Which means by this point the fb _must_ be fully set up - 4254b096ac1SDaniel Vetter * since all the fb attributes are invariant over its lifetime, no further 4264b096ac1SDaniel Vetter * locking but only correct reference counting is required. 4274b096ac1SDaniel Vetter * 428c8e32cc1SDaniel Vetter * Returns: 429af901ca1SAndré Goddard Rosa * Zero on success, error code on failure. 430f453ba04SDave Airlie */ 431f453ba04SDave Airlie int drm_framebuffer_init(struct drm_device *dev, struct drm_framebuffer *fb, 432f453ba04SDave Airlie const struct drm_framebuffer_funcs *funcs) 433f453ba04SDave Airlie { 434f453ba04SDave Airlie int ret; 435f453ba04SDave Airlie 4364b096ac1SDaniel Vetter INIT_LIST_HEAD(&fb->filp_head); 4374b096ac1SDaniel Vetter fb->dev = dev; 4384b096ac1SDaniel Vetter fb->funcs = funcs; 439f7eff60eSRob Clark 440d0f37cf6SDave Airlie ret = drm_mode_object_get_reg(dev, &fb->base, DRM_MODE_OBJECT_FB, 4419cd47424SDave Airlie false, drm_framebuffer_free); 4426bfc56aaSVille Syrjälä if (ret) 4434b096ac1SDaniel Vetter goto out; 444f453ba04SDave Airlie 4459cd47424SDave Airlie mutex_lock(&dev->mode_config.fb_lock); 446f453ba04SDave Airlie dev->mode_config.num_fb++; 447f453ba04SDave Airlie list_add(&fb->head, &dev->mode_config.fb_list); 4482ddea3fdSDave Airlie mutex_unlock(&dev->mode_config.fb_lock); 449f453ba04SDave Airlie 4509cd47424SDave Airlie drm_mode_object_register(dev, &fb->base); 4519cd47424SDave Airlie out: 4523c67d839SLukas Wunner return ret; 453f453ba04SDave Airlie } 454f453ba04SDave Airlie EXPORT_SYMBOL(drm_framebuffer_init); 455f453ba04SDave Airlie 456f7eff60eSRob Clark /** 457786b99edSDaniel Vetter * drm_framebuffer_lookup - look up a drm framebuffer and grab a reference 458786b99edSDaniel Vetter * @dev: drm device 459786b99edSDaniel Vetter * @id: id of the fb object 460786b99edSDaniel Vetter * 461786b99edSDaniel Vetter * If successful, this grabs an additional reference to the framebuffer - 462786b99edSDaniel Vetter * callers need to make sure to eventually unreference the returned framebuffer 463c8e32cc1SDaniel Vetter * again, using @drm_framebuffer_unreference. 464786b99edSDaniel Vetter */ 465786b99edSDaniel Vetter struct drm_framebuffer *drm_framebuffer_lookup(struct drm_device *dev, 466786b99edSDaniel Vetter uint32_t id) 467786b99edSDaniel Vetter { 468cee26ac4SDave Airlie struct drm_mode_object *obj; 469cee26ac4SDave Airlie struct drm_framebuffer *fb = NULL; 470786b99edSDaniel Vetter 471cee26ac4SDave Airlie obj = _object_find(dev, id, DRM_MODE_OBJECT_FB); 47272fe90b8SDave Airlie if (obj) 473cee26ac4SDave Airlie fb = obj_to_fb(obj); 474786b99edSDaniel Vetter return fb; 475786b99edSDaniel Vetter } 476786b99edSDaniel Vetter EXPORT_SYMBOL(drm_framebuffer_lookup); 477786b99edSDaniel Vetter 478786b99edSDaniel Vetter /** 47936206361SDaniel Vetter * drm_framebuffer_unregister_private - unregister a private fb from the lookup idr 48036206361SDaniel Vetter * @fb: fb to unregister 48136206361SDaniel Vetter * 48236206361SDaniel Vetter * Drivers need to call this when cleaning up driver-private framebuffers, e.g. 48336206361SDaniel Vetter * those used for fbdev. Note that the caller must hold a reference of it's own, 48436206361SDaniel Vetter * i.e. the object may not be destroyed through this call (since it'll lead to a 48536206361SDaniel Vetter * locking inversion). 48636206361SDaniel Vetter */ 48736206361SDaniel Vetter void drm_framebuffer_unregister_private(struct drm_framebuffer *fb) 48836206361SDaniel Vetter { 489a39a357cSDaniel Vetter struct drm_device *dev; 490a39a357cSDaniel Vetter 491a39a357cSDaniel Vetter if (!fb) 492a39a357cSDaniel Vetter return; 493a39a357cSDaniel Vetter 494a39a357cSDaniel Vetter dev = fb->dev; 4952b677e8cSDaniel Vetter 4962b677e8cSDaniel Vetter /* Mark fb as reaped and drop idr ref. */ 49719ab3f8bSDave Airlie drm_mode_object_unregister(dev, &fb->base); 49836206361SDaniel Vetter } 49936206361SDaniel Vetter EXPORT_SYMBOL(drm_framebuffer_unregister_private); 50036206361SDaniel Vetter 50136206361SDaniel Vetter /** 502f453ba04SDave Airlie * drm_framebuffer_cleanup - remove a framebuffer object 503f453ba04SDave Airlie * @fb: framebuffer to remove 504f453ba04SDave Airlie * 505c8e32cc1SDaniel Vetter * Cleanup framebuffer. This function is intended to be used from the drivers 506c8e32cc1SDaniel Vetter * ->destroy callback. It can also be used to clean up driver private 507c8e32cc1SDaniel Vetter * framebuffers embedded into a larger structure. 50836206361SDaniel Vetter * 50936206361SDaniel Vetter * Note that this function does not remove the fb from active usuage - if it is 51036206361SDaniel Vetter * still used anywhere, hilarity can ensue since userspace could call getfb on 51136206361SDaniel Vetter * the id and get back -EINVAL. Obviously no concern at driver unload time. 51236206361SDaniel Vetter * 51336206361SDaniel Vetter * Also, the framebuffer will not be removed from the lookup idr - for 51436206361SDaniel Vetter * user-created framebuffers this will happen in in the rmfb ioctl. For 51536206361SDaniel Vetter * driver-private objects (e.g. for fbdev) drivers need to explicitly call 51636206361SDaniel Vetter * drm_framebuffer_unregister_private. 517f453ba04SDave Airlie */ 518f453ba04SDave Airlie void drm_framebuffer_cleanup(struct drm_framebuffer *fb) 519f453ba04SDave Airlie { 520f453ba04SDave Airlie struct drm_device *dev = fb->dev; 5218faf6b18SDaniel Vetter 5224b096ac1SDaniel Vetter mutex_lock(&dev->mode_config.fb_lock); 523f7eff60eSRob Clark list_del(&fb->head); 524f7eff60eSRob Clark dev->mode_config.num_fb--; 5254b096ac1SDaniel Vetter mutex_unlock(&dev->mode_config.fb_lock); 526f7eff60eSRob Clark } 527f7eff60eSRob Clark EXPORT_SYMBOL(drm_framebuffer_cleanup); 528f7eff60eSRob Clark 529f7eff60eSRob Clark /** 530f7eff60eSRob Clark * drm_framebuffer_remove - remove and unreference a framebuffer object 531f7eff60eSRob Clark * @fb: framebuffer to remove 532f7eff60eSRob Clark * 533f7eff60eSRob Clark * Scans all the CRTCs and planes in @dev's mode_config. If they're 53436206361SDaniel Vetter * using @fb, removes it, setting it to NULL. Then drops the reference to the 535b62584e3SDaniel Vetter * passed-in framebuffer. Might take the modeset locks. 536b62584e3SDaniel Vetter * 537b62584e3SDaniel Vetter * Note that this function optimizes the cleanup away if the caller holds the 538b62584e3SDaniel Vetter * last reference to the framebuffer. It is also guaranteed to not take the 539b62584e3SDaniel Vetter * modeset locks in this case. 540f7eff60eSRob Clark */ 541f7eff60eSRob Clark void drm_framebuffer_remove(struct drm_framebuffer *fb) 542f7eff60eSRob Clark { 543a39a357cSDaniel Vetter struct drm_device *dev; 544f453ba04SDave Airlie struct drm_crtc *crtc; 5458cf5c917SJesse Barnes struct drm_plane *plane; 5465ef5f72fSDave Airlie struct drm_mode_set set; 5475ef5f72fSDave Airlie int ret; 548f453ba04SDave Airlie 549a39a357cSDaniel Vetter if (!fb) 550a39a357cSDaniel Vetter return; 551a39a357cSDaniel Vetter 552a39a357cSDaniel Vetter dev = fb->dev; 553a39a357cSDaniel Vetter 5544b096ac1SDaniel Vetter WARN_ON(!list_empty(&fb->filp_head)); 5558faf6b18SDaniel Vetter 556b62584e3SDaniel Vetter /* 557b62584e3SDaniel Vetter * drm ABI mandates that we remove any deleted framebuffers from active 558b62584e3SDaniel Vetter * useage. But since most sane clients only remove framebuffers they no 559b62584e3SDaniel Vetter * longer need, try to optimize this away. 560b62584e3SDaniel Vetter * 561b62584e3SDaniel Vetter * Since we're holding a reference ourselves, observing a refcount of 1 562b62584e3SDaniel Vetter * means that we're the last holder and can skip it. Also, the refcount 563b62584e3SDaniel Vetter * can never increase from 1 again, so we don't need any barriers or 564b62584e3SDaniel Vetter * locks. 565b62584e3SDaniel Vetter * 566b62584e3SDaniel Vetter * Note that userspace could try to race with use and instate a new 567b62584e3SDaniel Vetter * usage _after_ we've cleared all current ones. End result will be an 568b62584e3SDaniel Vetter * in-use fb with fb-id == 0. Userspace is allowed to shoot its own foot 569b62584e3SDaniel Vetter * in this manner. 570b62584e3SDaniel Vetter */ 571747a598fSDave Airlie if (drm_framebuffer_read_refcount(fb) > 1) { 572b62584e3SDaniel Vetter drm_modeset_lock_all(dev); 573f453ba04SDave Airlie /* remove from any CRTC */ 5746295d607SDaniel Vetter drm_for_each_crtc(crtc, dev) { 575f4510a27SMatt Roper if (crtc->primary->fb == fb) { 5765ef5f72fSDave Airlie /* should turn off the crtc */ 5775ef5f72fSDave Airlie memset(&set, 0, sizeof(struct drm_mode_set)); 5785ef5f72fSDave Airlie set.crtc = crtc; 5795ef5f72fSDave Airlie set.fb = NULL; 5802d13b679SDaniel Vetter ret = drm_mode_set_config_internal(&set); 5815ef5f72fSDave Airlie if (ret) 5825ef5f72fSDave Airlie DRM_ERROR("failed to reset crtc %p when fb was deleted\n", crtc); 5835ef5f72fSDave Airlie } 584f453ba04SDave Airlie } 585f453ba04SDave Airlie 5866295d607SDaniel Vetter drm_for_each_plane(plane, dev) { 5879125e618SVille Syrjälä if (plane->fb == fb) 5889125e618SVille Syrjälä drm_plane_force_disable(plane); 5898cf5c917SJesse Barnes } 590b62584e3SDaniel Vetter drm_modeset_unlock_all(dev); 591b62584e3SDaniel Vetter } 5928cf5c917SJesse Barnes 593f7eff60eSRob Clark drm_framebuffer_unreference(fb); 594f453ba04SDave Airlie } 595f7eff60eSRob Clark EXPORT_SYMBOL(drm_framebuffer_remove); 596f453ba04SDave Airlie 59751fd371bSRob Clark DEFINE_WW_CLASS(crtc_ww_class); 59851fd371bSRob Clark 599fa3ab4c2SVille Syrjälä static unsigned int drm_num_crtcs(struct drm_device *dev) 600fa3ab4c2SVille Syrjälä { 601fa3ab4c2SVille Syrjälä unsigned int num = 0; 602fa3ab4c2SVille Syrjälä struct drm_crtc *tmp; 603fa3ab4c2SVille Syrjälä 604fa3ab4c2SVille Syrjälä drm_for_each_crtc(tmp, dev) { 605fa3ab4c2SVille Syrjälä num++; 606fa3ab4c2SVille Syrjälä } 607fa3ab4c2SVille Syrjälä 608fa3ab4c2SVille Syrjälä return num; 609fa3ab4c2SVille Syrjälä } 610fa3ab4c2SVille Syrjälä 61179190ea2SBenjamin Gaignard static int drm_crtc_register_all(struct drm_device *dev) 61279190ea2SBenjamin Gaignard { 61379190ea2SBenjamin Gaignard struct drm_crtc *crtc; 61479190ea2SBenjamin Gaignard int ret = 0; 61579190ea2SBenjamin Gaignard 61679190ea2SBenjamin Gaignard drm_for_each_crtc(crtc, dev) { 61779190ea2SBenjamin Gaignard if (crtc->funcs->late_register) 61879190ea2SBenjamin Gaignard ret = crtc->funcs->late_register(crtc); 61979190ea2SBenjamin Gaignard if (ret) 62079190ea2SBenjamin Gaignard return ret; 62179190ea2SBenjamin Gaignard } 62279190ea2SBenjamin Gaignard 62379190ea2SBenjamin Gaignard return 0; 62479190ea2SBenjamin Gaignard } 62579190ea2SBenjamin Gaignard 62679190ea2SBenjamin Gaignard static void drm_crtc_unregister_all(struct drm_device *dev) 62779190ea2SBenjamin Gaignard { 62879190ea2SBenjamin Gaignard struct drm_crtc *crtc; 62979190ea2SBenjamin Gaignard 63079190ea2SBenjamin Gaignard drm_for_each_crtc(crtc, dev) { 63179190ea2SBenjamin Gaignard if (crtc->funcs->early_unregister) 63279190ea2SBenjamin Gaignard crtc->funcs->early_unregister(crtc); 63379190ea2SBenjamin Gaignard } 63479190ea2SBenjamin Gaignard } 63579190ea2SBenjamin Gaignard 636f453ba04SDave Airlie /** 637e13161afSMatt Roper * drm_crtc_init_with_planes - Initialise a new CRTC object with 638e13161afSMatt Roper * specified primary and cursor planes. 639f453ba04SDave Airlie * @dev: DRM device 640f453ba04SDave Airlie * @crtc: CRTC object to init 641e13161afSMatt Roper * @primary: Primary plane for CRTC 642e13161afSMatt Roper * @cursor: Cursor plane for CRTC 643f453ba04SDave Airlie * @funcs: callbacks for the new CRTC 644f9882876SVille Syrjälä * @name: printf style format string for the CRTC name, or NULL for default name 645f453ba04SDave Airlie * 646ad6f5c34SVille Syrjälä * Inits a new object created as base part of a driver crtc object. 6476bfc56aaSVille Syrjälä * 648c8e32cc1SDaniel Vetter * Returns: 6496bfc56aaSVille Syrjälä * Zero on success, error code on failure. 650f453ba04SDave Airlie */ 651e13161afSMatt Roper int drm_crtc_init_with_planes(struct drm_device *dev, struct drm_crtc *crtc, 652e13161afSMatt Roper struct drm_plane *primary, 653fc1d3e44SMatt Roper struct drm_plane *cursor, 654f9882876SVille Syrjälä const struct drm_crtc_funcs *funcs, 655f9882876SVille Syrjälä const char *name, ...) 656f453ba04SDave Airlie { 65751fd371bSRob Clark struct drm_mode_config *config = &dev->mode_config; 6586bfc56aaSVille Syrjälä int ret; 6596bfc56aaSVille Syrjälä 660522cf91fSBenjamin Gaignard WARN_ON(primary && primary->type != DRM_PLANE_TYPE_PRIMARY); 661522cf91fSBenjamin Gaignard WARN_ON(cursor && cursor->type != DRM_PLANE_TYPE_CURSOR); 662522cf91fSBenjamin Gaignard 663f453ba04SDave Airlie crtc->dev = dev; 664f453ba04SDave Airlie crtc->funcs = funcs; 665f453ba04SDave Airlie 6663b24f7d6SDaniel Vetter INIT_LIST_HEAD(&crtc->commit_list); 6673b24f7d6SDaniel Vetter spin_lock_init(&crtc->commit_lock); 6683b24f7d6SDaniel Vetter 66951fd371bSRob Clark drm_modeset_lock_init(&crtc->mutex); 6706bfc56aaSVille Syrjälä ret = drm_mode_object_get(dev, &crtc->base, DRM_MODE_OBJECT_CRTC); 6716bfc56aaSVille Syrjälä if (ret) 672baf698b0SDaniel Vetter return ret; 673f453ba04SDave Airlie 674fa3ab4c2SVille Syrjälä if (name) { 675fa3ab4c2SVille Syrjälä va_list ap; 676fa3ab4c2SVille Syrjälä 677fa3ab4c2SVille Syrjälä va_start(ap, name); 678fa3ab4c2SVille Syrjälä crtc->name = kvasprintf(GFP_KERNEL, name, ap); 679fa3ab4c2SVille Syrjälä va_end(ap); 680fa3ab4c2SVille Syrjälä } else { 681fa3ab4c2SVille Syrjälä crtc->name = kasprintf(GFP_KERNEL, "crtc-%d", 682fa3ab4c2SVille Syrjälä drm_num_crtcs(dev)); 683fa3ab4c2SVille Syrjälä } 684fa3ab4c2SVille Syrjälä if (!crtc->name) { 6857c8f6d25SDave Airlie drm_mode_object_unregister(dev, &crtc->base); 686fa3ab4c2SVille Syrjälä return -ENOMEM; 687fa3ab4c2SVille Syrjälä } 688fa3ab4c2SVille Syrjälä 689bffd9de0SPaulo Zanoni crtc->base.properties = &crtc->properties; 690bffd9de0SPaulo Zanoni 69151fd371bSRob Clark list_add_tail(&crtc->head, &config->crtc_list); 692490d3d1bSChris Wilson crtc->index = config->num_crtc++; 6936bfc56aaSVille Syrjälä 694e13161afSMatt Roper crtc->primary = primary; 695fc1d3e44SMatt Roper crtc->cursor = cursor; 696e13161afSMatt Roper if (primary) 697e13161afSMatt Roper primary->possible_crtcs = 1 << drm_crtc_index(crtc); 698fc1d3e44SMatt Roper if (cursor) 699fc1d3e44SMatt Roper cursor->possible_crtcs = 1 << drm_crtc_index(crtc); 700e13161afSMatt Roper 701eab3bbefSDaniel Vetter if (drm_core_check_feature(dev, DRIVER_ATOMIC)) { 702eab3bbefSDaniel Vetter drm_object_attach_property(&crtc->base, config->prop_active, 0); 703955f3c33SDaniel Stone drm_object_attach_property(&crtc->base, config->prop_mode_id, 0); 704eab3bbefSDaniel Vetter } 705eab3bbefSDaniel Vetter 706baf698b0SDaniel Vetter return 0; 707f453ba04SDave Airlie } 708e13161afSMatt Roper EXPORT_SYMBOL(drm_crtc_init_with_planes); 709f453ba04SDave Airlie 710f453ba04SDave Airlie /** 711ad6f5c34SVille Syrjälä * drm_crtc_cleanup - Clean up the core crtc usage 712f453ba04SDave Airlie * @crtc: CRTC to cleanup 713f453ba04SDave Airlie * 714ad6f5c34SVille Syrjälä * This function cleans up @crtc and removes it from the DRM mode setting 715ad6f5c34SVille Syrjälä * core. Note that the function does *not* free the crtc structure itself, 716ad6f5c34SVille Syrjälä * this is the responsibility of the caller. 717f453ba04SDave Airlie */ 718f453ba04SDave Airlie void drm_crtc_cleanup(struct drm_crtc *crtc) 719f453ba04SDave Airlie { 720f453ba04SDave Airlie struct drm_device *dev = crtc->dev; 721f453ba04SDave Airlie 722490d3d1bSChris Wilson /* Note that the crtc_list is considered to be static; should we 723490d3d1bSChris Wilson * remove the drm_crtc at runtime we would have to decrement all 724490d3d1bSChris Wilson * the indices on the drm_crtc after us in the crtc_list. 725490d3d1bSChris Wilson */ 726490d3d1bSChris Wilson 727f453ba04SDave Airlie kfree(crtc->gamma_store); 728f453ba04SDave Airlie crtc->gamma_store = NULL; 729f453ba04SDave Airlie 73051fd371bSRob Clark drm_modeset_lock_fini(&crtc->mutex); 73151fd371bSRob Clark 7327c8f6d25SDave Airlie drm_mode_object_unregister(dev, &crtc->base); 733f453ba04SDave Airlie list_del(&crtc->head); 734f453ba04SDave Airlie dev->mode_config.num_crtc--; 7353009c037SThierry Reding 7363009c037SThierry Reding WARN_ON(crtc->state && !crtc->funcs->atomic_destroy_state); 7373009c037SThierry Reding if (crtc->state && crtc->funcs->atomic_destroy_state) 7383009c037SThierry Reding crtc->funcs->atomic_destroy_state(crtc, crtc->state); 739a18c0af1SThierry Reding 740fa3ab4c2SVille Syrjälä kfree(crtc->name); 741fa3ab4c2SVille Syrjälä 742a18c0af1SThierry Reding memset(crtc, 0, sizeof(*crtc)); 743f453ba04SDave Airlie } 744f453ba04SDave Airlie EXPORT_SYMBOL(drm_crtc_cleanup); 745f453ba04SDave Airlie 74686f422d5SLespiau, Damien /* 747f453ba04SDave Airlie * drm_mode_remove - remove and free a mode 748f453ba04SDave Airlie * @connector: connector list to modify 749f453ba04SDave Airlie * @mode: mode to remove 750f453ba04SDave Airlie * 751f453ba04SDave Airlie * Remove @mode from @connector's mode list, then free it. 752f453ba04SDave Airlie */ 75386f422d5SLespiau, Damien static void drm_mode_remove(struct drm_connector *connector, 754f453ba04SDave Airlie struct drm_display_mode *mode) 755f453ba04SDave Airlie { 756f453ba04SDave Airlie list_del(&mode->head); 757554f1d78SSascha Hauer drm_mode_destroy(connector->dev, mode); 758f453ba04SDave Airlie } 759f453ba04SDave Airlie 760f453ba04SDave Airlie /** 761b5571e9dSBoris Brezillon * drm_display_info_set_bus_formats - set the supported bus formats 762b5571e9dSBoris Brezillon * @info: display info to store bus formats in 763e37bfa1aSBoris Brezillon * @formats: array containing the supported bus formats 764e37bfa1aSBoris Brezillon * @num_formats: the number of entries in the fmts array 765b5571e9dSBoris Brezillon * 766b5571e9dSBoris Brezillon * Store the supported bus formats in display info structure. 767b5571e9dSBoris Brezillon * See MEDIA_BUS_FMT_* definitions in include/uapi/linux/media-bus-format.h for 768b5571e9dSBoris Brezillon * a full list of available formats. 769b5571e9dSBoris Brezillon */ 770b5571e9dSBoris Brezillon int drm_display_info_set_bus_formats(struct drm_display_info *info, 771b5571e9dSBoris Brezillon const u32 *formats, 772b5571e9dSBoris Brezillon unsigned int num_formats) 773b5571e9dSBoris Brezillon { 774b5571e9dSBoris Brezillon u32 *fmts = NULL; 775b5571e9dSBoris Brezillon 776b5571e9dSBoris Brezillon if (!formats && num_formats) 777b5571e9dSBoris Brezillon return -EINVAL; 778b5571e9dSBoris Brezillon 779b5571e9dSBoris Brezillon if (formats && num_formats) { 780b5571e9dSBoris Brezillon fmts = kmemdup(formats, sizeof(*formats) * num_formats, 781b5571e9dSBoris Brezillon GFP_KERNEL); 782944579c5SDan Carpenter if (!fmts) 783b5571e9dSBoris Brezillon return -ENOMEM; 784b5571e9dSBoris Brezillon } 785b5571e9dSBoris Brezillon 786b5571e9dSBoris Brezillon kfree(info->bus_formats); 787b5571e9dSBoris Brezillon info->bus_formats = fmts; 788b5571e9dSBoris Brezillon info->num_bus_formats = num_formats; 789b5571e9dSBoris Brezillon 790b5571e9dSBoris Brezillon return 0; 791b5571e9dSBoris Brezillon } 792b5571e9dSBoris Brezillon EXPORT_SYMBOL(drm_display_info_set_bus_formats); 793b5571e9dSBoris Brezillon 794b5571e9dSBoris Brezillon /** 795eaf99c74SChris Wilson * drm_connector_get_cmdline_mode - reads the user's cmdline mode 796eaf99c74SChris Wilson * @connector: connector to quwery 797eaf99c74SChris Wilson * 798eaf99c74SChris Wilson * The kernel supports per-connector configration of its consoles through 799eaf99c74SChris Wilson * use of the video= parameter. This function parses that option and 800eaf99c74SChris Wilson * extracts the user's specified mode (or enable/disable status) for a 801eaf99c74SChris Wilson * particular connector. This is typically only used during the early fbdev 802eaf99c74SChris Wilson * setup. 803eaf99c74SChris Wilson */ 804eaf99c74SChris Wilson static void drm_connector_get_cmdline_mode(struct drm_connector *connector) 805eaf99c74SChris Wilson { 806eaf99c74SChris Wilson struct drm_cmdline_mode *mode = &connector->cmdline_mode; 807eaf99c74SChris Wilson char *option = NULL; 808eaf99c74SChris Wilson 809eaf99c74SChris Wilson if (fb_get_options(connector->name, &option)) 810eaf99c74SChris Wilson return; 811eaf99c74SChris Wilson 812eaf99c74SChris Wilson if (!drm_mode_parse_command_line_for_connector(option, 813eaf99c74SChris Wilson connector, 814eaf99c74SChris Wilson mode)) 815eaf99c74SChris Wilson return; 816eaf99c74SChris Wilson 817eaf99c74SChris Wilson if (mode->force) { 818eaf99c74SChris Wilson const char *s; 819eaf99c74SChris Wilson 820eaf99c74SChris Wilson switch (mode->force) { 821eaf99c74SChris Wilson case DRM_FORCE_OFF: 822eaf99c74SChris Wilson s = "OFF"; 823eaf99c74SChris Wilson break; 824eaf99c74SChris Wilson case DRM_FORCE_ON_DIGITAL: 825eaf99c74SChris Wilson s = "ON - dig"; 826eaf99c74SChris Wilson break; 827eaf99c74SChris Wilson default: 828eaf99c74SChris Wilson case DRM_FORCE_ON: 829eaf99c74SChris Wilson s = "ON"; 830eaf99c74SChris Wilson break; 831eaf99c74SChris Wilson } 832eaf99c74SChris Wilson 833eaf99c74SChris Wilson DRM_INFO("forcing %s connector %s\n", connector->name, s); 834eaf99c74SChris Wilson connector->force = mode->force; 835eaf99c74SChris Wilson } 836eaf99c74SChris Wilson 837eaf99c74SChris Wilson DRM_DEBUG_KMS("cmdline mode for connector %s %dx%d@%dHz%s%s%s\n", 838eaf99c74SChris Wilson connector->name, 839eaf99c74SChris Wilson mode->xres, mode->yres, 840eaf99c74SChris Wilson mode->refresh_specified ? mode->refresh : 60, 841eaf99c74SChris Wilson mode->rb ? " reduced blanking" : "", 842eaf99c74SChris Wilson mode->margins ? " with margins" : "", 843eaf99c74SChris Wilson mode->interlace ? " interlaced" : ""); 844eaf99c74SChris Wilson } 845eaf99c74SChris Wilson 846b164d31fSDave Airlie static void drm_connector_free(struct kref *kref) 847b164d31fSDave Airlie { 848b164d31fSDave Airlie struct drm_connector *connector = 849b164d31fSDave Airlie container_of(kref, struct drm_connector, base.refcount); 850b164d31fSDave Airlie struct drm_device *dev = connector->dev; 851b164d31fSDave Airlie 852b164d31fSDave Airlie drm_mode_object_unregister(dev, &connector->base); 853b164d31fSDave Airlie connector->funcs->destroy(connector); 854b164d31fSDave Airlie } 855b164d31fSDave Airlie 856eaf99c74SChris Wilson /** 857f453ba04SDave Airlie * drm_connector_init - Init a preallocated connector 858f453ba04SDave Airlie * @dev: DRM device 859f453ba04SDave Airlie * @connector: the connector to init 860f453ba04SDave Airlie * @funcs: callbacks for this connector 861065a50edSDaniel Vetter * @connector_type: user visible type of the connector 862f453ba04SDave Airlie * 863f453ba04SDave Airlie * Initialises a preallocated connector. Connectors should be 864f453ba04SDave Airlie * subclassed as part of driver connector objects. 8656bfc56aaSVille Syrjälä * 866c8e32cc1SDaniel Vetter * Returns: 8676bfc56aaSVille Syrjälä * Zero on success, error code on failure. 868f453ba04SDave Airlie */ 8696bfc56aaSVille Syrjälä int drm_connector_init(struct drm_device *dev, 870f453ba04SDave Airlie struct drm_connector *connector, 871f453ba04SDave Airlie const struct drm_connector_funcs *funcs, 872f453ba04SDave Airlie int connector_type) 873f453ba04SDave Airlie { 874ae16c597SRob Clark struct drm_mode_config *config = &dev->mode_config; 8756bfc56aaSVille Syrjälä int ret; 876b21e3afeSIlia Mirkin struct ida *connector_ida = 877b21e3afeSIlia Mirkin &drm_connector_enum_list[connector_type].ida; 8786bfc56aaSVille Syrjälä 87984849903SDaniel Vetter drm_modeset_lock_all(dev); 880f453ba04SDave Airlie 881b164d31fSDave Airlie ret = drm_mode_object_get_reg(dev, &connector->base, 882b164d31fSDave Airlie DRM_MODE_OBJECT_CONNECTOR, 883b164d31fSDave Airlie false, drm_connector_free); 8846bfc56aaSVille Syrjälä if (ret) 8852abdd313SJani Nikula goto out_unlock; 8866bfc56aaSVille Syrjälä 8877e3bdf4aSPaulo Zanoni connector->base.properties = &connector->properties; 888f453ba04SDave Airlie connector->dev = dev; 889f453ba04SDave Airlie connector->funcs = funcs; 8905fff80bbSMaarten Lankhorst 8915fff80bbSMaarten Lankhorst connector->connector_id = ida_simple_get(&config->connector_ida, 0, 0, GFP_KERNEL); 8925fff80bbSMaarten Lankhorst if (connector->connector_id < 0) { 8935fff80bbSMaarten Lankhorst ret = connector->connector_id; 8945fff80bbSMaarten Lankhorst goto out_put; 8955fff80bbSMaarten Lankhorst } 8965fff80bbSMaarten Lankhorst 897f453ba04SDave Airlie connector->connector_type = connector_type; 898f453ba04SDave Airlie connector->connector_type_id = 899b21e3afeSIlia Mirkin ida_simple_get(connector_ida, 1, 0, GFP_KERNEL); 900b21e3afeSIlia Mirkin if (connector->connector_type_id < 0) { 901b21e3afeSIlia Mirkin ret = connector->connector_type_id; 9025fff80bbSMaarten Lankhorst goto out_put_id; 903b21e3afeSIlia Mirkin } 9042abdd313SJani Nikula connector->name = 9052abdd313SJani Nikula kasprintf(GFP_KERNEL, "%s-%d", 9062abdd313SJani Nikula drm_connector_enum_list[connector_type].name, 9072abdd313SJani Nikula connector->connector_type_id); 9082abdd313SJani Nikula if (!connector->name) { 9092abdd313SJani Nikula ret = -ENOMEM; 9105fff80bbSMaarten Lankhorst goto out_put_type_id; 9112abdd313SJani Nikula } 9122abdd313SJani Nikula 913f453ba04SDave Airlie INIT_LIST_HEAD(&connector->probed_modes); 914f453ba04SDave Airlie INIT_LIST_HEAD(&connector->modes); 915f453ba04SDave Airlie connector->edid_blob_ptr = NULL; 9165e2cb2f6SDaniel Vetter connector->status = connector_status_unknown; 917f453ba04SDave Airlie 918eaf99c74SChris Wilson drm_connector_get_cmdline_mode(connector); 919eaf99c74SChris Wilson 920c7eb76f4SDaniel Vetter /* We should add connectors at the end to avoid upsetting the connector 921c7eb76f4SDaniel Vetter * index too much. */ 922ae16c597SRob Clark list_add_tail(&connector->head, &config->connector_list); 923ae16c597SRob Clark config->num_connector++; 924f453ba04SDave Airlie 925a7331e5cSThomas Hellstrom if (connector_type != DRM_MODE_CONNECTOR_VIRTUAL) 92658495563SRob Clark drm_object_attach_property(&connector->base, 927ae16c597SRob Clark config->edid_property, 928a7331e5cSThomas Hellstrom 0); 929f453ba04SDave Airlie 93058495563SRob Clark drm_object_attach_property(&connector->base, 931ae16c597SRob Clark config->dpms_property, 0); 932ae16c597SRob Clark 933ae16c597SRob Clark if (drm_core_check_feature(dev, DRIVER_ATOMIC)) { 934ae16c597SRob Clark drm_object_attach_property(&connector->base, config->prop_crtc_id, 0); 935ae16c597SRob Clark } 936f453ba04SDave Airlie 93730f65707SThomas Wood connector->debugfs_entry = NULL; 9385fff80bbSMaarten Lankhorst out_put_type_id: 9395fff80bbSMaarten Lankhorst if (ret) 9405fff80bbSMaarten Lankhorst ida_remove(connector_ida, connector->connector_type_id); 9415fff80bbSMaarten Lankhorst out_put_id: 9425fff80bbSMaarten Lankhorst if (ret) 9435fff80bbSMaarten Lankhorst ida_remove(&config->connector_ida, connector->connector_id); 9442abdd313SJani Nikula out_put: 9452abdd313SJani Nikula if (ret) 9467c8f6d25SDave Airlie drm_mode_object_unregister(dev, &connector->base); 9472abdd313SJani Nikula 9482abdd313SJani Nikula out_unlock: 94984849903SDaniel Vetter drm_modeset_unlock_all(dev); 9506bfc56aaSVille Syrjälä 9516bfc56aaSVille Syrjälä return ret; 952f453ba04SDave Airlie } 953f453ba04SDave Airlie EXPORT_SYMBOL(drm_connector_init); 954f453ba04SDave Airlie 955f453ba04SDave Airlie /** 956f453ba04SDave Airlie * drm_connector_cleanup - cleans up an initialised connector 957f453ba04SDave Airlie * @connector: connector to cleanup 958f453ba04SDave Airlie * 959f453ba04SDave Airlie * Cleans up the connector but doesn't free the object. 960f453ba04SDave Airlie */ 961f453ba04SDave Airlie void drm_connector_cleanup(struct drm_connector *connector) 962f453ba04SDave Airlie { 963f453ba04SDave Airlie struct drm_device *dev = connector->dev; 964f453ba04SDave Airlie struct drm_display_mode *mode, *t; 965f453ba04SDave Airlie 96680de3461SChris Wilson /* The connector should have been removed from userspace long before 96780de3461SChris Wilson * it is finally destroyed. 96880de3461SChris Wilson */ 96980de3461SChris Wilson if (WARN_ON(connector->registered)) 97080de3461SChris Wilson drm_connector_unregister(connector); 97180de3461SChris Wilson 97240d9b043SDave Airlie if (connector->tile_group) { 97340d9b043SDave Airlie drm_mode_put_tile_group(dev, connector->tile_group); 97440d9b043SDave Airlie connector->tile_group = NULL; 97540d9b043SDave Airlie } 97640d9b043SDave Airlie 977f453ba04SDave Airlie list_for_each_entry_safe(mode, t, &connector->probed_modes, head) 978f453ba04SDave Airlie drm_mode_remove(connector, mode); 979f453ba04SDave Airlie 980f453ba04SDave Airlie list_for_each_entry_safe(mode, t, &connector->modes, head) 981f453ba04SDave Airlie drm_mode_remove(connector, mode); 982f453ba04SDave Airlie 983b21e3afeSIlia Mirkin ida_remove(&drm_connector_enum_list[connector->connector_type].ida, 984b21e3afeSIlia Mirkin connector->connector_type_id); 985b21e3afeSIlia Mirkin 9865fff80bbSMaarten Lankhorst ida_remove(&dev->mode_config.connector_ida, 9875fff80bbSMaarten Lankhorst connector->connector_id); 9885fff80bbSMaarten Lankhorst 989b5571e9dSBoris Brezillon kfree(connector->display_info.bus_formats); 9907c8f6d25SDave Airlie drm_mode_object_unregister(dev, &connector->base); 9912abdd313SJani Nikula kfree(connector->name); 9922abdd313SJani Nikula connector->name = NULL; 993f453ba04SDave Airlie list_del(&connector->head); 9946380c509SJoonyoung Shim dev->mode_config.num_connector--; 9953009c037SThierry Reding 9963009c037SThierry Reding WARN_ON(connector->state && !connector->funcs->atomic_destroy_state); 9973009c037SThierry Reding if (connector->state && connector->funcs->atomic_destroy_state) 9983009c037SThierry Reding connector->funcs->atomic_destroy_state(connector, 9993009c037SThierry Reding connector->state); 1000a18c0af1SThierry Reding 1001a18c0af1SThierry Reding memset(connector, 0, sizeof(*connector)); 1002f453ba04SDave Airlie } 1003f453ba04SDave Airlie EXPORT_SYMBOL(drm_connector_cleanup); 1004f453ba04SDave Airlie 1005c8e32cc1SDaniel Vetter /** 100634ea3d38SThomas Wood * drm_connector_register - register a connector 100734ea3d38SThomas Wood * @connector: the connector to register 100834ea3d38SThomas Wood * 100934ea3d38SThomas Wood * Register userspace interfaces for a connector 101034ea3d38SThomas Wood * 101134ea3d38SThomas Wood * Returns: 101234ea3d38SThomas Wood * Zero on success, error code on failure. 101334ea3d38SThomas Wood */ 101434ea3d38SThomas Wood int drm_connector_register(struct drm_connector *connector) 101534ea3d38SThomas Wood { 101630f65707SThomas Wood int ret; 101730f65707SThomas Wood 101840daac61SChris Wilson if (connector->registered) 101940daac61SChris Wilson return 0; 102040daac61SChris Wilson 102130f65707SThomas Wood ret = drm_sysfs_connector_add(connector); 102230f65707SThomas Wood if (ret) 102330f65707SThomas Wood return ret; 102430f65707SThomas Wood 102530f65707SThomas Wood ret = drm_debugfs_connector_add(connector); 102630f65707SThomas Wood if (ret) { 1027aaf285e2SChris Wilson goto err_sysfs; 1028aaf285e2SChris Wilson } 1029aaf285e2SChris Wilson 1030aaf285e2SChris Wilson if (connector->funcs->late_register) { 1031aaf285e2SChris Wilson ret = connector->funcs->late_register(connector); 1032aaf285e2SChris Wilson if (ret) 1033aaf285e2SChris Wilson goto err_debugfs; 103430f65707SThomas Wood } 103530f65707SThomas Wood 1036fdf2c85fSDaniel Vetter drm_mode_object_register(connector->dev, &connector->base); 1037fdf2c85fSDaniel Vetter 103840daac61SChris Wilson connector->registered = true; 103930f65707SThomas Wood return 0; 1040aaf285e2SChris Wilson 1041aaf285e2SChris Wilson err_debugfs: 1042aaf285e2SChris Wilson drm_debugfs_connector_remove(connector); 1043aaf285e2SChris Wilson err_sysfs: 1044aaf285e2SChris Wilson drm_sysfs_connector_remove(connector); 1045aaf285e2SChris Wilson return ret; 104634ea3d38SThomas Wood } 104734ea3d38SThomas Wood EXPORT_SYMBOL(drm_connector_register); 104834ea3d38SThomas Wood 104934ea3d38SThomas Wood /** 105034ea3d38SThomas Wood * drm_connector_unregister - unregister a connector 105134ea3d38SThomas Wood * @connector: the connector to unregister 105234ea3d38SThomas Wood * 105334ea3d38SThomas Wood * Unregister userspace interfaces for a connector 105434ea3d38SThomas Wood */ 105534ea3d38SThomas Wood void drm_connector_unregister(struct drm_connector *connector) 105634ea3d38SThomas Wood { 105740daac61SChris Wilson if (!connector->registered) 105840daac61SChris Wilson return; 105940daac61SChris Wilson 1060aaf285e2SChris Wilson if (connector->funcs->early_unregister) 1061aaf285e2SChris Wilson connector->funcs->early_unregister(connector); 1062aaf285e2SChris Wilson 106334ea3d38SThomas Wood drm_sysfs_connector_remove(connector); 106430f65707SThomas Wood drm_debugfs_connector_remove(connector); 106540daac61SChris Wilson 106640daac61SChris Wilson connector->registered = false; 106734ea3d38SThomas Wood } 106834ea3d38SThomas Wood EXPORT_SYMBOL(drm_connector_unregister); 106934ea3d38SThomas Wood 107034ea3d38SThomas Wood /** 107154d2c2daSAlexey Brodkin * drm_connector_register_all - register all connectors 107254d2c2daSAlexey Brodkin * @dev: drm device 107354d2c2daSAlexey Brodkin * 107454d2c2daSAlexey Brodkin * This function registers all connectors in sysfs and other places so that 1075e28cd4d0SChris Wilson * userspace can start to access them. drm_connector_register_all() is called 1076e28cd4d0SChris Wilson * automatically from drm_dev_register() to complete the device registration, 1077e28cd4d0SChris Wilson * if they don't call drm_connector_register() on each connector individually. 107854d2c2daSAlexey Brodkin * 107954d2c2daSAlexey Brodkin * When a device is unplugged and should be removed from userspace access, 108054d2c2daSAlexey Brodkin * call drm_connector_unregister_all(), which is the inverse of this 108154d2c2daSAlexey Brodkin * function. 108254d2c2daSAlexey Brodkin * 108354d2c2daSAlexey Brodkin * Returns: 108454d2c2daSAlexey Brodkin * Zero on success, error code on failure. 108554d2c2daSAlexey Brodkin */ 108654d2c2daSAlexey Brodkin int drm_connector_register_all(struct drm_device *dev) 108754d2c2daSAlexey Brodkin { 108854d2c2daSAlexey Brodkin struct drm_connector *connector; 108954d2c2daSAlexey Brodkin int ret; 109054d2c2daSAlexey Brodkin 109154d2c2daSAlexey Brodkin mutex_lock(&dev->mode_config.mutex); 109254d2c2daSAlexey Brodkin 109354d2c2daSAlexey Brodkin drm_for_each_connector(connector, dev) { 109454d2c2daSAlexey Brodkin ret = drm_connector_register(connector); 109554d2c2daSAlexey Brodkin if (ret) 109654d2c2daSAlexey Brodkin goto err; 109754d2c2daSAlexey Brodkin } 109854d2c2daSAlexey Brodkin 109954d2c2daSAlexey Brodkin mutex_unlock(&dev->mode_config.mutex); 110054d2c2daSAlexey Brodkin 110154d2c2daSAlexey Brodkin return 0; 110254d2c2daSAlexey Brodkin 110354d2c2daSAlexey Brodkin err: 110454d2c2daSAlexey Brodkin mutex_unlock(&dev->mode_config.mutex); 110554d2c2daSAlexey Brodkin drm_connector_unregister_all(dev); 110654d2c2daSAlexey Brodkin return ret; 110754d2c2daSAlexey Brodkin } 110854d2c2daSAlexey Brodkin EXPORT_SYMBOL(drm_connector_register_all); 110954d2c2daSAlexey Brodkin 111054d2c2daSAlexey Brodkin /** 11116c87e5c3SAlexey Brodkin * drm_connector_unregister_all - unregister connector userspace interfaces 1112c8e32cc1SDaniel Vetter * @dev: drm device 1113c8e32cc1SDaniel Vetter * 11146c87e5c3SAlexey Brodkin * This functions unregisters all connectors from sysfs and other places so 11156c87e5c3SAlexey Brodkin * that userspace can no longer access them. Drivers should call this as the 11166c87e5c3SAlexey Brodkin * first step tearing down the device instace, or when the underlying 11176c87e5c3SAlexey Brodkin * physical device disappeared (e.g. USB unplug), right before calling 11186c87e5c3SAlexey Brodkin * drm_dev_unregister(). 1119c8e32cc1SDaniel Vetter */ 11206c87e5c3SAlexey Brodkin void drm_connector_unregister_all(struct drm_device *dev) 1121cbc7e221SDave Airlie { 1122cbc7e221SDave Airlie struct drm_connector *connector; 1123cbc7e221SDave Airlie 11249a9f5ce8SDaniel Vetter /* FIXME: taking the mode config mutex ends up in a clash with sysfs */ 112514ba0031SLaurent Pinchart list_for_each_entry(connector, &dev->mode_config.connector_list, head) 112634ea3d38SThomas Wood drm_connector_unregister(connector); 1127cbc7e221SDave Airlie } 11286c87e5c3SAlexey Brodkin EXPORT_SYMBOL(drm_connector_unregister_all); 1129cbc7e221SDave Airlie 113079190ea2SBenjamin Gaignard static int drm_encoder_register_all(struct drm_device *dev) 113179190ea2SBenjamin Gaignard { 113279190ea2SBenjamin Gaignard struct drm_encoder *encoder; 113379190ea2SBenjamin Gaignard int ret = 0; 113479190ea2SBenjamin Gaignard 113579190ea2SBenjamin Gaignard drm_for_each_encoder(encoder, dev) { 113679190ea2SBenjamin Gaignard if (encoder->funcs->late_register) 113779190ea2SBenjamin Gaignard ret = encoder->funcs->late_register(encoder); 113879190ea2SBenjamin Gaignard if (ret) 113979190ea2SBenjamin Gaignard return ret; 114079190ea2SBenjamin Gaignard } 114179190ea2SBenjamin Gaignard 114279190ea2SBenjamin Gaignard return 0; 114379190ea2SBenjamin Gaignard } 114479190ea2SBenjamin Gaignard 114579190ea2SBenjamin Gaignard static void drm_encoder_unregister_all(struct drm_device *dev) 114679190ea2SBenjamin Gaignard { 114779190ea2SBenjamin Gaignard struct drm_encoder *encoder; 114879190ea2SBenjamin Gaignard 114979190ea2SBenjamin Gaignard drm_for_each_encoder(encoder, dev) { 115079190ea2SBenjamin Gaignard if (encoder->funcs->early_unregister) 115179190ea2SBenjamin Gaignard encoder->funcs->early_unregister(encoder); 115279190ea2SBenjamin Gaignard } 115379190ea2SBenjamin Gaignard } 115479190ea2SBenjamin Gaignard 1155c8e32cc1SDaniel Vetter /** 1156c8e32cc1SDaniel Vetter * drm_encoder_init - Init a preallocated encoder 1157c8e32cc1SDaniel Vetter * @dev: drm device 1158c8e32cc1SDaniel Vetter * @encoder: the encoder to init 1159c8e32cc1SDaniel Vetter * @funcs: callbacks for this encoder 1160c8e32cc1SDaniel Vetter * @encoder_type: user visible type of the encoder 116113a3d91fSVille Syrjälä * @name: printf style format string for the encoder name, or NULL for default name 1162c8e32cc1SDaniel Vetter * 1163c8e32cc1SDaniel Vetter * Initialises a preallocated encoder. Encoder should be 1164c8e32cc1SDaniel Vetter * subclassed as part of driver encoder objects. 1165c8e32cc1SDaniel Vetter * 1166c8e32cc1SDaniel Vetter * Returns: 1167c8e32cc1SDaniel Vetter * Zero on success, error code on failure. 1168c8e32cc1SDaniel Vetter */ 11696bfc56aaSVille Syrjälä int drm_encoder_init(struct drm_device *dev, 1170f453ba04SDave Airlie struct drm_encoder *encoder, 1171f453ba04SDave Airlie const struct drm_encoder_funcs *funcs, 117213a3d91fSVille Syrjälä int encoder_type, const char *name, ...) 1173f453ba04SDave Airlie { 11746bfc56aaSVille Syrjälä int ret; 11756bfc56aaSVille Syrjälä 117684849903SDaniel Vetter drm_modeset_lock_all(dev); 1177f453ba04SDave Airlie 11786bfc56aaSVille Syrjälä ret = drm_mode_object_get(dev, &encoder->base, DRM_MODE_OBJECT_ENCODER); 11796bfc56aaSVille Syrjälä if (ret) 1180e5748946SJani Nikula goto out_unlock; 1181f453ba04SDave Airlie 11826bfc56aaSVille Syrjälä encoder->dev = dev; 1183f453ba04SDave Airlie encoder->encoder_type = encoder_type; 1184f453ba04SDave Airlie encoder->funcs = funcs; 118586bf546bSVille Syrjälä if (name) { 118686bf546bSVille Syrjälä va_list ap; 118786bf546bSVille Syrjälä 118886bf546bSVille Syrjälä va_start(ap, name); 118986bf546bSVille Syrjälä encoder->name = kvasprintf(GFP_KERNEL, name, ap); 119086bf546bSVille Syrjälä va_end(ap); 119186bf546bSVille Syrjälä } else { 1192e5748946SJani Nikula encoder->name = kasprintf(GFP_KERNEL, "%s-%d", 1193e5748946SJani Nikula drm_encoder_enum_list[encoder_type].name, 1194e5748946SJani Nikula encoder->base.id); 119586bf546bSVille Syrjälä } 1196e5748946SJani Nikula if (!encoder->name) { 1197e5748946SJani Nikula ret = -ENOMEM; 1198e5748946SJani Nikula goto out_put; 1199e5748946SJani Nikula } 1200f453ba04SDave Airlie 1201f453ba04SDave Airlie list_add_tail(&encoder->head, &dev->mode_config.encoder_list); 1202490d3d1bSChris Wilson encoder->index = dev->mode_config.num_encoder++; 1203f453ba04SDave Airlie 1204e5748946SJani Nikula out_put: 1205e5748946SJani Nikula if (ret) 12067c8f6d25SDave Airlie drm_mode_object_unregister(dev, &encoder->base); 1207e5748946SJani Nikula 1208e5748946SJani Nikula out_unlock: 120984849903SDaniel Vetter drm_modeset_unlock_all(dev); 12106bfc56aaSVille Syrjälä 12116bfc56aaSVille Syrjälä return ret; 1212f453ba04SDave Airlie } 1213f453ba04SDave Airlie EXPORT_SYMBOL(drm_encoder_init); 1214f453ba04SDave Airlie 1215c8e32cc1SDaniel Vetter /** 1216c8e32cc1SDaniel Vetter * drm_encoder_cleanup - cleans up an initialised encoder 1217c8e32cc1SDaniel Vetter * @encoder: encoder to cleanup 1218c8e32cc1SDaniel Vetter * 1219c8e32cc1SDaniel Vetter * Cleans up the encoder but doesn't free the object. 1220c8e32cc1SDaniel Vetter */ 1221f453ba04SDave Airlie void drm_encoder_cleanup(struct drm_encoder *encoder) 1222f453ba04SDave Airlie { 1223f453ba04SDave Airlie struct drm_device *dev = encoder->dev; 12244dfd909fSThierry Reding 1225490d3d1bSChris Wilson /* Note that the encoder_list is considered to be static; should we 1226490d3d1bSChris Wilson * remove the drm_encoder at runtime we would have to decrement all 1227490d3d1bSChris Wilson * the indices on the drm_encoder after us in the encoder_list. 1228490d3d1bSChris Wilson */ 1229490d3d1bSChris Wilson 123084849903SDaniel Vetter drm_modeset_lock_all(dev); 12317c8f6d25SDave Airlie drm_mode_object_unregister(dev, &encoder->base); 1232e5748946SJani Nikula kfree(encoder->name); 1233f453ba04SDave Airlie list_del(&encoder->head); 12346380c509SJoonyoung Shim dev->mode_config.num_encoder--; 123584849903SDaniel Vetter drm_modeset_unlock_all(dev); 1236a18c0af1SThierry Reding 1237a18c0af1SThierry Reding memset(encoder, 0, sizeof(*encoder)); 1238f453ba04SDave Airlie } 1239f453ba04SDave Airlie EXPORT_SYMBOL(drm_encoder_cleanup); 1240f453ba04SDave Airlie 12419f4c97a2SVille Syrjälä static unsigned int drm_num_planes(struct drm_device *dev) 12429f4c97a2SVille Syrjälä { 12439f4c97a2SVille Syrjälä unsigned int num = 0; 12449f4c97a2SVille Syrjälä struct drm_plane *tmp; 12459f4c97a2SVille Syrjälä 12469f4c97a2SVille Syrjälä drm_for_each_plane(tmp, dev) { 12479f4c97a2SVille Syrjälä num++; 12489f4c97a2SVille Syrjälä } 12499f4c97a2SVille Syrjälä 12509f4c97a2SVille Syrjälä return num; 12519f4c97a2SVille Syrjälä } 12529f4c97a2SVille Syrjälä 125335f2c3aeSVille Syrjälä /** 1254dc415ff9SMatt Roper * drm_universal_plane_init - Initialize a new universal plane object 125535f2c3aeSVille Syrjälä * @dev: DRM device 125635f2c3aeSVille Syrjälä * @plane: plane object to init 125735f2c3aeSVille Syrjälä * @possible_crtcs: bitmask of possible CRTCs 125835f2c3aeSVille Syrjälä * @funcs: callbacks for the new plane 125935f2c3aeSVille Syrjälä * @formats: array of supported formats (%DRM_FORMAT_*) 126035f2c3aeSVille Syrjälä * @format_count: number of elements in @formats 1261dc415ff9SMatt Roper * @type: type of plane (overlay, primary, cursor) 1262b0b3b795SVille Syrjälä * @name: printf style format string for the plane name, or NULL for default name 126335f2c3aeSVille Syrjälä * 1264dc415ff9SMatt Roper * Initializes a plane object of type @type. 126535f2c3aeSVille Syrjälä * 1266c8e32cc1SDaniel Vetter * Returns: 126735f2c3aeSVille Syrjälä * Zero on success, error code on failure. 126835f2c3aeSVille Syrjälä */ 1269dc415ff9SMatt Roper int drm_universal_plane_init(struct drm_device *dev, struct drm_plane *plane, 12708cf5c917SJesse Barnes unsigned long possible_crtcs, 12718cf5c917SJesse Barnes const struct drm_plane_funcs *funcs, 127245e3743aSThierry Reding const uint32_t *formats, unsigned int format_count, 1273b0b3b795SVille Syrjälä enum drm_plane_type type, 1274b0b3b795SVille Syrjälä const char *name, ...) 12758cf5c917SJesse Barnes { 12766b4959f4SRob Clark struct drm_mode_config *config = &dev->mode_config; 12776bfc56aaSVille Syrjälä int ret; 12786bfc56aaSVille Syrjälä 12796bfc56aaSVille Syrjälä ret = drm_mode_object_get(dev, &plane->base, DRM_MODE_OBJECT_PLANE); 12806bfc56aaSVille Syrjälä if (ret) 1281baf698b0SDaniel Vetter return ret; 12826bfc56aaSVille Syrjälä 12834d02e2deSDaniel Vetter drm_modeset_lock_init(&plane->mutex); 12844d02e2deSDaniel Vetter 12854d93914aSRob Clark plane->base.properties = &plane->properties; 12868cf5c917SJesse Barnes plane->dev = dev; 12878cf5c917SJesse Barnes plane->funcs = funcs; 12882f6c5389SThierry Reding plane->format_types = kmalloc_array(format_count, sizeof(uint32_t), 12898cf5c917SJesse Barnes GFP_KERNEL); 12908cf5c917SJesse Barnes if (!plane->format_types) { 12918cf5c917SJesse Barnes DRM_DEBUG_KMS("out of memory when allocating plane\n"); 12927c8f6d25SDave Airlie drm_mode_object_unregister(dev, &plane->base); 1293baf698b0SDaniel Vetter return -ENOMEM; 12948cf5c917SJesse Barnes } 12958cf5c917SJesse Barnes 12969f4c97a2SVille Syrjälä if (name) { 12979f4c97a2SVille Syrjälä va_list ap; 12989f4c97a2SVille Syrjälä 12999f4c97a2SVille Syrjälä va_start(ap, name); 13009f4c97a2SVille Syrjälä plane->name = kvasprintf(GFP_KERNEL, name, ap); 13019f4c97a2SVille Syrjälä va_end(ap); 13029f4c97a2SVille Syrjälä } else { 13039f4c97a2SVille Syrjälä plane->name = kasprintf(GFP_KERNEL, "plane-%d", 13049f4c97a2SVille Syrjälä drm_num_planes(dev)); 13059f4c97a2SVille Syrjälä } 13069f4c97a2SVille Syrjälä if (!plane->name) { 13079f4c97a2SVille Syrjälä kfree(plane->format_types); 13087c8f6d25SDave Airlie drm_mode_object_unregister(dev, &plane->base); 13099f4c97a2SVille Syrjälä return -ENOMEM; 13109f4c97a2SVille Syrjälä } 13119f4c97a2SVille Syrjälä 1312308e5bcbSJesse Barnes memcpy(plane->format_types, formats, format_count * sizeof(uint32_t)); 13138cf5c917SJesse Barnes plane->format_count = format_count; 13148cf5c917SJesse Barnes plane->possible_crtcs = possible_crtcs; 1315dc415ff9SMatt Roper plane->type = type; 13168cf5c917SJesse Barnes 13176b4959f4SRob Clark list_add_tail(&plane->head, &config->plane_list); 1318490d3d1bSChris Wilson plane->index = config->num_total_plane++; 1319e27dde3eSMatt Roper if (plane->type == DRM_PLANE_TYPE_OVERLAY) 13206b4959f4SRob Clark config->num_overlay_plane++; 13218cf5c917SJesse Barnes 13229922ab5aSRob Clark drm_object_attach_property(&plane->base, 13236b4959f4SRob Clark config->plane_type_property, 13249922ab5aSRob Clark plane->type); 13259922ab5aSRob Clark 13266b4959f4SRob Clark if (drm_core_check_feature(dev, DRIVER_ATOMIC)) { 13276b4959f4SRob Clark drm_object_attach_property(&plane->base, config->prop_fb_id, 0); 13286b4959f4SRob Clark drm_object_attach_property(&plane->base, config->prop_crtc_id, 0); 13296b4959f4SRob Clark drm_object_attach_property(&plane->base, config->prop_crtc_x, 0); 13306b4959f4SRob Clark drm_object_attach_property(&plane->base, config->prop_crtc_y, 0); 13316b4959f4SRob Clark drm_object_attach_property(&plane->base, config->prop_crtc_w, 0); 13326b4959f4SRob Clark drm_object_attach_property(&plane->base, config->prop_crtc_h, 0); 13336b4959f4SRob Clark drm_object_attach_property(&plane->base, config->prop_src_x, 0); 13346b4959f4SRob Clark drm_object_attach_property(&plane->base, config->prop_src_y, 0); 13356b4959f4SRob Clark drm_object_attach_property(&plane->base, config->prop_src_w, 0); 13366b4959f4SRob Clark drm_object_attach_property(&plane->base, config->prop_src_h, 0); 13376b4959f4SRob Clark } 13386b4959f4SRob Clark 1339baf698b0SDaniel Vetter return 0; 13408cf5c917SJesse Barnes } 1341dc415ff9SMatt Roper EXPORT_SYMBOL(drm_universal_plane_init); 1342dc415ff9SMatt Roper 134379190ea2SBenjamin Gaignard static int drm_plane_register_all(struct drm_device *dev) 134479190ea2SBenjamin Gaignard { 134579190ea2SBenjamin Gaignard struct drm_plane *plane; 134679190ea2SBenjamin Gaignard int ret = 0; 134779190ea2SBenjamin Gaignard 134879190ea2SBenjamin Gaignard drm_for_each_plane(plane, dev) { 134979190ea2SBenjamin Gaignard if (plane->funcs->late_register) 135079190ea2SBenjamin Gaignard ret = plane->funcs->late_register(plane); 135179190ea2SBenjamin Gaignard if (ret) 135279190ea2SBenjamin Gaignard return ret; 135379190ea2SBenjamin Gaignard } 135479190ea2SBenjamin Gaignard 135579190ea2SBenjamin Gaignard return 0; 135679190ea2SBenjamin Gaignard } 135779190ea2SBenjamin Gaignard 135879190ea2SBenjamin Gaignard static void drm_plane_unregister_all(struct drm_device *dev) 135979190ea2SBenjamin Gaignard { 136079190ea2SBenjamin Gaignard struct drm_plane *plane; 136179190ea2SBenjamin Gaignard 136279190ea2SBenjamin Gaignard drm_for_each_plane(plane, dev) { 136379190ea2SBenjamin Gaignard if (plane->funcs->early_unregister) 136479190ea2SBenjamin Gaignard plane->funcs->early_unregister(plane); 136579190ea2SBenjamin Gaignard } 136679190ea2SBenjamin Gaignard } 136779190ea2SBenjamin Gaignard 1368dc415ff9SMatt Roper /** 1369dc415ff9SMatt Roper * drm_plane_init - Initialize a legacy plane 1370dc415ff9SMatt Roper * @dev: DRM device 1371dc415ff9SMatt Roper * @plane: plane object to init 1372dc415ff9SMatt Roper * @possible_crtcs: bitmask of possible CRTCs 1373dc415ff9SMatt Roper * @funcs: callbacks for the new plane 1374dc415ff9SMatt Roper * @formats: array of supported formats (%DRM_FORMAT_*) 1375dc415ff9SMatt Roper * @format_count: number of elements in @formats 1376dc415ff9SMatt Roper * @is_primary: plane type (primary vs overlay) 1377dc415ff9SMatt Roper * 1378dc415ff9SMatt Roper * Legacy API to initialize a DRM plane. 1379dc415ff9SMatt Roper * 1380dc415ff9SMatt Roper * New drivers should call drm_universal_plane_init() instead. 1381dc415ff9SMatt Roper * 1382dc415ff9SMatt Roper * Returns: 1383dc415ff9SMatt Roper * Zero on success, error code on failure. 1384dc415ff9SMatt Roper */ 1385dc415ff9SMatt Roper int drm_plane_init(struct drm_device *dev, struct drm_plane *plane, 1386dc415ff9SMatt Roper unsigned long possible_crtcs, 1387dc415ff9SMatt Roper const struct drm_plane_funcs *funcs, 138845e3743aSThierry Reding const uint32_t *formats, unsigned int format_count, 1389dc415ff9SMatt Roper bool is_primary) 1390dc415ff9SMatt Roper { 1391dc415ff9SMatt Roper enum drm_plane_type type; 1392dc415ff9SMatt Roper 1393dc415ff9SMatt Roper type = is_primary ? DRM_PLANE_TYPE_PRIMARY : DRM_PLANE_TYPE_OVERLAY; 1394dc415ff9SMatt Roper return drm_universal_plane_init(dev, plane, possible_crtcs, funcs, 1395b0b3b795SVille Syrjälä formats, format_count, type, NULL); 1396dc415ff9SMatt Roper } 13978cf5c917SJesse Barnes EXPORT_SYMBOL(drm_plane_init); 13988cf5c917SJesse Barnes 139935f2c3aeSVille Syrjälä /** 140035f2c3aeSVille Syrjälä * drm_plane_cleanup - Clean up the core plane usage 140135f2c3aeSVille Syrjälä * @plane: plane to cleanup 140235f2c3aeSVille Syrjälä * 140335f2c3aeSVille Syrjälä * This function cleans up @plane and removes it from the DRM mode setting 140435f2c3aeSVille Syrjälä * core. Note that the function does *not* free the plane structure itself, 140535f2c3aeSVille Syrjälä * this is the responsibility of the caller. 140635f2c3aeSVille Syrjälä */ 14078cf5c917SJesse Barnes void drm_plane_cleanup(struct drm_plane *plane) 14088cf5c917SJesse Barnes { 14098cf5c917SJesse Barnes struct drm_device *dev = plane->dev; 14108cf5c917SJesse Barnes 141184849903SDaniel Vetter drm_modeset_lock_all(dev); 14128cf5c917SJesse Barnes kfree(plane->format_types); 14137c8f6d25SDave Airlie drm_mode_object_unregister(dev, &plane->base); 1414dc415ff9SMatt Roper 1415dc415ff9SMatt Roper BUG_ON(list_empty(&plane->head)); 1416dc415ff9SMatt Roper 1417490d3d1bSChris Wilson /* Note that the plane_list is considered to be static; should we 1418490d3d1bSChris Wilson * remove the drm_plane at runtime we would have to decrement all 1419490d3d1bSChris Wilson * the indices on the drm_plane after us in the plane_list. 1420490d3d1bSChris Wilson */ 1421490d3d1bSChris Wilson 14228cf5c917SJesse Barnes list_del(&plane->head); 1423e27dde3eSMatt Roper dev->mode_config.num_total_plane--; 1424e27dde3eSMatt Roper if (plane->type == DRM_PLANE_TYPE_OVERLAY) 1425e27dde3eSMatt Roper dev->mode_config.num_overlay_plane--; 142684849903SDaniel Vetter drm_modeset_unlock_all(dev); 14273009c037SThierry Reding 14283009c037SThierry Reding WARN_ON(plane->state && !plane->funcs->atomic_destroy_state); 14293009c037SThierry Reding if (plane->state && plane->funcs->atomic_destroy_state) 14303009c037SThierry Reding plane->funcs->atomic_destroy_state(plane, plane->state); 1431a18c0af1SThierry Reding 14329f4c97a2SVille Syrjälä kfree(plane->name); 14339f4c97a2SVille Syrjälä 1434a18c0af1SThierry Reding memset(plane, 0, sizeof(*plane)); 14358cf5c917SJesse Barnes } 14368cf5c917SJesse Barnes EXPORT_SYMBOL(drm_plane_cleanup); 14378cf5c917SJesse Barnes 143835f2c3aeSVille Syrjälä /** 1439f81338a5SChandra Konduru * drm_plane_from_index - find the registered plane at an index 1440f81338a5SChandra Konduru * @dev: DRM device 1441f81338a5SChandra Konduru * @idx: index of registered plane to find for 1442f81338a5SChandra Konduru * 1443f81338a5SChandra Konduru * Given a plane index, return the registered plane from DRM device's 1444f81338a5SChandra Konduru * list of planes with matching index. 1445f81338a5SChandra Konduru */ 1446f81338a5SChandra Konduru struct drm_plane * 1447f81338a5SChandra Konduru drm_plane_from_index(struct drm_device *dev, int idx) 1448f81338a5SChandra Konduru { 1449f81338a5SChandra Konduru struct drm_plane *plane; 1450f81338a5SChandra Konduru 1451490d3d1bSChris Wilson drm_for_each_plane(plane, dev) 1452490d3d1bSChris Wilson if (idx == plane->index) 1453f81338a5SChandra Konduru return plane; 1454490d3d1bSChris Wilson 1455f81338a5SChandra Konduru return NULL; 1456f81338a5SChandra Konduru } 1457f81338a5SChandra Konduru EXPORT_SYMBOL(drm_plane_from_index); 1458f81338a5SChandra Konduru 1459f81338a5SChandra Konduru /** 146035f2c3aeSVille Syrjälä * drm_plane_force_disable - Forcibly disable a plane 146135f2c3aeSVille Syrjälä * @plane: plane to disable 146235f2c3aeSVille Syrjälä * 146335f2c3aeSVille Syrjälä * Forces the plane to be disabled. 146435f2c3aeSVille Syrjälä * 146535f2c3aeSVille Syrjälä * Used when the plane's current framebuffer is destroyed, 146635f2c3aeSVille Syrjälä * and when restoring fbdev mode. 146735f2c3aeSVille Syrjälä */ 14689125e618SVille Syrjälä void drm_plane_force_disable(struct drm_plane *plane) 14699125e618SVille Syrjälä { 14709125e618SVille Syrjälä int ret; 14719125e618SVille Syrjälä 14723d30a59bSDaniel Vetter if (!plane->fb) 14739125e618SVille Syrjälä return; 14749125e618SVille Syrjälä 14753d30a59bSDaniel Vetter plane->old_fb = plane->fb; 14769125e618SVille Syrjälä ret = plane->funcs->disable_plane(plane); 1477731cce48SDaniel Vetter if (ret) { 14789125e618SVille Syrjälä DRM_ERROR("failed to disable plane with busy fb\n"); 14793d30a59bSDaniel Vetter plane->old_fb = NULL; 1480731cce48SDaniel Vetter return; 1481731cce48SDaniel Vetter } 14829125e618SVille Syrjälä /* disconnect the plane from the fb and crtc: */ 1483220dd2bcSDaniel Vetter drm_framebuffer_unreference(plane->old_fb); 14843d30a59bSDaniel Vetter plane->old_fb = NULL; 14859125e618SVille Syrjälä plane->fb = NULL; 14869125e618SVille Syrjälä plane->crtc = NULL; 14879125e618SVille Syrjälä } 14889125e618SVille Syrjälä EXPORT_SYMBOL(drm_plane_force_disable); 14899125e618SVille Syrjälä 149079190ea2SBenjamin Gaignard int drm_modeset_register_all(struct drm_device *dev) 149179190ea2SBenjamin Gaignard { 149279190ea2SBenjamin Gaignard int ret; 149379190ea2SBenjamin Gaignard 149479190ea2SBenjamin Gaignard ret = drm_plane_register_all(dev); 149579190ea2SBenjamin Gaignard if (ret) 149679190ea2SBenjamin Gaignard goto err_plane; 149779190ea2SBenjamin Gaignard 149879190ea2SBenjamin Gaignard ret = drm_crtc_register_all(dev); 149979190ea2SBenjamin Gaignard if (ret) 150079190ea2SBenjamin Gaignard goto err_crtc; 150179190ea2SBenjamin Gaignard 150279190ea2SBenjamin Gaignard ret = drm_encoder_register_all(dev); 150379190ea2SBenjamin Gaignard if (ret) 150479190ea2SBenjamin Gaignard goto err_encoder; 150579190ea2SBenjamin Gaignard 150679190ea2SBenjamin Gaignard ret = drm_connector_register_all(dev); 150779190ea2SBenjamin Gaignard if (ret) 150879190ea2SBenjamin Gaignard goto err_connector; 150979190ea2SBenjamin Gaignard 151079190ea2SBenjamin Gaignard return 0; 151179190ea2SBenjamin Gaignard 151279190ea2SBenjamin Gaignard err_connector: 151379190ea2SBenjamin Gaignard drm_encoder_unregister_all(dev); 151479190ea2SBenjamin Gaignard err_encoder: 151579190ea2SBenjamin Gaignard drm_crtc_unregister_all(dev); 151679190ea2SBenjamin Gaignard err_crtc: 151779190ea2SBenjamin Gaignard drm_plane_unregister_all(dev); 151879190ea2SBenjamin Gaignard err_plane: 151979190ea2SBenjamin Gaignard return ret; 152079190ea2SBenjamin Gaignard } 152179190ea2SBenjamin Gaignard 152279190ea2SBenjamin Gaignard void drm_modeset_unregister_all(struct drm_device *dev) 152379190ea2SBenjamin Gaignard { 152479190ea2SBenjamin Gaignard drm_connector_unregister_all(dev); 152579190ea2SBenjamin Gaignard drm_encoder_unregister_all(dev); 152679190ea2SBenjamin Gaignard drm_crtc_unregister_all(dev); 152779190ea2SBenjamin Gaignard drm_plane_unregister_all(dev); 152879190ea2SBenjamin Gaignard } 152979190ea2SBenjamin Gaignard 15306b4959f4SRob Clark static int drm_mode_create_standard_properties(struct drm_device *dev) 1531f453ba04SDave Airlie { 1532356af0e1SRob Clark struct drm_property *prop; 1533f453ba04SDave Airlie 1534f453ba04SDave Airlie /* 1535f453ba04SDave Airlie * Standard properties (apply to all connectors) 1536f453ba04SDave Airlie */ 1537356af0e1SRob Clark prop = drm_property_create(dev, DRM_MODE_PROP_BLOB | 1538f453ba04SDave Airlie DRM_MODE_PROP_IMMUTABLE, 1539f453ba04SDave Airlie "EDID", 0); 1540356af0e1SRob Clark if (!prop) 1541356af0e1SRob Clark return -ENOMEM; 1542356af0e1SRob Clark dev->mode_config.edid_property = prop; 1543f453ba04SDave Airlie 1544356af0e1SRob Clark prop = drm_property_create_enum(dev, 0, 15454a67d391SSascha Hauer "DPMS", drm_dpms_enum_list, 15464a67d391SSascha Hauer ARRAY_SIZE(drm_dpms_enum_list)); 1547356af0e1SRob Clark if (!prop) 1548356af0e1SRob Clark return -ENOMEM; 1549356af0e1SRob Clark dev->mode_config.dpms_property = prop; 1550f453ba04SDave Airlie 1551356af0e1SRob Clark prop = drm_property_create(dev, 155243aba7ebSDave Airlie DRM_MODE_PROP_BLOB | 155343aba7ebSDave Airlie DRM_MODE_PROP_IMMUTABLE, 155443aba7ebSDave Airlie "PATH", 0); 1555356af0e1SRob Clark if (!prop) 1556356af0e1SRob Clark return -ENOMEM; 1557356af0e1SRob Clark dev->mode_config.path_property = prop; 155843aba7ebSDave Airlie 1559356af0e1SRob Clark prop = drm_property_create(dev, 15606f134d7bSDave Airlie DRM_MODE_PROP_BLOB | 15616f134d7bSDave Airlie DRM_MODE_PROP_IMMUTABLE, 15626f134d7bSDave Airlie "TILE", 0); 1563356af0e1SRob Clark if (!prop) 1564356af0e1SRob Clark return -ENOMEM; 1565356af0e1SRob Clark dev->mode_config.tile_property = prop; 15666f134d7bSDave Airlie 15676b4959f4SRob Clark prop = drm_property_create_enum(dev, DRM_MODE_PROP_IMMUTABLE, 15689922ab5aSRob Clark "type", drm_plane_type_enum_list, 15699922ab5aSRob Clark ARRAY_SIZE(drm_plane_type_enum_list)); 15706b4959f4SRob Clark if (!prop) 15716b4959f4SRob Clark return -ENOMEM; 15726b4959f4SRob Clark dev->mode_config.plane_type_property = prop; 15736b4959f4SRob Clark 15746b4959f4SRob Clark prop = drm_property_create_range(dev, DRM_MODE_PROP_ATOMIC, 15756b4959f4SRob Clark "SRC_X", 0, UINT_MAX); 15766b4959f4SRob Clark if (!prop) 15776b4959f4SRob Clark return -ENOMEM; 15786b4959f4SRob Clark dev->mode_config.prop_src_x = prop; 15796b4959f4SRob Clark 15806b4959f4SRob Clark prop = drm_property_create_range(dev, DRM_MODE_PROP_ATOMIC, 15816b4959f4SRob Clark "SRC_Y", 0, UINT_MAX); 15826b4959f4SRob Clark if (!prop) 15836b4959f4SRob Clark return -ENOMEM; 15846b4959f4SRob Clark dev->mode_config.prop_src_y = prop; 15856b4959f4SRob Clark 15866b4959f4SRob Clark prop = drm_property_create_range(dev, DRM_MODE_PROP_ATOMIC, 15876b4959f4SRob Clark "SRC_W", 0, UINT_MAX); 15886b4959f4SRob Clark if (!prop) 15896b4959f4SRob Clark return -ENOMEM; 15906b4959f4SRob Clark dev->mode_config.prop_src_w = prop; 15916b4959f4SRob Clark 15926b4959f4SRob Clark prop = drm_property_create_range(dev, DRM_MODE_PROP_ATOMIC, 15936b4959f4SRob Clark "SRC_H", 0, UINT_MAX); 15946b4959f4SRob Clark if (!prop) 15956b4959f4SRob Clark return -ENOMEM; 15966b4959f4SRob Clark dev->mode_config.prop_src_h = prop; 15976b4959f4SRob Clark 15986b4959f4SRob Clark prop = drm_property_create_signed_range(dev, DRM_MODE_PROP_ATOMIC, 15996b4959f4SRob Clark "CRTC_X", INT_MIN, INT_MAX); 16006b4959f4SRob Clark if (!prop) 16016b4959f4SRob Clark return -ENOMEM; 16026b4959f4SRob Clark dev->mode_config.prop_crtc_x = prop; 16036b4959f4SRob Clark 16046b4959f4SRob Clark prop = drm_property_create_signed_range(dev, DRM_MODE_PROP_ATOMIC, 16056b4959f4SRob Clark "CRTC_Y", INT_MIN, INT_MAX); 16066b4959f4SRob Clark if (!prop) 16076b4959f4SRob Clark return -ENOMEM; 16086b4959f4SRob Clark dev->mode_config.prop_crtc_y = prop; 16096b4959f4SRob Clark 16106b4959f4SRob Clark prop = drm_property_create_range(dev, DRM_MODE_PROP_ATOMIC, 16116b4959f4SRob Clark "CRTC_W", 0, INT_MAX); 16126b4959f4SRob Clark if (!prop) 16136b4959f4SRob Clark return -ENOMEM; 16146b4959f4SRob Clark dev->mode_config.prop_crtc_w = prop; 16156b4959f4SRob Clark 16166b4959f4SRob Clark prop = drm_property_create_range(dev, DRM_MODE_PROP_ATOMIC, 16176b4959f4SRob Clark "CRTC_H", 0, INT_MAX); 16186b4959f4SRob Clark if (!prop) 16196b4959f4SRob Clark return -ENOMEM; 16206b4959f4SRob Clark dev->mode_config.prop_crtc_h = prop; 16216b4959f4SRob Clark 16226b4959f4SRob Clark prop = drm_property_create_object(dev, DRM_MODE_PROP_ATOMIC, 16236b4959f4SRob Clark "FB_ID", DRM_MODE_OBJECT_FB); 16246b4959f4SRob Clark if (!prop) 16256b4959f4SRob Clark return -ENOMEM; 16266b4959f4SRob Clark dev->mode_config.prop_fb_id = prop; 16276b4959f4SRob Clark 16286b4959f4SRob Clark prop = drm_property_create_object(dev, DRM_MODE_PROP_ATOMIC, 16296b4959f4SRob Clark "CRTC_ID", DRM_MODE_OBJECT_CRTC); 16306b4959f4SRob Clark if (!prop) 16316b4959f4SRob Clark return -ENOMEM; 16326b4959f4SRob Clark dev->mode_config.prop_crtc_id = prop; 16339922ab5aSRob Clark 1634eab3bbefSDaniel Vetter prop = drm_property_create_bool(dev, DRM_MODE_PROP_ATOMIC, 1635eab3bbefSDaniel Vetter "ACTIVE"); 1636eab3bbefSDaniel Vetter if (!prop) 1637eab3bbefSDaniel Vetter return -ENOMEM; 1638eab3bbefSDaniel Vetter dev->mode_config.prop_active = prop; 1639eab3bbefSDaniel Vetter 1640955f3c33SDaniel Stone prop = drm_property_create(dev, 1641955f3c33SDaniel Stone DRM_MODE_PROP_ATOMIC | DRM_MODE_PROP_BLOB, 1642955f3c33SDaniel Stone "MODE_ID", 0); 1643955f3c33SDaniel Stone if (!prop) 1644955f3c33SDaniel Stone return -ENOMEM; 1645955f3c33SDaniel Stone dev->mode_config.prop_mode_id = prop; 1646955f3c33SDaniel Stone 16475488dc16SLionel Landwerlin prop = drm_property_create(dev, 16485488dc16SLionel Landwerlin DRM_MODE_PROP_BLOB, 16495488dc16SLionel Landwerlin "DEGAMMA_LUT", 0); 16505488dc16SLionel Landwerlin if (!prop) 16515488dc16SLionel Landwerlin return -ENOMEM; 16525488dc16SLionel Landwerlin dev->mode_config.degamma_lut_property = prop; 16535488dc16SLionel Landwerlin 16545488dc16SLionel Landwerlin prop = drm_property_create_range(dev, 16555488dc16SLionel Landwerlin DRM_MODE_PROP_IMMUTABLE, 16565488dc16SLionel Landwerlin "DEGAMMA_LUT_SIZE", 0, UINT_MAX); 16575488dc16SLionel Landwerlin if (!prop) 16585488dc16SLionel Landwerlin return -ENOMEM; 16595488dc16SLionel Landwerlin dev->mode_config.degamma_lut_size_property = prop; 16605488dc16SLionel Landwerlin 16615488dc16SLionel Landwerlin prop = drm_property_create(dev, 16625488dc16SLionel Landwerlin DRM_MODE_PROP_BLOB, 16635488dc16SLionel Landwerlin "CTM", 0); 16645488dc16SLionel Landwerlin if (!prop) 16655488dc16SLionel Landwerlin return -ENOMEM; 16665488dc16SLionel Landwerlin dev->mode_config.ctm_property = prop; 16675488dc16SLionel Landwerlin 16685488dc16SLionel Landwerlin prop = drm_property_create(dev, 16695488dc16SLionel Landwerlin DRM_MODE_PROP_BLOB, 16705488dc16SLionel Landwerlin "GAMMA_LUT", 0); 16715488dc16SLionel Landwerlin if (!prop) 16725488dc16SLionel Landwerlin return -ENOMEM; 16735488dc16SLionel Landwerlin dev->mode_config.gamma_lut_property = prop; 16745488dc16SLionel Landwerlin 16755488dc16SLionel Landwerlin prop = drm_property_create_range(dev, 16765488dc16SLionel Landwerlin DRM_MODE_PROP_IMMUTABLE, 16775488dc16SLionel Landwerlin "GAMMA_LUT_SIZE", 0, UINT_MAX); 16785488dc16SLionel Landwerlin if (!prop) 16795488dc16SLionel Landwerlin return -ENOMEM; 16805488dc16SLionel Landwerlin dev->mode_config.gamma_lut_size_property = prop; 16815488dc16SLionel Landwerlin 16829922ab5aSRob Clark return 0; 16839922ab5aSRob Clark } 16849922ab5aSRob Clark 1685f453ba04SDave Airlie /** 1686f453ba04SDave Airlie * drm_mode_create_dvi_i_properties - create DVI-I specific connector properties 1687f453ba04SDave Airlie * @dev: DRM device 1688f453ba04SDave Airlie * 1689f453ba04SDave Airlie * Called by a driver the first time a DVI-I connector is made. 1690f453ba04SDave Airlie */ 1691f453ba04SDave Airlie int drm_mode_create_dvi_i_properties(struct drm_device *dev) 1692f453ba04SDave Airlie { 1693f453ba04SDave Airlie struct drm_property *dvi_i_selector; 1694f453ba04SDave Airlie struct drm_property *dvi_i_subconnector; 1695f453ba04SDave Airlie 1696f453ba04SDave Airlie if (dev->mode_config.dvi_i_select_subconnector_property) 1697f453ba04SDave Airlie return 0; 1698f453ba04SDave Airlie 1699f453ba04SDave Airlie dvi_i_selector = 17004a67d391SSascha Hauer drm_property_create_enum(dev, 0, 1701f453ba04SDave Airlie "select subconnector", 17024a67d391SSascha Hauer drm_dvi_i_select_enum_list, 1703f453ba04SDave Airlie ARRAY_SIZE(drm_dvi_i_select_enum_list)); 1704f453ba04SDave Airlie dev->mode_config.dvi_i_select_subconnector_property = dvi_i_selector; 1705f453ba04SDave Airlie 17064a67d391SSascha Hauer dvi_i_subconnector = drm_property_create_enum(dev, DRM_MODE_PROP_IMMUTABLE, 1707f453ba04SDave Airlie "subconnector", 17084a67d391SSascha Hauer drm_dvi_i_subconnector_enum_list, 1709f453ba04SDave Airlie ARRAY_SIZE(drm_dvi_i_subconnector_enum_list)); 1710f453ba04SDave Airlie dev->mode_config.dvi_i_subconnector_property = dvi_i_subconnector; 1711f453ba04SDave Airlie 1712f453ba04SDave Airlie return 0; 1713f453ba04SDave Airlie } 1714f453ba04SDave Airlie EXPORT_SYMBOL(drm_mode_create_dvi_i_properties); 1715f453ba04SDave Airlie 1716f453ba04SDave Airlie /** 1717f453ba04SDave Airlie * drm_create_tv_properties - create TV specific connector properties 1718f453ba04SDave Airlie * @dev: DRM device 1719f453ba04SDave Airlie * @num_modes: number of different TV formats (modes) supported 1720f453ba04SDave Airlie * @modes: array of pointers to strings containing name of each format 1721f453ba04SDave Airlie * 1722f453ba04SDave Airlie * Called by a driver's TV initialization routine, this function creates 1723f453ba04SDave Airlie * the TV specific connector properties for a given device. Caller is 1724f453ba04SDave Airlie * responsible for allocating a list of format names and passing them to 1725f453ba04SDave Airlie * this routine. 1726f453ba04SDave Airlie */ 17272f763312SThierry Reding int drm_mode_create_tv_properties(struct drm_device *dev, 17282f763312SThierry Reding unsigned int num_modes, 1729b7c914b3SVille Syrjälä const char * const modes[]) 1730f453ba04SDave Airlie { 1731f453ba04SDave Airlie struct drm_property *tv_selector; 1732f453ba04SDave Airlie struct drm_property *tv_subconnector; 17332f763312SThierry Reding unsigned int i; 1734f453ba04SDave Airlie 1735f453ba04SDave Airlie if (dev->mode_config.tv_select_subconnector_property) 1736f453ba04SDave Airlie return 0; 1737f453ba04SDave Airlie 1738f453ba04SDave Airlie /* 1739f453ba04SDave Airlie * Basic connector properties 1740f453ba04SDave Airlie */ 17414a67d391SSascha Hauer tv_selector = drm_property_create_enum(dev, 0, 1742f453ba04SDave Airlie "select subconnector", 17434a67d391SSascha Hauer drm_tv_select_enum_list, 1744f453ba04SDave Airlie ARRAY_SIZE(drm_tv_select_enum_list)); 174548aa1e74SInsu Yun if (!tv_selector) 174648aa1e74SInsu Yun goto nomem; 174748aa1e74SInsu Yun 1748f453ba04SDave Airlie dev->mode_config.tv_select_subconnector_property = tv_selector; 1749f453ba04SDave Airlie 1750f453ba04SDave Airlie tv_subconnector = 17514a67d391SSascha Hauer drm_property_create_enum(dev, DRM_MODE_PROP_IMMUTABLE, 17524a67d391SSascha Hauer "subconnector", 17534a67d391SSascha Hauer drm_tv_subconnector_enum_list, 1754f453ba04SDave Airlie ARRAY_SIZE(drm_tv_subconnector_enum_list)); 175548aa1e74SInsu Yun if (!tv_subconnector) 175648aa1e74SInsu Yun goto nomem; 1757f453ba04SDave Airlie dev->mode_config.tv_subconnector_property = tv_subconnector; 1758f453ba04SDave Airlie 1759f453ba04SDave Airlie /* 1760f453ba04SDave Airlie * Other, TV specific properties: margins & TV modes. 1761f453ba04SDave Airlie */ 1762f453ba04SDave Airlie dev->mode_config.tv_left_margin_property = 1763d9bc3c02SSascha Hauer drm_property_create_range(dev, 0, "left margin", 0, 100); 176448aa1e74SInsu Yun if (!dev->mode_config.tv_left_margin_property) 176548aa1e74SInsu Yun goto nomem; 1766f453ba04SDave Airlie 1767f453ba04SDave Airlie dev->mode_config.tv_right_margin_property = 1768d9bc3c02SSascha Hauer drm_property_create_range(dev, 0, "right margin", 0, 100); 176948aa1e74SInsu Yun if (!dev->mode_config.tv_right_margin_property) 177048aa1e74SInsu Yun goto nomem; 1771f453ba04SDave Airlie 1772f453ba04SDave Airlie dev->mode_config.tv_top_margin_property = 1773d9bc3c02SSascha Hauer drm_property_create_range(dev, 0, "top margin", 0, 100); 177448aa1e74SInsu Yun if (!dev->mode_config.tv_top_margin_property) 177548aa1e74SInsu Yun goto nomem; 1776f453ba04SDave Airlie 1777f453ba04SDave Airlie dev->mode_config.tv_bottom_margin_property = 1778d9bc3c02SSascha Hauer drm_property_create_range(dev, 0, "bottom margin", 0, 100); 177948aa1e74SInsu Yun if (!dev->mode_config.tv_bottom_margin_property) 178048aa1e74SInsu Yun goto nomem; 1781f453ba04SDave Airlie 1782f453ba04SDave Airlie dev->mode_config.tv_mode_property = 1783f453ba04SDave Airlie drm_property_create(dev, DRM_MODE_PROP_ENUM, 1784f453ba04SDave Airlie "mode", num_modes); 178548aa1e74SInsu Yun if (!dev->mode_config.tv_mode_property) 178648aa1e74SInsu Yun goto nomem; 178748aa1e74SInsu Yun 1788f453ba04SDave Airlie for (i = 0; i < num_modes; i++) 1789f453ba04SDave Airlie drm_property_add_enum(dev->mode_config.tv_mode_property, i, 1790f453ba04SDave Airlie i, modes[i]); 1791f453ba04SDave Airlie 1792b6b7902eSFrancisco Jerez dev->mode_config.tv_brightness_property = 1793d9bc3c02SSascha Hauer drm_property_create_range(dev, 0, "brightness", 0, 100); 179448aa1e74SInsu Yun if (!dev->mode_config.tv_brightness_property) 179548aa1e74SInsu Yun goto nomem; 1796b6b7902eSFrancisco Jerez 1797b6b7902eSFrancisco Jerez dev->mode_config.tv_contrast_property = 1798d9bc3c02SSascha Hauer drm_property_create_range(dev, 0, "contrast", 0, 100); 179948aa1e74SInsu Yun if (!dev->mode_config.tv_contrast_property) 180048aa1e74SInsu Yun goto nomem; 1801b6b7902eSFrancisco Jerez 1802b6b7902eSFrancisco Jerez dev->mode_config.tv_flicker_reduction_property = 1803d9bc3c02SSascha Hauer drm_property_create_range(dev, 0, "flicker reduction", 0, 100); 180448aa1e74SInsu Yun if (!dev->mode_config.tv_flicker_reduction_property) 180548aa1e74SInsu Yun goto nomem; 1806b6b7902eSFrancisco Jerez 1807a75f0236SFrancisco Jerez dev->mode_config.tv_overscan_property = 1808d9bc3c02SSascha Hauer drm_property_create_range(dev, 0, "overscan", 0, 100); 180948aa1e74SInsu Yun if (!dev->mode_config.tv_overscan_property) 181048aa1e74SInsu Yun goto nomem; 1811a75f0236SFrancisco Jerez 1812a75f0236SFrancisco Jerez dev->mode_config.tv_saturation_property = 1813d9bc3c02SSascha Hauer drm_property_create_range(dev, 0, "saturation", 0, 100); 181448aa1e74SInsu Yun if (!dev->mode_config.tv_saturation_property) 181548aa1e74SInsu Yun goto nomem; 1816a75f0236SFrancisco Jerez 1817a75f0236SFrancisco Jerez dev->mode_config.tv_hue_property = 1818d9bc3c02SSascha Hauer drm_property_create_range(dev, 0, "hue", 0, 100); 181948aa1e74SInsu Yun if (!dev->mode_config.tv_hue_property) 182048aa1e74SInsu Yun goto nomem; 1821a75f0236SFrancisco Jerez 1822f453ba04SDave Airlie return 0; 182348aa1e74SInsu Yun nomem: 182448aa1e74SInsu Yun return -ENOMEM; 1825f453ba04SDave Airlie } 1826f453ba04SDave Airlie EXPORT_SYMBOL(drm_mode_create_tv_properties); 1827f453ba04SDave Airlie 1828f453ba04SDave Airlie /** 1829f453ba04SDave Airlie * drm_mode_create_scaling_mode_property - create scaling mode property 1830f453ba04SDave Airlie * @dev: DRM device 1831f453ba04SDave Airlie * 1832f453ba04SDave Airlie * Called by a driver the first time it's needed, must be attached to desired 1833f453ba04SDave Airlie * connectors. 1834f453ba04SDave Airlie */ 1835f453ba04SDave Airlie int drm_mode_create_scaling_mode_property(struct drm_device *dev) 1836f453ba04SDave Airlie { 1837f453ba04SDave Airlie struct drm_property *scaling_mode; 1838f453ba04SDave Airlie 1839f453ba04SDave Airlie if (dev->mode_config.scaling_mode_property) 1840f453ba04SDave Airlie return 0; 1841f453ba04SDave Airlie 1842f453ba04SDave Airlie scaling_mode = 18434a67d391SSascha Hauer drm_property_create_enum(dev, 0, "scaling mode", 18444a67d391SSascha Hauer drm_scaling_mode_enum_list, 1845f453ba04SDave Airlie ARRAY_SIZE(drm_scaling_mode_enum_list)); 1846f453ba04SDave Airlie 1847f453ba04SDave Airlie dev->mode_config.scaling_mode_property = scaling_mode; 1848f453ba04SDave Airlie 1849f453ba04SDave Airlie return 0; 1850f453ba04SDave Airlie } 1851f453ba04SDave Airlie EXPORT_SYMBOL(drm_mode_create_scaling_mode_property); 1852f453ba04SDave Airlie 1853f453ba04SDave Airlie /** 1854ff587e45SVandana Kannan * drm_mode_create_aspect_ratio_property - create aspect ratio property 1855ff587e45SVandana Kannan * @dev: DRM device 1856ff587e45SVandana Kannan * 1857ff587e45SVandana Kannan * Called by a driver the first time it's needed, must be attached to desired 1858ff587e45SVandana Kannan * connectors. 1859ff587e45SVandana Kannan * 1860ff587e45SVandana Kannan * Returns: 18611a498633SDaniel Vetter * Zero on success, negative errno on failure. 1862ff587e45SVandana Kannan */ 1863ff587e45SVandana Kannan int drm_mode_create_aspect_ratio_property(struct drm_device *dev) 1864ff587e45SVandana Kannan { 1865ff587e45SVandana Kannan if (dev->mode_config.aspect_ratio_property) 1866ff587e45SVandana Kannan return 0; 1867ff587e45SVandana Kannan 1868ff587e45SVandana Kannan dev->mode_config.aspect_ratio_property = 1869ff587e45SVandana Kannan drm_property_create_enum(dev, 0, "aspect ratio", 1870ff587e45SVandana Kannan drm_aspect_ratio_enum_list, 1871ff587e45SVandana Kannan ARRAY_SIZE(drm_aspect_ratio_enum_list)); 1872ff587e45SVandana Kannan 1873ff587e45SVandana Kannan if (dev->mode_config.aspect_ratio_property == NULL) 1874ff587e45SVandana Kannan return -ENOMEM; 1875ff587e45SVandana Kannan 1876ff587e45SVandana Kannan return 0; 1877ff587e45SVandana Kannan } 1878ff587e45SVandana Kannan EXPORT_SYMBOL(drm_mode_create_aspect_ratio_property); 1879ff587e45SVandana Kannan 1880ff587e45SVandana Kannan /** 1881884840aaSJakob Bornecrantz * drm_mode_create_dirty_property - create dirty property 1882884840aaSJakob Bornecrantz * @dev: DRM device 1883884840aaSJakob Bornecrantz * 1884884840aaSJakob Bornecrantz * Called by a driver the first time it's needed, must be attached to desired 1885884840aaSJakob Bornecrantz * connectors. 1886884840aaSJakob Bornecrantz */ 1887884840aaSJakob Bornecrantz int drm_mode_create_dirty_info_property(struct drm_device *dev) 1888884840aaSJakob Bornecrantz { 1889884840aaSJakob Bornecrantz struct drm_property *dirty_info; 1890884840aaSJakob Bornecrantz 1891884840aaSJakob Bornecrantz if (dev->mode_config.dirty_info_property) 1892884840aaSJakob Bornecrantz return 0; 1893884840aaSJakob Bornecrantz 1894884840aaSJakob Bornecrantz dirty_info = 18954a67d391SSascha Hauer drm_property_create_enum(dev, DRM_MODE_PROP_IMMUTABLE, 1896884840aaSJakob Bornecrantz "dirty", 18974a67d391SSascha Hauer drm_dirty_info_enum_list, 1898884840aaSJakob Bornecrantz ARRAY_SIZE(drm_dirty_info_enum_list)); 1899884840aaSJakob Bornecrantz dev->mode_config.dirty_info_property = dirty_info; 1900884840aaSJakob Bornecrantz 1901884840aaSJakob Bornecrantz return 0; 1902884840aaSJakob Bornecrantz } 1903884840aaSJakob Bornecrantz EXPORT_SYMBOL(drm_mode_create_dirty_info_property); 1904884840aaSJakob Bornecrantz 19055bb2bbf5SDave Airlie /** 19065bb2bbf5SDave Airlie * drm_mode_create_suggested_offset_properties - create suggests offset properties 19075bb2bbf5SDave Airlie * @dev: DRM device 19085bb2bbf5SDave Airlie * 19095bb2bbf5SDave Airlie * Create the the suggested x/y offset property for connectors. 19105bb2bbf5SDave Airlie */ 19115bb2bbf5SDave Airlie int drm_mode_create_suggested_offset_properties(struct drm_device *dev) 19125bb2bbf5SDave Airlie { 19135bb2bbf5SDave Airlie if (dev->mode_config.suggested_x_property && dev->mode_config.suggested_y_property) 19145bb2bbf5SDave Airlie return 0; 19155bb2bbf5SDave Airlie 19165bb2bbf5SDave Airlie dev->mode_config.suggested_x_property = 19175bb2bbf5SDave Airlie drm_property_create_range(dev, DRM_MODE_PROP_IMMUTABLE, "suggested X", 0, 0xffffffff); 19185bb2bbf5SDave Airlie 19195bb2bbf5SDave Airlie dev->mode_config.suggested_y_property = 19205bb2bbf5SDave Airlie drm_property_create_range(dev, DRM_MODE_PROP_IMMUTABLE, "suggested Y", 0, 0xffffffff); 19215bb2bbf5SDave Airlie 19225bb2bbf5SDave Airlie if (dev->mode_config.suggested_x_property == NULL || 19235bb2bbf5SDave Airlie dev->mode_config.suggested_y_property == NULL) 19245bb2bbf5SDave Airlie return -ENOMEM; 19255bb2bbf5SDave Airlie return 0; 19265bb2bbf5SDave Airlie } 19275bb2bbf5SDave Airlie EXPORT_SYMBOL(drm_mode_create_suggested_offset_properties); 19285bb2bbf5SDave Airlie 1929f453ba04SDave Airlie /** 1930f453ba04SDave Airlie * drm_mode_getresources - get graphics configuration 1931065a50edSDaniel Vetter * @dev: drm device for the ioctl 1932065a50edSDaniel Vetter * @data: data pointer for the ioctl 1933065a50edSDaniel Vetter * @file_priv: drm file for the ioctl call 1934f453ba04SDave Airlie * 1935f453ba04SDave Airlie * Construct a set of configuration description structures and return 1936f453ba04SDave Airlie * them to the user, including CRTC, connector and framebuffer configuration. 1937f453ba04SDave Airlie * 1938f453ba04SDave Airlie * Called by the user via ioctl. 1939f453ba04SDave Airlie * 1940c8e32cc1SDaniel Vetter * Returns: 19411a498633SDaniel Vetter * Zero on success, negative errno on failure. 1942f453ba04SDave Airlie */ 1943f453ba04SDave Airlie int drm_mode_getresources(struct drm_device *dev, void *data, 1944f453ba04SDave Airlie struct drm_file *file_priv) 1945f453ba04SDave Airlie { 1946f453ba04SDave Airlie struct drm_mode_card_res *card_res = data; 1947f453ba04SDave Airlie struct list_head *lh; 1948f453ba04SDave Airlie struct drm_framebuffer *fb; 1949f453ba04SDave Airlie struct drm_connector *connector; 1950f453ba04SDave Airlie struct drm_crtc *crtc; 1951f453ba04SDave Airlie struct drm_encoder *encoder; 1952f453ba04SDave Airlie int ret = 0; 1953f453ba04SDave Airlie int connector_count = 0; 1954f453ba04SDave Airlie int crtc_count = 0; 1955f453ba04SDave Airlie int fb_count = 0; 1956f453ba04SDave Airlie int encoder_count = 0; 19579c7060f7SDaniel Vetter int copied = 0; 1958f453ba04SDave Airlie uint32_t __user *fb_id; 1959f453ba04SDave Airlie uint32_t __user *crtc_id; 1960f453ba04SDave Airlie uint32_t __user *connector_id; 1961f453ba04SDave Airlie uint32_t __user *encoder_id; 1962f453ba04SDave Airlie 1963fb3b06c8SDave Airlie if (!drm_core_check_feature(dev, DRIVER_MODESET)) 1964fb3b06c8SDave Airlie return -EINVAL; 1965fb3b06c8SDave Airlie 1966f453ba04SDave Airlie 19674b096ac1SDaniel Vetter mutex_lock(&file_priv->fbs_lock); 1968f453ba04SDave Airlie /* 1969f453ba04SDave Airlie * For the non-control nodes we need to limit the list of resources 1970f453ba04SDave Airlie * by IDs in the group list for this node 1971f453ba04SDave Airlie */ 1972f453ba04SDave Airlie list_for_each(lh, &file_priv->fbs) 1973f453ba04SDave Airlie fb_count++; 1974f453ba04SDave Airlie 19754b096ac1SDaniel Vetter /* handle this in 4 parts */ 19764b096ac1SDaniel Vetter /* FBs */ 19774b096ac1SDaniel Vetter if (card_res->count_fbs >= fb_count) { 19784b096ac1SDaniel Vetter copied = 0; 19794b096ac1SDaniel Vetter fb_id = (uint32_t __user *)(unsigned long)card_res->fb_id_ptr; 19804b096ac1SDaniel Vetter list_for_each_entry(fb, &file_priv->fbs, filp_head) { 19814b096ac1SDaniel Vetter if (put_user(fb->base.id, fb_id + copied)) { 19824b096ac1SDaniel Vetter mutex_unlock(&file_priv->fbs_lock); 19834b096ac1SDaniel Vetter return -EFAULT; 19844b096ac1SDaniel Vetter } 19854b096ac1SDaniel Vetter copied++; 19864b096ac1SDaniel Vetter } 19874b096ac1SDaniel Vetter } 19884b096ac1SDaniel Vetter card_res->count_fbs = fb_count; 19894b096ac1SDaniel Vetter mutex_unlock(&file_priv->fbs_lock); 19904b096ac1SDaniel Vetter 1991fcf93f69SDaniel Vetter /* mode_config.mutex protects the connector list against e.g. DP MST 1992fcf93f69SDaniel Vetter * connector hot-adding. CRTC/Plane lists are invariant. */ 1993fcf93f69SDaniel Vetter mutex_lock(&dev->mode_config.mutex); 1994e4f62546SDaniel Vetter drm_for_each_crtc(crtc, dev) 1995f453ba04SDave Airlie crtc_count++; 1996f453ba04SDave Airlie 19979a9f5ce8SDaniel Vetter drm_for_each_connector(connector, dev) 1998f453ba04SDave Airlie connector_count++; 1999f453ba04SDave Airlie 2000e4f62546SDaniel Vetter drm_for_each_encoder(encoder, dev) 2001f453ba04SDave Airlie encoder_count++; 2002f453ba04SDave Airlie 2003f453ba04SDave Airlie card_res->max_height = dev->mode_config.max_height; 2004f453ba04SDave Airlie card_res->min_height = dev->mode_config.min_height; 2005f453ba04SDave Airlie card_res->max_width = dev->mode_config.max_width; 2006f453ba04SDave Airlie card_res->min_width = dev->mode_config.min_width; 2007f453ba04SDave Airlie 2008f453ba04SDave Airlie /* CRTCs */ 2009f453ba04SDave Airlie if (card_res->count_crtcs >= crtc_count) { 2010f453ba04SDave Airlie copied = 0; 2011f453ba04SDave Airlie crtc_id = (uint32_t __user *)(unsigned long)card_res->crtc_id_ptr; 20126295d607SDaniel Vetter drm_for_each_crtc(crtc, dev) { 2013f453ba04SDave Airlie if (put_user(crtc->base.id, crtc_id + copied)) { 2014f453ba04SDave Airlie ret = -EFAULT; 2015f453ba04SDave Airlie goto out; 2016f453ba04SDave Airlie } 2017f453ba04SDave Airlie copied++; 2018f453ba04SDave Airlie } 2019f453ba04SDave Airlie } 2020f453ba04SDave Airlie card_res->count_crtcs = crtc_count; 2021f453ba04SDave Airlie 2022f453ba04SDave Airlie /* Encoders */ 2023f453ba04SDave Airlie if (card_res->count_encoders >= encoder_count) { 2024f453ba04SDave Airlie copied = 0; 2025f453ba04SDave Airlie encoder_id = (uint32_t __user *)(unsigned long)card_res->encoder_id_ptr; 20266295d607SDaniel Vetter drm_for_each_encoder(encoder, dev) { 2027f453ba04SDave Airlie if (put_user(encoder->base.id, encoder_id + 2028f453ba04SDave Airlie copied)) { 2029f453ba04SDave Airlie ret = -EFAULT; 2030f453ba04SDave Airlie goto out; 2031f453ba04SDave Airlie } 2032f453ba04SDave Airlie copied++; 2033f453ba04SDave Airlie } 2034f453ba04SDave Airlie } 2035f453ba04SDave Airlie card_res->count_encoders = encoder_count; 2036f453ba04SDave Airlie 2037f453ba04SDave Airlie /* Connectors */ 2038f453ba04SDave Airlie if (card_res->count_connectors >= connector_count) { 2039f453ba04SDave Airlie copied = 0; 2040f453ba04SDave Airlie connector_id = (uint32_t __user *)(unsigned long)card_res->connector_id_ptr; 20416295d607SDaniel Vetter drm_for_each_connector(connector, dev) { 2042f453ba04SDave Airlie if (put_user(connector->base.id, 2043f453ba04SDave Airlie connector_id + copied)) { 2044f453ba04SDave Airlie ret = -EFAULT; 2045f453ba04SDave Airlie goto out; 2046f453ba04SDave Airlie } 2047f453ba04SDave Airlie copied++; 2048f453ba04SDave Airlie } 2049f453ba04SDave Airlie } 2050f453ba04SDave Airlie card_res->count_connectors = connector_count; 2051f453ba04SDave Airlie 2052f453ba04SDave Airlie out: 2053fcf93f69SDaniel Vetter mutex_unlock(&dev->mode_config.mutex); 2054f453ba04SDave Airlie return ret; 2055f453ba04SDave Airlie } 2056f453ba04SDave Airlie 2057f453ba04SDave Airlie /** 2058f453ba04SDave Airlie * drm_mode_getcrtc - get CRTC configuration 2059065a50edSDaniel Vetter * @dev: drm device for the ioctl 2060065a50edSDaniel Vetter * @data: data pointer for the ioctl 2061065a50edSDaniel Vetter * @file_priv: drm file for the ioctl call 2062f453ba04SDave Airlie * 2063f453ba04SDave Airlie * Construct a CRTC configuration structure to return to the user. 2064f453ba04SDave Airlie * 2065f453ba04SDave Airlie * Called by the user via ioctl. 2066f453ba04SDave Airlie * 2067c8e32cc1SDaniel Vetter * Returns: 20681a498633SDaniel Vetter * Zero on success, negative errno on failure. 2069f453ba04SDave Airlie */ 2070f453ba04SDave Airlie int drm_mode_getcrtc(struct drm_device *dev, 2071f453ba04SDave Airlie void *data, struct drm_file *file_priv) 2072f453ba04SDave Airlie { 2073f453ba04SDave Airlie struct drm_mode_crtc *crtc_resp = data; 2074f453ba04SDave Airlie struct drm_crtc *crtc; 2075f453ba04SDave Airlie 2076fb3b06c8SDave Airlie if (!drm_core_check_feature(dev, DRIVER_MODESET)) 2077fb3b06c8SDave Airlie return -EINVAL; 2078fb3b06c8SDave Airlie 2079a2b34e22SRob Clark crtc = drm_crtc_find(dev, crtc_resp->crtc_id); 2080fcf93f69SDaniel Vetter if (!crtc) 2081fcf93f69SDaniel Vetter return -ENOENT; 2082f453ba04SDave Airlie 2083fcf93f69SDaniel Vetter drm_modeset_lock_crtc(crtc, crtc->primary); 2084f453ba04SDave Airlie crtc_resp->gamma_size = crtc->gamma_size; 2085f4510a27SMatt Roper if (crtc->primary->fb) 2086f4510a27SMatt Roper crtc_resp->fb_id = crtc->primary->fb->base.id; 2087f453ba04SDave Airlie else 2088f453ba04SDave Airlie crtc_resp->fb_id = 0; 2089f453ba04SDave Airlie 209031c946e8SDaniel Vetter if (crtc->state) { 209131c946e8SDaniel Vetter crtc_resp->x = crtc->primary->state->src_x >> 16; 209231c946e8SDaniel Vetter crtc_resp->y = crtc->primary->state->src_y >> 16; 209331c946e8SDaniel Vetter if (crtc->state->enable) { 2094934a8a89SDaniel Stone drm_mode_convert_to_umode(&crtc_resp->mode, &crtc->state->mode); 209531c946e8SDaniel Vetter crtc_resp->mode_valid = 1; 2096f453ba04SDave Airlie 209731c946e8SDaniel Vetter } else { 209831c946e8SDaniel Vetter crtc_resp->mode_valid = 0; 209931c946e8SDaniel Vetter } 210031c946e8SDaniel Vetter } else { 210131c946e8SDaniel Vetter crtc_resp->x = crtc->x; 210231c946e8SDaniel Vetter crtc_resp->y = crtc->y; 210331c946e8SDaniel Vetter if (crtc->enabled) { 2104934a8a89SDaniel Stone drm_mode_convert_to_umode(&crtc_resp->mode, &crtc->mode); 2105f453ba04SDave Airlie crtc_resp->mode_valid = 1; 2106f453ba04SDave Airlie 2107f453ba04SDave Airlie } else { 2108f453ba04SDave Airlie crtc_resp->mode_valid = 0; 2109f453ba04SDave Airlie } 211031c946e8SDaniel Vetter } 2111fcf93f69SDaniel Vetter drm_modeset_unlock_crtc(crtc); 2112f453ba04SDave Airlie 2113baf698b0SDaniel Vetter return 0; 2114f453ba04SDave Airlie } 2115f453ba04SDave Airlie 211661d8e328SDamien Lespiau static bool drm_mode_expose_to_userspace(const struct drm_display_mode *mode, 211761d8e328SDamien Lespiau const struct drm_file *file_priv) 211861d8e328SDamien Lespiau { 211961d8e328SDamien Lespiau /* 212061d8e328SDamien Lespiau * If user-space hasn't configured the driver to expose the stereo 3D 212161d8e328SDamien Lespiau * modes, don't expose them. 212261d8e328SDamien Lespiau */ 212361d8e328SDamien Lespiau if (!file_priv->stereo_allowed && drm_mode_is_stereo(mode)) 212461d8e328SDamien Lespiau return false; 212561d8e328SDamien Lespiau 212661d8e328SDamien Lespiau return true; 212761d8e328SDamien Lespiau } 212861d8e328SDamien Lespiau 2129abd69c55SDaniel Vetter static struct drm_encoder *drm_connector_get_encoder(struct drm_connector *connector) 2130abd69c55SDaniel Vetter { 2131abd69c55SDaniel Vetter /* For atomic drivers only state objects are synchronously updated and 2132abd69c55SDaniel Vetter * protected by modeset locks, so check those first. */ 2133abd69c55SDaniel Vetter if (connector->state) 2134abd69c55SDaniel Vetter return connector->state->best_encoder; 2135abd69c55SDaniel Vetter return connector->encoder; 2136abd69c55SDaniel Vetter } 2137abd69c55SDaniel Vetter 213895cbf110SRob Clark /* helper for getconnector and getproperties ioctls */ 213988a48e29SRob Clark static int get_properties(struct drm_mode_object *obj, bool atomic, 214095cbf110SRob Clark uint32_t __user *prop_ptr, uint64_t __user *prop_values, 214195cbf110SRob Clark uint32_t *arg_count_props) 214295cbf110SRob Clark { 214388a48e29SRob Clark int props_count; 214488a48e29SRob Clark int i, ret, copied; 214588a48e29SRob Clark 214688a48e29SRob Clark props_count = obj->properties->count; 214788a48e29SRob Clark if (!atomic) 214888a48e29SRob Clark props_count -= obj->properties->atomic_count; 214995cbf110SRob Clark 215095cbf110SRob Clark if ((*arg_count_props >= props_count) && props_count) { 215188a48e29SRob Clark for (i = 0, copied = 0; copied < props_count; i++) { 215295cbf110SRob Clark struct drm_property *prop = obj->properties->properties[i]; 215395cbf110SRob Clark uint64_t val; 215495cbf110SRob Clark 215588a48e29SRob Clark if ((prop->flags & DRM_MODE_PROP_ATOMIC) && !atomic) 215688a48e29SRob Clark continue; 215788a48e29SRob Clark 215895cbf110SRob Clark ret = drm_object_property_get_value(obj, prop, &val); 215995cbf110SRob Clark if (ret) 216095cbf110SRob Clark return ret; 216195cbf110SRob Clark 216295cbf110SRob Clark if (put_user(prop->base.id, prop_ptr + copied)) 216395cbf110SRob Clark return -EFAULT; 216495cbf110SRob Clark 216595cbf110SRob Clark if (put_user(val, prop_values + copied)) 216695cbf110SRob Clark return -EFAULT; 216795cbf110SRob Clark 216895cbf110SRob Clark copied++; 216995cbf110SRob Clark } 217095cbf110SRob Clark } 217195cbf110SRob Clark *arg_count_props = props_count; 217295cbf110SRob Clark 217395cbf110SRob Clark return 0; 217495cbf110SRob Clark } 217595cbf110SRob Clark 2176f453ba04SDave Airlie /** 2177f453ba04SDave Airlie * drm_mode_getconnector - get connector configuration 2178065a50edSDaniel Vetter * @dev: drm device for the ioctl 2179065a50edSDaniel Vetter * @data: data pointer for the ioctl 2180065a50edSDaniel Vetter * @file_priv: drm file for the ioctl call 2181f453ba04SDave Airlie * 2182f453ba04SDave Airlie * Construct a connector configuration structure to return to the user. 2183f453ba04SDave Airlie * 2184f453ba04SDave Airlie * Called by the user via ioctl. 2185f453ba04SDave Airlie * 2186c8e32cc1SDaniel Vetter * Returns: 21871a498633SDaniel Vetter * Zero on success, negative errno on failure. 2188f453ba04SDave Airlie */ 2189f453ba04SDave Airlie int drm_mode_getconnector(struct drm_device *dev, void *data, 2190f453ba04SDave Airlie struct drm_file *file_priv) 2191f453ba04SDave Airlie { 2192f453ba04SDave Airlie struct drm_mode_get_connector *out_resp = data; 2193f453ba04SDave Airlie struct drm_connector *connector; 2194abd69c55SDaniel Vetter struct drm_encoder *encoder; 2195f453ba04SDave Airlie struct drm_display_mode *mode; 2196f453ba04SDave Airlie int mode_count = 0; 2197f453ba04SDave Airlie int encoders_count = 0; 2198f453ba04SDave Airlie int ret = 0; 2199f453ba04SDave Airlie int copied = 0; 2200f453ba04SDave Airlie int i; 2201f453ba04SDave Airlie struct drm_mode_modeinfo u_mode; 2202f453ba04SDave Airlie struct drm_mode_modeinfo __user *mode_ptr; 2203f453ba04SDave Airlie uint32_t __user *encoder_ptr; 2204f453ba04SDave Airlie 2205fb3b06c8SDave Airlie if (!drm_core_check_feature(dev, DRIVER_MODESET)) 2206fb3b06c8SDave Airlie return -EINVAL; 2207fb3b06c8SDave Airlie 2208f453ba04SDave Airlie memset(&u_mode, 0, sizeof(struct drm_mode_modeinfo)); 2209f453ba04SDave Airlie 22107b24056bSDaniel Vetter mutex_lock(&dev->mode_config.mutex); 2211f453ba04SDave Airlie 2212b164d31fSDave Airlie connector = drm_connector_lookup(dev, out_resp->connector_id); 2213a2b34e22SRob Clark if (!connector) { 2214f27657f2SVille Syrjälä ret = -ENOENT; 221504bdf441STommi Rantala goto out_unlock; 2216f453ba04SDave Airlie } 2217f453ba04SDave Airlie 221801073b08SThierry Reding for (i = 0; i < DRM_CONNECTOR_MAX_ENCODER; i++) 221901073b08SThierry Reding if (connector->encoder_ids[i] != 0) 2220f453ba04SDave Airlie encoders_count++; 2221f453ba04SDave Airlie 2222f453ba04SDave Airlie if (out_resp->count_modes == 0) { 2223f453ba04SDave Airlie connector->funcs->fill_modes(connector, 2224f453ba04SDave Airlie dev->mode_config.max_width, 2225f453ba04SDave Airlie dev->mode_config.max_height); 2226f453ba04SDave Airlie } 2227f453ba04SDave Airlie 2228f453ba04SDave Airlie /* delayed so we get modes regardless of pre-fill_modes state */ 2229f453ba04SDave Airlie list_for_each_entry(mode, &connector->modes, head) 223061d8e328SDamien Lespiau if (drm_mode_expose_to_userspace(mode, file_priv)) 2231f453ba04SDave Airlie mode_count++; 2232f453ba04SDave Airlie 2233f453ba04SDave Airlie out_resp->connector_id = connector->base.id; 2234f453ba04SDave Airlie out_resp->connector_type = connector->connector_type; 2235f453ba04SDave Airlie out_resp->connector_type_id = connector->connector_type_id; 2236f453ba04SDave Airlie out_resp->mm_width = connector->display_info.width_mm; 2237f453ba04SDave Airlie out_resp->mm_height = connector->display_info.height_mm; 2238f453ba04SDave Airlie out_resp->subpixel = connector->display_info.subpixel_order; 2239f453ba04SDave Airlie out_resp->connection = connector->status; 22402caa80e7SDaniel Vetter 22412caa80e7SDaniel Vetter drm_modeset_lock(&dev->mode_config.connection_mutex, NULL); 2242abd69c55SDaniel Vetter encoder = drm_connector_get_encoder(connector); 2243abd69c55SDaniel Vetter if (encoder) 2244abd69c55SDaniel Vetter out_resp->encoder_id = encoder->base.id; 2245f453ba04SDave Airlie else 2246f453ba04SDave Airlie out_resp->encoder_id = 0; 2247f453ba04SDave Airlie 2248f453ba04SDave Airlie /* 2249f453ba04SDave Airlie * This ioctl is called twice, once to determine how much space is 2250f453ba04SDave Airlie * needed, and the 2nd time to fill it. 2251f453ba04SDave Airlie */ 2252f453ba04SDave Airlie if ((out_resp->count_modes >= mode_count) && mode_count) { 2253f453ba04SDave Airlie copied = 0; 225481f6c7f8SVille Syrjälä mode_ptr = (struct drm_mode_modeinfo __user *)(unsigned long)out_resp->modes_ptr; 2255f453ba04SDave Airlie list_for_each_entry(mode, &connector->modes, head) { 225661d8e328SDamien Lespiau if (!drm_mode_expose_to_userspace(mode, file_priv)) 225761d8e328SDamien Lespiau continue; 225861d8e328SDamien Lespiau 2259934a8a89SDaniel Stone drm_mode_convert_to_umode(&u_mode, mode); 2260f453ba04SDave Airlie if (copy_to_user(mode_ptr + copied, 2261f453ba04SDave Airlie &u_mode, sizeof(u_mode))) { 2262f453ba04SDave Airlie ret = -EFAULT; 2263f453ba04SDave Airlie goto out; 2264f453ba04SDave Airlie } 2265f453ba04SDave Airlie copied++; 2266f453ba04SDave Airlie } 2267f453ba04SDave Airlie } 2268f453ba04SDave Airlie out_resp->count_modes = mode_count; 2269f453ba04SDave Airlie 227088a48e29SRob Clark ret = get_properties(&connector->base, file_priv->atomic, 227195cbf110SRob Clark (uint32_t __user *)(unsigned long)(out_resp->props_ptr), 227295cbf110SRob Clark (uint64_t __user *)(unsigned long)(out_resp->prop_values_ptr), 227395cbf110SRob Clark &out_resp->count_props); 227422b8b13bSRob Clark if (ret) 2275f453ba04SDave Airlie goto out; 2276f453ba04SDave Airlie 2277f453ba04SDave Airlie if ((out_resp->count_encoders >= encoders_count) && encoders_count) { 2278f453ba04SDave Airlie copied = 0; 227981f6c7f8SVille Syrjälä encoder_ptr = (uint32_t __user *)(unsigned long)(out_resp->encoders_ptr); 2280f453ba04SDave Airlie for (i = 0; i < DRM_CONNECTOR_MAX_ENCODER; i++) { 2281f453ba04SDave Airlie if (connector->encoder_ids[i] != 0) { 2282f453ba04SDave Airlie if (put_user(connector->encoder_ids[i], 2283f453ba04SDave Airlie encoder_ptr + copied)) { 2284f453ba04SDave Airlie ret = -EFAULT; 2285f453ba04SDave Airlie goto out; 2286f453ba04SDave Airlie } 2287f453ba04SDave Airlie copied++; 2288f453ba04SDave Airlie } 2289f453ba04SDave Airlie } 2290f453ba04SDave Airlie } 2291f453ba04SDave Airlie out_resp->count_encoders = encoders_count; 2292f453ba04SDave Airlie 2293f453ba04SDave Airlie out: 2294ccfc0865SRob Clark drm_modeset_unlock(&dev->mode_config.connection_mutex); 229504bdf441STommi Rantala 2296b164d31fSDave Airlie drm_connector_unreference(connector); 229704bdf441STommi Rantala out_unlock: 22987b24056bSDaniel Vetter mutex_unlock(&dev->mode_config.mutex); 22997b24056bSDaniel Vetter 2300f453ba04SDave Airlie return ret; 2301f453ba04SDave Airlie } 2302f453ba04SDave Airlie 2303abd69c55SDaniel Vetter static struct drm_crtc *drm_encoder_get_crtc(struct drm_encoder *encoder) 2304abd69c55SDaniel Vetter { 2305abd69c55SDaniel Vetter struct drm_connector *connector; 2306abd69c55SDaniel Vetter struct drm_device *dev = encoder->dev; 2307abd69c55SDaniel Vetter bool uses_atomic = false; 2308abd69c55SDaniel Vetter 2309abd69c55SDaniel Vetter /* For atomic drivers only state objects are synchronously updated and 2310abd69c55SDaniel Vetter * protected by modeset locks, so check those first. */ 23116295d607SDaniel Vetter drm_for_each_connector(connector, dev) { 2312abd69c55SDaniel Vetter if (!connector->state) 2313abd69c55SDaniel Vetter continue; 2314abd69c55SDaniel Vetter 2315abd69c55SDaniel Vetter uses_atomic = true; 2316abd69c55SDaniel Vetter 2317abd69c55SDaniel Vetter if (connector->state->best_encoder != encoder) 2318abd69c55SDaniel Vetter continue; 2319abd69c55SDaniel Vetter 2320abd69c55SDaniel Vetter return connector->state->crtc; 2321abd69c55SDaniel Vetter } 2322abd69c55SDaniel Vetter 2323abd69c55SDaniel Vetter /* Don't return stale data (e.g. pending async disable). */ 2324abd69c55SDaniel Vetter if (uses_atomic) 2325abd69c55SDaniel Vetter return NULL; 2326abd69c55SDaniel Vetter 2327abd69c55SDaniel Vetter return encoder->crtc; 2328abd69c55SDaniel Vetter } 2329abd69c55SDaniel Vetter 2330c8e32cc1SDaniel Vetter /** 2331c8e32cc1SDaniel Vetter * drm_mode_getencoder - get encoder configuration 2332c8e32cc1SDaniel Vetter * @dev: drm device for the ioctl 2333c8e32cc1SDaniel Vetter * @data: data pointer for the ioctl 2334c8e32cc1SDaniel Vetter * @file_priv: drm file for the ioctl call 2335c8e32cc1SDaniel Vetter * 2336c8e32cc1SDaniel Vetter * Construct a encoder configuration structure to return to the user. 2337c8e32cc1SDaniel Vetter * 2338c8e32cc1SDaniel Vetter * Called by the user via ioctl. 2339c8e32cc1SDaniel Vetter * 2340c8e32cc1SDaniel Vetter * Returns: 23411a498633SDaniel Vetter * Zero on success, negative errno on failure. 2342c8e32cc1SDaniel Vetter */ 2343f453ba04SDave Airlie int drm_mode_getencoder(struct drm_device *dev, void *data, 2344f453ba04SDave Airlie struct drm_file *file_priv) 2345f453ba04SDave Airlie { 2346f453ba04SDave Airlie struct drm_mode_get_encoder *enc_resp = data; 2347f453ba04SDave Airlie struct drm_encoder *encoder; 2348abd69c55SDaniel Vetter struct drm_crtc *crtc; 2349f453ba04SDave Airlie 2350fb3b06c8SDave Airlie if (!drm_core_check_feature(dev, DRIVER_MODESET)) 2351fb3b06c8SDave Airlie return -EINVAL; 2352fb3b06c8SDave Airlie 2353a2b34e22SRob Clark encoder = drm_encoder_find(dev, enc_resp->encoder_id); 2354fcf93f69SDaniel Vetter if (!encoder) 2355fcf93f69SDaniel Vetter return -ENOENT; 2356f453ba04SDave Airlie 2357fcf93f69SDaniel Vetter drm_modeset_lock(&dev->mode_config.connection_mutex, NULL); 2358abd69c55SDaniel Vetter crtc = drm_encoder_get_crtc(encoder); 2359abd69c55SDaniel Vetter if (crtc) 2360abd69c55SDaniel Vetter enc_resp->crtc_id = crtc->base.id; 2361f453ba04SDave Airlie else 2362f453ba04SDave Airlie enc_resp->crtc_id = 0; 2363fcf93f69SDaniel Vetter drm_modeset_unlock(&dev->mode_config.connection_mutex); 2364fcf93f69SDaniel Vetter 2365f453ba04SDave Airlie enc_resp->encoder_type = encoder->encoder_type; 2366f453ba04SDave Airlie enc_resp->encoder_id = encoder->base.id; 2367f453ba04SDave Airlie enc_resp->possible_crtcs = encoder->possible_crtcs; 2368f453ba04SDave Airlie enc_resp->possible_clones = encoder->possible_clones; 2369f453ba04SDave Airlie 2370baf698b0SDaniel Vetter return 0; 2371f453ba04SDave Airlie } 2372f453ba04SDave Airlie 2373f453ba04SDave Airlie /** 2374c8e32cc1SDaniel Vetter * drm_mode_getplane_res - enumerate all plane resources 23758cf5c917SJesse Barnes * @dev: DRM device 23768cf5c917SJesse Barnes * @data: ioctl data 23778cf5c917SJesse Barnes * @file_priv: DRM file info 23788cf5c917SJesse Barnes * 2379c8e32cc1SDaniel Vetter * Construct a list of plane ids to return to the user. 2380c8e32cc1SDaniel Vetter * 2381c8e32cc1SDaniel Vetter * Called by the user via ioctl. 2382c8e32cc1SDaniel Vetter * 2383c8e32cc1SDaniel Vetter * Returns: 23841a498633SDaniel Vetter * Zero on success, negative errno on failure. 23858cf5c917SJesse Barnes */ 23868cf5c917SJesse Barnes int drm_mode_getplane_res(struct drm_device *dev, void *data, 23878cf5c917SJesse Barnes struct drm_file *file_priv) 23888cf5c917SJesse Barnes { 23898cf5c917SJesse Barnes struct drm_mode_get_plane_res *plane_resp = data; 23908cf5c917SJesse Barnes struct drm_mode_config *config; 23918cf5c917SJesse Barnes struct drm_plane *plane; 23928cf5c917SJesse Barnes uint32_t __user *plane_ptr; 2393fcf93f69SDaniel Vetter int copied = 0; 2394681e7ec7SMatt Roper unsigned num_planes; 23958cf5c917SJesse Barnes 23968cf5c917SJesse Barnes if (!drm_core_check_feature(dev, DRIVER_MODESET)) 23978cf5c917SJesse Barnes return -EINVAL; 23988cf5c917SJesse Barnes 23998cf5c917SJesse Barnes config = &dev->mode_config; 24008cf5c917SJesse Barnes 2401681e7ec7SMatt Roper if (file_priv->universal_planes) 2402681e7ec7SMatt Roper num_planes = config->num_total_plane; 2403681e7ec7SMatt Roper else 2404681e7ec7SMatt Roper num_planes = config->num_overlay_plane; 2405681e7ec7SMatt Roper 24068cf5c917SJesse Barnes /* 24078cf5c917SJesse Barnes * This ioctl is called twice, once to determine how much space is 24088cf5c917SJesse Barnes * needed, and the 2nd time to fill it. 24098cf5c917SJesse Barnes */ 2410681e7ec7SMatt Roper if (num_planes && 2411681e7ec7SMatt Roper (plane_resp->count_planes >= num_planes)) { 241281f6c7f8SVille Syrjälä plane_ptr = (uint32_t __user *)(unsigned long)plane_resp->plane_id_ptr; 24138cf5c917SJesse Barnes 2414fcf93f69SDaniel Vetter /* Plane lists are invariant, no locking needed. */ 2415e4f62546SDaniel Vetter drm_for_each_plane(plane, dev) { 2416681e7ec7SMatt Roper /* 2417681e7ec7SMatt Roper * Unless userspace set the 'universal planes' 2418681e7ec7SMatt Roper * capability bit, only advertise overlays. 2419681e7ec7SMatt Roper */ 2420681e7ec7SMatt Roper if (plane->type != DRM_PLANE_TYPE_OVERLAY && 2421681e7ec7SMatt Roper !file_priv->universal_planes) 2422e27dde3eSMatt Roper continue; 2423e27dde3eSMatt Roper 2424fcf93f69SDaniel Vetter if (put_user(plane->base.id, plane_ptr + copied)) 2425fcf93f69SDaniel Vetter return -EFAULT; 24268cf5c917SJesse Barnes copied++; 24278cf5c917SJesse Barnes } 24288cf5c917SJesse Barnes } 2429681e7ec7SMatt Roper plane_resp->count_planes = num_planes; 24308cf5c917SJesse Barnes 2431fcf93f69SDaniel Vetter return 0; 24328cf5c917SJesse Barnes } 24338cf5c917SJesse Barnes 24348cf5c917SJesse Barnes /** 2435c8e32cc1SDaniel Vetter * drm_mode_getplane - get plane configuration 24368cf5c917SJesse Barnes * @dev: DRM device 24378cf5c917SJesse Barnes * @data: ioctl data 24388cf5c917SJesse Barnes * @file_priv: DRM file info 24398cf5c917SJesse Barnes * 2440c8e32cc1SDaniel Vetter * Construct a plane configuration structure to return to the user. 2441c8e32cc1SDaniel Vetter * 2442c8e32cc1SDaniel Vetter * Called by the user via ioctl. 2443c8e32cc1SDaniel Vetter * 2444c8e32cc1SDaniel Vetter * Returns: 24451a498633SDaniel Vetter * Zero on success, negative errno on failure. 24468cf5c917SJesse Barnes */ 24478cf5c917SJesse Barnes int drm_mode_getplane(struct drm_device *dev, void *data, 24488cf5c917SJesse Barnes struct drm_file *file_priv) 24498cf5c917SJesse Barnes { 24508cf5c917SJesse Barnes struct drm_mode_get_plane *plane_resp = data; 24518cf5c917SJesse Barnes struct drm_plane *plane; 24528cf5c917SJesse Barnes uint32_t __user *format_ptr; 24538cf5c917SJesse Barnes 24548cf5c917SJesse Barnes if (!drm_core_check_feature(dev, DRIVER_MODESET)) 24558cf5c917SJesse Barnes return -EINVAL; 24568cf5c917SJesse Barnes 2457a2b34e22SRob Clark plane = drm_plane_find(dev, plane_resp->plane_id); 2458fcf93f69SDaniel Vetter if (!plane) 2459fcf93f69SDaniel Vetter return -ENOENT; 24608cf5c917SJesse Barnes 2461fcf93f69SDaniel Vetter drm_modeset_lock(&plane->mutex, NULL); 24628cf5c917SJesse Barnes if (plane->crtc) 24638cf5c917SJesse Barnes plane_resp->crtc_id = plane->crtc->base.id; 24648cf5c917SJesse Barnes else 24658cf5c917SJesse Barnes plane_resp->crtc_id = 0; 24668cf5c917SJesse Barnes 24678cf5c917SJesse Barnes if (plane->fb) 24688cf5c917SJesse Barnes plane_resp->fb_id = plane->fb->base.id; 24698cf5c917SJesse Barnes else 24708cf5c917SJesse Barnes plane_resp->fb_id = 0; 2471fcf93f69SDaniel Vetter drm_modeset_unlock(&plane->mutex); 24728cf5c917SJesse Barnes 24738cf5c917SJesse Barnes plane_resp->plane_id = plane->base.id; 24748cf5c917SJesse Barnes plane_resp->possible_crtcs = plane->possible_crtcs; 2475778ad903SVille Syrjälä plane_resp->gamma_size = 0; 24768cf5c917SJesse Barnes 24778cf5c917SJesse Barnes /* 24788cf5c917SJesse Barnes * This ioctl is called twice, once to determine how much space is 24798cf5c917SJesse Barnes * needed, and the 2nd time to fill it. 24808cf5c917SJesse Barnes */ 24818cf5c917SJesse Barnes if (plane->format_count && 24828cf5c917SJesse Barnes (plane_resp->count_format_types >= plane->format_count)) { 248381f6c7f8SVille Syrjälä format_ptr = (uint32_t __user *)(unsigned long)plane_resp->format_type_ptr; 24848cf5c917SJesse Barnes if (copy_to_user(format_ptr, 24858cf5c917SJesse Barnes plane->format_types, 24868cf5c917SJesse Barnes sizeof(uint32_t) * plane->format_count)) { 2487fcf93f69SDaniel Vetter return -EFAULT; 24888cf5c917SJesse Barnes } 24898cf5c917SJesse Barnes } 24908cf5c917SJesse Barnes plane_resp->count_format_types = plane->format_count; 24918cf5c917SJesse Barnes 2492baf698b0SDaniel Vetter return 0; 24938cf5c917SJesse Barnes } 24948cf5c917SJesse Barnes 2495ead8610dSLaurent Pinchart /** 2496ead8610dSLaurent Pinchart * drm_plane_check_pixel_format - Check if the plane supports the pixel format 2497ead8610dSLaurent Pinchart * @plane: plane to check for format support 2498ead8610dSLaurent Pinchart * @format: the pixel format 2499ead8610dSLaurent Pinchart * 2500ead8610dSLaurent Pinchart * Returns: 2501ead8610dSLaurent Pinchart * Zero of @plane has @format in its list of supported pixel formats, -EINVAL 2502ead8610dSLaurent Pinchart * otherwise. 2503ead8610dSLaurent Pinchart */ 2504ead8610dSLaurent Pinchart int drm_plane_check_pixel_format(const struct drm_plane *plane, u32 format) 2505ead8610dSLaurent Pinchart { 2506ead8610dSLaurent Pinchart unsigned int i; 2507ead8610dSLaurent Pinchart 2508ead8610dSLaurent Pinchart for (i = 0; i < plane->format_count; i++) { 2509ead8610dSLaurent Pinchart if (format == plane->format_types[i]) 2510ead8610dSLaurent Pinchart return 0; 2511ead8610dSLaurent Pinchart } 2512ead8610dSLaurent Pinchart 2513ead8610dSLaurent Pinchart return -EINVAL; 2514ead8610dSLaurent Pinchart } 2515ead8610dSLaurent Pinchart 2516ce8d9eccSVille Syrjälä static int check_src_coords(uint32_t src_x, uint32_t src_y, 2517ce8d9eccSVille Syrjälä uint32_t src_w, uint32_t src_h, 2518ce8d9eccSVille Syrjälä const struct drm_framebuffer *fb) 2519ce8d9eccSVille Syrjälä { 2520ce8d9eccSVille Syrjälä unsigned int fb_width, fb_height; 2521ce8d9eccSVille Syrjälä 2522ce8d9eccSVille Syrjälä fb_width = fb->width << 16; 2523ce8d9eccSVille Syrjälä fb_height = fb->height << 16; 2524ce8d9eccSVille Syrjälä 2525ce8d9eccSVille Syrjälä /* Make sure source coordinates are inside the fb. */ 2526ce8d9eccSVille Syrjälä if (src_w > fb_width || 2527ce8d9eccSVille Syrjälä src_x > fb_width - src_w || 2528ce8d9eccSVille Syrjälä src_h > fb_height || 2529ce8d9eccSVille Syrjälä src_y > fb_height - src_h) { 2530ce8d9eccSVille Syrjälä DRM_DEBUG_KMS("Invalid source coordinates " 2531ce8d9eccSVille Syrjälä "%u.%06ux%u.%06u+%u.%06u+%u.%06u\n", 2532ce8d9eccSVille Syrjälä src_w >> 16, ((src_w & 0xffff) * 15625) >> 10, 2533ce8d9eccSVille Syrjälä src_h >> 16, ((src_h & 0xffff) * 15625) >> 10, 2534ce8d9eccSVille Syrjälä src_x >> 16, ((src_x & 0xffff) * 15625) >> 10, 2535ce8d9eccSVille Syrjälä src_y >> 16, ((src_y & 0xffff) * 15625) >> 10); 2536ce8d9eccSVille Syrjälä return -ENOSPC; 2537ce8d9eccSVille Syrjälä } 2538ce8d9eccSVille Syrjälä 2539ce8d9eccSVille Syrjälä return 0; 2540ce8d9eccSVille Syrjälä } 2541ce8d9eccSVille Syrjälä 2542b36552b3SMatt Roper /* 2543b36552b3SMatt Roper * setplane_internal - setplane handler for internal callers 25448cf5c917SJesse Barnes * 2545b36552b3SMatt Roper * Note that we assume an extra reference has already been taken on fb. If the 2546b36552b3SMatt Roper * update fails, this reference will be dropped before return; if it succeeds, 2547b36552b3SMatt Roper * the previous framebuffer (if any) will be unreferenced instead. 2548c8e32cc1SDaniel Vetter * 2549b36552b3SMatt Roper * src_{x,y,w,h} are provided in 16.16 fixed point format 25508cf5c917SJesse Barnes */ 2551f2b50c11SDaniel Vetter static int __setplane_internal(struct drm_plane *plane, 255217cfd91fSChris Wilson struct drm_crtc *crtc, 2553b36552b3SMatt Roper struct drm_framebuffer *fb, 2554b36552b3SMatt Roper int32_t crtc_x, int32_t crtc_y, 2555b36552b3SMatt Roper uint32_t crtc_w, uint32_t crtc_h, 2556b36552b3SMatt Roper /* src_{x,y,w,h} values are 16.16 fixed point */ 2557b36552b3SMatt Roper uint32_t src_x, uint32_t src_y, 2558b36552b3SMatt Roper uint32_t src_w, uint32_t src_h) 25598cf5c917SJesse Barnes { 25608cf5c917SJesse Barnes int ret = 0; 25618cf5c917SJesse Barnes 25628cf5c917SJesse Barnes /* No fb means shut it down */ 2563b36552b3SMatt Roper if (!fb) { 25643d30a59bSDaniel Vetter plane->old_fb = plane->fb; 2565731cce48SDaniel Vetter ret = plane->funcs->disable_plane(plane); 2566731cce48SDaniel Vetter if (!ret) { 2567e5e3b44cSVille Syrjälä plane->crtc = NULL; 2568e5e3b44cSVille Syrjälä plane->fb = NULL; 2569731cce48SDaniel Vetter } else { 25703d30a59bSDaniel Vetter plane->old_fb = NULL; 2571731cce48SDaniel Vetter } 25728cf5c917SJesse Barnes goto out; 25738cf5c917SJesse Barnes } 25748cf5c917SJesse Barnes 25757f994f3fSMatt Roper /* Check whether this plane is usable on this CRTC */ 25767f994f3fSMatt Roper if (!(plane->possible_crtcs & drm_crtc_mask(crtc))) { 25777f994f3fSMatt Roper DRM_DEBUG_KMS("Invalid crtc for plane\n"); 25787f994f3fSMatt Roper ret = -EINVAL; 25797f994f3fSMatt Roper goto out; 25807f994f3fSMatt Roper } 25817f994f3fSMatt Roper 258262443be6SVille Syrjälä /* Check whether this plane supports the fb pixel format. */ 2583ead8610dSLaurent Pinchart ret = drm_plane_check_pixel_format(plane, fb->pixel_format); 2584ead8610dSLaurent Pinchart if (ret) { 25856ba6d03eSVille Syrjälä DRM_DEBUG_KMS("Invalid pixel format %s\n", 25866ba6d03eSVille Syrjälä drm_get_format_name(fb->pixel_format)); 258762443be6SVille Syrjälä goto out; 258862443be6SVille Syrjälä } 258962443be6SVille Syrjälä 25903968be94SMatt Roper /* Give drivers some help against integer overflows */ 25913968be94SMatt Roper if (crtc_w > INT_MAX || 25923968be94SMatt Roper crtc_x > INT_MAX - (int32_t) crtc_w || 25933968be94SMatt Roper crtc_h > INT_MAX || 25943968be94SMatt Roper crtc_y > INT_MAX - (int32_t) crtc_h) { 25953968be94SMatt Roper DRM_DEBUG_KMS("Invalid CRTC coordinates %ux%u+%d+%d\n", 25963968be94SMatt Roper crtc_w, crtc_h, crtc_x, crtc_y); 2597c390eed0SVille Syrjälä ret = -ERANGE; 259842ef8789SVille Syrjälä goto out; 259942ef8789SVille Syrjälä } 260042ef8789SVille Syrjälä 2601ce8d9eccSVille Syrjälä ret = check_src_coords(src_x, src_y, src_w, src_h, fb); 2602ce8d9eccSVille Syrjälä if (ret) 2603f453ba04SDave Airlie goto out; 2604f453ba04SDave Airlie 26053d30a59bSDaniel Vetter plane->old_fb = plane->fb; 2606f453ba04SDave Airlie ret = plane->funcs->update_plane(plane, crtc, fb, 2607b36552b3SMatt Roper crtc_x, crtc_y, crtc_w, crtc_h, 2608b36552b3SMatt Roper src_x, src_y, src_w, src_h); 2609f453ba04SDave Airlie if (!ret) { 2610f453ba04SDave Airlie plane->crtc = crtc; 2611f453ba04SDave Airlie plane->fb = fb; 261235f8badcSDaniel Vetter fb = NULL; 26130fe27f06SDaniel Vetter } else { 26143d30a59bSDaniel Vetter plane->old_fb = NULL; 2615f453ba04SDave Airlie } 2616f453ba04SDave Airlie 2617f453ba04SDave Airlie out: 26186c2a7532SDaniel Vetter if (fb) 26196c2a7532SDaniel Vetter drm_framebuffer_unreference(fb); 26203d30a59bSDaniel Vetter if (plane->old_fb) 26213d30a59bSDaniel Vetter drm_framebuffer_unreference(plane->old_fb); 26223d30a59bSDaniel Vetter plane->old_fb = NULL; 2623f453ba04SDave Airlie 2624f453ba04SDave Airlie return ret; 2625f2b50c11SDaniel Vetter } 2626b36552b3SMatt Roper 2627f2b50c11SDaniel Vetter static int setplane_internal(struct drm_plane *plane, 2628f2b50c11SDaniel Vetter struct drm_crtc *crtc, 2629f2b50c11SDaniel Vetter struct drm_framebuffer *fb, 2630f2b50c11SDaniel Vetter int32_t crtc_x, int32_t crtc_y, 2631f2b50c11SDaniel Vetter uint32_t crtc_w, uint32_t crtc_h, 2632f2b50c11SDaniel Vetter /* src_{x,y,w,h} values are 16.16 fixed point */ 2633f2b50c11SDaniel Vetter uint32_t src_x, uint32_t src_y, 2634f2b50c11SDaniel Vetter uint32_t src_w, uint32_t src_h) 2635f2b50c11SDaniel Vetter { 2636f2b50c11SDaniel Vetter int ret; 2637f2b50c11SDaniel Vetter 2638f2b50c11SDaniel Vetter drm_modeset_lock_all(plane->dev); 2639f2b50c11SDaniel Vetter ret = __setplane_internal(plane, crtc, fb, 2640f2b50c11SDaniel Vetter crtc_x, crtc_y, crtc_w, crtc_h, 2641f2b50c11SDaniel Vetter src_x, src_y, src_w, src_h); 2642f2b50c11SDaniel Vetter drm_modeset_unlock_all(plane->dev); 2643f2b50c11SDaniel Vetter 2644f2b50c11SDaniel Vetter return ret; 2645b36552b3SMatt Roper } 2646b36552b3SMatt Roper 2647b36552b3SMatt Roper /** 2648b36552b3SMatt Roper * drm_mode_setplane - configure a plane's configuration 2649b36552b3SMatt Roper * @dev: DRM device 2650b36552b3SMatt Roper * @data: ioctl data* 2651b36552b3SMatt Roper * @file_priv: DRM file info 2652b36552b3SMatt Roper * 2653b36552b3SMatt Roper * Set plane configuration, including placement, fb, scaling, and other factors. 2654b36552b3SMatt Roper * Or pass a NULL fb to disable (planes may be disabled without providing a 2655b36552b3SMatt Roper * valid crtc). 2656b36552b3SMatt Roper * 2657b36552b3SMatt Roper * Returns: 26581a498633SDaniel Vetter * Zero on success, negative errno on failure. 2659b36552b3SMatt Roper */ 2660b36552b3SMatt Roper int drm_mode_setplane(struct drm_device *dev, void *data, 2661b36552b3SMatt Roper struct drm_file *file_priv) 2662b36552b3SMatt Roper { 2663b36552b3SMatt Roper struct drm_mode_set_plane *plane_req = data; 2664b36552b3SMatt Roper struct drm_plane *plane; 2665b36552b3SMatt Roper struct drm_crtc *crtc = NULL; 2666b36552b3SMatt Roper struct drm_framebuffer *fb = NULL; 2667b36552b3SMatt Roper 2668b36552b3SMatt Roper if (!drm_core_check_feature(dev, DRIVER_MODESET)) 2669b36552b3SMatt Roper return -EINVAL; 2670b36552b3SMatt Roper 2671b36552b3SMatt Roper /* 2672b36552b3SMatt Roper * First, find the plane, crtc, and fb objects. If not available, 2673b36552b3SMatt Roper * we don't bother to call the driver. 2674b36552b3SMatt Roper */ 2675933f622fSRob Clark plane = drm_plane_find(dev, plane_req->plane_id); 2676933f622fSRob Clark if (!plane) { 2677b36552b3SMatt Roper DRM_DEBUG_KMS("Unknown plane ID %d\n", 2678b36552b3SMatt Roper plane_req->plane_id); 2679b36552b3SMatt Roper return -ENOENT; 2680b36552b3SMatt Roper } 2681b36552b3SMatt Roper 2682b36552b3SMatt Roper if (plane_req->fb_id) { 2683b36552b3SMatt Roper fb = drm_framebuffer_lookup(dev, plane_req->fb_id); 2684b36552b3SMatt Roper if (!fb) { 2685b36552b3SMatt Roper DRM_DEBUG_KMS("Unknown framebuffer ID %d\n", 2686b36552b3SMatt Roper plane_req->fb_id); 2687b36552b3SMatt Roper return -ENOENT; 2688b36552b3SMatt Roper } 2689b36552b3SMatt Roper 2690933f622fSRob Clark crtc = drm_crtc_find(dev, plane_req->crtc_id); 2691933f622fSRob Clark if (!crtc) { 2692b36552b3SMatt Roper DRM_DEBUG_KMS("Unknown crtc ID %d\n", 2693b36552b3SMatt Roper plane_req->crtc_id); 2694b36552b3SMatt Roper return -ENOENT; 2695b36552b3SMatt Roper } 2696b36552b3SMatt Roper } 2697b36552b3SMatt Roper 2698161d0dc1SMatt Roper /* 2699161d0dc1SMatt Roper * setplane_internal will take care of deref'ing either the old or new 2700161d0dc1SMatt Roper * framebuffer depending on success. 2701161d0dc1SMatt Roper */ 270217cfd91fSChris Wilson return setplane_internal(plane, crtc, fb, 2703b36552b3SMatt Roper plane_req->crtc_x, plane_req->crtc_y, 2704b36552b3SMatt Roper plane_req->crtc_w, plane_req->crtc_h, 2705b36552b3SMatt Roper plane_req->src_x, plane_req->src_y, 2706b36552b3SMatt Roper plane_req->src_w, plane_req->src_h); 2707f453ba04SDave Airlie } 2708f453ba04SDave Airlie 2709f453ba04SDave Airlie /** 27102d13b679SDaniel Vetter * drm_mode_set_config_internal - helper to call ->set_config 27112d13b679SDaniel Vetter * @set: modeset config to set 27122d13b679SDaniel Vetter * 27132d13b679SDaniel Vetter * This is a little helper to wrap internal calls to the ->set_config driver 27142d13b679SDaniel Vetter * interface. The only thing it adds is correct refcounting dance. 2715c8e32cc1SDaniel Vetter * 2716c8e32cc1SDaniel Vetter * Returns: 27171a498633SDaniel Vetter * Zero on success, negative errno on failure. 27182d13b679SDaniel Vetter */ 27192d13b679SDaniel Vetter int drm_mode_set_config_internal(struct drm_mode_set *set) 27202d13b679SDaniel Vetter { 27212d13b679SDaniel Vetter struct drm_crtc *crtc = set->crtc; 27225cef29aaSDaniel Vetter struct drm_framebuffer *fb; 27235cef29aaSDaniel Vetter struct drm_crtc *tmp; 2724b0d12325SDaniel Vetter int ret; 27252d13b679SDaniel Vetter 27265cef29aaSDaniel Vetter /* 27275cef29aaSDaniel Vetter * NOTE: ->set_config can also disable other crtcs (if we steal all 27285cef29aaSDaniel Vetter * connectors from it), hence we need to refcount the fbs across all 27295cef29aaSDaniel Vetter * crtcs. Atomic modeset will have saner semantics ... 27305cef29aaSDaniel Vetter */ 2731e4f62546SDaniel Vetter drm_for_each_crtc(tmp, crtc->dev) 27323d30a59bSDaniel Vetter tmp->primary->old_fb = tmp->primary->fb; 27335cef29aaSDaniel Vetter 2734b0d12325SDaniel Vetter fb = set->fb; 2735b0d12325SDaniel Vetter 2736b0d12325SDaniel Vetter ret = crtc->funcs->set_config(set); 2737b0d12325SDaniel Vetter if (ret == 0) { 2738e13161afSMatt Roper crtc->primary->crtc = crtc; 27390fe27f06SDaniel Vetter crtc->primary->fb = fb; 27405cef29aaSDaniel Vetter } 2741cc85e121SDaniel Vetter 2742e4f62546SDaniel Vetter drm_for_each_crtc(tmp, crtc->dev) { 2743f4510a27SMatt Roper if (tmp->primary->fb) 2744f4510a27SMatt Roper drm_framebuffer_reference(tmp->primary->fb); 27453d30a59bSDaniel Vetter if (tmp->primary->old_fb) 27463d30a59bSDaniel Vetter drm_framebuffer_unreference(tmp->primary->old_fb); 27473d30a59bSDaniel Vetter tmp->primary->old_fb = NULL; 2748b0d12325SDaniel Vetter } 2749b0d12325SDaniel Vetter 2750b0d12325SDaniel Vetter return ret; 27512d13b679SDaniel Vetter } 27522d13b679SDaniel Vetter EXPORT_SYMBOL(drm_mode_set_config_internal); 27532d13b679SDaniel Vetter 2754af93629dSMatt Roper /** 2755ecb7e16bSGustavo Padovan * drm_crtc_get_hv_timing - Fetches hdisplay/vdisplay for given mode 2756ecb7e16bSGustavo Padovan * @mode: mode to query 2757ecb7e16bSGustavo Padovan * @hdisplay: hdisplay value to fill in 2758ecb7e16bSGustavo Padovan * @vdisplay: vdisplay value to fill in 2759ecb7e16bSGustavo Padovan * 2760ecb7e16bSGustavo Padovan * The vdisplay value will be doubled if the specified mode is a stereo mode of 2761ecb7e16bSGustavo Padovan * the appropriate layout. 2762ecb7e16bSGustavo Padovan */ 2763ecb7e16bSGustavo Padovan void drm_crtc_get_hv_timing(const struct drm_display_mode *mode, 2764ecb7e16bSGustavo Padovan int *hdisplay, int *vdisplay) 2765ecb7e16bSGustavo Padovan { 2766ecb7e16bSGustavo Padovan struct drm_display_mode adjusted; 2767ecb7e16bSGustavo Padovan 2768ecb7e16bSGustavo Padovan drm_mode_copy(&adjusted, mode); 2769ecb7e16bSGustavo Padovan drm_mode_set_crtcinfo(&adjusted, CRTC_STEREO_DOUBLE_ONLY); 2770ecb7e16bSGustavo Padovan *hdisplay = adjusted.crtc_hdisplay; 2771ecb7e16bSGustavo Padovan *vdisplay = adjusted.crtc_vdisplay; 2772ecb7e16bSGustavo Padovan } 2773ecb7e16bSGustavo Padovan EXPORT_SYMBOL(drm_crtc_get_hv_timing); 2774ecb7e16bSGustavo Padovan 2775ecb7e16bSGustavo Padovan /** 2776af93629dSMatt Roper * drm_crtc_check_viewport - Checks that a framebuffer is big enough for the 2777af93629dSMatt Roper * CRTC viewport 2778af93629dSMatt Roper * @crtc: CRTC that framebuffer will be displayed on 2779af93629dSMatt Roper * @x: x panning 2780af93629dSMatt Roper * @y: y panning 2781af93629dSMatt Roper * @mode: mode that framebuffer will be displayed under 2782af93629dSMatt Roper * @fb: framebuffer to check size of 2783c11e9283SDamien Lespiau */ 2784af93629dSMatt Roper int drm_crtc_check_viewport(const struct drm_crtc *crtc, 2785c11e9283SDamien Lespiau int x, int y, 2786c11e9283SDamien Lespiau const struct drm_display_mode *mode, 2787c11e9283SDamien Lespiau const struct drm_framebuffer *fb) 2788c11e9283SDamien Lespiau 2789c11e9283SDamien Lespiau { 2790c11e9283SDamien Lespiau int hdisplay, vdisplay; 2791c11e9283SDamien Lespiau 2792ecb7e16bSGustavo Padovan drm_crtc_get_hv_timing(mode, &hdisplay, &vdisplay); 2793a0c1bbb0SDamien Lespiau 279433e0be63SVille Syrjälä if (crtc->state && 279533e0be63SVille Syrjälä crtc->primary->state->rotation & (BIT(DRM_ROTATE_90) | 279633e0be63SVille Syrjälä BIT(DRM_ROTATE_270))) 2797c11e9283SDamien Lespiau swap(hdisplay, vdisplay); 2798c11e9283SDamien Lespiau 2799ce8d9eccSVille Syrjälä return check_src_coords(x << 16, y << 16, 2800ce8d9eccSVille Syrjälä hdisplay << 16, vdisplay << 16, fb); 2801c11e9283SDamien Lespiau } 2802af93629dSMatt Roper EXPORT_SYMBOL(drm_crtc_check_viewport); 2803c11e9283SDamien Lespiau 28042d13b679SDaniel Vetter /** 2805f453ba04SDave Airlie * drm_mode_setcrtc - set CRTC configuration 2806065a50edSDaniel Vetter * @dev: drm device for the ioctl 2807065a50edSDaniel Vetter * @data: data pointer for the ioctl 2808065a50edSDaniel Vetter * @file_priv: drm file for the ioctl call 2809f453ba04SDave Airlie * 2810f453ba04SDave Airlie * Build a new CRTC configuration based on user request. 2811f453ba04SDave Airlie * 2812f453ba04SDave Airlie * Called by the user via ioctl. 2813f453ba04SDave Airlie * 2814c8e32cc1SDaniel Vetter * Returns: 28151a498633SDaniel Vetter * Zero on success, negative errno on failure. 2816f453ba04SDave Airlie */ 2817f453ba04SDave Airlie int drm_mode_setcrtc(struct drm_device *dev, void *data, 2818f453ba04SDave Airlie struct drm_file *file_priv) 2819f453ba04SDave Airlie { 2820f453ba04SDave Airlie struct drm_mode_config *config = &dev->mode_config; 2821f453ba04SDave Airlie struct drm_mode_crtc *crtc_req = data; 28226653cc8dSVille Syrjälä struct drm_crtc *crtc; 2823f453ba04SDave Airlie struct drm_connector **connector_set = NULL, *connector; 2824f453ba04SDave Airlie struct drm_framebuffer *fb = NULL; 2825f453ba04SDave Airlie struct drm_display_mode *mode = NULL; 2826f453ba04SDave Airlie struct drm_mode_set set; 2827f453ba04SDave Airlie uint32_t __user *set_connectors_ptr; 28284a1b0714SLaurent Pinchart int ret; 2829f453ba04SDave Airlie int i; 2830f453ba04SDave Airlie 2831fb3b06c8SDave Airlie if (!drm_core_check_feature(dev, DRIVER_MODESET)) 2832fb3b06c8SDave Airlie return -EINVAL; 2833fb3b06c8SDave Airlie 283401447e9fSZhao Junwang /* 283501447e9fSZhao Junwang * Universal plane src offsets are only 16.16, prevent havoc for 283601447e9fSZhao Junwang * drivers using universal plane code internally. 283701447e9fSZhao Junwang */ 283801447e9fSZhao Junwang if (crtc_req->x & 0xffff0000 || crtc_req->y & 0xffff0000) 28391d97e915SVille Syrjälä return -ERANGE; 28401d97e915SVille Syrjälä 284184849903SDaniel Vetter drm_modeset_lock_all(dev); 2842a2b34e22SRob Clark crtc = drm_crtc_find(dev, crtc_req->crtc_id); 2843a2b34e22SRob Clark if (!crtc) { 284458367ed6SZhao Yakui DRM_DEBUG_KMS("Unknown CRTC ID %d\n", crtc_req->crtc_id); 2845f27657f2SVille Syrjälä ret = -ENOENT; 2846f453ba04SDave Airlie goto out; 2847f453ba04SDave Airlie } 2848fa3ab4c2SVille Syrjälä DRM_DEBUG_KMS("[CRTC:%d:%s]\n", crtc->base.id, crtc->name); 2849f453ba04SDave Airlie 2850f453ba04SDave Airlie if (crtc_req->mode_valid) { 2851f453ba04SDave Airlie /* If we have a mode we need a framebuffer. */ 2852f453ba04SDave Airlie /* If we pass -1, set the mode with the currently bound fb */ 2853f453ba04SDave Airlie if (crtc_req->fb_id == -1) { 2854f4510a27SMatt Roper if (!crtc->primary->fb) { 28556653cc8dSVille Syrjälä DRM_DEBUG_KMS("CRTC doesn't have current FB\n"); 28566653cc8dSVille Syrjälä ret = -EINVAL; 28576653cc8dSVille Syrjälä goto out; 28586653cc8dSVille Syrjälä } 2859f4510a27SMatt Roper fb = crtc->primary->fb; 2860b0d12325SDaniel Vetter /* Make refcounting symmetric with the lookup path. */ 2861b0d12325SDaniel Vetter drm_framebuffer_reference(fb); 2862f453ba04SDave Airlie } else { 2863786b99edSDaniel Vetter fb = drm_framebuffer_lookup(dev, crtc_req->fb_id); 2864786b99edSDaniel Vetter if (!fb) { 286558367ed6SZhao Yakui DRM_DEBUG_KMS("Unknown FB ID%d\n", 286658367ed6SZhao Yakui crtc_req->fb_id); 286737c4e705SVille Syrjälä ret = -ENOENT; 2868f453ba04SDave Airlie goto out; 2869f453ba04SDave Airlie } 2870f453ba04SDave Airlie } 2871f453ba04SDave Airlie 2872f453ba04SDave Airlie mode = drm_mode_create(dev); 2873ee34ab5bSVille Syrjälä if (!mode) { 2874ee34ab5bSVille Syrjälä ret = -ENOMEM; 2875ee34ab5bSVille Syrjälä goto out; 2876ee34ab5bSVille Syrjälä } 2877ee34ab5bSVille Syrjälä 2878934a8a89SDaniel Stone ret = drm_mode_convert_umode(mode, &crtc_req->mode); 287990367bf6SVille Syrjälä if (ret) { 288090367bf6SVille Syrjälä DRM_DEBUG_KMS("Invalid mode\n"); 288190367bf6SVille Syrjälä goto out; 288290367bf6SVille Syrjälä } 288390367bf6SVille Syrjälä 28847eb5f302SLaurent Pinchart /* 28857eb5f302SLaurent Pinchart * Check whether the primary plane supports the fb pixel format. 28867eb5f302SLaurent Pinchart * Drivers not implementing the universal planes API use a 28877eb5f302SLaurent Pinchart * default formats list provided by the DRM core which doesn't 28887eb5f302SLaurent Pinchart * match real hardware capabilities. Skip the check in that 28897eb5f302SLaurent Pinchart * case. 28907eb5f302SLaurent Pinchart */ 28917eb5f302SLaurent Pinchart if (!crtc->primary->format_default) { 28927eb5f302SLaurent Pinchart ret = drm_plane_check_pixel_format(crtc->primary, 28937eb5f302SLaurent Pinchart fb->pixel_format); 28947eb5f302SLaurent Pinchart if (ret) { 28957eb5f302SLaurent Pinchart DRM_DEBUG_KMS("Invalid pixel format %s\n", 28967eb5f302SLaurent Pinchart drm_get_format_name(fb->pixel_format)); 28977eb5f302SLaurent Pinchart goto out; 28987eb5f302SLaurent Pinchart } 28997eb5f302SLaurent Pinchart } 29007eb5f302SLaurent Pinchart 2901c11e9283SDamien Lespiau ret = drm_crtc_check_viewport(crtc, crtc_req->x, crtc_req->y, 2902c11e9283SDamien Lespiau mode, fb); 2903c11e9283SDamien Lespiau if (ret) 29045f61bb42SVille Syrjälä goto out; 2905c11e9283SDamien Lespiau 2906f453ba04SDave Airlie } 2907f453ba04SDave Airlie 2908f453ba04SDave Airlie if (crtc_req->count_connectors == 0 && mode) { 290958367ed6SZhao Yakui DRM_DEBUG_KMS("Count connectors is 0 but mode set\n"); 2910f453ba04SDave Airlie ret = -EINVAL; 2911f453ba04SDave Airlie goto out; 2912f453ba04SDave Airlie } 2913f453ba04SDave Airlie 29147781de74SJakob Bornecrantz if (crtc_req->count_connectors > 0 && (!mode || !fb)) { 291558367ed6SZhao Yakui DRM_DEBUG_KMS("Count connectors is %d but no mode or fb set\n", 2916f453ba04SDave Airlie crtc_req->count_connectors); 2917f453ba04SDave Airlie ret = -EINVAL; 2918f453ba04SDave Airlie goto out; 2919f453ba04SDave Airlie } 2920f453ba04SDave Airlie 2921f453ba04SDave Airlie if (crtc_req->count_connectors > 0) { 2922f453ba04SDave Airlie u32 out_id; 2923f453ba04SDave Airlie 2924f453ba04SDave Airlie /* Avoid unbounded kernel memory allocation */ 2925f453ba04SDave Airlie if (crtc_req->count_connectors > config->num_connector) { 2926f453ba04SDave Airlie ret = -EINVAL; 2927f453ba04SDave Airlie goto out; 2928f453ba04SDave Airlie } 2929f453ba04SDave Airlie 29302f6c5389SThierry Reding connector_set = kmalloc_array(crtc_req->count_connectors, 2931f453ba04SDave Airlie sizeof(struct drm_connector *), 2932f453ba04SDave Airlie GFP_KERNEL); 2933f453ba04SDave Airlie if (!connector_set) { 2934f453ba04SDave Airlie ret = -ENOMEM; 2935f453ba04SDave Airlie goto out; 2936f453ba04SDave Airlie } 2937f453ba04SDave Airlie 2938f453ba04SDave Airlie for (i = 0; i < crtc_req->count_connectors; i++) { 2939b164d31fSDave Airlie connector_set[i] = NULL; 294081f6c7f8SVille Syrjälä set_connectors_ptr = (uint32_t __user *)(unsigned long)crtc_req->set_connectors_ptr; 2941f453ba04SDave Airlie if (get_user(out_id, &set_connectors_ptr[i])) { 2942f453ba04SDave Airlie ret = -EFAULT; 2943f453ba04SDave Airlie goto out; 2944f453ba04SDave Airlie } 2945f453ba04SDave Airlie 2946b164d31fSDave Airlie connector = drm_connector_lookup(dev, out_id); 2947a2b34e22SRob Clark if (!connector) { 294858367ed6SZhao Yakui DRM_DEBUG_KMS("Connector id %d unknown\n", 294958367ed6SZhao Yakui out_id); 2950f27657f2SVille Syrjälä ret = -ENOENT; 2951f453ba04SDave Airlie goto out; 2952f453ba04SDave Airlie } 29539440106bSJerome Glisse DRM_DEBUG_KMS("[CONNECTOR:%d:%s]\n", 29549440106bSJerome Glisse connector->base.id, 295525933820SJani Nikula connector->name); 2956f453ba04SDave Airlie 2957f453ba04SDave Airlie connector_set[i] = connector; 2958f453ba04SDave Airlie } 2959f453ba04SDave Airlie } 2960f453ba04SDave Airlie 2961f453ba04SDave Airlie set.crtc = crtc; 2962f453ba04SDave Airlie set.x = crtc_req->x; 2963f453ba04SDave Airlie set.y = crtc_req->y; 2964f453ba04SDave Airlie set.mode = mode; 2965f453ba04SDave Airlie set.connectors = connector_set; 2966f453ba04SDave Airlie set.num_connectors = crtc_req->count_connectors; 2967f453ba04SDave Airlie set.fb = fb; 29682d13b679SDaniel Vetter ret = drm_mode_set_config_internal(&set); 2969f453ba04SDave Airlie 2970f453ba04SDave Airlie out: 2971b0d12325SDaniel Vetter if (fb) 2972b0d12325SDaniel Vetter drm_framebuffer_unreference(fb); 2973b0d12325SDaniel Vetter 2974b164d31fSDave Airlie if (connector_set) { 2975b164d31fSDave Airlie for (i = 0; i < crtc_req->count_connectors; i++) { 2976b164d31fSDave Airlie if (connector_set[i]) 2977b164d31fSDave Airlie drm_connector_unreference(connector_set[i]); 2978b164d31fSDave Airlie } 2979b164d31fSDave Airlie } 2980f453ba04SDave Airlie kfree(connector_set); 2981ee34ab5bSVille Syrjälä drm_mode_destroy(dev, mode); 298284849903SDaniel Vetter drm_modeset_unlock_all(dev); 2983f453ba04SDave Airlie return ret; 2984f453ba04SDave Airlie } 2985f453ba04SDave Airlie 2986161d0dc1SMatt Roper /** 2987161d0dc1SMatt Roper * drm_mode_cursor_universal - translate legacy cursor ioctl call into a 2988161d0dc1SMatt Roper * universal plane handler call 2989161d0dc1SMatt Roper * @crtc: crtc to update cursor for 2990161d0dc1SMatt Roper * @req: data pointer for the ioctl 2991161d0dc1SMatt Roper * @file_priv: drm file for the ioctl call 2992161d0dc1SMatt Roper * 2993161d0dc1SMatt Roper * Legacy cursor ioctl's work directly with driver buffer handles. To 2994161d0dc1SMatt Roper * translate legacy ioctl calls into universal plane handler calls, we need to 2995161d0dc1SMatt Roper * wrap the native buffer handle in a drm_framebuffer. 2996161d0dc1SMatt Roper * 2997161d0dc1SMatt Roper * Note that we assume any handle passed to the legacy ioctls was a 32-bit ARGB 2998161d0dc1SMatt Roper * buffer with a pitch of 4*width; the universal plane interface should be used 2999161d0dc1SMatt Roper * directly in cases where the hardware can support other buffer settings and 3000161d0dc1SMatt Roper * userspace wants to make use of these capabilities. 3001161d0dc1SMatt Roper * 3002161d0dc1SMatt Roper * Returns: 30031a498633SDaniel Vetter * Zero on success, negative errno on failure. 3004161d0dc1SMatt Roper */ 3005161d0dc1SMatt Roper static int drm_mode_cursor_universal(struct drm_crtc *crtc, 3006161d0dc1SMatt Roper struct drm_mode_cursor2 *req, 3007161d0dc1SMatt Roper struct drm_file *file_priv) 3008161d0dc1SMatt Roper { 3009161d0dc1SMatt Roper struct drm_device *dev = crtc->dev; 3010161d0dc1SMatt Roper struct drm_framebuffer *fb = NULL; 3011161d0dc1SMatt Roper struct drm_mode_fb_cmd2 fbreq = { 3012161d0dc1SMatt Roper .width = req->width, 3013161d0dc1SMatt Roper .height = req->height, 3014161d0dc1SMatt Roper .pixel_format = DRM_FORMAT_ARGB8888, 3015161d0dc1SMatt Roper .pitches = { req->width * 4 }, 3016161d0dc1SMatt Roper .handles = { req->handle }, 3017161d0dc1SMatt Roper }; 3018161d0dc1SMatt Roper int32_t crtc_x, crtc_y; 3019161d0dc1SMatt Roper uint32_t crtc_w = 0, crtc_h = 0; 3020161d0dc1SMatt Roper uint32_t src_w = 0, src_h = 0; 3021161d0dc1SMatt Roper int ret = 0; 3022161d0dc1SMatt Roper 3023161d0dc1SMatt Roper BUG_ON(!crtc->cursor); 3024f2b50c11SDaniel Vetter WARN_ON(crtc->cursor->crtc != crtc && crtc->cursor->crtc != NULL); 3025161d0dc1SMatt Roper 3026161d0dc1SMatt Roper /* 3027161d0dc1SMatt Roper * Obtain fb we'll be using (either new or existing) and take an extra 3028161d0dc1SMatt Roper * reference to it if fb != null. setplane will take care of dropping 3029161d0dc1SMatt Roper * the reference if the plane update fails. 3030161d0dc1SMatt Roper */ 3031161d0dc1SMatt Roper if (req->flags & DRM_MODE_CURSOR_BO) { 3032161d0dc1SMatt Roper if (req->handle) { 30339a6f5130SChris Wilson fb = internal_framebuffer_create(dev, &fbreq, file_priv); 3034161d0dc1SMatt Roper if (IS_ERR(fb)) { 3035161d0dc1SMatt Roper DRM_DEBUG_KMS("failed to wrap cursor buffer in drm framebuffer\n"); 3036161d0dc1SMatt Roper return PTR_ERR(fb); 3037161d0dc1SMatt Roper } 3038dd546591SGerd Hoffmann fb->hot_x = req->hot_x; 3039dd546591SGerd Hoffmann fb->hot_y = req->hot_y; 3040161d0dc1SMatt Roper } else { 3041161d0dc1SMatt Roper fb = NULL; 3042161d0dc1SMatt Roper } 3043161d0dc1SMatt Roper } else { 3044161d0dc1SMatt Roper fb = crtc->cursor->fb; 3045161d0dc1SMatt Roper if (fb) 3046161d0dc1SMatt Roper drm_framebuffer_reference(fb); 3047161d0dc1SMatt Roper } 3048161d0dc1SMatt Roper 3049161d0dc1SMatt Roper if (req->flags & DRM_MODE_CURSOR_MOVE) { 3050161d0dc1SMatt Roper crtc_x = req->x; 3051161d0dc1SMatt Roper crtc_y = req->y; 3052161d0dc1SMatt Roper } else { 3053161d0dc1SMatt Roper crtc_x = crtc->cursor_x; 3054161d0dc1SMatt Roper crtc_y = crtc->cursor_y; 3055161d0dc1SMatt Roper } 3056161d0dc1SMatt Roper 3057161d0dc1SMatt Roper if (fb) { 3058161d0dc1SMatt Roper crtc_w = fb->width; 3059161d0dc1SMatt Roper crtc_h = fb->height; 3060161d0dc1SMatt Roper src_w = fb->width << 16; 3061161d0dc1SMatt Roper src_h = fb->height << 16; 3062161d0dc1SMatt Roper } 3063161d0dc1SMatt Roper 3064161d0dc1SMatt Roper /* 3065161d0dc1SMatt Roper * setplane_internal will take care of deref'ing either the old or new 3066161d0dc1SMatt Roper * framebuffer depending on success. 3067161d0dc1SMatt Roper */ 3068f2b50c11SDaniel Vetter ret = __setplane_internal(crtc->cursor, crtc, fb, 3069161d0dc1SMatt Roper crtc_x, crtc_y, crtc_w, crtc_h, 3070161d0dc1SMatt Roper 0, 0, src_w, src_h); 3071161d0dc1SMatt Roper 3072161d0dc1SMatt Roper /* Update successful; save new cursor position, if necessary */ 3073161d0dc1SMatt Roper if (ret == 0 && req->flags & DRM_MODE_CURSOR_MOVE) { 3074161d0dc1SMatt Roper crtc->cursor_x = req->x; 3075161d0dc1SMatt Roper crtc->cursor_y = req->y; 3076161d0dc1SMatt Roper } 3077161d0dc1SMatt Roper 3078161d0dc1SMatt Roper return ret; 3079161d0dc1SMatt Roper } 3080161d0dc1SMatt Roper 30814c813d4dSDave Airlie static int drm_mode_cursor_common(struct drm_device *dev, 30824c813d4dSDave Airlie struct drm_mode_cursor2 *req, 30834c813d4dSDave Airlie struct drm_file *file_priv) 3084f453ba04SDave Airlie { 3085f453ba04SDave Airlie struct drm_crtc *crtc; 3086f453ba04SDave Airlie int ret = 0; 3087f453ba04SDave Airlie 3088fb3b06c8SDave Airlie if (!drm_core_check_feature(dev, DRIVER_MODESET)) 3089fb3b06c8SDave Airlie return -EINVAL; 3090fb3b06c8SDave Airlie 30917c4eaca4SJakob Bornecrantz if (!req->flags || (~DRM_MODE_CURSOR_FLAGS & req->flags)) 3092f453ba04SDave Airlie return -EINVAL; 3093f453ba04SDave Airlie 3094a2b34e22SRob Clark crtc = drm_crtc_find(dev, req->crtc_id); 3095a2b34e22SRob Clark if (!crtc) { 309658367ed6SZhao Yakui DRM_DEBUG_KMS("Unknown CRTC ID %d\n", req->crtc_id); 3097f27657f2SVille Syrjälä return -ENOENT; 3098f453ba04SDave Airlie } 3099f453ba04SDave Airlie 3100161d0dc1SMatt Roper /* 3101161d0dc1SMatt Roper * If this crtc has a universal cursor plane, call that plane's update 3102161d0dc1SMatt Roper * handler rather than using legacy cursor handlers. 3103161d0dc1SMatt Roper */ 31044d02e2deSDaniel Vetter drm_modeset_lock_crtc(crtc, crtc->cursor); 3105f2b50c11SDaniel Vetter if (crtc->cursor) { 3106f2b50c11SDaniel Vetter ret = drm_mode_cursor_universal(crtc, req, file_priv); 3107f2b50c11SDaniel Vetter goto out; 3108f2b50c11SDaniel Vetter } 3109f2b50c11SDaniel Vetter 3110f453ba04SDave Airlie if (req->flags & DRM_MODE_CURSOR_BO) { 31114c813d4dSDave Airlie if (!crtc->funcs->cursor_set && !crtc->funcs->cursor_set2) { 3112f453ba04SDave Airlie ret = -ENXIO; 3113f453ba04SDave Airlie goto out; 3114f453ba04SDave Airlie } 3115f453ba04SDave Airlie /* Turns off the cursor if handle is 0 */ 31164c813d4dSDave Airlie if (crtc->funcs->cursor_set2) 31174c813d4dSDave Airlie ret = crtc->funcs->cursor_set2(crtc, file_priv, req->handle, 31184c813d4dSDave Airlie req->width, req->height, req->hot_x, req->hot_y); 31194c813d4dSDave Airlie else 3120f453ba04SDave Airlie ret = crtc->funcs->cursor_set(crtc, file_priv, req->handle, 3121f453ba04SDave Airlie req->width, req->height); 3122f453ba04SDave Airlie } 3123f453ba04SDave Airlie 3124f453ba04SDave Airlie if (req->flags & DRM_MODE_CURSOR_MOVE) { 3125f453ba04SDave Airlie if (crtc->funcs->cursor_move) { 3126f453ba04SDave Airlie ret = crtc->funcs->cursor_move(crtc, req->x, req->y); 3127f453ba04SDave Airlie } else { 3128f453ba04SDave Airlie ret = -EFAULT; 3129f453ba04SDave Airlie goto out; 3130f453ba04SDave Airlie } 3131f453ba04SDave Airlie } 3132f453ba04SDave Airlie out: 3133d059f652SDaniel Vetter drm_modeset_unlock_crtc(crtc); 3134dac35663SDaniel Vetter 3135f453ba04SDave Airlie return ret; 31364c813d4dSDave Airlie 31374c813d4dSDave Airlie } 3138c8e32cc1SDaniel Vetter 3139c8e32cc1SDaniel Vetter 3140c8e32cc1SDaniel Vetter /** 3141c8e32cc1SDaniel Vetter * drm_mode_cursor_ioctl - set CRTC's cursor configuration 3142c8e32cc1SDaniel Vetter * @dev: drm device for the ioctl 3143c8e32cc1SDaniel Vetter * @data: data pointer for the ioctl 3144c8e32cc1SDaniel Vetter * @file_priv: drm file for the ioctl call 3145c8e32cc1SDaniel Vetter * 3146c8e32cc1SDaniel Vetter * Set the cursor configuration based on user request. 3147c8e32cc1SDaniel Vetter * 3148c8e32cc1SDaniel Vetter * Called by the user via ioctl. 3149c8e32cc1SDaniel Vetter * 3150c8e32cc1SDaniel Vetter * Returns: 31511a498633SDaniel Vetter * Zero on success, negative errno on failure. 3152c8e32cc1SDaniel Vetter */ 31534c813d4dSDave Airlie int drm_mode_cursor_ioctl(struct drm_device *dev, 31544c813d4dSDave Airlie void *data, struct drm_file *file_priv) 31554c813d4dSDave Airlie { 31564c813d4dSDave Airlie struct drm_mode_cursor *req = data; 31574c813d4dSDave Airlie struct drm_mode_cursor2 new_req; 31584c813d4dSDave Airlie 31594c813d4dSDave Airlie memcpy(&new_req, req, sizeof(struct drm_mode_cursor)); 31604c813d4dSDave Airlie new_req.hot_x = new_req.hot_y = 0; 31614c813d4dSDave Airlie 31624c813d4dSDave Airlie return drm_mode_cursor_common(dev, &new_req, file_priv); 31634c813d4dSDave Airlie } 31644c813d4dSDave Airlie 3165c8e32cc1SDaniel Vetter /** 3166c8e32cc1SDaniel Vetter * drm_mode_cursor2_ioctl - set CRTC's cursor configuration 3167c8e32cc1SDaniel Vetter * @dev: drm device for the ioctl 3168c8e32cc1SDaniel Vetter * @data: data pointer for the ioctl 3169c8e32cc1SDaniel Vetter * @file_priv: drm file for the ioctl call 3170c8e32cc1SDaniel Vetter * 3171c8e32cc1SDaniel Vetter * Set the cursor configuration based on user request. This implements the 2nd 3172c8e32cc1SDaniel Vetter * version of the cursor ioctl, which allows userspace to additionally specify 3173c8e32cc1SDaniel Vetter * the hotspot of the pointer. 3174c8e32cc1SDaniel Vetter * 3175c8e32cc1SDaniel Vetter * Called by the user via ioctl. 3176c8e32cc1SDaniel Vetter * 3177c8e32cc1SDaniel Vetter * Returns: 31781a498633SDaniel Vetter * Zero on success, negative errno on failure. 3179c8e32cc1SDaniel Vetter */ 31804c813d4dSDave Airlie int drm_mode_cursor2_ioctl(struct drm_device *dev, 31814c813d4dSDave Airlie void *data, struct drm_file *file_priv) 31824c813d4dSDave Airlie { 31834c813d4dSDave Airlie struct drm_mode_cursor2 *req = data; 31844dfd909fSThierry Reding 31854c813d4dSDave Airlie return drm_mode_cursor_common(dev, req, file_priv); 3186f453ba04SDave Airlie } 3187f453ba04SDave Airlie 3188c8e32cc1SDaniel Vetter /** 3189c8e32cc1SDaniel Vetter * drm_mode_legacy_fb_format - compute drm fourcc code from legacy description 3190c8e32cc1SDaniel Vetter * @bpp: bits per pixels 3191c8e32cc1SDaniel Vetter * @depth: bit depth per pixel 3192c8e32cc1SDaniel Vetter * 3193c8e32cc1SDaniel Vetter * Computes a drm fourcc pixel format code for the given @bpp/@depth values. 3194c8e32cc1SDaniel Vetter * Useful in fbdev emulation code, since that deals in those values. 3195c8e32cc1SDaniel Vetter */ 3196308e5bcbSJesse Barnes uint32_t drm_mode_legacy_fb_format(uint32_t bpp, uint32_t depth) 3197308e5bcbSJesse Barnes { 3198308e5bcbSJesse Barnes uint32_t fmt; 3199308e5bcbSJesse Barnes 3200308e5bcbSJesse Barnes switch (bpp) { 3201308e5bcbSJesse Barnes case 8: 3202d84f031bSVille Syrjälä fmt = DRM_FORMAT_C8; 3203308e5bcbSJesse Barnes break; 3204308e5bcbSJesse Barnes case 16: 3205308e5bcbSJesse Barnes if (depth == 15) 320604b3924dSVille Syrjälä fmt = DRM_FORMAT_XRGB1555; 3207308e5bcbSJesse Barnes else 320804b3924dSVille Syrjälä fmt = DRM_FORMAT_RGB565; 3209308e5bcbSJesse Barnes break; 3210308e5bcbSJesse Barnes case 24: 321104b3924dSVille Syrjälä fmt = DRM_FORMAT_RGB888; 3212308e5bcbSJesse Barnes break; 3213308e5bcbSJesse Barnes case 32: 3214308e5bcbSJesse Barnes if (depth == 24) 321504b3924dSVille Syrjälä fmt = DRM_FORMAT_XRGB8888; 3216308e5bcbSJesse Barnes else if (depth == 30) 321704b3924dSVille Syrjälä fmt = DRM_FORMAT_XRGB2101010; 3218308e5bcbSJesse Barnes else 321904b3924dSVille Syrjälä fmt = DRM_FORMAT_ARGB8888; 3220308e5bcbSJesse Barnes break; 3221308e5bcbSJesse Barnes default: 322204b3924dSVille Syrjälä DRM_ERROR("bad bpp, assuming x8r8g8b8 pixel format\n"); 322304b3924dSVille Syrjälä fmt = DRM_FORMAT_XRGB8888; 3224308e5bcbSJesse Barnes break; 3225308e5bcbSJesse Barnes } 3226308e5bcbSJesse Barnes 3227308e5bcbSJesse Barnes return fmt; 3228308e5bcbSJesse Barnes } 3229308e5bcbSJesse Barnes EXPORT_SYMBOL(drm_mode_legacy_fb_format); 3230308e5bcbSJesse Barnes 3231f453ba04SDave Airlie /** 3232f453ba04SDave Airlie * drm_mode_addfb - add an FB to the graphics configuration 3233065a50edSDaniel Vetter * @dev: drm device for the ioctl 3234065a50edSDaniel Vetter * @data: data pointer for the ioctl 3235065a50edSDaniel Vetter * @file_priv: drm file for the ioctl call 3236f453ba04SDave Airlie * 3237c8e32cc1SDaniel Vetter * Add a new FB to the specified CRTC, given a user request. This is the 3238209f5527SChuck Ebbert * original addfb ioctl which only supported RGB formats. 3239f453ba04SDave Airlie * 3240f453ba04SDave Airlie * Called by the user via ioctl. 3241f453ba04SDave Airlie * 3242c8e32cc1SDaniel Vetter * Returns: 32431a498633SDaniel Vetter * Zero on success, negative errno on failure. 3244f453ba04SDave Airlie */ 3245f453ba04SDave Airlie int drm_mode_addfb(struct drm_device *dev, 3246f453ba04SDave Airlie void *data, struct drm_file *file_priv) 3247f453ba04SDave Airlie { 3248308e5bcbSJesse Barnes struct drm_mode_fb_cmd *or = data; 3249308e5bcbSJesse Barnes struct drm_mode_fb_cmd2 r = {}; 3250228f2cb3SChuck Ebbert int ret; 3251308e5bcbSJesse Barnes 3252228f2cb3SChuck Ebbert /* convert to new format and call new ioctl */ 3253308e5bcbSJesse Barnes r.fb_id = or->fb_id; 3254308e5bcbSJesse Barnes r.width = or->width; 3255308e5bcbSJesse Barnes r.height = or->height; 3256308e5bcbSJesse Barnes r.pitches[0] = or->pitch; 3257308e5bcbSJesse Barnes r.pixel_format = drm_mode_legacy_fb_format(or->bpp, or->depth); 3258308e5bcbSJesse Barnes r.handles[0] = or->handle; 3259308e5bcbSJesse Barnes 3260228f2cb3SChuck Ebbert ret = drm_mode_addfb2(dev, &r, file_priv); 3261228f2cb3SChuck Ebbert if (ret) 3262228f2cb3SChuck Ebbert return ret; 3263308e5bcbSJesse Barnes 3264228f2cb3SChuck Ebbert or->fb_id = r.fb_id; 32654b096ac1SDaniel Vetter 3266baf698b0SDaniel Vetter return 0; 3267308e5bcbSJesse Barnes } 3268308e5bcbSJesse Barnes 3269cff91b62SVille Syrjälä static int format_check(const struct drm_mode_fb_cmd2 *r) 3270935b5977SVille Syrjälä { 3271935b5977SVille Syrjälä uint32_t format = r->pixel_format & ~DRM_FORMAT_BIG_ENDIAN; 3272935b5977SVille Syrjälä 3273935b5977SVille Syrjälä switch (format) { 3274935b5977SVille Syrjälä case DRM_FORMAT_C8: 3275935b5977SVille Syrjälä case DRM_FORMAT_RGB332: 3276935b5977SVille Syrjälä case DRM_FORMAT_BGR233: 3277935b5977SVille Syrjälä case DRM_FORMAT_XRGB4444: 3278935b5977SVille Syrjälä case DRM_FORMAT_XBGR4444: 3279935b5977SVille Syrjälä case DRM_FORMAT_RGBX4444: 3280935b5977SVille Syrjälä case DRM_FORMAT_BGRX4444: 3281935b5977SVille Syrjälä case DRM_FORMAT_ARGB4444: 3282935b5977SVille Syrjälä case DRM_FORMAT_ABGR4444: 3283935b5977SVille Syrjälä case DRM_FORMAT_RGBA4444: 3284935b5977SVille Syrjälä case DRM_FORMAT_BGRA4444: 3285935b5977SVille Syrjälä case DRM_FORMAT_XRGB1555: 3286935b5977SVille Syrjälä case DRM_FORMAT_XBGR1555: 3287935b5977SVille Syrjälä case DRM_FORMAT_RGBX5551: 3288935b5977SVille Syrjälä case DRM_FORMAT_BGRX5551: 3289935b5977SVille Syrjälä case DRM_FORMAT_ARGB1555: 3290935b5977SVille Syrjälä case DRM_FORMAT_ABGR1555: 3291935b5977SVille Syrjälä case DRM_FORMAT_RGBA5551: 3292935b5977SVille Syrjälä case DRM_FORMAT_BGRA5551: 3293935b5977SVille Syrjälä case DRM_FORMAT_RGB565: 3294935b5977SVille Syrjälä case DRM_FORMAT_BGR565: 3295935b5977SVille Syrjälä case DRM_FORMAT_RGB888: 3296935b5977SVille Syrjälä case DRM_FORMAT_BGR888: 3297935b5977SVille Syrjälä case DRM_FORMAT_XRGB8888: 3298935b5977SVille Syrjälä case DRM_FORMAT_XBGR8888: 3299935b5977SVille Syrjälä case DRM_FORMAT_RGBX8888: 3300935b5977SVille Syrjälä case DRM_FORMAT_BGRX8888: 3301935b5977SVille Syrjälä case DRM_FORMAT_ARGB8888: 3302935b5977SVille Syrjälä case DRM_FORMAT_ABGR8888: 3303935b5977SVille Syrjälä case DRM_FORMAT_RGBA8888: 3304935b5977SVille Syrjälä case DRM_FORMAT_BGRA8888: 3305935b5977SVille Syrjälä case DRM_FORMAT_XRGB2101010: 3306935b5977SVille Syrjälä case DRM_FORMAT_XBGR2101010: 3307935b5977SVille Syrjälä case DRM_FORMAT_RGBX1010102: 3308935b5977SVille Syrjälä case DRM_FORMAT_BGRX1010102: 3309935b5977SVille Syrjälä case DRM_FORMAT_ARGB2101010: 3310935b5977SVille Syrjälä case DRM_FORMAT_ABGR2101010: 3311935b5977SVille Syrjälä case DRM_FORMAT_RGBA1010102: 3312935b5977SVille Syrjälä case DRM_FORMAT_BGRA1010102: 3313935b5977SVille Syrjälä case DRM_FORMAT_YUYV: 3314935b5977SVille Syrjälä case DRM_FORMAT_YVYU: 3315935b5977SVille Syrjälä case DRM_FORMAT_UYVY: 3316935b5977SVille Syrjälä case DRM_FORMAT_VYUY: 3317935b5977SVille Syrjälä case DRM_FORMAT_AYUV: 3318935b5977SVille Syrjälä case DRM_FORMAT_NV12: 3319935b5977SVille Syrjälä case DRM_FORMAT_NV21: 3320935b5977SVille Syrjälä case DRM_FORMAT_NV16: 3321935b5977SVille Syrjälä case DRM_FORMAT_NV61: 3322ba623f6aSLaurent Pinchart case DRM_FORMAT_NV24: 3323ba623f6aSLaurent Pinchart case DRM_FORMAT_NV42: 3324935b5977SVille Syrjälä case DRM_FORMAT_YUV410: 3325935b5977SVille Syrjälä case DRM_FORMAT_YVU410: 3326935b5977SVille Syrjälä case DRM_FORMAT_YUV411: 3327935b5977SVille Syrjälä case DRM_FORMAT_YVU411: 3328935b5977SVille Syrjälä case DRM_FORMAT_YUV420: 3329935b5977SVille Syrjälä case DRM_FORMAT_YVU420: 3330935b5977SVille Syrjälä case DRM_FORMAT_YUV422: 3331935b5977SVille Syrjälä case DRM_FORMAT_YVU422: 3332935b5977SVille Syrjälä case DRM_FORMAT_YUV444: 3333935b5977SVille Syrjälä case DRM_FORMAT_YVU444: 3334935b5977SVille Syrjälä return 0; 3335935b5977SVille Syrjälä default: 333623c453a4SVille Syrjälä DRM_DEBUG_KMS("invalid pixel format %s\n", 333723c453a4SVille Syrjälä drm_get_format_name(r->pixel_format)); 3338935b5977SVille Syrjälä return -EINVAL; 3339935b5977SVille Syrjälä } 3340935b5977SVille Syrjälä } 3341935b5977SVille Syrjälä 3342cff91b62SVille Syrjälä static int framebuffer_check(const struct drm_mode_fb_cmd2 *r) 3343d1b45d5fSVille Syrjälä { 3344d1b45d5fSVille Syrjälä int ret, hsub, vsub, num_planes, i; 3345d1b45d5fSVille Syrjälä 3346d1b45d5fSVille Syrjälä ret = format_check(r); 3347d1b45d5fSVille Syrjälä if (ret) { 33486ba6d03eSVille Syrjälä DRM_DEBUG_KMS("bad framebuffer format %s\n", 33496ba6d03eSVille Syrjälä drm_get_format_name(r->pixel_format)); 3350d1b45d5fSVille Syrjälä return ret; 3351d1b45d5fSVille Syrjälä } 3352d1b45d5fSVille Syrjälä 3353d1b45d5fSVille Syrjälä hsub = drm_format_horz_chroma_subsampling(r->pixel_format); 3354d1b45d5fSVille Syrjälä vsub = drm_format_vert_chroma_subsampling(r->pixel_format); 3355d1b45d5fSVille Syrjälä num_planes = drm_format_num_planes(r->pixel_format); 3356d1b45d5fSVille Syrjälä 3357d1b45d5fSVille Syrjälä if (r->width == 0 || r->width % hsub) { 3358209f5527SChuck Ebbert DRM_DEBUG_KMS("bad framebuffer width %u\n", r->width); 3359d1b45d5fSVille Syrjälä return -EINVAL; 3360d1b45d5fSVille Syrjälä } 3361d1b45d5fSVille Syrjälä 3362d1b45d5fSVille Syrjälä if (r->height == 0 || r->height % vsub) { 33631aa1b11cSDave Airlie DRM_DEBUG_KMS("bad framebuffer height %u\n", r->height); 3364d1b45d5fSVille Syrjälä return -EINVAL; 3365d1b45d5fSVille Syrjälä } 3366d1b45d5fSVille Syrjälä 3367d1b45d5fSVille Syrjälä for (i = 0; i < num_planes; i++) { 3368d1b45d5fSVille Syrjälä unsigned int width = r->width / (i != 0 ? hsub : 1); 3369b180b5d1SVille Syrjälä unsigned int height = r->height / (i != 0 ? vsub : 1); 3370b180b5d1SVille Syrjälä unsigned int cpp = drm_format_plane_cpp(r->pixel_format, i); 3371d1b45d5fSVille Syrjälä 3372d1b45d5fSVille Syrjälä if (!r->handles[i]) { 33731aa1b11cSDave Airlie DRM_DEBUG_KMS("no buffer object handle for plane %d\n", i); 3374d1b45d5fSVille Syrjälä return -EINVAL; 3375d1b45d5fSVille Syrjälä } 3376d1b45d5fSVille Syrjälä 3377b180b5d1SVille Syrjälä if ((uint64_t) width * cpp > UINT_MAX) 3378b180b5d1SVille Syrjälä return -ERANGE; 3379b180b5d1SVille Syrjälä 3380b180b5d1SVille Syrjälä if ((uint64_t) height * r->pitches[i] + r->offsets[i] > UINT_MAX) 3381b180b5d1SVille Syrjälä return -ERANGE; 3382b180b5d1SVille Syrjälä 3383b180b5d1SVille Syrjälä if (r->pitches[i] < width * cpp) { 33841aa1b11cSDave Airlie DRM_DEBUG_KMS("bad pitch %u for plane %d\n", r->pitches[i], i); 3385d1b45d5fSVille Syrjälä return -EINVAL; 3386d1b45d5fSVille Syrjälä } 3387e3eb3250SRob Clark 3388e3eb3250SRob Clark if (r->modifier[i] && !(r->flags & DRM_MODE_FB_MODIFIERS)) { 3389e3eb3250SRob Clark DRM_DEBUG_KMS("bad fb modifier %llu for plane %d\n", 3390e3eb3250SRob Clark r->modifier[i], i); 3391e3eb3250SRob Clark return -EINVAL; 3392e3eb3250SRob Clark } 3393570655b0SRob Clark 3394570655b0SRob Clark /* modifier specific checks: */ 3395570655b0SRob Clark switch (r->modifier[i]) { 3396570655b0SRob Clark case DRM_FORMAT_MOD_SAMSUNG_64_32_TILE: 3397570655b0SRob Clark /* NOTE: the pitch restriction may be lifted later if it turns 3398570655b0SRob Clark * out that no hw has this restriction: 3399570655b0SRob Clark */ 3400570655b0SRob Clark if (r->pixel_format != DRM_FORMAT_NV12 || 3401570655b0SRob Clark width % 128 || height % 32 || 3402570655b0SRob Clark r->pitches[i] % 128) { 3403570655b0SRob Clark DRM_DEBUG_KMS("bad modifier data for plane %d\n", i); 3404570655b0SRob Clark return -EINVAL; 3405570655b0SRob Clark } 3406570655b0SRob Clark break; 3407570655b0SRob Clark 3408570655b0SRob Clark default: 3409570655b0SRob Clark break; 3410570655b0SRob Clark } 3411d1b45d5fSVille Syrjälä } 3412d1b45d5fSVille Syrjälä 3413bbe16a40SDaniel Vetter for (i = num_planes; i < 4; i++) { 3414bbe16a40SDaniel Vetter if (r->modifier[i]) { 3415bbe16a40SDaniel Vetter DRM_DEBUG_KMS("non-zero modifier for unused plane %d\n", i); 3416bbe16a40SDaniel Vetter return -EINVAL; 3417bbe16a40SDaniel Vetter } 3418bbe16a40SDaniel Vetter 3419bbe16a40SDaniel Vetter /* Pre-FB_MODIFIERS userspace didn't clear the structs properly. */ 3420bbe16a40SDaniel Vetter if (!(r->flags & DRM_MODE_FB_MODIFIERS)) 3421bbe16a40SDaniel Vetter continue; 3422bbe16a40SDaniel Vetter 3423bbe16a40SDaniel Vetter if (r->handles[i]) { 3424bbe16a40SDaniel Vetter DRM_DEBUG_KMS("buffer object handle for unused plane %d\n", i); 3425bbe16a40SDaniel Vetter return -EINVAL; 3426bbe16a40SDaniel Vetter } 3427bbe16a40SDaniel Vetter 3428bbe16a40SDaniel Vetter if (r->pitches[i]) { 3429bbe16a40SDaniel Vetter DRM_DEBUG_KMS("non-zero pitch for unused plane %d\n", i); 3430bbe16a40SDaniel Vetter return -EINVAL; 3431bbe16a40SDaniel Vetter } 3432bbe16a40SDaniel Vetter 3433bbe16a40SDaniel Vetter if (r->offsets[i]) { 3434bbe16a40SDaniel Vetter DRM_DEBUG_KMS("non-zero offset for unused plane %d\n", i); 3435bbe16a40SDaniel Vetter return -EINVAL; 3436bbe16a40SDaniel Vetter } 3437bbe16a40SDaniel Vetter } 3438bbe16a40SDaniel Vetter 3439d1b45d5fSVille Syrjälä return 0; 3440d1b45d5fSVille Syrjälä } 3441d1b45d5fSVille Syrjälä 34429a6f5130SChris Wilson static struct drm_framebuffer * 34439a6f5130SChris Wilson internal_framebuffer_create(struct drm_device *dev, 34441eb83451SVille Syrjälä const struct drm_mode_fb_cmd2 *r, 3445c394c2b0SMatt Roper struct drm_file *file_priv) 3446c394c2b0SMatt Roper { 3447c394c2b0SMatt Roper struct drm_mode_config *config = &dev->mode_config; 3448c394c2b0SMatt Roper struct drm_framebuffer *fb; 3449c394c2b0SMatt Roper int ret; 3450c394c2b0SMatt Roper 3451e3eb3250SRob Clark if (r->flags & ~(DRM_MODE_FB_INTERLACED | DRM_MODE_FB_MODIFIERS)) { 3452c394c2b0SMatt Roper DRM_DEBUG_KMS("bad framebuffer flags 0x%08x\n", r->flags); 3453c394c2b0SMatt Roper return ERR_PTR(-EINVAL); 3454c394c2b0SMatt Roper } 3455c394c2b0SMatt Roper 3456c394c2b0SMatt Roper if ((config->min_width > r->width) || (r->width > config->max_width)) { 3457c394c2b0SMatt Roper DRM_DEBUG_KMS("bad framebuffer width %d, should be >= %d && <= %d\n", 3458c394c2b0SMatt Roper r->width, config->min_width, config->max_width); 3459c394c2b0SMatt Roper return ERR_PTR(-EINVAL); 3460c394c2b0SMatt Roper } 3461c394c2b0SMatt Roper if ((config->min_height > r->height) || (r->height > config->max_height)) { 3462c394c2b0SMatt Roper DRM_DEBUG_KMS("bad framebuffer height %d, should be >= %d && <= %d\n", 3463c394c2b0SMatt Roper r->height, config->min_height, config->max_height); 3464c394c2b0SMatt Roper return ERR_PTR(-EINVAL); 3465c394c2b0SMatt Roper } 3466c394c2b0SMatt Roper 3467e3eb3250SRob Clark if (r->flags & DRM_MODE_FB_MODIFIERS && 3468e3eb3250SRob Clark !dev->mode_config.allow_fb_modifiers) { 3469e3eb3250SRob Clark DRM_DEBUG_KMS("driver does not support fb modifiers\n"); 3470e3eb3250SRob Clark return ERR_PTR(-EINVAL); 3471e3eb3250SRob Clark } 3472e3eb3250SRob Clark 3473c394c2b0SMatt Roper ret = framebuffer_check(r); 3474c394c2b0SMatt Roper if (ret) 3475c394c2b0SMatt Roper return ERR_PTR(ret); 3476c394c2b0SMatt Roper 3477c394c2b0SMatt Roper fb = dev->mode_config.funcs->fb_create(dev, file_priv, r); 3478c394c2b0SMatt Roper if (IS_ERR(fb)) { 3479c394c2b0SMatt Roper DRM_DEBUG_KMS("could not create framebuffer\n"); 3480c394c2b0SMatt Roper return fb; 3481c394c2b0SMatt Roper } 3482c394c2b0SMatt Roper 3483c394c2b0SMatt Roper return fb; 3484c394c2b0SMatt Roper } 3485c394c2b0SMatt Roper 3486308e5bcbSJesse Barnes /** 3487308e5bcbSJesse Barnes * drm_mode_addfb2 - add an FB to the graphics configuration 3488065a50edSDaniel Vetter * @dev: drm device for the ioctl 3489065a50edSDaniel Vetter * @data: data pointer for the ioctl 3490065a50edSDaniel Vetter * @file_priv: drm file for the ioctl call 3491308e5bcbSJesse Barnes * 3492c8e32cc1SDaniel Vetter * Add a new FB to the specified CRTC, given a user request with format. This is 3493c8e32cc1SDaniel Vetter * the 2nd version of the addfb ioctl, which supports multi-planar framebuffers 3494c8e32cc1SDaniel Vetter * and uses fourcc codes as pixel format specifiers. 3495308e5bcbSJesse Barnes * 3496308e5bcbSJesse Barnes * Called by the user via ioctl. 3497308e5bcbSJesse Barnes * 3498c8e32cc1SDaniel Vetter * Returns: 34991a498633SDaniel Vetter * Zero on success, negative errno on failure. 3500308e5bcbSJesse Barnes */ 3501308e5bcbSJesse Barnes int drm_mode_addfb2(struct drm_device *dev, 3502308e5bcbSJesse Barnes void *data, struct drm_file *file_priv) 3503308e5bcbSJesse Barnes { 35049a6f5130SChris Wilson struct drm_mode_fb_cmd2 *r = data; 3505f453ba04SDave Airlie struct drm_framebuffer *fb; 3506f453ba04SDave Airlie 3507fb3b06c8SDave Airlie if (!drm_core_check_feature(dev, DRIVER_MODESET)) 3508fb3b06c8SDave Airlie return -EINVAL; 3509fb3b06c8SDave Airlie 35109a6f5130SChris Wilson fb = internal_framebuffer_create(dev, r, file_priv); 3511c394c2b0SMatt Roper if (IS_ERR(fb)) 35124b096ac1SDaniel Vetter return PTR_ERR(fb); 3513f453ba04SDave Airlie 35149a6f5130SChris Wilson DRM_DEBUG_KMS("[FB:%d]\n", fb->base.id); 35159a6f5130SChris Wilson r->fb_id = fb->base.id; 3516c7e1c59aSDave Airlie 3517c7e1c59aSDave Airlie /* Transfer ownership to the filp for reaping on close */ 3518c7e1c59aSDave Airlie mutex_lock(&file_priv->fbs_lock); 35199a6f5130SChris Wilson list_add(&fb->filp_head, &file_priv->fbs); 35209a6f5130SChris Wilson mutex_unlock(&file_priv->fbs_lock); 35219a6f5130SChris Wilson 3522c394c2b0SMatt Roper return 0; 3523f453ba04SDave Airlie } 3524f453ba04SDave Airlie 3525f2d580b9SMaarten Lankhorst struct drm_mode_rmfb_work { 3526f2d580b9SMaarten Lankhorst struct work_struct work; 3527f2d580b9SMaarten Lankhorst struct list_head fbs; 3528f2d580b9SMaarten Lankhorst }; 3529f2d580b9SMaarten Lankhorst 3530f2d580b9SMaarten Lankhorst static void drm_mode_rmfb_work_fn(struct work_struct *w) 3531f2d580b9SMaarten Lankhorst { 3532f2d580b9SMaarten Lankhorst struct drm_mode_rmfb_work *arg = container_of(w, typeof(*arg), work); 3533f2d580b9SMaarten Lankhorst 3534f2d580b9SMaarten Lankhorst while (!list_empty(&arg->fbs)) { 3535f2d580b9SMaarten Lankhorst struct drm_framebuffer *fb = 3536f2d580b9SMaarten Lankhorst list_first_entry(&arg->fbs, typeof(*fb), filp_head); 3537f2d580b9SMaarten Lankhorst 3538f2d580b9SMaarten Lankhorst list_del_init(&fb->filp_head); 3539f2d580b9SMaarten Lankhorst drm_framebuffer_remove(fb); 3540f2d580b9SMaarten Lankhorst } 3541f2d580b9SMaarten Lankhorst } 3542f2d580b9SMaarten Lankhorst 3543f453ba04SDave Airlie /** 3544f453ba04SDave Airlie * drm_mode_rmfb - remove an FB from the configuration 3545065a50edSDaniel Vetter * @dev: drm device for the ioctl 3546065a50edSDaniel Vetter * @data: data pointer for the ioctl 3547065a50edSDaniel Vetter * @file_priv: drm file for the ioctl call 3548f453ba04SDave Airlie * 3549f453ba04SDave Airlie * Remove the FB specified by the user. 3550f453ba04SDave Airlie * 3551f453ba04SDave Airlie * Called by the user via ioctl. 3552f453ba04SDave Airlie * 3553c8e32cc1SDaniel Vetter * Returns: 35541a498633SDaniel Vetter * Zero on success, negative errno on failure. 3555f453ba04SDave Airlie */ 3556f453ba04SDave Airlie int drm_mode_rmfb(struct drm_device *dev, 3557f453ba04SDave Airlie void *data, struct drm_file *file_priv) 3558f453ba04SDave Airlie { 3559f453ba04SDave Airlie struct drm_framebuffer *fb = NULL; 3560f453ba04SDave Airlie struct drm_framebuffer *fbl = NULL; 3561f453ba04SDave Airlie uint32_t *id = data; 3562f453ba04SDave Airlie int found = 0; 3563f453ba04SDave Airlie 3564fb3b06c8SDave Airlie if (!drm_core_check_feature(dev, DRIVER_MODESET)) 3565fb3b06c8SDave Airlie return -EINVAL; 3566fb3b06c8SDave Airlie 356772fe90b8SDave Airlie fb = drm_framebuffer_lookup(dev, *id); 356872fe90b8SDave Airlie if (!fb) 356972fe90b8SDave Airlie return -ENOENT; 357072fe90b8SDave Airlie 35714b096ac1SDaniel Vetter mutex_lock(&file_priv->fbs_lock); 3572f453ba04SDave Airlie list_for_each_entry(fbl, &file_priv->fbs, filp_head) 3573f453ba04SDave Airlie if (fb == fbl) 3574f453ba04SDave Airlie found = 1; 357572fe90b8SDave Airlie if (!found) { 357672fe90b8SDave Airlie mutex_unlock(&file_priv->fbs_lock); 357772fe90b8SDave Airlie goto fail_unref; 357872fe90b8SDave Airlie } 35792b677e8cSDaniel Vetter 35804b096ac1SDaniel Vetter list_del_init(&fb->filp_head); 35814b096ac1SDaniel Vetter mutex_unlock(&file_priv->fbs_lock); 3582f453ba04SDave Airlie 3583f2d580b9SMaarten Lankhorst /* drop the reference we picked up in framebuffer lookup */ 358472fe90b8SDave Airlie drm_framebuffer_unreference(fb); 358572fe90b8SDave Airlie 3586f2d580b9SMaarten Lankhorst /* 3587f2d580b9SMaarten Lankhorst * we now own the reference that was stored in the fbs list 3588f2d580b9SMaarten Lankhorst * 3589f2d580b9SMaarten Lankhorst * drm_framebuffer_remove may fail with -EINTR on pending signals, 3590f2d580b9SMaarten Lankhorst * so run this in a separate stack as there's no way to correctly 3591f2d580b9SMaarten Lankhorst * handle this after the fb is already removed from the lookup table. 3592f2d580b9SMaarten Lankhorst */ 3593f2d580b9SMaarten Lankhorst if (drm_framebuffer_read_refcount(fb) > 1) { 3594f2d580b9SMaarten Lankhorst struct drm_mode_rmfb_work arg; 3595f2d580b9SMaarten Lankhorst 3596f2d580b9SMaarten Lankhorst INIT_WORK_ONSTACK(&arg.work, drm_mode_rmfb_work_fn); 3597f2d580b9SMaarten Lankhorst INIT_LIST_HEAD(&arg.fbs); 3598f2d580b9SMaarten Lankhorst list_add_tail(&fb->filp_head, &arg.fbs); 3599f2d580b9SMaarten Lankhorst 3600f2d580b9SMaarten Lankhorst schedule_work(&arg.work); 3601f2d580b9SMaarten Lankhorst flush_work(&arg.work); 3602f2d580b9SMaarten Lankhorst destroy_work_on_stack(&arg.work); 3603f2d580b9SMaarten Lankhorst } else 360413803132SMaarten Lankhorst drm_framebuffer_unreference(fb); 36054b096ac1SDaniel Vetter 36062b677e8cSDaniel Vetter return 0; 36072b677e8cSDaniel Vetter 360872fe90b8SDave Airlie fail_unref: 360972fe90b8SDave Airlie drm_framebuffer_unreference(fb); 361037c4e705SVille Syrjälä return -ENOENT; 3611f453ba04SDave Airlie } 3612f453ba04SDave Airlie 3613f453ba04SDave Airlie /** 3614f453ba04SDave Airlie * drm_mode_getfb - get FB info 3615065a50edSDaniel Vetter * @dev: drm device for the ioctl 3616065a50edSDaniel Vetter * @data: data pointer for the ioctl 3617065a50edSDaniel Vetter * @file_priv: drm file for the ioctl call 3618f453ba04SDave Airlie * 3619f453ba04SDave Airlie * Lookup the FB given its ID and return info about it. 3620f453ba04SDave Airlie * 3621f453ba04SDave Airlie * Called by the user via ioctl. 3622f453ba04SDave Airlie * 3623c8e32cc1SDaniel Vetter * Returns: 36241a498633SDaniel Vetter * Zero on success, negative errno on failure. 3625f453ba04SDave Airlie */ 3626f453ba04SDave Airlie int drm_mode_getfb(struct drm_device *dev, 3627f453ba04SDave Airlie void *data, struct drm_file *file_priv) 3628f453ba04SDave Airlie { 3629f453ba04SDave Airlie struct drm_mode_fb_cmd *r = data; 3630f453ba04SDave Airlie struct drm_framebuffer *fb; 363158c0dca1SDaniel Vetter int ret; 3632f453ba04SDave Airlie 3633fb3b06c8SDave Airlie if (!drm_core_check_feature(dev, DRIVER_MODESET)) 3634fb3b06c8SDave Airlie return -EINVAL; 3635fb3b06c8SDave Airlie 3636786b99edSDaniel Vetter fb = drm_framebuffer_lookup(dev, r->fb_id); 363758c0dca1SDaniel Vetter if (!fb) 363837c4e705SVille Syrjälä return -ENOENT; 3639f453ba04SDave Airlie 3640f453ba04SDave Airlie r->height = fb->height; 3641f453ba04SDave Airlie r->width = fb->width; 3642f453ba04SDave Airlie r->depth = fb->depth; 3643f453ba04SDave Airlie r->bpp = fb->bits_per_pixel; 364401f2c773SVille Syrjälä r->pitch = fb->pitches[0]; 3645101b96f3SDavid Herrmann if (fb->funcs->create_handle) { 364609f308f7SThomas Hellstrom if (file_priv->is_master || capable(CAP_SYS_ADMIN) || 364743683057SThomas Hellstrom drm_is_control_client(file_priv)) { 3648101b96f3SDavid Herrmann ret = fb->funcs->create_handle(fb, file_priv, 3649101b96f3SDavid Herrmann &r->handle); 3650101b96f3SDavid Herrmann } else { 3651101b96f3SDavid Herrmann /* GET_FB() is an unprivileged ioctl so we must not 3652101b96f3SDavid Herrmann * return a buffer-handle to non-master processes! For 3653101b96f3SDavid Herrmann * backwards-compatibility reasons, we cannot make 3654101b96f3SDavid Herrmann * GET_FB() privileged, so just return an invalid handle 3655101b96f3SDavid Herrmann * for non-masters. */ 3656101b96f3SDavid Herrmann r->handle = 0; 3657101b96f3SDavid Herrmann ret = 0; 3658101b96f3SDavid Herrmann } 3659101b96f3SDavid Herrmann } else { 3660af26ef3bSDaniel Vetter ret = -ENODEV; 3661101b96f3SDavid Herrmann } 3662f453ba04SDave Airlie 366358c0dca1SDaniel Vetter drm_framebuffer_unreference(fb); 366458c0dca1SDaniel Vetter 3665f453ba04SDave Airlie return ret; 3666f453ba04SDave Airlie } 3667f453ba04SDave Airlie 3668c8e32cc1SDaniel Vetter /** 3669c8e32cc1SDaniel Vetter * drm_mode_dirtyfb_ioctl - flush frontbuffer rendering on an FB 3670c8e32cc1SDaniel Vetter * @dev: drm device for the ioctl 3671c8e32cc1SDaniel Vetter * @data: data pointer for the ioctl 3672c8e32cc1SDaniel Vetter * @file_priv: drm file for the ioctl call 3673c8e32cc1SDaniel Vetter * 3674c8e32cc1SDaniel Vetter * Lookup the FB and flush out the damaged area supplied by userspace as a clip 3675c8e32cc1SDaniel Vetter * rectangle list. Generic userspace which does frontbuffer rendering must call 3676c8e32cc1SDaniel Vetter * this ioctl to flush out the changes on manual-update display outputs, e.g. 3677c8e32cc1SDaniel Vetter * usb display-link, mipi manual update panels or edp panel self refresh modes. 3678c8e32cc1SDaniel Vetter * 3679c8e32cc1SDaniel Vetter * Modesetting drivers which always update the frontbuffer do not need to 3680c8e32cc1SDaniel Vetter * implement the corresponding ->dirty framebuffer callback. 3681c8e32cc1SDaniel Vetter * 3682c8e32cc1SDaniel Vetter * Called by the user via ioctl. 3683c8e32cc1SDaniel Vetter * 3684c8e32cc1SDaniel Vetter * Returns: 36851a498633SDaniel Vetter * Zero on success, negative errno on failure. 3686c8e32cc1SDaniel Vetter */ 3687884840aaSJakob Bornecrantz int drm_mode_dirtyfb_ioctl(struct drm_device *dev, 3688884840aaSJakob Bornecrantz void *data, struct drm_file *file_priv) 3689884840aaSJakob Bornecrantz { 3690884840aaSJakob Bornecrantz struct drm_clip_rect __user *clips_ptr; 3691884840aaSJakob Bornecrantz struct drm_clip_rect *clips = NULL; 3692884840aaSJakob Bornecrantz struct drm_mode_fb_dirty_cmd *r = data; 3693884840aaSJakob Bornecrantz struct drm_framebuffer *fb; 3694884840aaSJakob Bornecrantz unsigned flags; 3695884840aaSJakob Bornecrantz int num_clips; 36964a1b0714SLaurent Pinchart int ret; 3697884840aaSJakob Bornecrantz 3698fb3b06c8SDave Airlie if (!drm_core_check_feature(dev, DRIVER_MODESET)) 3699fb3b06c8SDave Airlie return -EINVAL; 3700fb3b06c8SDave Airlie 3701786b99edSDaniel Vetter fb = drm_framebuffer_lookup(dev, r->fb_id); 37024ccf097fSDaniel Vetter if (!fb) 370337c4e705SVille Syrjälä return -ENOENT; 3704884840aaSJakob Bornecrantz 3705884840aaSJakob Bornecrantz num_clips = r->num_clips; 370681f6c7f8SVille Syrjälä clips_ptr = (struct drm_clip_rect __user *)(unsigned long)r->clips_ptr; 3707884840aaSJakob Bornecrantz 3708884840aaSJakob Bornecrantz if (!num_clips != !clips_ptr) { 3709884840aaSJakob Bornecrantz ret = -EINVAL; 3710884840aaSJakob Bornecrantz goto out_err1; 3711884840aaSJakob Bornecrantz } 3712884840aaSJakob Bornecrantz 3713884840aaSJakob Bornecrantz flags = DRM_MODE_FB_DIRTY_FLAGS & r->flags; 3714884840aaSJakob Bornecrantz 3715884840aaSJakob Bornecrantz /* If userspace annotates copy, clips must come in pairs */ 3716884840aaSJakob Bornecrantz if (flags & DRM_MODE_FB_DIRTY_ANNOTATE_COPY && (num_clips % 2)) { 3717884840aaSJakob Bornecrantz ret = -EINVAL; 3718884840aaSJakob Bornecrantz goto out_err1; 3719884840aaSJakob Bornecrantz } 3720884840aaSJakob Bornecrantz 3721884840aaSJakob Bornecrantz if (num_clips && clips_ptr) { 3722a5cd3351SXi Wang if (num_clips < 0 || num_clips > DRM_MODE_FB_DIRTY_MAX_CLIPS) { 3723a5cd3351SXi Wang ret = -EINVAL; 3724a5cd3351SXi Wang goto out_err1; 3725a5cd3351SXi Wang } 3726bd3f0ff9SThierry Reding clips = kcalloc(num_clips, sizeof(*clips), GFP_KERNEL); 3727884840aaSJakob Bornecrantz if (!clips) { 3728884840aaSJakob Bornecrantz ret = -ENOMEM; 3729884840aaSJakob Bornecrantz goto out_err1; 3730884840aaSJakob Bornecrantz } 3731884840aaSJakob Bornecrantz 3732884840aaSJakob Bornecrantz ret = copy_from_user(clips, clips_ptr, 3733884840aaSJakob Bornecrantz num_clips * sizeof(*clips)); 3734e902a358SDan Carpenter if (ret) { 3735e902a358SDan Carpenter ret = -EFAULT; 3736884840aaSJakob Bornecrantz goto out_err2; 3737884840aaSJakob Bornecrantz } 3738e902a358SDan Carpenter } 3739884840aaSJakob Bornecrantz 3740884840aaSJakob Bornecrantz if (fb->funcs->dirty) { 374102b00162SThomas Hellstrom ret = fb->funcs->dirty(fb, file_priv, flags, r->color, 374202b00162SThomas Hellstrom clips, num_clips); 3743884840aaSJakob Bornecrantz } else { 3744884840aaSJakob Bornecrantz ret = -ENOSYS; 3745884840aaSJakob Bornecrantz } 3746884840aaSJakob Bornecrantz 3747884840aaSJakob Bornecrantz out_err2: 3748884840aaSJakob Bornecrantz kfree(clips); 3749884840aaSJakob Bornecrantz out_err1: 37504ccf097fSDaniel Vetter drm_framebuffer_unreference(fb); 37514ccf097fSDaniel Vetter 3752884840aaSJakob Bornecrantz return ret; 3753884840aaSJakob Bornecrantz } 3754884840aaSJakob Bornecrantz 3755f453ba04SDave Airlie /** 3756f453ba04SDave Airlie * drm_fb_release - remove and free the FBs on this file 3757065a50edSDaniel Vetter * @priv: drm file for the ioctl 3758f453ba04SDave Airlie * 3759f453ba04SDave Airlie * Destroy all the FBs associated with @filp. 3760f453ba04SDave Airlie * 3761f453ba04SDave Airlie * Called by the user via ioctl. 3762f453ba04SDave Airlie * 3763c8e32cc1SDaniel Vetter * Returns: 37641a498633SDaniel Vetter * Zero on success, negative errno on failure. 3765f453ba04SDave Airlie */ 3766ea39f835SKristian Høgsberg void drm_fb_release(struct drm_file *priv) 3767f453ba04SDave Airlie { 3768f453ba04SDave Airlie struct drm_framebuffer *fb, *tfb; 3769f2d580b9SMaarten Lankhorst struct drm_mode_rmfb_work arg; 3770f2d580b9SMaarten Lankhorst 3771f2d580b9SMaarten Lankhorst INIT_LIST_HEAD(&arg.fbs); 3772f453ba04SDave Airlie 37731b116297SDaniel Vetter /* 37741b116297SDaniel Vetter * When the file gets released that means no one else can access the fb 3775e2db726bSMartin Peres * list any more, so no need to grab fpriv->fbs_lock. And we need to 37761b116297SDaniel Vetter * avoid upsetting lockdep since the universal cursor code adds a 37771b116297SDaniel Vetter * framebuffer while holding mutex locks. 37781b116297SDaniel Vetter * 37791b116297SDaniel Vetter * Note that a real deadlock between fpriv->fbs_lock and the modeset 37801b116297SDaniel Vetter * locks is impossible here since no one else but this function can get 37811b116297SDaniel Vetter * at it any more. 37821b116297SDaniel Vetter */ 3783f453ba04SDave Airlie list_for_each_entry_safe(fb, tfb, &priv->fbs, filp_head) { 3784f2d580b9SMaarten Lankhorst if (drm_framebuffer_read_refcount(fb) > 1) { 3785f2d580b9SMaarten Lankhorst list_move_tail(&fb->filp_head, &arg.fbs); 3786f2d580b9SMaarten Lankhorst } else { 37874b096ac1SDaniel Vetter list_del_init(&fb->filp_head); 37882b677e8cSDaniel Vetter 378973f7570bSMaarten Lankhorst /* This drops the fpriv->fbs reference. */ 379013803132SMaarten Lankhorst drm_framebuffer_unreference(fb); 3791f453ba04SDave Airlie } 3792f453ba04SDave Airlie } 3793f453ba04SDave Airlie 3794f2d580b9SMaarten Lankhorst if (!list_empty(&arg.fbs)) { 3795f2d580b9SMaarten Lankhorst INIT_WORK_ONSTACK(&arg.work, drm_mode_rmfb_work_fn); 3796f2d580b9SMaarten Lankhorst 3797f2d580b9SMaarten Lankhorst schedule_work(&arg.work); 3798f2d580b9SMaarten Lankhorst flush_work(&arg.work); 3799f2d580b9SMaarten Lankhorst destroy_work_on_stack(&arg.work); 3800f2d580b9SMaarten Lankhorst } 3801f2d580b9SMaarten Lankhorst } 3802f2d580b9SMaarten Lankhorst 3803c8e32cc1SDaniel Vetter /** 3804c8e32cc1SDaniel Vetter * drm_property_create - create a new property type 3805c8e32cc1SDaniel Vetter * @dev: drm device 3806c8e32cc1SDaniel Vetter * @flags: flags specifying the property type 3807c8e32cc1SDaniel Vetter * @name: name of the property 3808c8e32cc1SDaniel Vetter * @num_values: number of pre-defined values 3809c8e32cc1SDaniel Vetter * 3810c8e32cc1SDaniel Vetter * This creates a new generic drm property which can then be attached to a drm 3811c8e32cc1SDaniel Vetter * object with drm_object_attach_property. The returned property object must be 3812c8e32cc1SDaniel Vetter * freed with drm_property_destroy. 3813c8e32cc1SDaniel Vetter * 38143b5b9932SDamien Lespiau * Note that the DRM core keeps a per-device list of properties and that, if 38153b5b9932SDamien Lespiau * drm_mode_config_cleanup() is called, it will destroy all properties created 38163b5b9932SDamien Lespiau * by the driver. 38173b5b9932SDamien Lespiau * 3818c8e32cc1SDaniel Vetter * Returns: 3819c8e32cc1SDaniel Vetter * A pointer to the newly created property on success, NULL on failure. 3820c8e32cc1SDaniel Vetter */ 3821f453ba04SDave Airlie struct drm_property *drm_property_create(struct drm_device *dev, int flags, 3822f453ba04SDave Airlie const char *name, int num_values) 3823f453ba04SDave Airlie { 3824f453ba04SDave Airlie struct drm_property *property = NULL; 38256bfc56aaSVille Syrjälä int ret; 3826f453ba04SDave Airlie 3827f453ba04SDave Airlie property = kzalloc(sizeof(struct drm_property), GFP_KERNEL); 3828f453ba04SDave Airlie if (!property) 3829f453ba04SDave Airlie return NULL; 3830f453ba04SDave Airlie 383198f75de4SRob Clark property->dev = dev; 383298f75de4SRob Clark 3833f453ba04SDave Airlie if (num_values) { 3834bd3f0ff9SThierry Reding property->values = kcalloc(num_values, sizeof(uint64_t), 3835bd3f0ff9SThierry Reding GFP_KERNEL); 3836f453ba04SDave Airlie if (!property->values) 3837f453ba04SDave Airlie goto fail; 3838f453ba04SDave Airlie } 3839f453ba04SDave Airlie 38406bfc56aaSVille Syrjälä ret = drm_mode_object_get(dev, &property->base, DRM_MODE_OBJECT_PROPERTY); 38416bfc56aaSVille Syrjälä if (ret) 38426bfc56aaSVille Syrjälä goto fail; 38436bfc56aaSVille Syrjälä 3844f453ba04SDave Airlie property->flags = flags; 3845f453ba04SDave Airlie property->num_values = num_values; 38463758b341SDaniel Vetter INIT_LIST_HEAD(&property->enum_list); 3847f453ba04SDave Airlie 3848471dd2efSVinson Lee if (name) { 3849f453ba04SDave Airlie strncpy(property->name, name, DRM_PROP_NAME_LEN); 3850471dd2efSVinson Lee property->name[DRM_PROP_NAME_LEN-1] = '\0'; 3851471dd2efSVinson Lee } 3852f453ba04SDave Airlie 3853f453ba04SDave Airlie list_add_tail(&property->head, &dev->mode_config.property_list); 38545ea22f24SRob Clark 38555ea22f24SRob Clark WARN_ON(!drm_property_type_valid(property)); 38565ea22f24SRob Clark 3857f453ba04SDave Airlie return property; 3858f453ba04SDave Airlie fail: 38596bfc56aaSVille Syrjälä kfree(property->values); 3860f453ba04SDave Airlie kfree(property); 3861f453ba04SDave Airlie return NULL; 3862f453ba04SDave Airlie } 3863f453ba04SDave Airlie EXPORT_SYMBOL(drm_property_create); 3864f453ba04SDave Airlie 3865c8e32cc1SDaniel Vetter /** 38662aa9d2bcSThierry Reding * drm_property_create_enum - create a new enumeration property type 3867c8e32cc1SDaniel Vetter * @dev: drm device 3868c8e32cc1SDaniel Vetter * @flags: flags specifying the property type 3869c8e32cc1SDaniel Vetter * @name: name of the property 3870c8e32cc1SDaniel Vetter * @props: enumeration lists with property values 3871c8e32cc1SDaniel Vetter * @num_values: number of pre-defined values 3872c8e32cc1SDaniel Vetter * 3873c8e32cc1SDaniel Vetter * This creates a new generic drm property which can then be attached to a drm 3874c8e32cc1SDaniel Vetter * object with drm_object_attach_property. The returned property object must be 3875c8e32cc1SDaniel Vetter * freed with drm_property_destroy. 3876c8e32cc1SDaniel Vetter * 3877c8e32cc1SDaniel Vetter * Userspace is only allowed to set one of the predefined values for enumeration 3878c8e32cc1SDaniel Vetter * properties. 3879c8e32cc1SDaniel Vetter * 3880c8e32cc1SDaniel Vetter * Returns: 3881c8e32cc1SDaniel Vetter * A pointer to the newly created property on success, NULL on failure. 3882c8e32cc1SDaniel Vetter */ 38834a67d391SSascha Hauer struct drm_property *drm_property_create_enum(struct drm_device *dev, int flags, 38844a67d391SSascha Hauer const char *name, 38854a67d391SSascha Hauer const struct drm_prop_enum_list *props, 38864a67d391SSascha Hauer int num_values) 38874a67d391SSascha Hauer { 38884a67d391SSascha Hauer struct drm_property *property; 38894a67d391SSascha Hauer int i, ret; 38904a67d391SSascha Hauer 38914a67d391SSascha Hauer flags |= DRM_MODE_PROP_ENUM; 38924a67d391SSascha Hauer 38934a67d391SSascha Hauer property = drm_property_create(dev, flags, name, num_values); 38944a67d391SSascha Hauer if (!property) 38954a67d391SSascha Hauer return NULL; 38964a67d391SSascha Hauer 38974a67d391SSascha Hauer for (i = 0; i < num_values; i++) { 38984a67d391SSascha Hauer ret = drm_property_add_enum(property, i, 38994a67d391SSascha Hauer props[i].type, 39004a67d391SSascha Hauer props[i].name); 39014a67d391SSascha Hauer if (ret) { 39024a67d391SSascha Hauer drm_property_destroy(dev, property); 39034a67d391SSascha Hauer return NULL; 39044a67d391SSascha Hauer } 39054a67d391SSascha Hauer } 39064a67d391SSascha Hauer 39074a67d391SSascha Hauer return property; 39084a67d391SSascha Hauer } 39094a67d391SSascha Hauer EXPORT_SYMBOL(drm_property_create_enum); 39104a67d391SSascha Hauer 3911c8e32cc1SDaniel Vetter /** 39122aa9d2bcSThierry Reding * drm_property_create_bitmask - create a new bitmask property type 3913c8e32cc1SDaniel Vetter * @dev: drm device 3914c8e32cc1SDaniel Vetter * @flags: flags specifying the property type 3915c8e32cc1SDaniel Vetter * @name: name of the property 3916c8e32cc1SDaniel Vetter * @props: enumeration lists with property bitflags 3917295ee853SDaniel Vetter * @num_props: size of the @props array 3918295ee853SDaniel Vetter * @supported_bits: bitmask of all supported enumeration values 3919c8e32cc1SDaniel Vetter * 3920295ee853SDaniel Vetter * This creates a new bitmask drm property which can then be attached to a drm 3921c8e32cc1SDaniel Vetter * object with drm_object_attach_property. The returned property object must be 3922c8e32cc1SDaniel Vetter * freed with drm_property_destroy. 3923c8e32cc1SDaniel Vetter * 3924c8e32cc1SDaniel Vetter * Compared to plain enumeration properties userspace is allowed to set any 3925c8e32cc1SDaniel Vetter * or'ed together combination of the predefined property bitflag values 3926c8e32cc1SDaniel Vetter * 3927c8e32cc1SDaniel Vetter * Returns: 3928c8e32cc1SDaniel Vetter * A pointer to the newly created property on success, NULL on failure. 3929c8e32cc1SDaniel Vetter */ 393049e27545SRob Clark struct drm_property *drm_property_create_bitmask(struct drm_device *dev, 393149e27545SRob Clark int flags, const char *name, 393249e27545SRob Clark const struct drm_prop_enum_list *props, 39337689ffb3SVille Syrjälä int num_props, 39347689ffb3SVille Syrjälä uint64_t supported_bits) 393549e27545SRob Clark { 393649e27545SRob Clark struct drm_property *property; 39377689ffb3SVille Syrjälä int i, ret, index = 0; 39387689ffb3SVille Syrjälä int num_values = hweight64(supported_bits); 393949e27545SRob Clark 394049e27545SRob Clark flags |= DRM_MODE_PROP_BITMASK; 394149e27545SRob Clark 394249e27545SRob Clark property = drm_property_create(dev, flags, name, num_values); 394349e27545SRob Clark if (!property) 394449e27545SRob Clark return NULL; 39457689ffb3SVille Syrjälä for (i = 0; i < num_props; i++) { 39467689ffb3SVille Syrjälä if (!(supported_bits & (1ULL << props[i].type))) 39477689ffb3SVille Syrjälä continue; 394849e27545SRob Clark 39497689ffb3SVille Syrjälä if (WARN_ON(index >= num_values)) { 39507689ffb3SVille Syrjälä drm_property_destroy(dev, property); 39517689ffb3SVille Syrjälä return NULL; 39527689ffb3SVille Syrjälä } 39537689ffb3SVille Syrjälä 39547689ffb3SVille Syrjälä ret = drm_property_add_enum(property, index++, 395549e27545SRob Clark props[i].type, 395649e27545SRob Clark props[i].name); 395749e27545SRob Clark if (ret) { 395849e27545SRob Clark drm_property_destroy(dev, property); 395949e27545SRob Clark return NULL; 396049e27545SRob Clark } 396149e27545SRob Clark } 396249e27545SRob Clark 396349e27545SRob Clark return property; 396449e27545SRob Clark } 396549e27545SRob Clark EXPORT_SYMBOL(drm_property_create_bitmask); 396649e27545SRob Clark 3967ebc44cf3SRob Clark static struct drm_property *property_create_range(struct drm_device *dev, 3968ebc44cf3SRob Clark int flags, const char *name, 3969ebc44cf3SRob Clark uint64_t min, uint64_t max) 3970ebc44cf3SRob Clark { 3971ebc44cf3SRob Clark struct drm_property *property; 3972ebc44cf3SRob Clark 3973ebc44cf3SRob Clark property = drm_property_create(dev, flags, name, 2); 3974ebc44cf3SRob Clark if (!property) 3975ebc44cf3SRob Clark return NULL; 3976ebc44cf3SRob Clark 3977ebc44cf3SRob Clark property->values[0] = min; 3978ebc44cf3SRob Clark property->values[1] = max; 3979ebc44cf3SRob Clark 3980ebc44cf3SRob Clark return property; 3981ebc44cf3SRob Clark } 3982ebc44cf3SRob Clark 3983c8e32cc1SDaniel Vetter /** 3984960cd9d4SDaniel Vetter * drm_property_create_range - create a new unsigned ranged property type 3985c8e32cc1SDaniel Vetter * @dev: drm device 3986c8e32cc1SDaniel Vetter * @flags: flags specifying the property type 3987c8e32cc1SDaniel Vetter * @name: name of the property 3988c8e32cc1SDaniel Vetter * @min: minimum value of the property 3989c8e32cc1SDaniel Vetter * @max: maximum value of the property 3990c8e32cc1SDaniel Vetter * 3991c8e32cc1SDaniel Vetter * This creates a new generic drm property which can then be attached to a drm 3992c8e32cc1SDaniel Vetter * object with drm_object_attach_property. The returned property object must be 3993c8e32cc1SDaniel Vetter * freed with drm_property_destroy. 3994c8e32cc1SDaniel Vetter * 3995960cd9d4SDaniel Vetter * Userspace is allowed to set any unsigned integer value in the (min, max) 3996960cd9d4SDaniel Vetter * range inclusive. 3997c8e32cc1SDaniel Vetter * 3998c8e32cc1SDaniel Vetter * Returns: 3999c8e32cc1SDaniel Vetter * A pointer to the newly created property on success, NULL on failure. 4000c8e32cc1SDaniel Vetter */ 4001d9bc3c02SSascha Hauer struct drm_property *drm_property_create_range(struct drm_device *dev, int flags, 4002d9bc3c02SSascha Hauer const char *name, 4003d9bc3c02SSascha Hauer uint64_t min, uint64_t max) 4004d9bc3c02SSascha Hauer { 4005ebc44cf3SRob Clark return property_create_range(dev, DRM_MODE_PROP_RANGE | flags, 4006ebc44cf3SRob Clark name, min, max); 4007d9bc3c02SSascha Hauer } 4008d9bc3c02SSascha Hauer EXPORT_SYMBOL(drm_property_create_range); 4009d9bc3c02SSascha Hauer 4010960cd9d4SDaniel Vetter /** 4011960cd9d4SDaniel Vetter * drm_property_create_signed_range - create a new signed ranged property type 4012960cd9d4SDaniel Vetter * @dev: drm device 4013960cd9d4SDaniel Vetter * @flags: flags specifying the property type 4014960cd9d4SDaniel Vetter * @name: name of the property 4015960cd9d4SDaniel Vetter * @min: minimum value of the property 4016960cd9d4SDaniel Vetter * @max: maximum value of the property 4017960cd9d4SDaniel Vetter * 4018960cd9d4SDaniel Vetter * This creates a new generic drm property which can then be attached to a drm 4019960cd9d4SDaniel Vetter * object with drm_object_attach_property. The returned property object must be 4020960cd9d4SDaniel Vetter * freed with drm_property_destroy. 4021960cd9d4SDaniel Vetter * 4022960cd9d4SDaniel Vetter * Userspace is allowed to set any signed integer value in the (min, max) 4023960cd9d4SDaniel Vetter * range inclusive. 4024960cd9d4SDaniel Vetter * 4025960cd9d4SDaniel Vetter * Returns: 4026960cd9d4SDaniel Vetter * A pointer to the newly created property on success, NULL on failure. 4027960cd9d4SDaniel Vetter */ 4028ebc44cf3SRob Clark struct drm_property *drm_property_create_signed_range(struct drm_device *dev, 4029ebc44cf3SRob Clark int flags, const char *name, 4030ebc44cf3SRob Clark int64_t min, int64_t max) 4031ebc44cf3SRob Clark { 4032ebc44cf3SRob Clark return property_create_range(dev, DRM_MODE_PROP_SIGNED_RANGE | flags, 4033ebc44cf3SRob Clark name, I642U64(min), I642U64(max)); 4034ebc44cf3SRob Clark } 4035ebc44cf3SRob Clark EXPORT_SYMBOL(drm_property_create_signed_range); 4036ebc44cf3SRob Clark 4037960cd9d4SDaniel Vetter /** 4038960cd9d4SDaniel Vetter * drm_property_create_object - create a new object property type 4039960cd9d4SDaniel Vetter * @dev: drm device 4040960cd9d4SDaniel Vetter * @flags: flags specifying the property type 4041960cd9d4SDaniel Vetter * @name: name of the property 4042960cd9d4SDaniel Vetter * @type: object type from DRM_MODE_OBJECT_* defines 4043960cd9d4SDaniel Vetter * 4044960cd9d4SDaniel Vetter * This creates a new generic drm property which can then be attached to a drm 4045960cd9d4SDaniel Vetter * object with drm_object_attach_property. The returned property object must be 4046960cd9d4SDaniel Vetter * freed with drm_property_destroy. 4047960cd9d4SDaniel Vetter * 4048960cd9d4SDaniel Vetter * Userspace is only allowed to set this to any property value of the given 4049960cd9d4SDaniel Vetter * @type. Only useful for atomic properties, which is enforced. 4050960cd9d4SDaniel Vetter * 4051960cd9d4SDaniel Vetter * Returns: 4052960cd9d4SDaniel Vetter * A pointer to the newly created property on success, NULL on failure. 4053960cd9d4SDaniel Vetter */ 405498f75de4SRob Clark struct drm_property *drm_property_create_object(struct drm_device *dev, 405598f75de4SRob Clark int flags, const char *name, uint32_t type) 405698f75de4SRob Clark { 405798f75de4SRob Clark struct drm_property *property; 405898f75de4SRob Clark 405998f75de4SRob Clark flags |= DRM_MODE_PROP_OBJECT; 406098f75de4SRob Clark 4061960cd9d4SDaniel Vetter if (WARN_ON(!(flags & DRM_MODE_PROP_ATOMIC))) 4062960cd9d4SDaniel Vetter return NULL; 4063960cd9d4SDaniel Vetter 406498f75de4SRob Clark property = drm_property_create(dev, flags, name, 1); 406598f75de4SRob Clark if (!property) 406698f75de4SRob Clark return NULL; 406798f75de4SRob Clark 406898f75de4SRob Clark property->values[0] = type; 406998f75de4SRob Clark 407098f75de4SRob Clark return property; 407198f75de4SRob Clark } 407298f75de4SRob Clark EXPORT_SYMBOL(drm_property_create_object); 407398f75de4SRob Clark 4074c8e32cc1SDaniel Vetter /** 4075960cd9d4SDaniel Vetter * drm_property_create_bool - create a new boolean property type 4076960cd9d4SDaniel Vetter * @dev: drm device 4077960cd9d4SDaniel Vetter * @flags: flags specifying the property type 4078960cd9d4SDaniel Vetter * @name: name of the property 4079960cd9d4SDaniel Vetter * 4080960cd9d4SDaniel Vetter * This creates a new generic drm property which can then be attached to a drm 4081960cd9d4SDaniel Vetter * object with drm_object_attach_property. The returned property object must be 4082960cd9d4SDaniel Vetter * freed with drm_property_destroy. 4083960cd9d4SDaniel Vetter * 4084960cd9d4SDaniel Vetter * This is implemented as a ranged property with only {0, 1} as valid values. 4085960cd9d4SDaniel Vetter * 4086960cd9d4SDaniel Vetter * Returns: 4087960cd9d4SDaniel Vetter * A pointer to the newly created property on success, NULL on failure. 4088960cd9d4SDaniel Vetter */ 4089960cd9d4SDaniel Vetter struct drm_property *drm_property_create_bool(struct drm_device *dev, int flags, 4090960cd9d4SDaniel Vetter const char *name) 4091960cd9d4SDaniel Vetter { 4092960cd9d4SDaniel Vetter return drm_property_create_range(dev, flags, name, 0, 1); 4093960cd9d4SDaniel Vetter } 4094960cd9d4SDaniel Vetter EXPORT_SYMBOL(drm_property_create_bool); 4095960cd9d4SDaniel Vetter 4096960cd9d4SDaniel Vetter /** 4097c8e32cc1SDaniel Vetter * drm_property_add_enum - add a possible value to an enumeration property 4098c8e32cc1SDaniel Vetter * @property: enumeration property to change 4099c8e32cc1SDaniel Vetter * @index: index of the new enumeration 4100c8e32cc1SDaniel Vetter * @value: value of the new enumeration 4101c8e32cc1SDaniel Vetter * @name: symbolic name of the new enumeration 4102c8e32cc1SDaniel Vetter * 4103c8e32cc1SDaniel Vetter * This functions adds enumerations to a property. 4104c8e32cc1SDaniel Vetter * 4105c8e32cc1SDaniel Vetter * It's use is deprecated, drivers should use one of the more specific helpers 4106c8e32cc1SDaniel Vetter * to directly create the property with all enumerations already attached. 4107c8e32cc1SDaniel Vetter * 4108c8e32cc1SDaniel Vetter * Returns: 4109c8e32cc1SDaniel Vetter * Zero on success, error code on failure. 4110c8e32cc1SDaniel Vetter */ 4111f453ba04SDave Airlie int drm_property_add_enum(struct drm_property *property, int index, 4112f453ba04SDave Airlie uint64_t value, const char *name) 4113f453ba04SDave Airlie { 4114f453ba04SDave Airlie struct drm_property_enum *prop_enum; 4115f453ba04SDave Airlie 41165ea22f24SRob Clark if (!(drm_property_type_is(property, DRM_MODE_PROP_ENUM) || 41175ea22f24SRob Clark drm_property_type_is(property, DRM_MODE_PROP_BITMASK))) 411849e27545SRob Clark return -EINVAL; 411949e27545SRob Clark 412049e27545SRob Clark /* 412149e27545SRob Clark * Bitmask enum properties have the additional constraint of values 412249e27545SRob Clark * from 0 to 63 412349e27545SRob Clark */ 41245ea22f24SRob Clark if (drm_property_type_is(property, DRM_MODE_PROP_BITMASK) && 41255ea22f24SRob Clark (value > 63)) 4126f453ba04SDave Airlie return -EINVAL; 4127f453ba04SDave Airlie 41283758b341SDaniel Vetter if (!list_empty(&property->enum_list)) { 41293758b341SDaniel Vetter list_for_each_entry(prop_enum, &property->enum_list, head) { 4130f453ba04SDave Airlie if (prop_enum->value == value) { 4131f453ba04SDave Airlie strncpy(prop_enum->name, name, DRM_PROP_NAME_LEN); 4132f453ba04SDave Airlie prop_enum->name[DRM_PROP_NAME_LEN-1] = '\0'; 4133f453ba04SDave Airlie return 0; 4134f453ba04SDave Airlie } 4135f453ba04SDave Airlie } 4136f453ba04SDave Airlie } 4137f453ba04SDave Airlie 4138f453ba04SDave Airlie prop_enum = kzalloc(sizeof(struct drm_property_enum), GFP_KERNEL); 4139f453ba04SDave Airlie if (!prop_enum) 4140f453ba04SDave Airlie return -ENOMEM; 4141f453ba04SDave Airlie 4142f453ba04SDave Airlie strncpy(prop_enum->name, name, DRM_PROP_NAME_LEN); 4143f453ba04SDave Airlie prop_enum->name[DRM_PROP_NAME_LEN-1] = '\0'; 4144f453ba04SDave Airlie prop_enum->value = value; 4145f453ba04SDave Airlie 4146f453ba04SDave Airlie property->values[index] = value; 41473758b341SDaniel Vetter list_add_tail(&prop_enum->head, &property->enum_list); 4148f453ba04SDave Airlie return 0; 4149f453ba04SDave Airlie } 4150f453ba04SDave Airlie EXPORT_SYMBOL(drm_property_add_enum); 4151f453ba04SDave Airlie 4152c8e32cc1SDaniel Vetter /** 4153c8e32cc1SDaniel Vetter * drm_property_destroy - destroy a drm property 4154c8e32cc1SDaniel Vetter * @dev: drm device 4155c8e32cc1SDaniel Vetter * @property: property to destry 4156c8e32cc1SDaniel Vetter * 4157c8e32cc1SDaniel Vetter * This function frees a property including any attached resources like 4158c8e32cc1SDaniel Vetter * enumeration values. 4159c8e32cc1SDaniel Vetter */ 4160f453ba04SDave Airlie void drm_property_destroy(struct drm_device *dev, struct drm_property *property) 4161f453ba04SDave Airlie { 4162f453ba04SDave Airlie struct drm_property_enum *prop_enum, *pt; 4163f453ba04SDave Airlie 41643758b341SDaniel Vetter list_for_each_entry_safe(prop_enum, pt, &property->enum_list, head) { 4165f453ba04SDave Airlie list_del(&prop_enum->head); 4166f453ba04SDave Airlie kfree(prop_enum); 4167f453ba04SDave Airlie } 4168f453ba04SDave Airlie 4169f453ba04SDave Airlie if (property->num_values) 4170f453ba04SDave Airlie kfree(property->values); 41717c8f6d25SDave Airlie drm_mode_object_unregister(dev, &property->base); 4172f453ba04SDave Airlie list_del(&property->head); 4173f453ba04SDave Airlie kfree(property); 4174f453ba04SDave Airlie } 4175f453ba04SDave Airlie EXPORT_SYMBOL(drm_property_destroy); 4176f453ba04SDave Airlie 4177c8e32cc1SDaniel Vetter /** 4178c8e32cc1SDaniel Vetter * drm_object_attach_property - attach a property to a modeset object 4179c8e32cc1SDaniel Vetter * @obj: drm modeset object 4180c8e32cc1SDaniel Vetter * @property: property to attach 4181c8e32cc1SDaniel Vetter * @init_val: initial value of the property 4182c8e32cc1SDaniel Vetter * 4183c8e32cc1SDaniel Vetter * This attaches the given property to the modeset object with the given initial 4184c8e32cc1SDaniel Vetter * value. Currently this function cannot fail since the properties are stored in 4185c8e32cc1SDaniel Vetter * a statically sized array. 4186c8e32cc1SDaniel Vetter */ 4187c543188aSPaulo Zanoni void drm_object_attach_property(struct drm_mode_object *obj, 4188c543188aSPaulo Zanoni struct drm_property *property, 4189c543188aSPaulo Zanoni uint64_t init_val) 4190c543188aSPaulo Zanoni { 41917f88a9beSPaulo Zanoni int count = obj->properties->count; 4192c543188aSPaulo Zanoni 41937f88a9beSPaulo Zanoni if (count == DRM_OBJECT_MAX_PROPERTY) { 41947f88a9beSPaulo Zanoni WARN(1, "Failed to attach object property (type: 0x%x). Please " 41957f88a9beSPaulo Zanoni "increase DRM_OBJECT_MAX_PROPERTY by 1 for each time " 41967f88a9beSPaulo Zanoni "you see this message on the same object type.\n", 41977f88a9beSPaulo Zanoni obj->type); 4198c543188aSPaulo Zanoni return; 4199c543188aSPaulo Zanoni } 4200c543188aSPaulo Zanoni 4201b17cd757SRob Clark obj->properties->properties[count] = property; 42027f88a9beSPaulo Zanoni obj->properties->values[count] = init_val; 42037f88a9beSPaulo Zanoni obj->properties->count++; 420488a48e29SRob Clark if (property->flags & DRM_MODE_PROP_ATOMIC) 420588a48e29SRob Clark obj->properties->atomic_count++; 4206c543188aSPaulo Zanoni } 4207c543188aSPaulo Zanoni EXPORT_SYMBOL(drm_object_attach_property); 4208c543188aSPaulo Zanoni 4209c8e32cc1SDaniel Vetter /** 4210c8e32cc1SDaniel Vetter * drm_object_property_set_value - set the value of a property 4211c8e32cc1SDaniel Vetter * @obj: drm mode object to set property value for 4212c8e32cc1SDaniel Vetter * @property: property to set 4213c8e32cc1SDaniel Vetter * @val: value the property should be set to 4214c8e32cc1SDaniel Vetter * 4215c8e32cc1SDaniel Vetter * This functions sets a given property on a given object. This function only 4216c8e32cc1SDaniel Vetter * changes the software state of the property, it does not call into the 4217c8e32cc1SDaniel Vetter * driver's ->set_property callback. 4218c8e32cc1SDaniel Vetter * 4219c8e32cc1SDaniel Vetter * Returns: 4220c8e32cc1SDaniel Vetter * Zero on success, error code on failure. 4221c8e32cc1SDaniel Vetter */ 4222c543188aSPaulo Zanoni int drm_object_property_set_value(struct drm_mode_object *obj, 4223c543188aSPaulo Zanoni struct drm_property *property, uint64_t val) 4224c543188aSPaulo Zanoni { 4225c543188aSPaulo Zanoni int i; 4226c543188aSPaulo Zanoni 42277f88a9beSPaulo Zanoni for (i = 0; i < obj->properties->count; i++) { 4228b17cd757SRob Clark if (obj->properties->properties[i] == property) { 4229c543188aSPaulo Zanoni obj->properties->values[i] = val; 4230c543188aSPaulo Zanoni return 0; 4231c543188aSPaulo Zanoni } 4232c543188aSPaulo Zanoni } 4233c543188aSPaulo Zanoni 4234c543188aSPaulo Zanoni return -EINVAL; 4235c543188aSPaulo Zanoni } 4236c543188aSPaulo Zanoni EXPORT_SYMBOL(drm_object_property_set_value); 4237c543188aSPaulo Zanoni 4238c8e32cc1SDaniel Vetter /** 4239c8e32cc1SDaniel Vetter * drm_object_property_get_value - retrieve the value of a property 4240c8e32cc1SDaniel Vetter * @obj: drm mode object to get property value from 4241c8e32cc1SDaniel Vetter * @property: property to retrieve 4242c8e32cc1SDaniel Vetter * @val: storage for the property value 4243c8e32cc1SDaniel Vetter * 4244c8e32cc1SDaniel Vetter * This function retrieves the softare state of the given property for the given 4245c8e32cc1SDaniel Vetter * property. Since there is no driver callback to retrieve the current property 4246c8e32cc1SDaniel Vetter * value this might be out of sync with the hardware, depending upon the driver 4247c8e32cc1SDaniel Vetter * and property. 4248c8e32cc1SDaniel Vetter * 4249c8e32cc1SDaniel Vetter * Returns: 4250c8e32cc1SDaniel Vetter * Zero on success, error code on failure. 4251c8e32cc1SDaniel Vetter */ 4252c543188aSPaulo Zanoni int drm_object_property_get_value(struct drm_mode_object *obj, 4253c543188aSPaulo Zanoni struct drm_property *property, uint64_t *val) 4254c543188aSPaulo Zanoni { 4255c543188aSPaulo Zanoni int i; 4256c543188aSPaulo Zanoni 425788a48e29SRob Clark /* read-only properties bypass atomic mechanism and still store 425888a48e29SRob Clark * their value in obj->properties->values[].. mostly to avoid 425988a48e29SRob Clark * having to deal w/ EDID and similar props in atomic paths: 426088a48e29SRob Clark */ 426188a48e29SRob Clark if (drm_core_check_feature(property->dev, DRIVER_ATOMIC) && 426288a48e29SRob Clark !(property->flags & DRM_MODE_PROP_IMMUTABLE)) 426388a48e29SRob Clark return drm_atomic_get_property(obj, property, val); 426488a48e29SRob Clark 42657f88a9beSPaulo Zanoni for (i = 0; i < obj->properties->count; i++) { 4266b17cd757SRob Clark if (obj->properties->properties[i] == property) { 4267c543188aSPaulo Zanoni *val = obj->properties->values[i]; 4268c543188aSPaulo Zanoni return 0; 4269c543188aSPaulo Zanoni } 4270c543188aSPaulo Zanoni } 4271c543188aSPaulo Zanoni 4272c543188aSPaulo Zanoni return -EINVAL; 4273c543188aSPaulo Zanoni } 4274c543188aSPaulo Zanoni EXPORT_SYMBOL(drm_object_property_get_value); 4275c543188aSPaulo Zanoni 4276c8e32cc1SDaniel Vetter /** 42771a498633SDaniel Vetter * drm_mode_getproperty_ioctl - get the property metadata 4278c8e32cc1SDaniel Vetter * @dev: DRM device 4279c8e32cc1SDaniel Vetter * @data: ioctl data 4280c8e32cc1SDaniel Vetter * @file_priv: DRM file info 4281c8e32cc1SDaniel Vetter * 42821a498633SDaniel Vetter * This function retrieves the metadata for a given property, like the different 42831a498633SDaniel Vetter * possible values for an enum property or the limits for a range property. 42841a498633SDaniel Vetter * 42851a498633SDaniel Vetter * Blob properties are special 4286c8e32cc1SDaniel Vetter * 4287c8e32cc1SDaniel Vetter * Called by the user via ioctl. 4288c8e32cc1SDaniel Vetter * 4289c8e32cc1SDaniel Vetter * Returns: 42901a498633SDaniel Vetter * Zero on success, negative errno on failure. 4291c8e32cc1SDaniel Vetter */ 4292f453ba04SDave Airlie int drm_mode_getproperty_ioctl(struct drm_device *dev, 4293f453ba04SDave Airlie void *data, struct drm_file *file_priv) 4294f453ba04SDave Airlie { 4295f453ba04SDave Airlie struct drm_mode_get_property *out_resp = data; 4296f453ba04SDave Airlie struct drm_property *property; 4297f453ba04SDave Airlie int enum_count = 0; 4298f453ba04SDave Airlie int value_count = 0; 4299f453ba04SDave Airlie int ret = 0, i; 4300f453ba04SDave Airlie int copied; 4301f453ba04SDave Airlie struct drm_property_enum *prop_enum; 4302f453ba04SDave Airlie struct drm_mode_property_enum __user *enum_ptr; 4303f453ba04SDave Airlie uint64_t __user *values_ptr; 4304f453ba04SDave Airlie 4305fb3b06c8SDave Airlie if (!drm_core_check_feature(dev, DRIVER_MODESET)) 4306fb3b06c8SDave Airlie return -EINVAL; 4307fb3b06c8SDave Airlie 430884849903SDaniel Vetter drm_modeset_lock_all(dev); 4309a2b34e22SRob Clark property = drm_property_find(dev, out_resp->prop_id); 4310a2b34e22SRob Clark if (!property) { 4311f27657f2SVille Syrjälä ret = -ENOENT; 4312f453ba04SDave Airlie goto done; 4313f453ba04SDave Airlie } 4314f453ba04SDave Airlie 43155ea22f24SRob Clark if (drm_property_type_is(property, DRM_MODE_PROP_ENUM) || 43165ea22f24SRob Clark drm_property_type_is(property, DRM_MODE_PROP_BITMASK)) { 43173758b341SDaniel Vetter list_for_each_entry(prop_enum, &property->enum_list, head) 4318f453ba04SDave Airlie enum_count++; 4319f453ba04SDave Airlie } 4320f453ba04SDave Airlie 4321f453ba04SDave Airlie value_count = property->num_values; 4322f453ba04SDave Airlie 4323f453ba04SDave Airlie strncpy(out_resp->name, property->name, DRM_PROP_NAME_LEN); 4324f453ba04SDave Airlie out_resp->name[DRM_PROP_NAME_LEN-1] = 0; 4325f453ba04SDave Airlie out_resp->flags = property->flags; 4326f453ba04SDave Airlie 4327f453ba04SDave Airlie if ((out_resp->count_values >= value_count) && value_count) { 432881f6c7f8SVille Syrjälä values_ptr = (uint64_t __user *)(unsigned long)out_resp->values_ptr; 4329f453ba04SDave Airlie for (i = 0; i < value_count; i++) { 4330f453ba04SDave Airlie if (copy_to_user(values_ptr + i, &property->values[i], sizeof(uint64_t))) { 4331f453ba04SDave Airlie ret = -EFAULT; 4332f453ba04SDave Airlie goto done; 4333f453ba04SDave Airlie } 4334f453ba04SDave Airlie } 4335f453ba04SDave Airlie } 4336f453ba04SDave Airlie out_resp->count_values = value_count; 4337f453ba04SDave Airlie 43385ea22f24SRob Clark if (drm_property_type_is(property, DRM_MODE_PROP_ENUM) || 43395ea22f24SRob Clark drm_property_type_is(property, DRM_MODE_PROP_BITMASK)) { 4340f453ba04SDave Airlie if ((out_resp->count_enum_blobs >= enum_count) && enum_count) { 4341f453ba04SDave Airlie copied = 0; 434281f6c7f8SVille Syrjälä enum_ptr = (struct drm_mode_property_enum __user *)(unsigned long)out_resp->enum_blob_ptr; 43433758b341SDaniel Vetter list_for_each_entry(prop_enum, &property->enum_list, head) { 4344f453ba04SDave Airlie 4345f453ba04SDave Airlie if (copy_to_user(&enum_ptr[copied].value, &prop_enum->value, sizeof(uint64_t))) { 4346f453ba04SDave Airlie ret = -EFAULT; 4347f453ba04SDave Airlie goto done; 4348f453ba04SDave Airlie } 4349f453ba04SDave Airlie 4350f453ba04SDave Airlie if (copy_to_user(&enum_ptr[copied].name, 4351f453ba04SDave Airlie &prop_enum->name, DRM_PROP_NAME_LEN)) { 4352f453ba04SDave Airlie ret = -EFAULT; 4353f453ba04SDave Airlie goto done; 4354f453ba04SDave Airlie } 4355f453ba04SDave Airlie copied++; 4356f453ba04SDave Airlie } 4357f453ba04SDave Airlie } 4358f453ba04SDave Airlie out_resp->count_enum_blobs = enum_count; 4359f453ba04SDave Airlie } 4360f453ba04SDave Airlie 43613758b341SDaniel Vetter /* 43623758b341SDaniel Vetter * NOTE: The idea seems to have been to use this to read all the blob 43633758b341SDaniel Vetter * property values. But nothing ever added them to the corresponding 43643758b341SDaniel Vetter * list, userspace always used the special-purpose get_blob ioctl to 43653758b341SDaniel Vetter * read the value for a blob property. It also doesn't make a lot of 43663758b341SDaniel Vetter * sense to return values here when everything else is just metadata for 43673758b341SDaniel Vetter * the property itself. 43683758b341SDaniel Vetter */ 43693758b341SDaniel Vetter if (drm_property_type_is(property, DRM_MODE_PROP_BLOB)) 43703758b341SDaniel Vetter out_resp->count_enum_blobs = 0; 4371f453ba04SDave Airlie done: 437284849903SDaniel Vetter drm_modeset_unlock_all(dev); 4373f453ba04SDave Airlie return ret; 4374f453ba04SDave Airlie } 4375f453ba04SDave Airlie 4376152ef5faSDaniel Vetter static void drm_property_free_blob(struct kref *kref) 4377152ef5faSDaniel Vetter { 4378152ef5faSDaniel Vetter struct drm_property_blob *blob = 4379152ef5faSDaniel Vetter container_of(kref, struct drm_property_blob, base.refcount); 4380152ef5faSDaniel Vetter 4381152ef5faSDaniel Vetter mutex_lock(&blob->dev->mode_config.blob_lock); 4382152ef5faSDaniel Vetter list_del(&blob->head_global); 4383152ef5faSDaniel Vetter mutex_unlock(&blob->dev->mode_config.blob_lock); 4384152ef5faSDaniel Vetter 4385152ef5faSDaniel Vetter drm_mode_object_unregister(blob->dev, &blob->base); 4386152ef5faSDaniel Vetter 4387152ef5faSDaniel Vetter kfree(blob); 4388152ef5faSDaniel Vetter } 4389152ef5faSDaniel Vetter 439099531d9bSDaniel Stone /** 439199531d9bSDaniel Stone * drm_property_create_blob - Create new blob property 439299531d9bSDaniel Stone * 439399531d9bSDaniel Stone * Creates a new blob property for a specified DRM device, optionally 439499531d9bSDaniel Stone * copying data. 439599531d9bSDaniel Stone * 439699531d9bSDaniel Stone * @dev: DRM device to create property for 439799531d9bSDaniel Stone * @length: Length to allocate for blob data 439899531d9bSDaniel Stone * @data: If specified, copies data into blob 439910e8cb7eSDaniel Stone * 440010e8cb7eSDaniel Stone * Returns: 440110e8cb7eSDaniel Stone * New blob property with a single reference on success, or an ERR_PTR 440210e8cb7eSDaniel Stone * value on failure. 440399531d9bSDaniel Stone */ 44046bcacf51SDaniel Stone struct drm_property_blob * 4405ecbbe59bSThierry Reding drm_property_create_blob(struct drm_device *dev, size_t length, 440612e6cecdSThierry Reding const void *data) 4407f453ba04SDave Airlie { 4408f453ba04SDave Airlie struct drm_property_blob *blob; 44096bfc56aaSVille Syrjälä int ret; 4410f453ba04SDave Airlie 44119ac0934bSDan Carpenter if (!length || length > ULONG_MAX - sizeof(struct drm_property_blob)) 441210e8cb7eSDaniel Stone return ERR_PTR(-EINVAL); 4413f453ba04SDave Airlie 4414f453ba04SDave Airlie blob = kzalloc(sizeof(struct drm_property_blob)+length, GFP_KERNEL); 4415f453ba04SDave Airlie if (!blob) 441610e8cb7eSDaniel Stone return ERR_PTR(-ENOMEM); 4417f453ba04SDave Airlie 4418e2f5d2eaSDaniel Stone /* This must be explicitly initialised, so we can safely call list_del 4419e2f5d2eaSDaniel Stone * on it in the removal handler, even if it isn't in a file list. */ 4420e2f5d2eaSDaniel Stone INIT_LIST_HEAD(&blob->head_file); 4421f453ba04SDave Airlie blob->length = length; 44226bcacf51SDaniel Stone blob->dev = dev; 4423f453ba04SDave Airlie 442499531d9bSDaniel Stone if (data) 4425f453ba04SDave Airlie memcpy(blob->data, data, length); 4426f453ba04SDave Airlie 4427152ef5faSDaniel Vetter ret = drm_mode_object_get_reg(dev, &blob->base, DRM_MODE_OBJECT_BLOB, 4428152ef5faSDaniel Vetter true, drm_property_free_blob); 44298fb6e7a5SDaniel Stone if (ret) { 44308fb6e7a5SDaniel Stone kfree(blob); 443110e8cb7eSDaniel Stone return ERR_PTR(-EINVAL); 44328fb6e7a5SDaniel Stone } 44338fb6e7a5SDaniel Stone 4434152ef5faSDaniel Vetter mutex_lock(&dev->mode_config.blob_lock); 4435e2f5d2eaSDaniel Stone list_add_tail(&blob->head_global, 4436e2f5d2eaSDaniel Stone &dev->mode_config.property_blob_list); 44378fb6e7a5SDaniel Stone mutex_unlock(&dev->mode_config.blob_lock); 44388fb6e7a5SDaniel Stone 4439f453ba04SDave Airlie return blob; 4440f453ba04SDave Airlie } 44416bcacf51SDaniel Stone EXPORT_SYMBOL(drm_property_create_blob); 4442f453ba04SDave Airlie 44436bcacf51SDaniel Stone /** 44446bcacf51SDaniel Stone * drm_property_unreference_blob - Unreference a blob property 44456bcacf51SDaniel Stone * 44466bcacf51SDaniel Stone * Drop a reference on a blob property. May free the object. 44476bcacf51SDaniel Stone * 4448f102c16eSDaniel Stone * @blob: Pointer to blob property 44496bcacf51SDaniel Stone */ 44506bcacf51SDaniel Stone void drm_property_unreference_blob(struct drm_property_blob *blob) 44516bcacf51SDaniel Stone { 44526bcacf51SDaniel Stone if (!blob) 44536bcacf51SDaniel Stone return; 44546bcacf51SDaniel Stone 4455152ef5faSDaniel Vetter drm_mode_object_unreference(&blob->base); 44566bcacf51SDaniel Stone } 44576bcacf51SDaniel Stone EXPORT_SYMBOL(drm_property_unreference_blob); 44586bcacf51SDaniel Stone 44596bcacf51SDaniel Stone /** 4460e2f5d2eaSDaniel Stone * drm_property_destroy_user_blobs - destroy all blobs created by this client 4461e2f5d2eaSDaniel Stone * @dev: DRM device 4462e2f5d2eaSDaniel Stone * @file_priv: destroy all blobs owned by this file handle 4463e2f5d2eaSDaniel Stone */ 4464e2f5d2eaSDaniel Stone void drm_property_destroy_user_blobs(struct drm_device *dev, 4465e2f5d2eaSDaniel Stone struct drm_file *file_priv) 4466e2f5d2eaSDaniel Stone { 4467e2f5d2eaSDaniel Stone struct drm_property_blob *blob, *bt; 4468e2f5d2eaSDaniel Stone 4469152ef5faSDaniel Vetter /* 4470152ef5faSDaniel Vetter * When the file gets released that means no one else can access the 4471152ef5faSDaniel Vetter * blob list any more, so no need to grab dev->blob_lock. 4472152ef5faSDaniel Vetter */ 4473e2f5d2eaSDaniel Stone list_for_each_entry_safe(blob, bt, &file_priv->blobs, head_file) { 4474e2f5d2eaSDaniel Stone list_del_init(&blob->head_file); 4475152ef5faSDaniel Vetter drm_property_unreference_blob(blob); 4476e2f5d2eaSDaniel Stone } 4477e2f5d2eaSDaniel Stone } 4478e2f5d2eaSDaniel Stone 4479e2f5d2eaSDaniel Stone /** 44806bcacf51SDaniel Stone * drm_property_reference_blob - Take a reference on an existing property 44816bcacf51SDaniel Stone * 44826bcacf51SDaniel Stone * Take a new reference on an existing blob property. 44836bcacf51SDaniel Stone * 4484f102c16eSDaniel Stone * @blob: Pointer to blob property 44856bcacf51SDaniel Stone */ 44866bcacf51SDaniel Stone struct drm_property_blob *drm_property_reference_blob(struct drm_property_blob *blob) 44876bcacf51SDaniel Stone { 4488152ef5faSDaniel Vetter drm_mode_object_reference(&blob->base); 44896bcacf51SDaniel Stone return blob; 44906bcacf51SDaniel Stone } 44916bcacf51SDaniel Stone EXPORT_SYMBOL(drm_property_reference_blob); 44926bcacf51SDaniel Stone 44936bcacf51SDaniel Stone /** 44946bcacf51SDaniel Stone * drm_property_lookup_blob - look up a blob property and take a reference 44956bcacf51SDaniel Stone * @dev: drm device 44966bcacf51SDaniel Stone * @id: id of the blob property 44976bcacf51SDaniel Stone * 44986bcacf51SDaniel Stone * If successful, this takes an additional reference to the blob property. 44996bcacf51SDaniel Stone * callers need to make sure to eventually unreference the returned property 45006bcacf51SDaniel Stone * again, using @drm_property_unreference_blob. 45016bcacf51SDaniel Stone */ 45026bcacf51SDaniel Stone struct drm_property_blob *drm_property_lookup_blob(struct drm_device *dev, 45036bcacf51SDaniel Stone uint32_t id) 4504f453ba04SDave Airlie { 4505152ef5faSDaniel Vetter struct drm_mode_object *obj; 4506152ef5faSDaniel Vetter struct drm_property_blob *blob = NULL; 45076bcacf51SDaniel Stone 4508152ef5faSDaniel Vetter obj = _object_find(dev, id, DRM_MODE_OBJECT_BLOB); 4509152ef5faSDaniel Vetter if (obj) 4510152ef5faSDaniel Vetter blob = obj_to_blob(obj); 45116bcacf51SDaniel Stone return blob; 45126bcacf51SDaniel Stone } 45136bcacf51SDaniel Stone EXPORT_SYMBOL(drm_property_lookup_blob); 45146bcacf51SDaniel Stone 45156bcacf51SDaniel Stone /** 4516d2ed3436SDaniel Stone * drm_property_replace_global_blob - atomically replace existing blob property 4517d2ed3436SDaniel Stone * @dev: drm device 4518d2ed3436SDaniel Stone * @replace: location of blob property pointer to be replaced 4519d2ed3436SDaniel Stone * @length: length of data for new blob, or 0 for no data 4520d2ed3436SDaniel Stone * @data: content for new blob, or NULL for no data 4521d2ed3436SDaniel Stone * @obj_holds_id: optional object for property holding blob ID 4522d2ed3436SDaniel Stone * @prop_holds_id: optional property holding blob ID 4523d2ed3436SDaniel Stone * @return 0 on success or error on failure 4524d2ed3436SDaniel Stone * 4525d2ed3436SDaniel Stone * This function will atomically replace a global property in the blob list, 4526d2ed3436SDaniel Stone * optionally updating a property which holds the ID of that property. It is 4527d2ed3436SDaniel Stone * guaranteed to be atomic: no caller will be allowed to see intermediate 4528d2ed3436SDaniel Stone * results, and either the entire operation will succeed and clean up the 4529d2ed3436SDaniel Stone * previous property, or it will fail and the state will be unchanged. 4530d2ed3436SDaniel Stone * 4531d2ed3436SDaniel Stone * If length is 0 or data is NULL, no new blob will be created, and the holding 4532d2ed3436SDaniel Stone * property, if specified, will be set to 0. 4533d2ed3436SDaniel Stone * 4534d2ed3436SDaniel Stone * Access to the replace pointer is assumed to be protected by the caller, e.g. 4535d2ed3436SDaniel Stone * by holding the relevant modesetting object lock for its parent. 4536d2ed3436SDaniel Stone * 4537d2ed3436SDaniel Stone * For example, a drm_connector has a 'PATH' property, which contains the ID 4538d2ed3436SDaniel Stone * of a blob property with the value of the MST path information. Calling this 4539d2ed3436SDaniel Stone * function with replace pointing to the connector's path_blob_ptr, length and 4540d2ed3436SDaniel Stone * data set for the new path information, obj_holds_id set to the connector's 4541d2ed3436SDaniel Stone * base object, and prop_holds_id set to the path property name, will perform 4542d2ed3436SDaniel Stone * a completely atomic update. The access to path_blob_ptr is protected by the 4543d2ed3436SDaniel Stone * caller holding a lock on the connector. 4544d2ed3436SDaniel Stone */ 4545d2ed3436SDaniel Stone static int drm_property_replace_global_blob(struct drm_device *dev, 4546d2ed3436SDaniel Stone struct drm_property_blob **replace, 4547d2ed3436SDaniel Stone size_t length, 4548d2ed3436SDaniel Stone const void *data, 4549d2ed3436SDaniel Stone struct drm_mode_object *obj_holds_id, 4550d2ed3436SDaniel Stone struct drm_property *prop_holds_id) 4551d2ed3436SDaniel Stone { 4552d2ed3436SDaniel Stone struct drm_property_blob *new_blob = NULL; 4553d2ed3436SDaniel Stone struct drm_property_blob *old_blob = NULL; 4554d2ed3436SDaniel Stone int ret; 4555d2ed3436SDaniel Stone 4556d2ed3436SDaniel Stone WARN_ON(replace == NULL); 4557d2ed3436SDaniel Stone 4558d2ed3436SDaniel Stone old_blob = *replace; 4559d2ed3436SDaniel Stone 4560d2ed3436SDaniel Stone if (length && data) { 4561d2ed3436SDaniel Stone new_blob = drm_property_create_blob(dev, length, data); 456210e8cb7eSDaniel Stone if (IS_ERR(new_blob)) 456310e8cb7eSDaniel Stone return PTR_ERR(new_blob); 4564d2ed3436SDaniel Stone } 4565d2ed3436SDaniel Stone 4566d2ed3436SDaniel Stone /* This does not need to be synchronised with blob_lock, as the 4567d2ed3436SDaniel Stone * get_properties ioctl locks all modesetting objects, and 4568d2ed3436SDaniel Stone * obj_holds_id must be locked before calling here, so we cannot 4569d2ed3436SDaniel Stone * have its value out of sync with the list membership modified 4570d2ed3436SDaniel Stone * below under blob_lock. */ 4571d2ed3436SDaniel Stone if (obj_holds_id) { 4572d2ed3436SDaniel Stone ret = drm_object_property_set_value(obj_holds_id, 4573d2ed3436SDaniel Stone prop_holds_id, 4574d2ed3436SDaniel Stone new_blob ? 4575d2ed3436SDaniel Stone new_blob->base.id : 0); 4576d2ed3436SDaniel Stone if (ret != 0) 4577d2ed3436SDaniel Stone goto err_created; 4578d2ed3436SDaniel Stone } 4579d2ed3436SDaniel Stone 45806bcacf51SDaniel Stone drm_property_unreference_blob(old_blob); 4581d2ed3436SDaniel Stone *replace = new_blob; 4582d2ed3436SDaniel Stone 4583d2ed3436SDaniel Stone return 0; 4584d2ed3436SDaniel Stone 4585d2ed3436SDaniel Stone err_created: 45866bcacf51SDaniel Stone drm_property_unreference_blob(new_blob); 4587d2ed3436SDaniel Stone return ret; 4588f453ba04SDave Airlie } 4589f453ba04SDave Airlie 4590c8e32cc1SDaniel Vetter /** 4591c8e32cc1SDaniel Vetter * drm_mode_getblob_ioctl - get the contents of a blob property value 4592c8e32cc1SDaniel Vetter * @dev: DRM device 4593c8e32cc1SDaniel Vetter * @data: ioctl data 4594c8e32cc1SDaniel Vetter * @file_priv: DRM file info 4595c8e32cc1SDaniel Vetter * 4596c8e32cc1SDaniel Vetter * This function retrieves the contents of a blob property. The value stored in 4597c8e32cc1SDaniel Vetter * an object's blob property is just a normal modeset object id. 4598c8e32cc1SDaniel Vetter * 4599c8e32cc1SDaniel Vetter * Called by the user via ioctl. 4600c8e32cc1SDaniel Vetter * 4601c8e32cc1SDaniel Vetter * Returns: 46021a498633SDaniel Vetter * Zero on success, negative errno on failure. 4603c8e32cc1SDaniel Vetter */ 4604f453ba04SDave Airlie int drm_mode_getblob_ioctl(struct drm_device *dev, 4605f453ba04SDave Airlie void *data, struct drm_file *file_priv) 4606f453ba04SDave Airlie { 4607f453ba04SDave Airlie struct drm_mode_get_blob *out_resp = data; 4608f453ba04SDave Airlie struct drm_property_blob *blob; 4609f453ba04SDave Airlie int ret = 0; 461081f6c7f8SVille Syrjälä void __user *blob_ptr; 4611f453ba04SDave Airlie 4612fb3b06c8SDave Airlie if (!drm_core_check_feature(dev, DRIVER_MODESET)) 4613fb3b06c8SDave Airlie return -EINVAL; 4614fb3b06c8SDave Airlie 4615152ef5faSDaniel Vetter blob = drm_property_lookup_blob(dev, out_resp->blob_id); 4616152ef5faSDaniel Vetter if (!blob) 4617152ef5faSDaniel Vetter return -ENOENT; 4618f453ba04SDave Airlie 4619f453ba04SDave Airlie if (out_resp->length == blob->length) { 462081f6c7f8SVille Syrjälä blob_ptr = (void __user *)(unsigned long)out_resp->data; 4621f453ba04SDave Airlie if (copy_to_user(blob_ptr, blob->data, blob->length)) { 4622f453ba04SDave Airlie ret = -EFAULT; 4623152ef5faSDaniel Vetter goto unref; 4624f453ba04SDave Airlie } 4625f453ba04SDave Airlie } 4626f453ba04SDave Airlie out_resp->length = blob->length; 4627152ef5faSDaniel Vetter unref: 4628152ef5faSDaniel Vetter drm_property_unreference_blob(blob); 4629f453ba04SDave Airlie 4630f453ba04SDave Airlie return ret; 4631f453ba04SDave Airlie } 4632f453ba04SDave Airlie 4633cc7096fbSDave Airlie /** 4634e2f5d2eaSDaniel Stone * drm_mode_createblob_ioctl - create a new blob property 4635e2f5d2eaSDaniel Stone * @dev: DRM device 4636e2f5d2eaSDaniel Stone * @data: ioctl data 4637e2f5d2eaSDaniel Stone * @file_priv: DRM file info 4638e2f5d2eaSDaniel Stone * 4639e2f5d2eaSDaniel Stone * This function creates a new blob property with user-defined values. In order 4640e2f5d2eaSDaniel Stone * to give us sensible validation and checking when creating, rather than at 4641e2f5d2eaSDaniel Stone * every potential use, we also require a type to be provided upfront. 4642e2f5d2eaSDaniel Stone * 4643e2f5d2eaSDaniel Stone * Called by the user via ioctl. 4644e2f5d2eaSDaniel Stone * 4645e2f5d2eaSDaniel Stone * Returns: 4646e2f5d2eaSDaniel Stone * Zero on success, negative errno on failure. 4647e2f5d2eaSDaniel Stone */ 4648e2f5d2eaSDaniel Stone int drm_mode_createblob_ioctl(struct drm_device *dev, 4649e2f5d2eaSDaniel Stone void *data, struct drm_file *file_priv) 4650e2f5d2eaSDaniel Stone { 4651e2f5d2eaSDaniel Stone struct drm_mode_create_blob *out_resp = data; 4652e2f5d2eaSDaniel Stone struct drm_property_blob *blob; 4653e2f5d2eaSDaniel Stone void __user *blob_ptr; 4654e2f5d2eaSDaniel Stone int ret = 0; 4655e2f5d2eaSDaniel Stone 4656e2f5d2eaSDaniel Stone if (!drm_core_check_feature(dev, DRIVER_MODESET)) 4657e2f5d2eaSDaniel Stone return -EINVAL; 4658e2f5d2eaSDaniel Stone 4659e2f5d2eaSDaniel Stone blob = drm_property_create_blob(dev, out_resp->length, NULL); 4660e2f5d2eaSDaniel Stone if (IS_ERR(blob)) 4661e2f5d2eaSDaniel Stone return PTR_ERR(blob); 4662e2f5d2eaSDaniel Stone 4663e2f5d2eaSDaniel Stone blob_ptr = (void __user *)(unsigned long)out_resp->data; 4664e2f5d2eaSDaniel Stone if (copy_from_user(blob->data, blob_ptr, out_resp->length)) { 4665e2f5d2eaSDaniel Stone ret = -EFAULT; 4666e2f5d2eaSDaniel Stone goto out_blob; 4667e2f5d2eaSDaniel Stone } 4668e2f5d2eaSDaniel Stone 4669e2f5d2eaSDaniel Stone /* Dropping the lock between create_blob and our access here is safe 4670e2f5d2eaSDaniel Stone * as only the same file_priv can remove the blob; at this point, it is 4671e2f5d2eaSDaniel Stone * not associated with any file_priv. */ 4672e2f5d2eaSDaniel Stone mutex_lock(&dev->mode_config.blob_lock); 4673e2f5d2eaSDaniel Stone out_resp->blob_id = blob->base.id; 46748731b269SManeet Singh list_add_tail(&blob->head_file, &file_priv->blobs); 4675e2f5d2eaSDaniel Stone mutex_unlock(&dev->mode_config.blob_lock); 4676e2f5d2eaSDaniel Stone 4677e2f5d2eaSDaniel Stone return 0; 4678e2f5d2eaSDaniel Stone 4679e2f5d2eaSDaniel Stone out_blob: 4680e2f5d2eaSDaniel Stone drm_property_unreference_blob(blob); 4681e2f5d2eaSDaniel Stone return ret; 4682e2f5d2eaSDaniel Stone } 4683e2f5d2eaSDaniel Stone 4684e2f5d2eaSDaniel Stone /** 4685e2f5d2eaSDaniel Stone * drm_mode_destroyblob_ioctl - destroy a user blob property 4686e2f5d2eaSDaniel Stone * @dev: DRM device 4687e2f5d2eaSDaniel Stone * @data: ioctl data 4688e2f5d2eaSDaniel Stone * @file_priv: DRM file info 4689e2f5d2eaSDaniel Stone * 4690e2f5d2eaSDaniel Stone * Destroy an existing user-defined blob property. 4691e2f5d2eaSDaniel Stone * 4692e2f5d2eaSDaniel Stone * Called by the user via ioctl. 4693e2f5d2eaSDaniel Stone * 4694e2f5d2eaSDaniel Stone * Returns: 4695e2f5d2eaSDaniel Stone * Zero on success, negative errno on failure. 4696e2f5d2eaSDaniel Stone */ 4697e2f5d2eaSDaniel Stone int drm_mode_destroyblob_ioctl(struct drm_device *dev, 4698e2f5d2eaSDaniel Stone void *data, struct drm_file *file_priv) 4699e2f5d2eaSDaniel Stone { 4700e2f5d2eaSDaniel Stone struct drm_mode_destroy_blob *out_resp = data; 4701e2f5d2eaSDaniel Stone struct drm_property_blob *blob = NULL, *bt; 4702e2f5d2eaSDaniel Stone bool found = false; 4703e2f5d2eaSDaniel Stone int ret = 0; 4704e2f5d2eaSDaniel Stone 4705e2f5d2eaSDaniel Stone if (!drm_core_check_feature(dev, DRIVER_MODESET)) 4706e2f5d2eaSDaniel Stone return -EINVAL; 4707e2f5d2eaSDaniel Stone 4708152ef5faSDaniel Vetter blob = drm_property_lookup_blob(dev, out_resp->blob_id); 4709152ef5faSDaniel Vetter if (!blob) 4710152ef5faSDaniel Vetter return -ENOENT; 4711e2f5d2eaSDaniel Stone 4712152ef5faSDaniel Vetter mutex_lock(&dev->mode_config.blob_lock); 4713e2f5d2eaSDaniel Stone /* Ensure the property was actually created by this user. */ 4714e2f5d2eaSDaniel Stone list_for_each_entry(bt, &file_priv->blobs, head_file) { 4715e2f5d2eaSDaniel Stone if (bt == blob) { 4716e2f5d2eaSDaniel Stone found = true; 4717e2f5d2eaSDaniel Stone break; 4718e2f5d2eaSDaniel Stone } 4719e2f5d2eaSDaniel Stone } 4720e2f5d2eaSDaniel Stone 4721e2f5d2eaSDaniel Stone if (!found) { 4722e2f5d2eaSDaniel Stone ret = -EPERM; 4723e2f5d2eaSDaniel Stone goto err; 4724e2f5d2eaSDaniel Stone } 4725e2f5d2eaSDaniel Stone 4726e2f5d2eaSDaniel Stone /* We must drop head_file here, because we may not be the last 4727e2f5d2eaSDaniel Stone * reference on the blob. */ 4728e2f5d2eaSDaniel Stone list_del_init(&blob->head_file); 4729e2f5d2eaSDaniel Stone mutex_unlock(&dev->mode_config.blob_lock); 4730e2f5d2eaSDaniel Stone 4731152ef5faSDaniel Vetter /* One reference from lookup, and one from the filp. */ 4732152ef5faSDaniel Vetter drm_property_unreference_blob(blob); 4733152ef5faSDaniel Vetter drm_property_unreference_blob(blob); 4734152ef5faSDaniel Vetter 4735e2f5d2eaSDaniel Stone return 0; 4736e2f5d2eaSDaniel Stone 4737e2f5d2eaSDaniel Stone err: 4738e2f5d2eaSDaniel Stone mutex_unlock(&dev->mode_config.blob_lock); 4739152ef5faSDaniel Vetter drm_property_unreference_blob(blob); 4740152ef5faSDaniel Vetter 4741e2f5d2eaSDaniel Stone return ret; 4742e2f5d2eaSDaniel Stone } 4743e2f5d2eaSDaniel Stone 4744e2f5d2eaSDaniel Stone /** 4745cc7096fbSDave Airlie * drm_mode_connector_set_path_property - set tile property on connector 4746cc7096fbSDave Airlie * @connector: connector to set property on. 4747d2ed3436SDaniel Stone * @path: path to use for property; must not be NULL. 4748cc7096fbSDave Airlie * 4749cc7096fbSDave Airlie * This creates a property to expose to userspace to specify a 4750cc7096fbSDave Airlie * connector path. This is mainly used for DisplayPort MST where 4751cc7096fbSDave Airlie * connectors have a topology and we want to allow userspace to give 4752cc7096fbSDave Airlie * them more meaningful names. 4753cc7096fbSDave Airlie * 4754cc7096fbSDave Airlie * Returns: 47551a498633SDaniel Vetter * Zero on success, negative errno on failure. 4756cc7096fbSDave Airlie */ 475743aba7ebSDave Airlie int drm_mode_connector_set_path_property(struct drm_connector *connector, 475812e6cecdSThierry Reding const char *path) 475943aba7ebSDave Airlie { 476043aba7ebSDave Airlie struct drm_device *dev = connector->dev; 4761ecbbe59bSThierry Reding int ret; 476243aba7ebSDave Airlie 4763d2ed3436SDaniel Stone ret = drm_property_replace_global_blob(dev, 4764d2ed3436SDaniel Stone &connector->path_blob_ptr, 4765d2ed3436SDaniel Stone strlen(path) + 1, 4766d2ed3436SDaniel Stone path, 4767d2ed3436SDaniel Stone &connector->base, 4768d2ed3436SDaniel Stone dev->mode_config.path_property); 476943aba7ebSDave Airlie return ret; 477043aba7ebSDave Airlie } 477143aba7ebSDave Airlie EXPORT_SYMBOL(drm_mode_connector_set_path_property); 477243aba7ebSDave Airlie 4773c8e32cc1SDaniel Vetter /** 47746f134d7bSDave Airlie * drm_mode_connector_set_tile_property - set tile property on connector 47756f134d7bSDave Airlie * @connector: connector to set property on. 47766f134d7bSDave Airlie * 47776f134d7bSDave Airlie * This looks up the tile information for a connector, and creates a 47786f134d7bSDave Airlie * property for userspace to parse if it exists. The property is of 47796f134d7bSDave Airlie * the form of 8 integers using ':' as a separator. 47806f134d7bSDave Airlie * 47816f134d7bSDave Airlie * Returns: 47826f134d7bSDave Airlie * Zero on success, errno on failure. 47836f134d7bSDave Airlie */ 47846f134d7bSDave Airlie int drm_mode_connector_set_tile_property(struct drm_connector *connector) 47856f134d7bSDave Airlie { 47866f134d7bSDave Airlie struct drm_device *dev = connector->dev; 47876f134d7bSDave Airlie char tile[256]; 4788d2ed3436SDaniel Stone int ret; 47896f134d7bSDave Airlie 47906f134d7bSDave Airlie if (!connector->has_tile) { 4791d2ed3436SDaniel Stone ret = drm_property_replace_global_blob(dev, 4792d2ed3436SDaniel Stone &connector->tile_blob_ptr, 4793d2ed3436SDaniel Stone 0, 4794d2ed3436SDaniel Stone NULL, 4795d2ed3436SDaniel Stone &connector->base, 4796d2ed3436SDaniel Stone dev->mode_config.tile_property); 47976f134d7bSDave Airlie return ret; 47986f134d7bSDave Airlie } 47996f134d7bSDave Airlie 48006f134d7bSDave Airlie snprintf(tile, 256, "%d:%d:%d:%d:%d:%d:%d:%d", 48016f134d7bSDave Airlie connector->tile_group->id, connector->tile_is_single_monitor, 48026f134d7bSDave Airlie connector->num_h_tile, connector->num_v_tile, 48036f134d7bSDave Airlie connector->tile_h_loc, connector->tile_v_loc, 48046f134d7bSDave Airlie connector->tile_h_size, connector->tile_v_size); 48056f134d7bSDave Airlie 4806d2ed3436SDaniel Stone ret = drm_property_replace_global_blob(dev, 4807d2ed3436SDaniel Stone &connector->tile_blob_ptr, 4808d2ed3436SDaniel Stone strlen(tile) + 1, 4809d2ed3436SDaniel Stone tile, 4810d2ed3436SDaniel Stone &connector->base, 4811d2ed3436SDaniel Stone dev->mode_config.tile_property); 48126f134d7bSDave Airlie return ret; 48136f134d7bSDave Airlie } 48146f134d7bSDave Airlie EXPORT_SYMBOL(drm_mode_connector_set_tile_property); 48156f134d7bSDave Airlie 48166f134d7bSDave Airlie /** 4817c8e32cc1SDaniel Vetter * drm_mode_connector_update_edid_property - update the edid property of a connector 4818c8e32cc1SDaniel Vetter * @connector: drm connector 4819c8e32cc1SDaniel Vetter * @edid: new value of the edid property 4820c8e32cc1SDaniel Vetter * 4821c8e32cc1SDaniel Vetter * This function creates a new blob modeset object and assigns its id to the 4822c8e32cc1SDaniel Vetter * connector's edid property. 4823c8e32cc1SDaniel Vetter * 4824c8e32cc1SDaniel Vetter * Returns: 48251a498633SDaniel Vetter * Zero on success, negative errno on failure. 4826c8e32cc1SDaniel Vetter */ 4827f453ba04SDave Airlie int drm_mode_connector_update_edid_property(struct drm_connector *connector, 482812e6cecdSThierry Reding const struct edid *edid) 4829f453ba04SDave Airlie { 4830f453ba04SDave Airlie struct drm_device *dev = connector->dev; 4831d2ed3436SDaniel Stone size_t size = 0; 4832ecbbe59bSThierry Reding int ret; 4833f453ba04SDave Airlie 48344cf2b281SThomas Wood /* ignore requests to set edid when overridden */ 48354cf2b281SThomas Wood if (connector->override_edid) 48364cf2b281SThomas Wood return 0; 48374cf2b281SThomas Wood 4838d2ed3436SDaniel Stone if (edid) 4839e24ff467SShixin Zeng size = EDID_LENGTH * (1 + edid->extensions); 4840f453ba04SDave Airlie 4841d2ed3436SDaniel Stone ret = drm_property_replace_global_blob(dev, 4842d2ed3436SDaniel Stone &connector->edid_blob_ptr, 4843d2ed3436SDaniel Stone size, 4844d2ed3436SDaniel Stone edid, 4845d2ed3436SDaniel Stone &connector->base, 4846d2ed3436SDaniel Stone dev->mode_config.edid_property); 4847f453ba04SDave Airlie return ret; 4848f453ba04SDave Airlie } 4849f453ba04SDave Airlie EXPORT_SYMBOL(drm_mode_connector_update_edid_property); 4850f453ba04SDave Airlie 48513843e71fSRob Clark /* Some properties could refer to dynamic refcnt'd objects, or things that 48523843e71fSRob Clark * need special locking to handle lifetime issues (ie. to ensure the prop 48533843e71fSRob Clark * value doesn't become invalid part way through the property update due to 48543843e71fSRob Clark * race). The value returned by reference via 'obj' should be passed back 48553843e71fSRob Clark * to drm_property_change_valid_put() after the property is set (and the 48563843e71fSRob Clark * object to which the property is attached has a chance to take it's own 48573843e71fSRob Clark * reference). 48583843e71fSRob Clark */ 4859d34f20d6SRob Clark bool drm_property_change_valid_get(struct drm_property *property, 48603843e71fSRob Clark uint64_t value, struct drm_mode_object **ref) 486126a34815SPaulo Zanoni { 48622ca651d1SThierry Reding int i; 48632ca651d1SThierry Reding 486426a34815SPaulo Zanoni if (property->flags & DRM_MODE_PROP_IMMUTABLE) 486526a34815SPaulo Zanoni return false; 48665ea22f24SRob Clark 48673843e71fSRob Clark *ref = NULL; 48683843e71fSRob Clark 48695ea22f24SRob Clark if (drm_property_type_is(property, DRM_MODE_PROP_RANGE)) { 487026a34815SPaulo Zanoni if (value < property->values[0] || value > property->values[1]) 487126a34815SPaulo Zanoni return false; 487226a34815SPaulo Zanoni return true; 4873ebc44cf3SRob Clark } else if (drm_property_type_is(property, DRM_MODE_PROP_SIGNED_RANGE)) { 4874ebc44cf3SRob Clark int64_t svalue = U642I64(value); 48754dfd909fSThierry Reding 4876ebc44cf3SRob Clark if (svalue < U642I64(property->values[0]) || 4877ebc44cf3SRob Clark svalue > U642I64(property->values[1])) 4878ebc44cf3SRob Clark return false; 4879ebc44cf3SRob Clark return true; 48805ea22f24SRob Clark } else if (drm_property_type_is(property, DRM_MODE_PROP_BITMASK)) { 4881592c20eeSVille Syrjälä uint64_t valid_mask = 0; 48824dfd909fSThierry Reding 488349e27545SRob Clark for (i = 0; i < property->num_values; i++) 488449e27545SRob Clark valid_mask |= (1ULL << property->values[i]); 488549e27545SRob Clark return !(value & ~valid_mask); 48865ea22f24SRob Clark } else if (drm_property_type_is(property, DRM_MODE_PROP_BLOB)) { 48876bcacf51SDaniel Stone struct drm_property_blob *blob; 48886bcacf51SDaniel Stone 48896bcacf51SDaniel Stone if (value == 0) 4890c4a56750SVille Syrjälä return true; 48916bcacf51SDaniel Stone 48926bcacf51SDaniel Stone blob = drm_property_lookup_blob(property->dev, value); 48936bcacf51SDaniel Stone if (blob) { 48946bcacf51SDaniel Stone *ref = &blob->base; 48956bcacf51SDaniel Stone return true; 48966bcacf51SDaniel Stone } else { 48976bcacf51SDaniel Stone return false; 48986bcacf51SDaniel Stone } 489998f75de4SRob Clark } else if (drm_property_type_is(property, DRM_MODE_PROP_OBJECT)) { 490098f75de4SRob Clark /* a zero value for an object property translates to null: */ 490198f75de4SRob Clark if (value == 0) 490298f75de4SRob Clark return true; 49033843e71fSRob Clark 49041e8985a8STomi Valkeinen *ref = _object_find(property->dev, value, property->values[0]); 49051e8985a8STomi Valkeinen return *ref != NULL; 49063843e71fSRob Clark } 49072ca651d1SThierry Reding 490826a34815SPaulo Zanoni for (i = 0; i < property->num_values; i++) 490926a34815SPaulo Zanoni if (property->values[i] == value) 491026a34815SPaulo Zanoni return true; 491126a34815SPaulo Zanoni return false; 491226a34815SPaulo Zanoni } 491326a34815SPaulo Zanoni 4914d34f20d6SRob Clark void drm_property_change_valid_put(struct drm_property *property, 49153843e71fSRob Clark struct drm_mode_object *ref) 49163843e71fSRob Clark { 49173843e71fSRob Clark if (!ref) 49183843e71fSRob Clark return; 49193843e71fSRob Clark 49203843e71fSRob Clark if (drm_property_type_is(property, DRM_MODE_PROP_OBJECT)) { 4921027b3f8bSDave Airlie drm_mode_object_unreference(ref); 4922da9b2a38SDaniel Stone } else if (drm_property_type_is(property, DRM_MODE_PROP_BLOB)) 4923da9b2a38SDaniel Stone drm_property_unreference_blob(obj_to_blob(ref)); 49243843e71fSRob Clark } 49253843e71fSRob Clark 4926c8e32cc1SDaniel Vetter /** 4927c8e32cc1SDaniel Vetter * drm_mode_connector_property_set_ioctl - set the current value of a connector property 4928c8e32cc1SDaniel Vetter * @dev: DRM device 4929c8e32cc1SDaniel Vetter * @data: ioctl data 4930c8e32cc1SDaniel Vetter * @file_priv: DRM file info 4931c8e32cc1SDaniel Vetter * 4932c8e32cc1SDaniel Vetter * This function sets the current value for a connectors's property. It also 4933c8e32cc1SDaniel Vetter * calls into a driver's ->set_property callback to update the hardware state 4934c8e32cc1SDaniel Vetter * 4935c8e32cc1SDaniel Vetter * Called by the user via ioctl. 4936c8e32cc1SDaniel Vetter * 4937c8e32cc1SDaniel Vetter * Returns: 49381a498633SDaniel Vetter * Zero on success, negative errno on failure. 4939c8e32cc1SDaniel Vetter */ 4940f453ba04SDave Airlie int drm_mode_connector_property_set_ioctl(struct drm_device *dev, 4941f453ba04SDave Airlie void *data, struct drm_file *file_priv) 4942f453ba04SDave Airlie { 49430057d8ddSPaulo Zanoni struct drm_mode_connector_set_property *conn_set_prop = data; 49440057d8ddSPaulo Zanoni struct drm_mode_obj_set_property obj_set_prop = { 49450057d8ddSPaulo Zanoni .value = conn_set_prop->value, 49460057d8ddSPaulo Zanoni .prop_id = conn_set_prop->prop_id, 49470057d8ddSPaulo Zanoni .obj_id = conn_set_prop->connector_id, 49480057d8ddSPaulo Zanoni .obj_type = DRM_MODE_OBJECT_CONNECTOR 49490057d8ddSPaulo Zanoni }; 4950f453ba04SDave Airlie 49510057d8ddSPaulo Zanoni /* It does all the locking and checking we need */ 49520057d8ddSPaulo Zanoni return drm_mode_obj_set_property_ioctl(dev, &obj_set_prop, file_priv); 4953f453ba04SDave Airlie } 4954f453ba04SDave Airlie 4955c543188aSPaulo Zanoni static int drm_mode_connector_set_obj_prop(struct drm_mode_object *obj, 4956c543188aSPaulo Zanoni struct drm_property *property, 4957c543188aSPaulo Zanoni uint64_t value) 4958c543188aSPaulo Zanoni { 4959c543188aSPaulo Zanoni int ret = -EINVAL; 4960c543188aSPaulo Zanoni struct drm_connector *connector = obj_to_connector(obj); 4961c543188aSPaulo Zanoni 4962c543188aSPaulo Zanoni /* Do DPMS ourselves */ 4963c543188aSPaulo Zanoni if (property == connector->dev->mode_config.dpms_property) { 49649a69a9acSMaarten Lankhorst ret = (*connector->funcs->dpms)(connector, (int)value); 4965c543188aSPaulo Zanoni } else if (connector->funcs->set_property) 4966c543188aSPaulo Zanoni ret = connector->funcs->set_property(connector, property, value); 4967c543188aSPaulo Zanoni 4968c543188aSPaulo Zanoni /* store the property value if successful */ 4969c543188aSPaulo Zanoni if (!ret) 497058495563SRob Clark drm_object_property_set_value(&connector->base, property, value); 4971c543188aSPaulo Zanoni return ret; 4972c543188aSPaulo Zanoni } 4973c543188aSPaulo Zanoni 4974bffd9de0SPaulo Zanoni static int drm_mode_crtc_set_obj_prop(struct drm_mode_object *obj, 4975bffd9de0SPaulo Zanoni struct drm_property *property, 4976bffd9de0SPaulo Zanoni uint64_t value) 4977bffd9de0SPaulo Zanoni { 4978bffd9de0SPaulo Zanoni int ret = -EINVAL; 4979bffd9de0SPaulo Zanoni struct drm_crtc *crtc = obj_to_crtc(obj); 4980bffd9de0SPaulo Zanoni 4981bffd9de0SPaulo Zanoni if (crtc->funcs->set_property) 4982bffd9de0SPaulo Zanoni ret = crtc->funcs->set_property(crtc, property, value); 4983bffd9de0SPaulo Zanoni if (!ret) 4984bffd9de0SPaulo Zanoni drm_object_property_set_value(obj, property, value); 4985bffd9de0SPaulo Zanoni 4986bffd9de0SPaulo Zanoni return ret; 4987bffd9de0SPaulo Zanoni } 4988bffd9de0SPaulo Zanoni 49893a5f87c2SThomas Wood /** 49903a5f87c2SThomas Wood * drm_mode_plane_set_obj_prop - set the value of a property 49913a5f87c2SThomas Wood * @plane: drm plane object to set property value for 49923a5f87c2SThomas Wood * @property: property to set 49933a5f87c2SThomas Wood * @value: value the property should be set to 49943a5f87c2SThomas Wood * 49953a5f87c2SThomas Wood * This functions sets a given property on a given plane object. This function 49963a5f87c2SThomas Wood * calls the driver's ->set_property callback and changes the software state of 49973a5f87c2SThomas Wood * the property if the callback succeeds. 49983a5f87c2SThomas Wood * 49993a5f87c2SThomas Wood * Returns: 50003a5f87c2SThomas Wood * Zero on success, error code on failure. 50013a5f87c2SThomas Wood */ 50023a5f87c2SThomas Wood int drm_mode_plane_set_obj_prop(struct drm_plane *plane, 50034d93914aSRob Clark struct drm_property *property, 50044d93914aSRob Clark uint64_t value) 50054d93914aSRob Clark { 50064d93914aSRob Clark int ret = -EINVAL; 50073a5f87c2SThomas Wood struct drm_mode_object *obj = &plane->base; 50084d93914aSRob Clark 50094d93914aSRob Clark if (plane->funcs->set_property) 50104d93914aSRob Clark ret = plane->funcs->set_property(plane, property, value); 50114d93914aSRob Clark if (!ret) 50124d93914aSRob Clark drm_object_property_set_value(obj, property, value); 50134d93914aSRob Clark 50144d93914aSRob Clark return ret; 50154d93914aSRob Clark } 50163a5f87c2SThomas Wood EXPORT_SYMBOL(drm_mode_plane_set_obj_prop); 50174d93914aSRob Clark 5018c8e32cc1SDaniel Vetter /** 50191a498633SDaniel Vetter * drm_mode_obj_get_properties_ioctl - get the current value of a object's property 5020c8e32cc1SDaniel Vetter * @dev: DRM device 5021c8e32cc1SDaniel Vetter * @data: ioctl data 5022c8e32cc1SDaniel Vetter * @file_priv: DRM file info 5023c8e32cc1SDaniel Vetter * 5024c8e32cc1SDaniel Vetter * This function retrieves the current value for an object's property. Compared 5025c8e32cc1SDaniel Vetter * to the connector specific ioctl this one is extended to also work on crtc and 5026c8e32cc1SDaniel Vetter * plane objects. 5027c8e32cc1SDaniel Vetter * 5028c8e32cc1SDaniel Vetter * Called by the user via ioctl. 5029c8e32cc1SDaniel Vetter * 5030c8e32cc1SDaniel Vetter * Returns: 50311a498633SDaniel Vetter * Zero on success, negative errno on failure. 5032c8e32cc1SDaniel Vetter */ 5033c543188aSPaulo Zanoni int drm_mode_obj_get_properties_ioctl(struct drm_device *dev, void *data, 5034c543188aSPaulo Zanoni struct drm_file *file_priv) 5035c543188aSPaulo Zanoni { 5036c543188aSPaulo Zanoni struct drm_mode_obj_get_properties *arg = data; 5037c543188aSPaulo Zanoni struct drm_mode_object *obj; 5038c543188aSPaulo Zanoni int ret = 0; 5039c543188aSPaulo Zanoni 5040c543188aSPaulo Zanoni if (!drm_core_check_feature(dev, DRIVER_MODESET)) 5041c543188aSPaulo Zanoni return -EINVAL; 5042c543188aSPaulo Zanoni 504384849903SDaniel Vetter drm_modeset_lock_all(dev); 5044c543188aSPaulo Zanoni 5045c543188aSPaulo Zanoni obj = drm_mode_object_find(dev, arg->obj_id, arg->obj_type); 5046c543188aSPaulo Zanoni if (!obj) { 5047f27657f2SVille Syrjälä ret = -ENOENT; 5048c543188aSPaulo Zanoni goto out; 5049c543188aSPaulo Zanoni } 5050c543188aSPaulo Zanoni if (!obj->properties) { 5051c543188aSPaulo Zanoni ret = -EINVAL; 50521649c33bSDaniel Vetter goto out_unref; 5053c543188aSPaulo Zanoni } 5054c543188aSPaulo Zanoni 505588a48e29SRob Clark ret = get_properties(obj, file_priv->atomic, 505695cbf110SRob Clark (uint32_t __user *)(unsigned long)(arg->props_ptr), 505795cbf110SRob Clark (uint64_t __user *)(unsigned long)(arg->prop_values_ptr), 505895cbf110SRob Clark &arg->count_props); 5059c543188aSPaulo Zanoni 50601649c33bSDaniel Vetter out_unref: 50611649c33bSDaniel Vetter drm_mode_object_unreference(obj); 5062c543188aSPaulo Zanoni out: 506384849903SDaniel Vetter drm_modeset_unlock_all(dev); 5064c543188aSPaulo Zanoni return ret; 5065c543188aSPaulo Zanoni } 5066c543188aSPaulo Zanoni 5067c8e32cc1SDaniel Vetter /** 5068c8e32cc1SDaniel Vetter * drm_mode_obj_set_property_ioctl - set the current value of an object's property 5069c8e32cc1SDaniel Vetter * @dev: DRM device 5070c8e32cc1SDaniel Vetter * @data: ioctl data 5071c8e32cc1SDaniel Vetter * @file_priv: DRM file info 5072c8e32cc1SDaniel Vetter * 5073c8e32cc1SDaniel Vetter * This function sets the current value for an object's property. It also calls 5074c8e32cc1SDaniel Vetter * into a driver's ->set_property callback to update the hardware state. 5075c8e32cc1SDaniel Vetter * Compared to the connector specific ioctl this one is extended to also work on 5076c8e32cc1SDaniel Vetter * crtc and plane objects. 5077c8e32cc1SDaniel Vetter * 5078c8e32cc1SDaniel Vetter * Called by the user via ioctl. 5079c8e32cc1SDaniel Vetter * 5080c8e32cc1SDaniel Vetter * Returns: 50811a498633SDaniel Vetter * Zero on success, negative errno on failure. 5082c8e32cc1SDaniel Vetter */ 5083c543188aSPaulo Zanoni int drm_mode_obj_set_property_ioctl(struct drm_device *dev, void *data, 5084c543188aSPaulo Zanoni struct drm_file *file_priv) 5085c543188aSPaulo Zanoni { 5086c543188aSPaulo Zanoni struct drm_mode_obj_set_property *arg = data; 5087c543188aSPaulo Zanoni struct drm_mode_object *arg_obj; 5088c543188aSPaulo Zanoni struct drm_mode_object *prop_obj; 5089c543188aSPaulo Zanoni struct drm_property *property; 50903843e71fSRob Clark int i, ret = -EINVAL; 50913843e71fSRob Clark struct drm_mode_object *ref; 5092c543188aSPaulo Zanoni 5093c543188aSPaulo Zanoni if (!drm_core_check_feature(dev, DRIVER_MODESET)) 5094c543188aSPaulo Zanoni return -EINVAL; 5095c543188aSPaulo Zanoni 509684849903SDaniel Vetter drm_modeset_lock_all(dev); 5097c543188aSPaulo Zanoni 5098c543188aSPaulo Zanoni arg_obj = drm_mode_object_find(dev, arg->obj_id, arg->obj_type); 5099f27657f2SVille Syrjälä if (!arg_obj) { 5100f27657f2SVille Syrjälä ret = -ENOENT; 5101c543188aSPaulo Zanoni goto out; 5102f27657f2SVille Syrjälä } 5103c543188aSPaulo Zanoni if (!arg_obj->properties) 51041649c33bSDaniel Vetter goto out_unref; 5105c543188aSPaulo Zanoni 51067f88a9beSPaulo Zanoni for (i = 0; i < arg_obj->properties->count; i++) 5107b17cd757SRob Clark if (arg_obj->properties->properties[i]->base.id == arg->prop_id) 5108c543188aSPaulo Zanoni break; 5109c543188aSPaulo Zanoni 51107f88a9beSPaulo Zanoni if (i == arg_obj->properties->count) 51111649c33bSDaniel Vetter goto out_unref; 5112c543188aSPaulo Zanoni 5113c543188aSPaulo Zanoni prop_obj = drm_mode_object_find(dev, arg->prop_id, 5114c543188aSPaulo Zanoni DRM_MODE_OBJECT_PROPERTY); 5115f27657f2SVille Syrjälä if (!prop_obj) { 5116f27657f2SVille Syrjälä ret = -ENOENT; 51171649c33bSDaniel Vetter goto out_unref; 5118f27657f2SVille Syrjälä } 5119c543188aSPaulo Zanoni property = obj_to_property(prop_obj); 5120c543188aSPaulo Zanoni 51213843e71fSRob Clark if (!drm_property_change_valid_get(property, arg->value, &ref)) 5122b164d31fSDave Airlie goto out_unref; 5123c543188aSPaulo Zanoni 5124c543188aSPaulo Zanoni switch (arg_obj->type) { 5125c543188aSPaulo Zanoni case DRM_MODE_OBJECT_CONNECTOR: 5126c543188aSPaulo Zanoni ret = drm_mode_connector_set_obj_prop(arg_obj, property, 5127c543188aSPaulo Zanoni arg->value); 5128c543188aSPaulo Zanoni break; 5129bffd9de0SPaulo Zanoni case DRM_MODE_OBJECT_CRTC: 5130bffd9de0SPaulo Zanoni ret = drm_mode_crtc_set_obj_prop(arg_obj, property, arg->value); 5131bffd9de0SPaulo Zanoni break; 51324d93914aSRob Clark case DRM_MODE_OBJECT_PLANE: 51333a5f87c2SThomas Wood ret = drm_mode_plane_set_obj_prop(obj_to_plane(arg_obj), 51343a5f87c2SThomas Wood property, arg->value); 51354d93914aSRob Clark break; 5136c543188aSPaulo Zanoni } 5137c543188aSPaulo Zanoni 51383843e71fSRob Clark drm_property_change_valid_put(property, ref); 51393843e71fSRob Clark 51401649c33bSDaniel Vetter out_unref: 51411649c33bSDaniel Vetter drm_mode_object_unreference(arg_obj); 5142c543188aSPaulo Zanoni out: 514384849903SDaniel Vetter drm_modeset_unlock_all(dev); 5144c543188aSPaulo Zanoni return ret; 5145c543188aSPaulo Zanoni } 5146c543188aSPaulo Zanoni 5147c8e32cc1SDaniel Vetter /** 5148c8e32cc1SDaniel Vetter * drm_mode_connector_attach_encoder - attach a connector to an encoder 5149c8e32cc1SDaniel Vetter * @connector: connector to attach 5150c8e32cc1SDaniel Vetter * @encoder: encoder to attach @connector to 5151c8e32cc1SDaniel Vetter * 5152c8e32cc1SDaniel Vetter * This function links up a connector to an encoder. Note that the routing 5153c8e32cc1SDaniel Vetter * restrictions between encoders and crtcs are exposed to userspace through the 5154c8e32cc1SDaniel Vetter * possible_clones and possible_crtcs bitmasks. 5155c8e32cc1SDaniel Vetter * 5156c8e32cc1SDaniel Vetter * Returns: 51571a498633SDaniel Vetter * Zero on success, negative errno on failure. 5158c8e32cc1SDaniel Vetter */ 5159f453ba04SDave Airlie int drm_mode_connector_attach_encoder(struct drm_connector *connector, 5160f453ba04SDave Airlie struct drm_encoder *encoder) 5161f453ba04SDave Airlie { 5162f453ba04SDave Airlie int i; 5163f453ba04SDave Airlie 5164eb47fe80SThierry Reding /* 5165eb47fe80SThierry Reding * In the past, drivers have attempted to model the static association 5166eb47fe80SThierry Reding * of connector to encoder in simple connector/encoder devices using a 5167eb47fe80SThierry Reding * direct assignment of connector->encoder = encoder. This connection 5168eb47fe80SThierry Reding * is a logical one and the responsibility of the core, so drivers are 5169eb47fe80SThierry Reding * expected not to mess with this. 5170eb47fe80SThierry Reding * 5171eb47fe80SThierry Reding * Note that the error return should've been enough here, but a large 5172eb47fe80SThierry Reding * majority of drivers ignores the return value, so add in a big WARN 5173eb47fe80SThierry Reding * to get people's attention. 5174eb47fe80SThierry Reding */ 5175eb47fe80SThierry Reding if (WARN_ON(connector->encoder)) 5176eb47fe80SThierry Reding return -EINVAL; 5177eb47fe80SThierry Reding 5178f453ba04SDave Airlie for (i = 0; i < DRM_CONNECTOR_MAX_ENCODER; i++) { 5179f453ba04SDave Airlie if (connector->encoder_ids[i] == 0) { 5180f453ba04SDave Airlie connector->encoder_ids[i] = encoder->base.id; 5181f453ba04SDave Airlie return 0; 5182f453ba04SDave Airlie } 5183f453ba04SDave Airlie } 5184f453ba04SDave Airlie return -ENOMEM; 5185f453ba04SDave Airlie } 5186f453ba04SDave Airlie EXPORT_SYMBOL(drm_mode_connector_attach_encoder); 5187f453ba04SDave Airlie 5188c8e32cc1SDaniel Vetter /** 5189c8e32cc1SDaniel Vetter * drm_mode_crtc_set_gamma_size - set the gamma table size 5190c8e32cc1SDaniel Vetter * @crtc: CRTC to set the gamma table size for 5191c8e32cc1SDaniel Vetter * @gamma_size: size of the gamma table 5192c8e32cc1SDaniel Vetter * 5193c8e32cc1SDaniel Vetter * Drivers which support gamma tables should set this to the supported gamma 5194c8e32cc1SDaniel Vetter * table size when initializing the CRTC. Currently the drm core only supports a 5195c8e32cc1SDaniel Vetter * fixed gamma table size. 5196c8e32cc1SDaniel Vetter * 5197c8e32cc1SDaniel Vetter * Returns: 51981a498633SDaniel Vetter * Zero on success, negative errno on failure. 5199c8e32cc1SDaniel Vetter */ 52004cae5b84SSascha Hauer int drm_mode_crtc_set_gamma_size(struct drm_crtc *crtc, 5201f453ba04SDave Airlie int gamma_size) 5202f453ba04SDave Airlie { 5203cf48e292SDaniel Vetter uint16_t *r_base, *g_base, *b_base; 5204cf48e292SDaniel Vetter int i; 5205cf48e292SDaniel Vetter 5206f453ba04SDave Airlie crtc->gamma_size = gamma_size; 5207f453ba04SDave Airlie 5208bd3f0ff9SThierry Reding crtc->gamma_store = kcalloc(gamma_size, sizeof(uint16_t) * 3, 5209bd3f0ff9SThierry Reding GFP_KERNEL); 5210f453ba04SDave Airlie if (!crtc->gamma_store) { 5211f453ba04SDave Airlie crtc->gamma_size = 0; 52124cae5b84SSascha Hauer return -ENOMEM; 5213f453ba04SDave Airlie } 5214f453ba04SDave Airlie 5215cf48e292SDaniel Vetter r_base = crtc->gamma_store; 5216cf48e292SDaniel Vetter g_base = r_base + gamma_size; 5217cf48e292SDaniel Vetter b_base = g_base + gamma_size; 5218cf48e292SDaniel Vetter for (i = 0; i < gamma_size; i++) { 5219cf48e292SDaniel Vetter r_base[i] = i << 8; 5220cf48e292SDaniel Vetter g_base[i] = i << 8; 5221cf48e292SDaniel Vetter b_base[i] = i << 8; 5222cf48e292SDaniel Vetter } 5223cf48e292SDaniel Vetter 5224cf48e292SDaniel Vetter 52254cae5b84SSascha Hauer return 0; 5226f453ba04SDave Airlie } 5227f453ba04SDave Airlie EXPORT_SYMBOL(drm_mode_crtc_set_gamma_size); 5228f453ba04SDave Airlie 5229c8e32cc1SDaniel Vetter /** 5230c8e32cc1SDaniel Vetter * drm_mode_gamma_set_ioctl - set the gamma table 5231c8e32cc1SDaniel Vetter * @dev: DRM device 5232c8e32cc1SDaniel Vetter * @data: ioctl data 5233c8e32cc1SDaniel Vetter * @file_priv: DRM file info 5234c8e32cc1SDaniel Vetter * 5235c8e32cc1SDaniel Vetter * Set the gamma table of a CRTC to the one passed in by the user. Userspace can 5236c8e32cc1SDaniel Vetter * inquire the required gamma table size through drm_mode_gamma_get_ioctl. 5237c8e32cc1SDaniel Vetter * 5238c8e32cc1SDaniel Vetter * Called by the user via ioctl. 5239c8e32cc1SDaniel Vetter * 5240c8e32cc1SDaniel Vetter * Returns: 52411a498633SDaniel Vetter * Zero on success, negative errno on failure. 5242c8e32cc1SDaniel Vetter */ 5243f453ba04SDave Airlie int drm_mode_gamma_set_ioctl(struct drm_device *dev, 5244f453ba04SDave Airlie void *data, struct drm_file *file_priv) 5245f453ba04SDave Airlie { 5246f453ba04SDave Airlie struct drm_mode_crtc_lut *crtc_lut = data; 5247f453ba04SDave Airlie struct drm_crtc *crtc; 5248f453ba04SDave Airlie void *r_base, *g_base, *b_base; 5249f453ba04SDave Airlie int size; 5250f453ba04SDave Airlie int ret = 0; 5251f453ba04SDave Airlie 5252fb3b06c8SDave Airlie if (!drm_core_check_feature(dev, DRIVER_MODESET)) 5253fb3b06c8SDave Airlie return -EINVAL; 5254fb3b06c8SDave Airlie 525584849903SDaniel Vetter drm_modeset_lock_all(dev); 5256a2b34e22SRob Clark crtc = drm_crtc_find(dev, crtc_lut->crtc_id); 5257a2b34e22SRob Clark if (!crtc) { 5258f27657f2SVille Syrjälä ret = -ENOENT; 5259f453ba04SDave Airlie goto out; 5260f453ba04SDave Airlie } 5261f453ba04SDave Airlie 5262ebe0f244SLaurent Pinchart if (crtc->funcs->gamma_set == NULL) { 5263ebe0f244SLaurent Pinchart ret = -ENOSYS; 5264ebe0f244SLaurent Pinchart goto out; 5265ebe0f244SLaurent Pinchart } 5266ebe0f244SLaurent Pinchart 5267f453ba04SDave Airlie /* memcpy into gamma store */ 5268f453ba04SDave Airlie if (crtc_lut->gamma_size != crtc->gamma_size) { 5269f453ba04SDave Airlie ret = -EINVAL; 5270f453ba04SDave Airlie goto out; 5271f453ba04SDave Airlie } 5272f453ba04SDave Airlie 5273f453ba04SDave Airlie size = crtc_lut->gamma_size * (sizeof(uint16_t)); 5274f453ba04SDave Airlie r_base = crtc->gamma_store; 5275f453ba04SDave Airlie if (copy_from_user(r_base, (void __user *)(unsigned long)crtc_lut->red, size)) { 5276f453ba04SDave Airlie ret = -EFAULT; 5277f453ba04SDave Airlie goto out; 5278f453ba04SDave Airlie } 5279f453ba04SDave Airlie 5280f453ba04SDave Airlie g_base = r_base + size; 5281f453ba04SDave Airlie if (copy_from_user(g_base, (void __user *)(unsigned long)crtc_lut->green, size)) { 5282f453ba04SDave Airlie ret = -EFAULT; 5283f453ba04SDave Airlie goto out; 5284f453ba04SDave Airlie } 5285f453ba04SDave Airlie 5286f453ba04SDave Airlie b_base = g_base + size; 5287f453ba04SDave Airlie if (copy_from_user(b_base, (void __user *)(unsigned long)crtc_lut->blue, size)) { 5288f453ba04SDave Airlie ret = -EFAULT; 5289f453ba04SDave Airlie goto out; 5290f453ba04SDave Airlie } 5291f453ba04SDave Airlie 52927ea77283SMaarten Lankhorst ret = crtc->funcs->gamma_set(crtc, r_base, g_base, b_base, crtc->gamma_size); 5293f453ba04SDave Airlie 5294f453ba04SDave Airlie out: 529584849903SDaniel Vetter drm_modeset_unlock_all(dev); 5296f453ba04SDave Airlie return ret; 5297f453ba04SDave Airlie 5298f453ba04SDave Airlie } 5299f453ba04SDave Airlie 5300c8e32cc1SDaniel Vetter /** 5301c8e32cc1SDaniel Vetter * drm_mode_gamma_get_ioctl - get the gamma table 5302c8e32cc1SDaniel Vetter * @dev: DRM device 5303c8e32cc1SDaniel Vetter * @data: ioctl data 5304c8e32cc1SDaniel Vetter * @file_priv: DRM file info 5305c8e32cc1SDaniel Vetter * 5306c8e32cc1SDaniel Vetter * Copy the current gamma table into the storage provided. This also provides 5307c8e32cc1SDaniel Vetter * the gamma table size the driver expects, which can be used to size the 5308c8e32cc1SDaniel Vetter * allocated storage. 5309c8e32cc1SDaniel Vetter * 5310c8e32cc1SDaniel Vetter * Called by the user via ioctl. 5311c8e32cc1SDaniel Vetter * 5312c8e32cc1SDaniel Vetter * Returns: 53131a498633SDaniel Vetter * Zero on success, negative errno on failure. 5314c8e32cc1SDaniel Vetter */ 5315f453ba04SDave Airlie int drm_mode_gamma_get_ioctl(struct drm_device *dev, 5316f453ba04SDave Airlie void *data, struct drm_file *file_priv) 5317f453ba04SDave Airlie { 5318f453ba04SDave Airlie struct drm_mode_crtc_lut *crtc_lut = data; 5319f453ba04SDave Airlie struct drm_crtc *crtc; 5320f453ba04SDave Airlie void *r_base, *g_base, *b_base; 5321f453ba04SDave Airlie int size; 5322f453ba04SDave Airlie int ret = 0; 5323f453ba04SDave Airlie 5324fb3b06c8SDave Airlie if (!drm_core_check_feature(dev, DRIVER_MODESET)) 5325fb3b06c8SDave Airlie return -EINVAL; 5326fb3b06c8SDave Airlie 532784849903SDaniel Vetter drm_modeset_lock_all(dev); 5328a2b34e22SRob Clark crtc = drm_crtc_find(dev, crtc_lut->crtc_id); 5329a2b34e22SRob Clark if (!crtc) { 5330f27657f2SVille Syrjälä ret = -ENOENT; 5331f453ba04SDave Airlie goto out; 5332f453ba04SDave Airlie } 5333f453ba04SDave Airlie 5334f453ba04SDave Airlie /* memcpy into gamma store */ 5335f453ba04SDave Airlie if (crtc_lut->gamma_size != crtc->gamma_size) { 5336f453ba04SDave Airlie ret = -EINVAL; 5337f453ba04SDave Airlie goto out; 5338f453ba04SDave Airlie } 5339f453ba04SDave Airlie 5340f453ba04SDave Airlie size = crtc_lut->gamma_size * (sizeof(uint16_t)); 5341f453ba04SDave Airlie r_base = crtc->gamma_store; 5342f453ba04SDave Airlie if (copy_to_user((void __user *)(unsigned long)crtc_lut->red, r_base, size)) { 5343f453ba04SDave Airlie ret = -EFAULT; 5344f453ba04SDave Airlie goto out; 5345f453ba04SDave Airlie } 5346f453ba04SDave Airlie 5347f453ba04SDave Airlie g_base = r_base + size; 5348f453ba04SDave Airlie if (copy_to_user((void __user *)(unsigned long)crtc_lut->green, g_base, size)) { 5349f453ba04SDave Airlie ret = -EFAULT; 5350f453ba04SDave Airlie goto out; 5351f453ba04SDave Airlie } 5352f453ba04SDave Airlie 5353f453ba04SDave Airlie b_base = g_base + size; 5354f453ba04SDave Airlie if (copy_to_user((void __user *)(unsigned long)crtc_lut->blue, b_base, size)) { 5355f453ba04SDave Airlie ret = -EFAULT; 5356f453ba04SDave Airlie goto out; 5357f453ba04SDave Airlie } 5358f453ba04SDave Airlie out: 535984849903SDaniel Vetter drm_modeset_unlock_all(dev); 5360f453ba04SDave Airlie return ret; 5361f453ba04SDave Airlie } 5362d91d8a3fSKristian Høgsberg 5363c8e32cc1SDaniel Vetter /** 5364c8e32cc1SDaniel Vetter * drm_mode_page_flip_ioctl - schedule an asynchronous fb update 5365c8e32cc1SDaniel Vetter * @dev: DRM device 5366c8e32cc1SDaniel Vetter * @data: ioctl data 5367c8e32cc1SDaniel Vetter * @file_priv: DRM file info 5368c8e32cc1SDaniel Vetter * 5369c8e32cc1SDaniel Vetter * This schedules an asynchronous update on a given CRTC, called page flip. 5370c8e32cc1SDaniel Vetter * Optionally a drm event is generated to signal the completion of the event. 5371c8e32cc1SDaniel Vetter * Generic drivers cannot assume that a pageflip with changed framebuffer 5372c8e32cc1SDaniel Vetter * properties (including driver specific metadata like tiling layout) will work, 5373c8e32cc1SDaniel Vetter * but some drivers support e.g. pixel format changes through the pageflip 5374c8e32cc1SDaniel Vetter * ioctl. 5375c8e32cc1SDaniel Vetter * 5376c8e32cc1SDaniel Vetter * Called by the user via ioctl. 5377c8e32cc1SDaniel Vetter * 5378c8e32cc1SDaniel Vetter * Returns: 53791a498633SDaniel Vetter * Zero on success, negative errno on failure. 5380c8e32cc1SDaniel Vetter */ 5381d91d8a3fSKristian Høgsberg int drm_mode_page_flip_ioctl(struct drm_device *dev, 5382d91d8a3fSKristian Høgsberg void *data, struct drm_file *file_priv) 5383d91d8a3fSKristian Høgsberg { 5384d91d8a3fSKristian Høgsberg struct drm_mode_crtc_page_flip *page_flip = data; 5385d91d8a3fSKristian Høgsberg struct drm_crtc *crtc; 53863d30a59bSDaniel Vetter struct drm_framebuffer *fb = NULL; 5387d91d8a3fSKristian Høgsberg struct drm_pending_vblank_event *e = NULL; 5388d91d8a3fSKristian Høgsberg int ret = -EINVAL; 5389d91d8a3fSKristian Høgsberg 5390d91d8a3fSKristian Høgsberg if (page_flip->flags & ~DRM_MODE_PAGE_FLIP_FLAGS || 5391d91d8a3fSKristian Høgsberg page_flip->reserved != 0) 5392d91d8a3fSKristian Høgsberg return -EINVAL; 5393d91d8a3fSKristian Høgsberg 539462f2104fSKeith Packard if ((page_flip->flags & DRM_MODE_PAGE_FLIP_ASYNC) && !dev->mode_config.async_page_flip) 539562f2104fSKeith Packard return -EINVAL; 539662f2104fSKeith Packard 5397a2b34e22SRob Clark crtc = drm_crtc_find(dev, page_flip->crtc_id); 5398a2b34e22SRob Clark if (!crtc) 5399f27657f2SVille Syrjälä return -ENOENT; 5400d91d8a3fSKristian Høgsberg 54014d02e2deSDaniel Vetter drm_modeset_lock_crtc(crtc, crtc->primary); 5402f4510a27SMatt Roper if (crtc->primary->fb == NULL) { 540390c1efddSChris Wilson /* The framebuffer is currently unbound, presumably 540490c1efddSChris Wilson * due to a hotplug event, that userspace has not 540590c1efddSChris Wilson * yet discovered. 540690c1efddSChris Wilson */ 540790c1efddSChris Wilson ret = -EBUSY; 540890c1efddSChris Wilson goto out; 540990c1efddSChris Wilson } 541090c1efddSChris Wilson 5411d91d8a3fSKristian Høgsberg if (crtc->funcs->page_flip == NULL) 5412d91d8a3fSKristian Høgsberg goto out; 5413d91d8a3fSKristian Høgsberg 5414786b99edSDaniel Vetter fb = drm_framebuffer_lookup(dev, page_flip->fb_id); 541537c4e705SVille Syrjälä if (!fb) { 541637c4e705SVille Syrjälä ret = -ENOENT; 5417d91d8a3fSKristian Høgsberg goto out; 541837c4e705SVille Syrjälä } 5419d91d8a3fSKristian Høgsberg 54202afa701dSVille Syrjälä if (crtc->state) { 54212afa701dSVille Syrjälä const struct drm_plane_state *state = crtc->primary->state; 54222afa701dSVille Syrjälä 54232afa701dSVille Syrjälä ret = check_src_coords(state->src_x, state->src_y, 54242afa701dSVille Syrjälä state->src_w, state->src_h, fb); 54252afa701dSVille Syrjälä } else { 5426c11e9283SDamien Lespiau ret = drm_crtc_check_viewport(crtc, crtc->x, crtc->y, &crtc->mode, fb); 54272afa701dSVille Syrjälä } 5428c11e9283SDamien Lespiau if (ret) 54295f61bb42SVille Syrjälä goto out; 54305f61bb42SVille Syrjälä 5431f4510a27SMatt Roper if (crtc->primary->fb->pixel_format != fb->pixel_format) { 5432909d9cdaSLaurent Pinchart DRM_DEBUG_KMS("Page flip is not allowed to change frame buffer format.\n"); 5433909d9cdaSLaurent Pinchart ret = -EINVAL; 5434909d9cdaSLaurent Pinchart goto out; 5435909d9cdaSLaurent Pinchart } 5436909d9cdaSLaurent Pinchart 5437d91d8a3fSKristian Høgsberg if (page_flip->flags & DRM_MODE_PAGE_FLIP_EVENT) { 54382dd500f1SDaniel Vetter e = kzalloc(sizeof *e, GFP_KERNEL); 54392dd500f1SDaniel Vetter if (!e) { 5440d91d8a3fSKristian Høgsberg ret = -ENOMEM; 5441d91d8a3fSKristian Høgsberg goto out; 5442d91d8a3fSKristian Høgsberg } 54437bd4d7beSJesse Barnes e->event.base.type = DRM_EVENT_FLIP_COMPLETE; 5444f76511b9SThierry Reding e->event.base.length = sizeof(e->event); 5445d91d8a3fSKristian Høgsberg e->event.user_data = page_flip->user_data; 54462dd500f1SDaniel Vetter ret = drm_event_reserve_init(dev, file_priv, &e->base, &e->event.base); 54472dd500f1SDaniel Vetter if (ret) { 54482dd500f1SDaniel Vetter kfree(e); 54492dd500f1SDaniel Vetter goto out; 54502dd500f1SDaniel Vetter } 5451d91d8a3fSKristian Høgsberg } 5452d91d8a3fSKristian Høgsberg 54533d30a59bSDaniel Vetter crtc->primary->old_fb = crtc->primary->fb; 5454ed8d1975SKeith Packard ret = crtc->funcs->page_flip(crtc, fb, e, page_flip->flags); 5455d91d8a3fSKristian Høgsberg if (ret) { 54562dd500f1SDaniel Vetter if (page_flip->flags & DRM_MODE_PAGE_FLIP_EVENT) 54572dd500f1SDaniel Vetter drm_event_cancel_free(dev, &e->base); 5458b0d12325SDaniel Vetter /* Keep the old fb, don't unref it. */ 54593d30a59bSDaniel Vetter crtc->primary->old_fb = NULL; 5460b0d12325SDaniel Vetter } else { 54613cb43cc0SDaniel Vetter crtc->primary->fb = fb; 5462b0d12325SDaniel Vetter /* Unref only the old framebuffer. */ 5463b0d12325SDaniel Vetter fb = NULL; 5464aef6a7eeSJoonyoung Shim } 5465d91d8a3fSKristian Høgsberg 5466d91d8a3fSKristian Høgsberg out: 5467b0d12325SDaniel Vetter if (fb) 5468b0d12325SDaniel Vetter drm_framebuffer_unreference(fb); 54693d30a59bSDaniel Vetter if (crtc->primary->old_fb) 54703d30a59bSDaniel Vetter drm_framebuffer_unreference(crtc->primary->old_fb); 54713d30a59bSDaniel Vetter crtc->primary->old_fb = NULL; 5472d059f652SDaniel Vetter drm_modeset_unlock_crtc(crtc); 5473b4d5e7d1SDaniel Vetter 5474d91d8a3fSKristian Høgsberg return ret; 5475d91d8a3fSKristian Høgsberg } 5476eb033556SChris Wilson 5477c8e32cc1SDaniel Vetter /** 5478c8e32cc1SDaniel Vetter * drm_mode_config_reset - call ->reset callbacks 5479c8e32cc1SDaniel Vetter * @dev: drm device 5480c8e32cc1SDaniel Vetter * 5481c8e32cc1SDaniel Vetter * This functions calls all the crtc's, encoder's and connector's ->reset 5482c8e32cc1SDaniel Vetter * callback. Drivers can use this in e.g. their driver load or resume code to 5483c8e32cc1SDaniel Vetter * reset hardware and software state. 5484c8e32cc1SDaniel Vetter */ 5485eb033556SChris Wilson void drm_mode_config_reset(struct drm_device *dev) 5486eb033556SChris Wilson { 5487eb033556SChris Wilson struct drm_crtc *crtc; 54882a0d7cfdSDaniel Vetter struct drm_plane *plane; 5489eb033556SChris Wilson struct drm_encoder *encoder; 5490eb033556SChris Wilson struct drm_connector *connector; 5491eb033556SChris Wilson 5492e4f62546SDaniel Vetter drm_for_each_plane(plane, dev) 54932a0d7cfdSDaniel Vetter if (plane->funcs->reset) 54942a0d7cfdSDaniel Vetter plane->funcs->reset(plane); 54952a0d7cfdSDaniel Vetter 5496e4f62546SDaniel Vetter drm_for_each_crtc(crtc, dev) 5497eb033556SChris Wilson if (crtc->funcs->reset) 5498eb033556SChris Wilson crtc->funcs->reset(crtc); 5499eb033556SChris Wilson 5500e4f62546SDaniel Vetter drm_for_each_encoder(encoder, dev) 5501eb033556SChris Wilson if (encoder->funcs->reset) 5502eb033556SChris Wilson encoder->funcs->reset(encoder); 5503eb033556SChris Wilson 5504f8c2ba31SDaniel Vetter mutex_lock(&dev->mode_config.mutex); 55054eebf60bSDave Airlie drm_for_each_connector(connector, dev) 5506eb033556SChris Wilson if (connector->funcs->reset) 5507eb033556SChris Wilson connector->funcs->reset(connector); 5508f8c2ba31SDaniel Vetter mutex_unlock(&dev->mode_config.mutex); 55095e2cb2f6SDaniel Vetter } 5510eb033556SChris Wilson EXPORT_SYMBOL(drm_mode_config_reset); 5511ff72145bSDave Airlie 5512c8e32cc1SDaniel Vetter /** 5513c8e32cc1SDaniel Vetter * drm_mode_create_dumb_ioctl - create a dumb backing storage buffer 5514c8e32cc1SDaniel Vetter * @dev: DRM device 5515c8e32cc1SDaniel Vetter * @data: ioctl data 5516c8e32cc1SDaniel Vetter * @file_priv: DRM file info 5517c8e32cc1SDaniel Vetter * 5518c8e32cc1SDaniel Vetter * This creates a new dumb buffer in the driver's backing storage manager (GEM, 5519c8e32cc1SDaniel Vetter * TTM or something else entirely) and returns the resulting buffer handle. This 5520c8e32cc1SDaniel Vetter * handle can then be wrapped up into a framebuffer modeset object. 5521c8e32cc1SDaniel Vetter * 5522c8e32cc1SDaniel Vetter * Note that userspace is not allowed to use such objects for render 5523c8e32cc1SDaniel Vetter * acceleration - drivers must create their own private ioctls for such a use 5524c8e32cc1SDaniel Vetter * case. 5525c8e32cc1SDaniel Vetter * 5526c8e32cc1SDaniel Vetter * Called by the user via ioctl. 5527c8e32cc1SDaniel Vetter * 5528c8e32cc1SDaniel Vetter * Returns: 55291a498633SDaniel Vetter * Zero on success, negative errno on failure. 5530c8e32cc1SDaniel Vetter */ 5531ff72145bSDave Airlie int drm_mode_create_dumb_ioctl(struct drm_device *dev, 5532ff72145bSDave Airlie void *data, struct drm_file *file_priv) 5533ff72145bSDave Airlie { 5534ff72145bSDave Airlie struct drm_mode_create_dumb *args = data; 5535b28cd41fSDavid Herrmann u32 cpp, stride, size; 5536ff72145bSDave Airlie 5537ff72145bSDave Airlie if (!dev->driver->dumb_create) 5538ff72145bSDave Airlie return -ENOSYS; 5539b28cd41fSDavid Herrmann if (!args->width || !args->height || !args->bpp) 5540b28cd41fSDavid Herrmann return -EINVAL; 5541b28cd41fSDavid Herrmann 5542b28cd41fSDavid Herrmann /* overflow checks for 32bit size calculations */ 554300e72089SDavid Herrmann /* NOTE: DIV_ROUND_UP() can overflow */ 5544b28cd41fSDavid Herrmann cpp = DIV_ROUND_UP(args->bpp, 8); 554500e72089SDavid Herrmann if (!cpp || cpp > 0xffffffffU / args->width) 5546b28cd41fSDavid Herrmann return -EINVAL; 5547b28cd41fSDavid Herrmann stride = cpp * args->width; 5548b28cd41fSDavid Herrmann if (args->height > 0xffffffffU / stride) 5549b28cd41fSDavid Herrmann return -EINVAL; 5550b28cd41fSDavid Herrmann 5551b28cd41fSDavid Herrmann /* test for wrap-around */ 5552b28cd41fSDavid Herrmann size = args->height * stride; 5553b28cd41fSDavid Herrmann if (PAGE_ALIGN(size) == 0) 5554b28cd41fSDavid Herrmann return -EINVAL; 5555b28cd41fSDavid Herrmann 5556f6085952SThierry Reding /* 5557f6085952SThierry Reding * handle, pitch and size are output parameters. Zero them out to 5558f6085952SThierry Reding * prevent drivers from accidentally using uninitialized data. Since 5559f6085952SThierry Reding * not all existing userspace is clearing these fields properly we 5560f6085952SThierry Reding * cannot reject IOCTL with garbage in them. 5561f6085952SThierry Reding */ 5562f6085952SThierry Reding args->handle = 0; 5563f6085952SThierry Reding args->pitch = 0; 5564f6085952SThierry Reding args->size = 0; 5565f6085952SThierry Reding 5566ff72145bSDave Airlie return dev->driver->dumb_create(file_priv, dev, args); 5567ff72145bSDave Airlie } 5568ff72145bSDave Airlie 5569c8e32cc1SDaniel Vetter /** 5570c8e32cc1SDaniel Vetter * drm_mode_mmap_dumb_ioctl - create an mmap offset for a dumb backing storage buffer 5571c8e32cc1SDaniel Vetter * @dev: DRM device 5572c8e32cc1SDaniel Vetter * @data: ioctl data 5573c8e32cc1SDaniel Vetter * @file_priv: DRM file info 5574c8e32cc1SDaniel Vetter * 5575c8e32cc1SDaniel Vetter * Allocate an offset in the drm device node's address space to be able to 5576c8e32cc1SDaniel Vetter * memory map a dumb buffer. 5577c8e32cc1SDaniel Vetter * 5578c8e32cc1SDaniel Vetter * Called by the user via ioctl. 5579c8e32cc1SDaniel Vetter * 5580c8e32cc1SDaniel Vetter * Returns: 55811a498633SDaniel Vetter * Zero on success, negative errno on failure. 5582c8e32cc1SDaniel Vetter */ 5583ff72145bSDave Airlie int drm_mode_mmap_dumb_ioctl(struct drm_device *dev, 5584ff72145bSDave Airlie void *data, struct drm_file *file_priv) 5585ff72145bSDave Airlie { 5586ff72145bSDave Airlie struct drm_mode_map_dumb *args = data; 5587ff72145bSDave Airlie 5588ff72145bSDave Airlie /* call driver ioctl to get mmap offset */ 5589ff72145bSDave Airlie if (!dev->driver->dumb_map_offset) 5590ff72145bSDave Airlie return -ENOSYS; 5591ff72145bSDave Airlie 5592ff72145bSDave Airlie return dev->driver->dumb_map_offset(file_priv, dev, args->handle, &args->offset); 5593ff72145bSDave Airlie } 5594ff72145bSDave Airlie 5595c8e32cc1SDaniel Vetter /** 5596c8e32cc1SDaniel Vetter * drm_mode_destroy_dumb_ioctl - destroy a dumb backing strage buffer 5597c8e32cc1SDaniel Vetter * @dev: DRM device 5598c8e32cc1SDaniel Vetter * @data: ioctl data 5599c8e32cc1SDaniel Vetter * @file_priv: DRM file info 5600c8e32cc1SDaniel Vetter * 5601c8e32cc1SDaniel Vetter * This destroys the userspace handle for the given dumb backing storage buffer. 5602c8e32cc1SDaniel Vetter * Since buffer objects must be reference counted in the kernel a buffer object 5603c8e32cc1SDaniel Vetter * won't be immediately freed if a framebuffer modeset object still uses it. 5604c8e32cc1SDaniel Vetter * 5605c8e32cc1SDaniel Vetter * Called by the user via ioctl. 5606c8e32cc1SDaniel Vetter * 5607c8e32cc1SDaniel Vetter * Returns: 56081a498633SDaniel Vetter * Zero on success, negative errno on failure. 5609c8e32cc1SDaniel Vetter */ 5610ff72145bSDave Airlie int drm_mode_destroy_dumb_ioctl(struct drm_device *dev, 5611ff72145bSDave Airlie void *data, struct drm_file *file_priv) 5612ff72145bSDave Airlie { 5613ff72145bSDave Airlie struct drm_mode_destroy_dumb *args = data; 5614ff72145bSDave Airlie 5615ff72145bSDave Airlie if (!dev->driver->dumb_destroy) 5616ff72145bSDave Airlie return -ENOSYS; 5617ff72145bSDave Airlie 5618ff72145bSDave Airlie return dev->driver->dumb_destroy(file_priv, dev, args->handle); 5619ff72145bSDave Airlie } 5620248dbc23SDave Airlie 5621c8e32cc1SDaniel Vetter /** 56223c9855f6SVille Syrjälä * drm_rotation_simplify() - Try to simplify the rotation 56233c9855f6SVille Syrjälä * @rotation: Rotation to be simplified 56243c9855f6SVille Syrjälä * @supported_rotations: Supported rotations 56253c9855f6SVille Syrjälä * 56263c9855f6SVille Syrjälä * Attempt to simplify the rotation to a form that is supported. 56273c9855f6SVille Syrjälä * Eg. if the hardware supports everything except DRM_REFLECT_X 56283c9855f6SVille Syrjälä * one could call this function like this: 56293c9855f6SVille Syrjälä * 56303c9855f6SVille Syrjälä * drm_rotation_simplify(rotation, BIT(DRM_ROTATE_0) | 56313c9855f6SVille Syrjälä * BIT(DRM_ROTATE_90) | BIT(DRM_ROTATE_180) | 56323c9855f6SVille Syrjälä * BIT(DRM_ROTATE_270) | BIT(DRM_REFLECT_Y)); 56333c9855f6SVille Syrjälä * 56343c9855f6SVille Syrjälä * to eliminate the DRM_ROTATE_X flag. Depending on what kind of 56353c9855f6SVille Syrjälä * transforms the hardware supports, this function may not 56363c9855f6SVille Syrjälä * be able to produce a supported transform, so the caller should 56373c9855f6SVille Syrjälä * check the result afterwards. 56383c9855f6SVille Syrjälä */ 56393c9855f6SVille Syrjälä unsigned int drm_rotation_simplify(unsigned int rotation, 56403c9855f6SVille Syrjälä unsigned int supported_rotations) 56413c9855f6SVille Syrjälä { 56423c9855f6SVille Syrjälä if (rotation & ~supported_rotations) { 56433c9855f6SVille Syrjälä rotation ^= BIT(DRM_REFLECT_X) | BIT(DRM_REFLECT_Y); 564414152c8dSJoonas Lahtinen rotation = (rotation & DRM_REFLECT_MASK) | 564514152c8dSJoonas Lahtinen BIT((ffs(rotation & DRM_ROTATE_MASK) + 1) % 4); 56463c9855f6SVille Syrjälä } 56473c9855f6SVille Syrjälä 56483c9855f6SVille Syrjälä return rotation; 56493c9855f6SVille Syrjälä } 56503c9855f6SVille Syrjälä EXPORT_SYMBOL(drm_rotation_simplify); 56513c9855f6SVille Syrjälä 56523c9855f6SVille Syrjälä /** 565387d24fc3SLaurent Pinchart * drm_mode_config_init - initialize DRM mode_configuration structure 565487d24fc3SLaurent Pinchart * @dev: DRM device 565587d24fc3SLaurent Pinchart * 565687d24fc3SLaurent Pinchart * Initialize @dev's mode_config structure, used for tracking the graphics 565787d24fc3SLaurent Pinchart * configuration of @dev. 565887d24fc3SLaurent Pinchart * 565987d24fc3SLaurent Pinchart * Since this initializes the modeset locks, no locking is possible. Which is no 566087d24fc3SLaurent Pinchart * problem, since this should happen single threaded at init time. It is the 566187d24fc3SLaurent Pinchart * driver's problem to ensure this guarantee. 566287d24fc3SLaurent Pinchart * 566387d24fc3SLaurent Pinchart */ 566487d24fc3SLaurent Pinchart void drm_mode_config_init(struct drm_device *dev) 566587d24fc3SLaurent Pinchart { 566687d24fc3SLaurent Pinchart mutex_init(&dev->mode_config.mutex); 566751fd371bSRob Clark drm_modeset_lock_init(&dev->mode_config.connection_mutex); 566887d24fc3SLaurent Pinchart mutex_init(&dev->mode_config.idr_mutex); 566987d24fc3SLaurent Pinchart mutex_init(&dev->mode_config.fb_lock); 56708fb6e7a5SDaniel Stone mutex_init(&dev->mode_config.blob_lock); 567187d24fc3SLaurent Pinchart INIT_LIST_HEAD(&dev->mode_config.fb_list); 567287d24fc3SLaurent Pinchart INIT_LIST_HEAD(&dev->mode_config.crtc_list); 567387d24fc3SLaurent Pinchart INIT_LIST_HEAD(&dev->mode_config.connector_list); 567487d24fc3SLaurent Pinchart INIT_LIST_HEAD(&dev->mode_config.encoder_list); 567587d24fc3SLaurent Pinchart INIT_LIST_HEAD(&dev->mode_config.property_list); 567687d24fc3SLaurent Pinchart INIT_LIST_HEAD(&dev->mode_config.property_blob_list); 567787d24fc3SLaurent Pinchart INIT_LIST_HEAD(&dev->mode_config.plane_list); 567887d24fc3SLaurent Pinchart idr_init(&dev->mode_config.crtc_idr); 5679138f9ebbSDave Airlie idr_init(&dev->mode_config.tile_idr); 56805fff80bbSMaarten Lankhorst ida_init(&dev->mode_config.connector_ida); 568187d24fc3SLaurent Pinchart 568287d24fc3SLaurent Pinchart drm_modeset_lock_all(dev); 56836b4959f4SRob Clark drm_mode_create_standard_properties(dev); 568487d24fc3SLaurent Pinchart drm_modeset_unlock_all(dev); 568587d24fc3SLaurent Pinchart 568687d24fc3SLaurent Pinchart /* Just to be sure */ 568787d24fc3SLaurent Pinchart dev->mode_config.num_fb = 0; 568887d24fc3SLaurent Pinchart dev->mode_config.num_connector = 0; 568987d24fc3SLaurent Pinchart dev->mode_config.num_crtc = 0; 569087d24fc3SLaurent Pinchart dev->mode_config.num_encoder = 0; 5691e27dde3eSMatt Roper dev->mode_config.num_overlay_plane = 0; 5692e27dde3eSMatt Roper dev->mode_config.num_total_plane = 0; 569387d24fc3SLaurent Pinchart } 569487d24fc3SLaurent Pinchart EXPORT_SYMBOL(drm_mode_config_init); 569587d24fc3SLaurent Pinchart 569687d24fc3SLaurent Pinchart /** 569787d24fc3SLaurent Pinchart * drm_mode_config_cleanup - free up DRM mode_config info 569887d24fc3SLaurent Pinchart * @dev: DRM device 569987d24fc3SLaurent Pinchart * 570087d24fc3SLaurent Pinchart * Free up all the connectors and CRTCs associated with this DRM device, then 570187d24fc3SLaurent Pinchart * free up the framebuffers and associated buffer objects. 570287d24fc3SLaurent Pinchart * 570387d24fc3SLaurent Pinchart * Note that since this /should/ happen single-threaded at driver/device 570487d24fc3SLaurent Pinchart * teardown time, no locking is required. It's the driver's job to ensure that 570587d24fc3SLaurent Pinchart * this guarantee actually holds true. 570687d24fc3SLaurent Pinchart * 570787d24fc3SLaurent Pinchart * FIXME: cleanup any dangling user buffer objects too 570887d24fc3SLaurent Pinchart */ 570987d24fc3SLaurent Pinchart void drm_mode_config_cleanup(struct drm_device *dev) 571087d24fc3SLaurent Pinchart { 571187d24fc3SLaurent Pinchart struct drm_connector *connector, *ot; 571287d24fc3SLaurent Pinchart struct drm_crtc *crtc, *ct; 571387d24fc3SLaurent Pinchart struct drm_encoder *encoder, *enct; 571487d24fc3SLaurent Pinchart struct drm_framebuffer *fb, *fbt; 571587d24fc3SLaurent Pinchart struct drm_property *property, *pt; 571687d24fc3SLaurent Pinchart struct drm_property_blob *blob, *bt; 571787d24fc3SLaurent Pinchart struct drm_plane *plane, *plt; 571887d24fc3SLaurent Pinchart 571987d24fc3SLaurent Pinchart list_for_each_entry_safe(encoder, enct, &dev->mode_config.encoder_list, 572087d24fc3SLaurent Pinchart head) { 572187d24fc3SLaurent Pinchart encoder->funcs->destroy(encoder); 572287d24fc3SLaurent Pinchart } 572387d24fc3SLaurent Pinchart 572487d24fc3SLaurent Pinchart list_for_each_entry_safe(connector, ot, 572587d24fc3SLaurent Pinchart &dev->mode_config.connector_list, head) { 572687d24fc3SLaurent Pinchart connector->funcs->destroy(connector); 572787d24fc3SLaurent Pinchart } 572887d24fc3SLaurent Pinchart 572987d24fc3SLaurent Pinchart list_for_each_entry_safe(property, pt, &dev->mode_config.property_list, 573087d24fc3SLaurent Pinchart head) { 573187d24fc3SLaurent Pinchart drm_property_destroy(dev, property); 573287d24fc3SLaurent Pinchart } 573387d24fc3SLaurent Pinchart 5734f35034f8SMaarten Lankhorst list_for_each_entry_safe(plane, plt, &dev->mode_config.plane_list, 5735f35034f8SMaarten Lankhorst head) { 5736f35034f8SMaarten Lankhorst plane->funcs->destroy(plane); 5737f35034f8SMaarten Lankhorst } 5738f35034f8SMaarten Lankhorst 5739f35034f8SMaarten Lankhorst list_for_each_entry_safe(crtc, ct, &dev->mode_config.crtc_list, head) { 5740f35034f8SMaarten Lankhorst crtc->funcs->destroy(crtc); 5741f35034f8SMaarten Lankhorst } 5742f35034f8SMaarten Lankhorst 574387d24fc3SLaurent Pinchart list_for_each_entry_safe(blob, bt, &dev->mode_config.property_blob_list, 5744e2f5d2eaSDaniel Stone head_global) { 57456bcacf51SDaniel Stone drm_property_unreference_blob(blob); 574687d24fc3SLaurent Pinchart } 574787d24fc3SLaurent Pinchart 574887d24fc3SLaurent Pinchart /* 574987d24fc3SLaurent Pinchart * Single-threaded teardown context, so it's not required to grab the 575087d24fc3SLaurent Pinchart * fb_lock to protect against concurrent fb_list access. Contrary, it 575187d24fc3SLaurent Pinchart * would actually deadlock with the drm_framebuffer_cleanup function. 575287d24fc3SLaurent Pinchart * 575387d24fc3SLaurent Pinchart * Also, if there are any framebuffers left, that's a driver leak now, 575487d24fc3SLaurent Pinchart * so politely WARN about this. 575587d24fc3SLaurent Pinchart */ 575687d24fc3SLaurent Pinchart WARN_ON(!list_empty(&dev->mode_config.fb_list)); 575787d24fc3SLaurent Pinchart list_for_each_entry_safe(fb, fbt, &dev->mode_config.fb_list, head) { 5758d0f37cf6SDave Airlie drm_framebuffer_free(&fb->base.refcount); 575987d24fc3SLaurent Pinchart } 576087d24fc3SLaurent Pinchart 57615fff80bbSMaarten Lankhorst ida_destroy(&dev->mode_config.connector_ida); 5762138f9ebbSDave Airlie idr_destroy(&dev->mode_config.tile_idr); 576387d24fc3SLaurent Pinchart idr_destroy(&dev->mode_config.crtc_idr); 576451fd371bSRob Clark drm_modeset_lock_fini(&dev->mode_config.connection_mutex); 576587d24fc3SLaurent Pinchart } 576687d24fc3SLaurent Pinchart EXPORT_SYMBOL(drm_mode_config_cleanup); 5767c1df5f3cSVille Syrjälä 5768c1df5f3cSVille Syrjälä struct drm_property *drm_mode_create_rotation_property(struct drm_device *dev, 5769c1df5f3cSVille Syrjälä unsigned int supported_rotations) 5770c1df5f3cSVille Syrjälä { 5771c1df5f3cSVille Syrjälä static const struct drm_prop_enum_list props[] = { 5772c1df5f3cSVille Syrjälä { DRM_ROTATE_0, "rotate-0" }, 5773c1df5f3cSVille Syrjälä { DRM_ROTATE_90, "rotate-90" }, 5774c1df5f3cSVille Syrjälä { DRM_ROTATE_180, "rotate-180" }, 5775c1df5f3cSVille Syrjälä { DRM_ROTATE_270, "rotate-270" }, 5776c1df5f3cSVille Syrjälä { DRM_REFLECT_X, "reflect-x" }, 5777c1df5f3cSVille Syrjälä { DRM_REFLECT_Y, "reflect-y" }, 5778c1df5f3cSVille Syrjälä }; 5779c1df5f3cSVille Syrjälä 5780c1df5f3cSVille Syrjälä return drm_property_create_bitmask(dev, 0, "rotation", 5781c1df5f3cSVille Syrjälä props, ARRAY_SIZE(props), 5782c1df5f3cSVille Syrjälä supported_rotations); 5783c1df5f3cSVille Syrjälä } 5784c1df5f3cSVille Syrjälä EXPORT_SYMBOL(drm_mode_create_rotation_property); 5785138f9ebbSDave Airlie 5786138f9ebbSDave Airlie /** 5787138f9ebbSDave Airlie * DOC: Tile group 5788138f9ebbSDave Airlie * 5789138f9ebbSDave Airlie * Tile groups are used to represent tiled monitors with a unique 5790138f9ebbSDave Airlie * integer identifier. Tiled monitors using DisplayID v1.3 have 5791138f9ebbSDave Airlie * a unique 8-byte handle, we store this in a tile group, so we 5792138f9ebbSDave Airlie * have a common identifier for all tiles in a monitor group. 5793138f9ebbSDave Airlie */ 5794138f9ebbSDave Airlie static void drm_tile_group_free(struct kref *kref) 5795138f9ebbSDave Airlie { 5796138f9ebbSDave Airlie struct drm_tile_group *tg = container_of(kref, struct drm_tile_group, refcount); 5797138f9ebbSDave Airlie struct drm_device *dev = tg->dev; 5798138f9ebbSDave Airlie mutex_lock(&dev->mode_config.idr_mutex); 5799138f9ebbSDave Airlie idr_remove(&dev->mode_config.tile_idr, tg->id); 5800138f9ebbSDave Airlie mutex_unlock(&dev->mode_config.idr_mutex); 5801138f9ebbSDave Airlie kfree(tg); 5802138f9ebbSDave Airlie } 5803138f9ebbSDave Airlie 5804138f9ebbSDave Airlie /** 5805138f9ebbSDave Airlie * drm_mode_put_tile_group - drop a reference to a tile group. 5806138f9ebbSDave Airlie * @dev: DRM device 5807138f9ebbSDave Airlie * @tg: tile group to drop reference to. 5808138f9ebbSDave Airlie * 5809138f9ebbSDave Airlie * drop reference to tile group and free if 0. 5810138f9ebbSDave Airlie */ 5811138f9ebbSDave Airlie void drm_mode_put_tile_group(struct drm_device *dev, 5812138f9ebbSDave Airlie struct drm_tile_group *tg) 5813138f9ebbSDave Airlie { 5814138f9ebbSDave Airlie kref_put(&tg->refcount, drm_tile_group_free); 5815138f9ebbSDave Airlie } 5816138f9ebbSDave Airlie 5817138f9ebbSDave Airlie /** 5818138f9ebbSDave Airlie * drm_mode_get_tile_group - get a reference to an existing tile group 5819138f9ebbSDave Airlie * @dev: DRM device 5820138f9ebbSDave Airlie * @topology: 8-bytes unique per monitor. 5821138f9ebbSDave Airlie * 5822138f9ebbSDave Airlie * Use the unique bytes to get a reference to an existing tile group. 5823138f9ebbSDave Airlie * 5824138f9ebbSDave Airlie * RETURNS: 5825138f9ebbSDave Airlie * tile group or NULL if not found. 5826138f9ebbSDave Airlie */ 5827138f9ebbSDave Airlie struct drm_tile_group *drm_mode_get_tile_group(struct drm_device *dev, 5828138f9ebbSDave Airlie char topology[8]) 5829138f9ebbSDave Airlie { 5830138f9ebbSDave Airlie struct drm_tile_group *tg; 5831138f9ebbSDave Airlie int id; 5832138f9ebbSDave Airlie mutex_lock(&dev->mode_config.idr_mutex); 5833138f9ebbSDave Airlie idr_for_each_entry(&dev->mode_config.tile_idr, tg, id) { 5834138f9ebbSDave Airlie if (!memcmp(tg->group_data, topology, 8)) { 5835138f9ebbSDave Airlie if (!kref_get_unless_zero(&tg->refcount)) 5836138f9ebbSDave Airlie tg = NULL; 5837138f9ebbSDave Airlie mutex_unlock(&dev->mode_config.idr_mutex); 5838138f9ebbSDave Airlie return tg; 5839138f9ebbSDave Airlie } 5840138f9ebbSDave Airlie } 5841138f9ebbSDave Airlie mutex_unlock(&dev->mode_config.idr_mutex); 5842138f9ebbSDave Airlie return NULL; 5843138f9ebbSDave Airlie } 584481ddd1bcSRob Clark EXPORT_SYMBOL(drm_mode_get_tile_group); 5845138f9ebbSDave Airlie 5846138f9ebbSDave Airlie /** 5847138f9ebbSDave Airlie * drm_mode_create_tile_group - create a tile group from a displayid description 5848138f9ebbSDave Airlie * @dev: DRM device 5849138f9ebbSDave Airlie * @topology: 8-bytes unique per monitor. 5850138f9ebbSDave Airlie * 5851138f9ebbSDave Airlie * Create a tile group for the unique monitor, and get a unique 5852138f9ebbSDave Airlie * identifier for the tile group. 5853138f9ebbSDave Airlie * 5854138f9ebbSDave Airlie * RETURNS: 5855138f9ebbSDave Airlie * new tile group or error. 5856138f9ebbSDave Airlie */ 5857138f9ebbSDave Airlie struct drm_tile_group *drm_mode_create_tile_group(struct drm_device *dev, 5858138f9ebbSDave Airlie char topology[8]) 5859138f9ebbSDave Airlie { 5860138f9ebbSDave Airlie struct drm_tile_group *tg; 5861138f9ebbSDave Airlie int ret; 5862138f9ebbSDave Airlie 5863138f9ebbSDave Airlie tg = kzalloc(sizeof(*tg), GFP_KERNEL); 5864138f9ebbSDave Airlie if (!tg) 5865138f9ebbSDave Airlie return ERR_PTR(-ENOMEM); 5866138f9ebbSDave Airlie 5867138f9ebbSDave Airlie kref_init(&tg->refcount); 5868138f9ebbSDave Airlie memcpy(tg->group_data, topology, 8); 5869138f9ebbSDave Airlie tg->dev = dev; 5870138f9ebbSDave Airlie 5871138f9ebbSDave Airlie mutex_lock(&dev->mode_config.idr_mutex); 5872138f9ebbSDave Airlie ret = idr_alloc(&dev->mode_config.tile_idr, tg, 1, 0, GFP_KERNEL); 5873138f9ebbSDave Airlie if (ret >= 0) { 5874138f9ebbSDave Airlie tg->id = ret; 5875138f9ebbSDave Airlie } else { 5876138f9ebbSDave Airlie kfree(tg); 5877138f9ebbSDave Airlie tg = ERR_PTR(ret); 5878138f9ebbSDave Airlie } 5879138f9ebbSDave Airlie 5880138f9ebbSDave Airlie mutex_unlock(&dev->mode_config.idr_mutex); 5881138f9ebbSDave Airlie return tg; 5882138f9ebbSDave Airlie } 588381ddd1bcSRob Clark EXPORT_SYMBOL(drm_mode_create_tile_group); 5884f8ed34acSJyri Sarha 5885f8ed34acSJyri Sarha /** 5886f8ed34acSJyri Sarha * drm_crtc_enable_color_mgmt - enable color management properties 5887f8ed34acSJyri Sarha * @crtc: DRM CRTC 5888f8ed34acSJyri Sarha * @degamma_lut_size: the size of the degamma lut (before CSC) 5889f8ed34acSJyri Sarha * @has_ctm: whether to attach ctm_property for CSC matrix 5890f8ed34acSJyri Sarha * @gamma_lut_size: the size of the gamma lut (after CSC) 5891f8ed34acSJyri Sarha * 5892f8ed34acSJyri Sarha * This function lets the driver enable the color correction 5893f8ed34acSJyri Sarha * properties on a CRTC. This includes 3 degamma, csc and gamma 5894f8ed34acSJyri Sarha * properties that userspace can set and 2 size properties to inform 5895f8ed34acSJyri Sarha * the userspace of the lut sizes. Each of the properties are 5896f8ed34acSJyri Sarha * optional. The gamma and degamma properties are only attached if 5897f8ed34acSJyri Sarha * their size is not 0 and ctm_property is only attached if has_ctm is 5898f8ed34acSJyri Sarha * true. 5899f8ed34acSJyri Sarha */ 5900f8ed34acSJyri Sarha void drm_crtc_enable_color_mgmt(struct drm_crtc *crtc, 5901f8ed34acSJyri Sarha uint degamma_lut_size, 5902f8ed34acSJyri Sarha bool has_ctm, 5903f8ed34acSJyri Sarha uint gamma_lut_size) 5904f8ed34acSJyri Sarha { 5905f8ed34acSJyri Sarha struct drm_device *dev = crtc->dev; 5906f8ed34acSJyri Sarha struct drm_mode_config *config = &dev->mode_config; 5907f8ed34acSJyri Sarha 5908f8ed34acSJyri Sarha if (degamma_lut_size) { 5909f8ed34acSJyri Sarha drm_object_attach_property(&crtc->base, 5910f8ed34acSJyri Sarha config->degamma_lut_property, 0); 5911f8ed34acSJyri Sarha drm_object_attach_property(&crtc->base, 5912f8ed34acSJyri Sarha config->degamma_lut_size_property, 5913f8ed34acSJyri Sarha degamma_lut_size); 5914f8ed34acSJyri Sarha } 5915f8ed34acSJyri Sarha 5916f8ed34acSJyri Sarha if (has_ctm) 5917f8ed34acSJyri Sarha drm_object_attach_property(&crtc->base, 5918f8ed34acSJyri Sarha config->ctm_property, 0); 5919f8ed34acSJyri Sarha 5920f8ed34acSJyri Sarha if (gamma_lut_size) { 5921f8ed34acSJyri Sarha drm_object_attach_property(&crtc->base, 5922f8ed34acSJyri Sarha config->gamma_lut_property, 0); 5923f8ed34acSJyri Sarha drm_object_attach_property(&crtc->base, 5924f8ed34acSJyri Sarha config->gamma_lut_size_property, 5925f8ed34acSJyri Sarha gamma_lut_size); 5926f8ed34acSJyri Sarha } 5927f8ed34acSJyri Sarha } 5928f8ed34acSJyri Sarha EXPORT_SYMBOL(drm_crtc_enable_color_mgmt); 5929