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ä 611f453ba04SDave Airlie /** 612e13161afSMatt Roper * drm_crtc_init_with_planes - Initialise a new CRTC object with 613e13161afSMatt Roper * specified primary and cursor planes. 614f453ba04SDave Airlie * @dev: DRM device 615f453ba04SDave Airlie * @crtc: CRTC object to init 616e13161afSMatt Roper * @primary: Primary plane for CRTC 617e13161afSMatt Roper * @cursor: Cursor plane for CRTC 618f453ba04SDave Airlie * @funcs: callbacks for the new CRTC 619f9882876SVille Syrjälä * @name: printf style format string for the CRTC name, or NULL for default name 620f453ba04SDave Airlie * 621ad6f5c34SVille Syrjälä * Inits a new object created as base part of a driver crtc object. 6226bfc56aaSVille Syrjälä * 623c8e32cc1SDaniel Vetter * Returns: 6246bfc56aaSVille Syrjälä * Zero on success, error code on failure. 625f453ba04SDave Airlie */ 626e13161afSMatt Roper int drm_crtc_init_with_planes(struct drm_device *dev, struct drm_crtc *crtc, 627e13161afSMatt Roper struct drm_plane *primary, 628fc1d3e44SMatt Roper struct drm_plane *cursor, 629f9882876SVille Syrjälä const struct drm_crtc_funcs *funcs, 630f9882876SVille Syrjälä const char *name, ...) 631f453ba04SDave Airlie { 63251fd371bSRob Clark struct drm_mode_config *config = &dev->mode_config; 6336bfc56aaSVille Syrjälä int ret; 6346bfc56aaSVille Syrjälä 635522cf91fSBenjamin Gaignard WARN_ON(primary && primary->type != DRM_PLANE_TYPE_PRIMARY); 636522cf91fSBenjamin Gaignard WARN_ON(cursor && cursor->type != DRM_PLANE_TYPE_CURSOR); 637522cf91fSBenjamin Gaignard 638f453ba04SDave Airlie crtc->dev = dev; 639f453ba04SDave Airlie crtc->funcs = funcs; 640f453ba04SDave Airlie 6413b24f7d6SDaniel Vetter INIT_LIST_HEAD(&crtc->commit_list); 6423b24f7d6SDaniel Vetter spin_lock_init(&crtc->commit_lock); 6433b24f7d6SDaniel Vetter 64451fd371bSRob Clark drm_modeset_lock_init(&crtc->mutex); 6456bfc56aaSVille Syrjälä ret = drm_mode_object_get(dev, &crtc->base, DRM_MODE_OBJECT_CRTC); 6466bfc56aaSVille Syrjälä if (ret) 647baf698b0SDaniel Vetter return ret; 648f453ba04SDave Airlie 649fa3ab4c2SVille Syrjälä if (name) { 650fa3ab4c2SVille Syrjälä va_list ap; 651fa3ab4c2SVille Syrjälä 652fa3ab4c2SVille Syrjälä va_start(ap, name); 653fa3ab4c2SVille Syrjälä crtc->name = kvasprintf(GFP_KERNEL, name, ap); 654fa3ab4c2SVille Syrjälä va_end(ap); 655fa3ab4c2SVille Syrjälä } else { 656fa3ab4c2SVille Syrjälä crtc->name = kasprintf(GFP_KERNEL, "crtc-%d", 657fa3ab4c2SVille Syrjälä drm_num_crtcs(dev)); 658fa3ab4c2SVille Syrjälä } 659fa3ab4c2SVille Syrjälä if (!crtc->name) { 6607c8f6d25SDave Airlie drm_mode_object_unregister(dev, &crtc->base); 661fa3ab4c2SVille Syrjälä return -ENOMEM; 662fa3ab4c2SVille Syrjälä } 663fa3ab4c2SVille Syrjälä 664bffd9de0SPaulo Zanoni crtc->base.properties = &crtc->properties; 665bffd9de0SPaulo Zanoni 66651fd371bSRob Clark list_add_tail(&crtc->head, &config->crtc_list); 667490d3d1bSChris Wilson crtc->index = config->num_crtc++; 6686bfc56aaSVille Syrjälä 669e13161afSMatt Roper crtc->primary = primary; 670fc1d3e44SMatt Roper crtc->cursor = cursor; 671e13161afSMatt Roper if (primary) 672e13161afSMatt Roper primary->possible_crtcs = 1 << drm_crtc_index(crtc); 673fc1d3e44SMatt Roper if (cursor) 674fc1d3e44SMatt Roper cursor->possible_crtcs = 1 << drm_crtc_index(crtc); 675e13161afSMatt Roper 676eab3bbefSDaniel Vetter if (drm_core_check_feature(dev, DRIVER_ATOMIC)) { 677eab3bbefSDaniel Vetter drm_object_attach_property(&crtc->base, config->prop_active, 0); 678955f3c33SDaniel Stone drm_object_attach_property(&crtc->base, config->prop_mode_id, 0); 679eab3bbefSDaniel Vetter } 680eab3bbefSDaniel Vetter 681baf698b0SDaniel Vetter return 0; 682f453ba04SDave Airlie } 683e13161afSMatt Roper EXPORT_SYMBOL(drm_crtc_init_with_planes); 684f453ba04SDave Airlie 685f453ba04SDave Airlie /** 686ad6f5c34SVille Syrjälä * drm_crtc_cleanup - Clean up the core crtc usage 687f453ba04SDave Airlie * @crtc: CRTC to cleanup 688f453ba04SDave Airlie * 689ad6f5c34SVille Syrjälä * This function cleans up @crtc and removes it from the DRM mode setting 690ad6f5c34SVille Syrjälä * core. Note that the function does *not* free the crtc structure itself, 691ad6f5c34SVille Syrjälä * this is the responsibility of the caller. 692f453ba04SDave Airlie */ 693f453ba04SDave Airlie void drm_crtc_cleanup(struct drm_crtc *crtc) 694f453ba04SDave Airlie { 695f453ba04SDave Airlie struct drm_device *dev = crtc->dev; 696f453ba04SDave Airlie 697490d3d1bSChris Wilson /* Note that the crtc_list is considered to be static; should we 698490d3d1bSChris Wilson * remove the drm_crtc at runtime we would have to decrement all 699490d3d1bSChris Wilson * the indices on the drm_crtc after us in the crtc_list. 700490d3d1bSChris Wilson */ 701490d3d1bSChris Wilson 702f453ba04SDave Airlie kfree(crtc->gamma_store); 703f453ba04SDave Airlie crtc->gamma_store = NULL; 704f453ba04SDave Airlie 70551fd371bSRob Clark drm_modeset_lock_fini(&crtc->mutex); 70651fd371bSRob Clark 7077c8f6d25SDave Airlie drm_mode_object_unregister(dev, &crtc->base); 708f453ba04SDave Airlie list_del(&crtc->head); 709f453ba04SDave Airlie dev->mode_config.num_crtc--; 7103009c037SThierry Reding 7113009c037SThierry Reding WARN_ON(crtc->state && !crtc->funcs->atomic_destroy_state); 7123009c037SThierry Reding if (crtc->state && crtc->funcs->atomic_destroy_state) 7133009c037SThierry Reding crtc->funcs->atomic_destroy_state(crtc, crtc->state); 714a18c0af1SThierry Reding 715fa3ab4c2SVille Syrjälä kfree(crtc->name); 716fa3ab4c2SVille Syrjälä 717a18c0af1SThierry Reding memset(crtc, 0, sizeof(*crtc)); 718f453ba04SDave Airlie } 719f453ba04SDave Airlie EXPORT_SYMBOL(drm_crtc_cleanup); 720f453ba04SDave Airlie 72186f422d5SLespiau, Damien /* 722f453ba04SDave Airlie * drm_mode_remove - remove and free a mode 723f453ba04SDave Airlie * @connector: connector list to modify 724f453ba04SDave Airlie * @mode: mode to remove 725f453ba04SDave Airlie * 726f453ba04SDave Airlie * Remove @mode from @connector's mode list, then free it. 727f453ba04SDave Airlie */ 72886f422d5SLespiau, Damien static void drm_mode_remove(struct drm_connector *connector, 729f453ba04SDave Airlie struct drm_display_mode *mode) 730f453ba04SDave Airlie { 731f453ba04SDave Airlie list_del(&mode->head); 732554f1d78SSascha Hauer drm_mode_destroy(connector->dev, mode); 733f453ba04SDave Airlie } 734f453ba04SDave Airlie 735f453ba04SDave Airlie /** 736b5571e9dSBoris Brezillon * drm_display_info_set_bus_formats - set the supported bus formats 737b5571e9dSBoris Brezillon * @info: display info to store bus formats in 738e37bfa1aSBoris Brezillon * @formats: array containing the supported bus formats 739e37bfa1aSBoris Brezillon * @num_formats: the number of entries in the fmts array 740b5571e9dSBoris Brezillon * 741b5571e9dSBoris Brezillon * Store the supported bus formats in display info structure. 742b5571e9dSBoris Brezillon * See MEDIA_BUS_FMT_* definitions in include/uapi/linux/media-bus-format.h for 743b5571e9dSBoris Brezillon * a full list of available formats. 744b5571e9dSBoris Brezillon */ 745b5571e9dSBoris Brezillon int drm_display_info_set_bus_formats(struct drm_display_info *info, 746b5571e9dSBoris Brezillon const u32 *formats, 747b5571e9dSBoris Brezillon unsigned int num_formats) 748b5571e9dSBoris Brezillon { 749b5571e9dSBoris Brezillon u32 *fmts = NULL; 750b5571e9dSBoris Brezillon 751b5571e9dSBoris Brezillon if (!formats && num_formats) 752b5571e9dSBoris Brezillon return -EINVAL; 753b5571e9dSBoris Brezillon 754b5571e9dSBoris Brezillon if (formats && num_formats) { 755b5571e9dSBoris Brezillon fmts = kmemdup(formats, sizeof(*formats) * num_formats, 756b5571e9dSBoris Brezillon GFP_KERNEL); 757944579c5SDan Carpenter if (!fmts) 758b5571e9dSBoris Brezillon return -ENOMEM; 759b5571e9dSBoris Brezillon } 760b5571e9dSBoris Brezillon 761b5571e9dSBoris Brezillon kfree(info->bus_formats); 762b5571e9dSBoris Brezillon info->bus_formats = fmts; 763b5571e9dSBoris Brezillon info->num_bus_formats = num_formats; 764b5571e9dSBoris Brezillon 765b5571e9dSBoris Brezillon return 0; 766b5571e9dSBoris Brezillon } 767b5571e9dSBoris Brezillon EXPORT_SYMBOL(drm_display_info_set_bus_formats); 768b5571e9dSBoris Brezillon 769b5571e9dSBoris Brezillon /** 770eaf99c74SChris Wilson * drm_connector_get_cmdline_mode - reads the user's cmdline mode 771eaf99c74SChris Wilson * @connector: connector to quwery 772eaf99c74SChris Wilson * 773eaf99c74SChris Wilson * The kernel supports per-connector configration of its consoles through 774eaf99c74SChris Wilson * use of the video= parameter. This function parses that option and 775eaf99c74SChris Wilson * extracts the user's specified mode (or enable/disable status) for a 776eaf99c74SChris Wilson * particular connector. This is typically only used during the early fbdev 777eaf99c74SChris Wilson * setup. 778eaf99c74SChris Wilson */ 779eaf99c74SChris Wilson static void drm_connector_get_cmdline_mode(struct drm_connector *connector) 780eaf99c74SChris Wilson { 781eaf99c74SChris Wilson struct drm_cmdline_mode *mode = &connector->cmdline_mode; 782eaf99c74SChris Wilson char *option = NULL; 783eaf99c74SChris Wilson 784eaf99c74SChris Wilson if (fb_get_options(connector->name, &option)) 785eaf99c74SChris Wilson return; 786eaf99c74SChris Wilson 787eaf99c74SChris Wilson if (!drm_mode_parse_command_line_for_connector(option, 788eaf99c74SChris Wilson connector, 789eaf99c74SChris Wilson mode)) 790eaf99c74SChris Wilson return; 791eaf99c74SChris Wilson 792eaf99c74SChris Wilson if (mode->force) { 793eaf99c74SChris Wilson const char *s; 794eaf99c74SChris Wilson 795eaf99c74SChris Wilson switch (mode->force) { 796eaf99c74SChris Wilson case DRM_FORCE_OFF: 797eaf99c74SChris Wilson s = "OFF"; 798eaf99c74SChris Wilson break; 799eaf99c74SChris Wilson case DRM_FORCE_ON_DIGITAL: 800eaf99c74SChris Wilson s = "ON - dig"; 801eaf99c74SChris Wilson break; 802eaf99c74SChris Wilson default: 803eaf99c74SChris Wilson case DRM_FORCE_ON: 804eaf99c74SChris Wilson s = "ON"; 805eaf99c74SChris Wilson break; 806eaf99c74SChris Wilson } 807eaf99c74SChris Wilson 808eaf99c74SChris Wilson DRM_INFO("forcing %s connector %s\n", connector->name, s); 809eaf99c74SChris Wilson connector->force = mode->force; 810eaf99c74SChris Wilson } 811eaf99c74SChris Wilson 812eaf99c74SChris Wilson DRM_DEBUG_KMS("cmdline mode for connector %s %dx%d@%dHz%s%s%s\n", 813eaf99c74SChris Wilson connector->name, 814eaf99c74SChris Wilson mode->xres, mode->yres, 815eaf99c74SChris Wilson mode->refresh_specified ? mode->refresh : 60, 816eaf99c74SChris Wilson mode->rb ? " reduced blanking" : "", 817eaf99c74SChris Wilson mode->margins ? " with margins" : "", 818eaf99c74SChris Wilson mode->interlace ? " interlaced" : ""); 819eaf99c74SChris Wilson } 820eaf99c74SChris Wilson 821b164d31fSDave Airlie static void drm_connector_free(struct kref *kref) 822b164d31fSDave Airlie { 823b164d31fSDave Airlie struct drm_connector *connector = 824b164d31fSDave Airlie container_of(kref, struct drm_connector, base.refcount); 825b164d31fSDave Airlie struct drm_device *dev = connector->dev; 826b164d31fSDave Airlie 827b164d31fSDave Airlie drm_mode_object_unregister(dev, &connector->base); 828b164d31fSDave Airlie connector->funcs->destroy(connector); 829b164d31fSDave Airlie } 830b164d31fSDave Airlie 831eaf99c74SChris Wilson /** 832f453ba04SDave Airlie * drm_connector_init - Init a preallocated connector 833f453ba04SDave Airlie * @dev: DRM device 834f453ba04SDave Airlie * @connector: the connector to init 835f453ba04SDave Airlie * @funcs: callbacks for this connector 836065a50edSDaniel Vetter * @connector_type: user visible type of the connector 837f453ba04SDave Airlie * 838f453ba04SDave Airlie * Initialises a preallocated connector. Connectors should be 839f453ba04SDave Airlie * subclassed as part of driver connector objects. 8406bfc56aaSVille Syrjälä * 841c8e32cc1SDaniel Vetter * Returns: 8426bfc56aaSVille Syrjälä * Zero on success, error code on failure. 843f453ba04SDave Airlie */ 8446bfc56aaSVille Syrjälä int drm_connector_init(struct drm_device *dev, 845f453ba04SDave Airlie struct drm_connector *connector, 846f453ba04SDave Airlie const struct drm_connector_funcs *funcs, 847f453ba04SDave Airlie int connector_type) 848f453ba04SDave Airlie { 849ae16c597SRob Clark struct drm_mode_config *config = &dev->mode_config; 8506bfc56aaSVille Syrjälä int ret; 851b21e3afeSIlia Mirkin struct ida *connector_ida = 852b21e3afeSIlia Mirkin &drm_connector_enum_list[connector_type].ida; 8536bfc56aaSVille Syrjälä 85484849903SDaniel Vetter drm_modeset_lock_all(dev); 855f453ba04SDave Airlie 856b164d31fSDave Airlie ret = drm_mode_object_get_reg(dev, &connector->base, 857b164d31fSDave Airlie DRM_MODE_OBJECT_CONNECTOR, 858b164d31fSDave Airlie false, drm_connector_free); 8596bfc56aaSVille Syrjälä if (ret) 8602abdd313SJani Nikula goto out_unlock; 8616bfc56aaSVille Syrjälä 8627e3bdf4aSPaulo Zanoni connector->base.properties = &connector->properties; 863f453ba04SDave Airlie connector->dev = dev; 864f453ba04SDave Airlie connector->funcs = funcs; 8655fff80bbSMaarten Lankhorst 8665fff80bbSMaarten Lankhorst connector->connector_id = ida_simple_get(&config->connector_ida, 0, 0, GFP_KERNEL); 8675fff80bbSMaarten Lankhorst if (connector->connector_id < 0) { 8685fff80bbSMaarten Lankhorst ret = connector->connector_id; 8695fff80bbSMaarten Lankhorst goto out_put; 8705fff80bbSMaarten Lankhorst } 8715fff80bbSMaarten Lankhorst 872f453ba04SDave Airlie connector->connector_type = connector_type; 873f453ba04SDave Airlie connector->connector_type_id = 874b21e3afeSIlia Mirkin ida_simple_get(connector_ida, 1, 0, GFP_KERNEL); 875b21e3afeSIlia Mirkin if (connector->connector_type_id < 0) { 876b21e3afeSIlia Mirkin ret = connector->connector_type_id; 8775fff80bbSMaarten Lankhorst goto out_put_id; 878b21e3afeSIlia Mirkin } 8792abdd313SJani Nikula connector->name = 8802abdd313SJani Nikula kasprintf(GFP_KERNEL, "%s-%d", 8812abdd313SJani Nikula drm_connector_enum_list[connector_type].name, 8822abdd313SJani Nikula connector->connector_type_id); 8832abdd313SJani Nikula if (!connector->name) { 8842abdd313SJani Nikula ret = -ENOMEM; 8855fff80bbSMaarten Lankhorst goto out_put_type_id; 8862abdd313SJani Nikula } 8872abdd313SJani Nikula 888f453ba04SDave Airlie INIT_LIST_HEAD(&connector->probed_modes); 889f453ba04SDave Airlie INIT_LIST_HEAD(&connector->modes); 890f453ba04SDave Airlie connector->edid_blob_ptr = NULL; 8915e2cb2f6SDaniel Vetter connector->status = connector_status_unknown; 892f453ba04SDave Airlie 893eaf99c74SChris Wilson drm_connector_get_cmdline_mode(connector); 894eaf99c74SChris Wilson 895c7eb76f4SDaniel Vetter /* We should add connectors at the end to avoid upsetting the connector 896c7eb76f4SDaniel Vetter * index too much. */ 897ae16c597SRob Clark list_add_tail(&connector->head, &config->connector_list); 898ae16c597SRob Clark config->num_connector++; 899f453ba04SDave Airlie 900a7331e5cSThomas Hellstrom if (connector_type != DRM_MODE_CONNECTOR_VIRTUAL) 90158495563SRob Clark drm_object_attach_property(&connector->base, 902ae16c597SRob Clark config->edid_property, 903a7331e5cSThomas Hellstrom 0); 904f453ba04SDave Airlie 90558495563SRob Clark drm_object_attach_property(&connector->base, 906ae16c597SRob Clark config->dpms_property, 0); 907ae16c597SRob Clark 908ae16c597SRob Clark if (drm_core_check_feature(dev, DRIVER_ATOMIC)) { 909ae16c597SRob Clark drm_object_attach_property(&connector->base, config->prop_crtc_id, 0); 910ae16c597SRob Clark } 911f453ba04SDave Airlie 91230f65707SThomas Wood connector->debugfs_entry = NULL; 9135fff80bbSMaarten Lankhorst out_put_type_id: 9145fff80bbSMaarten Lankhorst if (ret) 9155fff80bbSMaarten Lankhorst ida_remove(connector_ida, connector->connector_type_id); 9165fff80bbSMaarten Lankhorst out_put_id: 9175fff80bbSMaarten Lankhorst if (ret) 9185fff80bbSMaarten Lankhorst ida_remove(&config->connector_ida, connector->connector_id); 9192abdd313SJani Nikula out_put: 9202abdd313SJani Nikula if (ret) 9217c8f6d25SDave Airlie drm_mode_object_unregister(dev, &connector->base); 9222abdd313SJani Nikula 9232abdd313SJani Nikula out_unlock: 92484849903SDaniel Vetter drm_modeset_unlock_all(dev); 9256bfc56aaSVille Syrjälä 9266bfc56aaSVille Syrjälä return ret; 927f453ba04SDave Airlie } 928f453ba04SDave Airlie EXPORT_SYMBOL(drm_connector_init); 929f453ba04SDave Airlie 930f453ba04SDave Airlie /** 931f453ba04SDave Airlie * drm_connector_cleanup - cleans up an initialised connector 932f453ba04SDave Airlie * @connector: connector to cleanup 933f453ba04SDave Airlie * 934f453ba04SDave Airlie * Cleans up the connector but doesn't free the object. 935f453ba04SDave Airlie */ 936f453ba04SDave Airlie void drm_connector_cleanup(struct drm_connector *connector) 937f453ba04SDave Airlie { 938f453ba04SDave Airlie struct drm_device *dev = connector->dev; 939f453ba04SDave Airlie struct drm_display_mode *mode, *t; 940f453ba04SDave Airlie 94180de3461SChris Wilson /* The connector should have been removed from userspace long before 94280de3461SChris Wilson * it is finally destroyed. 94380de3461SChris Wilson */ 94480de3461SChris Wilson if (WARN_ON(connector->registered)) 94580de3461SChris Wilson drm_connector_unregister(connector); 94680de3461SChris Wilson 94740d9b043SDave Airlie if (connector->tile_group) { 94840d9b043SDave Airlie drm_mode_put_tile_group(dev, connector->tile_group); 94940d9b043SDave Airlie connector->tile_group = NULL; 95040d9b043SDave Airlie } 95140d9b043SDave Airlie 952f453ba04SDave Airlie list_for_each_entry_safe(mode, t, &connector->probed_modes, head) 953f453ba04SDave Airlie drm_mode_remove(connector, mode); 954f453ba04SDave Airlie 955f453ba04SDave Airlie list_for_each_entry_safe(mode, t, &connector->modes, head) 956f453ba04SDave Airlie drm_mode_remove(connector, mode); 957f453ba04SDave Airlie 958b21e3afeSIlia Mirkin ida_remove(&drm_connector_enum_list[connector->connector_type].ida, 959b21e3afeSIlia Mirkin connector->connector_type_id); 960b21e3afeSIlia Mirkin 9615fff80bbSMaarten Lankhorst ida_remove(&dev->mode_config.connector_ida, 9625fff80bbSMaarten Lankhorst connector->connector_id); 9635fff80bbSMaarten Lankhorst 964b5571e9dSBoris Brezillon kfree(connector->display_info.bus_formats); 9657c8f6d25SDave Airlie drm_mode_object_unregister(dev, &connector->base); 9662abdd313SJani Nikula kfree(connector->name); 9672abdd313SJani Nikula connector->name = NULL; 968f453ba04SDave Airlie list_del(&connector->head); 9696380c509SJoonyoung Shim dev->mode_config.num_connector--; 9703009c037SThierry Reding 9713009c037SThierry Reding WARN_ON(connector->state && !connector->funcs->atomic_destroy_state); 9723009c037SThierry Reding if (connector->state && connector->funcs->atomic_destroy_state) 9733009c037SThierry Reding connector->funcs->atomic_destroy_state(connector, 9743009c037SThierry Reding connector->state); 975a18c0af1SThierry Reding 976a18c0af1SThierry Reding memset(connector, 0, sizeof(*connector)); 977f453ba04SDave Airlie } 978f453ba04SDave Airlie EXPORT_SYMBOL(drm_connector_cleanup); 979f453ba04SDave Airlie 980c8e32cc1SDaniel Vetter /** 98134ea3d38SThomas Wood * drm_connector_register - register a connector 98234ea3d38SThomas Wood * @connector: the connector to register 98334ea3d38SThomas Wood * 98434ea3d38SThomas Wood * Register userspace interfaces for a connector 98534ea3d38SThomas Wood * 98634ea3d38SThomas Wood * Returns: 98734ea3d38SThomas Wood * Zero on success, error code on failure. 98834ea3d38SThomas Wood */ 98934ea3d38SThomas Wood int drm_connector_register(struct drm_connector *connector) 99034ea3d38SThomas Wood { 99130f65707SThomas Wood int ret; 99230f65707SThomas Wood 99340daac61SChris Wilson if (connector->registered) 99440daac61SChris Wilson return 0; 99540daac61SChris Wilson 99630f65707SThomas Wood ret = drm_sysfs_connector_add(connector); 99730f65707SThomas Wood if (ret) 99830f65707SThomas Wood return ret; 99930f65707SThomas Wood 100030f65707SThomas Wood ret = drm_debugfs_connector_add(connector); 100130f65707SThomas Wood if (ret) { 1002aaf285e2SChris Wilson goto err_sysfs; 1003aaf285e2SChris Wilson } 1004aaf285e2SChris Wilson 1005aaf285e2SChris Wilson if (connector->funcs->late_register) { 1006aaf285e2SChris Wilson ret = connector->funcs->late_register(connector); 1007aaf285e2SChris Wilson if (ret) 1008aaf285e2SChris Wilson goto err_debugfs; 100930f65707SThomas Wood } 101030f65707SThomas Wood 1011fdf2c85fSDaniel Vetter drm_mode_object_register(connector->dev, &connector->base); 1012fdf2c85fSDaniel Vetter 101340daac61SChris Wilson connector->registered = true; 101430f65707SThomas Wood return 0; 1015aaf285e2SChris Wilson 1016aaf285e2SChris Wilson err_debugfs: 1017aaf285e2SChris Wilson drm_debugfs_connector_remove(connector); 1018aaf285e2SChris Wilson err_sysfs: 1019aaf285e2SChris Wilson drm_sysfs_connector_remove(connector); 1020aaf285e2SChris Wilson return ret; 102134ea3d38SThomas Wood } 102234ea3d38SThomas Wood EXPORT_SYMBOL(drm_connector_register); 102334ea3d38SThomas Wood 102434ea3d38SThomas Wood /** 102534ea3d38SThomas Wood * drm_connector_unregister - unregister a connector 102634ea3d38SThomas Wood * @connector: the connector to unregister 102734ea3d38SThomas Wood * 102834ea3d38SThomas Wood * Unregister userspace interfaces for a connector 102934ea3d38SThomas Wood */ 103034ea3d38SThomas Wood void drm_connector_unregister(struct drm_connector *connector) 103134ea3d38SThomas Wood { 103240daac61SChris Wilson if (!connector->registered) 103340daac61SChris Wilson return; 103440daac61SChris Wilson 1035aaf285e2SChris Wilson if (connector->funcs->early_unregister) 1036aaf285e2SChris Wilson connector->funcs->early_unregister(connector); 1037aaf285e2SChris Wilson 103834ea3d38SThomas Wood drm_sysfs_connector_remove(connector); 103930f65707SThomas Wood drm_debugfs_connector_remove(connector); 104040daac61SChris Wilson 104140daac61SChris Wilson connector->registered = false; 104234ea3d38SThomas Wood } 104334ea3d38SThomas Wood EXPORT_SYMBOL(drm_connector_unregister); 104434ea3d38SThomas Wood 104534ea3d38SThomas Wood /** 104654d2c2daSAlexey Brodkin * drm_connector_register_all - register all connectors 104754d2c2daSAlexey Brodkin * @dev: drm device 104854d2c2daSAlexey Brodkin * 104954d2c2daSAlexey Brodkin * This function registers all connectors in sysfs and other places so that 1050e28cd4d0SChris Wilson * userspace can start to access them. drm_connector_register_all() is called 1051e28cd4d0SChris Wilson * automatically from drm_dev_register() to complete the device registration, 1052e28cd4d0SChris Wilson * if they don't call drm_connector_register() on each connector individually. 105354d2c2daSAlexey Brodkin * 105454d2c2daSAlexey Brodkin * When a device is unplugged and should be removed from userspace access, 105554d2c2daSAlexey Brodkin * call drm_connector_unregister_all(), which is the inverse of this 105654d2c2daSAlexey Brodkin * function. 105754d2c2daSAlexey Brodkin * 105854d2c2daSAlexey Brodkin * Returns: 105954d2c2daSAlexey Brodkin * Zero on success, error code on failure. 106054d2c2daSAlexey Brodkin */ 106154d2c2daSAlexey Brodkin int drm_connector_register_all(struct drm_device *dev) 106254d2c2daSAlexey Brodkin { 106354d2c2daSAlexey Brodkin struct drm_connector *connector; 106454d2c2daSAlexey Brodkin int ret; 106554d2c2daSAlexey Brodkin 106654d2c2daSAlexey Brodkin mutex_lock(&dev->mode_config.mutex); 106754d2c2daSAlexey Brodkin 106854d2c2daSAlexey Brodkin drm_for_each_connector(connector, dev) { 106954d2c2daSAlexey Brodkin ret = drm_connector_register(connector); 107054d2c2daSAlexey Brodkin if (ret) 107154d2c2daSAlexey Brodkin goto err; 107254d2c2daSAlexey Brodkin } 107354d2c2daSAlexey Brodkin 107454d2c2daSAlexey Brodkin mutex_unlock(&dev->mode_config.mutex); 107554d2c2daSAlexey Brodkin 107654d2c2daSAlexey Brodkin return 0; 107754d2c2daSAlexey Brodkin 107854d2c2daSAlexey Brodkin err: 107954d2c2daSAlexey Brodkin mutex_unlock(&dev->mode_config.mutex); 108054d2c2daSAlexey Brodkin drm_connector_unregister_all(dev); 108154d2c2daSAlexey Brodkin return ret; 108254d2c2daSAlexey Brodkin } 108354d2c2daSAlexey Brodkin EXPORT_SYMBOL(drm_connector_register_all); 108454d2c2daSAlexey Brodkin 108554d2c2daSAlexey Brodkin /** 10866c87e5c3SAlexey Brodkin * drm_connector_unregister_all - unregister connector userspace interfaces 1087c8e32cc1SDaniel Vetter * @dev: drm device 1088c8e32cc1SDaniel Vetter * 10896c87e5c3SAlexey Brodkin * This functions unregisters all connectors from sysfs and other places so 10906c87e5c3SAlexey Brodkin * that userspace can no longer access them. Drivers should call this as the 10916c87e5c3SAlexey Brodkin * first step tearing down the device instace, or when the underlying 10926c87e5c3SAlexey Brodkin * physical device disappeared (e.g. USB unplug), right before calling 10936c87e5c3SAlexey Brodkin * drm_dev_unregister(). 1094c8e32cc1SDaniel Vetter */ 10956c87e5c3SAlexey Brodkin void drm_connector_unregister_all(struct drm_device *dev) 1096cbc7e221SDave Airlie { 1097cbc7e221SDave Airlie struct drm_connector *connector; 1098cbc7e221SDave Airlie 10999a9f5ce8SDaniel Vetter /* FIXME: taking the mode config mutex ends up in a clash with sysfs */ 110014ba0031SLaurent Pinchart list_for_each_entry(connector, &dev->mode_config.connector_list, head) 110134ea3d38SThomas Wood drm_connector_unregister(connector); 1102cbc7e221SDave Airlie } 11036c87e5c3SAlexey Brodkin EXPORT_SYMBOL(drm_connector_unregister_all); 1104cbc7e221SDave Airlie 1105c8e32cc1SDaniel Vetter /** 1106c8e32cc1SDaniel Vetter * drm_encoder_init - Init a preallocated encoder 1107c8e32cc1SDaniel Vetter * @dev: drm device 1108c8e32cc1SDaniel Vetter * @encoder: the encoder to init 1109c8e32cc1SDaniel Vetter * @funcs: callbacks for this encoder 1110c8e32cc1SDaniel Vetter * @encoder_type: user visible type of the encoder 111113a3d91fSVille Syrjälä * @name: printf style format string for the encoder name, or NULL for default name 1112c8e32cc1SDaniel Vetter * 1113c8e32cc1SDaniel Vetter * Initialises a preallocated encoder. Encoder should be 1114c8e32cc1SDaniel Vetter * subclassed as part of driver encoder objects. 1115c8e32cc1SDaniel Vetter * 1116c8e32cc1SDaniel Vetter * Returns: 1117c8e32cc1SDaniel Vetter * Zero on success, error code on failure. 1118c8e32cc1SDaniel Vetter */ 11196bfc56aaSVille Syrjälä int drm_encoder_init(struct drm_device *dev, 1120f453ba04SDave Airlie struct drm_encoder *encoder, 1121f453ba04SDave Airlie const struct drm_encoder_funcs *funcs, 112213a3d91fSVille Syrjälä int encoder_type, const char *name, ...) 1123f453ba04SDave Airlie { 11246bfc56aaSVille Syrjälä int ret; 11256bfc56aaSVille Syrjälä 112684849903SDaniel Vetter drm_modeset_lock_all(dev); 1127f453ba04SDave Airlie 11286bfc56aaSVille Syrjälä ret = drm_mode_object_get(dev, &encoder->base, DRM_MODE_OBJECT_ENCODER); 11296bfc56aaSVille Syrjälä if (ret) 1130e5748946SJani Nikula goto out_unlock; 1131f453ba04SDave Airlie 11326bfc56aaSVille Syrjälä encoder->dev = dev; 1133f453ba04SDave Airlie encoder->encoder_type = encoder_type; 1134f453ba04SDave Airlie encoder->funcs = funcs; 113586bf546bSVille Syrjälä if (name) { 113686bf546bSVille Syrjälä va_list ap; 113786bf546bSVille Syrjälä 113886bf546bSVille Syrjälä va_start(ap, name); 113986bf546bSVille Syrjälä encoder->name = kvasprintf(GFP_KERNEL, name, ap); 114086bf546bSVille Syrjälä va_end(ap); 114186bf546bSVille Syrjälä } else { 1142e5748946SJani Nikula encoder->name = kasprintf(GFP_KERNEL, "%s-%d", 1143e5748946SJani Nikula drm_encoder_enum_list[encoder_type].name, 1144e5748946SJani Nikula encoder->base.id); 114586bf546bSVille Syrjälä } 1146e5748946SJani Nikula if (!encoder->name) { 1147e5748946SJani Nikula ret = -ENOMEM; 1148e5748946SJani Nikula goto out_put; 1149e5748946SJani Nikula } 1150f453ba04SDave Airlie 1151f453ba04SDave Airlie list_add_tail(&encoder->head, &dev->mode_config.encoder_list); 1152490d3d1bSChris Wilson encoder->index = dev->mode_config.num_encoder++; 1153f453ba04SDave Airlie 1154e5748946SJani Nikula out_put: 1155e5748946SJani Nikula if (ret) 11567c8f6d25SDave Airlie drm_mode_object_unregister(dev, &encoder->base); 1157e5748946SJani Nikula 1158e5748946SJani Nikula out_unlock: 115984849903SDaniel Vetter drm_modeset_unlock_all(dev); 11606bfc56aaSVille Syrjälä 11616bfc56aaSVille Syrjälä return ret; 1162f453ba04SDave Airlie } 1163f453ba04SDave Airlie EXPORT_SYMBOL(drm_encoder_init); 1164f453ba04SDave Airlie 1165c8e32cc1SDaniel Vetter /** 1166c8e32cc1SDaniel Vetter * drm_encoder_cleanup - cleans up an initialised encoder 1167c8e32cc1SDaniel Vetter * @encoder: encoder to cleanup 1168c8e32cc1SDaniel Vetter * 1169c8e32cc1SDaniel Vetter * Cleans up the encoder but doesn't free the object. 1170c8e32cc1SDaniel Vetter */ 1171f453ba04SDave Airlie void drm_encoder_cleanup(struct drm_encoder *encoder) 1172f453ba04SDave Airlie { 1173f453ba04SDave Airlie struct drm_device *dev = encoder->dev; 11744dfd909fSThierry Reding 1175490d3d1bSChris Wilson /* Note that the encoder_list is considered to be static; should we 1176490d3d1bSChris Wilson * remove the drm_encoder at runtime we would have to decrement all 1177490d3d1bSChris Wilson * the indices on the drm_encoder after us in the encoder_list. 1178490d3d1bSChris Wilson */ 1179490d3d1bSChris Wilson 118084849903SDaniel Vetter drm_modeset_lock_all(dev); 11817c8f6d25SDave Airlie drm_mode_object_unregister(dev, &encoder->base); 1182e5748946SJani Nikula kfree(encoder->name); 1183f453ba04SDave Airlie list_del(&encoder->head); 11846380c509SJoonyoung Shim dev->mode_config.num_encoder--; 118584849903SDaniel Vetter drm_modeset_unlock_all(dev); 1186a18c0af1SThierry Reding 1187a18c0af1SThierry Reding memset(encoder, 0, sizeof(*encoder)); 1188f453ba04SDave Airlie } 1189f453ba04SDave Airlie EXPORT_SYMBOL(drm_encoder_cleanup); 1190f453ba04SDave Airlie 11919f4c97a2SVille Syrjälä static unsigned int drm_num_planes(struct drm_device *dev) 11929f4c97a2SVille Syrjälä { 11939f4c97a2SVille Syrjälä unsigned int num = 0; 11949f4c97a2SVille Syrjälä struct drm_plane *tmp; 11959f4c97a2SVille Syrjälä 11969f4c97a2SVille Syrjälä drm_for_each_plane(tmp, dev) { 11979f4c97a2SVille Syrjälä num++; 11989f4c97a2SVille Syrjälä } 11999f4c97a2SVille Syrjälä 12009f4c97a2SVille Syrjälä return num; 12019f4c97a2SVille Syrjälä } 12029f4c97a2SVille Syrjälä 120335f2c3aeSVille Syrjälä /** 1204dc415ff9SMatt Roper * drm_universal_plane_init - Initialize a new universal plane object 120535f2c3aeSVille Syrjälä * @dev: DRM device 120635f2c3aeSVille Syrjälä * @plane: plane object to init 120735f2c3aeSVille Syrjälä * @possible_crtcs: bitmask of possible CRTCs 120835f2c3aeSVille Syrjälä * @funcs: callbacks for the new plane 120935f2c3aeSVille Syrjälä * @formats: array of supported formats (%DRM_FORMAT_*) 121035f2c3aeSVille Syrjälä * @format_count: number of elements in @formats 1211dc415ff9SMatt Roper * @type: type of plane (overlay, primary, cursor) 1212b0b3b795SVille Syrjälä * @name: printf style format string for the plane name, or NULL for default name 121335f2c3aeSVille Syrjälä * 1214dc415ff9SMatt Roper * Initializes a plane object of type @type. 121535f2c3aeSVille Syrjälä * 1216c8e32cc1SDaniel Vetter * Returns: 121735f2c3aeSVille Syrjälä * Zero on success, error code on failure. 121835f2c3aeSVille Syrjälä */ 1219dc415ff9SMatt Roper int drm_universal_plane_init(struct drm_device *dev, struct drm_plane *plane, 12208cf5c917SJesse Barnes unsigned long possible_crtcs, 12218cf5c917SJesse Barnes const struct drm_plane_funcs *funcs, 122245e3743aSThierry Reding const uint32_t *formats, unsigned int format_count, 1223b0b3b795SVille Syrjälä enum drm_plane_type type, 1224b0b3b795SVille Syrjälä const char *name, ...) 12258cf5c917SJesse Barnes { 12266b4959f4SRob Clark struct drm_mode_config *config = &dev->mode_config; 12276bfc56aaSVille Syrjälä int ret; 12286bfc56aaSVille Syrjälä 12296bfc56aaSVille Syrjälä ret = drm_mode_object_get(dev, &plane->base, DRM_MODE_OBJECT_PLANE); 12306bfc56aaSVille Syrjälä if (ret) 1231baf698b0SDaniel Vetter return ret; 12326bfc56aaSVille Syrjälä 12334d02e2deSDaniel Vetter drm_modeset_lock_init(&plane->mutex); 12344d02e2deSDaniel Vetter 12354d93914aSRob Clark plane->base.properties = &plane->properties; 12368cf5c917SJesse Barnes plane->dev = dev; 12378cf5c917SJesse Barnes plane->funcs = funcs; 12382f6c5389SThierry Reding plane->format_types = kmalloc_array(format_count, sizeof(uint32_t), 12398cf5c917SJesse Barnes GFP_KERNEL); 12408cf5c917SJesse Barnes if (!plane->format_types) { 12418cf5c917SJesse Barnes DRM_DEBUG_KMS("out of memory when allocating plane\n"); 12427c8f6d25SDave Airlie drm_mode_object_unregister(dev, &plane->base); 1243baf698b0SDaniel Vetter return -ENOMEM; 12448cf5c917SJesse Barnes } 12458cf5c917SJesse Barnes 12469f4c97a2SVille Syrjälä if (name) { 12479f4c97a2SVille Syrjälä va_list ap; 12489f4c97a2SVille Syrjälä 12499f4c97a2SVille Syrjälä va_start(ap, name); 12509f4c97a2SVille Syrjälä plane->name = kvasprintf(GFP_KERNEL, name, ap); 12519f4c97a2SVille Syrjälä va_end(ap); 12529f4c97a2SVille Syrjälä } else { 12539f4c97a2SVille Syrjälä plane->name = kasprintf(GFP_KERNEL, "plane-%d", 12549f4c97a2SVille Syrjälä drm_num_planes(dev)); 12559f4c97a2SVille Syrjälä } 12569f4c97a2SVille Syrjälä if (!plane->name) { 12579f4c97a2SVille Syrjälä kfree(plane->format_types); 12587c8f6d25SDave Airlie drm_mode_object_unregister(dev, &plane->base); 12599f4c97a2SVille Syrjälä return -ENOMEM; 12609f4c97a2SVille Syrjälä } 12619f4c97a2SVille Syrjälä 1262308e5bcbSJesse Barnes memcpy(plane->format_types, formats, format_count * sizeof(uint32_t)); 12638cf5c917SJesse Barnes plane->format_count = format_count; 12648cf5c917SJesse Barnes plane->possible_crtcs = possible_crtcs; 1265dc415ff9SMatt Roper plane->type = type; 12668cf5c917SJesse Barnes 12676b4959f4SRob Clark list_add_tail(&plane->head, &config->plane_list); 1268490d3d1bSChris Wilson plane->index = config->num_total_plane++; 1269e27dde3eSMatt Roper if (plane->type == DRM_PLANE_TYPE_OVERLAY) 12706b4959f4SRob Clark config->num_overlay_plane++; 12718cf5c917SJesse Barnes 12729922ab5aSRob Clark drm_object_attach_property(&plane->base, 12736b4959f4SRob Clark config->plane_type_property, 12749922ab5aSRob Clark plane->type); 12759922ab5aSRob Clark 12766b4959f4SRob Clark if (drm_core_check_feature(dev, DRIVER_ATOMIC)) { 12776b4959f4SRob Clark drm_object_attach_property(&plane->base, config->prop_fb_id, 0); 12786b4959f4SRob Clark drm_object_attach_property(&plane->base, config->prop_crtc_id, 0); 12796b4959f4SRob Clark drm_object_attach_property(&plane->base, config->prop_crtc_x, 0); 12806b4959f4SRob Clark drm_object_attach_property(&plane->base, config->prop_crtc_y, 0); 12816b4959f4SRob Clark drm_object_attach_property(&plane->base, config->prop_crtc_w, 0); 12826b4959f4SRob Clark drm_object_attach_property(&plane->base, config->prop_crtc_h, 0); 12836b4959f4SRob Clark drm_object_attach_property(&plane->base, config->prop_src_x, 0); 12846b4959f4SRob Clark drm_object_attach_property(&plane->base, config->prop_src_y, 0); 12856b4959f4SRob Clark drm_object_attach_property(&plane->base, config->prop_src_w, 0); 12866b4959f4SRob Clark drm_object_attach_property(&plane->base, config->prop_src_h, 0); 12876b4959f4SRob Clark } 12886b4959f4SRob Clark 1289baf698b0SDaniel Vetter return 0; 12908cf5c917SJesse Barnes } 1291dc415ff9SMatt Roper EXPORT_SYMBOL(drm_universal_plane_init); 1292dc415ff9SMatt Roper 1293dc415ff9SMatt Roper /** 1294dc415ff9SMatt Roper * drm_plane_init - Initialize a legacy plane 1295dc415ff9SMatt Roper * @dev: DRM device 1296dc415ff9SMatt Roper * @plane: plane object to init 1297dc415ff9SMatt Roper * @possible_crtcs: bitmask of possible CRTCs 1298dc415ff9SMatt Roper * @funcs: callbacks for the new plane 1299dc415ff9SMatt Roper * @formats: array of supported formats (%DRM_FORMAT_*) 1300dc415ff9SMatt Roper * @format_count: number of elements in @formats 1301dc415ff9SMatt Roper * @is_primary: plane type (primary vs overlay) 1302dc415ff9SMatt Roper * 1303dc415ff9SMatt Roper * Legacy API to initialize a DRM plane. 1304dc415ff9SMatt Roper * 1305dc415ff9SMatt Roper * New drivers should call drm_universal_plane_init() instead. 1306dc415ff9SMatt Roper * 1307dc415ff9SMatt Roper * Returns: 1308dc415ff9SMatt Roper * Zero on success, error code on failure. 1309dc415ff9SMatt Roper */ 1310dc415ff9SMatt Roper int drm_plane_init(struct drm_device *dev, struct drm_plane *plane, 1311dc415ff9SMatt Roper unsigned long possible_crtcs, 1312dc415ff9SMatt Roper const struct drm_plane_funcs *funcs, 131345e3743aSThierry Reding const uint32_t *formats, unsigned int format_count, 1314dc415ff9SMatt Roper bool is_primary) 1315dc415ff9SMatt Roper { 1316dc415ff9SMatt Roper enum drm_plane_type type; 1317dc415ff9SMatt Roper 1318dc415ff9SMatt Roper type = is_primary ? DRM_PLANE_TYPE_PRIMARY : DRM_PLANE_TYPE_OVERLAY; 1319dc415ff9SMatt Roper return drm_universal_plane_init(dev, plane, possible_crtcs, funcs, 1320b0b3b795SVille Syrjälä formats, format_count, type, NULL); 1321dc415ff9SMatt Roper } 13228cf5c917SJesse Barnes EXPORT_SYMBOL(drm_plane_init); 13238cf5c917SJesse Barnes 132435f2c3aeSVille Syrjälä /** 132535f2c3aeSVille Syrjälä * drm_plane_cleanup - Clean up the core plane usage 132635f2c3aeSVille Syrjälä * @plane: plane to cleanup 132735f2c3aeSVille Syrjälä * 132835f2c3aeSVille Syrjälä * This function cleans up @plane and removes it from the DRM mode setting 132935f2c3aeSVille Syrjälä * core. Note that the function does *not* free the plane structure itself, 133035f2c3aeSVille Syrjälä * this is the responsibility of the caller. 133135f2c3aeSVille Syrjälä */ 13328cf5c917SJesse Barnes void drm_plane_cleanup(struct drm_plane *plane) 13338cf5c917SJesse Barnes { 13348cf5c917SJesse Barnes struct drm_device *dev = plane->dev; 13358cf5c917SJesse Barnes 133684849903SDaniel Vetter drm_modeset_lock_all(dev); 13378cf5c917SJesse Barnes kfree(plane->format_types); 13387c8f6d25SDave Airlie drm_mode_object_unregister(dev, &plane->base); 1339dc415ff9SMatt Roper 1340dc415ff9SMatt Roper BUG_ON(list_empty(&plane->head)); 1341dc415ff9SMatt Roper 1342490d3d1bSChris Wilson /* Note that the plane_list is considered to be static; should we 1343490d3d1bSChris Wilson * remove the drm_plane at runtime we would have to decrement all 1344490d3d1bSChris Wilson * the indices on the drm_plane after us in the plane_list. 1345490d3d1bSChris Wilson */ 1346490d3d1bSChris Wilson 13478cf5c917SJesse Barnes list_del(&plane->head); 1348e27dde3eSMatt Roper dev->mode_config.num_total_plane--; 1349e27dde3eSMatt Roper if (plane->type == DRM_PLANE_TYPE_OVERLAY) 1350e27dde3eSMatt Roper dev->mode_config.num_overlay_plane--; 135184849903SDaniel Vetter drm_modeset_unlock_all(dev); 13523009c037SThierry Reding 13533009c037SThierry Reding WARN_ON(plane->state && !plane->funcs->atomic_destroy_state); 13543009c037SThierry Reding if (plane->state && plane->funcs->atomic_destroy_state) 13553009c037SThierry Reding plane->funcs->atomic_destroy_state(plane, plane->state); 1356a18c0af1SThierry Reding 13579f4c97a2SVille Syrjälä kfree(plane->name); 13589f4c97a2SVille Syrjälä 1359a18c0af1SThierry Reding memset(plane, 0, sizeof(*plane)); 13608cf5c917SJesse Barnes } 13618cf5c917SJesse Barnes EXPORT_SYMBOL(drm_plane_cleanup); 13628cf5c917SJesse Barnes 136335f2c3aeSVille Syrjälä /** 1364f81338a5SChandra Konduru * drm_plane_from_index - find the registered plane at an index 1365f81338a5SChandra Konduru * @dev: DRM device 1366f81338a5SChandra Konduru * @idx: index of registered plane to find for 1367f81338a5SChandra Konduru * 1368f81338a5SChandra Konduru * Given a plane index, return the registered plane from DRM device's 1369f81338a5SChandra Konduru * list of planes with matching index. 1370f81338a5SChandra Konduru */ 1371f81338a5SChandra Konduru struct drm_plane * 1372f81338a5SChandra Konduru drm_plane_from_index(struct drm_device *dev, int idx) 1373f81338a5SChandra Konduru { 1374f81338a5SChandra Konduru struct drm_plane *plane; 1375f81338a5SChandra Konduru 1376490d3d1bSChris Wilson drm_for_each_plane(plane, dev) 1377490d3d1bSChris Wilson if (idx == plane->index) 1378f81338a5SChandra Konduru return plane; 1379490d3d1bSChris Wilson 1380f81338a5SChandra Konduru return NULL; 1381f81338a5SChandra Konduru } 1382f81338a5SChandra Konduru EXPORT_SYMBOL(drm_plane_from_index); 1383f81338a5SChandra Konduru 1384f81338a5SChandra Konduru /** 138535f2c3aeSVille Syrjälä * drm_plane_force_disable - Forcibly disable a plane 138635f2c3aeSVille Syrjälä * @plane: plane to disable 138735f2c3aeSVille Syrjälä * 138835f2c3aeSVille Syrjälä * Forces the plane to be disabled. 138935f2c3aeSVille Syrjälä * 139035f2c3aeSVille Syrjälä * Used when the plane's current framebuffer is destroyed, 139135f2c3aeSVille Syrjälä * and when restoring fbdev mode. 139235f2c3aeSVille Syrjälä */ 13939125e618SVille Syrjälä void drm_plane_force_disable(struct drm_plane *plane) 13949125e618SVille Syrjälä { 13959125e618SVille Syrjälä int ret; 13969125e618SVille Syrjälä 13973d30a59bSDaniel Vetter if (!plane->fb) 13989125e618SVille Syrjälä return; 13999125e618SVille Syrjälä 14003d30a59bSDaniel Vetter plane->old_fb = plane->fb; 14019125e618SVille Syrjälä ret = plane->funcs->disable_plane(plane); 1402731cce48SDaniel Vetter if (ret) { 14039125e618SVille Syrjälä DRM_ERROR("failed to disable plane with busy fb\n"); 14043d30a59bSDaniel Vetter plane->old_fb = NULL; 1405731cce48SDaniel Vetter return; 1406731cce48SDaniel Vetter } 14079125e618SVille Syrjälä /* disconnect the plane from the fb and crtc: */ 1408220dd2bcSDaniel Vetter drm_framebuffer_unreference(plane->old_fb); 14093d30a59bSDaniel Vetter plane->old_fb = NULL; 14109125e618SVille Syrjälä plane->fb = NULL; 14119125e618SVille Syrjälä plane->crtc = NULL; 14129125e618SVille Syrjälä } 14139125e618SVille Syrjälä EXPORT_SYMBOL(drm_plane_force_disable); 14149125e618SVille Syrjälä 14156b4959f4SRob Clark static int drm_mode_create_standard_properties(struct drm_device *dev) 1416f453ba04SDave Airlie { 1417356af0e1SRob Clark struct drm_property *prop; 1418f453ba04SDave Airlie 1419f453ba04SDave Airlie /* 1420f453ba04SDave Airlie * Standard properties (apply to all connectors) 1421f453ba04SDave Airlie */ 1422356af0e1SRob Clark prop = drm_property_create(dev, DRM_MODE_PROP_BLOB | 1423f453ba04SDave Airlie DRM_MODE_PROP_IMMUTABLE, 1424f453ba04SDave Airlie "EDID", 0); 1425356af0e1SRob Clark if (!prop) 1426356af0e1SRob Clark return -ENOMEM; 1427356af0e1SRob Clark dev->mode_config.edid_property = prop; 1428f453ba04SDave Airlie 1429356af0e1SRob Clark prop = drm_property_create_enum(dev, 0, 14304a67d391SSascha Hauer "DPMS", drm_dpms_enum_list, 14314a67d391SSascha Hauer ARRAY_SIZE(drm_dpms_enum_list)); 1432356af0e1SRob Clark if (!prop) 1433356af0e1SRob Clark return -ENOMEM; 1434356af0e1SRob Clark dev->mode_config.dpms_property = prop; 1435f453ba04SDave Airlie 1436356af0e1SRob Clark prop = drm_property_create(dev, 143743aba7ebSDave Airlie DRM_MODE_PROP_BLOB | 143843aba7ebSDave Airlie DRM_MODE_PROP_IMMUTABLE, 143943aba7ebSDave Airlie "PATH", 0); 1440356af0e1SRob Clark if (!prop) 1441356af0e1SRob Clark return -ENOMEM; 1442356af0e1SRob Clark dev->mode_config.path_property = prop; 144343aba7ebSDave Airlie 1444356af0e1SRob Clark prop = drm_property_create(dev, 14456f134d7bSDave Airlie DRM_MODE_PROP_BLOB | 14466f134d7bSDave Airlie DRM_MODE_PROP_IMMUTABLE, 14476f134d7bSDave Airlie "TILE", 0); 1448356af0e1SRob Clark if (!prop) 1449356af0e1SRob Clark return -ENOMEM; 1450356af0e1SRob Clark dev->mode_config.tile_property = prop; 14516f134d7bSDave Airlie 14526b4959f4SRob Clark prop = drm_property_create_enum(dev, DRM_MODE_PROP_IMMUTABLE, 14539922ab5aSRob Clark "type", drm_plane_type_enum_list, 14549922ab5aSRob Clark ARRAY_SIZE(drm_plane_type_enum_list)); 14556b4959f4SRob Clark if (!prop) 14566b4959f4SRob Clark return -ENOMEM; 14576b4959f4SRob Clark dev->mode_config.plane_type_property = prop; 14586b4959f4SRob Clark 14596b4959f4SRob Clark prop = drm_property_create_range(dev, DRM_MODE_PROP_ATOMIC, 14606b4959f4SRob Clark "SRC_X", 0, UINT_MAX); 14616b4959f4SRob Clark if (!prop) 14626b4959f4SRob Clark return -ENOMEM; 14636b4959f4SRob Clark dev->mode_config.prop_src_x = prop; 14646b4959f4SRob Clark 14656b4959f4SRob Clark prop = drm_property_create_range(dev, DRM_MODE_PROP_ATOMIC, 14666b4959f4SRob Clark "SRC_Y", 0, UINT_MAX); 14676b4959f4SRob Clark if (!prop) 14686b4959f4SRob Clark return -ENOMEM; 14696b4959f4SRob Clark dev->mode_config.prop_src_y = prop; 14706b4959f4SRob Clark 14716b4959f4SRob Clark prop = drm_property_create_range(dev, DRM_MODE_PROP_ATOMIC, 14726b4959f4SRob Clark "SRC_W", 0, UINT_MAX); 14736b4959f4SRob Clark if (!prop) 14746b4959f4SRob Clark return -ENOMEM; 14756b4959f4SRob Clark dev->mode_config.prop_src_w = prop; 14766b4959f4SRob Clark 14776b4959f4SRob Clark prop = drm_property_create_range(dev, DRM_MODE_PROP_ATOMIC, 14786b4959f4SRob Clark "SRC_H", 0, UINT_MAX); 14796b4959f4SRob Clark if (!prop) 14806b4959f4SRob Clark return -ENOMEM; 14816b4959f4SRob Clark dev->mode_config.prop_src_h = prop; 14826b4959f4SRob Clark 14836b4959f4SRob Clark prop = drm_property_create_signed_range(dev, DRM_MODE_PROP_ATOMIC, 14846b4959f4SRob Clark "CRTC_X", INT_MIN, INT_MAX); 14856b4959f4SRob Clark if (!prop) 14866b4959f4SRob Clark return -ENOMEM; 14876b4959f4SRob Clark dev->mode_config.prop_crtc_x = prop; 14886b4959f4SRob Clark 14896b4959f4SRob Clark prop = drm_property_create_signed_range(dev, DRM_MODE_PROP_ATOMIC, 14906b4959f4SRob Clark "CRTC_Y", INT_MIN, INT_MAX); 14916b4959f4SRob Clark if (!prop) 14926b4959f4SRob Clark return -ENOMEM; 14936b4959f4SRob Clark dev->mode_config.prop_crtc_y = prop; 14946b4959f4SRob Clark 14956b4959f4SRob Clark prop = drm_property_create_range(dev, DRM_MODE_PROP_ATOMIC, 14966b4959f4SRob Clark "CRTC_W", 0, INT_MAX); 14976b4959f4SRob Clark if (!prop) 14986b4959f4SRob Clark return -ENOMEM; 14996b4959f4SRob Clark dev->mode_config.prop_crtc_w = prop; 15006b4959f4SRob Clark 15016b4959f4SRob Clark prop = drm_property_create_range(dev, DRM_MODE_PROP_ATOMIC, 15026b4959f4SRob Clark "CRTC_H", 0, INT_MAX); 15036b4959f4SRob Clark if (!prop) 15046b4959f4SRob Clark return -ENOMEM; 15056b4959f4SRob Clark dev->mode_config.prop_crtc_h = prop; 15066b4959f4SRob Clark 15076b4959f4SRob Clark prop = drm_property_create_object(dev, DRM_MODE_PROP_ATOMIC, 15086b4959f4SRob Clark "FB_ID", DRM_MODE_OBJECT_FB); 15096b4959f4SRob Clark if (!prop) 15106b4959f4SRob Clark return -ENOMEM; 15116b4959f4SRob Clark dev->mode_config.prop_fb_id = prop; 15126b4959f4SRob Clark 15136b4959f4SRob Clark prop = drm_property_create_object(dev, DRM_MODE_PROP_ATOMIC, 15146b4959f4SRob Clark "CRTC_ID", DRM_MODE_OBJECT_CRTC); 15156b4959f4SRob Clark if (!prop) 15166b4959f4SRob Clark return -ENOMEM; 15176b4959f4SRob Clark dev->mode_config.prop_crtc_id = prop; 15189922ab5aSRob Clark 1519eab3bbefSDaniel Vetter prop = drm_property_create_bool(dev, DRM_MODE_PROP_ATOMIC, 1520eab3bbefSDaniel Vetter "ACTIVE"); 1521eab3bbefSDaniel Vetter if (!prop) 1522eab3bbefSDaniel Vetter return -ENOMEM; 1523eab3bbefSDaniel Vetter dev->mode_config.prop_active = prop; 1524eab3bbefSDaniel Vetter 1525955f3c33SDaniel Stone prop = drm_property_create(dev, 1526955f3c33SDaniel Stone DRM_MODE_PROP_ATOMIC | DRM_MODE_PROP_BLOB, 1527955f3c33SDaniel Stone "MODE_ID", 0); 1528955f3c33SDaniel Stone if (!prop) 1529955f3c33SDaniel Stone return -ENOMEM; 1530955f3c33SDaniel Stone dev->mode_config.prop_mode_id = prop; 1531955f3c33SDaniel Stone 15325488dc16SLionel Landwerlin prop = drm_property_create(dev, 15335488dc16SLionel Landwerlin DRM_MODE_PROP_BLOB, 15345488dc16SLionel Landwerlin "DEGAMMA_LUT", 0); 15355488dc16SLionel Landwerlin if (!prop) 15365488dc16SLionel Landwerlin return -ENOMEM; 15375488dc16SLionel Landwerlin dev->mode_config.degamma_lut_property = prop; 15385488dc16SLionel Landwerlin 15395488dc16SLionel Landwerlin prop = drm_property_create_range(dev, 15405488dc16SLionel Landwerlin DRM_MODE_PROP_IMMUTABLE, 15415488dc16SLionel Landwerlin "DEGAMMA_LUT_SIZE", 0, UINT_MAX); 15425488dc16SLionel Landwerlin if (!prop) 15435488dc16SLionel Landwerlin return -ENOMEM; 15445488dc16SLionel Landwerlin dev->mode_config.degamma_lut_size_property = prop; 15455488dc16SLionel Landwerlin 15465488dc16SLionel Landwerlin prop = drm_property_create(dev, 15475488dc16SLionel Landwerlin DRM_MODE_PROP_BLOB, 15485488dc16SLionel Landwerlin "CTM", 0); 15495488dc16SLionel Landwerlin if (!prop) 15505488dc16SLionel Landwerlin return -ENOMEM; 15515488dc16SLionel Landwerlin dev->mode_config.ctm_property = prop; 15525488dc16SLionel Landwerlin 15535488dc16SLionel Landwerlin prop = drm_property_create(dev, 15545488dc16SLionel Landwerlin DRM_MODE_PROP_BLOB, 15555488dc16SLionel Landwerlin "GAMMA_LUT", 0); 15565488dc16SLionel Landwerlin if (!prop) 15575488dc16SLionel Landwerlin return -ENOMEM; 15585488dc16SLionel Landwerlin dev->mode_config.gamma_lut_property = prop; 15595488dc16SLionel Landwerlin 15605488dc16SLionel Landwerlin prop = drm_property_create_range(dev, 15615488dc16SLionel Landwerlin DRM_MODE_PROP_IMMUTABLE, 15625488dc16SLionel Landwerlin "GAMMA_LUT_SIZE", 0, UINT_MAX); 15635488dc16SLionel Landwerlin if (!prop) 15645488dc16SLionel Landwerlin return -ENOMEM; 15655488dc16SLionel Landwerlin dev->mode_config.gamma_lut_size_property = prop; 15665488dc16SLionel Landwerlin 15679922ab5aSRob Clark return 0; 15689922ab5aSRob Clark } 15699922ab5aSRob Clark 1570f453ba04SDave Airlie /** 1571f453ba04SDave Airlie * drm_mode_create_dvi_i_properties - create DVI-I specific connector properties 1572f453ba04SDave Airlie * @dev: DRM device 1573f453ba04SDave Airlie * 1574f453ba04SDave Airlie * Called by a driver the first time a DVI-I connector is made. 1575f453ba04SDave Airlie */ 1576f453ba04SDave Airlie int drm_mode_create_dvi_i_properties(struct drm_device *dev) 1577f453ba04SDave Airlie { 1578f453ba04SDave Airlie struct drm_property *dvi_i_selector; 1579f453ba04SDave Airlie struct drm_property *dvi_i_subconnector; 1580f453ba04SDave Airlie 1581f453ba04SDave Airlie if (dev->mode_config.dvi_i_select_subconnector_property) 1582f453ba04SDave Airlie return 0; 1583f453ba04SDave Airlie 1584f453ba04SDave Airlie dvi_i_selector = 15854a67d391SSascha Hauer drm_property_create_enum(dev, 0, 1586f453ba04SDave Airlie "select subconnector", 15874a67d391SSascha Hauer drm_dvi_i_select_enum_list, 1588f453ba04SDave Airlie ARRAY_SIZE(drm_dvi_i_select_enum_list)); 1589f453ba04SDave Airlie dev->mode_config.dvi_i_select_subconnector_property = dvi_i_selector; 1590f453ba04SDave Airlie 15914a67d391SSascha Hauer dvi_i_subconnector = drm_property_create_enum(dev, DRM_MODE_PROP_IMMUTABLE, 1592f453ba04SDave Airlie "subconnector", 15934a67d391SSascha Hauer drm_dvi_i_subconnector_enum_list, 1594f453ba04SDave Airlie ARRAY_SIZE(drm_dvi_i_subconnector_enum_list)); 1595f453ba04SDave Airlie dev->mode_config.dvi_i_subconnector_property = dvi_i_subconnector; 1596f453ba04SDave Airlie 1597f453ba04SDave Airlie return 0; 1598f453ba04SDave Airlie } 1599f453ba04SDave Airlie EXPORT_SYMBOL(drm_mode_create_dvi_i_properties); 1600f453ba04SDave Airlie 1601f453ba04SDave Airlie /** 1602f453ba04SDave Airlie * drm_create_tv_properties - create TV specific connector properties 1603f453ba04SDave Airlie * @dev: DRM device 1604f453ba04SDave Airlie * @num_modes: number of different TV formats (modes) supported 1605f453ba04SDave Airlie * @modes: array of pointers to strings containing name of each format 1606f453ba04SDave Airlie * 1607f453ba04SDave Airlie * Called by a driver's TV initialization routine, this function creates 1608f453ba04SDave Airlie * the TV specific connector properties for a given device. Caller is 1609f453ba04SDave Airlie * responsible for allocating a list of format names and passing them to 1610f453ba04SDave Airlie * this routine. 1611f453ba04SDave Airlie */ 16122f763312SThierry Reding int drm_mode_create_tv_properties(struct drm_device *dev, 16132f763312SThierry Reding unsigned int num_modes, 1614b7c914b3SVille Syrjälä const char * const modes[]) 1615f453ba04SDave Airlie { 1616f453ba04SDave Airlie struct drm_property *tv_selector; 1617f453ba04SDave Airlie struct drm_property *tv_subconnector; 16182f763312SThierry Reding unsigned int i; 1619f453ba04SDave Airlie 1620f453ba04SDave Airlie if (dev->mode_config.tv_select_subconnector_property) 1621f453ba04SDave Airlie return 0; 1622f453ba04SDave Airlie 1623f453ba04SDave Airlie /* 1624f453ba04SDave Airlie * Basic connector properties 1625f453ba04SDave Airlie */ 16264a67d391SSascha Hauer tv_selector = drm_property_create_enum(dev, 0, 1627f453ba04SDave Airlie "select subconnector", 16284a67d391SSascha Hauer drm_tv_select_enum_list, 1629f453ba04SDave Airlie ARRAY_SIZE(drm_tv_select_enum_list)); 163048aa1e74SInsu Yun if (!tv_selector) 163148aa1e74SInsu Yun goto nomem; 163248aa1e74SInsu Yun 1633f453ba04SDave Airlie dev->mode_config.tv_select_subconnector_property = tv_selector; 1634f453ba04SDave Airlie 1635f453ba04SDave Airlie tv_subconnector = 16364a67d391SSascha Hauer drm_property_create_enum(dev, DRM_MODE_PROP_IMMUTABLE, 16374a67d391SSascha Hauer "subconnector", 16384a67d391SSascha Hauer drm_tv_subconnector_enum_list, 1639f453ba04SDave Airlie ARRAY_SIZE(drm_tv_subconnector_enum_list)); 164048aa1e74SInsu Yun if (!tv_subconnector) 164148aa1e74SInsu Yun goto nomem; 1642f453ba04SDave Airlie dev->mode_config.tv_subconnector_property = tv_subconnector; 1643f453ba04SDave Airlie 1644f453ba04SDave Airlie /* 1645f453ba04SDave Airlie * Other, TV specific properties: margins & TV modes. 1646f453ba04SDave Airlie */ 1647f453ba04SDave Airlie dev->mode_config.tv_left_margin_property = 1648d9bc3c02SSascha Hauer drm_property_create_range(dev, 0, "left margin", 0, 100); 164948aa1e74SInsu Yun if (!dev->mode_config.tv_left_margin_property) 165048aa1e74SInsu Yun goto nomem; 1651f453ba04SDave Airlie 1652f453ba04SDave Airlie dev->mode_config.tv_right_margin_property = 1653d9bc3c02SSascha Hauer drm_property_create_range(dev, 0, "right margin", 0, 100); 165448aa1e74SInsu Yun if (!dev->mode_config.tv_right_margin_property) 165548aa1e74SInsu Yun goto nomem; 1656f453ba04SDave Airlie 1657f453ba04SDave Airlie dev->mode_config.tv_top_margin_property = 1658d9bc3c02SSascha Hauer drm_property_create_range(dev, 0, "top margin", 0, 100); 165948aa1e74SInsu Yun if (!dev->mode_config.tv_top_margin_property) 166048aa1e74SInsu Yun goto nomem; 1661f453ba04SDave Airlie 1662f453ba04SDave Airlie dev->mode_config.tv_bottom_margin_property = 1663d9bc3c02SSascha Hauer drm_property_create_range(dev, 0, "bottom margin", 0, 100); 166448aa1e74SInsu Yun if (!dev->mode_config.tv_bottom_margin_property) 166548aa1e74SInsu Yun goto nomem; 1666f453ba04SDave Airlie 1667f453ba04SDave Airlie dev->mode_config.tv_mode_property = 1668f453ba04SDave Airlie drm_property_create(dev, DRM_MODE_PROP_ENUM, 1669f453ba04SDave Airlie "mode", num_modes); 167048aa1e74SInsu Yun if (!dev->mode_config.tv_mode_property) 167148aa1e74SInsu Yun goto nomem; 167248aa1e74SInsu Yun 1673f453ba04SDave Airlie for (i = 0; i < num_modes; i++) 1674f453ba04SDave Airlie drm_property_add_enum(dev->mode_config.tv_mode_property, i, 1675f453ba04SDave Airlie i, modes[i]); 1676f453ba04SDave Airlie 1677b6b7902eSFrancisco Jerez dev->mode_config.tv_brightness_property = 1678d9bc3c02SSascha Hauer drm_property_create_range(dev, 0, "brightness", 0, 100); 167948aa1e74SInsu Yun if (!dev->mode_config.tv_brightness_property) 168048aa1e74SInsu Yun goto nomem; 1681b6b7902eSFrancisco Jerez 1682b6b7902eSFrancisco Jerez dev->mode_config.tv_contrast_property = 1683d9bc3c02SSascha Hauer drm_property_create_range(dev, 0, "contrast", 0, 100); 168448aa1e74SInsu Yun if (!dev->mode_config.tv_contrast_property) 168548aa1e74SInsu Yun goto nomem; 1686b6b7902eSFrancisco Jerez 1687b6b7902eSFrancisco Jerez dev->mode_config.tv_flicker_reduction_property = 1688d9bc3c02SSascha Hauer drm_property_create_range(dev, 0, "flicker reduction", 0, 100); 168948aa1e74SInsu Yun if (!dev->mode_config.tv_flicker_reduction_property) 169048aa1e74SInsu Yun goto nomem; 1691b6b7902eSFrancisco Jerez 1692a75f0236SFrancisco Jerez dev->mode_config.tv_overscan_property = 1693d9bc3c02SSascha Hauer drm_property_create_range(dev, 0, "overscan", 0, 100); 169448aa1e74SInsu Yun if (!dev->mode_config.tv_overscan_property) 169548aa1e74SInsu Yun goto nomem; 1696a75f0236SFrancisco Jerez 1697a75f0236SFrancisco Jerez dev->mode_config.tv_saturation_property = 1698d9bc3c02SSascha Hauer drm_property_create_range(dev, 0, "saturation", 0, 100); 169948aa1e74SInsu Yun if (!dev->mode_config.tv_saturation_property) 170048aa1e74SInsu Yun goto nomem; 1701a75f0236SFrancisco Jerez 1702a75f0236SFrancisco Jerez dev->mode_config.tv_hue_property = 1703d9bc3c02SSascha Hauer drm_property_create_range(dev, 0, "hue", 0, 100); 170448aa1e74SInsu Yun if (!dev->mode_config.tv_hue_property) 170548aa1e74SInsu Yun goto nomem; 1706a75f0236SFrancisco Jerez 1707f453ba04SDave Airlie return 0; 170848aa1e74SInsu Yun nomem: 170948aa1e74SInsu Yun return -ENOMEM; 1710f453ba04SDave Airlie } 1711f453ba04SDave Airlie EXPORT_SYMBOL(drm_mode_create_tv_properties); 1712f453ba04SDave Airlie 1713f453ba04SDave Airlie /** 1714f453ba04SDave Airlie * drm_mode_create_scaling_mode_property - create scaling mode property 1715f453ba04SDave Airlie * @dev: DRM device 1716f453ba04SDave Airlie * 1717f453ba04SDave Airlie * Called by a driver the first time it's needed, must be attached to desired 1718f453ba04SDave Airlie * connectors. 1719f453ba04SDave Airlie */ 1720f453ba04SDave Airlie int drm_mode_create_scaling_mode_property(struct drm_device *dev) 1721f453ba04SDave Airlie { 1722f453ba04SDave Airlie struct drm_property *scaling_mode; 1723f453ba04SDave Airlie 1724f453ba04SDave Airlie if (dev->mode_config.scaling_mode_property) 1725f453ba04SDave Airlie return 0; 1726f453ba04SDave Airlie 1727f453ba04SDave Airlie scaling_mode = 17284a67d391SSascha Hauer drm_property_create_enum(dev, 0, "scaling mode", 17294a67d391SSascha Hauer drm_scaling_mode_enum_list, 1730f453ba04SDave Airlie ARRAY_SIZE(drm_scaling_mode_enum_list)); 1731f453ba04SDave Airlie 1732f453ba04SDave Airlie dev->mode_config.scaling_mode_property = scaling_mode; 1733f453ba04SDave Airlie 1734f453ba04SDave Airlie return 0; 1735f453ba04SDave Airlie } 1736f453ba04SDave Airlie EXPORT_SYMBOL(drm_mode_create_scaling_mode_property); 1737f453ba04SDave Airlie 1738f453ba04SDave Airlie /** 1739ff587e45SVandana Kannan * drm_mode_create_aspect_ratio_property - create aspect ratio property 1740ff587e45SVandana Kannan * @dev: DRM device 1741ff587e45SVandana Kannan * 1742ff587e45SVandana Kannan * Called by a driver the first time it's needed, must be attached to desired 1743ff587e45SVandana Kannan * connectors. 1744ff587e45SVandana Kannan * 1745ff587e45SVandana Kannan * Returns: 17461a498633SDaniel Vetter * Zero on success, negative errno on failure. 1747ff587e45SVandana Kannan */ 1748ff587e45SVandana Kannan int drm_mode_create_aspect_ratio_property(struct drm_device *dev) 1749ff587e45SVandana Kannan { 1750ff587e45SVandana Kannan if (dev->mode_config.aspect_ratio_property) 1751ff587e45SVandana Kannan return 0; 1752ff587e45SVandana Kannan 1753ff587e45SVandana Kannan dev->mode_config.aspect_ratio_property = 1754ff587e45SVandana Kannan drm_property_create_enum(dev, 0, "aspect ratio", 1755ff587e45SVandana Kannan drm_aspect_ratio_enum_list, 1756ff587e45SVandana Kannan ARRAY_SIZE(drm_aspect_ratio_enum_list)); 1757ff587e45SVandana Kannan 1758ff587e45SVandana Kannan if (dev->mode_config.aspect_ratio_property == NULL) 1759ff587e45SVandana Kannan return -ENOMEM; 1760ff587e45SVandana Kannan 1761ff587e45SVandana Kannan return 0; 1762ff587e45SVandana Kannan } 1763ff587e45SVandana Kannan EXPORT_SYMBOL(drm_mode_create_aspect_ratio_property); 1764ff587e45SVandana Kannan 1765ff587e45SVandana Kannan /** 1766884840aaSJakob Bornecrantz * drm_mode_create_dirty_property - create dirty property 1767884840aaSJakob Bornecrantz * @dev: DRM device 1768884840aaSJakob Bornecrantz * 1769884840aaSJakob Bornecrantz * Called by a driver the first time it's needed, must be attached to desired 1770884840aaSJakob Bornecrantz * connectors. 1771884840aaSJakob Bornecrantz */ 1772884840aaSJakob Bornecrantz int drm_mode_create_dirty_info_property(struct drm_device *dev) 1773884840aaSJakob Bornecrantz { 1774884840aaSJakob Bornecrantz struct drm_property *dirty_info; 1775884840aaSJakob Bornecrantz 1776884840aaSJakob Bornecrantz if (dev->mode_config.dirty_info_property) 1777884840aaSJakob Bornecrantz return 0; 1778884840aaSJakob Bornecrantz 1779884840aaSJakob Bornecrantz dirty_info = 17804a67d391SSascha Hauer drm_property_create_enum(dev, DRM_MODE_PROP_IMMUTABLE, 1781884840aaSJakob Bornecrantz "dirty", 17824a67d391SSascha Hauer drm_dirty_info_enum_list, 1783884840aaSJakob Bornecrantz ARRAY_SIZE(drm_dirty_info_enum_list)); 1784884840aaSJakob Bornecrantz dev->mode_config.dirty_info_property = dirty_info; 1785884840aaSJakob Bornecrantz 1786884840aaSJakob Bornecrantz return 0; 1787884840aaSJakob Bornecrantz } 1788884840aaSJakob Bornecrantz EXPORT_SYMBOL(drm_mode_create_dirty_info_property); 1789884840aaSJakob Bornecrantz 17905bb2bbf5SDave Airlie /** 17915bb2bbf5SDave Airlie * drm_mode_create_suggested_offset_properties - create suggests offset properties 17925bb2bbf5SDave Airlie * @dev: DRM device 17935bb2bbf5SDave Airlie * 17945bb2bbf5SDave Airlie * Create the the suggested x/y offset property for connectors. 17955bb2bbf5SDave Airlie */ 17965bb2bbf5SDave Airlie int drm_mode_create_suggested_offset_properties(struct drm_device *dev) 17975bb2bbf5SDave Airlie { 17985bb2bbf5SDave Airlie if (dev->mode_config.suggested_x_property && dev->mode_config.suggested_y_property) 17995bb2bbf5SDave Airlie return 0; 18005bb2bbf5SDave Airlie 18015bb2bbf5SDave Airlie dev->mode_config.suggested_x_property = 18025bb2bbf5SDave Airlie drm_property_create_range(dev, DRM_MODE_PROP_IMMUTABLE, "suggested X", 0, 0xffffffff); 18035bb2bbf5SDave Airlie 18045bb2bbf5SDave Airlie dev->mode_config.suggested_y_property = 18055bb2bbf5SDave Airlie drm_property_create_range(dev, DRM_MODE_PROP_IMMUTABLE, "suggested Y", 0, 0xffffffff); 18065bb2bbf5SDave Airlie 18075bb2bbf5SDave Airlie if (dev->mode_config.suggested_x_property == NULL || 18085bb2bbf5SDave Airlie dev->mode_config.suggested_y_property == NULL) 18095bb2bbf5SDave Airlie return -ENOMEM; 18105bb2bbf5SDave Airlie return 0; 18115bb2bbf5SDave Airlie } 18125bb2bbf5SDave Airlie EXPORT_SYMBOL(drm_mode_create_suggested_offset_properties); 18135bb2bbf5SDave Airlie 1814f453ba04SDave Airlie /** 1815f453ba04SDave Airlie * drm_mode_getresources - get graphics configuration 1816065a50edSDaniel Vetter * @dev: drm device for the ioctl 1817065a50edSDaniel Vetter * @data: data pointer for the ioctl 1818065a50edSDaniel Vetter * @file_priv: drm file for the ioctl call 1819f453ba04SDave Airlie * 1820f453ba04SDave Airlie * Construct a set of configuration description structures and return 1821f453ba04SDave Airlie * them to the user, including CRTC, connector and framebuffer configuration. 1822f453ba04SDave Airlie * 1823f453ba04SDave Airlie * Called by the user via ioctl. 1824f453ba04SDave Airlie * 1825c8e32cc1SDaniel Vetter * Returns: 18261a498633SDaniel Vetter * Zero on success, negative errno on failure. 1827f453ba04SDave Airlie */ 1828f453ba04SDave Airlie int drm_mode_getresources(struct drm_device *dev, void *data, 1829f453ba04SDave Airlie struct drm_file *file_priv) 1830f453ba04SDave Airlie { 1831f453ba04SDave Airlie struct drm_mode_card_res *card_res = data; 1832f453ba04SDave Airlie struct list_head *lh; 1833f453ba04SDave Airlie struct drm_framebuffer *fb; 1834f453ba04SDave Airlie struct drm_connector *connector; 1835f453ba04SDave Airlie struct drm_crtc *crtc; 1836f453ba04SDave Airlie struct drm_encoder *encoder; 1837f453ba04SDave Airlie int ret = 0; 1838f453ba04SDave Airlie int connector_count = 0; 1839f453ba04SDave Airlie int crtc_count = 0; 1840f453ba04SDave Airlie int fb_count = 0; 1841f453ba04SDave Airlie int encoder_count = 0; 18429c7060f7SDaniel Vetter int copied = 0; 1843f453ba04SDave Airlie uint32_t __user *fb_id; 1844f453ba04SDave Airlie uint32_t __user *crtc_id; 1845f453ba04SDave Airlie uint32_t __user *connector_id; 1846f453ba04SDave Airlie uint32_t __user *encoder_id; 1847f453ba04SDave Airlie 1848fb3b06c8SDave Airlie if (!drm_core_check_feature(dev, DRIVER_MODESET)) 1849fb3b06c8SDave Airlie return -EINVAL; 1850fb3b06c8SDave Airlie 1851f453ba04SDave Airlie 18524b096ac1SDaniel Vetter mutex_lock(&file_priv->fbs_lock); 1853f453ba04SDave Airlie /* 1854f453ba04SDave Airlie * For the non-control nodes we need to limit the list of resources 1855f453ba04SDave Airlie * by IDs in the group list for this node 1856f453ba04SDave Airlie */ 1857f453ba04SDave Airlie list_for_each(lh, &file_priv->fbs) 1858f453ba04SDave Airlie fb_count++; 1859f453ba04SDave Airlie 18604b096ac1SDaniel Vetter /* handle this in 4 parts */ 18614b096ac1SDaniel Vetter /* FBs */ 18624b096ac1SDaniel Vetter if (card_res->count_fbs >= fb_count) { 18634b096ac1SDaniel Vetter copied = 0; 18644b096ac1SDaniel Vetter fb_id = (uint32_t __user *)(unsigned long)card_res->fb_id_ptr; 18654b096ac1SDaniel Vetter list_for_each_entry(fb, &file_priv->fbs, filp_head) { 18664b096ac1SDaniel Vetter if (put_user(fb->base.id, fb_id + copied)) { 18674b096ac1SDaniel Vetter mutex_unlock(&file_priv->fbs_lock); 18684b096ac1SDaniel Vetter return -EFAULT; 18694b096ac1SDaniel Vetter } 18704b096ac1SDaniel Vetter copied++; 18714b096ac1SDaniel Vetter } 18724b096ac1SDaniel Vetter } 18734b096ac1SDaniel Vetter card_res->count_fbs = fb_count; 18744b096ac1SDaniel Vetter mutex_unlock(&file_priv->fbs_lock); 18754b096ac1SDaniel Vetter 1876fcf93f69SDaniel Vetter /* mode_config.mutex protects the connector list against e.g. DP MST 1877fcf93f69SDaniel Vetter * connector hot-adding. CRTC/Plane lists are invariant. */ 1878fcf93f69SDaniel Vetter mutex_lock(&dev->mode_config.mutex); 1879e4f62546SDaniel Vetter drm_for_each_crtc(crtc, dev) 1880f453ba04SDave Airlie crtc_count++; 1881f453ba04SDave Airlie 18829a9f5ce8SDaniel Vetter drm_for_each_connector(connector, dev) 1883f453ba04SDave Airlie connector_count++; 1884f453ba04SDave Airlie 1885e4f62546SDaniel Vetter drm_for_each_encoder(encoder, dev) 1886f453ba04SDave Airlie encoder_count++; 1887f453ba04SDave Airlie 1888f453ba04SDave Airlie card_res->max_height = dev->mode_config.max_height; 1889f453ba04SDave Airlie card_res->min_height = dev->mode_config.min_height; 1890f453ba04SDave Airlie card_res->max_width = dev->mode_config.max_width; 1891f453ba04SDave Airlie card_res->min_width = dev->mode_config.min_width; 1892f453ba04SDave Airlie 1893f453ba04SDave Airlie /* CRTCs */ 1894f453ba04SDave Airlie if (card_res->count_crtcs >= crtc_count) { 1895f453ba04SDave Airlie copied = 0; 1896f453ba04SDave Airlie crtc_id = (uint32_t __user *)(unsigned long)card_res->crtc_id_ptr; 18976295d607SDaniel Vetter drm_for_each_crtc(crtc, dev) { 1898f453ba04SDave Airlie if (put_user(crtc->base.id, crtc_id + copied)) { 1899f453ba04SDave Airlie ret = -EFAULT; 1900f453ba04SDave Airlie goto out; 1901f453ba04SDave Airlie } 1902f453ba04SDave Airlie copied++; 1903f453ba04SDave Airlie } 1904f453ba04SDave Airlie } 1905f453ba04SDave Airlie card_res->count_crtcs = crtc_count; 1906f453ba04SDave Airlie 1907f453ba04SDave Airlie /* Encoders */ 1908f453ba04SDave Airlie if (card_res->count_encoders >= encoder_count) { 1909f453ba04SDave Airlie copied = 0; 1910f453ba04SDave Airlie encoder_id = (uint32_t __user *)(unsigned long)card_res->encoder_id_ptr; 19116295d607SDaniel Vetter drm_for_each_encoder(encoder, dev) { 1912f453ba04SDave Airlie if (put_user(encoder->base.id, encoder_id + 1913f453ba04SDave Airlie copied)) { 1914f453ba04SDave Airlie ret = -EFAULT; 1915f453ba04SDave Airlie goto out; 1916f453ba04SDave Airlie } 1917f453ba04SDave Airlie copied++; 1918f453ba04SDave Airlie } 1919f453ba04SDave Airlie } 1920f453ba04SDave Airlie card_res->count_encoders = encoder_count; 1921f453ba04SDave Airlie 1922f453ba04SDave Airlie /* Connectors */ 1923f453ba04SDave Airlie if (card_res->count_connectors >= connector_count) { 1924f453ba04SDave Airlie copied = 0; 1925f453ba04SDave Airlie connector_id = (uint32_t __user *)(unsigned long)card_res->connector_id_ptr; 19266295d607SDaniel Vetter drm_for_each_connector(connector, dev) { 1927f453ba04SDave Airlie if (put_user(connector->base.id, 1928f453ba04SDave Airlie connector_id + copied)) { 1929f453ba04SDave Airlie ret = -EFAULT; 1930f453ba04SDave Airlie goto out; 1931f453ba04SDave Airlie } 1932f453ba04SDave Airlie copied++; 1933f453ba04SDave Airlie } 1934f453ba04SDave Airlie } 1935f453ba04SDave Airlie card_res->count_connectors = connector_count; 1936f453ba04SDave Airlie 1937f453ba04SDave Airlie out: 1938fcf93f69SDaniel Vetter mutex_unlock(&dev->mode_config.mutex); 1939f453ba04SDave Airlie return ret; 1940f453ba04SDave Airlie } 1941f453ba04SDave Airlie 1942f453ba04SDave Airlie /** 1943f453ba04SDave Airlie * drm_mode_getcrtc - get CRTC configuration 1944065a50edSDaniel Vetter * @dev: drm device for the ioctl 1945065a50edSDaniel Vetter * @data: data pointer for the ioctl 1946065a50edSDaniel Vetter * @file_priv: drm file for the ioctl call 1947f453ba04SDave Airlie * 1948f453ba04SDave Airlie * Construct a CRTC configuration structure to return to the user. 1949f453ba04SDave Airlie * 1950f453ba04SDave Airlie * Called by the user via ioctl. 1951f453ba04SDave Airlie * 1952c8e32cc1SDaniel Vetter * Returns: 19531a498633SDaniel Vetter * Zero on success, negative errno on failure. 1954f453ba04SDave Airlie */ 1955f453ba04SDave Airlie int drm_mode_getcrtc(struct drm_device *dev, 1956f453ba04SDave Airlie void *data, struct drm_file *file_priv) 1957f453ba04SDave Airlie { 1958f453ba04SDave Airlie struct drm_mode_crtc *crtc_resp = data; 1959f453ba04SDave Airlie struct drm_crtc *crtc; 1960f453ba04SDave Airlie 1961fb3b06c8SDave Airlie if (!drm_core_check_feature(dev, DRIVER_MODESET)) 1962fb3b06c8SDave Airlie return -EINVAL; 1963fb3b06c8SDave Airlie 1964a2b34e22SRob Clark crtc = drm_crtc_find(dev, crtc_resp->crtc_id); 1965fcf93f69SDaniel Vetter if (!crtc) 1966fcf93f69SDaniel Vetter return -ENOENT; 1967f453ba04SDave Airlie 1968fcf93f69SDaniel Vetter drm_modeset_lock_crtc(crtc, crtc->primary); 1969f453ba04SDave Airlie crtc_resp->gamma_size = crtc->gamma_size; 1970f4510a27SMatt Roper if (crtc->primary->fb) 1971f4510a27SMatt Roper crtc_resp->fb_id = crtc->primary->fb->base.id; 1972f453ba04SDave Airlie else 1973f453ba04SDave Airlie crtc_resp->fb_id = 0; 1974f453ba04SDave Airlie 197531c946e8SDaniel Vetter if (crtc->state) { 197631c946e8SDaniel Vetter crtc_resp->x = crtc->primary->state->src_x >> 16; 197731c946e8SDaniel Vetter crtc_resp->y = crtc->primary->state->src_y >> 16; 197831c946e8SDaniel Vetter if (crtc->state->enable) { 1979934a8a89SDaniel Stone drm_mode_convert_to_umode(&crtc_resp->mode, &crtc->state->mode); 198031c946e8SDaniel Vetter crtc_resp->mode_valid = 1; 1981f453ba04SDave Airlie 198231c946e8SDaniel Vetter } else { 198331c946e8SDaniel Vetter crtc_resp->mode_valid = 0; 198431c946e8SDaniel Vetter } 198531c946e8SDaniel Vetter } else { 198631c946e8SDaniel Vetter crtc_resp->x = crtc->x; 198731c946e8SDaniel Vetter crtc_resp->y = crtc->y; 198831c946e8SDaniel Vetter if (crtc->enabled) { 1989934a8a89SDaniel Stone drm_mode_convert_to_umode(&crtc_resp->mode, &crtc->mode); 1990f453ba04SDave Airlie crtc_resp->mode_valid = 1; 1991f453ba04SDave Airlie 1992f453ba04SDave Airlie } else { 1993f453ba04SDave Airlie crtc_resp->mode_valid = 0; 1994f453ba04SDave Airlie } 199531c946e8SDaniel Vetter } 1996fcf93f69SDaniel Vetter drm_modeset_unlock_crtc(crtc); 1997f453ba04SDave Airlie 1998baf698b0SDaniel Vetter return 0; 1999f453ba04SDave Airlie } 2000f453ba04SDave Airlie 200161d8e328SDamien Lespiau static bool drm_mode_expose_to_userspace(const struct drm_display_mode *mode, 200261d8e328SDamien Lespiau const struct drm_file *file_priv) 200361d8e328SDamien Lespiau { 200461d8e328SDamien Lespiau /* 200561d8e328SDamien Lespiau * If user-space hasn't configured the driver to expose the stereo 3D 200661d8e328SDamien Lespiau * modes, don't expose them. 200761d8e328SDamien Lespiau */ 200861d8e328SDamien Lespiau if (!file_priv->stereo_allowed && drm_mode_is_stereo(mode)) 200961d8e328SDamien Lespiau return false; 201061d8e328SDamien Lespiau 201161d8e328SDamien Lespiau return true; 201261d8e328SDamien Lespiau } 201361d8e328SDamien Lespiau 2014abd69c55SDaniel Vetter static struct drm_encoder *drm_connector_get_encoder(struct drm_connector *connector) 2015abd69c55SDaniel Vetter { 2016abd69c55SDaniel Vetter /* For atomic drivers only state objects are synchronously updated and 2017abd69c55SDaniel Vetter * protected by modeset locks, so check those first. */ 2018abd69c55SDaniel Vetter if (connector->state) 2019abd69c55SDaniel Vetter return connector->state->best_encoder; 2020abd69c55SDaniel Vetter return connector->encoder; 2021abd69c55SDaniel Vetter } 2022abd69c55SDaniel Vetter 202395cbf110SRob Clark /* helper for getconnector and getproperties ioctls */ 202488a48e29SRob Clark static int get_properties(struct drm_mode_object *obj, bool atomic, 202595cbf110SRob Clark uint32_t __user *prop_ptr, uint64_t __user *prop_values, 202695cbf110SRob Clark uint32_t *arg_count_props) 202795cbf110SRob Clark { 202888a48e29SRob Clark int props_count; 202988a48e29SRob Clark int i, ret, copied; 203088a48e29SRob Clark 203188a48e29SRob Clark props_count = obj->properties->count; 203288a48e29SRob Clark if (!atomic) 203388a48e29SRob Clark props_count -= obj->properties->atomic_count; 203495cbf110SRob Clark 203595cbf110SRob Clark if ((*arg_count_props >= props_count) && props_count) { 203688a48e29SRob Clark for (i = 0, copied = 0; copied < props_count; i++) { 203795cbf110SRob Clark struct drm_property *prop = obj->properties->properties[i]; 203895cbf110SRob Clark uint64_t val; 203995cbf110SRob Clark 204088a48e29SRob Clark if ((prop->flags & DRM_MODE_PROP_ATOMIC) && !atomic) 204188a48e29SRob Clark continue; 204288a48e29SRob Clark 204395cbf110SRob Clark ret = drm_object_property_get_value(obj, prop, &val); 204495cbf110SRob Clark if (ret) 204595cbf110SRob Clark return ret; 204695cbf110SRob Clark 204795cbf110SRob Clark if (put_user(prop->base.id, prop_ptr + copied)) 204895cbf110SRob Clark return -EFAULT; 204995cbf110SRob Clark 205095cbf110SRob Clark if (put_user(val, prop_values + copied)) 205195cbf110SRob Clark return -EFAULT; 205295cbf110SRob Clark 205395cbf110SRob Clark copied++; 205495cbf110SRob Clark } 205595cbf110SRob Clark } 205695cbf110SRob Clark *arg_count_props = props_count; 205795cbf110SRob Clark 205895cbf110SRob Clark return 0; 205995cbf110SRob Clark } 206095cbf110SRob Clark 2061f453ba04SDave Airlie /** 2062f453ba04SDave Airlie * drm_mode_getconnector - get connector configuration 2063065a50edSDaniel Vetter * @dev: drm device for the ioctl 2064065a50edSDaniel Vetter * @data: data pointer for the ioctl 2065065a50edSDaniel Vetter * @file_priv: drm file for the ioctl call 2066f453ba04SDave Airlie * 2067f453ba04SDave Airlie * Construct a connector configuration structure to return to the user. 2068f453ba04SDave Airlie * 2069f453ba04SDave Airlie * Called by the user via ioctl. 2070f453ba04SDave Airlie * 2071c8e32cc1SDaniel Vetter * Returns: 20721a498633SDaniel Vetter * Zero on success, negative errno on failure. 2073f453ba04SDave Airlie */ 2074f453ba04SDave Airlie int drm_mode_getconnector(struct drm_device *dev, void *data, 2075f453ba04SDave Airlie struct drm_file *file_priv) 2076f453ba04SDave Airlie { 2077f453ba04SDave Airlie struct drm_mode_get_connector *out_resp = data; 2078f453ba04SDave Airlie struct drm_connector *connector; 2079abd69c55SDaniel Vetter struct drm_encoder *encoder; 2080f453ba04SDave Airlie struct drm_display_mode *mode; 2081f453ba04SDave Airlie int mode_count = 0; 2082f453ba04SDave Airlie int encoders_count = 0; 2083f453ba04SDave Airlie int ret = 0; 2084f453ba04SDave Airlie int copied = 0; 2085f453ba04SDave Airlie int i; 2086f453ba04SDave Airlie struct drm_mode_modeinfo u_mode; 2087f453ba04SDave Airlie struct drm_mode_modeinfo __user *mode_ptr; 2088f453ba04SDave Airlie uint32_t __user *encoder_ptr; 2089f453ba04SDave Airlie 2090fb3b06c8SDave Airlie if (!drm_core_check_feature(dev, DRIVER_MODESET)) 2091fb3b06c8SDave Airlie return -EINVAL; 2092fb3b06c8SDave Airlie 2093f453ba04SDave Airlie memset(&u_mode, 0, sizeof(struct drm_mode_modeinfo)); 2094f453ba04SDave Airlie 20957b24056bSDaniel Vetter mutex_lock(&dev->mode_config.mutex); 2096f453ba04SDave Airlie 2097b164d31fSDave Airlie connector = drm_connector_lookup(dev, out_resp->connector_id); 2098a2b34e22SRob Clark if (!connector) { 2099f27657f2SVille Syrjälä ret = -ENOENT; 210004bdf441STommi Rantala goto out_unlock; 2101f453ba04SDave Airlie } 2102f453ba04SDave Airlie 210301073b08SThierry Reding for (i = 0; i < DRM_CONNECTOR_MAX_ENCODER; i++) 210401073b08SThierry Reding if (connector->encoder_ids[i] != 0) 2105f453ba04SDave Airlie encoders_count++; 2106f453ba04SDave Airlie 2107f453ba04SDave Airlie if (out_resp->count_modes == 0) { 2108f453ba04SDave Airlie connector->funcs->fill_modes(connector, 2109f453ba04SDave Airlie dev->mode_config.max_width, 2110f453ba04SDave Airlie dev->mode_config.max_height); 2111f453ba04SDave Airlie } 2112f453ba04SDave Airlie 2113f453ba04SDave Airlie /* delayed so we get modes regardless of pre-fill_modes state */ 2114f453ba04SDave Airlie list_for_each_entry(mode, &connector->modes, head) 211561d8e328SDamien Lespiau if (drm_mode_expose_to_userspace(mode, file_priv)) 2116f453ba04SDave Airlie mode_count++; 2117f453ba04SDave Airlie 2118f453ba04SDave Airlie out_resp->connector_id = connector->base.id; 2119f453ba04SDave Airlie out_resp->connector_type = connector->connector_type; 2120f453ba04SDave Airlie out_resp->connector_type_id = connector->connector_type_id; 2121f453ba04SDave Airlie out_resp->mm_width = connector->display_info.width_mm; 2122f453ba04SDave Airlie out_resp->mm_height = connector->display_info.height_mm; 2123f453ba04SDave Airlie out_resp->subpixel = connector->display_info.subpixel_order; 2124f453ba04SDave Airlie out_resp->connection = connector->status; 21252caa80e7SDaniel Vetter 21262caa80e7SDaniel Vetter drm_modeset_lock(&dev->mode_config.connection_mutex, NULL); 2127abd69c55SDaniel Vetter encoder = drm_connector_get_encoder(connector); 2128abd69c55SDaniel Vetter if (encoder) 2129abd69c55SDaniel Vetter out_resp->encoder_id = encoder->base.id; 2130f453ba04SDave Airlie else 2131f453ba04SDave Airlie out_resp->encoder_id = 0; 2132f453ba04SDave Airlie 2133f453ba04SDave Airlie /* 2134f453ba04SDave Airlie * This ioctl is called twice, once to determine how much space is 2135f453ba04SDave Airlie * needed, and the 2nd time to fill it. 2136f453ba04SDave Airlie */ 2137f453ba04SDave Airlie if ((out_resp->count_modes >= mode_count) && mode_count) { 2138f453ba04SDave Airlie copied = 0; 213981f6c7f8SVille Syrjälä mode_ptr = (struct drm_mode_modeinfo __user *)(unsigned long)out_resp->modes_ptr; 2140f453ba04SDave Airlie list_for_each_entry(mode, &connector->modes, head) { 214161d8e328SDamien Lespiau if (!drm_mode_expose_to_userspace(mode, file_priv)) 214261d8e328SDamien Lespiau continue; 214361d8e328SDamien Lespiau 2144934a8a89SDaniel Stone drm_mode_convert_to_umode(&u_mode, mode); 2145f453ba04SDave Airlie if (copy_to_user(mode_ptr + copied, 2146f453ba04SDave Airlie &u_mode, sizeof(u_mode))) { 2147f453ba04SDave Airlie ret = -EFAULT; 2148f453ba04SDave Airlie goto out; 2149f453ba04SDave Airlie } 2150f453ba04SDave Airlie copied++; 2151f453ba04SDave Airlie } 2152f453ba04SDave Airlie } 2153f453ba04SDave Airlie out_resp->count_modes = mode_count; 2154f453ba04SDave Airlie 215588a48e29SRob Clark ret = get_properties(&connector->base, file_priv->atomic, 215695cbf110SRob Clark (uint32_t __user *)(unsigned long)(out_resp->props_ptr), 215795cbf110SRob Clark (uint64_t __user *)(unsigned long)(out_resp->prop_values_ptr), 215895cbf110SRob Clark &out_resp->count_props); 215922b8b13bSRob Clark if (ret) 2160f453ba04SDave Airlie goto out; 2161f453ba04SDave Airlie 2162f453ba04SDave Airlie if ((out_resp->count_encoders >= encoders_count) && encoders_count) { 2163f453ba04SDave Airlie copied = 0; 216481f6c7f8SVille Syrjälä encoder_ptr = (uint32_t __user *)(unsigned long)(out_resp->encoders_ptr); 2165f453ba04SDave Airlie for (i = 0; i < DRM_CONNECTOR_MAX_ENCODER; i++) { 2166f453ba04SDave Airlie if (connector->encoder_ids[i] != 0) { 2167f453ba04SDave Airlie if (put_user(connector->encoder_ids[i], 2168f453ba04SDave Airlie encoder_ptr + copied)) { 2169f453ba04SDave Airlie ret = -EFAULT; 2170f453ba04SDave Airlie goto out; 2171f453ba04SDave Airlie } 2172f453ba04SDave Airlie copied++; 2173f453ba04SDave Airlie } 2174f453ba04SDave Airlie } 2175f453ba04SDave Airlie } 2176f453ba04SDave Airlie out_resp->count_encoders = encoders_count; 2177f453ba04SDave Airlie 2178f453ba04SDave Airlie out: 2179ccfc0865SRob Clark drm_modeset_unlock(&dev->mode_config.connection_mutex); 218004bdf441STommi Rantala 2181b164d31fSDave Airlie drm_connector_unreference(connector); 218204bdf441STommi Rantala out_unlock: 21837b24056bSDaniel Vetter mutex_unlock(&dev->mode_config.mutex); 21847b24056bSDaniel Vetter 2185f453ba04SDave Airlie return ret; 2186f453ba04SDave Airlie } 2187f453ba04SDave Airlie 2188abd69c55SDaniel Vetter static struct drm_crtc *drm_encoder_get_crtc(struct drm_encoder *encoder) 2189abd69c55SDaniel Vetter { 2190abd69c55SDaniel Vetter struct drm_connector *connector; 2191abd69c55SDaniel Vetter struct drm_device *dev = encoder->dev; 2192abd69c55SDaniel Vetter bool uses_atomic = false; 2193abd69c55SDaniel Vetter 2194abd69c55SDaniel Vetter /* For atomic drivers only state objects are synchronously updated and 2195abd69c55SDaniel Vetter * protected by modeset locks, so check those first. */ 21966295d607SDaniel Vetter drm_for_each_connector(connector, dev) { 2197abd69c55SDaniel Vetter if (!connector->state) 2198abd69c55SDaniel Vetter continue; 2199abd69c55SDaniel Vetter 2200abd69c55SDaniel Vetter uses_atomic = true; 2201abd69c55SDaniel Vetter 2202abd69c55SDaniel Vetter if (connector->state->best_encoder != encoder) 2203abd69c55SDaniel Vetter continue; 2204abd69c55SDaniel Vetter 2205abd69c55SDaniel Vetter return connector->state->crtc; 2206abd69c55SDaniel Vetter } 2207abd69c55SDaniel Vetter 2208abd69c55SDaniel Vetter /* Don't return stale data (e.g. pending async disable). */ 2209abd69c55SDaniel Vetter if (uses_atomic) 2210abd69c55SDaniel Vetter return NULL; 2211abd69c55SDaniel Vetter 2212abd69c55SDaniel Vetter return encoder->crtc; 2213abd69c55SDaniel Vetter } 2214abd69c55SDaniel Vetter 2215c8e32cc1SDaniel Vetter /** 2216c8e32cc1SDaniel Vetter * drm_mode_getencoder - get encoder configuration 2217c8e32cc1SDaniel Vetter * @dev: drm device for the ioctl 2218c8e32cc1SDaniel Vetter * @data: data pointer for the ioctl 2219c8e32cc1SDaniel Vetter * @file_priv: drm file for the ioctl call 2220c8e32cc1SDaniel Vetter * 2221c8e32cc1SDaniel Vetter * Construct a encoder configuration structure to return to the user. 2222c8e32cc1SDaniel Vetter * 2223c8e32cc1SDaniel Vetter * Called by the user via ioctl. 2224c8e32cc1SDaniel Vetter * 2225c8e32cc1SDaniel Vetter * Returns: 22261a498633SDaniel Vetter * Zero on success, negative errno on failure. 2227c8e32cc1SDaniel Vetter */ 2228f453ba04SDave Airlie int drm_mode_getencoder(struct drm_device *dev, void *data, 2229f453ba04SDave Airlie struct drm_file *file_priv) 2230f453ba04SDave Airlie { 2231f453ba04SDave Airlie struct drm_mode_get_encoder *enc_resp = data; 2232f453ba04SDave Airlie struct drm_encoder *encoder; 2233abd69c55SDaniel Vetter struct drm_crtc *crtc; 2234f453ba04SDave Airlie 2235fb3b06c8SDave Airlie if (!drm_core_check_feature(dev, DRIVER_MODESET)) 2236fb3b06c8SDave Airlie return -EINVAL; 2237fb3b06c8SDave Airlie 2238a2b34e22SRob Clark encoder = drm_encoder_find(dev, enc_resp->encoder_id); 2239fcf93f69SDaniel Vetter if (!encoder) 2240fcf93f69SDaniel Vetter return -ENOENT; 2241f453ba04SDave Airlie 2242fcf93f69SDaniel Vetter drm_modeset_lock(&dev->mode_config.connection_mutex, NULL); 2243abd69c55SDaniel Vetter crtc = drm_encoder_get_crtc(encoder); 2244abd69c55SDaniel Vetter if (crtc) 2245abd69c55SDaniel Vetter enc_resp->crtc_id = crtc->base.id; 2246f453ba04SDave Airlie else 2247f453ba04SDave Airlie enc_resp->crtc_id = 0; 2248fcf93f69SDaniel Vetter drm_modeset_unlock(&dev->mode_config.connection_mutex); 2249fcf93f69SDaniel Vetter 2250f453ba04SDave Airlie enc_resp->encoder_type = encoder->encoder_type; 2251f453ba04SDave Airlie enc_resp->encoder_id = encoder->base.id; 2252f453ba04SDave Airlie enc_resp->possible_crtcs = encoder->possible_crtcs; 2253f453ba04SDave Airlie enc_resp->possible_clones = encoder->possible_clones; 2254f453ba04SDave Airlie 2255baf698b0SDaniel Vetter return 0; 2256f453ba04SDave Airlie } 2257f453ba04SDave Airlie 2258f453ba04SDave Airlie /** 2259c8e32cc1SDaniel Vetter * drm_mode_getplane_res - enumerate all plane resources 22608cf5c917SJesse Barnes * @dev: DRM device 22618cf5c917SJesse Barnes * @data: ioctl data 22628cf5c917SJesse Barnes * @file_priv: DRM file info 22638cf5c917SJesse Barnes * 2264c8e32cc1SDaniel Vetter * Construct a list of plane ids to return to the user. 2265c8e32cc1SDaniel Vetter * 2266c8e32cc1SDaniel Vetter * Called by the user via ioctl. 2267c8e32cc1SDaniel Vetter * 2268c8e32cc1SDaniel Vetter * Returns: 22691a498633SDaniel Vetter * Zero on success, negative errno on failure. 22708cf5c917SJesse Barnes */ 22718cf5c917SJesse Barnes int drm_mode_getplane_res(struct drm_device *dev, void *data, 22728cf5c917SJesse Barnes struct drm_file *file_priv) 22738cf5c917SJesse Barnes { 22748cf5c917SJesse Barnes struct drm_mode_get_plane_res *plane_resp = data; 22758cf5c917SJesse Barnes struct drm_mode_config *config; 22768cf5c917SJesse Barnes struct drm_plane *plane; 22778cf5c917SJesse Barnes uint32_t __user *plane_ptr; 2278fcf93f69SDaniel Vetter int copied = 0; 2279681e7ec7SMatt Roper unsigned num_planes; 22808cf5c917SJesse Barnes 22818cf5c917SJesse Barnes if (!drm_core_check_feature(dev, DRIVER_MODESET)) 22828cf5c917SJesse Barnes return -EINVAL; 22838cf5c917SJesse Barnes 22848cf5c917SJesse Barnes config = &dev->mode_config; 22858cf5c917SJesse Barnes 2286681e7ec7SMatt Roper if (file_priv->universal_planes) 2287681e7ec7SMatt Roper num_planes = config->num_total_plane; 2288681e7ec7SMatt Roper else 2289681e7ec7SMatt Roper num_planes = config->num_overlay_plane; 2290681e7ec7SMatt Roper 22918cf5c917SJesse Barnes /* 22928cf5c917SJesse Barnes * This ioctl is called twice, once to determine how much space is 22938cf5c917SJesse Barnes * needed, and the 2nd time to fill it. 22948cf5c917SJesse Barnes */ 2295681e7ec7SMatt Roper if (num_planes && 2296681e7ec7SMatt Roper (plane_resp->count_planes >= num_planes)) { 229781f6c7f8SVille Syrjälä plane_ptr = (uint32_t __user *)(unsigned long)plane_resp->plane_id_ptr; 22988cf5c917SJesse Barnes 2299fcf93f69SDaniel Vetter /* Plane lists are invariant, no locking needed. */ 2300e4f62546SDaniel Vetter drm_for_each_plane(plane, dev) { 2301681e7ec7SMatt Roper /* 2302681e7ec7SMatt Roper * Unless userspace set the 'universal planes' 2303681e7ec7SMatt Roper * capability bit, only advertise overlays. 2304681e7ec7SMatt Roper */ 2305681e7ec7SMatt Roper if (plane->type != DRM_PLANE_TYPE_OVERLAY && 2306681e7ec7SMatt Roper !file_priv->universal_planes) 2307e27dde3eSMatt Roper continue; 2308e27dde3eSMatt Roper 2309fcf93f69SDaniel Vetter if (put_user(plane->base.id, plane_ptr + copied)) 2310fcf93f69SDaniel Vetter return -EFAULT; 23118cf5c917SJesse Barnes copied++; 23128cf5c917SJesse Barnes } 23138cf5c917SJesse Barnes } 2314681e7ec7SMatt Roper plane_resp->count_planes = num_planes; 23158cf5c917SJesse Barnes 2316fcf93f69SDaniel Vetter return 0; 23178cf5c917SJesse Barnes } 23188cf5c917SJesse Barnes 23198cf5c917SJesse Barnes /** 2320c8e32cc1SDaniel Vetter * drm_mode_getplane - get plane configuration 23218cf5c917SJesse Barnes * @dev: DRM device 23228cf5c917SJesse Barnes * @data: ioctl data 23238cf5c917SJesse Barnes * @file_priv: DRM file info 23248cf5c917SJesse Barnes * 2325c8e32cc1SDaniel Vetter * Construct a plane configuration structure to return to the user. 2326c8e32cc1SDaniel Vetter * 2327c8e32cc1SDaniel Vetter * Called by the user via ioctl. 2328c8e32cc1SDaniel Vetter * 2329c8e32cc1SDaniel Vetter * Returns: 23301a498633SDaniel Vetter * Zero on success, negative errno on failure. 23318cf5c917SJesse Barnes */ 23328cf5c917SJesse Barnes int drm_mode_getplane(struct drm_device *dev, void *data, 23338cf5c917SJesse Barnes struct drm_file *file_priv) 23348cf5c917SJesse Barnes { 23358cf5c917SJesse Barnes struct drm_mode_get_plane *plane_resp = data; 23368cf5c917SJesse Barnes struct drm_plane *plane; 23378cf5c917SJesse Barnes uint32_t __user *format_ptr; 23388cf5c917SJesse Barnes 23398cf5c917SJesse Barnes if (!drm_core_check_feature(dev, DRIVER_MODESET)) 23408cf5c917SJesse Barnes return -EINVAL; 23418cf5c917SJesse Barnes 2342a2b34e22SRob Clark plane = drm_plane_find(dev, plane_resp->plane_id); 2343fcf93f69SDaniel Vetter if (!plane) 2344fcf93f69SDaniel Vetter return -ENOENT; 23458cf5c917SJesse Barnes 2346fcf93f69SDaniel Vetter drm_modeset_lock(&plane->mutex, NULL); 23478cf5c917SJesse Barnes if (plane->crtc) 23488cf5c917SJesse Barnes plane_resp->crtc_id = plane->crtc->base.id; 23498cf5c917SJesse Barnes else 23508cf5c917SJesse Barnes plane_resp->crtc_id = 0; 23518cf5c917SJesse Barnes 23528cf5c917SJesse Barnes if (plane->fb) 23538cf5c917SJesse Barnes plane_resp->fb_id = plane->fb->base.id; 23548cf5c917SJesse Barnes else 23558cf5c917SJesse Barnes plane_resp->fb_id = 0; 2356fcf93f69SDaniel Vetter drm_modeset_unlock(&plane->mutex); 23578cf5c917SJesse Barnes 23588cf5c917SJesse Barnes plane_resp->plane_id = plane->base.id; 23598cf5c917SJesse Barnes plane_resp->possible_crtcs = plane->possible_crtcs; 2360778ad903SVille Syrjälä plane_resp->gamma_size = 0; 23618cf5c917SJesse Barnes 23628cf5c917SJesse Barnes /* 23638cf5c917SJesse Barnes * This ioctl is called twice, once to determine how much space is 23648cf5c917SJesse Barnes * needed, and the 2nd time to fill it. 23658cf5c917SJesse Barnes */ 23668cf5c917SJesse Barnes if (plane->format_count && 23678cf5c917SJesse Barnes (plane_resp->count_format_types >= plane->format_count)) { 236881f6c7f8SVille Syrjälä format_ptr = (uint32_t __user *)(unsigned long)plane_resp->format_type_ptr; 23698cf5c917SJesse Barnes if (copy_to_user(format_ptr, 23708cf5c917SJesse Barnes plane->format_types, 23718cf5c917SJesse Barnes sizeof(uint32_t) * plane->format_count)) { 2372fcf93f69SDaniel Vetter return -EFAULT; 23738cf5c917SJesse Barnes } 23748cf5c917SJesse Barnes } 23758cf5c917SJesse Barnes plane_resp->count_format_types = plane->format_count; 23768cf5c917SJesse Barnes 2377baf698b0SDaniel Vetter return 0; 23788cf5c917SJesse Barnes } 23798cf5c917SJesse Barnes 2380ead8610dSLaurent Pinchart /** 2381ead8610dSLaurent Pinchart * drm_plane_check_pixel_format - Check if the plane supports the pixel format 2382ead8610dSLaurent Pinchart * @plane: plane to check for format support 2383ead8610dSLaurent Pinchart * @format: the pixel format 2384ead8610dSLaurent Pinchart * 2385ead8610dSLaurent Pinchart * Returns: 2386ead8610dSLaurent Pinchart * Zero of @plane has @format in its list of supported pixel formats, -EINVAL 2387ead8610dSLaurent Pinchart * otherwise. 2388ead8610dSLaurent Pinchart */ 2389ead8610dSLaurent Pinchart int drm_plane_check_pixel_format(const struct drm_plane *plane, u32 format) 2390ead8610dSLaurent Pinchart { 2391ead8610dSLaurent Pinchart unsigned int i; 2392ead8610dSLaurent Pinchart 2393ead8610dSLaurent Pinchart for (i = 0; i < plane->format_count; i++) { 2394ead8610dSLaurent Pinchart if (format == plane->format_types[i]) 2395ead8610dSLaurent Pinchart return 0; 2396ead8610dSLaurent Pinchart } 2397ead8610dSLaurent Pinchart 2398ead8610dSLaurent Pinchart return -EINVAL; 2399ead8610dSLaurent Pinchart } 2400ead8610dSLaurent Pinchart 2401ce8d9eccSVille Syrjälä static int check_src_coords(uint32_t src_x, uint32_t src_y, 2402ce8d9eccSVille Syrjälä uint32_t src_w, uint32_t src_h, 2403ce8d9eccSVille Syrjälä const struct drm_framebuffer *fb) 2404ce8d9eccSVille Syrjälä { 2405ce8d9eccSVille Syrjälä unsigned int fb_width, fb_height; 2406ce8d9eccSVille Syrjälä 2407ce8d9eccSVille Syrjälä fb_width = fb->width << 16; 2408ce8d9eccSVille Syrjälä fb_height = fb->height << 16; 2409ce8d9eccSVille Syrjälä 2410ce8d9eccSVille Syrjälä /* Make sure source coordinates are inside the fb. */ 2411ce8d9eccSVille Syrjälä if (src_w > fb_width || 2412ce8d9eccSVille Syrjälä src_x > fb_width - src_w || 2413ce8d9eccSVille Syrjälä src_h > fb_height || 2414ce8d9eccSVille Syrjälä src_y > fb_height - src_h) { 2415ce8d9eccSVille Syrjälä DRM_DEBUG_KMS("Invalid source coordinates " 2416ce8d9eccSVille Syrjälä "%u.%06ux%u.%06u+%u.%06u+%u.%06u\n", 2417ce8d9eccSVille Syrjälä src_w >> 16, ((src_w & 0xffff) * 15625) >> 10, 2418ce8d9eccSVille Syrjälä src_h >> 16, ((src_h & 0xffff) * 15625) >> 10, 2419ce8d9eccSVille Syrjälä src_x >> 16, ((src_x & 0xffff) * 15625) >> 10, 2420ce8d9eccSVille Syrjälä src_y >> 16, ((src_y & 0xffff) * 15625) >> 10); 2421ce8d9eccSVille Syrjälä return -ENOSPC; 2422ce8d9eccSVille Syrjälä } 2423ce8d9eccSVille Syrjälä 2424ce8d9eccSVille Syrjälä return 0; 2425ce8d9eccSVille Syrjälä } 2426ce8d9eccSVille Syrjälä 2427b36552b3SMatt Roper /* 2428b36552b3SMatt Roper * setplane_internal - setplane handler for internal callers 24298cf5c917SJesse Barnes * 2430b36552b3SMatt Roper * Note that we assume an extra reference has already been taken on fb. If the 2431b36552b3SMatt Roper * update fails, this reference will be dropped before return; if it succeeds, 2432b36552b3SMatt Roper * the previous framebuffer (if any) will be unreferenced instead. 2433c8e32cc1SDaniel Vetter * 2434b36552b3SMatt Roper * src_{x,y,w,h} are provided in 16.16 fixed point format 24358cf5c917SJesse Barnes */ 2436f2b50c11SDaniel Vetter static int __setplane_internal(struct drm_plane *plane, 243717cfd91fSChris Wilson struct drm_crtc *crtc, 2438b36552b3SMatt Roper struct drm_framebuffer *fb, 2439b36552b3SMatt Roper int32_t crtc_x, int32_t crtc_y, 2440b36552b3SMatt Roper uint32_t crtc_w, uint32_t crtc_h, 2441b36552b3SMatt Roper /* src_{x,y,w,h} values are 16.16 fixed point */ 2442b36552b3SMatt Roper uint32_t src_x, uint32_t src_y, 2443b36552b3SMatt Roper uint32_t src_w, uint32_t src_h) 24448cf5c917SJesse Barnes { 24458cf5c917SJesse Barnes int ret = 0; 24468cf5c917SJesse Barnes 24478cf5c917SJesse Barnes /* No fb means shut it down */ 2448b36552b3SMatt Roper if (!fb) { 24493d30a59bSDaniel Vetter plane->old_fb = plane->fb; 2450731cce48SDaniel Vetter ret = plane->funcs->disable_plane(plane); 2451731cce48SDaniel Vetter if (!ret) { 2452e5e3b44cSVille Syrjälä plane->crtc = NULL; 2453e5e3b44cSVille Syrjälä plane->fb = NULL; 2454731cce48SDaniel Vetter } else { 24553d30a59bSDaniel Vetter plane->old_fb = NULL; 2456731cce48SDaniel Vetter } 24578cf5c917SJesse Barnes goto out; 24588cf5c917SJesse Barnes } 24598cf5c917SJesse Barnes 24607f994f3fSMatt Roper /* Check whether this plane is usable on this CRTC */ 24617f994f3fSMatt Roper if (!(plane->possible_crtcs & drm_crtc_mask(crtc))) { 24627f994f3fSMatt Roper DRM_DEBUG_KMS("Invalid crtc for plane\n"); 24637f994f3fSMatt Roper ret = -EINVAL; 24647f994f3fSMatt Roper goto out; 24657f994f3fSMatt Roper } 24667f994f3fSMatt Roper 246762443be6SVille Syrjälä /* Check whether this plane supports the fb pixel format. */ 2468ead8610dSLaurent Pinchart ret = drm_plane_check_pixel_format(plane, fb->pixel_format); 2469ead8610dSLaurent Pinchart if (ret) { 24706ba6d03eSVille Syrjälä DRM_DEBUG_KMS("Invalid pixel format %s\n", 24716ba6d03eSVille Syrjälä drm_get_format_name(fb->pixel_format)); 247262443be6SVille Syrjälä goto out; 247362443be6SVille Syrjälä } 247462443be6SVille Syrjälä 24753968be94SMatt Roper /* Give drivers some help against integer overflows */ 24763968be94SMatt Roper if (crtc_w > INT_MAX || 24773968be94SMatt Roper crtc_x > INT_MAX - (int32_t) crtc_w || 24783968be94SMatt Roper crtc_h > INT_MAX || 24793968be94SMatt Roper crtc_y > INT_MAX - (int32_t) crtc_h) { 24803968be94SMatt Roper DRM_DEBUG_KMS("Invalid CRTC coordinates %ux%u+%d+%d\n", 24813968be94SMatt Roper crtc_w, crtc_h, crtc_x, crtc_y); 2482c390eed0SVille Syrjälä ret = -ERANGE; 248342ef8789SVille Syrjälä goto out; 248442ef8789SVille Syrjälä } 248542ef8789SVille Syrjälä 2486ce8d9eccSVille Syrjälä ret = check_src_coords(src_x, src_y, src_w, src_h, fb); 2487ce8d9eccSVille Syrjälä if (ret) 2488f453ba04SDave Airlie goto out; 2489f453ba04SDave Airlie 24903d30a59bSDaniel Vetter plane->old_fb = plane->fb; 2491f453ba04SDave Airlie ret = plane->funcs->update_plane(plane, crtc, fb, 2492b36552b3SMatt Roper crtc_x, crtc_y, crtc_w, crtc_h, 2493b36552b3SMatt Roper src_x, src_y, src_w, src_h); 2494f453ba04SDave Airlie if (!ret) { 2495f453ba04SDave Airlie plane->crtc = crtc; 2496f453ba04SDave Airlie plane->fb = fb; 249735f8badcSDaniel Vetter fb = NULL; 24980fe27f06SDaniel Vetter } else { 24993d30a59bSDaniel Vetter plane->old_fb = NULL; 2500f453ba04SDave Airlie } 2501f453ba04SDave Airlie 2502f453ba04SDave Airlie out: 25036c2a7532SDaniel Vetter if (fb) 25046c2a7532SDaniel Vetter drm_framebuffer_unreference(fb); 25053d30a59bSDaniel Vetter if (plane->old_fb) 25063d30a59bSDaniel Vetter drm_framebuffer_unreference(plane->old_fb); 25073d30a59bSDaniel Vetter plane->old_fb = NULL; 2508f453ba04SDave Airlie 2509f453ba04SDave Airlie return ret; 2510f2b50c11SDaniel Vetter } 2511b36552b3SMatt Roper 2512f2b50c11SDaniel Vetter static int setplane_internal(struct drm_plane *plane, 2513f2b50c11SDaniel Vetter struct drm_crtc *crtc, 2514f2b50c11SDaniel Vetter struct drm_framebuffer *fb, 2515f2b50c11SDaniel Vetter int32_t crtc_x, int32_t crtc_y, 2516f2b50c11SDaniel Vetter uint32_t crtc_w, uint32_t crtc_h, 2517f2b50c11SDaniel Vetter /* src_{x,y,w,h} values are 16.16 fixed point */ 2518f2b50c11SDaniel Vetter uint32_t src_x, uint32_t src_y, 2519f2b50c11SDaniel Vetter uint32_t src_w, uint32_t src_h) 2520f2b50c11SDaniel Vetter { 2521f2b50c11SDaniel Vetter int ret; 2522f2b50c11SDaniel Vetter 2523f2b50c11SDaniel Vetter drm_modeset_lock_all(plane->dev); 2524f2b50c11SDaniel Vetter ret = __setplane_internal(plane, crtc, fb, 2525f2b50c11SDaniel Vetter crtc_x, crtc_y, crtc_w, crtc_h, 2526f2b50c11SDaniel Vetter src_x, src_y, src_w, src_h); 2527f2b50c11SDaniel Vetter drm_modeset_unlock_all(plane->dev); 2528f2b50c11SDaniel Vetter 2529f2b50c11SDaniel Vetter return ret; 2530b36552b3SMatt Roper } 2531b36552b3SMatt Roper 2532b36552b3SMatt Roper /** 2533b36552b3SMatt Roper * drm_mode_setplane - configure a plane's configuration 2534b36552b3SMatt Roper * @dev: DRM device 2535b36552b3SMatt Roper * @data: ioctl data* 2536b36552b3SMatt Roper * @file_priv: DRM file info 2537b36552b3SMatt Roper * 2538b36552b3SMatt Roper * Set plane configuration, including placement, fb, scaling, and other factors. 2539b36552b3SMatt Roper * Or pass a NULL fb to disable (planes may be disabled without providing a 2540b36552b3SMatt Roper * valid crtc). 2541b36552b3SMatt Roper * 2542b36552b3SMatt Roper * Returns: 25431a498633SDaniel Vetter * Zero on success, negative errno on failure. 2544b36552b3SMatt Roper */ 2545b36552b3SMatt Roper int drm_mode_setplane(struct drm_device *dev, void *data, 2546b36552b3SMatt Roper struct drm_file *file_priv) 2547b36552b3SMatt Roper { 2548b36552b3SMatt Roper struct drm_mode_set_plane *plane_req = data; 2549b36552b3SMatt Roper struct drm_plane *plane; 2550b36552b3SMatt Roper struct drm_crtc *crtc = NULL; 2551b36552b3SMatt Roper struct drm_framebuffer *fb = NULL; 2552b36552b3SMatt Roper 2553b36552b3SMatt Roper if (!drm_core_check_feature(dev, DRIVER_MODESET)) 2554b36552b3SMatt Roper return -EINVAL; 2555b36552b3SMatt Roper 2556b36552b3SMatt Roper /* 2557b36552b3SMatt Roper * First, find the plane, crtc, and fb objects. If not available, 2558b36552b3SMatt Roper * we don't bother to call the driver. 2559b36552b3SMatt Roper */ 2560933f622fSRob Clark plane = drm_plane_find(dev, plane_req->plane_id); 2561933f622fSRob Clark if (!plane) { 2562b36552b3SMatt Roper DRM_DEBUG_KMS("Unknown plane ID %d\n", 2563b36552b3SMatt Roper plane_req->plane_id); 2564b36552b3SMatt Roper return -ENOENT; 2565b36552b3SMatt Roper } 2566b36552b3SMatt Roper 2567b36552b3SMatt Roper if (plane_req->fb_id) { 2568b36552b3SMatt Roper fb = drm_framebuffer_lookup(dev, plane_req->fb_id); 2569b36552b3SMatt Roper if (!fb) { 2570b36552b3SMatt Roper DRM_DEBUG_KMS("Unknown framebuffer ID %d\n", 2571b36552b3SMatt Roper plane_req->fb_id); 2572b36552b3SMatt Roper return -ENOENT; 2573b36552b3SMatt Roper } 2574b36552b3SMatt Roper 2575933f622fSRob Clark crtc = drm_crtc_find(dev, plane_req->crtc_id); 2576933f622fSRob Clark if (!crtc) { 2577b36552b3SMatt Roper DRM_DEBUG_KMS("Unknown crtc ID %d\n", 2578b36552b3SMatt Roper plane_req->crtc_id); 2579b36552b3SMatt Roper return -ENOENT; 2580b36552b3SMatt Roper } 2581b36552b3SMatt Roper } 2582b36552b3SMatt Roper 2583161d0dc1SMatt Roper /* 2584161d0dc1SMatt Roper * setplane_internal will take care of deref'ing either the old or new 2585161d0dc1SMatt Roper * framebuffer depending on success. 2586161d0dc1SMatt Roper */ 258717cfd91fSChris Wilson return setplane_internal(plane, crtc, fb, 2588b36552b3SMatt Roper plane_req->crtc_x, plane_req->crtc_y, 2589b36552b3SMatt Roper plane_req->crtc_w, plane_req->crtc_h, 2590b36552b3SMatt Roper plane_req->src_x, plane_req->src_y, 2591b36552b3SMatt Roper plane_req->src_w, plane_req->src_h); 2592f453ba04SDave Airlie } 2593f453ba04SDave Airlie 2594f453ba04SDave Airlie /** 25952d13b679SDaniel Vetter * drm_mode_set_config_internal - helper to call ->set_config 25962d13b679SDaniel Vetter * @set: modeset config to set 25972d13b679SDaniel Vetter * 25982d13b679SDaniel Vetter * This is a little helper to wrap internal calls to the ->set_config driver 25992d13b679SDaniel Vetter * interface. The only thing it adds is correct refcounting dance. 2600c8e32cc1SDaniel Vetter * 2601c8e32cc1SDaniel Vetter * Returns: 26021a498633SDaniel Vetter * Zero on success, negative errno on failure. 26032d13b679SDaniel Vetter */ 26042d13b679SDaniel Vetter int drm_mode_set_config_internal(struct drm_mode_set *set) 26052d13b679SDaniel Vetter { 26062d13b679SDaniel Vetter struct drm_crtc *crtc = set->crtc; 26075cef29aaSDaniel Vetter struct drm_framebuffer *fb; 26085cef29aaSDaniel Vetter struct drm_crtc *tmp; 2609b0d12325SDaniel Vetter int ret; 26102d13b679SDaniel Vetter 26115cef29aaSDaniel Vetter /* 26125cef29aaSDaniel Vetter * NOTE: ->set_config can also disable other crtcs (if we steal all 26135cef29aaSDaniel Vetter * connectors from it), hence we need to refcount the fbs across all 26145cef29aaSDaniel Vetter * crtcs. Atomic modeset will have saner semantics ... 26155cef29aaSDaniel Vetter */ 2616e4f62546SDaniel Vetter drm_for_each_crtc(tmp, crtc->dev) 26173d30a59bSDaniel Vetter tmp->primary->old_fb = tmp->primary->fb; 26185cef29aaSDaniel Vetter 2619b0d12325SDaniel Vetter fb = set->fb; 2620b0d12325SDaniel Vetter 2621b0d12325SDaniel Vetter ret = crtc->funcs->set_config(set); 2622b0d12325SDaniel Vetter if (ret == 0) { 2623e13161afSMatt Roper crtc->primary->crtc = crtc; 26240fe27f06SDaniel Vetter crtc->primary->fb = fb; 26255cef29aaSDaniel Vetter } 2626cc85e121SDaniel Vetter 2627e4f62546SDaniel Vetter drm_for_each_crtc(tmp, crtc->dev) { 2628f4510a27SMatt Roper if (tmp->primary->fb) 2629f4510a27SMatt Roper drm_framebuffer_reference(tmp->primary->fb); 26303d30a59bSDaniel Vetter if (tmp->primary->old_fb) 26313d30a59bSDaniel Vetter drm_framebuffer_unreference(tmp->primary->old_fb); 26323d30a59bSDaniel Vetter tmp->primary->old_fb = NULL; 2633b0d12325SDaniel Vetter } 2634b0d12325SDaniel Vetter 2635b0d12325SDaniel Vetter return ret; 26362d13b679SDaniel Vetter } 26372d13b679SDaniel Vetter EXPORT_SYMBOL(drm_mode_set_config_internal); 26382d13b679SDaniel Vetter 2639af93629dSMatt Roper /** 2640ecb7e16bSGustavo Padovan * drm_crtc_get_hv_timing - Fetches hdisplay/vdisplay for given mode 2641ecb7e16bSGustavo Padovan * @mode: mode to query 2642ecb7e16bSGustavo Padovan * @hdisplay: hdisplay value to fill in 2643ecb7e16bSGustavo Padovan * @vdisplay: vdisplay value to fill in 2644ecb7e16bSGustavo Padovan * 2645ecb7e16bSGustavo Padovan * The vdisplay value will be doubled if the specified mode is a stereo mode of 2646ecb7e16bSGustavo Padovan * the appropriate layout. 2647ecb7e16bSGustavo Padovan */ 2648ecb7e16bSGustavo Padovan void drm_crtc_get_hv_timing(const struct drm_display_mode *mode, 2649ecb7e16bSGustavo Padovan int *hdisplay, int *vdisplay) 2650ecb7e16bSGustavo Padovan { 2651ecb7e16bSGustavo Padovan struct drm_display_mode adjusted; 2652ecb7e16bSGustavo Padovan 2653ecb7e16bSGustavo Padovan drm_mode_copy(&adjusted, mode); 2654ecb7e16bSGustavo Padovan drm_mode_set_crtcinfo(&adjusted, CRTC_STEREO_DOUBLE_ONLY); 2655ecb7e16bSGustavo Padovan *hdisplay = adjusted.crtc_hdisplay; 2656ecb7e16bSGustavo Padovan *vdisplay = adjusted.crtc_vdisplay; 2657ecb7e16bSGustavo Padovan } 2658ecb7e16bSGustavo Padovan EXPORT_SYMBOL(drm_crtc_get_hv_timing); 2659ecb7e16bSGustavo Padovan 2660ecb7e16bSGustavo Padovan /** 2661af93629dSMatt Roper * drm_crtc_check_viewport - Checks that a framebuffer is big enough for the 2662af93629dSMatt Roper * CRTC viewport 2663af93629dSMatt Roper * @crtc: CRTC that framebuffer will be displayed on 2664af93629dSMatt Roper * @x: x panning 2665af93629dSMatt Roper * @y: y panning 2666af93629dSMatt Roper * @mode: mode that framebuffer will be displayed under 2667af93629dSMatt Roper * @fb: framebuffer to check size of 2668c11e9283SDamien Lespiau */ 2669af93629dSMatt Roper int drm_crtc_check_viewport(const struct drm_crtc *crtc, 2670c11e9283SDamien Lespiau int x, int y, 2671c11e9283SDamien Lespiau const struct drm_display_mode *mode, 2672c11e9283SDamien Lespiau const struct drm_framebuffer *fb) 2673c11e9283SDamien Lespiau 2674c11e9283SDamien Lespiau { 2675c11e9283SDamien Lespiau int hdisplay, vdisplay; 2676c11e9283SDamien Lespiau 2677ecb7e16bSGustavo Padovan drm_crtc_get_hv_timing(mode, &hdisplay, &vdisplay); 2678a0c1bbb0SDamien Lespiau 267933e0be63SVille Syrjälä if (crtc->state && 268033e0be63SVille Syrjälä crtc->primary->state->rotation & (BIT(DRM_ROTATE_90) | 268133e0be63SVille Syrjälä BIT(DRM_ROTATE_270))) 2682c11e9283SDamien Lespiau swap(hdisplay, vdisplay); 2683c11e9283SDamien Lespiau 2684ce8d9eccSVille Syrjälä return check_src_coords(x << 16, y << 16, 2685ce8d9eccSVille Syrjälä hdisplay << 16, vdisplay << 16, fb); 2686c11e9283SDamien Lespiau } 2687af93629dSMatt Roper EXPORT_SYMBOL(drm_crtc_check_viewport); 2688c11e9283SDamien Lespiau 26892d13b679SDaniel Vetter /** 2690f453ba04SDave Airlie * drm_mode_setcrtc - set CRTC configuration 2691065a50edSDaniel Vetter * @dev: drm device for the ioctl 2692065a50edSDaniel Vetter * @data: data pointer for the ioctl 2693065a50edSDaniel Vetter * @file_priv: drm file for the ioctl call 2694f453ba04SDave Airlie * 2695f453ba04SDave Airlie * Build a new CRTC configuration based on user request. 2696f453ba04SDave Airlie * 2697f453ba04SDave Airlie * Called by the user via ioctl. 2698f453ba04SDave Airlie * 2699c8e32cc1SDaniel Vetter * Returns: 27001a498633SDaniel Vetter * Zero on success, negative errno on failure. 2701f453ba04SDave Airlie */ 2702f453ba04SDave Airlie int drm_mode_setcrtc(struct drm_device *dev, void *data, 2703f453ba04SDave Airlie struct drm_file *file_priv) 2704f453ba04SDave Airlie { 2705f453ba04SDave Airlie struct drm_mode_config *config = &dev->mode_config; 2706f453ba04SDave Airlie struct drm_mode_crtc *crtc_req = data; 27076653cc8dSVille Syrjälä struct drm_crtc *crtc; 2708f453ba04SDave Airlie struct drm_connector **connector_set = NULL, *connector; 2709f453ba04SDave Airlie struct drm_framebuffer *fb = NULL; 2710f453ba04SDave Airlie struct drm_display_mode *mode = NULL; 2711f453ba04SDave Airlie struct drm_mode_set set; 2712f453ba04SDave Airlie uint32_t __user *set_connectors_ptr; 27134a1b0714SLaurent Pinchart int ret; 2714f453ba04SDave Airlie int i; 2715f453ba04SDave Airlie 2716fb3b06c8SDave Airlie if (!drm_core_check_feature(dev, DRIVER_MODESET)) 2717fb3b06c8SDave Airlie return -EINVAL; 2718fb3b06c8SDave Airlie 271901447e9fSZhao Junwang /* 272001447e9fSZhao Junwang * Universal plane src offsets are only 16.16, prevent havoc for 272101447e9fSZhao Junwang * drivers using universal plane code internally. 272201447e9fSZhao Junwang */ 272301447e9fSZhao Junwang if (crtc_req->x & 0xffff0000 || crtc_req->y & 0xffff0000) 27241d97e915SVille Syrjälä return -ERANGE; 27251d97e915SVille Syrjälä 272684849903SDaniel Vetter drm_modeset_lock_all(dev); 2727a2b34e22SRob Clark crtc = drm_crtc_find(dev, crtc_req->crtc_id); 2728a2b34e22SRob Clark if (!crtc) { 272958367ed6SZhao Yakui DRM_DEBUG_KMS("Unknown CRTC ID %d\n", crtc_req->crtc_id); 2730f27657f2SVille Syrjälä ret = -ENOENT; 2731f453ba04SDave Airlie goto out; 2732f453ba04SDave Airlie } 2733fa3ab4c2SVille Syrjälä DRM_DEBUG_KMS("[CRTC:%d:%s]\n", crtc->base.id, crtc->name); 2734f453ba04SDave Airlie 2735f453ba04SDave Airlie if (crtc_req->mode_valid) { 2736f453ba04SDave Airlie /* If we have a mode we need a framebuffer. */ 2737f453ba04SDave Airlie /* If we pass -1, set the mode with the currently bound fb */ 2738f453ba04SDave Airlie if (crtc_req->fb_id == -1) { 2739f4510a27SMatt Roper if (!crtc->primary->fb) { 27406653cc8dSVille Syrjälä DRM_DEBUG_KMS("CRTC doesn't have current FB\n"); 27416653cc8dSVille Syrjälä ret = -EINVAL; 27426653cc8dSVille Syrjälä goto out; 27436653cc8dSVille Syrjälä } 2744f4510a27SMatt Roper fb = crtc->primary->fb; 2745b0d12325SDaniel Vetter /* Make refcounting symmetric with the lookup path. */ 2746b0d12325SDaniel Vetter drm_framebuffer_reference(fb); 2747f453ba04SDave Airlie } else { 2748786b99edSDaniel Vetter fb = drm_framebuffer_lookup(dev, crtc_req->fb_id); 2749786b99edSDaniel Vetter if (!fb) { 275058367ed6SZhao Yakui DRM_DEBUG_KMS("Unknown FB ID%d\n", 275158367ed6SZhao Yakui crtc_req->fb_id); 275237c4e705SVille Syrjälä ret = -ENOENT; 2753f453ba04SDave Airlie goto out; 2754f453ba04SDave Airlie } 2755f453ba04SDave Airlie } 2756f453ba04SDave Airlie 2757f453ba04SDave Airlie mode = drm_mode_create(dev); 2758ee34ab5bSVille Syrjälä if (!mode) { 2759ee34ab5bSVille Syrjälä ret = -ENOMEM; 2760ee34ab5bSVille Syrjälä goto out; 2761ee34ab5bSVille Syrjälä } 2762ee34ab5bSVille Syrjälä 2763934a8a89SDaniel Stone ret = drm_mode_convert_umode(mode, &crtc_req->mode); 276490367bf6SVille Syrjälä if (ret) { 276590367bf6SVille Syrjälä DRM_DEBUG_KMS("Invalid mode\n"); 276690367bf6SVille Syrjälä goto out; 276790367bf6SVille Syrjälä } 276890367bf6SVille Syrjälä 27697eb5f302SLaurent Pinchart /* 27707eb5f302SLaurent Pinchart * Check whether the primary plane supports the fb pixel format. 27717eb5f302SLaurent Pinchart * Drivers not implementing the universal planes API use a 27727eb5f302SLaurent Pinchart * default formats list provided by the DRM core which doesn't 27737eb5f302SLaurent Pinchart * match real hardware capabilities. Skip the check in that 27747eb5f302SLaurent Pinchart * case. 27757eb5f302SLaurent Pinchart */ 27767eb5f302SLaurent Pinchart if (!crtc->primary->format_default) { 27777eb5f302SLaurent Pinchart ret = drm_plane_check_pixel_format(crtc->primary, 27787eb5f302SLaurent Pinchart fb->pixel_format); 27797eb5f302SLaurent Pinchart if (ret) { 27807eb5f302SLaurent Pinchart DRM_DEBUG_KMS("Invalid pixel format %s\n", 27817eb5f302SLaurent Pinchart drm_get_format_name(fb->pixel_format)); 27827eb5f302SLaurent Pinchart goto out; 27837eb5f302SLaurent Pinchart } 27847eb5f302SLaurent Pinchart } 27857eb5f302SLaurent Pinchart 2786c11e9283SDamien Lespiau ret = drm_crtc_check_viewport(crtc, crtc_req->x, crtc_req->y, 2787c11e9283SDamien Lespiau mode, fb); 2788c11e9283SDamien Lespiau if (ret) 27895f61bb42SVille Syrjälä goto out; 2790c11e9283SDamien Lespiau 2791f453ba04SDave Airlie } 2792f453ba04SDave Airlie 2793f453ba04SDave Airlie if (crtc_req->count_connectors == 0 && mode) { 279458367ed6SZhao Yakui DRM_DEBUG_KMS("Count connectors is 0 but mode set\n"); 2795f453ba04SDave Airlie ret = -EINVAL; 2796f453ba04SDave Airlie goto out; 2797f453ba04SDave Airlie } 2798f453ba04SDave Airlie 27997781de74SJakob Bornecrantz if (crtc_req->count_connectors > 0 && (!mode || !fb)) { 280058367ed6SZhao Yakui DRM_DEBUG_KMS("Count connectors is %d but no mode or fb set\n", 2801f453ba04SDave Airlie crtc_req->count_connectors); 2802f453ba04SDave Airlie ret = -EINVAL; 2803f453ba04SDave Airlie goto out; 2804f453ba04SDave Airlie } 2805f453ba04SDave Airlie 2806f453ba04SDave Airlie if (crtc_req->count_connectors > 0) { 2807f453ba04SDave Airlie u32 out_id; 2808f453ba04SDave Airlie 2809f453ba04SDave Airlie /* Avoid unbounded kernel memory allocation */ 2810f453ba04SDave Airlie if (crtc_req->count_connectors > config->num_connector) { 2811f453ba04SDave Airlie ret = -EINVAL; 2812f453ba04SDave Airlie goto out; 2813f453ba04SDave Airlie } 2814f453ba04SDave Airlie 28152f6c5389SThierry Reding connector_set = kmalloc_array(crtc_req->count_connectors, 2816f453ba04SDave Airlie sizeof(struct drm_connector *), 2817f453ba04SDave Airlie GFP_KERNEL); 2818f453ba04SDave Airlie if (!connector_set) { 2819f453ba04SDave Airlie ret = -ENOMEM; 2820f453ba04SDave Airlie goto out; 2821f453ba04SDave Airlie } 2822f453ba04SDave Airlie 2823f453ba04SDave Airlie for (i = 0; i < crtc_req->count_connectors; i++) { 2824b164d31fSDave Airlie connector_set[i] = NULL; 282581f6c7f8SVille Syrjälä set_connectors_ptr = (uint32_t __user *)(unsigned long)crtc_req->set_connectors_ptr; 2826f453ba04SDave Airlie if (get_user(out_id, &set_connectors_ptr[i])) { 2827f453ba04SDave Airlie ret = -EFAULT; 2828f453ba04SDave Airlie goto out; 2829f453ba04SDave Airlie } 2830f453ba04SDave Airlie 2831b164d31fSDave Airlie connector = drm_connector_lookup(dev, out_id); 2832a2b34e22SRob Clark if (!connector) { 283358367ed6SZhao Yakui DRM_DEBUG_KMS("Connector id %d unknown\n", 283458367ed6SZhao Yakui out_id); 2835f27657f2SVille Syrjälä ret = -ENOENT; 2836f453ba04SDave Airlie goto out; 2837f453ba04SDave Airlie } 28389440106bSJerome Glisse DRM_DEBUG_KMS("[CONNECTOR:%d:%s]\n", 28399440106bSJerome Glisse connector->base.id, 284025933820SJani Nikula connector->name); 2841f453ba04SDave Airlie 2842f453ba04SDave Airlie connector_set[i] = connector; 2843f453ba04SDave Airlie } 2844f453ba04SDave Airlie } 2845f453ba04SDave Airlie 2846f453ba04SDave Airlie set.crtc = crtc; 2847f453ba04SDave Airlie set.x = crtc_req->x; 2848f453ba04SDave Airlie set.y = crtc_req->y; 2849f453ba04SDave Airlie set.mode = mode; 2850f453ba04SDave Airlie set.connectors = connector_set; 2851f453ba04SDave Airlie set.num_connectors = crtc_req->count_connectors; 2852f453ba04SDave Airlie set.fb = fb; 28532d13b679SDaniel Vetter ret = drm_mode_set_config_internal(&set); 2854f453ba04SDave Airlie 2855f453ba04SDave Airlie out: 2856b0d12325SDaniel Vetter if (fb) 2857b0d12325SDaniel Vetter drm_framebuffer_unreference(fb); 2858b0d12325SDaniel Vetter 2859b164d31fSDave Airlie if (connector_set) { 2860b164d31fSDave Airlie for (i = 0; i < crtc_req->count_connectors; i++) { 2861b164d31fSDave Airlie if (connector_set[i]) 2862b164d31fSDave Airlie drm_connector_unreference(connector_set[i]); 2863b164d31fSDave Airlie } 2864b164d31fSDave Airlie } 2865f453ba04SDave Airlie kfree(connector_set); 2866ee34ab5bSVille Syrjälä drm_mode_destroy(dev, mode); 286784849903SDaniel Vetter drm_modeset_unlock_all(dev); 2868f453ba04SDave Airlie return ret; 2869f453ba04SDave Airlie } 2870f453ba04SDave Airlie 2871161d0dc1SMatt Roper /** 2872161d0dc1SMatt Roper * drm_mode_cursor_universal - translate legacy cursor ioctl call into a 2873161d0dc1SMatt Roper * universal plane handler call 2874161d0dc1SMatt Roper * @crtc: crtc to update cursor for 2875161d0dc1SMatt Roper * @req: data pointer for the ioctl 2876161d0dc1SMatt Roper * @file_priv: drm file for the ioctl call 2877161d0dc1SMatt Roper * 2878161d0dc1SMatt Roper * Legacy cursor ioctl's work directly with driver buffer handles. To 2879161d0dc1SMatt Roper * translate legacy ioctl calls into universal plane handler calls, we need to 2880161d0dc1SMatt Roper * wrap the native buffer handle in a drm_framebuffer. 2881161d0dc1SMatt Roper * 2882161d0dc1SMatt Roper * Note that we assume any handle passed to the legacy ioctls was a 32-bit ARGB 2883161d0dc1SMatt Roper * buffer with a pitch of 4*width; the universal plane interface should be used 2884161d0dc1SMatt Roper * directly in cases where the hardware can support other buffer settings and 2885161d0dc1SMatt Roper * userspace wants to make use of these capabilities. 2886161d0dc1SMatt Roper * 2887161d0dc1SMatt Roper * Returns: 28881a498633SDaniel Vetter * Zero on success, negative errno on failure. 2889161d0dc1SMatt Roper */ 2890161d0dc1SMatt Roper static int drm_mode_cursor_universal(struct drm_crtc *crtc, 2891161d0dc1SMatt Roper struct drm_mode_cursor2 *req, 2892161d0dc1SMatt Roper struct drm_file *file_priv) 2893161d0dc1SMatt Roper { 2894161d0dc1SMatt Roper struct drm_device *dev = crtc->dev; 2895161d0dc1SMatt Roper struct drm_framebuffer *fb = NULL; 2896161d0dc1SMatt Roper struct drm_mode_fb_cmd2 fbreq = { 2897161d0dc1SMatt Roper .width = req->width, 2898161d0dc1SMatt Roper .height = req->height, 2899161d0dc1SMatt Roper .pixel_format = DRM_FORMAT_ARGB8888, 2900161d0dc1SMatt Roper .pitches = { req->width * 4 }, 2901161d0dc1SMatt Roper .handles = { req->handle }, 2902161d0dc1SMatt Roper }; 2903161d0dc1SMatt Roper int32_t crtc_x, crtc_y; 2904161d0dc1SMatt Roper uint32_t crtc_w = 0, crtc_h = 0; 2905161d0dc1SMatt Roper uint32_t src_w = 0, src_h = 0; 2906161d0dc1SMatt Roper int ret = 0; 2907161d0dc1SMatt Roper 2908161d0dc1SMatt Roper BUG_ON(!crtc->cursor); 2909f2b50c11SDaniel Vetter WARN_ON(crtc->cursor->crtc != crtc && crtc->cursor->crtc != NULL); 2910161d0dc1SMatt Roper 2911161d0dc1SMatt Roper /* 2912161d0dc1SMatt Roper * Obtain fb we'll be using (either new or existing) and take an extra 2913161d0dc1SMatt Roper * reference to it if fb != null. setplane will take care of dropping 2914161d0dc1SMatt Roper * the reference if the plane update fails. 2915161d0dc1SMatt Roper */ 2916161d0dc1SMatt Roper if (req->flags & DRM_MODE_CURSOR_BO) { 2917161d0dc1SMatt Roper if (req->handle) { 29189a6f5130SChris Wilson fb = internal_framebuffer_create(dev, &fbreq, file_priv); 2919161d0dc1SMatt Roper if (IS_ERR(fb)) { 2920161d0dc1SMatt Roper DRM_DEBUG_KMS("failed to wrap cursor buffer in drm framebuffer\n"); 2921161d0dc1SMatt Roper return PTR_ERR(fb); 2922161d0dc1SMatt Roper } 2923dd546591SGerd Hoffmann fb->hot_x = req->hot_x; 2924dd546591SGerd Hoffmann fb->hot_y = req->hot_y; 2925161d0dc1SMatt Roper } else { 2926161d0dc1SMatt Roper fb = NULL; 2927161d0dc1SMatt Roper } 2928161d0dc1SMatt Roper } else { 2929161d0dc1SMatt Roper fb = crtc->cursor->fb; 2930161d0dc1SMatt Roper if (fb) 2931161d0dc1SMatt Roper drm_framebuffer_reference(fb); 2932161d0dc1SMatt Roper } 2933161d0dc1SMatt Roper 2934161d0dc1SMatt Roper if (req->flags & DRM_MODE_CURSOR_MOVE) { 2935161d0dc1SMatt Roper crtc_x = req->x; 2936161d0dc1SMatt Roper crtc_y = req->y; 2937161d0dc1SMatt Roper } else { 2938161d0dc1SMatt Roper crtc_x = crtc->cursor_x; 2939161d0dc1SMatt Roper crtc_y = crtc->cursor_y; 2940161d0dc1SMatt Roper } 2941161d0dc1SMatt Roper 2942161d0dc1SMatt Roper if (fb) { 2943161d0dc1SMatt Roper crtc_w = fb->width; 2944161d0dc1SMatt Roper crtc_h = fb->height; 2945161d0dc1SMatt Roper src_w = fb->width << 16; 2946161d0dc1SMatt Roper src_h = fb->height << 16; 2947161d0dc1SMatt Roper } 2948161d0dc1SMatt Roper 2949161d0dc1SMatt Roper /* 2950161d0dc1SMatt Roper * setplane_internal will take care of deref'ing either the old or new 2951161d0dc1SMatt Roper * framebuffer depending on success. 2952161d0dc1SMatt Roper */ 2953f2b50c11SDaniel Vetter ret = __setplane_internal(crtc->cursor, crtc, fb, 2954161d0dc1SMatt Roper crtc_x, crtc_y, crtc_w, crtc_h, 2955161d0dc1SMatt Roper 0, 0, src_w, src_h); 2956161d0dc1SMatt Roper 2957161d0dc1SMatt Roper /* Update successful; save new cursor position, if necessary */ 2958161d0dc1SMatt Roper if (ret == 0 && req->flags & DRM_MODE_CURSOR_MOVE) { 2959161d0dc1SMatt Roper crtc->cursor_x = req->x; 2960161d0dc1SMatt Roper crtc->cursor_y = req->y; 2961161d0dc1SMatt Roper } 2962161d0dc1SMatt Roper 2963161d0dc1SMatt Roper return ret; 2964161d0dc1SMatt Roper } 2965161d0dc1SMatt Roper 29664c813d4dSDave Airlie static int drm_mode_cursor_common(struct drm_device *dev, 29674c813d4dSDave Airlie struct drm_mode_cursor2 *req, 29684c813d4dSDave Airlie struct drm_file *file_priv) 2969f453ba04SDave Airlie { 2970f453ba04SDave Airlie struct drm_crtc *crtc; 2971f453ba04SDave Airlie int ret = 0; 2972f453ba04SDave Airlie 2973fb3b06c8SDave Airlie if (!drm_core_check_feature(dev, DRIVER_MODESET)) 2974fb3b06c8SDave Airlie return -EINVAL; 2975fb3b06c8SDave Airlie 29767c4eaca4SJakob Bornecrantz if (!req->flags || (~DRM_MODE_CURSOR_FLAGS & req->flags)) 2977f453ba04SDave Airlie return -EINVAL; 2978f453ba04SDave Airlie 2979a2b34e22SRob Clark crtc = drm_crtc_find(dev, req->crtc_id); 2980a2b34e22SRob Clark if (!crtc) { 298158367ed6SZhao Yakui DRM_DEBUG_KMS("Unknown CRTC ID %d\n", req->crtc_id); 2982f27657f2SVille Syrjälä return -ENOENT; 2983f453ba04SDave Airlie } 2984f453ba04SDave Airlie 2985161d0dc1SMatt Roper /* 2986161d0dc1SMatt Roper * If this crtc has a universal cursor plane, call that plane's update 2987161d0dc1SMatt Roper * handler rather than using legacy cursor handlers. 2988161d0dc1SMatt Roper */ 29894d02e2deSDaniel Vetter drm_modeset_lock_crtc(crtc, crtc->cursor); 2990f2b50c11SDaniel Vetter if (crtc->cursor) { 2991f2b50c11SDaniel Vetter ret = drm_mode_cursor_universal(crtc, req, file_priv); 2992f2b50c11SDaniel Vetter goto out; 2993f2b50c11SDaniel Vetter } 2994f2b50c11SDaniel Vetter 2995f453ba04SDave Airlie if (req->flags & DRM_MODE_CURSOR_BO) { 29964c813d4dSDave Airlie if (!crtc->funcs->cursor_set && !crtc->funcs->cursor_set2) { 2997f453ba04SDave Airlie ret = -ENXIO; 2998f453ba04SDave Airlie goto out; 2999f453ba04SDave Airlie } 3000f453ba04SDave Airlie /* Turns off the cursor if handle is 0 */ 30014c813d4dSDave Airlie if (crtc->funcs->cursor_set2) 30024c813d4dSDave Airlie ret = crtc->funcs->cursor_set2(crtc, file_priv, req->handle, 30034c813d4dSDave Airlie req->width, req->height, req->hot_x, req->hot_y); 30044c813d4dSDave Airlie else 3005f453ba04SDave Airlie ret = crtc->funcs->cursor_set(crtc, file_priv, req->handle, 3006f453ba04SDave Airlie req->width, req->height); 3007f453ba04SDave Airlie } 3008f453ba04SDave Airlie 3009f453ba04SDave Airlie if (req->flags & DRM_MODE_CURSOR_MOVE) { 3010f453ba04SDave Airlie if (crtc->funcs->cursor_move) { 3011f453ba04SDave Airlie ret = crtc->funcs->cursor_move(crtc, req->x, req->y); 3012f453ba04SDave Airlie } else { 3013f453ba04SDave Airlie ret = -EFAULT; 3014f453ba04SDave Airlie goto out; 3015f453ba04SDave Airlie } 3016f453ba04SDave Airlie } 3017f453ba04SDave Airlie out: 3018d059f652SDaniel Vetter drm_modeset_unlock_crtc(crtc); 3019dac35663SDaniel Vetter 3020f453ba04SDave Airlie return ret; 30214c813d4dSDave Airlie 30224c813d4dSDave Airlie } 3023c8e32cc1SDaniel Vetter 3024c8e32cc1SDaniel Vetter 3025c8e32cc1SDaniel Vetter /** 3026c8e32cc1SDaniel Vetter * drm_mode_cursor_ioctl - set CRTC's cursor configuration 3027c8e32cc1SDaniel Vetter * @dev: drm device for the ioctl 3028c8e32cc1SDaniel Vetter * @data: data pointer for the ioctl 3029c8e32cc1SDaniel Vetter * @file_priv: drm file for the ioctl call 3030c8e32cc1SDaniel Vetter * 3031c8e32cc1SDaniel Vetter * Set the cursor configuration based on user request. 3032c8e32cc1SDaniel Vetter * 3033c8e32cc1SDaniel Vetter * Called by the user via ioctl. 3034c8e32cc1SDaniel Vetter * 3035c8e32cc1SDaniel Vetter * Returns: 30361a498633SDaniel Vetter * Zero on success, negative errno on failure. 3037c8e32cc1SDaniel Vetter */ 30384c813d4dSDave Airlie int drm_mode_cursor_ioctl(struct drm_device *dev, 30394c813d4dSDave Airlie void *data, struct drm_file *file_priv) 30404c813d4dSDave Airlie { 30414c813d4dSDave Airlie struct drm_mode_cursor *req = data; 30424c813d4dSDave Airlie struct drm_mode_cursor2 new_req; 30434c813d4dSDave Airlie 30444c813d4dSDave Airlie memcpy(&new_req, req, sizeof(struct drm_mode_cursor)); 30454c813d4dSDave Airlie new_req.hot_x = new_req.hot_y = 0; 30464c813d4dSDave Airlie 30474c813d4dSDave Airlie return drm_mode_cursor_common(dev, &new_req, file_priv); 30484c813d4dSDave Airlie } 30494c813d4dSDave Airlie 3050c8e32cc1SDaniel Vetter /** 3051c8e32cc1SDaniel Vetter * drm_mode_cursor2_ioctl - set CRTC's cursor configuration 3052c8e32cc1SDaniel Vetter * @dev: drm device for the ioctl 3053c8e32cc1SDaniel Vetter * @data: data pointer for the ioctl 3054c8e32cc1SDaniel Vetter * @file_priv: drm file for the ioctl call 3055c8e32cc1SDaniel Vetter * 3056c8e32cc1SDaniel Vetter * Set the cursor configuration based on user request. This implements the 2nd 3057c8e32cc1SDaniel Vetter * version of the cursor ioctl, which allows userspace to additionally specify 3058c8e32cc1SDaniel Vetter * the hotspot of the pointer. 3059c8e32cc1SDaniel Vetter * 3060c8e32cc1SDaniel Vetter * Called by the user via ioctl. 3061c8e32cc1SDaniel Vetter * 3062c8e32cc1SDaniel Vetter * Returns: 30631a498633SDaniel Vetter * Zero on success, negative errno on failure. 3064c8e32cc1SDaniel Vetter */ 30654c813d4dSDave Airlie int drm_mode_cursor2_ioctl(struct drm_device *dev, 30664c813d4dSDave Airlie void *data, struct drm_file *file_priv) 30674c813d4dSDave Airlie { 30684c813d4dSDave Airlie struct drm_mode_cursor2 *req = data; 30694dfd909fSThierry Reding 30704c813d4dSDave Airlie return drm_mode_cursor_common(dev, req, file_priv); 3071f453ba04SDave Airlie } 3072f453ba04SDave Airlie 3073c8e32cc1SDaniel Vetter /** 3074c8e32cc1SDaniel Vetter * drm_mode_legacy_fb_format - compute drm fourcc code from legacy description 3075c8e32cc1SDaniel Vetter * @bpp: bits per pixels 3076c8e32cc1SDaniel Vetter * @depth: bit depth per pixel 3077c8e32cc1SDaniel Vetter * 3078c8e32cc1SDaniel Vetter * Computes a drm fourcc pixel format code for the given @bpp/@depth values. 3079c8e32cc1SDaniel Vetter * Useful in fbdev emulation code, since that deals in those values. 3080c8e32cc1SDaniel Vetter */ 3081308e5bcbSJesse Barnes uint32_t drm_mode_legacy_fb_format(uint32_t bpp, uint32_t depth) 3082308e5bcbSJesse Barnes { 3083308e5bcbSJesse Barnes uint32_t fmt; 3084308e5bcbSJesse Barnes 3085308e5bcbSJesse Barnes switch (bpp) { 3086308e5bcbSJesse Barnes case 8: 3087d84f031bSVille Syrjälä fmt = DRM_FORMAT_C8; 3088308e5bcbSJesse Barnes break; 3089308e5bcbSJesse Barnes case 16: 3090308e5bcbSJesse Barnes if (depth == 15) 309104b3924dSVille Syrjälä fmt = DRM_FORMAT_XRGB1555; 3092308e5bcbSJesse Barnes else 309304b3924dSVille Syrjälä fmt = DRM_FORMAT_RGB565; 3094308e5bcbSJesse Barnes break; 3095308e5bcbSJesse Barnes case 24: 309604b3924dSVille Syrjälä fmt = DRM_FORMAT_RGB888; 3097308e5bcbSJesse Barnes break; 3098308e5bcbSJesse Barnes case 32: 3099308e5bcbSJesse Barnes if (depth == 24) 310004b3924dSVille Syrjälä fmt = DRM_FORMAT_XRGB8888; 3101308e5bcbSJesse Barnes else if (depth == 30) 310204b3924dSVille Syrjälä fmt = DRM_FORMAT_XRGB2101010; 3103308e5bcbSJesse Barnes else 310404b3924dSVille Syrjälä fmt = DRM_FORMAT_ARGB8888; 3105308e5bcbSJesse Barnes break; 3106308e5bcbSJesse Barnes default: 310704b3924dSVille Syrjälä DRM_ERROR("bad bpp, assuming x8r8g8b8 pixel format\n"); 310804b3924dSVille Syrjälä fmt = DRM_FORMAT_XRGB8888; 3109308e5bcbSJesse Barnes break; 3110308e5bcbSJesse Barnes } 3111308e5bcbSJesse Barnes 3112308e5bcbSJesse Barnes return fmt; 3113308e5bcbSJesse Barnes } 3114308e5bcbSJesse Barnes EXPORT_SYMBOL(drm_mode_legacy_fb_format); 3115308e5bcbSJesse Barnes 3116f453ba04SDave Airlie /** 3117f453ba04SDave Airlie * drm_mode_addfb - add an FB to the graphics configuration 3118065a50edSDaniel Vetter * @dev: drm device for the ioctl 3119065a50edSDaniel Vetter * @data: data pointer for the ioctl 3120065a50edSDaniel Vetter * @file_priv: drm file for the ioctl call 3121f453ba04SDave Airlie * 3122c8e32cc1SDaniel Vetter * Add a new FB to the specified CRTC, given a user request. This is the 3123209f5527SChuck Ebbert * original addfb ioctl which only supported RGB formats. 3124f453ba04SDave Airlie * 3125f453ba04SDave Airlie * Called by the user via ioctl. 3126f453ba04SDave Airlie * 3127c8e32cc1SDaniel Vetter * Returns: 31281a498633SDaniel Vetter * Zero on success, negative errno on failure. 3129f453ba04SDave Airlie */ 3130f453ba04SDave Airlie int drm_mode_addfb(struct drm_device *dev, 3131f453ba04SDave Airlie void *data, struct drm_file *file_priv) 3132f453ba04SDave Airlie { 3133308e5bcbSJesse Barnes struct drm_mode_fb_cmd *or = data; 3134308e5bcbSJesse Barnes struct drm_mode_fb_cmd2 r = {}; 3135228f2cb3SChuck Ebbert int ret; 3136308e5bcbSJesse Barnes 3137228f2cb3SChuck Ebbert /* convert to new format and call new ioctl */ 3138308e5bcbSJesse Barnes r.fb_id = or->fb_id; 3139308e5bcbSJesse Barnes r.width = or->width; 3140308e5bcbSJesse Barnes r.height = or->height; 3141308e5bcbSJesse Barnes r.pitches[0] = or->pitch; 3142308e5bcbSJesse Barnes r.pixel_format = drm_mode_legacy_fb_format(or->bpp, or->depth); 3143308e5bcbSJesse Barnes r.handles[0] = or->handle; 3144308e5bcbSJesse Barnes 3145228f2cb3SChuck Ebbert ret = drm_mode_addfb2(dev, &r, file_priv); 3146228f2cb3SChuck Ebbert if (ret) 3147228f2cb3SChuck Ebbert return ret; 3148308e5bcbSJesse Barnes 3149228f2cb3SChuck Ebbert or->fb_id = r.fb_id; 31504b096ac1SDaniel Vetter 3151baf698b0SDaniel Vetter return 0; 3152308e5bcbSJesse Barnes } 3153308e5bcbSJesse Barnes 3154cff91b62SVille Syrjälä static int format_check(const struct drm_mode_fb_cmd2 *r) 3155935b5977SVille Syrjälä { 3156935b5977SVille Syrjälä uint32_t format = r->pixel_format & ~DRM_FORMAT_BIG_ENDIAN; 3157935b5977SVille Syrjälä 3158935b5977SVille Syrjälä switch (format) { 3159935b5977SVille Syrjälä case DRM_FORMAT_C8: 3160935b5977SVille Syrjälä case DRM_FORMAT_RGB332: 3161935b5977SVille Syrjälä case DRM_FORMAT_BGR233: 3162935b5977SVille Syrjälä case DRM_FORMAT_XRGB4444: 3163935b5977SVille Syrjälä case DRM_FORMAT_XBGR4444: 3164935b5977SVille Syrjälä case DRM_FORMAT_RGBX4444: 3165935b5977SVille Syrjälä case DRM_FORMAT_BGRX4444: 3166935b5977SVille Syrjälä case DRM_FORMAT_ARGB4444: 3167935b5977SVille Syrjälä case DRM_FORMAT_ABGR4444: 3168935b5977SVille Syrjälä case DRM_FORMAT_RGBA4444: 3169935b5977SVille Syrjälä case DRM_FORMAT_BGRA4444: 3170935b5977SVille Syrjälä case DRM_FORMAT_XRGB1555: 3171935b5977SVille Syrjälä case DRM_FORMAT_XBGR1555: 3172935b5977SVille Syrjälä case DRM_FORMAT_RGBX5551: 3173935b5977SVille Syrjälä case DRM_FORMAT_BGRX5551: 3174935b5977SVille Syrjälä case DRM_FORMAT_ARGB1555: 3175935b5977SVille Syrjälä case DRM_FORMAT_ABGR1555: 3176935b5977SVille Syrjälä case DRM_FORMAT_RGBA5551: 3177935b5977SVille Syrjälä case DRM_FORMAT_BGRA5551: 3178935b5977SVille Syrjälä case DRM_FORMAT_RGB565: 3179935b5977SVille Syrjälä case DRM_FORMAT_BGR565: 3180935b5977SVille Syrjälä case DRM_FORMAT_RGB888: 3181935b5977SVille Syrjälä case DRM_FORMAT_BGR888: 3182935b5977SVille Syrjälä case DRM_FORMAT_XRGB8888: 3183935b5977SVille Syrjälä case DRM_FORMAT_XBGR8888: 3184935b5977SVille Syrjälä case DRM_FORMAT_RGBX8888: 3185935b5977SVille Syrjälä case DRM_FORMAT_BGRX8888: 3186935b5977SVille Syrjälä case DRM_FORMAT_ARGB8888: 3187935b5977SVille Syrjälä case DRM_FORMAT_ABGR8888: 3188935b5977SVille Syrjälä case DRM_FORMAT_RGBA8888: 3189935b5977SVille Syrjälä case DRM_FORMAT_BGRA8888: 3190935b5977SVille Syrjälä case DRM_FORMAT_XRGB2101010: 3191935b5977SVille Syrjälä case DRM_FORMAT_XBGR2101010: 3192935b5977SVille Syrjälä case DRM_FORMAT_RGBX1010102: 3193935b5977SVille Syrjälä case DRM_FORMAT_BGRX1010102: 3194935b5977SVille Syrjälä case DRM_FORMAT_ARGB2101010: 3195935b5977SVille Syrjälä case DRM_FORMAT_ABGR2101010: 3196935b5977SVille Syrjälä case DRM_FORMAT_RGBA1010102: 3197935b5977SVille Syrjälä case DRM_FORMAT_BGRA1010102: 3198935b5977SVille Syrjälä case DRM_FORMAT_YUYV: 3199935b5977SVille Syrjälä case DRM_FORMAT_YVYU: 3200935b5977SVille Syrjälä case DRM_FORMAT_UYVY: 3201935b5977SVille Syrjälä case DRM_FORMAT_VYUY: 3202935b5977SVille Syrjälä case DRM_FORMAT_AYUV: 3203935b5977SVille Syrjälä case DRM_FORMAT_NV12: 3204935b5977SVille Syrjälä case DRM_FORMAT_NV21: 3205935b5977SVille Syrjälä case DRM_FORMAT_NV16: 3206935b5977SVille Syrjälä case DRM_FORMAT_NV61: 3207ba623f6aSLaurent Pinchart case DRM_FORMAT_NV24: 3208ba623f6aSLaurent Pinchart case DRM_FORMAT_NV42: 3209935b5977SVille Syrjälä case DRM_FORMAT_YUV410: 3210935b5977SVille Syrjälä case DRM_FORMAT_YVU410: 3211935b5977SVille Syrjälä case DRM_FORMAT_YUV411: 3212935b5977SVille Syrjälä case DRM_FORMAT_YVU411: 3213935b5977SVille Syrjälä case DRM_FORMAT_YUV420: 3214935b5977SVille Syrjälä case DRM_FORMAT_YVU420: 3215935b5977SVille Syrjälä case DRM_FORMAT_YUV422: 3216935b5977SVille Syrjälä case DRM_FORMAT_YVU422: 3217935b5977SVille Syrjälä case DRM_FORMAT_YUV444: 3218935b5977SVille Syrjälä case DRM_FORMAT_YVU444: 3219935b5977SVille Syrjälä return 0; 3220935b5977SVille Syrjälä default: 322123c453a4SVille Syrjälä DRM_DEBUG_KMS("invalid pixel format %s\n", 322223c453a4SVille Syrjälä drm_get_format_name(r->pixel_format)); 3223935b5977SVille Syrjälä return -EINVAL; 3224935b5977SVille Syrjälä } 3225935b5977SVille Syrjälä } 3226935b5977SVille Syrjälä 3227cff91b62SVille Syrjälä static int framebuffer_check(const struct drm_mode_fb_cmd2 *r) 3228d1b45d5fSVille Syrjälä { 3229d1b45d5fSVille Syrjälä int ret, hsub, vsub, num_planes, i; 3230d1b45d5fSVille Syrjälä 3231d1b45d5fSVille Syrjälä ret = format_check(r); 3232d1b45d5fSVille Syrjälä if (ret) { 32336ba6d03eSVille Syrjälä DRM_DEBUG_KMS("bad framebuffer format %s\n", 32346ba6d03eSVille Syrjälä drm_get_format_name(r->pixel_format)); 3235d1b45d5fSVille Syrjälä return ret; 3236d1b45d5fSVille Syrjälä } 3237d1b45d5fSVille Syrjälä 3238d1b45d5fSVille Syrjälä hsub = drm_format_horz_chroma_subsampling(r->pixel_format); 3239d1b45d5fSVille Syrjälä vsub = drm_format_vert_chroma_subsampling(r->pixel_format); 3240d1b45d5fSVille Syrjälä num_planes = drm_format_num_planes(r->pixel_format); 3241d1b45d5fSVille Syrjälä 3242d1b45d5fSVille Syrjälä if (r->width == 0 || r->width % hsub) { 3243209f5527SChuck Ebbert DRM_DEBUG_KMS("bad framebuffer width %u\n", r->width); 3244d1b45d5fSVille Syrjälä return -EINVAL; 3245d1b45d5fSVille Syrjälä } 3246d1b45d5fSVille Syrjälä 3247d1b45d5fSVille Syrjälä if (r->height == 0 || r->height % vsub) { 32481aa1b11cSDave Airlie DRM_DEBUG_KMS("bad framebuffer height %u\n", r->height); 3249d1b45d5fSVille Syrjälä return -EINVAL; 3250d1b45d5fSVille Syrjälä } 3251d1b45d5fSVille Syrjälä 3252d1b45d5fSVille Syrjälä for (i = 0; i < num_planes; i++) { 3253d1b45d5fSVille Syrjälä unsigned int width = r->width / (i != 0 ? hsub : 1); 3254b180b5d1SVille Syrjälä unsigned int height = r->height / (i != 0 ? vsub : 1); 3255b180b5d1SVille Syrjälä unsigned int cpp = drm_format_plane_cpp(r->pixel_format, i); 3256d1b45d5fSVille Syrjälä 3257d1b45d5fSVille Syrjälä if (!r->handles[i]) { 32581aa1b11cSDave Airlie DRM_DEBUG_KMS("no buffer object handle for plane %d\n", i); 3259d1b45d5fSVille Syrjälä return -EINVAL; 3260d1b45d5fSVille Syrjälä } 3261d1b45d5fSVille Syrjälä 3262b180b5d1SVille Syrjälä if ((uint64_t) width * cpp > UINT_MAX) 3263b180b5d1SVille Syrjälä return -ERANGE; 3264b180b5d1SVille Syrjälä 3265b180b5d1SVille Syrjälä if ((uint64_t) height * r->pitches[i] + r->offsets[i] > UINT_MAX) 3266b180b5d1SVille Syrjälä return -ERANGE; 3267b180b5d1SVille Syrjälä 3268b180b5d1SVille Syrjälä if (r->pitches[i] < width * cpp) { 32691aa1b11cSDave Airlie DRM_DEBUG_KMS("bad pitch %u for plane %d\n", r->pitches[i], i); 3270d1b45d5fSVille Syrjälä return -EINVAL; 3271d1b45d5fSVille Syrjälä } 3272e3eb3250SRob Clark 3273e3eb3250SRob Clark if (r->modifier[i] && !(r->flags & DRM_MODE_FB_MODIFIERS)) { 3274e3eb3250SRob Clark DRM_DEBUG_KMS("bad fb modifier %llu for plane %d\n", 3275e3eb3250SRob Clark r->modifier[i], i); 3276e3eb3250SRob Clark return -EINVAL; 3277e3eb3250SRob Clark } 3278570655b0SRob Clark 3279570655b0SRob Clark /* modifier specific checks: */ 3280570655b0SRob Clark switch (r->modifier[i]) { 3281570655b0SRob Clark case DRM_FORMAT_MOD_SAMSUNG_64_32_TILE: 3282570655b0SRob Clark /* NOTE: the pitch restriction may be lifted later if it turns 3283570655b0SRob Clark * out that no hw has this restriction: 3284570655b0SRob Clark */ 3285570655b0SRob Clark if (r->pixel_format != DRM_FORMAT_NV12 || 3286570655b0SRob Clark width % 128 || height % 32 || 3287570655b0SRob Clark r->pitches[i] % 128) { 3288570655b0SRob Clark DRM_DEBUG_KMS("bad modifier data for plane %d\n", i); 3289570655b0SRob Clark return -EINVAL; 3290570655b0SRob Clark } 3291570655b0SRob Clark break; 3292570655b0SRob Clark 3293570655b0SRob Clark default: 3294570655b0SRob Clark break; 3295570655b0SRob Clark } 3296d1b45d5fSVille Syrjälä } 3297d1b45d5fSVille Syrjälä 3298bbe16a40SDaniel Vetter for (i = num_planes; i < 4; i++) { 3299bbe16a40SDaniel Vetter if (r->modifier[i]) { 3300bbe16a40SDaniel Vetter DRM_DEBUG_KMS("non-zero modifier for unused plane %d\n", i); 3301bbe16a40SDaniel Vetter return -EINVAL; 3302bbe16a40SDaniel Vetter } 3303bbe16a40SDaniel Vetter 3304bbe16a40SDaniel Vetter /* Pre-FB_MODIFIERS userspace didn't clear the structs properly. */ 3305bbe16a40SDaniel Vetter if (!(r->flags & DRM_MODE_FB_MODIFIERS)) 3306bbe16a40SDaniel Vetter continue; 3307bbe16a40SDaniel Vetter 3308bbe16a40SDaniel Vetter if (r->handles[i]) { 3309bbe16a40SDaniel Vetter DRM_DEBUG_KMS("buffer object handle for unused plane %d\n", i); 3310bbe16a40SDaniel Vetter return -EINVAL; 3311bbe16a40SDaniel Vetter } 3312bbe16a40SDaniel Vetter 3313bbe16a40SDaniel Vetter if (r->pitches[i]) { 3314bbe16a40SDaniel Vetter DRM_DEBUG_KMS("non-zero pitch for unused plane %d\n", i); 3315bbe16a40SDaniel Vetter return -EINVAL; 3316bbe16a40SDaniel Vetter } 3317bbe16a40SDaniel Vetter 3318bbe16a40SDaniel Vetter if (r->offsets[i]) { 3319bbe16a40SDaniel Vetter DRM_DEBUG_KMS("non-zero offset for unused plane %d\n", i); 3320bbe16a40SDaniel Vetter return -EINVAL; 3321bbe16a40SDaniel Vetter } 3322bbe16a40SDaniel Vetter } 3323bbe16a40SDaniel Vetter 3324d1b45d5fSVille Syrjälä return 0; 3325d1b45d5fSVille Syrjälä } 3326d1b45d5fSVille Syrjälä 33279a6f5130SChris Wilson static struct drm_framebuffer * 33289a6f5130SChris Wilson internal_framebuffer_create(struct drm_device *dev, 33291eb83451SVille Syrjälä const struct drm_mode_fb_cmd2 *r, 3330c394c2b0SMatt Roper struct drm_file *file_priv) 3331c394c2b0SMatt Roper { 3332c394c2b0SMatt Roper struct drm_mode_config *config = &dev->mode_config; 3333c394c2b0SMatt Roper struct drm_framebuffer *fb; 3334c394c2b0SMatt Roper int ret; 3335c394c2b0SMatt Roper 3336e3eb3250SRob Clark if (r->flags & ~(DRM_MODE_FB_INTERLACED | DRM_MODE_FB_MODIFIERS)) { 3337c394c2b0SMatt Roper DRM_DEBUG_KMS("bad framebuffer flags 0x%08x\n", r->flags); 3338c394c2b0SMatt Roper return ERR_PTR(-EINVAL); 3339c394c2b0SMatt Roper } 3340c394c2b0SMatt Roper 3341c394c2b0SMatt Roper if ((config->min_width > r->width) || (r->width > config->max_width)) { 3342c394c2b0SMatt Roper DRM_DEBUG_KMS("bad framebuffer width %d, should be >= %d && <= %d\n", 3343c394c2b0SMatt Roper r->width, config->min_width, config->max_width); 3344c394c2b0SMatt Roper return ERR_PTR(-EINVAL); 3345c394c2b0SMatt Roper } 3346c394c2b0SMatt Roper if ((config->min_height > r->height) || (r->height > config->max_height)) { 3347c394c2b0SMatt Roper DRM_DEBUG_KMS("bad framebuffer height %d, should be >= %d && <= %d\n", 3348c394c2b0SMatt Roper r->height, config->min_height, config->max_height); 3349c394c2b0SMatt Roper return ERR_PTR(-EINVAL); 3350c394c2b0SMatt Roper } 3351c394c2b0SMatt Roper 3352e3eb3250SRob Clark if (r->flags & DRM_MODE_FB_MODIFIERS && 3353e3eb3250SRob Clark !dev->mode_config.allow_fb_modifiers) { 3354e3eb3250SRob Clark DRM_DEBUG_KMS("driver does not support fb modifiers\n"); 3355e3eb3250SRob Clark return ERR_PTR(-EINVAL); 3356e3eb3250SRob Clark } 3357e3eb3250SRob Clark 3358c394c2b0SMatt Roper ret = framebuffer_check(r); 3359c394c2b0SMatt Roper if (ret) 3360c394c2b0SMatt Roper return ERR_PTR(ret); 3361c394c2b0SMatt Roper 3362c394c2b0SMatt Roper fb = dev->mode_config.funcs->fb_create(dev, file_priv, r); 3363c394c2b0SMatt Roper if (IS_ERR(fb)) { 3364c394c2b0SMatt Roper DRM_DEBUG_KMS("could not create framebuffer\n"); 3365c394c2b0SMatt Roper return fb; 3366c394c2b0SMatt Roper } 3367c394c2b0SMatt Roper 3368c394c2b0SMatt Roper return fb; 3369c394c2b0SMatt Roper } 3370c394c2b0SMatt Roper 3371308e5bcbSJesse Barnes /** 3372308e5bcbSJesse Barnes * drm_mode_addfb2 - add an FB to the graphics configuration 3373065a50edSDaniel Vetter * @dev: drm device for the ioctl 3374065a50edSDaniel Vetter * @data: data pointer for the ioctl 3375065a50edSDaniel Vetter * @file_priv: drm file for the ioctl call 3376308e5bcbSJesse Barnes * 3377c8e32cc1SDaniel Vetter * Add a new FB to the specified CRTC, given a user request with format. This is 3378c8e32cc1SDaniel Vetter * the 2nd version of the addfb ioctl, which supports multi-planar framebuffers 3379c8e32cc1SDaniel Vetter * and uses fourcc codes as pixel format specifiers. 3380308e5bcbSJesse Barnes * 3381308e5bcbSJesse Barnes * Called by the user via ioctl. 3382308e5bcbSJesse Barnes * 3383c8e32cc1SDaniel Vetter * Returns: 33841a498633SDaniel Vetter * Zero on success, negative errno on failure. 3385308e5bcbSJesse Barnes */ 3386308e5bcbSJesse Barnes int drm_mode_addfb2(struct drm_device *dev, 3387308e5bcbSJesse Barnes void *data, struct drm_file *file_priv) 3388308e5bcbSJesse Barnes { 33899a6f5130SChris Wilson struct drm_mode_fb_cmd2 *r = data; 3390f453ba04SDave Airlie struct drm_framebuffer *fb; 3391f453ba04SDave Airlie 3392fb3b06c8SDave Airlie if (!drm_core_check_feature(dev, DRIVER_MODESET)) 3393fb3b06c8SDave Airlie return -EINVAL; 3394fb3b06c8SDave Airlie 33959a6f5130SChris Wilson fb = internal_framebuffer_create(dev, r, file_priv); 3396c394c2b0SMatt Roper if (IS_ERR(fb)) 33974b096ac1SDaniel Vetter return PTR_ERR(fb); 3398f453ba04SDave Airlie 33999a6f5130SChris Wilson DRM_DEBUG_KMS("[FB:%d]\n", fb->base.id); 34009a6f5130SChris Wilson r->fb_id = fb->base.id; 3401c7e1c59aSDave Airlie 3402c7e1c59aSDave Airlie /* Transfer ownership to the filp for reaping on close */ 3403c7e1c59aSDave Airlie mutex_lock(&file_priv->fbs_lock); 34049a6f5130SChris Wilson list_add(&fb->filp_head, &file_priv->fbs); 34059a6f5130SChris Wilson mutex_unlock(&file_priv->fbs_lock); 34069a6f5130SChris Wilson 3407c394c2b0SMatt Roper return 0; 3408f453ba04SDave Airlie } 3409f453ba04SDave Airlie 3410f2d580b9SMaarten Lankhorst struct drm_mode_rmfb_work { 3411f2d580b9SMaarten Lankhorst struct work_struct work; 3412f2d580b9SMaarten Lankhorst struct list_head fbs; 3413f2d580b9SMaarten Lankhorst }; 3414f2d580b9SMaarten Lankhorst 3415f2d580b9SMaarten Lankhorst static void drm_mode_rmfb_work_fn(struct work_struct *w) 3416f2d580b9SMaarten Lankhorst { 3417f2d580b9SMaarten Lankhorst struct drm_mode_rmfb_work *arg = container_of(w, typeof(*arg), work); 3418f2d580b9SMaarten Lankhorst 3419f2d580b9SMaarten Lankhorst while (!list_empty(&arg->fbs)) { 3420f2d580b9SMaarten Lankhorst struct drm_framebuffer *fb = 3421f2d580b9SMaarten Lankhorst list_first_entry(&arg->fbs, typeof(*fb), filp_head); 3422f2d580b9SMaarten Lankhorst 3423f2d580b9SMaarten Lankhorst list_del_init(&fb->filp_head); 3424f2d580b9SMaarten Lankhorst drm_framebuffer_remove(fb); 3425f2d580b9SMaarten Lankhorst } 3426f2d580b9SMaarten Lankhorst } 3427f2d580b9SMaarten Lankhorst 3428f453ba04SDave Airlie /** 3429f453ba04SDave Airlie * drm_mode_rmfb - remove an FB from the configuration 3430065a50edSDaniel Vetter * @dev: drm device for the ioctl 3431065a50edSDaniel Vetter * @data: data pointer for the ioctl 3432065a50edSDaniel Vetter * @file_priv: drm file for the ioctl call 3433f453ba04SDave Airlie * 3434f453ba04SDave Airlie * Remove the FB specified by the user. 3435f453ba04SDave Airlie * 3436f453ba04SDave Airlie * Called by the user via ioctl. 3437f453ba04SDave Airlie * 3438c8e32cc1SDaniel Vetter * Returns: 34391a498633SDaniel Vetter * Zero on success, negative errno on failure. 3440f453ba04SDave Airlie */ 3441f453ba04SDave Airlie int drm_mode_rmfb(struct drm_device *dev, 3442f453ba04SDave Airlie void *data, struct drm_file *file_priv) 3443f453ba04SDave Airlie { 3444f453ba04SDave Airlie struct drm_framebuffer *fb = NULL; 3445f453ba04SDave Airlie struct drm_framebuffer *fbl = NULL; 3446f453ba04SDave Airlie uint32_t *id = data; 3447f453ba04SDave Airlie int found = 0; 3448f453ba04SDave Airlie 3449fb3b06c8SDave Airlie if (!drm_core_check_feature(dev, DRIVER_MODESET)) 3450fb3b06c8SDave Airlie return -EINVAL; 3451fb3b06c8SDave Airlie 345272fe90b8SDave Airlie fb = drm_framebuffer_lookup(dev, *id); 345372fe90b8SDave Airlie if (!fb) 345472fe90b8SDave Airlie return -ENOENT; 345572fe90b8SDave Airlie 34564b096ac1SDaniel Vetter mutex_lock(&file_priv->fbs_lock); 3457f453ba04SDave Airlie list_for_each_entry(fbl, &file_priv->fbs, filp_head) 3458f453ba04SDave Airlie if (fb == fbl) 3459f453ba04SDave Airlie found = 1; 346072fe90b8SDave Airlie if (!found) { 346172fe90b8SDave Airlie mutex_unlock(&file_priv->fbs_lock); 346272fe90b8SDave Airlie goto fail_unref; 346372fe90b8SDave Airlie } 34642b677e8cSDaniel Vetter 34654b096ac1SDaniel Vetter list_del_init(&fb->filp_head); 34664b096ac1SDaniel Vetter mutex_unlock(&file_priv->fbs_lock); 3467f453ba04SDave Airlie 3468f2d580b9SMaarten Lankhorst /* drop the reference we picked up in framebuffer lookup */ 346972fe90b8SDave Airlie drm_framebuffer_unreference(fb); 347072fe90b8SDave Airlie 3471f2d580b9SMaarten Lankhorst /* 3472f2d580b9SMaarten Lankhorst * we now own the reference that was stored in the fbs list 3473f2d580b9SMaarten Lankhorst * 3474f2d580b9SMaarten Lankhorst * drm_framebuffer_remove may fail with -EINTR on pending signals, 3475f2d580b9SMaarten Lankhorst * so run this in a separate stack as there's no way to correctly 3476f2d580b9SMaarten Lankhorst * handle this after the fb is already removed from the lookup table. 3477f2d580b9SMaarten Lankhorst */ 3478f2d580b9SMaarten Lankhorst if (drm_framebuffer_read_refcount(fb) > 1) { 3479f2d580b9SMaarten Lankhorst struct drm_mode_rmfb_work arg; 3480f2d580b9SMaarten Lankhorst 3481f2d580b9SMaarten Lankhorst INIT_WORK_ONSTACK(&arg.work, drm_mode_rmfb_work_fn); 3482f2d580b9SMaarten Lankhorst INIT_LIST_HEAD(&arg.fbs); 3483f2d580b9SMaarten Lankhorst list_add_tail(&fb->filp_head, &arg.fbs); 3484f2d580b9SMaarten Lankhorst 3485f2d580b9SMaarten Lankhorst schedule_work(&arg.work); 3486f2d580b9SMaarten Lankhorst flush_work(&arg.work); 3487f2d580b9SMaarten Lankhorst destroy_work_on_stack(&arg.work); 3488f2d580b9SMaarten Lankhorst } else 348913803132SMaarten Lankhorst drm_framebuffer_unreference(fb); 34904b096ac1SDaniel Vetter 34912b677e8cSDaniel Vetter return 0; 34922b677e8cSDaniel Vetter 349372fe90b8SDave Airlie fail_unref: 349472fe90b8SDave Airlie drm_framebuffer_unreference(fb); 349537c4e705SVille Syrjälä return -ENOENT; 3496f453ba04SDave Airlie } 3497f453ba04SDave Airlie 3498f453ba04SDave Airlie /** 3499f453ba04SDave Airlie * drm_mode_getfb - get FB info 3500065a50edSDaniel Vetter * @dev: drm device for the ioctl 3501065a50edSDaniel Vetter * @data: data pointer for the ioctl 3502065a50edSDaniel Vetter * @file_priv: drm file for the ioctl call 3503f453ba04SDave Airlie * 3504f453ba04SDave Airlie * Lookup the FB given its ID and return info about it. 3505f453ba04SDave Airlie * 3506f453ba04SDave Airlie * Called by the user via ioctl. 3507f453ba04SDave Airlie * 3508c8e32cc1SDaniel Vetter * Returns: 35091a498633SDaniel Vetter * Zero on success, negative errno on failure. 3510f453ba04SDave Airlie */ 3511f453ba04SDave Airlie int drm_mode_getfb(struct drm_device *dev, 3512f453ba04SDave Airlie void *data, struct drm_file *file_priv) 3513f453ba04SDave Airlie { 3514f453ba04SDave Airlie struct drm_mode_fb_cmd *r = data; 3515f453ba04SDave Airlie struct drm_framebuffer *fb; 351658c0dca1SDaniel Vetter int ret; 3517f453ba04SDave Airlie 3518fb3b06c8SDave Airlie if (!drm_core_check_feature(dev, DRIVER_MODESET)) 3519fb3b06c8SDave Airlie return -EINVAL; 3520fb3b06c8SDave Airlie 3521786b99edSDaniel Vetter fb = drm_framebuffer_lookup(dev, r->fb_id); 352258c0dca1SDaniel Vetter if (!fb) 352337c4e705SVille Syrjälä return -ENOENT; 3524f453ba04SDave Airlie 3525f453ba04SDave Airlie r->height = fb->height; 3526f453ba04SDave Airlie r->width = fb->width; 3527f453ba04SDave Airlie r->depth = fb->depth; 3528f453ba04SDave Airlie r->bpp = fb->bits_per_pixel; 352901f2c773SVille Syrjälä r->pitch = fb->pitches[0]; 3530101b96f3SDavid Herrmann if (fb->funcs->create_handle) { 353109f308f7SThomas Hellstrom if (file_priv->is_master || capable(CAP_SYS_ADMIN) || 353243683057SThomas Hellstrom drm_is_control_client(file_priv)) { 3533101b96f3SDavid Herrmann ret = fb->funcs->create_handle(fb, file_priv, 3534101b96f3SDavid Herrmann &r->handle); 3535101b96f3SDavid Herrmann } else { 3536101b96f3SDavid Herrmann /* GET_FB() is an unprivileged ioctl so we must not 3537101b96f3SDavid Herrmann * return a buffer-handle to non-master processes! For 3538101b96f3SDavid Herrmann * backwards-compatibility reasons, we cannot make 3539101b96f3SDavid Herrmann * GET_FB() privileged, so just return an invalid handle 3540101b96f3SDavid Herrmann * for non-masters. */ 3541101b96f3SDavid Herrmann r->handle = 0; 3542101b96f3SDavid Herrmann ret = 0; 3543101b96f3SDavid Herrmann } 3544101b96f3SDavid Herrmann } else { 3545af26ef3bSDaniel Vetter ret = -ENODEV; 3546101b96f3SDavid Herrmann } 3547f453ba04SDave Airlie 354858c0dca1SDaniel Vetter drm_framebuffer_unreference(fb); 354958c0dca1SDaniel Vetter 3550f453ba04SDave Airlie return ret; 3551f453ba04SDave Airlie } 3552f453ba04SDave Airlie 3553c8e32cc1SDaniel Vetter /** 3554c8e32cc1SDaniel Vetter * drm_mode_dirtyfb_ioctl - flush frontbuffer rendering on an FB 3555c8e32cc1SDaniel Vetter * @dev: drm device for the ioctl 3556c8e32cc1SDaniel Vetter * @data: data pointer for the ioctl 3557c8e32cc1SDaniel Vetter * @file_priv: drm file for the ioctl call 3558c8e32cc1SDaniel Vetter * 3559c8e32cc1SDaniel Vetter * Lookup the FB and flush out the damaged area supplied by userspace as a clip 3560c8e32cc1SDaniel Vetter * rectangle list. Generic userspace which does frontbuffer rendering must call 3561c8e32cc1SDaniel Vetter * this ioctl to flush out the changes on manual-update display outputs, e.g. 3562c8e32cc1SDaniel Vetter * usb display-link, mipi manual update panels or edp panel self refresh modes. 3563c8e32cc1SDaniel Vetter * 3564c8e32cc1SDaniel Vetter * Modesetting drivers which always update the frontbuffer do not need to 3565c8e32cc1SDaniel Vetter * implement the corresponding ->dirty framebuffer callback. 3566c8e32cc1SDaniel Vetter * 3567c8e32cc1SDaniel Vetter * Called by the user via ioctl. 3568c8e32cc1SDaniel Vetter * 3569c8e32cc1SDaniel Vetter * Returns: 35701a498633SDaniel Vetter * Zero on success, negative errno on failure. 3571c8e32cc1SDaniel Vetter */ 3572884840aaSJakob Bornecrantz int drm_mode_dirtyfb_ioctl(struct drm_device *dev, 3573884840aaSJakob Bornecrantz void *data, struct drm_file *file_priv) 3574884840aaSJakob Bornecrantz { 3575884840aaSJakob Bornecrantz struct drm_clip_rect __user *clips_ptr; 3576884840aaSJakob Bornecrantz struct drm_clip_rect *clips = NULL; 3577884840aaSJakob Bornecrantz struct drm_mode_fb_dirty_cmd *r = data; 3578884840aaSJakob Bornecrantz struct drm_framebuffer *fb; 3579884840aaSJakob Bornecrantz unsigned flags; 3580884840aaSJakob Bornecrantz int num_clips; 35814a1b0714SLaurent Pinchart int ret; 3582884840aaSJakob Bornecrantz 3583fb3b06c8SDave Airlie if (!drm_core_check_feature(dev, DRIVER_MODESET)) 3584fb3b06c8SDave Airlie return -EINVAL; 3585fb3b06c8SDave Airlie 3586786b99edSDaniel Vetter fb = drm_framebuffer_lookup(dev, r->fb_id); 35874ccf097fSDaniel Vetter if (!fb) 358837c4e705SVille Syrjälä return -ENOENT; 3589884840aaSJakob Bornecrantz 3590884840aaSJakob Bornecrantz num_clips = r->num_clips; 359181f6c7f8SVille Syrjälä clips_ptr = (struct drm_clip_rect __user *)(unsigned long)r->clips_ptr; 3592884840aaSJakob Bornecrantz 3593884840aaSJakob Bornecrantz if (!num_clips != !clips_ptr) { 3594884840aaSJakob Bornecrantz ret = -EINVAL; 3595884840aaSJakob Bornecrantz goto out_err1; 3596884840aaSJakob Bornecrantz } 3597884840aaSJakob Bornecrantz 3598884840aaSJakob Bornecrantz flags = DRM_MODE_FB_DIRTY_FLAGS & r->flags; 3599884840aaSJakob Bornecrantz 3600884840aaSJakob Bornecrantz /* If userspace annotates copy, clips must come in pairs */ 3601884840aaSJakob Bornecrantz if (flags & DRM_MODE_FB_DIRTY_ANNOTATE_COPY && (num_clips % 2)) { 3602884840aaSJakob Bornecrantz ret = -EINVAL; 3603884840aaSJakob Bornecrantz goto out_err1; 3604884840aaSJakob Bornecrantz } 3605884840aaSJakob Bornecrantz 3606884840aaSJakob Bornecrantz if (num_clips && clips_ptr) { 3607a5cd3351SXi Wang if (num_clips < 0 || num_clips > DRM_MODE_FB_DIRTY_MAX_CLIPS) { 3608a5cd3351SXi Wang ret = -EINVAL; 3609a5cd3351SXi Wang goto out_err1; 3610a5cd3351SXi Wang } 3611bd3f0ff9SThierry Reding clips = kcalloc(num_clips, sizeof(*clips), GFP_KERNEL); 3612884840aaSJakob Bornecrantz if (!clips) { 3613884840aaSJakob Bornecrantz ret = -ENOMEM; 3614884840aaSJakob Bornecrantz goto out_err1; 3615884840aaSJakob Bornecrantz } 3616884840aaSJakob Bornecrantz 3617884840aaSJakob Bornecrantz ret = copy_from_user(clips, clips_ptr, 3618884840aaSJakob Bornecrantz num_clips * sizeof(*clips)); 3619e902a358SDan Carpenter if (ret) { 3620e902a358SDan Carpenter ret = -EFAULT; 3621884840aaSJakob Bornecrantz goto out_err2; 3622884840aaSJakob Bornecrantz } 3623e902a358SDan Carpenter } 3624884840aaSJakob Bornecrantz 3625884840aaSJakob Bornecrantz if (fb->funcs->dirty) { 362602b00162SThomas Hellstrom ret = fb->funcs->dirty(fb, file_priv, flags, r->color, 362702b00162SThomas Hellstrom clips, num_clips); 3628884840aaSJakob Bornecrantz } else { 3629884840aaSJakob Bornecrantz ret = -ENOSYS; 3630884840aaSJakob Bornecrantz } 3631884840aaSJakob Bornecrantz 3632884840aaSJakob Bornecrantz out_err2: 3633884840aaSJakob Bornecrantz kfree(clips); 3634884840aaSJakob Bornecrantz out_err1: 36354ccf097fSDaniel Vetter drm_framebuffer_unreference(fb); 36364ccf097fSDaniel Vetter 3637884840aaSJakob Bornecrantz return ret; 3638884840aaSJakob Bornecrantz } 3639884840aaSJakob Bornecrantz 3640f453ba04SDave Airlie /** 3641f453ba04SDave Airlie * drm_fb_release - remove and free the FBs on this file 3642065a50edSDaniel Vetter * @priv: drm file for the ioctl 3643f453ba04SDave Airlie * 3644f453ba04SDave Airlie * Destroy all the FBs associated with @filp. 3645f453ba04SDave Airlie * 3646f453ba04SDave Airlie * Called by the user via ioctl. 3647f453ba04SDave Airlie * 3648c8e32cc1SDaniel Vetter * Returns: 36491a498633SDaniel Vetter * Zero on success, negative errno on failure. 3650f453ba04SDave Airlie */ 3651ea39f835SKristian Høgsberg void drm_fb_release(struct drm_file *priv) 3652f453ba04SDave Airlie { 3653f453ba04SDave Airlie struct drm_framebuffer *fb, *tfb; 3654f2d580b9SMaarten Lankhorst struct drm_mode_rmfb_work arg; 3655f2d580b9SMaarten Lankhorst 3656f2d580b9SMaarten Lankhorst INIT_LIST_HEAD(&arg.fbs); 3657f453ba04SDave Airlie 36581b116297SDaniel Vetter /* 36591b116297SDaniel Vetter * When the file gets released that means no one else can access the fb 3660e2db726bSMartin Peres * list any more, so no need to grab fpriv->fbs_lock. And we need to 36611b116297SDaniel Vetter * avoid upsetting lockdep since the universal cursor code adds a 36621b116297SDaniel Vetter * framebuffer while holding mutex locks. 36631b116297SDaniel Vetter * 36641b116297SDaniel Vetter * Note that a real deadlock between fpriv->fbs_lock and the modeset 36651b116297SDaniel Vetter * locks is impossible here since no one else but this function can get 36661b116297SDaniel Vetter * at it any more. 36671b116297SDaniel Vetter */ 3668f453ba04SDave Airlie list_for_each_entry_safe(fb, tfb, &priv->fbs, filp_head) { 3669f2d580b9SMaarten Lankhorst if (drm_framebuffer_read_refcount(fb) > 1) { 3670f2d580b9SMaarten Lankhorst list_move_tail(&fb->filp_head, &arg.fbs); 3671f2d580b9SMaarten Lankhorst } else { 36724b096ac1SDaniel Vetter list_del_init(&fb->filp_head); 36732b677e8cSDaniel Vetter 367473f7570bSMaarten Lankhorst /* This drops the fpriv->fbs reference. */ 367513803132SMaarten Lankhorst drm_framebuffer_unreference(fb); 3676f453ba04SDave Airlie } 3677f453ba04SDave Airlie } 3678f453ba04SDave Airlie 3679f2d580b9SMaarten Lankhorst if (!list_empty(&arg.fbs)) { 3680f2d580b9SMaarten Lankhorst INIT_WORK_ONSTACK(&arg.work, drm_mode_rmfb_work_fn); 3681f2d580b9SMaarten Lankhorst 3682f2d580b9SMaarten Lankhorst schedule_work(&arg.work); 3683f2d580b9SMaarten Lankhorst flush_work(&arg.work); 3684f2d580b9SMaarten Lankhorst destroy_work_on_stack(&arg.work); 3685f2d580b9SMaarten Lankhorst } 3686f2d580b9SMaarten Lankhorst } 3687f2d580b9SMaarten Lankhorst 3688c8e32cc1SDaniel Vetter /** 3689c8e32cc1SDaniel Vetter * drm_property_create - create a new property type 3690c8e32cc1SDaniel Vetter * @dev: drm device 3691c8e32cc1SDaniel Vetter * @flags: flags specifying the property type 3692c8e32cc1SDaniel Vetter * @name: name of the property 3693c8e32cc1SDaniel Vetter * @num_values: number of pre-defined values 3694c8e32cc1SDaniel Vetter * 3695c8e32cc1SDaniel Vetter * This creates a new generic drm property which can then be attached to a drm 3696c8e32cc1SDaniel Vetter * object with drm_object_attach_property. The returned property object must be 3697c8e32cc1SDaniel Vetter * freed with drm_property_destroy. 3698c8e32cc1SDaniel Vetter * 36993b5b9932SDamien Lespiau * Note that the DRM core keeps a per-device list of properties and that, if 37003b5b9932SDamien Lespiau * drm_mode_config_cleanup() is called, it will destroy all properties created 37013b5b9932SDamien Lespiau * by the driver. 37023b5b9932SDamien Lespiau * 3703c8e32cc1SDaniel Vetter * Returns: 3704c8e32cc1SDaniel Vetter * A pointer to the newly created property on success, NULL on failure. 3705c8e32cc1SDaniel Vetter */ 3706f453ba04SDave Airlie struct drm_property *drm_property_create(struct drm_device *dev, int flags, 3707f453ba04SDave Airlie const char *name, int num_values) 3708f453ba04SDave Airlie { 3709f453ba04SDave Airlie struct drm_property *property = NULL; 37106bfc56aaSVille Syrjälä int ret; 3711f453ba04SDave Airlie 3712f453ba04SDave Airlie property = kzalloc(sizeof(struct drm_property), GFP_KERNEL); 3713f453ba04SDave Airlie if (!property) 3714f453ba04SDave Airlie return NULL; 3715f453ba04SDave Airlie 371698f75de4SRob Clark property->dev = dev; 371798f75de4SRob Clark 3718f453ba04SDave Airlie if (num_values) { 3719bd3f0ff9SThierry Reding property->values = kcalloc(num_values, sizeof(uint64_t), 3720bd3f0ff9SThierry Reding GFP_KERNEL); 3721f453ba04SDave Airlie if (!property->values) 3722f453ba04SDave Airlie goto fail; 3723f453ba04SDave Airlie } 3724f453ba04SDave Airlie 37256bfc56aaSVille Syrjälä ret = drm_mode_object_get(dev, &property->base, DRM_MODE_OBJECT_PROPERTY); 37266bfc56aaSVille Syrjälä if (ret) 37276bfc56aaSVille Syrjälä goto fail; 37286bfc56aaSVille Syrjälä 3729f453ba04SDave Airlie property->flags = flags; 3730f453ba04SDave Airlie property->num_values = num_values; 37313758b341SDaniel Vetter INIT_LIST_HEAD(&property->enum_list); 3732f453ba04SDave Airlie 3733471dd2efSVinson Lee if (name) { 3734f453ba04SDave Airlie strncpy(property->name, name, DRM_PROP_NAME_LEN); 3735471dd2efSVinson Lee property->name[DRM_PROP_NAME_LEN-1] = '\0'; 3736471dd2efSVinson Lee } 3737f453ba04SDave Airlie 3738f453ba04SDave Airlie list_add_tail(&property->head, &dev->mode_config.property_list); 37395ea22f24SRob Clark 37405ea22f24SRob Clark WARN_ON(!drm_property_type_valid(property)); 37415ea22f24SRob Clark 3742f453ba04SDave Airlie return property; 3743f453ba04SDave Airlie fail: 37446bfc56aaSVille Syrjälä kfree(property->values); 3745f453ba04SDave Airlie kfree(property); 3746f453ba04SDave Airlie return NULL; 3747f453ba04SDave Airlie } 3748f453ba04SDave Airlie EXPORT_SYMBOL(drm_property_create); 3749f453ba04SDave Airlie 3750c8e32cc1SDaniel Vetter /** 37512aa9d2bcSThierry Reding * drm_property_create_enum - create a new enumeration property type 3752c8e32cc1SDaniel Vetter * @dev: drm device 3753c8e32cc1SDaniel Vetter * @flags: flags specifying the property type 3754c8e32cc1SDaniel Vetter * @name: name of the property 3755c8e32cc1SDaniel Vetter * @props: enumeration lists with property values 3756c8e32cc1SDaniel Vetter * @num_values: number of pre-defined values 3757c8e32cc1SDaniel Vetter * 3758c8e32cc1SDaniel Vetter * This creates a new generic drm property which can then be attached to a drm 3759c8e32cc1SDaniel Vetter * object with drm_object_attach_property. The returned property object must be 3760c8e32cc1SDaniel Vetter * freed with drm_property_destroy. 3761c8e32cc1SDaniel Vetter * 3762c8e32cc1SDaniel Vetter * Userspace is only allowed to set one of the predefined values for enumeration 3763c8e32cc1SDaniel Vetter * properties. 3764c8e32cc1SDaniel Vetter * 3765c8e32cc1SDaniel Vetter * Returns: 3766c8e32cc1SDaniel Vetter * A pointer to the newly created property on success, NULL on failure. 3767c8e32cc1SDaniel Vetter */ 37684a67d391SSascha Hauer struct drm_property *drm_property_create_enum(struct drm_device *dev, int flags, 37694a67d391SSascha Hauer const char *name, 37704a67d391SSascha Hauer const struct drm_prop_enum_list *props, 37714a67d391SSascha Hauer int num_values) 37724a67d391SSascha Hauer { 37734a67d391SSascha Hauer struct drm_property *property; 37744a67d391SSascha Hauer int i, ret; 37754a67d391SSascha Hauer 37764a67d391SSascha Hauer flags |= DRM_MODE_PROP_ENUM; 37774a67d391SSascha Hauer 37784a67d391SSascha Hauer property = drm_property_create(dev, flags, name, num_values); 37794a67d391SSascha Hauer if (!property) 37804a67d391SSascha Hauer return NULL; 37814a67d391SSascha Hauer 37824a67d391SSascha Hauer for (i = 0; i < num_values; i++) { 37834a67d391SSascha Hauer ret = drm_property_add_enum(property, i, 37844a67d391SSascha Hauer props[i].type, 37854a67d391SSascha Hauer props[i].name); 37864a67d391SSascha Hauer if (ret) { 37874a67d391SSascha Hauer drm_property_destroy(dev, property); 37884a67d391SSascha Hauer return NULL; 37894a67d391SSascha Hauer } 37904a67d391SSascha Hauer } 37914a67d391SSascha Hauer 37924a67d391SSascha Hauer return property; 37934a67d391SSascha Hauer } 37944a67d391SSascha Hauer EXPORT_SYMBOL(drm_property_create_enum); 37954a67d391SSascha Hauer 3796c8e32cc1SDaniel Vetter /** 37972aa9d2bcSThierry Reding * drm_property_create_bitmask - create a new bitmask property type 3798c8e32cc1SDaniel Vetter * @dev: drm device 3799c8e32cc1SDaniel Vetter * @flags: flags specifying the property type 3800c8e32cc1SDaniel Vetter * @name: name of the property 3801c8e32cc1SDaniel Vetter * @props: enumeration lists with property bitflags 3802295ee853SDaniel Vetter * @num_props: size of the @props array 3803295ee853SDaniel Vetter * @supported_bits: bitmask of all supported enumeration values 3804c8e32cc1SDaniel Vetter * 3805295ee853SDaniel Vetter * This creates a new bitmask drm property which can then be attached to a drm 3806c8e32cc1SDaniel Vetter * object with drm_object_attach_property. The returned property object must be 3807c8e32cc1SDaniel Vetter * freed with drm_property_destroy. 3808c8e32cc1SDaniel Vetter * 3809c8e32cc1SDaniel Vetter * Compared to plain enumeration properties userspace is allowed to set any 3810c8e32cc1SDaniel Vetter * or'ed together combination of the predefined property bitflag values 3811c8e32cc1SDaniel Vetter * 3812c8e32cc1SDaniel Vetter * Returns: 3813c8e32cc1SDaniel Vetter * A pointer to the newly created property on success, NULL on failure. 3814c8e32cc1SDaniel Vetter */ 381549e27545SRob Clark struct drm_property *drm_property_create_bitmask(struct drm_device *dev, 381649e27545SRob Clark int flags, const char *name, 381749e27545SRob Clark const struct drm_prop_enum_list *props, 38187689ffb3SVille Syrjälä int num_props, 38197689ffb3SVille Syrjälä uint64_t supported_bits) 382049e27545SRob Clark { 382149e27545SRob Clark struct drm_property *property; 38227689ffb3SVille Syrjälä int i, ret, index = 0; 38237689ffb3SVille Syrjälä int num_values = hweight64(supported_bits); 382449e27545SRob Clark 382549e27545SRob Clark flags |= DRM_MODE_PROP_BITMASK; 382649e27545SRob Clark 382749e27545SRob Clark property = drm_property_create(dev, flags, name, num_values); 382849e27545SRob Clark if (!property) 382949e27545SRob Clark return NULL; 38307689ffb3SVille Syrjälä for (i = 0; i < num_props; i++) { 38317689ffb3SVille Syrjälä if (!(supported_bits & (1ULL << props[i].type))) 38327689ffb3SVille Syrjälä continue; 383349e27545SRob Clark 38347689ffb3SVille Syrjälä if (WARN_ON(index >= num_values)) { 38357689ffb3SVille Syrjälä drm_property_destroy(dev, property); 38367689ffb3SVille Syrjälä return NULL; 38377689ffb3SVille Syrjälä } 38387689ffb3SVille Syrjälä 38397689ffb3SVille Syrjälä ret = drm_property_add_enum(property, index++, 384049e27545SRob Clark props[i].type, 384149e27545SRob Clark props[i].name); 384249e27545SRob Clark if (ret) { 384349e27545SRob Clark drm_property_destroy(dev, property); 384449e27545SRob Clark return NULL; 384549e27545SRob Clark } 384649e27545SRob Clark } 384749e27545SRob Clark 384849e27545SRob Clark return property; 384949e27545SRob Clark } 385049e27545SRob Clark EXPORT_SYMBOL(drm_property_create_bitmask); 385149e27545SRob Clark 3852ebc44cf3SRob Clark static struct drm_property *property_create_range(struct drm_device *dev, 3853ebc44cf3SRob Clark int flags, const char *name, 3854ebc44cf3SRob Clark uint64_t min, uint64_t max) 3855ebc44cf3SRob Clark { 3856ebc44cf3SRob Clark struct drm_property *property; 3857ebc44cf3SRob Clark 3858ebc44cf3SRob Clark property = drm_property_create(dev, flags, name, 2); 3859ebc44cf3SRob Clark if (!property) 3860ebc44cf3SRob Clark return NULL; 3861ebc44cf3SRob Clark 3862ebc44cf3SRob Clark property->values[0] = min; 3863ebc44cf3SRob Clark property->values[1] = max; 3864ebc44cf3SRob Clark 3865ebc44cf3SRob Clark return property; 3866ebc44cf3SRob Clark } 3867ebc44cf3SRob Clark 3868c8e32cc1SDaniel Vetter /** 3869960cd9d4SDaniel Vetter * drm_property_create_range - create a new unsigned ranged property type 3870c8e32cc1SDaniel Vetter * @dev: drm device 3871c8e32cc1SDaniel Vetter * @flags: flags specifying the property type 3872c8e32cc1SDaniel Vetter * @name: name of the property 3873c8e32cc1SDaniel Vetter * @min: minimum value of the property 3874c8e32cc1SDaniel Vetter * @max: maximum value of the property 3875c8e32cc1SDaniel Vetter * 3876c8e32cc1SDaniel Vetter * This creates a new generic drm property which can then be attached to a drm 3877c8e32cc1SDaniel Vetter * object with drm_object_attach_property. The returned property object must be 3878c8e32cc1SDaniel Vetter * freed with drm_property_destroy. 3879c8e32cc1SDaniel Vetter * 3880960cd9d4SDaniel Vetter * Userspace is allowed to set any unsigned integer value in the (min, max) 3881960cd9d4SDaniel Vetter * range inclusive. 3882c8e32cc1SDaniel Vetter * 3883c8e32cc1SDaniel Vetter * Returns: 3884c8e32cc1SDaniel Vetter * A pointer to the newly created property on success, NULL on failure. 3885c8e32cc1SDaniel Vetter */ 3886d9bc3c02SSascha Hauer struct drm_property *drm_property_create_range(struct drm_device *dev, int flags, 3887d9bc3c02SSascha Hauer const char *name, 3888d9bc3c02SSascha Hauer uint64_t min, uint64_t max) 3889d9bc3c02SSascha Hauer { 3890ebc44cf3SRob Clark return property_create_range(dev, DRM_MODE_PROP_RANGE | flags, 3891ebc44cf3SRob Clark name, min, max); 3892d9bc3c02SSascha Hauer } 3893d9bc3c02SSascha Hauer EXPORT_SYMBOL(drm_property_create_range); 3894d9bc3c02SSascha Hauer 3895960cd9d4SDaniel Vetter /** 3896960cd9d4SDaniel Vetter * drm_property_create_signed_range - create a new signed ranged property type 3897960cd9d4SDaniel Vetter * @dev: drm device 3898960cd9d4SDaniel Vetter * @flags: flags specifying the property type 3899960cd9d4SDaniel Vetter * @name: name of the property 3900960cd9d4SDaniel Vetter * @min: minimum value of the property 3901960cd9d4SDaniel Vetter * @max: maximum value of the property 3902960cd9d4SDaniel Vetter * 3903960cd9d4SDaniel Vetter * This creates a new generic drm property which can then be attached to a drm 3904960cd9d4SDaniel Vetter * object with drm_object_attach_property. The returned property object must be 3905960cd9d4SDaniel Vetter * freed with drm_property_destroy. 3906960cd9d4SDaniel Vetter * 3907960cd9d4SDaniel Vetter * Userspace is allowed to set any signed integer value in the (min, max) 3908960cd9d4SDaniel Vetter * range inclusive. 3909960cd9d4SDaniel Vetter * 3910960cd9d4SDaniel Vetter * Returns: 3911960cd9d4SDaniel Vetter * A pointer to the newly created property on success, NULL on failure. 3912960cd9d4SDaniel Vetter */ 3913ebc44cf3SRob Clark struct drm_property *drm_property_create_signed_range(struct drm_device *dev, 3914ebc44cf3SRob Clark int flags, const char *name, 3915ebc44cf3SRob Clark int64_t min, int64_t max) 3916ebc44cf3SRob Clark { 3917ebc44cf3SRob Clark return property_create_range(dev, DRM_MODE_PROP_SIGNED_RANGE | flags, 3918ebc44cf3SRob Clark name, I642U64(min), I642U64(max)); 3919ebc44cf3SRob Clark } 3920ebc44cf3SRob Clark EXPORT_SYMBOL(drm_property_create_signed_range); 3921ebc44cf3SRob Clark 3922960cd9d4SDaniel Vetter /** 3923960cd9d4SDaniel Vetter * drm_property_create_object - create a new object property type 3924960cd9d4SDaniel Vetter * @dev: drm device 3925960cd9d4SDaniel Vetter * @flags: flags specifying the property type 3926960cd9d4SDaniel Vetter * @name: name of the property 3927960cd9d4SDaniel Vetter * @type: object type from DRM_MODE_OBJECT_* defines 3928960cd9d4SDaniel Vetter * 3929960cd9d4SDaniel Vetter * This creates a new generic drm property which can then be attached to a drm 3930960cd9d4SDaniel Vetter * object with drm_object_attach_property. The returned property object must be 3931960cd9d4SDaniel Vetter * freed with drm_property_destroy. 3932960cd9d4SDaniel Vetter * 3933960cd9d4SDaniel Vetter * Userspace is only allowed to set this to any property value of the given 3934960cd9d4SDaniel Vetter * @type. Only useful for atomic properties, which is enforced. 3935960cd9d4SDaniel Vetter * 3936960cd9d4SDaniel Vetter * Returns: 3937960cd9d4SDaniel Vetter * A pointer to the newly created property on success, NULL on failure. 3938960cd9d4SDaniel Vetter */ 393998f75de4SRob Clark struct drm_property *drm_property_create_object(struct drm_device *dev, 394098f75de4SRob Clark int flags, const char *name, uint32_t type) 394198f75de4SRob Clark { 394298f75de4SRob Clark struct drm_property *property; 394398f75de4SRob Clark 394498f75de4SRob Clark flags |= DRM_MODE_PROP_OBJECT; 394598f75de4SRob Clark 3946960cd9d4SDaniel Vetter if (WARN_ON(!(flags & DRM_MODE_PROP_ATOMIC))) 3947960cd9d4SDaniel Vetter return NULL; 3948960cd9d4SDaniel Vetter 394998f75de4SRob Clark property = drm_property_create(dev, flags, name, 1); 395098f75de4SRob Clark if (!property) 395198f75de4SRob Clark return NULL; 395298f75de4SRob Clark 395398f75de4SRob Clark property->values[0] = type; 395498f75de4SRob Clark 395598f75de4SRob Clark return property; 395698f75de4SRob Clark } 395798f75de4SRob Clark EXPORT_SYMBOL(drm_property_create_object); 395898f75de4SRob Clark 3959c8e32cc1SDaniel Vetter /** 3960960cd9d4SDaniel Vetter * drm_property_create_bool - create a new boolean property type 3961960cd9d4SDaniel Vetter * @dev: drm device 3962960cd9d4SDaniel Vetter * @flags: flags specifying the property type 3963960cd9d4SDaniel Vetter * @name: name of the property 3964960cd9d4SDaniel Vetter * 3965960cd9d4SDaniel Vetter * This creates a new generic drm property which can then be attached to a drm 3966960cd9d4SDaniel Vetter * object with drm_object_attach_property. The returned property object must be 3967960cd9d4SDaniel Vetter * freed with drm_property_destroy. 3968960cd9d4SDaniel Vetter * 3969960cd9d4SDaniel Vetter * This is implemented as a ranged property with only {0, 1} as valid values. 3970960cd9d4SDaniel Vetter * 3971960cd9d4SDaniel Vetter * Returns: 3972960cd9d4SDaniel Vetter * A pointer to the newly created property on success, NULL on failure. 3973960cd9d4SDaniel Vetter */ 3974960cd9d4SDaniel Vetter struct drm_property *drm_property_create_bool(struct drm_device *dev, int flags, 3975960cd9d4SDaniel Vetter const char *name) 3976960cd9d4SDaniel Vetter { 3977960cd9d4SDaniel Vetter return drm_property_create_range(dev, flags, name, 0, 1); 3978960cd9d4SDaniel Vetter } 3979960cd9d4SDaniel Vetter EXPORT_SYMBOL(drm_property_create_bool); 3980960cd9d4SDaniel Vetter 3981960cd9d4SDaniel Vetter /** 3982c8e32cc1SDaniel Vetter * drm_property_add_enum - add a possible value to an enumeration property 3983c8e32cc1SDaniel Vetter * @property: enumeration property to change 3984c8e32cc1SDaniel Vetter * @index: index of the new enumeration 3985c8e32cc1SDaniel Vetter * @value: value of the new enumeration 3986c8e32cc1SDaniel Vetter * @name: symbolic name of the new enumeration 3987c8e32cc1SDaniel Vetter * 3988c8e32cc1SDaniel Vetter * This functions adds enumerations to a property. 3989c8e32cc1SDaniel Vetter * 3990c8e32cc1SDaniel Vetter * It's use is deprecated, drivers should use one of the more specific helpers 3991c8e32cc1SDaniel Vetter * to directly create the property with all enumerations already attached. 3992c8e32cc1SDaniel Vetter * 3993c8e32cc1SDaniel Vetter * Returns: 3994c8e32cc1SDaniel Vetter * Zero on success, error code on failure. 3995c8e32cc1SDaniel Vetter */ 3996f453ba04SDave Airlie int drm_property_add_enum(struct drm_property *property, int index, 3997f453ba04SDave Airlie uint64_t value, const char *name) 3998f453ba04SDave Airlie { 3999f453ba04SDave Airlie struct drm_property_enum *prop_enum; 4000f453ba04SDave Airlie 40015ea22f24SRob Clark if (!(drm_property_type_is(property, DRM_MODE_PROP_ENUM) || 40025ea22f24SRob Clark drm_property_type_is(property, DRM_MODE_PROP_BITMASK))) 400349e27545SRob Clark return -EINVAL; 400449e27545SRob Clark 400549e27545SRob Clark /* 400649e27545SRob Clark * Bitmask enum properties have the additional constraint of values 400749e27545SRob Clark * from 0 to 63 400849e27545SRob Clark */ 40095ea22f24SRob Clark if (drm_property_type_is(property, DRM_MODE_PROP_BITMASK) && 40105ea22f24SRob Clark (value > 63)) 4011f453ba04SDave Airlie return -EINVAL; 4012f453ba04SDave Airlie 40133758b341SDaniel Vetter if (!list_empty(&property->enum_list)) { 40143758b341SDaniel Vetter list_for_each_entry(prop_enum, &property->enum_list, head) { 4015f453ba04SDave Airlie if (prop_enum->value == value) { 4016f453ba04SDave Airlie strncpy(prop_enum->name, name, DRM_PROP_NAME_LEN); 4017f453ba04SDave Airlie prop_enum->name[DRM_PROP_NAME_LEN-1] = '\0'; 4018f453ba04SDave Airlie return 0; 4019f453ba04SDave Airlie } 4020f453ba04SDave Airlie } 4021f453ba04SDave Airlie } 4022f453ba04SDave Airlie 4023f453ba04SDave Airlie prop_enum = kzalloc(sizeof(struct drm_property_enum), GFP_KERNEL); 4024f453ba04SDave Airlie if (!prop_enum) 4025f453ba04SDave Airlie return -ENOMEM; 4026f453ba04SDave Airlie 4027f453ba04SDave Airlie strncpy(prop_enum->name, name, DRM_PROP_NAME_LEN); 4028f453ba04SDave Airlie prop_enum->name[DRM_PROP_NAME_LEN-1] = '\0'; 4029f453ba04SDave Airlie prop_enum->value = value; 4030f453ba04SDave Airlie 4031f453ba04SDave Airlie property->values[index] = value; 40323758b341SDaniel Vetter list_add_tail(&prop_enum->head, &property->enum_list); 4033f453ba04SDave Airlie return 0; 4034f453ba04SDave Airlie } 4035f453ba04SDave Airlie EXPORT_SYMBOL(drm_property_add_enum); 4036f453ba04SDave Airlie 4037c8e32cc1SDaniel Vetter /** 4038c8e32cc1SDaniel Vetter * drm_property_destroy - destroy a drm property 4039c8e32cc1SDaniel Vetter * @dev: drm device 4040c8e32cc1SDaniel Vetter * @property: property to destry 4041c8e32cc1SDaniel Vetter * 4042c8e32cc1SDaniel Vetter * This function frees a property including any attached resources like 4043c8e32cc1SDaniel Vetter * enumeration values. 4044c8e32cc1SDaniel Vetter */ 4045f453ba04SDave Airlie void drm_property_destroy(struct drm_device *dev, struct drm_property *property) 4046f453ba04SDave Airlie { 4047f453ba04SDave Airlie struct drm_property_enum *prop_enum, *pt; 4048f453ba04SDave Airlie 40493758b341SDaniel Vetter list_for_each_entry_safe(prop_enum, pt, &property->enum_list, head) { 4050f453ba04SDave Airlie list_del(&prop_enum->head); 4051f453ba04SDave Airlie kfree(prop_enum); 4052f453ba04SDave Airlie } 4053f453ba04SDave Airlie 4054f453ba04SDave Airlie if (property->num_values) 4055f453ba04SDave Airlie kfree(property->values); 40567c8f6d25SDave Airlie drm_mode_object_unregister(dev, &property->base); 4057f453ba04SDave Airlie list_del(&property->head); 4058f453ba04SDave Airlie kfree(property); 4059f453ba04SDave Airlie } 4060f453ba04SDave Airlie EXPORT_SYMBOL(drm_property_destroy); 4061f453ba04SDave Airlie 4062c8e32cc1SDaniel Vetter /** 4063c8e32cc1SDaniel Vetter * drm_object_attach_property - attach a property to a modeset object 4064c8e32cc1SDaniel Vetter * @obj: drm modeset object 4065c8e32cc1SDaniel Vetter * @property: property to attach 4066c8e32cc1SDaniel Vetter * @init_val: initial value of the property 4067c8e32cc1SDaniel Vetter * 4068c8e32cc1SDaniel Vetter * This attaches the given property to the modeset object with the given initial 4069c8e32cc1SDaniel Vetter * value. Currently this function cannot fail since the properties are stored in 4070c8e32cc1SDaniel Vetter * a statically sized array. 4071c8e32cc1SDaniel Vetter */ 4072c543188aSPaulo Zanoni void drm_object_attach_property(struct drm_mode_object *obj, 4073c543188aSPaulo Zanoni struct drm_property *property, 4074c543188aSPaulo Zanoni uint64_t init_val) 4075c543188aSPaulo Zanoni { 40767f88a9beSPaulo Zanoni int count = obj->properties->count; 4077c543188aSPaulo Zanoni 40787f88a9beSPaulo Zanoni if (count == DRM_OBJECT_MAX_PROPERTY) { 40797f88a9beSPaulo Zanoni WARN(1, "Failed to attach object property (type: 0x%x). Please " 40807f88a9beSPaulo Zanoni "increase DRM_OBJECT_MAX_PROPERTY by 1 for each time " 40817f88a9beSPaulo Zanoni "you see this message on the same object type.\n", 40827f88a9beSPaulo Zanoni obj->type); 4083c543188aSPaulo Zanoni return; 4084c543188aSPaulo Zanoni } 4085c543188aSPaulo Zanoni 4086b17cd757SRob Clark obj->properties->properties[count] = property; 40877f88a9beSPaulo Zanoni obj->properties->values[count] = init_val; 40887f88a9beSPaulo Zanoni obj->properties->count++; 408988a48e29SRob Clark if (property->flags & DRM_MODE_PROP_ATOMIC) 409088a48e29SRob Clark obj->properties->atomic_count++; 4091c543188aSPaulo Zanoni } 4092c543188aSPaulo Zanoni EXPORT_SYMBOL(drm_object_attach_property); 4093c543188aSPaulo Zanoni 4094c8e32cc1SDaniel Vetter /** 4095c8e32cc1SDaniel Vetter * drm_object_property_set_value - set the value of a property 4096c8e32cc1SDaniel Vetter * @obj: drm mode object to set property value for 4097c8e32cc1SDaniel Vetter * @property: property to set 4098c8e32cc1SDaniel Vetter * @val: value the property should be set to 4099c8e32cc1SDaniel Vetter * 4100c8e32cc1SDaniel Vetter * This functions sets a given property on a given object. This function only 4101c8e32cc1SDaniel Vetter * changes the software state of the property, it does not call into the 4102c8e32cc1SDaniel Vetter * driver's ->set_property callback. 4103c8e32cc1SDaniel Vetter * 4104c8e32cc1SDaniel Vetter * Returns: 4105c8e32cc1SDaniel Vetter * Zero on success, error code on failure. 4106c8e32cc1SDaniel Vetter */ 4107c543188aSPaulo Zanoni int drm_object_property_set_value(struct drm_mode_object *obj, 4108c543188aSPaulo Zanoni struct drm_property *property, uint64_t val) 4109c543188aSPaulo Zanoni { 4110c543188aSPaulo Zanoni int i; 4111c543188aSPaulo Zanoni 41127f88a9beSPaulo Zanoni for (i = 0; i < obj->properties->count; i++) { 4113b17cd757SRob Clark if (obj->properties->properties[i] == property) { 4114c543188aSPaulo Zanoni obj->properties->values[i] = val; 4115c543188aSPaulo Zanoni return 0; 4116c543188aSPaulo Zanoni } 4117c543188aSPaulo Zanoni } 4118c543188aSPaulo Zanoni 4119c543188aSPaulo Zanoni return -EINVAL; 4120c543188aSPaulo Zanoni } 4121c543188aSPaulo Zanoni EXPORT_SYMBOL(drm_object_property_set_value); 4122c543188aSPaulo Zanoni 4123c8e32cc1SDaniel Vetter /** 4124c8e32cc1SDaniel Vetter * drm_object_property_get_value - retrieve the value of a property 4125c8e32cc1SDaniel Vetter * @obj: drm mode object to get property value from 4126c8e32cc1SDaniel Vetter * @property: property to retrieve 4127c8e32cc1SDaniel Vetter * @val: storage for the property value 4128c8e32cc1SDaniel Vetter * 4129c8e32cc1SDaniel Vetter * This function retrieves the softare state of the given property for the given 4130c8e32cc1SDaniel Vetter * property. Since there is no driver callback to retrieve the current property 4131c8e32cc1SDaniel Vetter * value this might be out of sync with the hardware, depending upon the driver 4132c8e32cc1SDaniel Vetter * and property. 4133c8e32cc1SDaniel Vetter * 4134c8e32cc1SDaniel Vetter * Returns: 4135c8e32cc1SDaniel Vetter * Zero on success, error code on failure. 4136c8e32cc1SDaniel Vetter */ 4137c543188aSPaulo Zanoni int drm_object_property_get_value(struct drm_mode_object *obj, 4138c543188aSPaulo Zanoni struct drm_property *property, uint64_t *val) 4139c543188aSPaulo Zanoni { 4140c543188aSPaulo Zanoni int i; 4141c543188aSPaulo Zanoni 414288a48e29SRob Clark /* read-only properties bypass atomic mechanism and still store 414388a48e29SRob Clark * their value in obj->properties->values[].. mostly to avoid 414488a48e29SRob Clark * having to deal w/ EDID and similar props in atomic paths: 414588a48e29SRob Clark */ 414688a48e29SRob Clark if (drm_core_check_feature(property->dev, DRIVER_ATOMIC) && 414788a48e29SRob Clark !(property->flags & DRM_MODE_PROP_IMMUTABLE)) 414888a48e29SRob Clark return drm_atomic_get_property(obj, property, val); 414988a48e29SRob Clark 41507f88a9beSPaulo Zanoni for (i = 0; i < obj->properties->count; i++) { 4151b17cd757SRob Clark if (obj->properties->properties[i] == property) { 4152c543188aSPaulo Zanoni *val = obj->properties->values[i]; 4153c543188aSPaulo Zanoni return 0; 4154c543188aSPaulo Zanoni } 4155c543188aSPaulo Zanoni } 4156c543188aSPaulo Zanoni 4157c543188aSPaulo Zanoni return -EINVAL; 4158c543188aSPaulo Zanoni } 4159c543188aSPaulo Zanoni EXPORT_SYMBOL(drm_object_property_get_value); 4160c543188aSPaulo Zanoni 4161c8e32cc1SDaniel Vetter /** 41621a498633SDaniel Vetter * drm_mode_getproperty_ioctl - get the property metadata 4163c8e32cc1SDaniel Vetter * @dev: DRM device 4164c8e32cc1SDaniel Vetter * @data: ioctl data 4165c8e32cc1SDaniel Vetter * @file_priv: DRM file info 4166c8e32cc1SDaniel Vetter * 41671a498633SDaniel Vetter * This function retrieves the metadata for a given property, like the different 41681a498633SDaniel Vetter * possible values for an enum property or the limits for a range property. 41691a498633SDaniel Vetter * 41701a498633SDaniel Vetter * Blob properties are special 4171c8e32cc1SDaniel Vetter * 4172c8e32cc1SDaniel Vetter * Called by the user via ioctl. 4173c8e32cc1SDaniel Vetter * 4174c8e32cc1SDaniel Vetter * Returns: 41751a498633SDaniel Vetter * Zero on success, negative errno on failure. 4176c8e32cc1SDaniel Vetter */ 4177f453ba04SDave Airlie int drm_mode_getproperty_ioctl(struct drm_device *dev, 4178f453ba04SDave Airlie void *data, struct drm_file *file_priv) 4179f453ba04SDave Airlie { 4180f453ba04SDave Airlie struct drm_mode_get_property *out_resp = data; 4181f453ba04SDave Airlie struct drm_property *property; 4182f453ba04SDave Airlie int enum_count = 0; 4183f453ba04SDave Airlie int value_count = 0; 4184f453ba04SDave Airlie int ret = 0, i; 4185f453ba04SDave Airlie int copied; 4186f453ba04SDave Airlie struct drm_property_enum *prop_enum; 4187f453ba04SDave Airlie struct drm_mode_property_enum __user *enum_ptr; 4188f453ba04SDave Airlie uint64_t __user *values_ptr; 4189f453ba04SDave Airlie 4190fb3b06c8SDave Airlie if (!drm_core_check_feature(dev, DRIVER_MODESET)) 4191fb3b06c8SDave Airlie return -EINVAL; 4192fb3b06c8SDave Airlie 419384849903SDaniel Vetter drm_modeset_lock_all(dev); 4194a2b34e22SRob Clark property = drm_property_find(dev, out_resp->prop_id); 4195a2b34e22SRob Clark if (!property) { 4196f27657f2SVille Syrjälä ret = -ENOENT; 4197f453ba04SDave Airlie goto done; 4198f453ba04SDave Airlie } 4199f453ba04SDave Airlie 42005ea22f24SRob Clark if (drm_property_type_is(property, DRM_MODE_PROP_ENUM) || 42015ea22f24SRob Clark drm_property_type_is(property, DRM_MODE_PROP_BITMASK)) { 42023758b341SDaniel Vetter list_for_each_entry(prop_enum, &property->enum_list, head) 4203f453ba04SDave Airlie enum_count++; 4204f453ba04SDave Airlie } 4205f453ba04SDave Airlie 4206f453ba04SDave Airlie value_count = property->num_values; 4207f453ba04SDave Airlie 4208f453ba04SDave Airlie strncpy(out_resp->name, property->name, DRM_PROP_NAME_LEN); 4209f453ba04SDave Airlie out_resp->name[DRM_PROP_NAME_LEN-1] = 0; 4210f453ba04SDave Airlie out_resp->flags = property->flags; 4211f453ba04SDave Airlie 4212f453ba04SDave Airlie if ((out_resp->count_values >= value_count) && value_count) { 421381f6c7f8SVille Syrjälä values_ptr = (uint64_t __user *)(unsigned long)out_resp->values_ptr; 4214f453ba04SDave Airlie for (i = 0; i < value_count; i++) { 4215f453ba04SDave Airlie if (copy_to_user(values_ptr + i, &property->values[i], sizeof(uint64_t))) { 4216f453ba04SDave Airlie ret = -EFAULT; 4217f453ba04SDave Airlie goto done; 4218f453ba04SDave Airlie } 4219f453ba04SDave Airlie } 4220f453ba04SDave Airlie } 4221f453ba04SDave Airlie out_resp->count_values = value_count; 4222f453ba04SDave Airlie 42235ea22f24SRob Clark if (drm_property_type_is(property, DRM_MODE_PROP_ENUM) || 42245ea22f24SRob Clark drm_property_type_is(property, DRM_MODE_PROP_BITMASK)) { 4225f453ba04SDave Airlie if ((out_resp->count_enum_blobs >= enum_count) && enum_count) { 4226f453ba04SDave Airlie copied = 0; 422781f6c7f8SVille Syrjälä enum_ptr = (struct drm_mode_property_enum __user *)(unsigned long)out_resp->enum_blob_ptr; 42283758b341SDaniel Vetter list_for_each_entry(prop_enum, &property->enum_list, head) { 4229f453ba04SDave Airlie 4230f453ba04SDave Airlie if (copy_to_user(&enum_ptr[copied].value, &prop_enum->value, sizeof(uint64_t))) { 4231f453ba04SDave Airlie ret = -EFAULT; 4232f453ba04SDave Airlie goto done; 4233f453ba04SDave Airlie } 4234f453ba04SDave Airlie 4235f453ba04SDave Airlie if (copy_to_user(&enum_ptr[copied].name, 4236f453ba04SDave Airlie &prop_enum->name, DRM_PROP_NAME_LEN)) { 4237f453ba04SDave Airlie ret = -EFAULT; 4238f453ba04SDave Airlie goto done; 4239f453ba04SDave Airlie } 4240f453ba04SDave Airlie copied++; 4241f453ba04SDave Airlie } 4242f453ba04SDave Airlie } 4243f453ba04SDave Airlie out_resp->count_enum_blobs = enum_count; 4244f453ba04SDave Airlie } 4245f453ba04SDave Airlie 42463758b341SDaniel Vetter /* 42473758b341SDaniel Vetter * NOTE: The idea seems to have been to use this to read all the blob 42483758b341SDaniel Vetter * property values. But nothing ever added them to the corresponding 42493758b341SDaniel Vetter * list, userspace always used the special-purpose get_blob ioctl to 42503758b341SDaniel Vetter * read the value for a blob property. It also doesn't make a lot of 42513758b341SDaniel Vetter * sense to return values here when everything else is just metadata for 42523758b341SDaniel Vetter * the property itself. 42533758b341SDaniel Vetter */ 42543758b341SDaniel Vetter if (drm_property_type_is(property, DRM_MODE_PROP_BLOB)) 42553758b341SDaniel Vetter out_resp->count_enum_blobs = 0; 4256f453ba04SDave Airlie done: 425784849903SDaniel Vetter drm_modeset_unlock_all(dev); 4258f453ba04SDave Airlie return ret; 4259f453ba04SDave Airlie } 4260f453ba04SDave Airlie 4261152ef5faSDaniel Vetter static void drm_property_free_blob(struct kref *kref) 4262152ef5faSDaniel Vetter { 4263152ef5faSDaniel Vetter struct drm_property_blob *blob = 4264152ef5faSDaniel Vetter container_of(kref, struct drm_property_blob, base.refcount); 4265152ef5faSDaniel Vetter 4266152ef5faSDaniel Vetter mutex_lock(&blob->dev->mode_config.blob_lock); 4267152ef5faSDaniel Vetter list_del(&blob->head_global); 4268152ef5faSDaniel Vetter mutex_unlock(&blob->dev->mode_config.blob_lock); 4269152ef5faSDaniel Vetter 4270152ef5faSDaniel Vetter drm_mode_object_unregister(blob->dev, &blob->base); 4271152ef5faSDaniel Vetter 4272152ef5faSDaniel Vetter kfree(blob); 4273152ef5faSDaniel Vetter } 4274152ef5faSDaniel Vetter 427599531d9bSDaniel Stone /** 427699531d9bSDaniel Stone * drm_property_create_blob - Create new blob property 427799531d9bSDaniel Stone * 427899531d9bSDaniel Stone * Creates a new blob property for a specified DRM device, optionally 427999531d9bSDaniel Stone * copying data. 428099531d9bSDaniel Stone * 428199531d9bSDaniel Stone * @dev: DRM device to create property for 428299531d9bSDaniel Stone * @length: Length to allocate for blob data 428399531d9bSDaniel Stone * @data: If specified, copies data into blob 428410e8cb7eSDaniel Stone * 428510e8cb7eSDaniel Stone * Returns: 428610e8cb7eSDaniel Stone * New blob property with a single reference on success, or an ERR_PTR 428710e8cb7eSDaniel Stone * value on failure. 428899531d9bSDaniel Stone */ 42896bcacf51SDaniel Stone struct drm_property_blob * 4290ecbbe59bSThierry Reding drm_property_create_blob(struct drm_device *dev, size_t length, 429112e6cecdSThierry Reding const void *data) 4292f453ba04SDave Airlie { 4293f453ba04SDave Airlie struct drm_property_blob *blob; 42946bfc56aaSVille Syrjälä int ret; 4295f453ba04SDave Airlie 42969ac0934bSDan Carpenter if (!length || length > ULONG_MAX - sizeof(struct drm_property_blob)) 429710e8cb7eSDaniel Stone return ERR_PTR(-EINVAL); 4298f453ba04SDave Airlie 4299f453ba04SDave Airlie blob = kzalloc(sizeof(struct drm_property_blob)+length, GFP_KERNEL); 4300f453ba04SDave Airlie if (!blob) 430110e8cb7eSDaniel Stone return ERR_PTR(-ENOMEM); 4302f453ba04SDave Airlie 4303e2f5d2eaSDaniel Stone /* This must be explicitly initialised, so we can safely call list_del 4304e2f5d2eaSDaniel Stone * on it in the removal handler, even if it isn't in a file list. */ 4305e2f5d2eaSDaniel Stone INIT_LIST_HEAD(&blob->head_file); 4306f453ba04SDave Airlie blob->length = length; 43076bcacf51SDaniel Stone blob->dev = dev; 4308f453ba04SDave Airlie 430999531d9bSDaniel Stone if (data) 4310f453ba04SDave Airlie memcpy(blob->data, data, length); 4311f453ba04SDave Airlie 4312152ef5faSDaniel Vetter ret = drm_mode_object_get_reg(dev, &blob->base, DRM_MODE_OBJECT_BLOB, 4313152ef5faSDaniel Vetter true, drm_property_free_blob); 43148fb6e7a5SDaniel Stone if (ret) { 43158fb6e7a5SDaniel Stone kfree(blob); 431610e8cb7eSDaniel Stone return ERR_PTR(-EINVAL); 43178fb6e7a5SDaniel Stone } 43188fb6e7a5SDaniel Stone 4319152ef5faSDaniel Vetter mutex_lock(&dev->mode_config.blob_lock); 4320e2f5d2eaSDaniel Stone list_add_tail(&blob->head_global, 4321e2f5d2eaSDaniel Stone &dev->mode_config.property_blob_list); 43228fb6e7a5SDaniel Stone mutex_unlock(&dev->mode_config.blob_lock); 43238fb6e7a5SDaniel Stone 4324f453ba04SDave Airlie return blob; 4325f453ba04SDave Airlie } 43266bcacf51SDaniel Stone EXPORT_SYMBOL(drm_property_create_blob); 4327f453ba04SDave Airlie 43286bcacf51SDaniel Stone /** 43296bcacf51SDaniel Stone * drm_property_unreference_blob - Unreference a blob property 43306bcacf51SDaniel Stone * 43316bcacf51SDaniel Stone * Drop a reference on a blob property. May free the object. 43326bcacf51SDaniel Stone * 4333f102c16eSDaniel Stone * @blob: Pointer to blob property 43346bcacf51SDaniel Stone */ 43356bcacf51SDaniel Stone void drm_property_unreference_blob(struct drm_property_blob *blob) 43366bcacf51SDaniel Stone { 43376bcacf51SDaniel Stone if (!blob) 43386bcacf51SDaniel Stone return; 43396bcacf51SDaniel Stone 4340152ef5faSDaniel Vetter drm_mode_object_unreference(&blob->base); 43416bcacf51SDaniel Stone } 43426bcacf51SDaniel Stone EXPORT_SYMBOL(drm_property_unreference_blob); 43436bcacf51SDaniel Stone 43446bcacf51SDaniel Stone /** 4345e2f5d2eaSDaniel Stone * drm_property_destroy_user_blobs - destroy all blobs created by this client 4346e2f5d2eaSDaniel Stone * @dev: DRM device 4347e2f5d2eaSDaniel Stone * @file_priv: destroy all blobs owned by this file handle 4348e2f5d2eaSDaniel Stone */ 4349e2f5d2eaSDaniel Stone void drm_property_destroy_user_blobs(struct drm_device *dev, 4350e2f5d2eaSDaniel Stone struct drm_file *file_priv) 4351e2f5d2eaSDaniel Stone { 4352e2f5d2eaSDaniel Stone struct drm_property_blob *blob, *bt; 4353e2f5d2eaSDaniel Stone 4354152ef5faSDaniel Vetter /* 4355152ef5faSDaniel Vetter * When the file gets released that means no one else can access the 4356152ef5faSDaniel Vetter * blob list any more, so no need to grab dev->blob_lock. 4357152ef5faSDaniel Vetter */ 4358e2f5d2eaSDaniel Stone list_for_each_entry_safe(blob, bt, &file_priv->blobs, head_file) { 4359e2f5d2eaSDaniel Stone list_del_init(&blob->head_file); 4360152ef5faSDaniel Vetter drm_property_unreference_blob(blob); 4361e2f5d2eaSDaniel Stone } 4362e2f5d2eaSDaniel Stone } 4363e2f5d2eaSDaniel Stone 4364e2f5d2eaSDaniel Stone /** 43656bcacf51SDaniel Stone * drm_property_reference_blob - Take a reference on an existing property 43666bcacf51SDaniel Stone * 43676bcacf51SDaniel Stone * Take a new reference on an existing blob property. 43686bcacf51SDaniel Stone * 4369f102c16eSDaniel Stone * @blob: Pointer to blob property 43706bcacf51SDaniel Stone */ 43716bcacf51SDaniel Stone struct drm_property_blob *drm_property_reference_blob(struct drm_property_blob *blob) 43726bcacf51SDaniel Stone { 4373152ef5faSDaniel Vetter drm_mode_object_reference(&blob->base); 43746bcacf51SDaniel Stone return blob; 43756bcacf51SDaniel Stone } 43766bcacf51SDaniel Stone EXPORT_SYMBOL(drm_property_reference_blob); 43776bcacf51SDaniel Stone 43786bcacf51SDaniel Stone /** 43796bcacf51SDaniel Stone * drm_property_lookup_blob - look up a blob property and take a reference 43806bcacf51SDaniel Stone * @dev: drm device 43816bcacf51SDaniel Stone * @id: id of the blob property 43826bcacf51SDaniel Stone * 43836bcacf51SDaniel Stone * If successful, this takes an additional reference to the blob property. 43846bcacf51SDaniel Stone * callers need to make sure to eventually unreference the returned property 43856bcacf51SDaniel Stone * again, using @drm_property_unreference_blob. 43866bcacf51SDaniel Stone */ 43876bcacf51SDaniel Stone struct drm_property_blob *drm_property_lookup_blob(struct drm_device *dev, 43886bcacf51SDaniel Stone uint32_t id) 4389f453ba04SDave Airlie { 4390152ef5faSDaniel Vetter struct drm_mode_object *obj; 4391152ef5faSDaniel Vetter struct drm_property_blob *blob = NULL; 43926bcacf51SDaniel Stone 4393152ef5faSDaniel Vetter obj = _object_find(dev, id, DRM_MODE_OBJECT_BLOB); 4394152ef5faSDaniel Vetter if (obj) 4395152ef5faSDaniel Vetter blob = obj_to_blob(obj); 43966bcacf51SDaniel Stone return blob; 43976bcacf51SDaniel Stone } 43986bcacf51SDaniel Stone EXPORT_SYMBOL(drm_property_lookup_blob); 43996bcacf51SDaniel Stone 44006bcacf51SDaniel Stone /** 4401d2ed3436SDaniel Stone * drm_property_replace_global_blob - atomically replace existing blob property 4402d2ed3436SDaniel Stone * @dev: drm device 4403d2ed3436SDaniel Stone * @replace: location of blob property pointer to be replaced 4404d2ed3436SDaniel Stone * @length: length of data for new blob, or 0 for no data 4405d2ed3436SDaniel Stone * @data: content for new blob, or NULL for no data 4406d2ed3436SDaniel Stone * @obj_holds_id: optional object for property holding blob ID 4407d2ed3436SDaniel Stone * @prop_holds_id: optional property holding blob ID 4408d2ed3436SDaniel Stone * @return 0 on success or error on failure 4409d2ed3436SDaniel Stone * 4410d2ed3436SDaniel Stone * This function will atomically replace a global property in the blob list, 4411d2ed3436SDaniel Stone * optionally updating a property which holds the ID of that property. It is 4412d2ed3436SDaniel Stone * guaranteed to be atomic: no caller will be allowed to see intermediate 4413d2ed3436SDaniel Stone * results, and either the entire operation will succeed and clean up the 4414d2ed3436SDaniel Stone * previous property, or it will fail and the state will be unchanged. 4415d2ed3436SDaniel Stone * 4416d2ed3436SDaniel Stone * If length is 0 or data is NULL, no new blob will be created, and the holding 4417d2ed3436SDaniel Stone * property, if specified, will be set to 0. 4418d2ed3436SDaniel Stone * 4419d2ed3436SDaniel Stone * Access to the replace pointer is assumed to be protected by the caller, e.g. 4420d2ed3436SDaniel Stone * by holding the relevant modesetting object lock for its parent. 4421d2ed3436SDaniel Stone * 4422d2ed3436SDaniel Stone * For example, a drm_connector has a 'PATH' property, which contains the ID 4423d2ed3436SDaniel Stone * of a blob property with the value of the MST path information. Calling this 4424d2ed3436SDaniel Stone * function with replace pointing to the connector's path_blob_ptr, length and 4425d2ed3436SDaniel Stone * data set for the new path information, obj_holds_id set to the connector's 4426d2ed3436SDaniel Stone * base object, and prop_holds_id set to the path property name, will perform 4427d2ed3436SDaniel Stone * a completely atomic update. The access to path_blob_ptr is protected by the 4428d2ed3436SDaniel Stone * caller holding a lock on the connector. 4429d2ed3436SDaniel Stone */ 4430d2ed3436SDaniel Stone static int drm_property_replace_global_blob(struct drm_device *dev, 4431d2ed3436SDaniel Stone struct drm_property_blob **replace, 4432d2ed3436SDaniel Stone size_t length, 4433d2ed3436SDaniel Stone const void *data, 4434d2ed3436SDaniel Stone struct drm_mode_object *obj_holds_id, 4435d2ed3436SDaniel Stone struct drm_property *prop_holds_id) 4436d2ed3436SDaniel Stone { 4437d2ed3436SDaniel Stone struct drm_property_blob *new_blob = NULL; 4438d2ed3436SDaniel Stone struct drm_property_blob *old_blob = NULL; 4439d2ed3436SDaniel Stone int ret; 4440d2ed3436SDaniel Stone 4441d2ed3436SDaniel Stone WARN_ON(replace == NULL); 4442d2ed3436SDaniel Stone 4443d2ed3436SDaniel Stone old_blob = *replace; 4444d2ed3436SDaniel Stone 4445d2ed3436SDaniel Stone if (length && data) { 4446d2ed3436SDaniel Stone new_blob = drm_property_create_blob(dev, length, data); 444710e8cb7eSDaniel Stone if (IS_ERR(new_blob)) 444810e8cb7eSDaniel Stone return PTR_ERR(new_blob); 4449d2ed3436SDaniel Stone } 4450d2ed3436SDaniel Stone 4451d2ed3436SDaniel Stone /* This does not need to be synchronised with blob_lock, as the 4452d2ed3436SDaniel Stone * get_properties ioctl locks all modesetting objects, and 4453d2ed3436SDaniel Stone * obj_holds_id must be locked before calling here, so we cannot 4454d2ed3436SDaniel Stone * have its value out of sync with the list membership modified 4455d2ed3436SDaniel Stone * below under blob_lock. */ 4456d2ed3436SDaniel Stone if (obj_holds_id) { 4457d2ed3436SDaniel Stone ret = drm_object_property_set_value(obj_holds_id, 4458d2ed3436SDaniel Stone prop_holds_id, 4459d2ed3436SDaniel Stone new_blob ? 4460d2ed3436SDaniel Stone new_blob->base.id : 0); 4461d2ed3436SDaniel Stone if (ret != 0) 4462d2ed3436SDaniel Stone goto err_created; 4463d2ed3436SDaniel Stone } 4464d2ed3436SDaniel Stone 44656bcacf51SDaniel Stone drm_property_unreference_blob(old_blob); 4466d2ed3436SDaniel Stone *replace = new_blob; 4467d2ed3436SDaniel Stone 4468d2ed3436SDaniel Stone return 0; 4469d2ed3436SDaniel Stone 4470d2ed3436SDaniel Stone err_created: 44716bcacf51SDaniel Stone drm_property_unreference_blob(new_blob); 4472d2ed3436SDaniel Stone return ret; 4473f453ba04SDave Airlie } 4474f453ba04SDave Airlie 4475c8e32cc1SDaniel Vetter /** 4476c8e32cc1SDaniel Vetter * drm_mode_getblob_ioctl - get the contents of a blob property value 4477c8e32cc1SDaniel Vetter * @dev: DRM device 4478c8e32cc1SDaniel Vetter * @data: ioctl data 4479c8e32cc1SDaniel Vetter * @file_priv: DRM file info 4480c8e32cc1SDaniel Vetter * 4481c8e32cc1SDaniel Vetter * This function retrieves the contents of a blob property. The value stored in 4482c8e32cc1SDaniel Vetter * an object's blob property is just a normal modeset object id. 4483c8e32cc1SDaniel Vetter * 4484c8e32cc1SDaniel Vetter * Called by the user via ioctl. 4485c8e32cc1SDaniel Vetter * 4486c8e32cc1SDaniel Vetter * Returns: 44871a498633SDaniel Vetter * Zero on success, negative errno on failure. 4488c8e32cc1SDaniel Vetter */ 4489f453ba04SDave Airlie int drm_mode_getblob_ioctl(struct drm_device *dev, 4490f453ba04SDave Airlie void *data, struct drm_file *file_priv) 4491f453ba04SDave Airlie { 4492f453ba04SDave Airlie struct drm_mode_get_blob *out_resp = data; 4493f453ba04SDave Airlie struct drm_property_blob *blob; 4494f453ba04SDave Airlie int ret = 0; 449581f6c7f8SVille Syrjälä void __user *blob_ptr; 4496f453ba04SDave Airlie 4497fb3b06c8SDave Airlie if (!drm_core_check_feature(dev, DRIVER_MODESET)) 4498fb3b06c8SDave Airlie return -EINVAL; 4499fb3b06c8SDave Airlie 4500152ef5faSDaniel Vetter blob = drm_property_lookup_blob(dev, out_resp->blob_id); 4501152ef5faSDaniel Vetter if (!blob) 4502152ef5faSDaniel Vetter return -ENOENT; 4503f453ba04SDave Airlie 4504f453ba04SDave Airlie if (out_resp->length == blob->length) { 450581f6c7f8SVille Syrjälä blob_ptr = (void __user *)(unsigned long)out_resp->data; 4506f453ba04SDave Airlie if (copy_to_user(blob_ptr, blob->data, blob->length)) { 4507f453ba04SDave Airlie ret = -EFAULT; 4508152ef5faSDaniel Vetter goto unref; 4509f453ba04SDave Airlie } 4510f453ba04SDave Airlie } 4511f453ba04SDave Airlie out_resp->length = blob->length; 4512152ef5faSDaniel Vetter unref: 4513152ef5faSDaniel Vetter drm_property_unreference_blob(blob); 4514f453ba04SDave Airlie 4515f453ba04SDave Airlie return ret; 4516f453ba04SDave Airlie } 4517f453ba04SDave Airlie 4518cc7096fbSDave Airlie /** 4519e2f5d2eaSDaniel Stone * drm_mode_createblob_ioctl - create a new blob property 4520e2f5d2eaSDaniel Stone * @dev: DRM device 4521e2f5d2eaSDaniel Stone * @data: ioctl data 4522e2f5d2eaSDaniel Stone * @file_priv: DRM file info 4523e2f5d2eaSDaniel Stone * 4524e2f5d2eaSDaniel Stone * This function creates a new blob property with user-defined values. In order 4525e2f5d2eaSDaniel Stone * to give us sensible validation and checking when creating, rather than at 4526e2f5d2eaSDaniel Stone * every potential use, we also require a type to be provided upfront. 4527e2f5d2eaSDaniel Stone * 4528e2f5d2eaSDaniel Stone * Called by the user via ioctl. 4529e2f5d2eaSDaniel Stone * 4530e2f5d2eaSDaniel Stone * Returns: 4531e2f5d2eaSDaniel Stone * Zero on success, negative errno on failure. 4532e2f5d2eaSDaniel Stone */ 4533e2f5d2eaSDaniel Stone int drm_mode_createblob_ioctl(struct drm_device *dev, 4534e2f5d2eaSDaniel Stone void *data, struct drm_file *file_priv) 4535e2f5d2eaSDaniel Stone { 4536e2f5d2eaSDaniel Stone struct drm_mode_create_blob *out_resp = data; 4537e2f5d2eaSDaniel Stone struct drm_property_blob *blob; 4538e2f5d2eaSDaniel Stone void __user *blob_ptr; 4539e2f5d2eaSDaniel Stone int ret = 0; 4540e2f5d2eaSDaniel Stone 4541e2f5d2eaSDaniel Stone if (!drm_core_check_feature(dev, DRIVER_MODESET)) 4542e2f5d2eaSDaniel Stone return -EINVAL; 4543e2f5d2eaSDaniel Stone 4544e2f5d2eaSDaniel Stone blob = drm_property_create_blob(dev, out_resp->length, NULL); 4545e2f5d2eaSDaniel Stone if (IS_ERR(blob)) 4546e2f5d2eaSDaniel Stone return PTR_ERR(blob); 4547e2f5d2eaSDaniel Stone 4548e2f5d2eaSDaniel Stone blob_ptr = (void __user *)(unsigned long)out_resp->data; 4549e2f5d2eaSDaniel Stone if (copy_from_user(blob->data, blob_ptr, out_resp->length)) { 4550e2f5d2eaSDaniel Stone ret = -EFAULT; 4551e2f5d2eaSDaniel Stone goto out_blob; 4552e2f5d2eaSDaniel Stone } 4553e2f5d2eaSDaniel Stone 4554e2f5d2eaSDaniel Stone /* Dropping the lock between create_blob and our access here is safe 4555e2f5d2eaSDaniel Stone * as only the same file_priv can remove the blob; at this point, it is 4556e2f5d2eaSDaniel Stone * not associated with any file_priv. */ 4557e2f5d2eaSDaniel Stone mutex_lock(&dev->mode_config.blob_lock); 4558e2f5d2eaSDaniel Stone out_resp->blob_id = blob->base.id; 45598731b269SManeet Singh list_add_tail(&blob->head_file, &file_priv->blobs); 4560e2f5d2eaSDaniel Stone mutex_unlock(&dev->mode_config.blob_lock); 4561e2f5d2eaSDaniel Stone 4562e2f5d2eaSDaniel Stone return 0; 4563e2f5d2eaSDaniel Stone 4564e2f5d2eaSDaniel Stone out_blob: 4565e2f5d2eaSDaniel Stone drm_property_unreference_blob(blob); 4566e2f5d2eaSDaniel Stone return ret; 4567e2f5d2eaSDaniel Stone } 4568e2f5d2eaSDaniel Stone 4569e2f5d2eaSDaniel Stone /** 4570e2f5d2eaSDaniel Stone * drm_mode_destroyblob_ioctl - destroy a user blob property 4571e2f5d2eaSDaniel Stone * @dev: DRM device 4572e2f5d2eaSDaniel Stone * @data: ioctl data 4573e2f5d2eaSDaniel Stone * @file_priv: DRM file info 4574e2f5d2eaSDaniel Stone * 4575e2f5d2eaSDaniel Stone * Destroy an existing user-defined blob property. 4576e2f5d2eaSDaniel Stone * 4577e2f5d2eaSDaniel Stone * Called by the user via ioctl. 4578e2f5d2eaSDaniel Stone * 4579e2f5d2eaSDaniel Stone * Returns: 4580e2f5d2eaSDaniel Stone * Zero on success, negative errno on failure. 4581e2f5d2eaSDaniel Stone */ 4582e2f5d2eaSDaniel Stone int drm_mode_destroyblob_ioctl(struct drm_device *dev, 4583e2f5d2eaSDaniel Stone void *data, struct drm_file *file_priv) 4584e2f5d2eaSDaniel Stone { 4585e2f5d2eaSDaniel Stone struct drm_mode_destroy_blob *out_resp = data; 4586e2f5d2eaSDaniel Stone struct drm_property_blob *blob = NULL, *bt; 4587e2f5d2eaSDaniel Stone bool found = false; 4588e2f5d2eaSDaniel Stone int ret = 0; 4589e2f5d2eaSDaniel Stone 4590e2f5d2eaSDaniel Stone if (!drm_core_check_feature(dev, DRIVER_MODESET)) 4591e2f5d2eaSDaniel Stone return -EINVAL; 4592e2f5d2eaSDaniel Stone 4593152ef5faSDaniel Vetter blob = drm_property_lookup_blob(dev, out_resp->blob_id); 4594152ef5faSDaniel Vetter if (!blob) 4595152ef5faSDaniel Vetter return -ENOENT; 4596e2f5d2eaSDaniel Stone 4597152ef5faSDaniel Vetter mutex_lock(&dev->mode_config.blob_lock); 4598e2f5d2eaSDaniel Stone /* Ensure the property was actually created by this user. */ 4599e2f5d2eaSDaniel Stone list_for_each_entry(bt, &file_priv->blobs, head_file) { 4600e2f5d2eaSDaniel Stone if (bt == blob) { 4601e2f5d2eaSDaniel Stone found = true; 4602e2f5d2eaSDaniel Stone break; 4603e2f5d2eaSDaniel Stone } 4604e2f5d2eaSDaniel Stone } 4605e2f5d2eaSDaniel Stone 4606e2f5d2eaSDaniel Stone if (!found) { 4607e2f5d2eaSDaniel Stone ret = -EPERM; 4608e2f5d2eaSDaniel Stone goto err; 4609e2f5d2eaSDaniel Stone } 4610e2f5d2eaSDaniel Stone 4611e2f5d2eaSDaniel Stone /* We must drop head_file here, because we may not be the last 4612e2f5d2eaSDaniel Stone * reference on the blob. */ 4613e2f5d2eaSDaniel Stone list_del_init(&blob->head_file); 4614e2f5d2eaSDaniel Stone mutex_unlock(&dev->mode_config.blob_lock); 4615e2f5d2eaSDaniel Stone 4616152ef5faSDaniel Vetter /* One reference from lookup, and one from the filp. */ 4617152ef5faSDaniel Vetter drm_property_unreference_blob(blob); 4618152ef5faSDaniel Vetter drm_property_unreference_blob(blob); 4619152ef5faSDaniel Vetter 4620e2f5d2eaSDaniel Stone return 0; 4621e2f5d2eaSDaniel Stone 4622e2f5d2eaSDaniel Stone err: 4623e2f5d2eaSDaniel Stone mutex_unlock(&dev->mode_config.blob_lock); 4624152ef5faSDaniel Vetter drm_property_unreference_blob(blob); 4625152ef5faSDaniel Vetter 4626e2f5d2eaSDaniel Stone return ret; 4627e2f5d2eaSDaniel Stone } 4628e2f5d2eaSDaniel Stone 4629e2f5d2eaSDaniel Stone /** 4630cc7096fbSDave Airlie * drm_mode_connector_set_path_property - set tile property on connector 4631cc7096fbSDave Airlie * @connector: connector to set property on. 4632d2ed3436SDaniel Stone * @path: path to use for property; must not be NULL. 4633cc7096fbSDave Airlie * 4634cc7096fbSDave Airlie * This creates a property to expose to userspace to specify a 4635cc7096fbSDave Airlie * connector path. This is mainly used for DisplayPort MST where 4636cc7096fbSDave Airlie * connectors have a topology and we want to allow userspace to give 4637cc7096fbSDave Airlie * them more meaningful names. 4638cc7096fbSDave Airlie * 4639cc7096fbSDave Airlie * Returns: 46401a498633SDaniel Vetter * Zero on success, negative errno on failure. 4641cc7096fbSDave Airlie */ 464243aba7ebSDave Airlie int drm_mode_connector_set_path_property(struct drm_connector *connector, 464312e6cecdSThierry Reding const char *path) 464443aba7ebSDave Airlie { 464543aba7ebSDave Airlie struct drm_device *dev = connector->dev; 4646ecbbe59bSThierry Reding int ret; 464743aba7ebSDave Airlie 4648d2ed3436SDaniel Stone ret = drm_property_replace_global_blob(dev, 4649d2ed3436SDaniel Stone &connector->path_blob_ptr, 4650d2ed3436SDaniel Stone strlen(path) + 1, 4651d2ed3436SDaniel Stone path, 4652d2ed3436SDaniel Stone &connector->base, 4653d2ed3436SDaniel Stone dev->mode_config.path_property); 465443aba7ebSDave Airlie return ret; 465543aba7ebSDave Airlie } 465643aba7ebSDave Airlie EXPORT_SYMBOL(drm_mode_connector_set_path_property); 465743aba7ebSDave Airlie 4658c8e32cc1SDaniel Vetter /** 46596f134d7bSDave Airlie * drm_mode_connector_set_tile_property - set tile property on connector 46606f134d7bSDave Airlie * @connector: connector to set property on. 46616f134d7bSDave Airlie * 46626f134d7bSDave Airlie * This looks up the tile information for a connector, and creates a 46636f134d7bSDave Airlie * property for userspace to parse if it exists. The property is of 46646f134d7bSDave Airlie * the form of 8 integers using ':' as a separator. 46656f134d7bSDave Airlie * 46666f134d7bSDave Airlie * Returns: 46676f134d7bSDave Airlie * Zero on success, errno on failure. 46686f134d7bSDave Airlie */ 46696f134d7bSDave Airlie int drm_mode_connector_set_tile_property(struct drm_connector *connector) 46706f134d7bSDave Airlie { 46716f134d7bSDave Airlie struct drm_device *dev = connector->dev; 46726f134d7bSDave Airlie char tile[256]; 4673d2ed3436SDaniel Stone int ret; 46746f134d7bSDave Airlie 46756f134d7bSDave Airlie if (!connector->has_tile) { 4676d2ed3436SDaniel Stone ret = drm_property_replace_global_blob(dev, 4677d2ed3436SDaniel Stone &connector->tile_blob_ptr, 4678d2ed3436SDaniel Stone 0, 4679d2ed3436SDaniel Stone NULL, 4680d2ed3436SDaniel Stone &connector->base, 4681d2ed3436SDaniel Stone dev->mode_config.tile_property); 46826f134d7bSDave Airlie return ret; 46836f134d7bSDave Airlie } 46846f134d7bSDave Airlie 46856f134d7bSDave Airlie snprintf(tile, 256, "%d:%d:%d:%d:%d:%d:%d:%d", 46866f134d7bSDave Airlie connector->tile_group->id, connector->tile_is_single_monitor, 46876f134d7bSDave Airlie connector->num_h_tile, connector->num_v_tile, 46886f134d7bSDave Airlie connector->tile_h_loc, connector->tile_v_loc, 46896f134d7bSDave Airlie connector->tile_h_size, connector->tile_v_size); 46906f134d7bSDave Airlie 4691d2ed3436SDaniel Stone ret = drm_property_replace_global_blob(dev, 4692d2ed3436SDaniel Stone &connector->tile_blob_ptr, 4693d2ed3436SDaniel Stone strlen(tile) + 1, 4694d2ed3436SDaniel Stone tile, 4695d2ed3436SDaniel Stone &connector->base, 4696d2ed3436SDaniel Stone dev->mode_config.tile_property); 46976f134d7bSDave Airlie return ret; 46986f134d7bSDave Airlie } 46996f134d7bSDave Airlie EXPORT_SYMBOL(drm_mode_connector_set_tile_property); 47006f134d7bSDave Airlie 47016f134d7bSDave Airlie /** 4702c8e32cc1SDaniel Vetter * drm_mode_connector_update_edid_property - update the edid property of a connector 4703c8e32cc1SDaniel Vetter * @connector: drm connector 4704c8e32cc1SDaniel Vetter * @edid: new value of the edid property 4705c8e32cc1SDaniel Vetter * 4706c8e32cc1SDaniel Vetter * This function creates a new blob modeset object and assigns its id to the 4707c8e32cc1SDaniel Vetter * connector's edid property. 4708c8e32cc1SDaniel Vetter * 4709c8e32cc1SDaniel Vetter * Returns: 47101a498633SDaniel Vetter * Zero on success, negative errno on failure. 4711c8e32cc1SDaniel Vetter */ 4712f453ba04SDave Airlie int drm_mode_connector_update_edid_property(struct drm_connector *connector, 471312e6cecdSThierry Reding const struct edid *edid) 4714f453ba04SDave Airlie { 4715f453ba04SDave Airlie struct drm_device *dev = connector->dev; 4716d2ed3436SDaniel Stone size_t size = 0; 4717ecbbe59bSThierry Reding int ret; 4718f453ba04SDave Airlie 47194cf2b281SThomas Wood /* ignore requests to set edid when overridden */ 47204cf2b281SThomas Wood if (connector->override_edid) 47214cf2b281SThomas Wood return 0; 47224cf2b281SThomas Wood 4723d2ed3436SDaniel Stone if (edid) 4724e24ff467SShixin Zeng size = EDID_LENGTH * (1 + edid->extensions); 4725f453ba04SDave Airlie 4726d2ed3436SDaniel Stone ret = drm_property_replace_global_blob(dev, 4727d2ed3436SDaniel Stone &connector->edid_blob_ptr, 4728d2ed3436SDaniel Stone size, 4729d2ed3436SDaniel Stone edid, 4730d2ed3436SDaniel Stone &connector->base, 4731d2ed3436SDaniel Stone dev->mode_config.edid_property); 4732f453ba04SDave Airlie return ret; 4733f453ba04SDave Airlie } 4734f453ba04SDave Airlie EXPORT_SYMBOL(drm_mode_connector_update_edid_property); 4735f453ba04SDave Airlie 47363843e71fSRob Clark /* Some properties could refer to dynamic refcnt'd objects, or things that 47373843e71fSRob Clark * need special locking to handle lifetime issues (ie. to ensure the prop 47383843e71fSRob Clark * value doesn't become invalid part way through the property update due to 47393843e71fSRob Clark * race). The value returned by reference via 'obj' should be passed back 47403843e71fSRob Clark * to drm_property_change_valid_put() after the property is set (and the 47413843e71fSRob Clark * object to which the property is attached has a chance to take it's own 47423843e71fSRob Clark * reference). 47433843e71fSRob Clark */ 4744d34f20d6SRob Clark bool drm_property_change_valid_get(struct drm_property *property, 47453843e71fSRob Clark uint64_t value, struct drm_mode_object **ref) 474626a34815SPaulo Zanoni { 47472ca651d1SThierry Reding int i; 47482ca651d1SThierry Reding 474926a34815SPaulo Zanoni if (property->flags & DRM_MODE_PROP_IMMUTABLE) 475026a34815SPaulo Zanoni return false; 47515ea22f24SRob Clark 47523843e71fSRob Clark *ref = NULL; 47533843e71fSRob Clark 47545ea22f24SRob Clark if (drm_property_type_is(property, DRM_MODE_PROP_RANGE)) { 475526a34815SPaulo Zanoni if (value < property->values[0] || value > property->values[1]) 475626a34815SPaulo Zanoni return false; 475726a34815SPaulo Zanoni return true; 4758ebc44cf3SRob Clark } else if (drm_property_type_is(property, DRM_MODE_PROP_SIGNED_RANGE)) { 4759ebc44cf3SRob Clark int64_t svalue = U642I64(value); 47604dfd909fSThierry Reding 4761ebc44cf3SRob Clark if (svalue < U642I64(property->values[0]) || 4762ebc44cf3SRob Clark svalue > U642I64(property->values[1])) 4763ebc44cf3SRob Clark return false; 4764ebc44cf3SRob Clark return true; 47655ea22f24SRob Clark } else if (drm_property_type_is(property, DRM_MODE_PROP_BITMASK)) { 4766592c20eeSVille Syrjälä uint64_t valid_mask = 0; 47674dfd909fSThierry Reding 476849e27545SRob Clark for (i = 0; i < property->num_values; i++) 476949e27545SRob Clark valid_mask |= (1ULL << property->values[i]); 477049e27545SRob Clark return !(value & ~valid_mask); 47715ea22f24SRob Clark } else if (drm_property_type_is(property, DRM_MODE_PROP_BLOB)) { 47726bcacf51SDaniel Stone struct drm_property_blob *blob; 47736bcacf51SDaniel Stone 47746bcacf51SDaniel Stone if (value == 0) 4775c4a56750SVille Syrjälä return true; 47766bcacf51SDaniel Stone 47776bcacf51SDaniel Stone blob = drm_property_lookup_blob(property->dev, value); 47786bcacf51SDaniel Stone if (blob) { 47796bcacf51SDaniel Stone *ref = &blob->base; 47806bcacf51SDaniel Stone return true; 47816bcacf51SDaniel Stone } else { 47826bcacf51SDaniel Stone return false; 47836bcacf51SDaniel Stone } 478498f75de4SRob Clark } else if (drm_property_type_is(property, DRM_MODE_PROP_OBJECT)) { 478598f75de4SRob Clark /* a zero value for an object property translates to null: */ 478698f75de4SRob Clark if (value == 0) 478798f75de4SRob Clark return true; 47883843e71fSRob Clark 47891e8985a8STomi Valkeinen *ref = _object_find(property->dev, value, property->values[0]); 47901e8985a8STomi Valkeinen return *ref != NULL; 47913843e71fSRob Clark } 47922ca651d1SThierry Reding 479326a34815SPaulo Zanoni for (i = 0; i < property->num_values; i++) 479426a34815SPaulo Zanoni if (property->values[i] == value) 479526a34815SPaulo Zanoni return true; 479626a34815SPaulo Zanoni return false; 479726a34815SPaulo Zanoni } 479826a34815SPaulo Zanoni 4799d34f20d6SRob Clark void drm_property_change_valid_put(struct drm_property *property, 48003843e71fSRob Clark struct drm_mode_object *ref) 48013843e71fSRob Clark { 48023843e71fSRob Clark if (!ref) 48033843e71fSRob Clark return; 48043843e71fSRob Clark 48053843e71fSRob Clark if (drm_property_type_is(property, DRM_MODE_PROP_OBJECT)) { 4806027b3f8bSDave Airlie drm_mode_object_unreference(ref); 4807da9b2a38SDaniel Stone } else if (drm_property_type_is(property, DRM_MODE_PROP_BLOB)) 4808da9b2a38SDaniel Stone drm_property_unreference_blob(obj_to_blob(ref)); 48093843e71fSRob Clark } 48103843e71fSRob Clark 4811c8e32cc1SDaniel Vetter /** 4812c8e32cc1SDaniel Vetter * drm_mode_connector_property_set_ioctl - set the current value of a connector property 4813c8e32cc1SDaniel Vetter * @dev: DRM device 4814c8e32cc1SDaniel Vetter * @data: ioctl data 4815c8e32cc1SDaniel Vetter * @file_priv: DRM file info 4816c8e32cc1SDaniel Vetter * 4817c8e32cc1SDaniel Vetter * This function sets the current value for a connectors's property. It also 4818c8e32cc1SDaniel Vetter * calls into a driver's ->set_property callback to update the hardware state 4819c8e32cc1SDaniel Vetter * 4820c8e32cc1SDaniel Vetter * Called by the user via ioctl. 4821c8e32cc1SDaniel Vetter * 4822c8e32cc1SDaniel Vetter * Returns: 48231a498633SDaniel Vetter * Zero on success, negative errno on failure. 4824c8e32cc1SDaniel Vetter */ 4825f453ba04SDave Airlie int drm_mode_connector_property_set_ioctl(struct drm_device *dev, 4826f453ba04SDave Airlie void *data, struct drm_file *file_priv) 4827f453ba04SDave Airlie { 48280057d8ddSPaulo Zanoni struct drm_mode_connector_set_property *conn_set_prop = data; 48290057d8ddSPaulo Zanoni struct drm_mode_obj_set_property obj_set_prop = { 48300057d8ddSPaulo Zanoni .value = conn_set_prop->value, 48310057d8ddSPaulo Zanoni .prop_id = conn_set_prop->prop_id, 48320057d8ddSPaulo Zanoni .obj_id = conn_set_prop->connector_id, 48330057d8ddSPaulo Zanoni .obj_type = DRM_MODE_OBJECT_CONNECTOR 48340057d8ddSPaulo Zanoni }; 4835f453ba04SDave Airlie 48360057d8ddSPaulo Zanoni /* It does all the locking and checking we need */ 48370057d8ddSPaulo Zanoni return drm_mode_obj_set_property_ioctl(dev, &obj_set_prop, file_priv); 4838f453ba04SDave Airlie } 4839f453ba04SDave Airlie 4840c543188aSPaulo Zanoni static int drm_mode_connector_set_obj_prop(struct drm_mode_object *obj, 4841c543188aSPaulo Zanoni struct drm_property *property, 4842c543188aSPaulo Zanoni uint64_t value) 4843c543188aSPaulo Zanoni { 4844c543188aSPaulo Zanoni int ret = -EINVAL; 4845c543188aSPaulo Zanoni struct drm_connector *connector = obj_to_connector(obj); 4846c543188aSPaulo Zanoni 4847c543188aSPaulo Zanoni /* Do DPMS ourselves */ 4848c543188aSPaulo Zanoni if (property == connector->dev->mode_config.dpms_property) { 48499a69a9acSMaarten Lankhorst ret = (*connector->funcs->dpms)(connector, (int)value); 4850c543188aSPaulo Zanoni } else if (connector->funcs->set_property) 4851c543188aSPaulo Zanoni ret = connector->funcs->set_property(connector, property, value); 4852c543188aSPaulo Zanoni 4853c543188aSPaulo Zanoni /* store the property value if successful */ 4854c543188aSPaulo Zanoni if (!ret) 485558495563SRob Clark drm_object_property_set_value(&connector->base, property, value); 4856c543188aSPaulo Zanoni return ret; 4857c543188aSPaulo Zanoni } 4858c543188aSPaulo Zanoni 4859bffd9de0SPaulo Zanoni static int drm_mode_crtc_set_obj_prop(struct drm_mode_object *obj, 4860bffd9de0SPaulo Zanoni struct drm_property *property, 4861bffd9de0SPaulo Zanoni uint64_t value) 4862bffd9de0SPaulo Zanoni { 4863bffd9de0SPaulo Zanoni int ret = -EINVAL; 4864bffd9de0SPaulo Zanoni struct drm_crtc *crtc = obj_to_crtc(obj); 4865bffd9de0SPaulo Zanoni 4866bffd9de0SPaulo Zanoni if (crtc->funcs->set_property) 4867bffd9de0SPaulo Zanoni ret = crtc->funcs->set_property(crtc, property, value); 4868bffd9de0SPaulo Zanoni if (!ret) 4869bffd9de0SPaulo Zanoni drm_object_property_set_value(obj, property, value); 4870bffd9de0SPaulo Zanoni 4871bffd9de0SPaulo Zanoni return ret; 4872bffd9de0SPaulo Zanoni } 4873bffd9de0SPaulo Zanoni 48743a5f87c2SThomas Wood /** 48753a5f87c2SThomas Wood * drm_mode_plane_set_obj_prop - set the value of a property 48763a5f87c2SThomas Wood * @plane: drm plane object to set property value for 48773a5f87c2SThomas Wood * @property: property to set 48783a5f87c2SThomas Wood * @value: value the property should be set to 48793a5f87c2SThomas Wood * 48803a5f87c2SThomas Wood * This functions sets a given property on a given plane object. This function 48813a5f87c2SThomas Wood * calls the driver's ->set_property callback and changes the software state of 48823a5f87c2SThomas Wood * the property if the callback succeeds. 48833a5f87c2SThomas Wood * 48843a5f87c2SThomas Wood * Returns: 48853a5f87c2SThomas Wood * Zero on success, error code on failure. 48863a5f87c2SThomas Wood */ 48873a5f87c2SThomas Wood int drm_mode_plane_set_obj_prop(struct drm_plane *plane, 48884d93914aSRob Clark struct drm_property *property, 48894d93914aSRob Clark uint64_t value) 48904d93914aSRob Clark { 48914d93914aSRob Clark int ret = -EINVAL; 48923a5f87c2SThomas Wood struct drm_mode_object *obj = &plane->base; 48934d93914aSRob Clark 48944d93914aSRob Clark if (plane->funcs->set_property) 48954d93914aSRob Clark ret = plane->funcs->set_property(plane, property, value); 48964d93914aSRob Clark if (!ret) 48974d93914aSRob Clark drm_object_property_set_value(obj, property, value); 48984d93914aSRob Clark 48994d93914aSRob Clark return ret; 49004d93914aSRob Clark } 49013a5f87c2SThomas Wood EXPORT_SYMBOL(drm_mode_plane_set_obj_prop); 49024d93914aSRob Clark 4903c8e32cc1SDaniel Vetter /** 49041a498633SDaniel Vetter * drm_mode_obj_get_properties_ioctl - get the current value of a object's property 4905c8e32cc1SDaniel Vetter * @dev: DRM device 4906c8e32cc1SDaniel Vetter * @data: ioctl data 4907c8e32cc1SDaniel Vetter * @file_priv: DRM file info 4908c8e32cc1SDaniel Vetter * 4909c8e32cc1SDaniel Vetter * This function retrieves the current value for an object's property. Compared 4910c8e32cc1SDaniel Vetter * to the connector specific ioctl this one is extended to also work on crtc and 4911c8e32cc1SDaniel Vetter * plane objects. 4912c8e32cc1SDaniel Vetter * 4913c8e32cc1SDaniel Vetter * Called by the user via ioctl. 4914c8e32cc1SDaniel Vetter * 4915c8e32cc1SDaniel Vetter * Returns: 49161a498633SDaniel Vetter * Zero on success, negative errno on failure. 4917c8e32cc1SDaniel Vetter */ 4918c543188aSPaulo Zanoni int drm_mode_obj_get_properties_ioctl(struct drm_device *dev, void *data, 4919c543188aSPaulo Zanoni struct drm_file *file_priv) 4920c543188aSPaulo Zanoni { 4921c543188aSPaulo Zanoni struct drm_mode_obj_get_properties *arg = data; 4922c543188aSPaulo Zanoni struct drm_mode_object *obj; 4923c543188aSPaulo Zanoni int ret = 0; 4924c543188aSPaulo Zanoni 4925c543188aSPaulo Zanoni if (!drm_core_check_feature(dev, DRIVER_MODESET)) 4926c543188aSPaulo Zanoni return -EINVAL; 4927c543188aSPaulo Zanoni 492884849903SDaniel Vetter drm_modeset_lock_all(dev); 4929c543188aSPaulo Zanoni 4930c543188aSPaulo Zanoni obj = drm_mode_object_find(dev, arg->obj_id, arg->obj_type); 4931c543188aSPaulo Zanoni if (!obj) { 4932f27657f2SVille Syrjälä ret = -ENOENT; 4933c543188aSPaulo Zanoni goto out; 4934c543188aSPaulo Zanoni } 4935c543188aSPaulo Zanoni if (!obj->properties) { 4936c543188aSPaulo Zanoni ret = -EINVAL; 49371649c33bSDaniel Vetter goto out_unref; 4938c543188aSPaulo Zanoni } 4939c543188aSPaulo Zanoni 494088a48e29SRob Clark ret = get_properties(obj, file_priv->atomic, 494195cbf110SRob Clark (uint32_t __user *)(unsigned long)(arg->props_ptr), 494295cbf110SRob Clark (uint64_t __user *)(unsigned long)(arg->prop_values_ptr), 494395cbf110SRob Clark &arg->count_props); 4944c543188aSPaulo Zanoni 49451649c33bSDaniel Vetter out_unref: 49461649c33bSDaniel Vetter drm_mode_object_unreference(obj); 4947c543188aSPaulo Zanoni out: 494884849903SDaniel Vetter drm_modeset_unlock_all(dev); 4949c543188aSPaulo Zanoni return ret; 4950c543188aSPaulo Zanoni } 4951c543188aSPaulo Zanoni 4952c8e32cc1SDaniel Vetter /** 4953c8e32cc1SDaniel Vetter * drm_mode_obj_set_property_ioctl - set the current value of an object's property 4954c8e32cc1SDaniel Vetter * @dev: DRM device 4955c8e32cc1SDaniel Vetter * @data: ioctl data 4956c8e32cc1SDaniel Vetter * @file_priv: DRM file info 4957c8e32cc1SDaniel Vetter * 4958c8e32cc1SDaniel Vetter * This function sets the current value for an object's property. It also calls 4959c8e32cc1SDaniel Vetter * into a driver's ->set_property callback to update the hardware state. 4960c8e32cc1SDaniel Vetter * Compared to the connector specific ioctl this one is extended to also work on 4961c8e32cc1SDaniel Vetter * crtc and plane objects. 4962c8e32cc1SDaniel Vetter * 4963c8e32cc1SDaniel Vetter * Called by the user via ioctl. 4964c8e32cc1SDaniel Vetter * 4965c8e32cc1SDaniel Vetter * Returns: 49661a498633SDaniel Vetter * Zero on success, negative errno on failure. 4967c8e32cc1SDaniel Vetter */ 4968c543188aSPaulo Zanoni int drm_mode_obj_set_property_ioctl(struct drm_device *dev, void *data, 4969c543188aSPaulo Zanoni struct drm_file *file_priv) 4970c543188aSPaulo Zanoni { 4971c543188aSPaulo Zanoni struct drm_mode_obj_set_property *arg = data; 4972c543188aSPaulo Zanoni struct drm_mode_object *arg_obj; 4973c543188aSPaulo Zanoni struct drm_mode_object *prop_obj; 4974c543188aSPaulo Zanoni struct drm_property *property; 49753843e71fSRob Clark int i, ret = -EINVAL; 49763843e71fSRob Clark struct drm_mode_object *ref; 4977c543188aSPaulo Zanoni 4978c543188aSPaulo Zanoni if (!drm_core_check_feature(dev, DRIVER_MODESET)) 4979c543188aSPaulo Zanoni return -EINVAL; 4980c543188aSPaulo Zanoni 498184849903SDaniel Vetter drm_modeset_lock_all(dev); 4982c543188aSPaulo Zanoni 4983c543188aSPaulo Zanoni arg_obj = drm_mode_object_find(dev, arg->obj_id, arg->obj_type); 4984f27657f2SVille Syrjälä if (!arg_obj) { 4985f27657f2SVille Syrjälä ret = -ENOENT; 4986c543188aSPaulo Zanoni goto out; 4987f27657f2SVille Syrjälä } 4988c543188aSPaulo Zanoni if (!arg_obj->properties) 49891649c33bSDaniel Vetter goto out_unref; 4990c543188aSPaulo Zanoni 49917f88a9beSPaulo Zanoni for (i = 0; i < arg_obj->properties->count; i++) 4992b17cd757SRob Clark if (arg_obj->properties->properties[i]->base.id == arg->prop_id) 4993c543188aSPaulo Zanoni break; 4994c543188aSPaulo Zanoni 49957f88a9beSPaulo Zanoni if (i == arg_obj->properties->count) 49961649c33bSDaniel Vetter goto out_unref; 4997c543188aSPaulo Zanoni 4998c543188aSPaulo Zanoni prop_obj = drm_mode_object_find(dev, arg->prop_id, 4999c543188aSPaulo Zanoni DRM_MODE_OBJECT_PROPERTY); 5000f27657f2SVille Syrjälä if (!prop_obj) { 5001f27657f2SVille Syrjälä ret = -ENOENT; 50021649c33bSDaniel Vetter goto out_unref; 5003f27657f2SVille Syrjälä } 5004c543188aSPaulo Zanoni property = obj_to_property(prop_obj); 5005c543188aSPaulo Zanoni 50063843e71fSRob Clark if (!drm_property_change_valid_get(property, arg->value, &ref)) 5007b164d31fSDave Airlie goto out_unref; 5008c543188aSPaulo Zanoni 5009c543188aSPaulo Zanoni switch (arg_obj->type) { 5010c543188aSPaulo Zanoni case DRM_MODE_OBJECT_CONNECTOR: 5011c543188aSPaulo Zanoni ret = drm_mode_connector_set_obj_prop(arg_obj, property, 5012c543188aSPaulo Zanoni arg->value); 5013c543188aSPaulo Zanoni break; 5014bffd9de0SPaulo Zanoni case DRM_MODE_OBJECT_CRTC: 5015bffd9de0SPaulo Zanoni ret = drm_mode_crtc_set_obj_prop(arg_obj, property, arg->value); 5016bffd9de0SPaulo Zanoni break; 50174d93914aSRob Clark case DRM_MODE_OBJECT_PLANE: 50183a5f87c2SThomas Wood ret = drm_mode_plane_set_obj_prop(obj_to_plane(arg_obj), 50193a5f87c2SThomas Wood property, arg->value); 50204d93914aSRob Clark break; 5021c543188aSPaulo Zanoni } 5022c543188aSPaulo Zanoni 50233843e71fSRob Clark drm_property_change_valid_put(property, ref); 50243843e71fSRob Clark 50251649c33bSDaniel Vetter out_unref: 50261649c33bSDaniel Vetter drm_mode_object_unreference(arg_obj); 5027c543188aSPaulo Zanoni out: 502884849903SDaniel Vetter drm_modeset_unlock_all(dev); 5029c543188aSPaulo Zanoni return ret; 5030c543188aSPaulo Zanoni } 5031c543188aSPaulo Zanoni 5032c8e32cc1SDaniel Vetter /** 5033c8e32cc1SDaniel Vetter * drm_mode_connector_attach_encoder - attach a connector to an encoder 5034c8e32cc1SDaniel Vetter * @connector: connector to attach 5035c8e32cc1SDaniel Vetter * @encoder: encoder to attach @connector to 5036c8e32cc1SDaniel Vetter * 5037c8e32cc1SDaniel Vetter * This function links up a connector to an encoder. Note that the routing 5038c8e32cc1SDaniel Vetter * restrictions between encoders and crtcs are exposed to userspace through the 5039c8e32cc1SDaniel Vetter * possible_clones and possible_crtcs bitmasks. 5040c8e32cc1SDaniel Vetter * 5041c8e32cc1SDaniel Vetter * Returns: 50421a498633SDaniel Vetter * Zero on success, negative errno on failure. 5043c8e32cc1SDaniel Vetter */ 5044f453ba04SDave Airlie int drm_mode_connector_attach_encoder(struct drm_connector *connector, 5045f453ba04SDave Airlie struct drm_encoder *encoder) 5046f453ba04SDave Airlie { 5047f453ba04SDave Airlie int i; 5048f453ba04SDave Airlie 5049eb47fe80SThierry Reding /* 5050eb47fe80SThierry Reding * In the past, drivers have attempted to model the static association 5051eb47fe80SThierry Reding * of connector to encoder in simple connector/encoder devices using a 5052eb47fe80SThierry Reding * direct assignment of connector->encoder = encoder. This connection 5053eb47fe80SThierry Reding * is a logical one and the responsibility of the core, so drivers are 5054eb47fe80SThierry Reding * expected not to mess with this. 5055eb47fe80SThierry Reding * 5056eb47fe80SThierry Reding * Note that the error return should've been enough here, but a large 5057eb47fe80SThierry Reding * majority of drivers ignores the return value, so add in a big WARN 5058eb47fe80SThierry Reding * to get people's attention. 5059eb47fe80SThierry Reding */ 5060eb47fe80SThierry Reding if (WARN_ON(connector->encoder)) 5061eb47fe80SThierry Reding return -EINVAL; 5062eb47fe80SThierry Reding 5063f453ba04SDave Airlie for (i = 0; i < DRM_CONNECTOR_MAX_ENCODER; i++) { 5064f453ba04SDave Airlie if (connector->encoder_ids[i] == 0) { 5065f453ba04SDave Airlie connector->encoder_ids[i] = encoder->base.id; 5066f453ba04SDave Airlie return 0; 5067f453ba04SDave Airlie } 5068f453ba04SDave Airlie } 5069f453ba04SDave Airlie return -ENOMEM; 5070f453ba04SDave Airlie } 5071f453ba04SDave Airlie EXPORT_SYMBOL(drm_mode_connector_attach_encoder); 5072f453ba04SDave Airlie 5073c8e32cc1SDaniel Vetter /** 5074c8e32cc1SDaniel Vetter * drm_mode_crtc_set_gamma_size - set the gamma table size 5075c8e32cc1SDaniel Vetter * @crtc: CRTC to set the gamma table size for 5076c8e32cc1SDaniel Vetter * @gamma_size: size of the gamma table 5077c8e32cc1SDaniel Vetter * 5078c8e32cc1SDaniel Vetter * Drivers which support gamma tables should set this to the supported gamma 5079c8e32cc1SDaniel Vetter * table size when initializing the CRTC. Currently the drm core only supports a 5080c8e32cc1SDaniel Vetter * fixed gamma table size. 5081c8e32cc1SDaniel Vetter * 5082c8e32cc1SDaniel Vetter * Returns: 50831a498633SDaniel Vetter * Zero on success, negative errno on failure. 5084c8e32cc1SDaniel Vetter */ 50854cae5b84SSascha Hauer int drm_mode_crtc_set_gamma_size(struct drm_crtc *crtc, 5086f453ba04SDave Airlie int gamma_size) 5087f453ba04SDave Airlie { 5088cf48e292SDaniel Vetter uint16_t *r_base, *g_base, *b_base; 5089cf48e292SDaniel Vetter int i; 5090cf48e292SDaniel Vetter 5091f453ba04SDave Airlie crtc->gamma_size = gamma_size; 5092f453ba04SDave Airlie 5093bd3f0ff9SThierry Reding crtc->gamma_store = kcalloc(gamma_size, sizeof(uint16_t) * 3, 5094bd3f0ff9SThierry Reding GFP_KERNEL); 5095f453ba04SDave Airlie if (!crtc->gamma_store) { 5096f453ba04SDave Airlie crtc->gamma_size = 0; 50974cae5b84SSascha Hauer return -ENOMEM; 5098f453ba04SDave Airlie } 5099f453ba04SDave Airlie 5100cf48e292SDaniel Vetter r_base = crtc->gamma_store; 5101cf48e292SDaniel Vetter g_base = r_base + gamma_size; 5102cf48e292SDaniel Vetter b_base = g_base + gamma_size; 5103cf48e292SDaniel Vetter for (i = 0; i < gamma_size; i++) { 5104cf48e292SDaniel Vetter r_base[i] = i << 8; 5105cf48e292SDaniel Vetter g_base[i] = i << 8; 5106cf48e292SDaniel Vetter b_base[i] = i << 8; 5107cf48e292SDaniel Vetter } 5108cf48e292SDaniel Vetter 5109cf48e292SDaniel Vetter 51104cae5b84SSascha Hauer return 0; 5111f453ba04SDave Airlie } 5112f453ba04SDave Airlie EXPORT_SYMBOL(drm_mode_crtc_set_gamma_size); 5113f453ba04SDave Airlie 5114c8e32cc1SDaniel Vetter /** 5115c8e32cc1SDaniel Vetter * drm_mode_gamma_set_ioctl - set the gamma table 5116c8e32cc1SDaniel Vetter * @dev: DRM device 5117c8e32cc1SDaniel Vetter * @data: ioctl data 5118c8e32cc1SDaniel Vetter * @file_priv: DRM file info 5119c8e32cc1SDaniel Vetter * 5120c8e32cc1SDaniel Vetter * Set the gamma table of a CRTC to the one passed in by the user. Userspace can 5121c8e32cc1SDaniel Vetter * inquire the required gamma table size through drm_mode_gamma_get_ioctl. 5122c8e32cc1SDaniel Vetter * 5123c8e32cc1SDaniel Vetter * Called by the user via ioctl. 5124c8e32cc1SDaniel Vetter * 5125c8e32cc1SDaniel Vetter * Returns: 51261a498633SDaniel Vetter * Zero on success, negative errno on failure. 5127c8e32cc1SDaniel Vetter */ 5128f453ba04SDave Airlie int drm_mode_gamma_set_ioctl(struct drm_device *dev, 5129f453ba04SDave Airlie void *data, struct drm_file *file_priv) 5130f453ba04SDave Airlie { 5131f453ba04SDave Airlie struct drm_mode_crtc_lut *crtc_lut = data; 5132f453ba04SDave Airlie struct drm_crtc *crtc; 5133f453ba04SDave Airlie void *r_base, *g_base, *b_base; 5134f453ba04SDave Airlie int size; 5135f453ba04SDave Airlie int ret = 0; 5136f453ba04SDave Airlie 5137fb3b06c8SDave Airlie if (!drm_core_check_feature(dev, DRIVER_MODESET)) 5138fb3b06c8SDave Airlie return -EINVAL; 5139fb3b06c8SDave Airlie 514084849903SDaniel Vetter drm_modeset_lock_all(dev); 5141a2b34e22SRob Clark crtc = drm_crtc_find(dev, crtc_lut->crtc_id); 5142a2b34e22SRob Clark if (!crtc) { 5143f27657f2SVille Syrjälä ret = -ENOENT; 5144f453ba04SDave Airlie goto out; 5145f453ba04SDave Airlie } 5146f453ba04SDave Airlie 5147ebe0f244SLaurent Pinchart if (crtc->funcs->gamma_set == NULL) { 5148ebe0f244SLaurent Pinchart ret = -ENOSYS; 5149ebe0f244SLaurent Pinchart goto out; 5150ebe0f244SLaurent Pinchart } 5151ebe0f244SLaurent Pinchart 5152f453ba04SDave Airlie /* memcpy into gamma store */ 5153f453ba04SDave Airlie if (crtc_lut->gamma_size != crtc->gamma_size) { 5154f453ba04SDave Airlie ret = -EINVAL; 5155f453ba04SDave Airlie goto out; 5156f453ba04SDave Airlie } 5157f453ba04SDave Airlie 5158f453ba04SDave Airlie size = crtc_lut->gamma_size * (sizeof(uint16_t)); 5159f453ba04SDave Airlie r_base = crtc->gamma_store; 5160f453ba04SDave Airlie if (copy_from_user(r_base, (void __user *)(unsigned long)crtc_lut->red, size)) { 5161f453ba04SDave Airlie ret = -EFAULT; 5162f453ba04SDave Airlie goto out; 5163f453ba04SDave Airlie } 5164f453ba04SDave Airlie 5165f453ba04SDave Airlie g_base = r_base + size; 5166f453ba04SDave Airlie if (copy_from_user(g_base, (void __user *)(unsigned long)crtc_lut->green, size)) { 5167f453ba04SDave Airlie ret = -EFAULT; 5168f453ba04SDave Airlie goto out; 5169f453ba04SDave Airlie } 5170f453ba04SDave Airlie 5171f453ba04SDave Airlie b_base = g_base + size; 5172f453ba04SDave Airlie if (copy_from_user(b_base, (void __user *)(unsigned long)crtc_lut->blue, size)) { 5173f453ba04SDave Airlie ret = -EFAULT; 5174f453ba04SDave Airlie goto out; 5175f453ba04SDave Airlie } 5176f453ba04SDave Airlie 51777ea77283SMaarten Lankhorst ret = crtc->funcs->gamma_set(crtc, r_base, g_base, b_base, crtc->gamma_size); 5178f453ba04SDave Airlie 5179f453ba04SDave Airlie out: 518084849903SDaniel Vetter drm_modeset_unlock_all(dev); 5181f453ba04SDave Airlie return ret; 5182f453ba04SDave Airlie 5183f453ba04SDave Airlie } 5184f453ba04SDave Airlie 5185c8e32cc1SDaniel Vetter /** 5186c8e32cc1SDaniel Vetter * drm_mode_gamma_get_ioctl - get the gamma table 5187c8e32cc1SDaniel Vetter * @dev: DRM device 5188c8e32cc1SDaniel Vetter * @data: ioctl data 5189c8e32cc1SDaniel Vetter * @file_priv: DRM file info 5190c8e32cc1SDaniel Vetter * 5191c8e32cc1SDaniel Vetter * Copy the current gamma table into the storage provided. This also provides 5192c8e32cc1SDaniel Vetter * the gamma table size the driver expects, which can be used to size the 5193c8e32cc1SDaniel Vetter * allocated storage. 5194c8e32cc1SDaniel Vetter * 5195c8e32cc1SDaniel Vetter * Called by the user via ioctl. 5196c8e32cc1SDaniel Vetter * 5197c8e32cc1SDaniel Vetter * Returns: 51981a498633SDaniel Vetter * Zero on success, negative errno on failure. 5199c8e32cc1SDaniel Vetter */ 5200f453ba04SDave Airlie int drm_mode_gamma_get_ioctl(struct drm_device *dev, 5201f453ba04SDave Airlie void *data, struct drm_file *file_priv) 5202f453ba04SDave Airlie { 5203f453ba04SDave Airlie struct drm_mode_crtc_lut *crtc_lut = data; 5204f453ba04SDave Airlie struct drm_crtc *crtc; 5205f453ba04SDave Airlie void *r_base, *g_base, *b_base; 5206f453ba04SDave Airlie int size; 5207f453ba04SDave Airlie int ret = 0; 5208f453ba04SDave Airlie 5209fb3b06c8SDave Airlie if (!drm_core_check_feature(dev, DRIVER_MODESET)) 5210fb3b06c8SDave Airlie return -EINVAL; 5211fb3b06c8SDave Airlie 521284849903SDaniel Vetter drm_modeset_lock_all(dev); 5213a2b34e22SRob Clark crtc = drm_crtc_find(dev, crtc_lut->crtc_id); 5214a2b34e22SRob Clark if (!crtc) { 5215f27657f2SVille Syrjälä ret = -ENOENT; 5216f453ba04SDave Airlie goto out; 5217f453ba04SDave Airlie } 5218f453ba04SDave Airlie 5219f453ba04SDave Airlie /* memcpy into gamma store */ 5220f453ba04SDave Airlie if (crtc_lut->gamma_size != crtc->gamma_size) { 5221f453ba04SDave Airlie ret = -EINVAL; 5222f453ba04SDave Airlie goto out; 5223f453ba04SDave Airlie } 5224f453ba04SDave Airlie 5225f453ba04SDave Airlie size = crtc_lut->gamma_size * (sizeof(uint16_t)); 5226f453ba04SDave Airlie r_base = crtc->gamma_store; 5227f453ba04SDave Airlie if (copy_to_user((void __user *)(unsigned long)crtc_lut->red, r_base, size)) { 5228f453ba04SDave Airlie ret = -EFAULT; 5229f453ba04SDave Airlie goto out; 5230f453ba04SDave Airlie } 5231f453ba04SDave Airlie 5232f453ba04SDave Airlie g_base = r_base + size; 5233f453ba04SDave Airlie if (copy_to_user((void __user *)(unsigned long)crtc_lut->green, g_base, size)) { 5234f453ba04SDave Airlie ret = -EFAULT; 5235f453ba04SDave Airlie goto out; 5236f453ba04SDave Airlie } 5237f453ba04SDave Airlie 5238f453ba04SDave Airlie b_base = g_base + size; 5239f453ba04SDave Airlie if (copy_to_user((void __user *)(unsigned long)crtc_lut->blue, b_base, size)) { 5240f453ba04SDave Airlie ret = -EFAULT; 5241f453ba04SDave Airlie goto out; 5242f453ba04SDave Airlie } 5243f453ba04SDave Airlie out: 524484849903SDaniel Vetter drm_modeset_unlock_all(dev); 5245f453ba04SDave Airlie return ret; 5246f453ba04SDave Airlie } 5247d91d8a3fSKristian Høgsberg 5248c8e32cc1SDaniel Vetter /** 5249c8e32cc1SDaniel Vetter * drm_mode_page_flip_ioctl - schedule an asynchronous fb update 5250c8e32cc1SDaniel Vetter * @dev: DRM device 5251c8e32cc1SDaniel Vetter * @data: ioctl data 5252c8e32cc1SDaniel Vetter * @file_priv: DRM file info 5253c8e32cc1SDaniel Vetter * 5254c8e32cc1SDaniel Vetter * This schedules an asynchronous update on a given CRTC, called page flip. 5255c8e32cc1SDaniel Vetter * Optionally a drm event is generated to signal the completion of the event. 5256c8e32cc1SDaniel Vetter * Generic drivers cannot assume that a pageflip with changed framebuffer 5257c8e32cc1SDaniel Vetter * properties (including driver specific metadata like tiling layout) will work, 5258c8e32cc1SDaniel Vetter * but some drivers support e.g. pixel format changes through the pageflip 5259c8e32cc1SDaniel Vetter * ioctl. 5260c8e32cc1SDaniel Vetter * 5261c8e32cc1SDaniel Vetter * Called by the user via ioctl. 5262c8e32cc1SDaniel Vetter * 5263c8e32cc1SDaniel Vetter * Returns: 52641a498633SDaniel Vetter * Zero on success, negative errno on failure. 5265c8e32cc1SDaniel Vetter */ 5266d91d8a3fSKristian Høgsberg int drm_mode_page_flip_ioctl(struct drm_device *dev, 5267d91d8a3fSKristian Høgsberg void *data, struct drm_file *file_priv) 5268d91d8a3fSKristian Høgsberg { 5269d91d8a3fSKristian Høgsberg struct drm_mode_crtc_page_flip *page_flip = data; 5270d91d8a3fSKristian Høgsberg struct drm_crtc *crtc; 52713d30a59bSDaniel Vetter struct drm_framebuffer *fb = NULL; 5272d91d8a3fSKristian Høgsberg struct drm_pending_vblank_event *e = NULL; 5273d91d8a3fSKristian Høgsberg int ret = -EINVAL; 5274d91d8a3fSKristian Høgsberg 5275d91d8a3fSKristian Høgsberg if (page_flip->flags & ~DRM_MODE_PAGE_FLIP_FLAGS || 5276d91d8a3fSKristian Høgsberg page_flip->reserved != 0) 5277d91d8a3fSKristian Høgsberg return -EINVAL; 5278d91d8a3fSKristian Høgsberg 527962f2104fSKeith Packard if ((page_flip->flags & DRM_MODE_PAGE_FLIP_ASYNC) && !dev->mode_config.async_page_flip) 528062f2104fSKeith Packard return -EINVAL; 528162f2104fSKeith Packard 5282a2b34e22SRob Clark crtc = drm_crtc_find(dev, page_flip->crtc_id); 5283a2b34e22SRob Clark if (!crtc) 5284f27657f2SVille Syrjälä return -ENOENT; 5285d91d8a3fSKristian Høgsberg 52864d02e2deSDaniel Vetter drm_modeset_lock_crtc(crtc, crtc->primary); 5287f4510a27SMatt Roper if (crtc->primary->fb == NULL) { 528890c1efddSChris Wilson /* The framebuffer is currently unbound, presumably 528990c1efddSChris Wilson * due to a hotplug event, that userspace has not 529090c1efddSChris Wilson * yet discovered. 529190c1efddSChris Wilson */ 529290c1efddSChris Wilson ret = -EBUSY; 529390c1efddSChris Wilson goto out; 529490c1efddSChris Wilson } 529590c1efddSChris Wilson 5296d91d8a3fSKristian Høgsberg if (crtc->funcs->page_flip == NULL) 5297d91d8a3fSKristian Høgsberg goto out; 5298d91d8a3fSKristian Høgsberg 5299786b99edSDaniel Vetter fb = drm_framebuffer_lookup(dev, page_flip->fb_id); 530037c4e705SVille Syrjälä if (!fb) { 530137c4e705SVille Syrjälä ret = -ENOENT; 5302d91d8a3fSKristian Høgsberg goto out; 530337c4e705SVille Syrjälä } 5304d91d8a3fSKristian Høgsberg 53052afa701dSVille Syrjälä if (crtc->state) { 53062afa701dSVille Syrjälä const struct drm_plane_state *state = crtc->primary->state; 53072afa701dSVille Syrjälä 53082afa701dSVille Syrjälä ret = check_src_coords(state->src_x, state->src_y, 53092afa701dSVille Syrjälä state->src_w, state->src_h, fb); 53102afa701dSVille Syrjälä } else { 5311c11e9283SDamien Lespiau ret = drm_crtc_check_viewport(crtc, crtc->x, crtc->y, &crtc->mode, fb); 53122afa701dSVille Syrjälä } 5313c11e9283SDamien Lespiau if (ret) 53145f61bb42SVille Syrjälä goto out; 53155f61bb42SVille Syrjälä 5316f4510a27SMatt Roper if (crtc->primary->fb->pixel_format != fb->pixel_format) { 5317909d9cdaSLaurent Pinchart DRM_DEBUG_KMS("Page flip is not allowed to change frame buffer format.\n"); 5318909d9cdaSLaurent Pinchart ret = -EINVAL; 5319909d9cdaSLaurent Pinchart goto out; 5320909d9cdaSLaurent Pinchart } 5321909d9cdaSLaurent Pinchart 5322d91d8a3fSKristian Høgsberg if (page_flip->flags & DRM_MODE_PAGE_FLIP_EVENT) { 53232dd500f1SDaniel Vetter e = kzalloc(sizeof *e, GFP_KERNEL); 53242dd500f1SDaniel Vetter if (!e) { 5325d91d8a3fSKristian Høgsberg ret = -ENOMEM; 5326d91d8a3fSKristian Høgsberg goto out; 5327d91d8a3fSKristian Høgsberg } 53287bd4d7beSJesse Barnes e->event.base.type = DRM_EVENT_FLIP_COMPLETE; 5329f76511b9SThierry Reding e->event.base.length = sizeof(e->event); 5330d91d8a3fSKristian Høgsberg e->event.user_data = page_flip->user_data; 53312dd500f1SDaniel Vetter ret = drm_event_reserve_init(dev, file_priv, &e->base, &e->event.base); 53322dd500f1SDaniel Vetter if (ret) { 53332dd500f1SDaniel Vetter kfree(e); 53342dd500f1SDaniel Vetter goto out; 53352dd500f1SDaniel Vetter } 5336d91d8a3fSKristian Høgsberg } 5337d91d8a3fSKristian Høgsberg 53383d30a59bSDaniel Vetter crtc->primary->old_fb = crtc->primary->fb; 5339ed8d1975SKeith Packard ret = crtc->funcs->page_flip(crtc, fb, e, page_flip->flags); 5340d91d8a3fSKristian Høgsberg if (ret) { 53412dd500f1SDaniel Vetter if (page_flip->flags & DRM_MODE_PAGE_FLIP_EVENT) 53422dd500f1SDaniel Vetter drm_event_cancel_free(dev, &e->base); 5343b0d12325SDaniel Vetter /* Keep the old fb, don't unref it. */ 53443d30a59bSDaniel Vetter crtc->primary->old_fb = NULL; 5345b0d12325SDaniel Vetter } else { 53463cb43cc0SDaniel Vetter crtc->primary->fb = fb; 5347b0d12325SDaniel Vetter /* Unref only the old framebuffer. */ 5348b0d12325SDaniel Vetter fb = NULL; 5349aef6a7eeSJoonyoung Shim } 5350d91d8a3fSKristian Høgsberg 5351d91d8a3fSKristian Høgsberg out: 5352b0d12325SDaniel Vetter if (fb) 5353b0d12325SDaniel Vetter drm_framebuffer_unreference(fb); 53543d30a59bSDaniel Vetter if (crtc->primary->old_fb) 53553d30a59bSDaniel Vetter drm_framebuffer_unreference(crtc->primary->old_fb); 53563d30a59bSDaniel Vetter crtc->primary->old_fb = NULL; 5357d059f652SDaniel Vetter drm_modeset_unlock_crtc(crtc); 5358b4d5e7d1SDaniel Vetter 5359d91d8a3fSKristian Høgsberg return ret; 5360d91d8a3fSKristian Høgsberg } 5361eb033556SChris Wilson 5362c8e32cc1SDaniel Vetter /** 5363c8e32cc1SDaniel Vetter * drm_mode_config_reset - call ->reset callbacks 5364c8e32cc1SDaniel Vetter * @dev: drm device 5365c8e32cc1SDaniel Vetter * 5366c8e32cc1SDaniel Vetter * This functions calls all the crtc's, encoder's and connector's ->reset 5367c8e32cc1SDaniel Vetter * callback. Drivers can use this in e.g. their driver load or resume code to 5368c8e32cc1SDaniel Vetter * reset hardware and software state. 5369c8e32cc1SDaniel Vetter */ 5370eb033556SChris Wilson void drm_mode_config_reset(struct drm_device *dev) 5371eb033556SChris Wilson { 5372eb033556SChris Wilson struct drm_crtc *crtc; 53732a0d7cfdSDaniel Vetter struct drm_plane *plane; 5374eb033556SChris Wilson struct drm_encoder *encoder; 5375eb033556SChris Wilson struct drm_connector *connector; 5376eb033556SChris Wilson 5377e4f62546SDaniel Vetter drm_for_each_plane(plane, dev) 53782a0d7cfdSDaniel Vetter if (plane->funcs->reset) 53792a0d7cfdSDaniel Vetter plane->funcs->reset(plane); 53802a0d7cfdSDaniel Vetter 5381e4f62546SDaniel Vetter drm_for_each_crtc(crtc, dev) 5382eb033556SChris Wilson if (crtc->funcs->reset) 5383eb033556SChris Wilson crtc->funcs->reset(crtc); 5384eb033556SChris Wilson 5385e4f62546SDaniel Vetter drm_for_each_encoder(encoder, dev) 5386eb033556SChris Wilson if (encoder->funcs->reset) 5387eb033556SChris Wilson encoder->funcs->reset(encoder); 5388eb033556SChris Wilson 5389f8c2ba31SDaniel Vetter mutex_lock(&dev->mode_config.mutex); 53904eebf60bSDave Airlie drm_for_each_connector(connector, dev) 5391eb033556SChris Wilson if (connector->funcs->reset) 5392eb033556SChris Wilson connector->funcs->reset(connector); 5393f8c2ba31SDaniel Vetter mutex_unlock(&dev->mode_config.mutex); 53945e2cb2f6SDaniel Vetter } 5395eb033556SChris Wilson EXPORT_SYMBOL(drm_mode_config_reset); 5396ff72145bSDave Airlie 5397c8e32cc1SDaniel Vetter /** 5398c8e32cc1SDaniel Vetter * drm_mode_create_dumb_ioctl - create a dumb backing storage buffer 5399c8e32cc1SDaniel Vetter * @dev: DRM device 5400c8e32cc1SDaniel Vetter * @data: ioctl data 5401c8e32cc1SDaniel Vetter * @file_priv: DRM file info 5402c8e32cc1SDaniel Vetter * 5403c8e32cc1SDaniel Vetter * This creates a new dumb buffer in the driver's backing storage manager (GEM, 5404c8e32cc1SDaniel Vetter * TTM or something else entirely) and returns the resulting buffer handle. This 5405c8e32cc1SDaniel Vetter * handle can then be wrapped up into a framebuffer modeset object. 5406c8e32cc1SDaniel Vetter * 5407c8e32cc1SDaniel Vetter * Note that userspace is not allowed to use such objects for render 5408c8e32cc1SDaniel Vetter * acceleration - drivers must create their own private ioctls for such a use 5409c8e32cc1SDaniel Vetter * case. 5410c8e32cc1SDaniel Vetter * 5411c8e32cc1SDaniel Vetter * Called by the user via ioctl. 5412c8e32cc1SDaniel Vetter * 5413c8e32cc1SDaniel Vetter * Returns: 54141a498633SDaniel Vetter * Zero on success, negative errno on failure. 5415c8e32cc1SDaniel Vetter */ 5416ff72145bSDave Airlie int drm_mode_create_dumb_ioctl(struct drm_device *dev, 5417ff72145bSDave Airlie void *data, struct drm_file *file_priv) 5418ff72145bSDave Airlie { 5419ff72145bSDave Airlie struct drm_mode_create_dumb *args = data; 5420b28cd41fSDavid Herrmann u32 cpp, stride, size; 5421ff72145bSDave Airlie 5422ff72145bSDave Airlie if (!dev->driver->dumb_create) 5423ff72145bSDave Airlie return -ENOSYS; 5424b28cd41fSDavid Herrmann if (!args->width || !args->height || !args->bpp) 5425b28cd41fSDavid Herrmann return -EINVAL; 5426b28cd41fSDavid Herrmann 5427b28cd41fSDavid Herrmann /* overflow checks for 32bit size calculations */ 542800e72089SDavid Herrmann /* NOTE: DIV_ROUND_UP() can overflow */ 5429b28cd41fSDavid Herrmann cpp = DIV_ROUND_UP(args->bpp, 8); 543000e72089SDavid Herrmann if (!cpp || cpp > 0xffffffffU / args->width) 5431b28cd41fSDavid Herrmann return -EINVAL; 5432b28cd41fSDavid Herrmann stride = cpp * args->width; 5433b28cd41fSDavid Herrmann if (args->height > 0xffffffffU / stride) 5434b28cd41fSDavid Herrmann return -EINVAL; 5435b28cd41fSDavid Herrmann 5436b28cd41fSDavid Herrmann /* test for wrap-around */ 5437b28cd41fSDavid Herrmann size = args->height * stride; 5438b28cd41fSDavid Herrmann if (PAGE_ALIGN(size) == 0) 5439b28cd41fSDavid Herrmann return -EINVAL; 5440b28cd41fSDavid Herrmann 5441f6085952SThierry Reding /* 5442f6085952SThierry Reding * handle, pitch and size are output parameters. Zero them out to 5443f6085952SThierry Reding * prevent drivers from accidentally using uninitialized data. Since 5444f6085952SThierry Reding * not all existing userspace is clearing these fields properly we 5445f6085952SThierry Reding * cannot reject IOCTL with garbage in them. 5446f6085952SThierry Reding */ 5447f6085952SThierry Reding args->handle = 0; 5448f6085952SThierry Reding args->pitch = 0; 5449f6085952SThierry Reding args->size = 0; 5450f6085952SThierry Reding 5451ff72145bSDave Airlie return dev->driver->dumb_create(file_priv, dev, args); 5452ff72145bSDave Airlie } 5453ff72145bSDave Airlie 5454c8e32cc1SDaniel Vetter /** 5455c8e32cc1SDaniel Vetter * drm_mode_mmap_dumb_ioctl - create an mmap offset for a dumb backing storage buffer 5456c8e32cc1SDaniel Vetter * @dev: DRM device 5457c8e32cc1SDaniel Vetter * @data: ioctl data 5458c8e32cc1SDaniel Vetter * @file_priv: DRM file info 5459c8e32cc1SDaniel Vetter * 5460c8e32cc1SDaniel Vetter * Allocate an offset in the drm device node's address space to be able to 5461c8e32cc1SDaniel Vetter * memory map a dumb buffer. 5462c8e32cc1SDaniel Vetter * 5463c8e32cc1SDaniel Vetter * Called by the user via ioctl. 5464c8e32cc1SDaniel Vetter * 5465c8e32cc1SDaniel Vetter * Returns: 54661a498633SDaniel Vetter * Zero on success, negative errno on failure. 5467c8e32cc1SDaniel Vetter */ 5468ff72145bSDave Airlie int drm_mode_mmap_dumb_ioctl(struct drm_device *dev, 5469ff72145bSDave Airlie void *data, struct drm_file *file_priv) 5470ff72145bSDave Airlie { 5471ff72145bSDave Airlie struct drm_mode_map_dumb *args = data; 5472ff72145bSDave Airlie 5473ff72145bSDave Airlie /* call driver ioctl to get mmap offset */ 5474ff72145bSDave Airlie if (!dev->driver->dumb_map_offset) 5475ff72145bSDave Airlie return -ENOSYS; 5476ff72145bSDave Airlie 5477ff72145bSDave Airlie return dev->driver->dumb_map_offset(file_priv, dev, args->handle, &args->offset); 5478ff72145bSDave Airlie } 5479ff72145bSDave Airlie 5480c8e32cc1SDaniel Vetter /** 5481c8e32cc1SDaniel Vetter * drm_mode_destroy_dumb_ioctl - destroy a dumb backing strage buffer 5482c8e32cc1SDaniel Vetter * @dev: DRM device 5483c8e32cc1SDaniel Vetter * @data: ioctl data 5484c8e32cc1SDaniel Vetter * @file_priv: DRM file info 5485c8e32cc1SDaniel Vetter * 5486c8e32cc1SDaniel Vetter * This destroys the userspace handle for the given dumb backing storage buffer. 5487c8e32cc1SDaniel Vetter * Since buffer objects must be reference counted in the kernel a buffer object 5488c8e32cc1SDaniel Vetter * won't be immediately freed if a framebuffer modeset object still uses it. 5489c8e32cc1SDaniel Vetter * 5490c8e32cc1SDaniel Vetter * Called by the user via ioctl. 5491c8e32cc1SDaniel Vetter * 5492c8e32cc1SDaniel Vetter * Returns: 54931a498633SDaniel Vetter * Zero on success, negative errno on failure. 5494c8e32cc1SDaniel Vetter */ 5495ff72145bSDave Airlie int drm_mode_destroy_dumb_ioctl(struct drm_device *dev, 5496ff72145bSDave Airlie void *data, struct drm_file *file_priv) 5497ff72145bSDave Airlie { 5498ff72145bSDave Airlie struct drm_mode_destroy_dumb *args = data; 5499ff72145bSDave Airlie 5500ff72145bSDave Airlie if (!dev->driver->dumb_destroy) 5501ff72145bSDave Airlie return -ENOSYS; 5502ff72145bSDave Airlie 5503ff72145bSDave Airlie return dev->driver->dumb_destroy(file_priv, dev, args->handle); 5504ff72145bSDave Airlie } 5505248dbc23SDave Airlie 5506c8e32cc1SDaniel Vetter /** 55073c9855f6SVille Syrjälä * drm_rotation_simplify() - Try to simplify the rotation 55083c9855f6SVille Syrjälä * @rotation: Rotation to be simplified 55093c9855f6SVille Syrjälä * @supported_rotations: Supported rotations 55103c9855f6SVille Syrjälä * 55113c9855f6SVille Syrjälä * Attempt to simplify the rotation to a form that is supported. 55123c9855f6SVille Syrjälä * Eg. if the hardware supports everything except DRM_REFLECT_X 55133c9855f6SVille Syrjälä * one could call this function like this: 55143c9855f6SVille Syrjälä * 55153c9855f6SVille Syrjälä * drm_rotation_simplify(rotation, BIT(DRM_ROTATE_0) | 55163c9855f6SVille Syrjälä * BIT(DRM_ROTATE_90) | BIT(DRM_ROTATE_180) | 55173c9855f6SVille Syrjälä * BIT(DRM_ROTATE_270) | BIT(DRM_REFLECT_Y)); 55183c9855f6SVille Syrjälä * 55193c9855f6SVille Syrjälä * to eliminate the DRM_ROTATE_X flag. Depending on what kind of 55203c9855f6SVille Syrjälä * transforms the hardware supports, this function may not 55213c9855f6SVille Syrjälä * be able to produce a supported transform, so the caller should 55223c9855f6SVille Syrjälä * check the result afterwards. 55233c9855f6SVille Syrjälä */ 55243c9855f6SVille Syrjälä unsigned int drm_rotation_simplify(unsigned int rotation, 55253c9855f6SVille Syrjälä unsigned int supported_rotations) 55263c9855f6SVille Syrjälä { 55273c9855f6SVille Syrjälä if (rotation & ~supported_rotations) { 55283c9855f6SVille Syrjälä rotation ^= BIT(DRM_REFLECT_X) | BIT(DRM_REFLECT_Y); 552914152c8dSJoonas Lahtinen rotation = (rotation & DRM_REFLECT_MASK) | 553014152c8dSJoonas Lahtinen BIT((ffs(rotation & DRM_ROTATE_MASK) + 1) % 4); 55313c9855f6SVille Syrjälä } 55323c9855f6SVille Syrjälä 55333c9855f6SVille Syrjälä return rotation; 55343c9855f6SVille Syrjälä } 55353c9855f6SVille Syrjälä EXPORT_SYMBOL(drm_rotation_simplify); 55363c9855f6SVille Syrjälä 55373c9855f6SVille Syrjälä /** 553887d24fc3SLaurent Pinchart * drm_mode_config_init - initialize DRM mode_configuration structure 553987d24fc3SLaurent Pinchart * @dev: DRM device 554087d24fc3SLaurent Pinchart * 554187d24fc3SLaurent Pinchart * Initialize @dev's mode_config structure, used for tracking the graphics 554287d24fc3SLaurent Pinchart * configuration of @dev. 554387d24fc3SLaurent Pinchart * 554487d24fc3SLaurent Pinchart * Since this initializes the modeset locks, no locking is possible. Which is no 554587d24fc3SLaurent Pinchart * problem, since this should happen single threaded at init time. It is the 554687d24fc3SLaurent Pinchart * driver's problem to ensure this guarantee. 554787d24fc3SLaurent Pinchart * 554887d24fc3SLaurent Pinchart */ 554987d24fc3SLaurent Pinchart void drm_mode_config_init(struct drm_device *dev) 555087d24fc3SLaurent Pinchart { 555187d24fc3SLaurent Pinchart mutex_init(&dev->mode_config.mutex); 555251fd371bSRob Clark drm_modeset_lock_init(&dev->mode_config.connection_mutex); 555387d24fc3SLaurent Pinchart mutex_init(&dev->mode_config.idr_mutex); 555487d24fc3SLaurent Pinchart mutex_init(&dev->mode_config.fb_lock); 55558fb6e7a5SDaniel Stone mutex_init(&dev->mode_config.blob_lock); 555687d24fc3SLaurent Pinchart INIT_LIST_HEAD(&dev->mode_config.fb_list); 555787d24fc3SLaurent Pinchart INIT_LIST_HEAD(&dev->mode_config.crtc_list); 555887d24fc3SLaurent Pinchart INIT_LIST_HEAD(&dev->mode_config.connector_list); 555987d24fc3SLaurent Pinchart INIT_LIST_HEAD(&dev->mode_config.encoder_list); 556087d24fc3SLaurent Pinchart INIT_LIST_HEAD(&dev->mode_config.property_list); 556187d24fc3SLaurent Pinchart INIT_LIST_HEAD(&dev->mode_config.property_blob_list); 556287d24fc3SLaurent Pinchart INIT_LIST_HEAD(&dev->mode_config.plane_list); 556387d24fc3SLaurent Pinchart idr_init(&dev->mode_config.crtc_idr); 5564138f9ebbSDave Airlie idr_init(&dev->mode_config.tile_idr); 55655fff80bbSMaarten Lankhorst ida_init(&dev->mode_config.connector_ida); 556687d24fc3SLaurent Pinchart 556787d24fc3SLaurent Pinchart drm_modeset_lock_all(dev); 55686b4959f4SRob Clark drm_mode_create_standard_properties(dev); 556987d24fc3SLaurent Pinchart drm_modeset_unlock_all(dev); 557087d24fc3SLaurent Pinchart 557187d24fc3SLaurent Pinchart /* Just to be sure */ 557287d24fc3SLaurent Pinchart dev->mode_config.num_fb = 0; 557387d24fc3SLaurent Pinchart dev->mode_config.num_connector = 0; 557487d24fc3SLaurent Pinchart dev->mode_config.num_crtc = 0; 557587d24fc3SLaurent Pinchart dev->mode_config.num_encoder = 0; 5576e27dde3eSMatt Roper dev->mode_config.num_overlay_plane = 0; 5577e27dde3eSMatt Roper dev->mode_config.num_total_plane = 0; 557887d24fc3SLaurent Pinchart } 557987d24fc3SLaurent Pinchart EXPORT_SYMBOL(drm_mode_config_init); 558087d24fc3SLaurent Pinchart 558187d24fc3SLaurent Pinchart /** 558287d24fc3SLaurent Pinchart * drm_mode_config_cleanup - free up DRM mode_config info 558387d24fc3SLaurent Pinchart * @dev: DRM device 558487d24fc3SLaurent Pinchart * 558587d24fc3SLaurent Pinchart * Free up all the connectors and CRTCs associated with this DRM device, then 558687d24fc3SLaurent Pinchart * free up the framebuffers and associated buffer objects. 558787d24fc3SLaurent Pinchart * 558887d24fc3SLaurent Pinchart * Note that since this /should/ happen single-threaded at driver/device 558987d24fc3SLaurent Pinchart * teardown time, no locking is required. It's the driver's job to ensure that 559087d24fc3SLaurent Pinchart * this guarantee actually holds true. 559187d24fc3SLaurent Pinchart * 559287d24fc3SLaurent Pinchart * FIXME: cleanup any dangling user buffer objects too 559387d24fc3SLaurent Pinchart */ 559487d24fc3SLaurent Pinchart void drm_mode_config_cleanup(struct drm_device *dev) 559587d24fc3SLaurent Pinchart { 559687d24fc3SLaurent Pinchart struct drm_connector *connector, *ot; 559787d24fc3SLaurent Pinchart struct drm_crtc *crtc, *ct; 559887d24fc3SLaurent Pinchart struct drm_encoder *encoder, *enct; 559987d24fc3SLaurent Pinchart struct drm_framebuffer *fb, *fbt; 560087d24fc3SLaurent Pinchart struct drm_property *property, *pt; 560187d24fc3SLaurent Pinchart struct drm_property_blob *blob, *bt; 560287d24fc3SLaurent Pinchart struct drm_plane *plane, *plt; 560387d24fc3SLaurent Pinchart 560487d24fc3SLaurent Pinchart list_for_each_entry_safe(encoder, enct, &dev->mode_config.encoder_list, 560587d24fc3SLaurent Pinchart head) { 560687d24fc3SLaurent Pinchart encoder->funcs->destroy(encoder); 560787d24fc3SLaurent Pinchart } 560887d24fc3SLaurent Pinchart 560987d24fc3SLaurent Pinchart list_for_each_entry_safe(connector, ot, 561087d24fc3SLaurent Pinchart &dev->mode_config.connector_list, head) { 561187d24fc3SLaurent Pinchart connector->funcs->destroy(connector); 561287d24fc3SLaurent Pinchart } 561387d24fc3SLaurent Pinchart 561487d24fc3SLaurent Pinchart list_for_each_entry_safe(property, pt, &dev->mode_config.property_list, 561587d24fc3SLaurent Pinchart head) { 561687d24fc3SLaurent Pinchart drm_property_destroy(dev, property); 561787d24fc3SLaurent Pinchart } 561887d24fc3SLaurent Pinchart 5619f35034f8SMaarten Lankhorst list_for_each_entry_safe(plane, plt, &dev->mode_config.plane_list, 5620f35034f8SMaarten Lankhorst head) { 5621f35034f8SMaarten Lankhorst plane->funcs->destroy(plane); 5622f35034f8SMaarten Lankhorst } 5623f35034f8SMaarten Lankhorst 5624f35034f8SMaarten Lankhorst list_for_each_entry_safe(crtc, ct, &dev->mode_config.crtc_list, head) { 5625f35034f8SMaarten Lankhorst crtc->funcs->destroy(crtc); 5626f35034f8SMaarten Lankhorst } 5627f35034f8SMaarten Lankhorst 562887d24fc3SLaurent Pinchart list_for_each_entry_safe(blob, bt, &dev->mode_config.property_blob_list, 5629e2f5d2eaSDaniel Stone head_global) { 56306bcacf51SDaniel Stone drm_property_unreference_blob(blob); 563187d24fc3SLaurent Pinchart } 563287d24fc3SLaurent Pinchart 563387d24fc3SLaurent Pinchart /* 563487d24fc3SLaurent Pinchart * Single-threaded teardown context, so it's not required to grab the 563587d24fc3SLaurent Pinchart * fb_lock to protect against concurrent fb_list access. Contrary, it 563687d24fc3SLaurent Pinchart * would actually deadlock with the drm_framebuffer_cleanup function. 563787d24fc3SLaurent Pinchart * 563887d24fc3SLaurent Pinchart * Also, if there are any framebuffers left, that's a driver leak now, 563987d24fc3SLaurent Pinchart * so politely WARN about this. 564087d24fc3SLaurent Pinchart */ 564187d24fc3SLaurent Pinchart WARN_ON(!list_empty(&dev->mode_config.fb_list)); 564287d24fc3SLaurent Pinchart list_for_each_entry_safe(fb, fbt, &dev->mode_config.fb_list, head) { 5643d0f37cf6SDave Airlie drm_framebuffer_free(&fb->base.refcount); 564487d24fc3SLaurent Pinchart } 564587d24fc3SLaurent Pinchart 56465fff80bbSMaarten Lankhorst ida_destroy(&dev->mode_config.connector_ida); 5647138f9ebbSDave Airlie idr_destroy(&dev->mode_config.tile_idr); 564887d24fc3SLaurent Pinchart idr_destroy(&dev->mode_config.crtc_idr); 564951fd371bSRob Clark drm_modeset_lock_fini(&dev->mode_config.connection_mutex); 565087d24fc3SLaurent Pinchart } 565187d24fc3SLaurent Pinchart EXPORT_SYMBOL(drm_mode_config_cleanup); 5652c1df5f3cSVille Syrjälä 5653c1df5f3cSVille Syrjälä struct drm_property *drm_mode_create_rotation_property(struct drm_device *dev, 5654c1df5f3cSVille Syrjälä unsigned int supported_rotations) 5655c1df5f3cSVille Syrjälä { 5656c1df5f3cSVille Syrjälä static const struct drm_prop_enum_list props[] = { 5657c1df5f3cSVille Syrjälä { DRM_ROTATE_0, "rotate-0" }, 5658c1df5f3cSVille Syrjälä { DRM_ROTATE_90, "rotate-90" }, 5659c1df5f3cSVille Syrjälä { DRM_ROTATE_180, "rotate-180" }, 5660c1df5f3cSVille Syrjälä { DRM_ROTATE_270, "rotate-270" }, 5661c1df5f3cSVille Syrjälä { DRM_REFLECT_X, "reflect-x" }, 5662c1df5f3cSVille Syrjälä { DRM_REFLECT_Y, "reflect-y" }, 5663c1df5f3cSVille Syrjälä }; 5664c1df5f3cSVille Syrjälä 5665c1df5f3cSVille Syrjälä return drm_property_create_bitmask(dev, 0, "rotation", 5666c1df5f3cSVille Syrjälä props, ARRAY_SIZE(props), 5667c1df5f3cSVille Syrjälä supported_rotations); 5668c1df5f3cSVille Syrjälä } 5669c1df5f3cSVille Syrjälä EXPORT_SYMBOL(drm_mode_create_rotation_property); 5670138f9ebbSDave Airlie 5671138f9ebbSDave Airlie /** 5672138f9ebbSDave Airlie * DOC: Tile group 5673138f9ebbSDave Airlie * 5674138f9ebbSDave Airlie * Tile groups are used to represent tiled monitors with a unique 5675138f9ebbSDave Airlie * integer identifier. Tiled monitors using DisplayID v1.3 have 5676138f9ebbSDave Airlie * a unique 8-byte handle, we store this in a tile group, so we 5677138f9ebbSDave Airlie * have a common identifier for all tiles in a monitor group. 5678138f9ebbSDave Airlie */ 5679138f9ebbSDave Airlie static void drm_tile_group_free(struct kref *kref) 5680138f9ebbSDave Airlie { 5681138f9ebbSDave Airlie struct drm_tile_group *tg = container_of(kref, struct drm_tile_group, refcount); 5682138f9ebbSDave Airlie struct drm_device *dev = tg->dev; 5683138f9ebbSDave Airlie mutex_lock(&dev->mode_config.idr_mutex); 5684138f9ebbSDave Airlie idr_remove(&dev->mode_config.tile_idr, tg->id); 5685138f9ebbSDave Airlie mutex_unlock(&dev->mode_config.idr_mutex); 5686138f9ebbSDave Airlie kfree(tg); 5687138f9ebbSDave Airlie } 5688138f9ebbSDave Airlie 5689138f9ebbSDave Airlie /** 5690138f9ebbSDave Airlie * drm_mode_put_tile_group - drop a reference to a tile group. 5691138f9ebbSDave Airlie * @dev: DRM device 5692138f9ebbSDave Airlie * @tg: tile group to drop reference to. 5693138f9ebbSDave Airlie * 5694138f9ebbSDave Airlie * drop reference to tile group and free if 0. 5695138f9ebbSDave Airlie */ 5696138f9ebbSDave Airlie void drm_mode_put_tile_group(struct drm_device *dev, 5697138f9ebbSDave Airlie struct drm_tile_group *tg) 5698138f9ebbSDave Airlie { 5699138f9ebbSDave Airlie kref_put(&tg->refcount, drm_tile_group_free); 5700138f9ebbSDave Airlie } 5701138f9ebbSDave Airlie 5702138f9ebbSDave Airlie /** 5703138f9ebbSDave Airlie * drm_mode_get_tile_group - get a reference to an existing tile group 5704138f9ebbSDave Airlie * @dev: DRM device 5705138f9ebbSDave Airlie * @topology: 8-bytes unique per monitor. 5706138f9ebbSDave Airlie * 5707138f9ebbSDave Airlie * Use the unique bytes to get a reference to an existing tile group. 5708138f9ebbSDave Airlie * 5709138f9ebbSDave Airlie * RETURNS: 5710138f9ebbSDave Airlie * tile group or NULL if not found. 5711138f9ebbSDave Airlie */ 5712138f9ebbSDave Airlie struct drm_tile_group *drm_mode_get_tile_group(struct drm_device *dev, 5713138f9ebbSDave Airlie char topology[8]) 5714138f9ebbSDave Airlie { 5715138f9ebbSDave Airlie struct drm_tile_group *tg; 5716138f9ebbSDave Airlie int id; 5717138f9ebbSDave Airlie mutex_lock(&dev->mode_config.idr_mutex); 5718138f9ebbSDave Airlie idr_for_each_entry(&dev->mode_config.tile_idr, tg, id) { 5719138f9ebbSDave Airlie if (!memcmp(tg->group_data, topology, 8)) { 5720138f9ebbSDave Airlie if (!kref_get_unless_zero(&tg->refcount)) 5721138f9ebbSDave Airlie tg = NULL; 5722138f9ebbSDave Airlie mutex_unlock(&dev->mode_config.idr_mutex); 5723138f9ebbSDave Airlie return tg; 5724138f9ebbSDave Airlie } 5725138f9ebbSDave Airlie } 5726138f9ebbSDave Airlie mutex_unlock(&dev->mode_config.idr_mutex); 5727138f9ebbSDave Airlie return NULL; 5728138f9ebbSDave Airlie } 572981ddd1bcSRob Clark EXPORT_SYMBOL(drm_mode_get_tile_group); 5730138f9ebbSDave Airlie 5731138f9ebbSDave Airlie /** 5732138f9ebbSDave Airlie * drm_mode_create_tile_group - create a tile group from a displayid description 5733138f9ebbSDave Airlie * @dev: DRM device 5734138f9ebbSDave Airlie * @topology: 8-bytes unique per monitor. 5735138f9ebbSDave Airlie * 5736138f9ebbSDave Airlie * Create a tile group for the unique monitor, and get a unique 5737138f9ebbSDave Airlie * identifier for the tile group. 5738138f9ebbSDave Airlie * 5739138f9ebbSDave Airlie * RETURNS: 5740138f9ebbSDave Airlie * new tile group or error. 5741138f9ebbSDave Airlie */ 5742138f9ebbSDave Airlie struct drm_tile_group *drm_mode_create_tile_group(struct drm_device *dev, 5743138f9ebbSDave Airlie char topology[8]) 5744138f9ebbSDave Airlie { 5745138f9ebbSDave Airlie struct drm_tile_group *tg; 5746138f9ebbSDave Airlie int ret; 5747138f9ebbSDave Airlie 5748138f9ebbSDave Airlie tg = kzalloc(sizeof(*tg), GFP_KERNEL); 5749138f9ebbSDave Airlie if (!tg) 5750138f9ebbSDave Airlie return ERR_PTR(-ENOMEM); 5751138f9ebbSDave Airlie 5752138f9ebbSDave Airlie kref_init(&tg->refcount); 5753138f9ebbSDave Airlie memcpy(tg->group_data, topology, 8); 5754138f9ebbSDave Airlie tg->dev = dev; 5755138f9ebbSDave Airlie 5756138f9ebbSDave Airlie mutex_lock(&dev->mode_config.idr_mutex); 5757138f9ebbSDave Airlie ret = idr_alloc(&dev->mode_config.tile_idr, tg, 1, 0, GFP_KERNEL); 5758138f9ebbSDave Airlie if (ret >= 0) { 5759138f9ebbSDave Airlie tg->id = ret; 5760138f9ebbSDave Airlie } else { 5761138f9ebbSDave Airlie kfree(tg); 5762138f9ebbSDave Airlie tg = ERR_PTR(ret); 5763138f9ebbSDave Airlie } 5764138f9ebbSDave Airlie 5765138f9ebbSDave Airlie mutex_unlock(&dev->mode_config.idr_mutex); 5766138f9ebbSDave Airlie return tg; 5767138f9ebbSDave Airlie } 576881ddd1bcSRob Clark EXPORT_SYMBOL(drm_mode_create_tile_group); 5769f8ed34acSJyri Sarha 5770f8ed34acSJyri Sarha /** 5771f8ed34acSJyri Sarha * drm_crtc_enable_color_mgmt - enable color management properties 5772f8ed34acSJyri Sarha * @crtc: DRM CRTC 5773f8ed34acSJyri Sarha * @degamma_lut_size: the size of the degamma lut (before CSC) 5774f8ed34acSJyri Sarha * @has_ctm: whether to attach ctm_property for CSC matrix 5775f8ed34acSJyri Sarha * @gamma_lut_size: the size of the gamma lut (after CSC) 5776f8ed34acSJyri Sarha * 5777f8ed34acSJyri Sarha * This function lets the driver enable the color correction 5778f8ed34acSJyri Sarha * properties on a CRTC. This includes 3 degamma, csc and gamma 5779f8ed34acSJyri Sarha * properties that userspace can set and 2 size properties to inform 5780f8ed34acSJyri Sarha * the userspace of the lut sizes. Each of the properties are 5781f8ed34acSJyri Sarha * optional. The gamma and degamma properties are only attached if 5782f8ed34acSJyri Sarha * their size is not 0 and ctm_property is only attached if has_ctm is 5783f8ed34acSJyri Sarha * true. 5784f8ed34acSJyri Sarha */ 5785f8ed34acSJyri Sarha void drm_crtc_enable_color_mgmt(struct drm_crtc *crtc, 5786f8ed34acSJyri Sarha uint degamma_lut_size, 5787f8ed34acSJyri Sarha bool has_ctm, 5788f8ed34acSJyri Sarha uint gamma_lut_size) 5789f8ed34acSJyri Sarha { 5790f8ed34acSJyri Sarha struct drm_device *dev = crtc->dev; 5791f8ed34acSJyri Sarha struct drm_mode_config *config = &dev->mode_config; 5792f8ed34acSJyri Sarha 5793f8ed34acSJyri Sarha if (degamma_lut_size) { 5794f8ed34acSJyri Sarha drm_object_attach_property(&crtc->base, 5795f8ed34acSJyri Sarha config->degamma_lut_property, 0); 5796f8ed34acSJyri Sarha drm_object_attach_property(&crtc->base, 5797f8ed34acSJyri Sarha config->degamma_lut_size_property, 5798f8ed34acSJyri Sarha degamma_lut_size); 5799f8ed34acSJyri Sarha } 5800f8ed34acSJyri Sarha 5801f8ed34acSJyri Sarha if (has_ctm) 5802f8ed34acSJyri Sarha drm_object_attach_property(&crtc->base, 5803f8ed34acSJyri Sarha config->ctm_property, 0); 5804f8ed34acSJyri Sarha 5805f8ed34acSJyri Sarha if (gamma_lut_size) { 5806f8ed34acSJyri Sarha drm_object_attach_property(&crtc->base, 5807f8ed34acSJyri Sarha config->gamma_lut_property, 0); 5808f8ed34acSJyri Sarha drm_object_attach_property(&crtc->base, 5809f8ed34acSJyri Sarha config->gamma_lut_size_property, 5810f8ed34acSJyri Sarha gamma_lut_size); 5811f8ed34acSJyri Sarha } 5812f8ed34acSJyri Sarha } 5813f8ed34acSJyri Sarha EXPORT_SYMBOL(drm_crtc_enable_color_mgmt); 5814