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> 40f453ba04SDave Airlie 418bd441b2SDaniel Vetter #include "drm_crtc_internal.h" 428bd441b2SDaniel Vetter 4384849903SDaniel Vetter /** 4484849903SDaniel Vetter * drm_modeset_lock_all - take all modeset locks 4584849903SDaniel Vetter * @dev: drm device 4684849903SDaniel Vetter * 4784849903SDaniel Vetter * This function takes all modeset locks, suitable where a more fine-grained 48c8e32cc1SDaniel Vetter * scheme isn't (yet) implemented. Locks must be dropped with 49c8e32cc1SDaniel Vetter * drm_modeset_unlock_all. 5084849903SDaniel Vetter */ 5184849903SDaniel Vetter void drm_modeset_lock_all(struct drm_device *dev) 5284849903SDaniel Vetter { 5329494c17SDaniel Vetter struct drm_crtc *crtc; 5429494c17SDaniel Vetter 5584849903SDaniel Vetter mutex_lock(&dev->mode_config.mutex); 5629494c17SDaniel Vetter 5729494c17SDaniel Vetter list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) 5829494c17SDaniel Vetter mutex_lock_nest_lock(&crtc->mutex, &dev->mode_config.mutex); 5984849903SDaniel Vetter } 6084849903SDaniel Vetter EXPORT_SYMBOL(drm_modeset_lock_all); 6184849903SDaniel Vetter 6284849903SDaniel Vetter /** 6384849903SDaniel Vetter * drm_modeset_unlock_all - drop all modeset locks 6484849903SDaniel Vetter * @dev: device 65c8e32cc1SDaniel Vetter * 66c8e32cc1SDaniel Vetter * This function drop all modeset locks taken by drm_modeset_lock_all. 6784849903SDaniel Vetter */ 6884849903SDaniel Vetter void drm_modeset_unlock_all(struct drm_device *dev) 6984849903SDaniel Vetter { 7029494c17SDaniel Vetter struct drm_crtc *crtc; 7129494c17SDaniel Vetter 7229494c17SDaniel Vetter list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) 7329494c17SDaniel Vetter mutex_unlock(&crtc->mutex); 7429494c17SDaniel Vetter 7584849903SDaniel Vetter mutex_unlock(&dev->mode_config.mutex); 7684849903SDaniel Vetter } 7784849903SDaniel Vetter EXPORT_SYMBOL(drm_modeset_unlock_all); 7884849903SDaniel Vetter 796aed8ec3SDaniel Vetter /** 806aed8ec3SDaniel Vetter * drm_warn_on_modeset_not_all_locked - check that all modeset locks are locked 816aed8ec3SDaniel Vetter * @dev: device 82c8e32cc1SDaniel Vetter * 83c8e32cc1SDaniel Vetter * Useful as a debug assert. 846aed8ec3SDaniel Vetter */ 856aed8ec3SDaniel Vetter void drm_warn_on_modeset_not_all_locked(struct drm_device *dev) 866aed8ec3SDaniel Vetter { 876aed8ec3SDaniel Vetter struct drm_crtc *crtc; 886aed8ec3SDaniel Vetter 89a9b054e8SDaniel Vetter /* Locking is currently fubar in the panic handler. */ 90a9b054e8SDaniel Vetter if (oops_in_progress) 91a9b054e8SDaniel Vetter return; 92a9b054e8SDaniel Vetter 936aed8ec3SDaniel Vetter list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) 946aed8ec3SDaniel Vetter WARN_ON(!mutex_is_locked(&crtc->mutex)); 956aed8ec3SDaniel Vetter 966aed8ec3SDaniel Vetter WARN_ON(!mutex_is_locked(&dev->mode_config.mutex)); 976aed8ec3SDaniel Vetter } 986aed8ec3SDaniel Vetter EXPORT_SYMBOL(drm_warn_on_modeset_not_all_locked); 996aed8ec3SDaniel Vetter 100f453ba04SDave Airlie /* Avoid boilerplate. I'm tired of typing. */ 101f453ba04SDave Airlie #define DRM_ENUM_NAME_FN(fnname, list) \ 102d20d3174SVille Syrjälä const char *fnname(int val) \ 103f453ba04SDave Airlie { \ 104f453ba04SDave Airlie int i; \ 105f453ba04SDave Airlie for (i = 0; i < ARRAY_SIZE(list); i++) { \ 106f453ba04SDave Airlie if (list[i].type == val) \ 107f453ba04SDave Airlie return list[i].name; \ 108f453ba04SDave Airlie } \ 109f453ba04SDave Airlie return "(unknown)"; \ 110f453ba04SDave Airlie } 111f453ba04SDave Airlie 112f453ba04SDave Airlie /* 113f453ba04SDave Airlie * Global properties 114f453ba04SDave Airlie */ 115d20d3174SVille Syrjälä static const struct drm_prop_enum_list drm_dpms_enum_list[] = 116f453ba04SDave Airlie { { DRM_MODE_DPMS_ON, "On" }, 117f453ba04SDave Airlie { DRM_MODE_DPMS_STANDBY, "Standby" }, 118f453ba04SDave Airlie { DRM_MODE_DPMS_SUSPEND, "Suspend" }, 119f453ba04SDave Airlie { DRM_MODE_DPMS_OFF, "Off" } 120f453ba04SDave Airlie }; 121f453ba04SDave Airlie 122f453ba04SDave Airlie DRM_ENUM_NAME_FN(drm_get_dpms_name, drm_dpms_enum_list) 123f453ba04SDave Airlie 1249922ab5aSRob Clark static const struct drm_prop_enum_list drm_plane_type_enum_list[] = 1259922ab5aSRob Clark { 1269922ab5aSRob Clark { DRM_PLANE_TYPE_OVERLAY, "Overlay" }, 1279922ab5aSRob Clark { DRM_PLANE_TYPE_PRIMARY, "Primary" }, 1289922ab5aSRob Clark { DRM_PLANE_TYPE_CURSOR, "Cursor" }, 1299922ab5aSRob Clark }; 1309922ab5aSRob Clark 131f453ba04SDave Airlie /* 132f453ba04SDave Airlie * Optional properties 133f453ba04SDave Airlie */ 134d20d3174SVille Syrjälä static const struct drm_prop_enum_list drm_scaling_mode_enum_list[] = 135f453ba04SDave Airlie { 13653bd8389SJesse Barnes { DRM_MODE_SCALE_NONE, "None" }, 13753bd8389SJesse Barnes { DRM_MODE_SCALE_FULLSCREEN, "Full" }, 13853bd8389SJesse Barnes { DRM_MODE_SCALE_CENTER, "Center" }, 13953bd8389SJesse Barnes { DRM_MODE_SCALE_ASPECT, "Full aspect" }, 140f453ba04SDave Airlie }; 141f453ba04SDave Airlie 142f453ba04SDave Airlie /* 143f453ba04SDave Airlie * Non-global properties, but "required" for certain connectors. 144f453ba04SDave Airlie */ 145d20d3174SVille Syrjälä static const struct drm_prop_enum_list drm_dvi_i_select_enum_list[] = 146f453ba04SDave Airlie { 147f453ba04SDave Airlie { DRM_MODE_SUBCONNECTOR_Automatic, "Automatic" }, /* DVI-I and TV-out */ 148f453ba04SDave Airlie { DRM_MODE_SUBCONNECTOR_DVID, "DVI-D" }, /* DVI-I */ 149f453ba04SDave Airlie { DRM_MODE_SUBCONNECTOR_DVIA, "DVI-A" }, /* DVI-I */ 150f453ba04SDave Airlie }; 151f453ba04SDave Airlie 152f453ba04SDave Airlie DRM_ENUM_NAME_FN(drm_get_dvi_i_select_name, drm_dvi_i_select_enum_list) 153f453ba04SDave Airlie 154d20d3174SVille Syrjälä static const struct drm_prop_enum_list drm_dvi_i_subconnector_enum_list[] = 155f453ba04SDave Airlie { 156f453ba04SDave Airlie { DRM_MODE_SUBCONNECTOR_Unknown, "Unknown" }, /* DVI-I and TV-out */ 157f453ba04SDave Airlie { DRM_MODE_SUBCONNECTOR_DVID, "DVI-D" }, /* DVI-I */ 158f453ba04SDave Airlie { DRM_MODE_SUBCONNECTOR_DVIA, "DVI-A" }, /* DVI-I */ 159f453ba04SDave Airlie }; 160f453ba04SDave Airlie 161f453ba04SDave Airlie DRM_ENUM_NAME_FN(drm_get_dvi_i_subconnector_name, 162f453ba04SDave Airlie drm_dvi_i_subconnector_enum_list) 163f453ba04SDave Airlie 164d20d3174SVille Syrjälä static const struct drm_prop_enum_list drm_tv_select_enum_list[] = 165f453ba04SDave Airlie { 166f453ba04SDave Airlie { DRM_MODE_SUBCONNECTOR_Automatic, "Automatic" }, /* DVI-I and TV-out */ 167f453ba04SDave Airlie { DRM_MODE_SUBCONNECTOR_Composite, "Composite" }, /* TV-out */ 168f453ba04SDave Airlie { DRM_MODE_SUBCONNECTOR_SVIDEO, "SVIDEO" }, /* TV-out */ 169f453ba04SDave Airlie { DRM_MODE_SUBCONNECTOR_Component, "Component" }, /* TV-out */ 170aeaa1ad3SFrancisco Jerez { DRM_MODE_SUBCONNECTOR_SCART, "SCART" }, /* TV-out */ 171f453ba04SDave Airlie }; 172f453ba04SDave Airlie 173f453ba04SDave Airlie DRM_ENUM_NAME_FN(drm_get_tv_select_name, drm_tv_select_enum_list) 174f453ba04SDave Airlie 175d20d3174SVille Syrjälä static const struct drm_prop_enum_list drm_tv_subconnector_enum_list[] = 176f453ba04SDave Airlie { 177f453ba04SDave Airlie { DRM_MODE_SUBCONNECTOR_Unknown, "Unknown" }, /* DVI-I and TV-out */ 178f453ba04SDave Airlie { DRM_MODE_SUBCONNECTOR_Composite, "Composite" }, /* TV-out */ 179f453ba04SDave Airlie { DRM_MODE_SUBCONNECTOR_SVIDEO, "SVIDEO" }, /* TV-out */ 180f453ba04SDave Airlie { DRM_MODE_SUBCONNECTOR_Component, "Component" }, /* TV-out */ 181aeaa1ad3SFrancisco Jerez { DRM_MODE_SUBCONNECTOR_SCART, "SCART" }, /* TV-out */ 182f453ba04SDave Airlie }; 183f453ba04SDave Airlie 184f453ba04SDave Airlie DRM_ENUM_NAME_FN(drm_get_tv_subconnector_name, 185f453ba04SDave Airlie drm_tv_subconnector_enum_list) 186f453ba04SDave Airlie 187d20d3174SVille Syrjälä static const struct drm_prop_enum_list drm_dirty_info_enum_list[] = { 188884840aaSJakob Bornecrantz { DRM_MODE_DIRTY_OFF, "Off" }, 189884840aaSJakob Bornecrantz { DRM_MODE_DIRTY_ON, "On" }, 190884840aaSJakob Bornecrantz { DRM_MODE_DIRTY_ANNOTATE, "Annotate" }, 191884840aaSJakob Bornecrantz }; 192884840aaSJakob Bornecrantz 193f453ba04SDave Airlie struct drm_conn_prop_enum_list { 194f453ba04SDave Airlie int type; 195d20d3174SVille Syrjälä const char *name; 196b21e3afeSIlia Mirkin struct ida ida; 197f453ba04SDave Airlie }; 198f453ba04SDave Airlie 199f453ba04SDave Airlie /* 200f453ba04SDave Airlie * Connector and encoder types. 201f453ba04SDave Airlie */ 202f453ba04SDave Airlie static struct drm_conn_prop_enum_list drm_connector_enum_list[] = 203b21e3afeSIlia Mirkin { { DRM_MODE_CONNECTOR_Unknown, "Unknown" }, 204b21e3afeSIlia Mirkin { DRM_MODE_CONNECTOR_VGA, "VGA" }, 205b21e3afeSIlia Mirkin { DRM_MODE_CONNECTOR_DVII, "DVI-I" }, 206b21e3afeSIlia Mirkin { DRM_MODE_CONNECTOR_DVID, "DVI-D" }, 207b21e3afeSIlia Mirkin { DRM_MODE_CONNECTOR_DVIA, "DVI-A" }, 208b21e3afeSIlia Mirkin { DRM_MODE_CONNECTOR_Composite, "Composite" }, 209b21e3afeSIlia Mirkin { DRM_MODE_CONNECTOR_SVIDEO, "SVIDEO" }, 210b21e3afeSIlia Mirkin { DRM_MODE_CONNECTOR_LVDS, "LVDS" }, 211b21e3afeSIlia Mirkin { DRM_MODE_CONNECTOR_Component, "Component" }, 212b21e3afeSIlia Mirkin { DRM_MODE_CONNECTOR_9PinDIN, "DIN" }, 213b21e3afeSIlia Mirkin { DRM_MODE_CONNECTOR_DisplayPort, "DP" }, 214b21e3afeSIlia Mirkin { DRM_MODE_CONNECTOR_HDMIA, "HDMI-A" }, 215b21e3afeSIlia Mirkin { DRM_MODE_CONNECTOR_HDMIB, "HDMI-B" }, 216b21e3afeSIlia Mirkin { DRM_MODE_CONNECTOR_TV, "TV" }, 217b21e3afeSIlia Mirkin { DRM_MODE_CONNECTOR_eDP, "eDP" }, 218b21e3afeSIlia Mirkin { DRM_MODE_CONNECTOR_VIRTUAL, "Virtual" }, 219b8923273SShobhit Kumar { DRM_MODE_CONNECTOR_DSI, "DSI" }, 220f453ba04SDave Airlie }; 221f453ba04SDave Airlie 222d20d3174SVille Syrjälä static const struct drm_prop_enum_list drm_encoder_enum_list[] = 223f453ba04SDave Airlie { { DRM_MODE_ENCODER_NONE, "None" }, 224f453ba04SDave Airlie { DRM_MODE_ENCODER_DAC, "DAC" }, 225f453ba04SDave Airlie { DRM_MODE_ENCODER_TMDS, "TMDS" }, 226f453ba04SDave Airlie { DRM_MODE_ENCODER_LVDS, "LVDS" }, 227f453ba04SDave Airlie { DRM_MODE_ENCODER_TVDAC, "TV" }, 228a7331e5cSThomas Hellstrom { DRM_MODE_ENCODER_VIRTUAL, "Virtual" }, 229b8923273SShobhit Kumar { DRM_MODE_ENCODER_DSI, "DSI" }, 230f453ba04SDave Airlie }; 231f453ba04SDave Airlie 232ac1bb36cSJesse Barnes static const struct drm_prop_enum_list drm_subpixel_enum_list[] = 233ac1bb36cSJesse Barnes { 234ac1bb36cSJesse Barnes { SubPixelUnknown, "Unknown" }, 235ac1bb36cSJesse Barnes { SubPixelHorizontalRGB, "Horizontal RGB" }, 236ac1bb36cSJesse Barnes { SubPixelHorizontalBGR, "Horizontal BGR" }, 237ac1bb36cSJesse Barnes { SubPixelVerticalRGB, "Vertical RGB" }, 238ac1bb36cSJesse Barnes { SubPixelVerticalBGR, "Vertical BGR" }, 239ac1bb36cSJesse Barnes { SubPixelNone, "None" }, 240ac1bb36cSJesse Barnes }; 241ac1bb36cSJesse Barnes 242b21e3afeSIlia Mirkin void drm_connector_ida_init(void) 243b21e3afeSIlia Mirkin { 244b21e3afeSIlia Mirkin int i; 245b21e3afeSIlia Mirkin 246b21e3afeSIlia Mirkin for (i = 0; i < ARRAY_SIZE(drm_connector_enum_list); i++) 247b21e3afeSIlia Mirkin ida_init(&drm_connector_enum_list[i].ida); 248b21e3afeSIlia Mirkin } 249b21e3afeSIlia Mirkin 250b21e3afeSIlia Mirkin void drm_connector_ida_destroy(void) 251b21e3afeSIlia Mirkin { 252b21e3afeSIlia Mirkin int i; 253b21e3afeSIlia Mirkin 254b21e3afeSIlia Mirkin for (i = 0; i < ARRAY_SIZE(drm_connector_enum_list); i++) 255b21e3afeSIlia Mirkin ida_destroy(&drm_connector_enum_list[i].ida); 256b21e3afeSIlia Mirkin } 257b21e3afeSIlia Mirkin 258c8e32cc1SDaniel Vetter /** 259c8e32cc1SDaniel Vetter * drm_get_encoder_name - return a string for encoder 260c8e32cc1SDaniel Vetter * @encoder: encoder to compute name of 261c8e32cc1SDaniel Vetter * 262c8e32cc1SDaniel Vetter * Note that the buffer used by this function is globally shared and owned by 263c8e32cc1SDaniel Vetter * the function itself. 264c8e32cc1SDaniel Vetter * 265c8e32cc1SDaniel Vetter * FIXME: This isn't really multithreading safe. 266c8e32cc1SDaniel Vetter */ 267d20d3174SVille Syrjälä const char *drm_get_encoder_name(const struct drm_encoder *encoder) 268f453ba04SDave Airlie { 269f453ba04SDave Airlie static char buf[32]; 270f453ba04SDave Airlie 271f453ba04SDave Airlie snprintf(buf, 32, "%s-%d", 272f453ba04SDave Airlie drm_encoder_enum_list[encoder->encoder_type].name, 273f453ba04SDave Airlie encoder->base.id); 274f453ba04SDave Airlie return buf; 275f453ba04SDave Airlie } 27613a8195bSDave Airlie EXPORT_SYMBOL(drm_get_encoder_name); 277f453ba04SDave Airlie 278c8e32cc1SDaniel Vetter /** 279c8e32cc1SDaniel Vetter * drm_get_connector_name - return a string for connector 280c8e32cc1SDaniel Vetter * @connector: connector to compute name of 281c8e32cc1SDaniel Vetter * 282c8e32cc1SDaniel Vetter * Note that the buffer used by this function is globally shared and owned by 283c8e32cc1SDaniel Vetter * the function itself. 284c8e32cc1SDaniel Vetter * 285c8e32cc1SDaniel Vetter * FIXME: This isn't really multithreading safe. 286c8e32cc1SDaniel Vetter */ 287d20d3174SVille Syrjälä const char *drm_get_connector_name(const struct drm_connector *connector) 288f453ba04SDave Airlie { 289f453ba04SDave Airlie static char buf[32]; 290f453ba04SDave Airlie 291f453ba04SDave Airlie snprintf(buf, 32, "%s-%d", 292f453ba04SDave Airlie drm_connector_enum_list[connector->connector_type].name, 293f453ba04SDave Airlie connector->connector_type_id); 294f453ba04SDave Airlie return buf; 295f453ba04SDave Airlie } 296f453ba04SDave Airlie EXPORT_SYMBOL(drm_get_connector_name); 297f453ba04SDave Airlie 298c8e32cc1SDaniel Vetter /** 299c8e32cc1SDaniel Vetter * drm_get_connector_status_name - return a string for connector status 300c8e32cc1SDaniel Vetter * @status: connector status to compute name of 301c8e32cc1SDaniel Vetter * 302c8e32cc1SDaniel Vetter * In contrast to the other drm_get_*_name functions this one here returns a 303c8e32cc1SDaniel Vetter * const pointer and hence is threadsafe. 304c8e32cc1SDaniel Vetter */ 305d20d3174SVille Syrjälä const char *drm_get_connector_status_name(enum drm_connector_status status) 306f453ba04SDave Airlie { 307f453ba04SDave Airlie if (status == connector_status_connected) 308f453ba04SDave Airlie return "connected"; 309f453ba04SDave Airlie else if (status == connector_status_disconnected) 310f453ba04SDave Airlie return "disconnected"; 311f453ba04SDave Airlie else 312f453ba04SDave Airlie return "unknown"; 313f453ba04SDave Airlie } 314ed7951dcSLespiau, Damien EXPORT_SYMBOL(drm_get_connector_status_name); 315f453ba04SDave Airlie 316ac1bb36cSJesse Barnes /** 317ac1bb36cSJesse Barnes * drm_get_subpixel_order_name - return a string for a given subpixel enum 318ac1bb36cSJesse Barnes * @order: enum of subpixel_order 319ac1bb36cSJesse Barnes * 320ac1bb36cSJesse Barnes * Note you could abuse this and return something out of bounds, but that 321ac1bb36cSJesse Barnes * would be a caller error. No unscrubbed user data should make it here. 322ac1bb36cSJesse Barnes */ 323ac1bb36cSJesse Barnes const char *drm_get_subpixel_order_name(enum subpixel_order order) 324ac1bb36cSJesse Barnes { 325ac1bb36cSJesse Barnes return drm_subpixel_enum_list[order].name; 326ac1bb36cSJesse Barnes } 327ac1bb36cSJesse Barnes EXPORT_SYMBOL(drm_get_subpixel_order_name); 328ac1bb36cSJesse Barnes 3296ba6d03eSVille Syrjälä static char printable_char(int c) 3306ba6d03eSVille Syrjälä { 3316ba6d03eSVille Syrjälä return isascii(c) && isprint(c) ? c : '?'; 3326ba6d03eSVille Syrjälä } 3336ba6d03eSVille Syrjälä 334c8e32cc1SDaniel Vetter /** 335c8e32cc1SDaniel Vetter * drm_get_format_name - return a string for drm fourcc format 336c8e32cc1SDaniel Vetter * @format: format to compute name of 337c8e32cc1SDaniel Vetter * 338c8e32cc1SDaniel Vetter * Note that the buffer used by this function is globally shared and owned by 339c8e32cc1SDaniel Vetter * the function itself. 340c8e32cc1SDaniel Vetter * 341c8e32cc1SDaniel Vetter * FIXME: This isn't really multithreading safe. 342c8e32cc1SDaniel Vetter */ 343d20d3174SVille Syrjälä const char *drm_get_format_name(uint32_t format) 3446ba6d03eSVille Syrjälä { 3456ba6d03eSVille Syrjälä static char buf[32]; 3466ba6d03eSVille Syrjälä 3476ba6d03eSVille Syrjälä snprintf(buf, sizeof(buf), 3486ba6d03eSVille Syrjälä "%c%c%c%c %s-endian (0x%08x)", 3496ba6d03eSVille Syrjälä printable_char(format & 0xff), 3506ba6d03eSVille Syrjälä printable_char((format >> 8) & 0xff), 3516ba6d03eSVille Syrjälä printable_char((format >> 16) & 0xff), 3526ba6d03eSVille Syrjälä printable_char((format >> 24) & 0x7f), 3536ba6d03eSVille Syrjälä format & DRM_FORMAT_BIG_ENDIAN ? "big" : "little", 3546ba6d03eSVille Syrjälä format); 3556ba6d03eSVille Syrjälä 3566ba6d03eSVille Syrjälä return buf; 3576ba6d03eSVille Syrjälä } 3586ba6d03eSVille Syrjälä EXPORT_SYMBOL(drm_get_format_name); 3596ba6d03eSVille Syrjälä 360f453ba04SDave Airlie /** 361065a50edSDaniel Vetter * drm_mode_object_get - allocate a new modeset identifier 362f453ba04SDave Airlie * @dev: DRM device 363065a50edSDaniel Vetter * @obj: object pointer, used to generate unique ID 364065a50edSDaniel Vetter * @obj_type: object type 365f453ba04SDave Airlie * 366f453ba04SDave Airlie * Create a unique identifier based on @ptr in @dev's identifier space. Used 367c8e32cc1SDaniel Vetter * for tracking modes, CRTCs and connectors. Note that despite the _get postfix 368c8e32cc1SDaniel Vetter * modeset identifiers are _not_ reference counted. Hence don't use this for 369c8e32cc1SDaniel Vetter * reference counted modeset objects like framebuffers. 370f453ba04SDave Airlie * 371c8e32cc1SDaniel Vetter * Returns: 372f453ba04SDave Airlie * New unique (relative to other objects in @dev) integer identifier for the 373f453ba04SDave Airlie * object. 374f453ba04SDave Airlie */ 3758bd441b2SDaniel Vetter int drm_mode_object_get(struct drm_device *dev, 376f453ba04SDave Airlie struct drm_mode_object *obj, uint32_t obj_type) 377f453ba04SDave Airlie { 378f453ba04SDave Airlie int ret; 379f453ba04SDave Airlie 380ad2563c2SJesse Barnes mutex_lock(&dev->mode_config.idr_mutex); 3812e928815STejun Heo ret = idr_alloc(&dev->mode_config.crtc_idr, obj, 1, 0, GFP_KERNEL); 3822e928815STejun Heo if (ret >= 0) { 3834b096ac1SDaniel Vetter /* 3844b096ac1SDaniel Vetter * Set up the object linking under the protection of the idr 3854b096ac1SDaniel Vetter * lock so that other users can't see inconsistent state. 3864b096ac1SDaniel Vetter */ 3872e928815STejun Heo obj->id = ret; 388f453ba04SDave Airlie obj->type = obj_type; 3894b096ac1SDaniel Vetter } 3904b096ac1SDaniel Vetter mutex_unlock(&dev->mode_config.idr_mutex); 3914b096ac1SDaniel Vetter 3922e928815STejun Heo return ret < 0 ? ret : 0; 393f453ba04SDave Airlie } 394f453ba04SDave Airlie 395f453ba04SDave Airlie /** 396065a50edSDaniel Vetter * drm_mode_object_put - free a modeset identifer 397f453ba04SDave Airlie * @dev: DRM device 398065a50edSDaniel Vetter * @object: object to free 399f453ba04SDave Airlie * 400c8e32cc1SDaniel Vetter * Free @id from @dev's unique identifier pool. Note that despite the _get 401c8e32cc1SDaniel Vetter * postfix modeset identifiers are _not_ reference counted. Hence don't use this 402c8e32cc1SDaniel Vetter * for reference counted modeset objects like framebuffers. 403f453ba04SDave Airlie */ 4048bd441b2SDaniel Vetter void drm_mode_object_put(struct drm_device *dev, 405f453ba04SDave Airlie struct drm_mode_object *object) 406f453ba04SDave Airlie { 407ad2563c2SJesse Barnes mutex_lock(&dev->mode_config.idr_mutex); 408f453ba04SDave Airlie idr_remove(&dev->mode_config.crtc_idr, object->id); 409ad2563c2SJesse Barnes mutex_unlock(&dev->mode_config.idr_mutex); 410f453ba04SDave Airlie } 411f453ba04SDave Airlie 412786b99edSDaniel Vetter /** 413786b99edSDaniel Vetter * drm_mode_object_find - look up a drm object with static lifetime 414786b99edSDaniel Vetter * @dev: drm device 415786b99edSDaniel Vetter * @id: id of the mode object 416786b99edSDaniel Vetter * @type: type of the mode object 417786b99edSDaniel Vetter * 418786b99edSDaniel Vetter * Note that framebuffers cannot be looked up with this functions - since those 419786b99edSDaniel Vetter * are reference counted, they need special treatment. 420786b99edSDaniel Vetter */ 4217a9c9060SDaniel Vetter struct drm_mode_object *drm_mode_object_find(struct drm_device *dev, 4227a9c9060SDaniel Vetter uint32_t id, uint32_t type) 423f453ba04SDave Airlie { 424ad2563c2SJesse Barnes struct drm_mode_object *obj = NULL; 425f453ba04SDave Airlie 426786b99edSDaniel Vetter /* Framebuffers are reference counted and need their own lookup 427786b99edSDaniel Vetter * function.*/ 428786b99edSDaniel Vetter WARN_ON(type == DRM_MODE_OBJECT_FB); 429786b99edSDaniel Vetter 430ad2563c2SJesse Barnes mutex_lock(&dev->mode_config.idr_mutex); 431f453ba04SDave Airlie obj = idr_find(&dev->mode_config.crtc_idr, id); 432f453ba04SDave Airlie if (!obj || (obj->type != type) || (obj->id != id)) 433ad2563c2SJesse Barnes obj = NULL; 434ad2563c2SJesse Barnes mutex_unlock(&dev->mode_config.idr_mutex); 435f453ba04SDave Airlie 436f453ba04SDave Airlie return obj; 437f453ba04SDave Airlie } 438f453ba04SDave Airlie EXPORT_SYMBOL(drm_mode_object_find); 439f453ba04SDave Airlie 440f453ba04SDave Airlie /** 441f453ba04SDave Airlie * drm_framebuffer_init - initialize a framebuffer 442f453ba04SDave Airlie * @dev: DRM device 443065a50edSDaniel Vetter * @fb: framebuffer to be initialized 444065a50edSDaniel Vetter * @funcs: ... with these functions 445f453ba04SDave Airlie * 446f453ba04SDave Airlie * Allocates an ID for the framebuffer's parent mode object, sets its mode 447f453ba04SDave Airlie * functions & device file and adds it to the master fd list. 448f453ba04SDave Airlie * 4494b096ac1SDaniel Vetter * IMPORTANT: 4504b096ac1SDaniel Vetter * This functions publishes the fb and makes it available for concurrent access 4514b096ac1SDaniel Vetter * by other users. Which means by this point the fb _must_ be fully set up - 4524b096ac1SDaniel Vetter * since all the fb attributes are invariant over its lifetime, no further 4534b096ac1SDaniel Vetter * locking but only correct reference counting is required. 4544b096ac1SDaniel Vetter * 455c8e32cc1SDaniel Vetter * Returns: 456af901ca1SAndré Goddard Rosa * Zero on success, error code on failure. 457f453ba04SDave Airlie */ 458f453ba04SDave Airlie int drm_framebuffer_init(struct drm_device *dev, struct drm_framebuffer *fb, 459f453ba04SDave Airlie const struct drm_framebuffer_funcs *funcs) 460f453ba04SDave Airlie { 461f453ba04SDave Airlie int ret; 462f453ba04SDave Airlie 4634b096ac1SDaniel Vetter mutex_lock(&dev->mode_config.fb_lock); 464f7eff60eSRob Clark kref_init(&fb->refcount); 4654b096ac1SDaniel Vetter INIT_LIST_HEAD(&fb->filp_head); 4664b096ac1SDaniel Vetter fb->dev = dev; 4674b096ac1SDaniel Vetter fb->funcs = funcs; 468f7eff60eSRob Clark 469f453ba04SDave Airlie ret = drm_mode_object_get(dev, &fb->base, DRM_MODE_OBJECT_FB); 4706bfc56aaSVille Syrjälä if (ret) 4714b096ac1SDaniel Vetter goto out; 472f453ba04SDave Airlie 4732b677e8cSDaniel Vetter /* Grab the idr reference. */ 4742b677e8cSDaniel Vetter drm_framebuffer_reference(fb); 4752b677e8cSDaniel Vetter 476f453ba04SDave Airlie dev->mode_config.num_fb++; 477f453ba04SDave Airlie list_add(&fb->head, &dev->mode_config.fb_list); 4784b096ac1SDaniel Vetter out: 4794b096ac1SDaniel Vetter mutex_unlock(&dev->mode_config.fb_lock); 480f453ba04SDave Airlie 481f453ba04SDave Airlie return 0; 482f453ba04SDave Airlie } 483f453ba04SDave Airlie EXPORT_SYMBOL(drm_framebuffer_init); 484f453ba04SDave Airlie 485f7eff60eSRob Clark static void drm_framebuffer_free(struct kref *kref) 486f7eff60eSRob Clark { 487f7eff60eSRob Clark struct drm_framebuffer *fb = 488f7eff60eSRob Clark container_of(kref, struct drm_framebuffer, refcount); 489f7eff60eSRob Clark fb->funcs->destroy(fb); 490f7eff60eSRob Clark } 491f7eff60eSRob Clark 4922b677e8cSDaniel Vetter static struct drm_framebuffer *__drm_framebuffer_lookup(struct drm_device *dev, 4932b677e8cSDaniel Vetter uint32_t id) 4942b677e8cSDaniel Vetter { 4952b677e8cSDaniel Vetter struct drm_mode_object *obj = NULL; 4962b677e8cSDaniel Vetter struct drm_framebuffer *fb; 4972b677e8cSDaniel Vetter 4982b677e8cSDaniel Vetter mutex_lock(&dev->mode_config.idr_mutex); 4992b677e8cSDaniel Vetter obj = idr_find(&dev->mode_config.crtc_idr, id); 5002b677e8cSDaniel Vetter if (!obj || (obj->type != DRM_MODE_OBJECT_FB) || (obj->id != id)) 5012b677e8cSDaniel Vetter fb = NULL; 5022b677e8cSDaniel Vetter else 5032b677e8cSDaniel Vetter fb = obj_to_fb(obj); 5042b677e8cSDaniel Vetter mutex_unlock(&dev->mode_config.idr_mutex); 5052b677e8cSDaniel Vetter 5062b677e8cSDaniel Vetter return fb; 5072b677e8cSDaniel Vetter } 5082b677e8cSDaniel Vetter 509f7eff60eSRob Clark /** 510786b99edSDaniel Vetter * drm_framebuffer_lookup - look up a drm framebuffer and grab a reference 511786b99edSDaniel Vetter * @dev: drm device 512786b99edSDaniel Vetter * @id: id of the fb object 513786b99edSDaniel Vetter * 514786b99edSDaniel Vetter * If successful, this grabs an additional reference to the framebuffer - 515786b99edSDaniel Vetter * callers need to make sure to eventually unreference the returned framebuffer 516c8e32cc1SDaniel Vetter * again, using @drm_framebuffer_unreference. 517786b99edSDaniel Vetter */ 518786b99edSDaniel Vetter struct drm_framebuffer *drm_framebuffer_lookup(struct drm_device *dev, 519786b99edSDaniel Vetter uint32_t id) 520786b99edSDaniel Vetter { 521786b99edSDaniel Vetter struct drm_framebuffer *fb; 522786b99edSDaniel Vetter 523786b99edSDaniel Vetter mutex_lock(&dev->mode_config.fb_lock); 5242b677e8cSDaniel Vetter fb = __drm_framebuffer_lookup(dev, id); 525786b99edSDaniel Vetter if (fb) 5269131d3d8Sarchit taneja drm_framebuffer_reference(fb); 527786b99edSDaniel Vetter mutex_unlock(&dev->mode_config.fb_lock); 528786b99edSDaniel Vetter 529786b99edSDaniel Vetter return fb; 530786b99edSDaniel Vetter } 531786b99edSDaniel Vetter EXPORT_SYMBOL(drm_framebuffer_lookup); 532786b99edSDaniel Vetter 533786b99edSDaniel Vetter /** 534f7eff60eSRob Clark * drm_framebuffer_unreference - unref a framebuffer 535065a50edSDaniel Vetter * @fb: framebuffer to unref 536065a50edSDaniel Vetter * 537065a50edSDaniel Vetter * This functions decrements the fb's refcount and frees it if it drops to zero. 538f7eff60eSRob Clark */ 539f7eff60eSRob Clark void drm_framebuffer_unreference(struct drm_framebuffer *fb) 540f7eff60eSRob Clark { 541f7eff60eSRob Clark DRM_DEBUG("FB ID: %d\n", fb->base.id); 542f7eff60eSRob Clark kref_put(&fb->refcount, drm_framebuffer_free); 543f7eff60eSRob Clark } 544f7eff60eSRob Clark EXPORT_SYMBOL(drm_framebuffer_unreference); 545f7eff60eSRob Clark 546f7eff60eSRob Clark /** 547f7eff60eSRob Clark * drm_framebuffer_reference - incr the fb refcnt 548065a50edSDaniel Vetter * @fb: framebuffer 549c8e32cc1SDaniel Vetter * 550c8e32cc1SDaniel Vetter * This functions increments the fb's refcount. 551f7eff60eSRob Clark */ 552f7eff60eSRob Clark void drm_framebuffer_reference(struct drm_framebuffer *fb) 553f7eff60eSRob Clark { 554f7eff60eSRob Clark DRM_DEBUG("FB ID: %d\n", fb->base.id); 555f7eff60eSRob Clark kref_get(&fb->refcount); 556f7eff60eSRob Clark } 557f7eff60eSRob Clark EXPORT_SYMBOL(drm_framebuffer_reference); 558f7eff60eSRob Clark 5592b677e8cSDaniel Vetter static void drm_framebuffer_free_bug(struct kref *kref) 5602b677e8cSDaniel Vetter { 5612b677e8cSDaniel Vetter BUG(); 5622b677e8cSDaniel Vetter } 5632b677e8cSDaniel Vetter 5646c2a7532SDaniel Vetter static void __drm_framebuffer_unreference(struct drm_framebuffer *fb) 5656c2a7532SDaniel Vetter { 5666c2a7532SDaniel Vetter DRM_DEBUG("FB ID: %d\n", fb->base.id); 5676c2a7532SDaniel Vetter kref_put(&fb->refcount, drm_framebuffer_free_bug); 5686c2a7532SDaniel Vetter } 5696c2a7532SDaniel Vetter 5702b677e8cSDaniel Vetter /* dev->mode_config.fb_lock must be held! */ 5712b677e8cSDaniel Vetter static void __drm_framebuffer_unregister(struct drm_device *dev, 5722b677e8cSDaniel Vetter struct drm_framebuffer *fb) 5732b677e8cSDaniel Vetter { 5742b677e8cSDaniel Vetter mutex_lock(&dev->mode_config.idr_mutex); 5752b677e8cSDaniel Vetter idr_remove(&dev->mode_config.crtc_idr, fb->base.id); 5762b677e8cSDaniel Vetter mutex_unlock(&dev->mode_config.idr_mutex); 5772b677e8cSDaniel Vetter 5782b677e8cSDaniel Vetter fb->base.id = 0; 5792b677e8cSDaniel Vetter 5806c2a7532SDaniel Vetter __drm_framebuffer_unreference(fb); 5812b677e8cSDaniel Vetter } 5822b677e8cSDaniel Vetter 583f453ba04SDave Airlie /** 58436206361SDaniel Vetter * drm_framebuffer_unregister_private - unregister a private fb from the lookup idr 58536206361SDaniel Vetter * @fb: fb to unregister 58636206361SDaniel Vetter * 58736206361SDaniel Vetter * Drivers need to call this when cleaning up driver-private framebuffers, e.g. 58836206361SDaniel Vetter * those used for fbdev. Note that the caller must hold a reference of it's own, 58936206361SDaniel Vetter * i.e. the object may not be destroyed through this call (since it'll lead to a 59036206361SDaniel Vetter * locking inversion). 59136206361SDaniel Vetter */ 59236206361SDaniel Vetter void drm_framebuffer_unregister_private(struct drm_framebuffer *fb) 59336206361SDaniel Vetter { 5942b677e8cSDaniel Vetter struct drm_device *dev = fb->dev; 5952b677e8cSDaniel Vetter 5962b677e8cSDaniel Vetter mutex_lock(&dev->mode_config.fb_lock); 5972b677e8cSDaniel Vetter /* Mark fb as reaped and drop idr ref. */ 5982b677e8cSDaniel Vetter __drm_framebuffer_unregister(dev, fb); 5992b677e8cSDaniel Vetter mutex_unlock(&dev->mode_config.fb_lock); 60036206361SDaniel Vetter } 60136206361SDaniel Vetter EXPORT_SYMBOL(drm_framebuffer_unregister_private); 60236206361SDaniel Vetter 60336206361SDaniel Vetter /** 604f453ba04SDave Airlie * drm_framebuffer_cleanup - remove a framebuffer object 605f453ba04SDave Airlie * @fb: framebuffer to remove 606f453ba04SDave Airlie * 607c8e32cc1SDaniel Vetter * Cleanup framebuffer. This function is intended to be used from the drivers 608c8e32cc1SDaniel Vetter * ->destroy callback. It can also be used to clean up driver private 609c8e32cc1SDaniel Vetter * framebuffers embedded into a larger structure. 61036206361SDaniel Vetter * 61136206361SDaniel Vetter * Note that this function does not remove the fb from active usuage - if it is 61236206361SDaniel Vetter * still used anywhere, hilarity can ensue since userspace could call getfb on 61336206361SDaniel Vetter * the id and get back -EINVAL. Obviously no concern at driver unload time. 61436206361SDaniel Vetter * 61536206361SDaniel Vetter * Also, the framebuffer will not be removed from the lookup idr - for 61636206361SDaniel Vetter * user-created framebuffers this will happen in in the rmfb ioctl. For 61736206361SDaniel Vetter * driver-private objects (e.g. for fbdev) drivers need to explicitly call 61836206361SDaniel Vetter * drm_framebuffer_unregister_private. 619f453ba04SDave Airlie */ 620f453ba04SDave Airlie void drm_framebuffer_cleanup(struct drm_framebuffer *fb) 621f453ba04SDave Airlie { 622f453ba04SDave Airlie struct drm_device *dev = fb->dev; 6238faf6b18SDaniel Vetter 6244b096ac1SDaniel Vetter mutex_lock(&dev->mode_config.fb_lock); 625f7eff60eSRob Clark list_del(&fb->head); 626f7eff60eSRob Clark dev->mode_config.num_fb--; 6274b096ac1SDaniel Vetter mutex_unlock(&dev->mode_config.fb_lock); 628f7eff60eSRob Clark } 629f7eff60eSRob Clark EXPORT_SYMBOL(drm_framebuffer_cleanup); 630f7eff60eSRob Clark 631f7eff60eSRob Clark /** 632f7eff60eSRob Clark * drm_framebuffer_remove - remove and unreference a framebuffer object 633f7eff60eSRob Clark * @fb: framebuffer to remove 634f7eff60eSRob Clark * 635f7eff60eSRob Clark * Scans all the CRTCs and planes in @dev's mode_config. If they're 63636206361SDaniel Vetter * using @fb, removes it, setting it to NULL. Then drops the reference to the 637b62584e3SDaniel Vetter * passed-in framebuffer. Might take the modeset locks. 638b62584e3SDaniel Vetter * 639b62584e3SDaniel Vetter * Note that this function optimizes the cleanup away if the caller holds the 640b62584e3SDaniel Vetter * last reference to the framebuffer. It is also guaranteed to not take the 641b62584e3SDaniel Vetter * modeset locks in this case. 642f7eff60eSRob Clark */ 643f7eff60eSRob Clark void drm_framebuffer_remove(struct drm_framebuffer *fb) 644f7eff60eSRob Clark { 645f7eff60eSRob Clark struct drm_device *dev = fb->dev; 646f453ba04SDave Airlie struct drm_crtc *crtc; 6478cf5c917SJesse Barnes struct drm_plane *plane; 6485ef5f72fSDave Airlie struct drm_mode_set set; 6495ef5f72fSDave Airlie int ret; 650f453ba04SDave Airlie 6514b096ac1SDaniel Vetter WARN_ON(!list_empty(&fb->filp_head)); 6528faf6b18SDaniel Vetter 653b62584e3SDaniel Vetter /* 654b62584e3SDaniel Vetter * drm ABI mandates that we remove any deleted framebuffers from active 655b62584e3SDaniel Vetter * useage. But since most sane clients only remove framebuffers they no 656b62584e3SDaniel Vetter * longer need, try to optimize this away. 657b62584e3SDaniel Vetter * 658b62584e3SDaniel Vetter * Since we're holding a reference ourselves, observing a refcount of 1 659b62584e3SDaniel Vetter * means that we're the last holder and can skip it. Also, the refcount 660b62584e3SDaniel Vetter * can never increase from 1 again, so we don't need any barriers or 661b62584e3SDaniel Vetter * locks. 662b62584e3SDaniel Vetter * 663b62584e3SDaniel Vetter * Note that userspace could try to race with use and instate a new 664b62584e3SDaniel Vetter * usage _after_ we've cleared all current ones. End result will be an 665b62584e3SDaniel Vetter * in-use fb with fb-id == 0. Userspace is allowed to shoot its own foot 666b62584e3SDaniel Vetter * in this manner. 667b62584e3SDaniel Vetter */ 668b62584e3SDaniel Vetter if (atomic_read(&fb->refcount.refcount) > 1) { 669b62584e3SDaniel Vetter drm_modeset_lock_all(dev); 670f453ba04SDave Airlie /* remove from any CRTC */ 671f453ba04SDave Airlie list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { 672f4510a27SMatt Roper if (crtc->primary->fb == fb) { 6735ef5f72fSDave Airlie /* should turn off the crtc */ 6745ef5f72fSDave Airlie memset(&set, 0, sizeof(struct drm_mode_set)); 6755ef5f72fSDave Airlie set.crtc = crtc; 6765ef5f72fSDave Airlie set.fb = NULL; 6772d13b679SDaniel Vetter ret = drm_mode_set_config_internal(&set); 6785ef5f72fSDave Airlie if (ret) 6795ef5f72fSDave Airlie DRM_ERROR("failed to reset crtc %p when fb was deleted\n", crtc); 6805ef5f72fSDave Airlie } 681f453ba04SDave Airlie } 682f453ba04SDave Airlie 6838cf5c917SJesse Barnes list_for_each_entry(plane, &dev->mode_config.plane_list, head) { 6849125e618SVille Syrjälä if (plane->fb == fb) 6859125e618SVille Syrjälä drm_plane_force_disable(plane); 6868cf5c917SJesse Barnes } 687b62584e3SDaniel Vetter drm_modeset_unlock_all(dev); 688b62584e3SDaniel Vetter } 6898cf5c917SJesse Barnes 690f7eff60eSRob Clark drm_framebuffer_unreference(fb); 691f453ba04SDave Airlie } 692f7eff60eSRob Clark EXPORT_SYMBOL(drm_framebuffer_remove); 693f453ba04SDave Airlie 694f453ba04SDave Airlie /** 695e13161afSMatt Roper * drm_crtc_init_with_planes - Initialise a new CRTC object with 696e13161afSMatt Roper * specified primary and cursor planes. 697f453ba04SDave Airlie * @dev: DRM device 698f453ba04SDave Airlie * @crtc: CRTC object to init 699e13161afSMatt Roper * @primary: Primary plane for CRTC 700e13161afSMatt Roper * @cursor: Cursor plane for CRTC 701f453ba04SDave Airlie * @funcs: callbacks for the new CRTC 702f453ba04SDave Airlie * 703ad6f5c34SVille Syrjälä * Inits a new object created as base part of a driver crtc object. 7046bfc56aaSVille Syrjälä * 705c8e32cc1SDaniel Vetter * Returns: 7066bfc56aaSVille Syrjälä * Zero on success, error code on failure. 707f453ba04SDave Airlie */ 708e13161afSMatt Roper int drm_crtc_init_with_planes(struct drm_device *dev, struct drm_crtc *crtc, 709e13161afSMatt Roper struct drm_plane *primary, 710e13161afSMatt Roper void *cursor, 711f453ba04SDave Airlie const struct drm_crtc_funcs *funcs) 712f453ba04SDave Airlie { 7136bfc56aaSVille Syrjälä int ret; 7146bfc56aaSVille Syrjälä 715f453ba04SDave Airlie crtc->dev = dev; 716f453ba04SDave Airlie crtc->funcs = funcs; 7177c80e128SRob Clark crtc->invert_dimensions = false; 718f453ba04SDave Airlie 71984849903SDaniel Vetter drm_modeset_lock_all(dev); 72029494c17SDaniel Vetter mutex_init(&crtc->mutex); 72129494c17SDaniel Vetter mutex_lock_nest_lock(&crtc->mutex, &dev->mode_config.mutex); 7226bfc56aaSVille Syrjälä 7236bfc56aaSVille Syrjälä ret = drm_mode_object_get(dev, &crtc->base, DRM_MODE_OBJECT_CRTC); 7246bfc56aaSVille Syrjälä if (ret) 7256bfc56aaSVille Syrjälä goto out; 726f453ba04SDave Airlie 727bffd9de0SPaulo Zanoni crtc->base.properties = &crtc->properties; 728bffd9de0SPaulo Zanoni 729f453ba04SDave Airlie list_add_tail(&crtc->head, &dev->mode_config.crtc_list); 730f453ba04SDave Airlie dev->mode_config.num_crtc++; 7316bfc56aaSVille Syrjälä 732e13161afSMatt Roper crtc->primary = primary; 733e13161afSMatt Roper if (primary) 734e13161afSMatt Roper primary->possible_crtcs = 1 << drm_crtc_index(crtc); 735e13161afSMatt Roper 7366bfc56aaSVille Syrjälä out: 73784849903SDaniel Vetter drm_modeset_unlock_all(dev); 7386bfc56aaSVille Syrjälä 7396bfc56aaSVille Syrjälä return ret; 740f453ba04SDave Airlie } 741e13161afSMatt Roper EXPORT_SYMBOL(drm_crtc_init_with_planes); 742f453ba04SDave Airlie 743f453ba04SDave Airlie /** 744ad6f5c34SVille Syrjälä * drm_crtc_cleanup - Clean up the core crtc usage 745f453ba04SDave Airlie * @crtc: CRTC to cleanup 746f453ba04SDave Airlie * 747ad6f5c34SVille Syrjälä * This function cleans up @crtc and removes it from the DRM mode setting 748ad6f5c34SVille Syrjälä * core. Note that the function does *not* free the crtc structure itself, 749ad6f5c34SVille Syrjälä * this is the responsibility of the caller. 750f453ba04SDave Airlie */ 751f453ba04SDave Airlie void drm_crtc_cleanup(struct drm_crtc *crtc) 752f453ba04SDave Airlie { 753f453ba04SDave Airlie struct drm_device *dev = crtc->dev; 754f453ba04SDave Airlie 755f453ba04SDave Airlie kfree(crtc->gamma_store); 756f453ba04SDave Airlie crtc->gamma_store = NULL; 757f453ba04SDave Airlie 758f453ba04SDave Airlie drm_mode_object_put(dev, &crtc->base); 759f453ba04SDave Airlie list_del(&crtc->head); 760f453ba04SDave Airlie dev->mode_config.num_crtc--; 761f453ba04SDave Airlie } 762f453ba04SDave Airlie EXPORT_SYMBOL(drm_crtc_cleanup); 763f453ba04SDave Airlie 764f453ba04SDave Airlie /** 765db5f7a6eSRussell King * drm_crtc_index - find the index of a registered CRTC 766db5f7a6eSRussell King * @crtc: CRTC to find index for 767db5f7a6eSRussell King * 768db5f7a6eSRussell King * Given a registered CRTC, return the index of that CRTC within a DRM 769db5f7a6eSRussell King * device's list of CRTCs. 770db5f7a6eSRussell King */ 771db5f7a6eSRussell King unsigned int drm_crtc_index(struct drm_crtc *crtc) 772db5f7a6eSRussell King { 773db5f7a6eSRussell King unsigned int index = 0; 774db5f7a6eSRussell King struct drm_crtc *tmp; 775db5f7a6eSRussell King 776db5f7a6eSRussell King list_for_each_entry(tmp, &crtc->dev->mode_config.crtc_list, head) { 777db5f7a6eSRussell King if (tmp == crtc) 778db5f7a6eSRussell King return index; 779db5f7a6eSRussell King 780db5f7a6eSRussell King index++; 781db5f7a6eSRussell King } 782db5f7a6eSRussell King 783db5f7a6eSRussell King BUG(); 784db5f7a6eSRussell King } 785db5f7a6eSRussell King EXPORT_SYMBOL(drm_crtc_index); 786db5f7a6eSRussell King 78786f422d5SLespiau, Damien /* 788f453ba04SDave Airlie * drm_mode_remove - remove and free a mode 789f453ba04SDave Airlie * @connector: connector list to modify 790f453ba04SDave Airlie * @mode: mode to remove 791f453ba04SDave Airlie * 792f453ba04SDave Airlie * Remove @mode from @connector's mode list, then free it. 793f453ba04SDave Airlie */ 79486f422d5SLespiau, Damien static void drm_mode_remove(struct drm_connector *connector, 795f453ba04SDave Airlie struct drm_display_mode *mode) 796f453ba04SDave Airlie { 797f453ba04SDave Airlie list_del(&mode->head); 798554f1d78SSascha Hauer drm_mode_destroy(connector->dev, mode); 799f453ba04SDave Airlie } 800f453ba04SDave Airlie 801f453ba04SDave Airlie /** 802f453ba04SDave Airlie * drm_connector_init - Init a preallocated connector 803f453ba04SDave Airlie * @dev: DRM device 804f453ba04SDave Airlie * @connector: the connector to init 805f453ba04SDave Airlie * @funcs: callbacks for this connector 806065a50edSDaniel Vetter * @connector_type: user visible type of the connector 807f453ba04SDave Airlie * 808f453ba04SDave Airlie * Initialises a preallocated connector. Connectors should be 809f453ba04SDave Airlie * subclassed as part of driver connector objects. 8106bfc56aaSVille Syrjälä * 811c8e32cc1SDaniel Vetter * Returns: 8126bfc56aaSVille Syrjälä * Zero on success, error code on failure. 813f453ba04SDave Airlie */ 8146bfc56aaSVille Syrjälä int drm_connector_init(struct drm_device *dev, 815f453ba04SDave Airlie struct drm_connector *connector, 816f453ba04SDave Airlie const struct drm_connector_funcs *funcs, 817f453ba04SDave Airlie int connector_type) 818f453ba04SDave Airlie { 8196bfc56aaSVille Syrjälä int ret; 820b21e3afeSIlia Mirkin struct ida *connector_ida = 821b21e3afeSIlia Mirkin &drm_connector_enum_list[connector_type].ida; 8226bfc56aaSVille Syrjälä 82384849903SDaniel Vetter drm_modeset_lock_all(dev); 824f453ba04SDave Airlie 8256bfc56aaSVille Syrjälä ret = drm_mode_object_get(dev, &connector->base, DRM_MODE_OBJECT_CONNECTOR); 8266bfc56aaSVille Syrjälä if (ret) 8276bfc56aaSVille Syrjälä goto out; 8286bfc56aaSVille Syrjälä 8297e3bdf4aSPaulo Zanoni connector->base.properties = &connector->properties; 830f453ba04SDave Airlie connector->dev = dev; 831f453ba04SDave Airlie connector->funcs = funcs; 832f453ba04SDave Airlie connector->connector_type = connector_type; 833f453ba04SDave Airlie connector->connector_type_id = 834b21e3afeSIlia Mirkin ida_simple_get(connector_ida, 1, 0, GFP_KERNEL); 835b21e3afeSIlia Mirkin if (connector->connector_type_id < 0) { 836b21e3afeSIlia Mirkin ret = connector->connector_type_id; 837b21e3afeSIlia Mirkin drm_mode_object_put(dev, &connector->base); 838b21e3afeSIlia Mirkin goto out; 839b21e3afeSIlia Mirkin } 840f453ba04SDave Airlie INIT_LIST_HEAD(&connector->probed_modes); 841f453ba04SDave Airlie INIT_LIST_HEAD(&connector->modes); 842f453ba04SDave Airlie connector->edid_blob_ptr = NULL; 8435e2cb2f6SDaniel Vetter connector->status = connector_status_unknown; 844f453ba04SDave Airlie 845f453ba04SDave Airlie list_add_tail(&connector->head, &dev->mode_config.connector_list); 846f453ba04SDave Airlie dev->mode_config.num_connector++; 847f453ba04SDave Airlie 848a7331e5cSThomas Hellstrom if (connector_type != DRM_MODE_CONNECTOR_VIRTUAL) 84958495563SRob Clark drm_object_attach_property(&connector->base, 850a7331e5cSThomas Hellstrom dev->mode_config.edid_property, 851a7331e5cSThomas Hellstrom 0); 852f453ba04SDave Airlie 85358495563SRob Clark drm_object_attach_property(&connector->base, 854f453ba04SDave Airlie dev->mode_config.dpms_property, 0); 855f453ba04SDave Airlie 8566bfc56aaSVille Syrjälä out: 85784849903SDaniel Vetter drm_modeset_unlock_all(dev); 8586bfc56aaSVille Syrjälä 8596bfc56aaSVille Syrjälä return ret; 860f453ba04SDave Airlie } 861f453ba04SDave Airlie EXPORT_SYMBOL(drm_connector_init); 862f453ba04SDave Airlie 863f453ba04SDave Airlie /** 864f453ba04SDave Airlie * drm_connector_cleanup - cleans up an initialised connector 865f453ba04SDave Airlie * @connector: connector to cleanup 866f453ba04SDave Airlie * 867f453ba04SDave Airlie * Cleans up the connector but doesn't free the object. 868f453ba04SDave Airlie */ 869f453ba04SDave Airlie void drm_connector_cleanup(struct drm_connector *connector) 870f453ba04SDave Airlie { 871f453ba04SDave Airlie struct drm_device *dev = connector->dev; 872f453ba04SDave Airlie struct drm_display_mode *mode, *t; 873f453ba04SDave Airlie 874f453ba04SDave Airlie list_for_each_entry_safe(mode, t, &connector->probed_modes, head) 875f453ba04SDave Airlie drm_mode_remove(connector, mode); 876f453ba04SDave Airlie 877f453ba04SDave Airlie list_for_each_entry_safe(mode, t, &connector->modes, head) 878f453ba04SDave Airlie drm_mode_remove(connector, mode); 879f453ba04SDave Airlie 880b21e3afeSIlia Mirkin ida_remove(&drm_connector_enum_list[connector->connector_type].ida, 881b21e3afeSIlia Mirkin connector->connector_type_id); 882b21e3afeSIlia Mirkin 883f453ba04SDave Airlie drm_mode_object_put(dev, &connector->base); 884f453ba04SDave Airlie list_del(&connector->head); 8856380c509SJoonyoung Shim dev->mode_config.num_connector--; 886f453ba04SDave Airlie } 887f453ba04SDave Airlie EXPORT_SYMBOL(drm_connector_cleanup); 888f453ba04SDave Airlie 889c8e32cc1SDaniel Vetter /** 890c8e32cc1SDaniel Vetter * drm_connector_unplug_all - unregister connector userspace interfaces 891c8e32cc1SDaniel Vetter * @dev: drm device 892c8e32cc1SDaniel Vetter * 893c8e32cc1SDaniel Vetter * This function unregisters all connector userspace interfaces in sysfs. Should 894c8e32cc1SDaniel Vetter * be call when the device is disconnected, e.g. from an usb driver's 895c8e32cc1SDaniel Vetter * ->disconnect callback. 896c8e32cc1SDaniel Vetter */ 897cbc7e221SDave Airlie void drm_connector_unplug_all(struct drm_device *dev) 898cbc7e221SDave Airlie { 899cbc7e221SDave Airlie struct drm_connector *connector; 900cbc7e221SDave Airlie 901cbc7e221SDave Airlie /* taking the mode config mutex ends up in a clash with sysfs */ 902cbc7e221SDave Airlie list_for_each_entry(connector, &dev->mode_config.connector_list, head) 903cbc7e221SDave Airlie drm_sysfs_connector_remove(connector); 904cbc7e221SDave Airlie 905cbc7e221SDave Airlie } 906cbc7e221SDave Airlie EXPORT_SYMBOL(drm_connector_unplug_all); 907cbc7e221SDave Airlie 908c8e32cc1SDaniel Vetter /** 909c8e32cc1SDaniel Vetter * drm_bridge_init - initialize a drm transcoder/bridge 910c8e32cc1SDaniel Vetter * @dev: drm device 911c8e32cc1SDaniel Vetter * @bridge: transcoder/bridge to set up 912c8e32cc1SDaniel Vetter * @funcs: bridge function table 913c8e32cc1SDaniel Vetter * 914c8e32cc1SDaniel Vetter * Initialises a preallocated bridge. Bridges should be 915c8e32cc1SDaniel Vetter * subclassed as part of driver connector objects. 916c8e32cc1SDaniel Vetter * 917c8e32cc1SDaniel Vetter * Returns: 918c8e32cc1SDaniel Vetter * Zero on success, error code on failure. 919c8e32cc1SDaniel Vetter */ 9203b336ec4SSean Paul int drm_bridge_init(struct drm_device *dev, struct drm_bridge *bridge, 9213b336ec4SSean Paul const struct drm_bridge_funcs *funcs) 9223b336ec4SSean Paul { 9233b336ec4SSean Paul int ret; 9243b336ec4SSean Paul 9253b336ec4SSean Paul drm_modeset_lock_all(dev); 9263b336ec4SSean Paul 9273b336ec4SSean Paul ret = drm_mode_object_get(dev, &bridge->base, DRM_MODE_OBJECT_BRIDGE); 9283b336ec4SSean Paul if (ret) 9293b336ec4SSean Paul goto out; 9303b336ec4SSean Paul 9313b336ec4SSean Paul bridge->dev = dev; 9323b336ec4SSean Paul bridge->funcs = funcs; 9333b336ec4SSean Paul 9343b336ec4SSean Paul list_add_tail(&bridge->head, &dev->mode_config.bridge_list); 9353b336ec4SSean Paul dev->mode_config.num_bridge++; 9363b336ec4SSean Paul 9373b336ec4SSean Paul out: 9383b336ec4SSean Paul drm_modeset_unlock_all(dev); 9393b336ec4SSean Paul return ret; 9403b336ec4SSean Paul } 9413b336ec4SSean Paul EXPORT_SYMBOL(drm_bridge_init); 9423b336ec4SSean Paul 943c8e32cc1SDaniel Vetter /** 944c8e32cc1SDaniel Vetter * drm_bridge_cleanup - cleans up an initialised bridge 945c8e32cc1SDaniel Vetter * @bridge: bridge to cleanup 946c8e32cc1SDaniel Vetter * 947c8e32cc1SDaniel Vetter * Cleans up the bridge but doesn't free the object. 948c8e32cc1SDaniel Vetter */ 9493b336ec4SSean Paul void drm_bridge_cleanup(struct drm_bridge *bridge) 9503b336ec4SSean Paul { 9513b336ec4SSean Paul struct drm_device *dev = bridge->dev; 9523b336ec4SSean Paul 9533b336ec4SSean Paul drm_modeset_lock_all(dev); 9543b336ec4SSean Paul drm_mode_object_put(dev, &bridge->base); 9553b336ec4SSean Paul list_del(&bridge->head); 9563b336ec4SSean Paul dev->mode_config.num_bridge--; 9573b336ec4SSean Paul drm_modeset_unlock_all(dev); 9583b336ec4SSean Paul } 9593b336ec4SSean Paul EXPORT_SYMBOL(drm_bridge_cleanup); 9603b336ec4SSean Paul 961c8e32cc1SDaniel Vetter /** 962c8e32cc1SDaniel Vetter * drm_encoder_init - Init a preallocated encoder 963c8e32cc1SDaniel Vetter * @dev: drm device 964c8e32cc1SDaniel Vetter * @encoder: the encoder to init 965c8e32cc1SDaniel Vetter * @funcs: callbacks for this encoder 966c8e32cc1SDaniel Vetter * @encoder_type: user visible type of the encoder 967c8e32cc1SDaniel Vetter * 968c8e32cc1SDaniel Vetter * Initialises a preallocated encoder. Encoder should be 969c8e32cc1SDaniel Vetter * subclassed as part of driver encoder objects. 970c8e32cc1SDaniel Vetter * 971c8e32cc1SDaniel Vetter * Returns: 972c8e32cc1SDaniel Vetter * Zero on success, error code on failure. 973c8e32cc1SDaniel Vetter */ 9746bfc56aaSVille Syrjälä int drm_encoder_init(struct drm_device *dev, 975f453ba04SDave Airlie struct drm_encoder *encoder, 976f453ba04SDave Airlie const struct drm_encoder_funcs *funcs, 977f453ba04SDave Airlie int encoder_type) 978f453ba04SDave Airlie { 9796bfc56aaSVille Syrjälä int ret; 9806bfc56aaSVille Syrjälä 98184849903SDaniel Vetter drm_modeset_lock_all(dev); 982f453ba04SDave Airlie 9836bfc56aaSVille Syrjälä ret = drm_mode_object_get(dev, &encoder->base, DRM_MODE_OBJECT_ENCODER); 9846bfc56aaSVille Syrjälä if (ret) 9856bfc56aaSVille Syrjälä goto out; 986f453ba04SDave Airlie 9876bfc56aaSVille Syrjälä encoder->dev = dev; 988f453ba04SDave Airlie encoder->encoder_type = encoder_type; 989f453ba04SDave Airlie encoder->funcs = funcs; 990f453ba04SDave Airlie 991f453ba04SDave Airlie list_add_tail(&encoder->head, &dev->mode_config.encoder_list); 992f453ba04SDave Airlie dev->mode_config.num_encoder++; 993f453ba04SDave Airlie 9946bfc56aaSVille Syrjälä out: 99584849903SDaniel Vetter drm_modeset_unlock_all(dev); 9966bfc56aaSVille Syrjälä 9976bfc56aaSVille Syrjälä return ret; 998f453ba04SDave Airlie } 999f453ba04SDave Airlie EXPORT_SYMBOL(drm_encoder_init); 1000f453ba04SDave Airlie 1001c8e32cc1SDaniel Vetter /** 1002c8e32cc1SDaniel Vetter * drm_encoder_cleanup - cleans up an initialised encoder 1003c8e32cc1SDaniel Vetter * @encoder: encoder to cleanup 1004c8e32cc1SDaniel Vetter * 1005c8e32cc1SDaniel Vetter * Cleans up the encoder but doesn't free the object. 1006c8e32cc1SDaniel Vetter */ 1007f453ba04SDave Airlie void drm_encoder_cleanup(struct drm_encoder *encoder) 1008f453ba04SDave Airlie { 1009f453ba04SDave Airlie struct drm_device *dev = encoder->dev; 101084849903SDaniel Vetter drm_modeset_lock_all(dev); 1011f453ba04SDave Airlie drm_mode_object_put(dev, &encoder->base); 1012f453ba04SDave Airlie list_del(&encoder->head); 10136380c509SJoonyoung Shim dev->mode_config.num_encoder--; 101484849903SDaniel Vetter drm_modeset_unlock_all(dev); 1015f453ba04SDave Airlie } 1016f453ba04SDave Airlie EXPORT_SYMBOL(drm_encoder_cleanup); 1017f453ba04SDave Airlie 101835f2c3aeSVille Syrjälä /** 1019dc415ff9SMatt Roper * drm_universal_plane_init - Initialize a new universal plane object 102035f2c3aeSVille Syrjälä * @dev: DRM device 102135f2c3aeSVille Syrjälä * @plane: plane object to init 102235f2c3aeSVille Syrjälä * @possible_crtcs: bitmask of possible CRTCs 102335f2c3aeSVille Syrjälä * @funcs: callbacks for the new plane 102435f2c3aeSVille Syrjälä * @formats: array of supported formats (%DRM_FORMAT_*) 102535f2c3aeSVille Syrjälä * @format_count: number of elements in @formats 1026dc415ff9SMatt Roper * @type: type of plane (overlay, primary, cursor) 102735f2c3aeSVille Syrjälä * 1028dc415ff9SMatt Roper * Initializes a plane object of type @type. 102935f2c3aeSVille Syrjälä * 1030c8e32cc1SDaniel Vetter * Returns: 103135f2c3aeSVille Syrjälä * Zero on success, error code on failure. 103235f2c3aeSVille Syrjälä */ 1033dc415ff9SMatt Roper int drm_universal_plane_init(struct drm_device *dev, struct drm_plane *plane, 10348cf5c917SJesse Barnes unsigned long possible_crtcs, 10358cf5c917SJesse Barnes const struct drm_plane_funcs *funcs, 10360a7eb243SRob Clark const uint32_t *formats, uint32_t format_count, 1037dc415ff9SMatt Roper enum drm_plane_type type) 10388cf5c917SJesse Barnes { 10396bfc56aaSVille Syrjälä int ret; 10406bfc56aaSVille Syrjälä 104184849903SDaniel Vetter drm_modeset_lock_all(dev); 10428cf5c917SJesse Barnes 10436bfc56aaSVille Syrjälä ret = drm_mode_object_get(dev, &plane->base, DRM_MODE_OBJECT_PLANE); 10446bfc56aaSVille Syrjälä if (ret) 10456bfc56aaSVille Syrjälä goto out; 10466bfc56aaSVille Syrjälä 10474d93914aSRob Clark plane->base.properties = &plane->properties; 10488cf5c917SJesse Barnes plane->dev = dev; 10498cf5c917SJesse Barnes plane->funcs = funcs; 10508cf5c917SJesse Barnes plane->format_types = kmalloc(sizeof(uint32_t) * format_count, 10518cf5c917SJesse Barnes GFP_KERNEL); 10528cf5c917SJesse Barnes if (!plane->format_types) { 10538cf5c917SJesse Barnes DRM_DEBUG_KMS("out of memory when allocating plane\n"); 10548cf5c917SJesse Barnes drm_mode_object_put(dev, &plane->base); 10556bfc56aaSVille Syrjälä ret = -ENOMEM; 10566bfc56aaSVille Syrjälä goto out; 10578cf5c917SJesse Barnes } 10588cf5c917SJesse Barnes 1059308e5bcbSJesse Barnes memcpy(plane->format_types, formats, format_count * sizeof(uint32_t)); 10608cf5c917SJesse Barnes plane->format_count = format_count; 10618cf5c917SJesse Barnes plane->possible_crtcs = possible_crtcs; 1062dc415ff9SMatt Roper plane->type = type; 10638cf5c917SJesse Barnes 10648cf5c917SJesse Barnes list_add_tail(&plane->head, &dev->mode_config.plane_list); 1065e27dde3eSMatt Roper dev->mode_config.num_total_plane++; 1066e27dde3eSMatt Roper if (plane->type == DRM_PLANE_TYPE_OVERLAY) 1067e27dde3eSMatt Roper dev->mode_config.num_overlay_plane++; 10688cf5c917SJesse Barnes 10699922ab5aSRob Clark drm_object_attach_property(&plane->base, 10709922ab5aSRob Clark dev->mode_config.plane_type_property, 10719922ab5aSRob Clark plane->type); 10729922ab5aSRob Clark 10736bfc56aaSVille Syrjälä out: 107484849903SDaniel Vetter drm_modeset_unlock_all(dev); 10758cf5c917SJesse Barnes 10766bfc56aaSVille Syrjälä return ret; 10778cf5c917SJesse Barnes } 1078dc415ff9SMatt Roper EXPORT_SYMBOL(drm_universal_plane_init); 1079dc415ff9SMatt Roper 1080dc415ff9SMatt Roper /** 1081dc415ff9SMatt Roper * drm_plane_init - Initialize a legacy plane 1082dc415ff9SMatt Roper * @dev: DRM device 1083dc415ff9SMatt Roper * @plane: plane object to init 1084dc415ff9SMatt Roper * @possible_crtcs: bitmask of possible CRTCs 1085dc415ff9SMatt Roper * @funcs: callbacks for the new plane 1086dc415ff9SMatt Roper * @formats: array of supported formats (%DRM_FORMAT_*) 1087dc415ff9SMatt Roper * @format_count: number of elements in @formats 1088dc415ff9SMatt Roper * @is_primary: plane type (primary vs overlay) 1089dc415ff9SMatt Roper * 1090dc415ff9SMatt Roper * Legacy API to initialize a DRM plane. 1091dc415ff9SMatt Roper * 1092dc415ff9SMatt Roper * New drivers should call drm_universal_plane_init() instead. 1093dc415ff9SMatt Roper * 1094dc415ff9SMatt Roper * Returns: 1095dc415ff9SMatt Roper * Zero on success, error code on failure. 1096dc415ff9SMatt Roper */ 1097dc415ff9SMatt Roper int drm_plane_init(struct drm_device *dev, struct drm_plane *plane, 1098dc415ff9SMatt Roper unsigned long possible_crtcs, 1099dc415ff9SMatt Roper const struct drm_plane_funcs *funcs, 1100dc415ff9SMatt Roper const uint32_t *formats, uint32_t format_count, 1101dc415ff9SMatt Roper bool is_primary) 1102dc415ff9SMatt Roper { 1103dc415ff9SMatt Roper enum drm_plane_type type; 1104dc415ff9SMatt Roper 1105dc415ff9SMatt Roper type = is_primary ? DRM_PLANE_TYPE_PRIMARY : DRM_PLANE_TYPE_OVERLAY; 1106dc415ff9SMatt Roper return drm_universal_plane_init(dev, plane, possible_crtcs, funcs, 1107dc415ff9SMatt Roper formats, format_count, type); 1108dc415ff9SMatt Roper } 11098cf5c917SJesse Barnes EXPORT_SYMBOL(drm_plane_init); 11108cf5c917SJesse Barnes 111135f2c3aeSVille Syrjälä /** 111235f2c3aeSVille Syrjälä * drm_plane_cleanup - Clean up the core plane usage 111335f2c3aeSVille Syrjälä * @plane: plane to cleanup 111435f2c3aeSVille Syrjälä * 111535f2c3aeSVille Syrjälä * This function cleans up @plane and removes it from the DRM mode setting 111635f2c3aeSVille Syrjälä * core. Note that the function does *not* free the plane structure itself, 111735f2c3aeSVille Syrjälä * this is the responsibility of the caller. 111835f2c3aeSVille Syrjälä */ 11198cf5c917SJesse Barnes void drm_plane_cleanup(struct drm_plane *plane) 11208cf5c917SJesse Barnes { 11218cf5c917SJesse Barnes struct drm_device *dev = plane->dev; 11228cf5c917SJesse Barnes 112384849903SDaniel Vetter drm_modeset_lock_all(dev); 11248cf5c917SJesse Barnes kfree(plane->format_types); 11258cf5c917SJesse Barnes drm_mode_object_put(dev, &plane->base); 1126dc415ff9SMatt Roper 1127dc415ff9SMatt Roper BUG_ON(list_empty(&plane->head)); 1128dc415ff9SMatt Roper 11298cf5c917SJesse Barnes list_del(&plane->head); 1130e27dde3eSMatt Roper dev->mode_config.num_total_plane--; 1131e27dde3eSMatt Roper if (plane->type == DRM_PLANE_TYPE_OVERLAY) 1132e27dde3eSMatt Roper dev->mode_config.num_overlay_plane--; 113384849903SDaniel Vetter drm_modeset_unlock_all(dev); 11348cf5c917SJesse Barnes } 11358cf5c917SJesse Barnes EXPORT_SYMBOL(drm_plane_cleanup); 11368cf5c917SJesse Barnes 113735f2c3aeSVille Syrjälä /** 113835f2c3aeSVille Syrjälä * drm_plane_force_disable - Forcibly disable a plane 113935f2c3aeSVille Syrjälä * @plane: plane to disable 114035f2c3aeSVille Syrjälä * 114135f2c3aeSVille Syrjälä * Forces the plane to be disabled. 114235f2c3aeSVille Syrjälä * 114335f2c3aeSVille Syrjälä * Used when the plane's current framebuffer is destroyed, 114435f2c3aeSVille Syrjälä * and when restoring fbdev mode. 114535f2c3aeSVille Syrjälä */ 11469125e618SVille Syrjälä void drm_plane_force_disable(struct drm_plane *plane) 11479125e618SVille Syrjälä { 11489125e618SVille Syrjälä int ret; 11499125e618SVille Syrjälä 11509125e618SVille Syrjälä if (!plane->fb) 11519125e618SVille Syrjälä return; 11529125e618SVille Syrjälä 11539125e618SVille Syrjälä ret = plane->funcs->disable_plane(plane); 11549125e618SVille Syrjälä if (ret) 11559125e618SVille Syrjälä DRM_ERROR("failed to disable plane with busy fb\n"); 11569125e618SVille Syrjälä /* disconnect the plane from the fb and crtc: */ 11579125e618SVille Syrjälä __drm_framebuffer_unreference(plane->fb); 11589125e618SVille Syrjälä plane->fb = NULL; 11599125e618SVille Syrjälä plane->crtc = NULL; 11609125e618SVille Syrjälä } 11619125e618SVille Syrjälä EXPORT_SYMBOL(drm_plane_force_disable); 11629125e618SVille Syrjälä 1163f453ba04SDave Airlie static int drm_mode_create_standard_connector_properties(struct drm_device *dev) 1164f453ba04SDave Airlie { 1165f453ba04SDave Airlie struct drm_property *edid; 1166f453ba04SDave Airlie struct drm_property *dpms; 1167f453ba04SDave Airlie 1168f453ba04SDave Airlie /* 1169f453ba04SDave Airlie * Standard properties (apply to all connectors) 1170f453ba04SDave Airlie */ 1171f453ba04SDave Airlie edid = drm_property_create(dev, DRM_MODE_PROP_BLOB | 1172f453ba04SDave Airlie DRM_MODE_PROP_IMMUTABLE, 1173f453ba04SDave Airlie "EDID", 0); 1174f453ba04SDave Airlie dev->mode_config.edid_property = edid; 1175f453ba04SDave Airlie 11764a67d391SSascha Hauer dpms = drm_property_create_enum(dev, 0, 11774a67d391SSascha Hauer "DPMS", drm_dpms_enum_list, 11784a67d391SSascha Hauer ARRAY_SIZE(drm_dpms_enum_list)); 1179f453ba04SDave Airlie dev->mode_config.dpms_property = dpms; 1180f453ba04SDave Airlie 1181f453ba04SDave Airlie return 0; 1182f453ba04SDave Airlie } 1183f453ba04SDave Airlie 11849922ab5aSRob Clark static int drm_mode_create_standard_plane_properties(struct drm_device *dev) 11859922ab5aSRob Clark { 11869922ab5aSRob Clark struct drm_property *type; 11879922ab5aSRob Clark 11889922ab5aSRob Clark /* 11899922ab5aSRob Clark * Standard properties (apply to all planes) 11909922ab5aSRob Clark */ 11919922ab5aSRob Clark type = drm_property_create_enum(dev, DRM_MODE_PROP_IMMUTABLE, 11929922ab5aSRob Clark "type", drm_plane_type_enum_list, 11939922ab5aSRob Clark ARRAY_SIZE(drm_plane_type_enum_list)); 11949922ab5aSRob Clark dev->mode_config.plane_type_property = type; 11959922ab5aSRob Clark 11969922ab5aSRob Clark return 0; 11979922ab5aSRob Clark } 11989922ab5aSRob Clark 1199f453ba04SDave Airlie /** 1200f453ba04SDave Airlie * drm_mode_create_dvi_i_properties - create DVI-I specific connector properties 1201f453ba04SDave Airlie * @dev: DRM device 1202f453ba04SDave Airlie * 1203f453ba04SDave Airlie * Called by a driver the first time a DVI-I connector is made. 1204f453ba04SDave Airlie */ 1205f453ba04SDave Airlie int drm_mode_create_dvi_i_properties(struct drm_device *dev) 1206f453ba04SDave Airlie { 1207f453ba04SDave Airlie struct drm_property *dvi_i_selector; 1208f453ba04SDave Airlie struct drm_property *dvi_i_subconnector; 1209f453ba04SDave Airlie 1210f453ba04SDave Airlie if (dev->mode_config.dvi_i_select_subconnector_property) 1211f453ba04SDave Airlie return 0; 1212f453ba04SDave Airlie 1213f453ba04SDave Airlie dvi_i_selector = 12144a67d391SSascha Hauer drm_property_create_enum(dev, 0, 1215f453ba04SDave Airlie "select subconnector", 12164a67d391SSascha Hauer drm_dvi_i_select_enum_list, 1217f453ba04SDave Airlie ARRAY_SIZE(drm_dvi_i_select_enum_list)); 1218f453ba04SDave Airlie dev->mode_config.dvi_i_select_subconnector_property = dvi_i_selector; 1219f453ba04SDave Airlie 12204a67d391SSascha Hauer dvi_i_subconnector = drm_property_create_enum(dev, DRM_MODE_PROP_IMMUTABLE, 1221f453ba04SDave Airlie "subconnector", 12224a67d391SSascha Hauer drm_dvi_i_subconnector_enum_list, 1223f453ba04SDave Airlie ARRAY_SIZE(drm_dvi_i_subconnector_enum_list)); 1224f453ba04SDave Airlie dev->mode_config.dvi_i_subconnector_property = dvi_i_subconnector; 1225f453ba04SDave Airlie 1226f453ba04SDave Airlie return 0; 1227f453ba04SDave Airlie } 1228f453ba04SDave Airlie EXPORT_SYMBOL(drm_mode_create_dvi_i_properties); 1229f453ba04SDave Airlie 1230f453ba04SDave Airlie /** 1231f453ba04SDave Airlie * drm_create_tv_properties - create TV specific connector properties 1232f453ba04SDave Airlie * @dev: DRM device 1233f453ba04SDave Airlie * @num_modes: number of different TV formats (modes) supported 1234f453ba04SDave Airlie * @modes: array of pointers to strings containing name of each format 1235f453ba04SDave Airlie * 1236f453ba04SDave Airlie * Called by a driver's TV initialization routine, this function creates 1237f453ba04SDave Airlie * the TV specific connector properties for a given device. Caller is 1238f453ba04SDave Airlie * responsible for allocating a list of format names and passing them to 1239f453ba04SDave Airlie * this routine. 1240f453ba04SDave Airlie */ 1241f453ba04SDave Airlie int drm_mode_create_tv_properties(struct drm_device *dev, int num_modes, 1242f453ba04SDave Airlie char *modes[]) 1243f453ba04SDave Airlie { 1244f453ba04SDave Airlie struct drm_property *tv_selector; 1245f453ba04SDave Airlie struct drm_property *tv_subconnector; 1246f453ba04SDave Airlie int i; 1247f453ba04SDave Airlie 1248f453ba04SDave Airlie if (dev->mode_config.tv_select_subconnector_property) 1249f453ba04SDave Airlie return 0; 1250f453ba04SDave Airlie 1251f453ba04SDave Airlie /* 1252f453ba04SDave Airlie * Basic connector properties 1253f453ba04SDave Airlie */ 12544a67d391SSascha Hauer tv_selector = drm_property_create_enum(dev, 0, 1255f453ba04SDave Airlie "select subconnector", 12564a67d391SSascha Hauer drm_tv_select_enum_list, 1257f453ba04SDave Airlie ARRAY_SIZE(drm_tv_select_enum_list)); 1258f453ba04SDave Airlie dev->mode_config.tv_select_subconnector_property = tv_selector; 1259f453ba04SDave Airlie 1260f453ba04SDave Airlie tv_subconnector = 12614a67d391SSascha Hauer drm_property_create_enum(dev, DRM_MODE_PROP_IMMUTABLE, 12624a67d391SSascha Hauer "subconnector", 12634a67d391SSascha Hauer drm_tv_subconnector_enum_list, 1264f453ba04SDave Airlie ARRAY_SIZE(drm_tv_subconnector_enum_list)); 1265f453ba04SDave Airlie dev->mode_config.tv_subconnector_property = tv_subconnector; 1266f453ba04SDave Airlie 1267f453ba04SDave Airlie /* 1268f453ba04SDave Airlie * Other, TV specific properties: margins & TV modes. 1269f453ba04SDave Airlie */ 1270f453ba04SDave Airlie dev->mode_config.tv_left_margin_property = 1271d9bc3c02SSascha Hauer drm_property_create_range(dev, 0, "left margin", 0, 100); 1272f453ba04SDave Airlie 1273f453ba04SDave Airlie dev->mode_config.tv_right_margin_property = 1274d9bc3c02SSascha Hauer drm_property_create_range(dev, 0, "right margin", 0, 100); 1275f453ba04SDave Airlie 1276f453ba04SDave Airlie dev->mode_config.tv_top_margin_property = 1277d9bc3c02SSascha Hauer drm_property_create_range(dev, 0, "top margin", 0, 100); 1278f453ba04SDave Airlie 1279f453ba04SDave Airlie dev->mode_config.tv_bottom_margin_property = 1280d9bc3c02SSascha Hauer drm_property_create_range(dev, 0, "bottom margin", 0, 100); 1281f453ba04SDave Airlie 1282f453ba04SDave Airlie dev->mode_config.tv_mode_property = 1283f453ba04SDave Airlie drm_property_create(dev, DRM_MODE_PROP_ENUM, 1284f453ba04SDave Airlie "mode", num_modes); 1285f453ba04SDave Airlie for (i = 0; i < num_modes; i++) 1286f453ba04SDave Airlie drm_property_add_enum(dev->mode_config.tv_mode_property, i, 1287f453ba04SDave Airlie i, modes[i]); 1288f453ba04SDave Airlie 1289b6b7902eSFrancisco Jerez dev->mode_config.tv_brightness_property = 1290d9bc3c02SSascha Hauer drm_property_create_range(dev, 0, "brightness", 0, 100); 1291b6b7902eSFrancisco Jerez 1292b6b7902eSFrancisco Jerez dev->mode_config.tv_contrast_property = 1293d9bc3c02SSascha Hauer drm_property_create_range(dev, 0, "contrast", 0, 100); 1294b6b7902eSFrancisco Jerez 1295b6b7902eSFrancisco Jerez dev->mode_config.tv_flicker_reduction_property = 1296d9bc3c02SSascha Hauer drm_property_create_range(dev, 0, "flicker reduction", 0, 100); 1297b6b7902eSFrancisco Jerez 1298a75f0236SFrancisco Jerez dev->mode_config.tv_overscan_property = 1299d9bc3c02SSascha Hauer drm_property_create_range(dev, 0, "overscan", 0, 100); 1300a75f0236SFrancisco Jerez 1301a75f0236SFrancisco Jerez dev->mode_config.tv_saturation_property = 1302d9bc3c02SSascha Hauer drm_property_create_range(dev, 0, "saturation", 0, 100); 1303a75f0236SFrancisco Jerez 1304a75f0236SFrancisco Jerez dev->mode_config.tv_hue_property = 1305d9bc3c02SSascha Hauer drm_property_create_range(dev, 0, "hue", 0, 100); 1306a75f0236SFrancisco Jerez 1307f453ba04SDave Airlie return 0; 1308f453ba04SDave Airlie } 1309f453ba04SDave Airlie EXPORT_SYMBOL(drm_mode_create_tv_properties); 1310f453ba04SDave Airlie 1311f453ba04SDave Airlie /** 1312f453ba04SDave Airlie * drm_mode_create_scaling_mode_property - create scaling mode property 1313f453ba04SDave Airlie * @dev: DRM device 1314f453ba04SDave Airlie * 1315f453ba04SDave Airlie * Called by a driver the first time it's needed, must be attached to desired 1316f453ba04SDave Airlie * connectors. 1317f453ba04SDave Airlie */ 1318f453ba04SDave Airlie int drm_mode_create_scaling_mode_property(struct drm_device *dev) 1319f453ba04SDave Airlie { 1320f453ba04SDave Airlie struct drm_property *scaling_mode; 1321f453ba04SDave Airlie 1322f453ba04SDave Airlie if (dev->mode_config.scaling_mode_property) 1323f453ba04SDave Airlie return 0; 1324f453ba04SDave Airlie 1325f453ba04SDave Airlie scaling_mode = 13264a67d391SSascha Hauer drm_property_create_enum(dev, 0, "scaling mode", 13274a67d391SSascha Hauer drm_scaling_mode_enum_list, 1328f453ba04SDave Airlie ARRAY_SIZE(drm_scaling_mode_enum_list)); 1329f453ba04SDave Airlie 1330f453ba04SDave Airlie dev->mode_config.scaling_mode_property = scaling_mode; 1331f453ba04SDave Airlie 1332f453ba04SDave Airlie return 0; 1333f453ba04SDave Airlie } 1334f453ba04SDave Airlie EXPORT_SYMBOL(drm_mode_create_scaling_mode_property); 1335f453ba04SDave Airlie 1336f453ba04SDave Airlie /** 1337884840aaSJakob Bornecrantz * drm_mode_create_dirty_property - create dirty property 1338884840aaSJakob Bornecrantz * @dev: DRM device 1339884840aaSJakob Bornecrantz * 1340884840aaSJakob Bornecrantz * Called by a driver the first time it's needed, must be attached to desired 1341884840aaSJakob Bornecrantz * connectors. 1342884840aaSJakob Bornecrantz */ 1343884840aaSJakob Bornecrantz int drm_mode_create_dirty_info_property(struct drm_device *dev) 1344884840aaSJakob Bornecrantz { 1345884840aaSJakob Bornecrantz struct drm_property *dirty_info; 1346884840aaSJakob Bornecrantz 1347884840aaSJakob Bornecrantz if (dev->mode_config.dirty_info_property) 1348884840aaSJakob Bornecrantz return 0; 1349884840aaSJakob Bornecrantz 1350884840aaSJakob Bornecrantz dirty_info = 13514a67d391SSascha Hauer drm_property_create_enum(dev, DRM_MODE_PROP_IMMUTABLE, 1352884840aaSJakob Bornecrantz "dirty", 13534a67d391SSascha Hauer drm_dirty_info_enum_list, 1354884840aaSJakob Bornecrantz ARRAY_SIZE(drm_dirty_info_enum_list)); 1355884840aaSJakob Bornecrantz dev->mode_config.dirty_info_property = dirty_info; 1356884840aaSJakob Bornecrantz 1357884840aaSJakob Bornecrantz return 0; 1358884840aaSJakob Bornecrantz } 1359884840aaSJakob Bornecrantz EXPORT_SYMBOL(drm_mode_create_dirty_info_property); 1360884840aaSJakob Bornecrantz 1361ea9cbb06SVille Syrjälä static int drm_mode_group_init(struct drm_device *dev, struct drm_mode_group *group) 1362f453ba04SDave Airlie { 1363f453ba04SDave Airlie uint32_t total_objects = 0; 1364f453ba04SDave Airlie 1365f453ba04SDave Airlie total_objects += dev->mode_config.num_crtc; 1366f453ba04SDave Airlie total_objects += dev->mode_config.num_connector; 1367f453ba04SDave Airlie total_objects += dev->mode_config.num_encoder; 13683b336ec4SSean Paul total_objects += dev->mode_config.num_bridge; 1369f453ba04SDave Airlie 1370f453ba04SDave Airlie group->id_list = kzalloc(total_objects * sizeof(uint32_t), GFP_KERNEL); 1371f453ba04SDave Airlie if (!group->id_list) 1372f453ba04SDave Airlie return -ENOMEM; 1373f453ba04SDave Airlie 1374f453ba04SDave Airlie group->num_crtcs = 0; 1375f453ba04SDave Airlie group->num_connectors = 0; 1376f453ba04SDave Airlie group->num_encoders = 0; 13773b336ec4SSean Paul group->num_bridges = 0; 1378f453ba04SDave Airlie return 0; 1379f453ba04SDave Airlie } 1380f453ba04SDave Airlie 1381ad222799SDave Airlie void drm_mode_group_destroy(struct drm_mode_group *group) 1382ad222799SDave Airlie { 1383ad222799SDave Airlie kfree(group->id_list); 1384ad222799SDave Airlie group->id_list = NULL; 1385ad222799SDave Airlie } 1386ad222799SDave Airlie 1387c8e32cc1SDaniel Vetter /* 1388c8e32cc1SDaniel Vetter * NOTE: Driver's shouldn't ever call drm_mode_group_init_legacy_group - it is 1389c8e32cc1SDaniel Vetter * the drm core's responsibility to set up mode control groups. 1390c8e32cc1SDaniel Vetter */ 1391f453ba04SDave Airlie int drm_mode_group_init_legacy_group(struct drm_device *dev, 1392f453ba04SDave Airlie struct drm_mode_group *group) 1393f453ba04SDave Airlie { 1394f453ba04SDave Airlie struct drm_crtc *crtc; 1395f453ba04SDave Airlie struct drm_encoder *encoder; 1396f453ba04SDave Airlie struct drm_connector *connector; 13973b336ec4SSean Paul struct drm_bridge *bridge; 1398f453ba04SDave Airlie int ret; 1399f453ba04SDave Airlie 1400f453ba04SDave Airlie if ((ret = drm_mode_group_init(dev, group))) 1401f453ba04SDave Airlie return ret; 1402f453ba04SDave Airlie 1403f453ba04SDave Airlie list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) 1404f453ba04SDave Airlie group->id_list[group->num_crtcs++] = crtc->base.id; 1405f453ba04SDave Airlie 1406f453ba04SDave Airlie list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) 1407f453ba04SDave Airlie group->id_list[group->num_crtcs + group->num_encoders++] = 1408f453ba04SDave Airlie encoder->base.id; 1409f453ba04SDave Airlie 1410f453ba04SDave Airlie list_for_each_entry(connector, &dev->mode_config.connector_list, head) 1411f453ba04SDave Airlie group->id_list[group->num_crtcs + group->num_encoders + 1412f453ba04SDave Airlie group->num_connectors++] = connector->base.id; 1413f453ba04SDave Airlie 14143b336ec4SSean Paul list_for_each_entry(bridge, &dev->mode_config.bridge_list, head) 14153b336ec4SSean Paul group->id_list[group->num_crtcs + group->num_encoders + 14163b336ec4SSean Paul group->num_connectors + group->num_bridges++] = 14173b336ec4SSean Paul bridge->base.id; 14183b336ec4SSean Paul 1419f453ba04SDave Airlie return 0; 1420f453ba04SDave Airlie } 14219c1dfc55SDave Airlie EXPORT_SYMBOL(drm_mode_group_init_legacy_group); 1422f453ba04SDave Airlie 1423f453ba04SDave Airlie /** 1424f453ba04SDave Airlie * drm_crtc_convert_to_umode - convert a drm_display_mode into a modeinfo 1425f453ba04SDave Airlie * @out: drm_mode_modeinfo struct to return to the user 1426f453ba04SDave Airlie * @in: drm_display_mode to use 1427f453ba04SDave Airlie * 1428f453ba04SDave Airlie * Convert a drm_display_mode into a drm_mode_modeinfo structure to return to 1429f453ba04SDave Airlie * the user. 1430f453ba04SDave Airlie */ 143193bbf6dbSVille Syrjälä static void drm_crtc_convert_to_umode(struct drm_mode_modeinfo *out, 143293bbf6dbSVille Syrjälä const struct drm_display_mode *in) 1433f453ba04SDave Airlie { 1434e36fae38SVille Syrjälä WARN(in->hdisplay > USHRT_MAX || in->hsync_start > USHRT_MAX || 1435e36fae38SVille Syrjälä in->hsync_end > USHRT_MAX || in->htotal > USHRT_MAX || 1436e36fae38SVille Syrjälä in->hskew > USHRT_MAX || in->vdisplay > USHRT_MAX || 1437e36fae38SVille Syrjälä in->vsync_start > USHRT_MAX || in->vsync_end > USHRT_MAX || 1438e36fae38SVille Syrjälä in->vtotal > USHRT_MAX || in->vscan > USHRT_MAX, 1439e36fae38SVille Syrjälä "timing values too large for mode info\n"); 1440e36fae38SVille Syrjälä 1441f453ba04SDave Airlie out->clock = in->clock; 1442f453ba04SDave Airlie out->hdisplay = in->hdisplay; 1443f453ba04SDave Airlie out->hsync_start = in->hsync_start; 1444f453ba04SDave Airlie out->hsync_end = in->hsync_end; 1445f453ba04SDave Airlie out->htotal = in->htotal; 1446f453ba04SDave Airlie out->hskew = in->hskew; 1447f453ba04SDave Airlie out->vdisplay = in->vdisplay; 1448f453ba04SDave Airlie out->vsync_start = in->vsync_start; 1449f453ba04SDave Airlie out->vsync_end = in->vsync_end; 1450f453ba04SDave Airlie out->vtotal = in->vtotal; 1451f453ba04SDave Airlie out->vscan = in->vscan; 1452f453ba04SDave Airlie out->vrefresh = in->vrefresh; 1453f453ba04SDave Airlie out->flags = in->flags; 1454f453ba04SDave Airlie out->type = in->type; 1455f453ba04SDave Airlie strncpy(out->name, in->name, DRM_DISPLAY_MODE_LEN); 1456f453ba04SDave Airlie out->name[DRM_DISPLAY_MODE_LEN-1] = 0; 1457f453ba04SDave Airlie } 1458f453ba04SDave Airlie 1459f453ba04SDave Airlie /** 146074afee7dSMarc-André Lureau * drm_crtc_convert_umode - convert a modeinfo into a drm_display_mode 1461f453ba04SDave Airlie * @out: drm_display_mode to return to the user 1462f453ba04SDave Airlie * @in: drm_mode_modeinfo to use 1463f453ba04SDave Airlie * 1464f453ba04SDave Airlie * Convert a drm_mode_modeinfo into a drm_display_mode structure to return to 1465f453ba04SDave Airlie * the caller. 146690367bf6SVille Syrjälä * 1467c8e32cc1SDaniel Vetter * Returns: 146890367bf6SVille Syrjälä * Zero on success, errno on failure. 1469f453ba04SDave Airlie */ 147093bbf6dbSVille Syrjälä static int drm_crtc_convert_umode(struct drm_display_mode *out, 147193bbf6dbSVille Syrjälä const struct drm_mode_modeinfo *in) 1472f453ba04SDave Airlie { 147390367bf6SVille Syrjälä if (in->clock > INT_MAX || in->vrefresh > INT_MAX) 147490367bf6SVille Syrjälä return -ERANGE; 147590367bf6SVille Syrjälä 14765848ad40SDamien Lespiau if ((in->flags & DRM_MODE_FLAG_3D_MASK) > DRM_MODE_FLAG_3D_MAX) 14775848ad40SDamien Lespiau return -EINVAL; 14785848ad40SDamien Lespiau 1479f453ba04SDave Airlie out->clock = in->clock; 1480f453ba04SDave Airlie out->hdisplay = in->hdisplay; 1481f453ba04SDave Airlie out->hsync_start = in->hsync_start; 1482f453ba04SDave Airlie out->hsync_end = in->hsync_end; 1483f453ba04SDave Airlie out->htotal = in->htotal; 1484f453ba04SDave Airlie out->hskew = in->hskew; 1485f453ba04SDave Airlie out->vdisplay = in->vdisplay; 1486f453ba04SDave Airlie out->vsync_start = in->vsync_start; 1487f453ba04SDave Airlie out->vsync_end = in->vsync_end; 1488f453ba04SDave Airlie out->vtotal = in->vtotal; 1489f453ba04SDave Airlie out->vscan = in->vscan; 1490f453ba04SDave Airlie out->vrefresh = in->vrefresh; 1491f453ba04SDave Airlie out->flags = in->flags; 1492f453ba04SDave Airlie out->type = in->type; 1493f453ba04SDave Airlie strncpy(out->name, in->name, DRM_DISPLAY_MODE_LEN); 1494f453ba04SDave Airlie out->name[DRM_DISPLAY_MODE_LEN-1] = 0; 149590367bf6SVille Syrjälä 149690367bf6SVille Syrjälä return 0; 1497f453ba04SDave Airlie } 1498f453ba04SDave Airlie 1499f453ba04SDave Airlie /** 1500f453ba04SDave Airlie * drm_mode_getresources - get graphics configuration 1501065a50edSDaniel Vetter * @dev: drm device for the ioctl 1502065a50edSDaniel Vetter * @data: data pointer for the ioctl 1503065a50edSDaniel Vetter * @file_priv: drm file for the ioctl call 1504f453ba04SDave Airlie * 1505f453ba04SDave Airlie * Construct a set of configuration description structures and return 1506f453ba04SDave Airlie * them to the user, including CRTC, connector and framebuffer configuration. 1507f453ba04SDave Airlie * 1508f453ba04SDave Airlie * Called by the user via ioctl. 1509f453ba04SDave Airlie * 1510c8e32cc1SDaniel Vetter * Returns: 1511f453ba04SDave Airlie * Zero on success, errno on failure. 1512f453ba04SDave Airlie */ 1513f453ba04SDave Airlie int drm_mode_getresources(struct drm_device *dev, void *data, 1514f453ba04SDave Airlie struct drm_file *file_priv) 1515f453ba04SDave Airlie { 1516f453ba04SDave Airlie struct drm_mode_card_res *card_res = data; 1517f453ba04SDave Airlie struct list_head *lh; 1518f453ba04SDave Airlie struct drm_framebuffer *fb; 1519f453ba04SDave Airlie struct drm_connector *connector; 1520f453ba04SDave Airlie struct drm_crtc *crtc; 1521f453ba04SDave Airlie struct drm_encoder *encoder; 1522f453ba04SDave Airlie int ret = 0; 1523f453ba04SDave Airlie int connector_count = 0; 1524f453ba04SDave Airlie int crtc_count = 0; 1525f453ba04SDave Airlie int fb_count = 0; 1526f453ba04SDave Airlie int encoder_count = 0; 1527f453ba04SDave Airlie int copied = 0, i; 1528f453ba04SDave Airlie uint32_t __user *fb_id; 1529f453ba04SDave Airlie uint32_t __user *crtc_id; 1530f453ba04SDave Airlie uint32_t __user *connector_id; 1531f453ba04SDave Airlie uint32_t __user *encoder_id; 1532f453ba04SDave Airlie struct drm_mode_group *mode_group; 1533f453ba04SDave Airlie 1534fb3b06c8SDave Airlie if (!drm_core_check_feature(dev, DRIVER_MODESET)) 1535fb3b06c8SDave Airlie return -EINVAL; 1536fb3b06c8SDave Airlie 1537f453ba04SDave Airlie 15384b096ac1SDaniel Vetter mutex_lock(&file_priv->fbs_lock); 1539f453ba04SDave Airlie /* 1540f453ba04SDave Airlie * For the non-control nodes we need to limit the list of resources 1541f453ba04SDave Airlie * by IDs in the group list for this node 1542f453ba04SDave Airlie */ 1543f453ba04SDave Airlie list_for_each(lh, &file_priv->fbs) 1544f453ba04SDave Airlie fb_count++; 1545f453ba04SDave Airlie 15464b096ac1SDaniel Vetter /* handle this in 4 parts */ 15474b096ac1SDaniel Vetter /* FBs */ 15484b096ac1SDaniel Vetter if (card_res->count_fbs >= fb_count) { 15494b096ac1SDaniel Vetter copied = 0; 15504b096ac1SDaniel Vetter fb_id = (uint32_t __user *)(unsigned long)card_res->fb_id_ptr; 15514b096ac1SDaniel Vetter list_for_each_entry(fb, &file_priv->fbs, filp_head) { 15524b096ac1SDaniel Vetter if (put_user(fb->base.id, fb_id + copied)) { 15534b096ac1SDaniel Vetter mutex_unlock(&file_priv->fbs_lock); 15544b096ac1SDaniel Vetter return -EFAULT; 15554b096ac1SDaniel Vetter } 15564b096ac1SDaniel Vetter copied++; 15574b096ac1SDaniel Vetter } 15584b096ac1SDaniel Vetter } 15594b096ac1SDaniel Vetter card_res->count_fbs = fb_count; 15604b096ac1SDaniel Vetter mutex_unlock(&file_priv->fbs_lock); 15614b096ac1SDaniel Vetter 15624b096ac1SDaniel Vetter drm_modeset_lock_all(dev); 156343683057SThomas Hellstrom if (!drm_is_primary_client(file_priv)) { 1564f453ba04SDave Airlie 156509f308f7SThomas Hellstrom mode_group = NULL; 1566f453ba04SDave Airlie list_for_each(lh, &dev->mode_config.crtc_list) 1567f453ba04SDave Airlie crtc_count++; 1568f453ba04SDave Airlie 1569f453ba04SDave Airlie list_for_each(lh, &dev->mode_config.connector_list) 1570f453ba04SDave Airlie connector_count++; 1571f453ba04SDave Airlie 1572f453ba04SDave Airlie list_for_each(lh, &dev->mode_config.encoder_list) 1573f453ba04SDave Airlie encoder_count++; 1574f453ba04SDave Airlie } else { 1575f453ba04SDave Airlie 157609f308f7SThomas Hellstrom mode_group = &file_priv->master->minor->mode_group; 1577f453ba04SDave Airlie crtc_count = mode_group->num_crtcs; 1578f453ba04SDave Airlie connector_count = mode_group->num_connectors; 1579f453ba04SDave Airlie encoder_count = mode_group->num_encoders; 1580f453ba04SDave Airlie } 1581f453ba04SDave Airlie 1582f453ba04SDave Airlie card_res->max_height = dev->mode_config.max_height; 1583f453ba04SDave Airlie card_res->min_height = dev->mode_config.min_height; 1584f453ba04SDave Airlie card_res->max_width = dev->mode_config.max_width; 1585f453ba04SDave Airlie card_res->min_width = dev->mode_config.min_width; 1586f453ba04SDave Airlie 1587f453ba04SDave Airlie /* CRTCs */ 1588f453ba04SDave Airlie if (card_res->count_crtcs >= crtc_count) { 1589f453ba04SDave Airlie copied = 0; 1590f453ba04SDave Airlie crtc_id = (uint32_t __user *)(unsigned long)card_res->crtc_id_ptr; 159109f308f7SThomas Hellstrom if (!mode_group) { 1592f453ba04SDave Airlie list_for_each_entry(crtc, &dev->mode_config.crtc_list, 1593f453ba04SDave Airlie head) { 15949440106bSJerome Glisse DRM_DEBUG_KMS("[CRTC:%d]\n", crtc->base.id); 1595f453ba04SDave Airlie if (put_user(crtc->base.id, crtc_id + copied)) { 1596f453ba04SDave Airlie ret = -EFAULT; 1597f453ba04SDave Airlie goto out; 1598f453ba04SDave Airlie } 1599f453ba04SDave Airlie copied++; 1600f453ba04SDave Airlie } 1601f453ba04SDave Airlie } else { 1602f453ba04SDave Airlie for (i = 0; i < mode_group->num_crtcs; i++) { 1603f453ba04SDave Airlie if (put_user(mode_group->id_list[i], 1604f453ba04SDave Airlie crtc_id + copied)) { 1605f453ba04SDave Airlie ret = -EFAULT; 1606f453ba04SDave Airlie goto out; 1607f453ba04SDave Airlie } 1608f453ba04SDave Airlie copied++; 1609f453ba04SDave Airlie } 1610f453ba04SDave Airlie } 1611f453ba04SDave Airlie } 1612f453ba04SDave Airlie card_res->count_crtcs = crtc_count; 1613f453ba04SDave Airlie 1614f453ba04SDave Airlie /* Encoders */ 1615f453ba04SDave Airlie if (card_res->count_encoders >= encoder_count) { 1616f453ba04SDave Airlie copied = 0; 1617f453ba04SDave Airlie encoder_id = (uint32_t __user *)(unsigned long)card_res->encoder_id_ptr; 161809f308f7SThomas Hellstrom if (!mode_group) { 1619f453ba04SDave Airlie list_for_each_entry(encoder, 1620f453ba04SDave Airlie &dev->mode_config.encoder_list, 1621f453ba04SDave Airlie head) { 16229440106bSJerome Glisse DRM_DEBUG_KMS("[ENCODER:%d:%s]\n", encoder->base.id, 16239440106bSJerome Glisse drm_get_encoder_name(encoder)); 1624f453ba04SDave Airlie if (put_user(encoder->base.id, encoder_id + 1625f453ba04SDave Airlie copied)) { 1626f453ba04SDave Airlie ret = -EFAULT; 1627f453ba04SDave Airlie goto out; 1628f453ba04SDave Airlie } 1629f453ba04SDave Airlie copied++; 1630f453ba04SDave Airlie } 1631f453ba04SDave Airlie } else { 1632f453ba04SDave Airlie for (i = mode_group->num_crtcs; i < mode_group->num_crtcs + mode_group->num_encoders; i++) { 1633f453ba04SDave Airlie if (put_user(mode_group->id_list[i], 1634f453ba04SDave Airlie encoder_id + copied)) { 1635f453ba04SDave Airlie ret = -EFAULT; 1636f453ba04SDave Airlie goto out; 1637f453ba04SDave Airlie } 1638f453ba04SDave Airlie copied++; 1639f453ba04SDave Airlie } 1640f453ba04SDave Airlie 1641f453ba04SDave Airlie } 1642f453ba04SDave Airlie } 1643f453ba04SDave Airlie card_res->count_encoders = encoder_count; 1644f453ba04SDave Airlie 1645f453ba04SDave Airlie /* Connectors */ 1646f453ba04SDave Airlie if (card_res->count_connectors >= connector_count) { 1647f453ba04SDave Airlie copied = 0; 1648f453ba04SDave Airlie connector_id = (uint32_t __user *)(unsigned long)card_res->connector_id_ptr; 164909f308f7SThomas Hellstrom if (!mode_group) { 1650f453ba04SDave Airlie list_for_each_entry(connector, 1651f453ba04SDave Airlie &dev->mode_config.connector_list, 1652f453ba04SDave Airlie head) { 16539440106bSJerome Glisse DRM_DEBUG_KMS("[CONNECTOR:%d:%s]\n", 16549440106bSJerome Glisse connector->base.id, 16559440106bSJerome Glisse drm_get_connector_name(connector)); 1656f453ba04SDave Airlie if (put_user(connector->base.id, 1657f453ba04SDave Airlie connector_id + copied)) { 1658f453ba04SDave Airlie ret = -EFAULT; 1659f453ba04SDave Airlie goto out; 1660f453ba04SDave Airlie } 1661f453ba04SDave Airlie copied++; 1662f453ba04SDave Airlie } 1663f453ba04SDave Airlie } else { 1664f453ba04SDave Airlie int start = mode_group->num_crtcs + 1665f453ba04SDave Airlie mode_group->num_encoders; 1666f453ba04SDave Airlie for (i = start; i < start + mode_group->num_connectors; i++) { 1667f453ba04SDave Airlie if (put_user(mode_group->id_list[i], 1668f453ba04SDave Airlie connector_id + copied)) { 1669f453ba04SDave Airlie ret = -EFAULT; 1670f453ba04SDave Airlie goto out; 1671f453ba04SDave Airlie } 1672f453ba04SDave Airlie copied++; 1673f453ba04SDave Airlie } 1674f453ba04SDave Airlie } 1675f453ba04SDave Airlie } 1676f453ba04SDave Airlie card_res->count_connectors = connector_count; 1677f453ba04SDave Airlie 16789440106bSJerome Glisse DRM_DEBUG_KMS("CRTC[%d] CONNECTORS[%d] ENCODERS[%d]\n", card_res->count_crtcs, 1679f453ba04SDave Airlie card_res->count_connectors, card_res->count_encoders); 1680f453ba04SDave Airlie 1681f453ba04SDave Airlie out: 168284849903SDaniel Vetter drm_modeset_unlock_all(dev); 1683f453ba04SDave Airlie return ret; 1684f453ba04SDave Airlie } 1685f453ba04SDave Airlie 1686f453ba04SDave Airlie /** 1687f453ba04SDave Airlie * drm_mode_getcrtc - get CRTC configuration 1688065a50edSDaniel Vetter * @dev: drm device for the ioctl 1689065a50edSDaniel Vetter * @data: data pointer for the ioctl 1690065a50edSDaniel Vetter * @file_priv: drm file for the ioctl call 1691f453ba04SDave Airlie * 1692f453ba04SDave Airlie * Construct a CRTC configuration structure to return to the user. 1693f453ba04SDave Airlie * 1694f453ba04SDave Airlie * Called by the user via ioctl. 1695f453ba04SDave Airlie * 1696c8e32cc1SDaniel Vetter * Returns: 1697f453ba04SDave Airlie * Zero on success, errno on failure. 1698f453ba04SDave Airlie */ 1699f453ba04SDave Airlie int drm_mode_getcrtc(struct drm_device *dev, 1700f453ba04SDave Airlie void *data, struct drm_file *file_priv) 1701f453ba04SDave Airlie { 1702f453ba04SDave Airlie struct drm_mode_crtc *crtc_resp = data; 1703f453ba04SDave Airlie struct drm_crtc *crtc; 1704f453ba04SDave Airlie struct drm_mode_object *obj; 1705f453ba04SDave Airlie int ret = 0; 1706f453ba04SDave Airlie 1707fb3b06c8SDave Airlie if (!drm_core_check_feature(dev, DRIVER_MODESET)) 1708fb3b06c8SDave Airlie return -EINVAL; 1709fb3b06c8SDave Airlie 171084849903SDaniel Vetter drm_modeset_lock_all(dev); 1711f453ba04SDave Airlie 1712f453ba04SDave Airlie obj = drm_mode_object_find(dev, crtc_resp->crtc_id, 1713f453ba04SDave Airlie DRM_MODE_OBJECT_CRTC); 1714f453ba04SDave Airlie if (!obj) { 1715f27657f2SVille Syrjälä ret = -ENOENT; 1716f453ba04SDave Airlie goto out; 1717f453ba04SDave Airlie } 1718f453ba04SDave Airlie crtc = obj_to_crtc(obj); 1719f453ba04SDave Airlie 1720f453ba04SDave Airlie crtc_resp->x = crtc->x; 1721f453ba04SDave Airlie crtc_resp->y = crtc->y; 1722f453ba04SDave Airlie crtc_resp->gamma_size = crtc->gamma_size; 1723f4510a27SMatt Roper if (crtc->primary->fb) 1724f4510a27SMatt Roper crtc_resp->fb_id = crtc->primary->fb->base.id; 1725f453ba04SDave Airlie else 1726f453ba04SDave Airlie crtc_resp->fb_id = 0; 1727f453ba04SDave Airlie 1728f453ba04SDave Airlie if (crtc->enabled) { 1729f453ba04SDave Airlie 1730f453ba04SDave Airlie drm_crtc_convert_to_umode(&crtc_resp->mode, &crtc->mode); 1731f453ba04SDave Airlie crtc_resp->mode_valid = 1; 1732f453ba04SDave Airlie 1733f453ba04SDave Airlie } else { 1734f453ba04SDave Airlie crtc_resp->mode_valid = 0; 1735f453ba04SDave Airlie } 1736f453ba04SDave Airlie 1737f453ba04SDave Airlie out: 173884849903SDaniel Vetter drm_modeset_unlock_all(dev); 1739f453ba04SDave Airlie return ret; 1740f453ba04SDave Airlie } 1741f453ba04SDave Airlie 174261d8e328SDamien Lespiau static bool drm_mode_expose_to_userspace(const struct drm_display_mode *mode, 174361d8e328SDamien Lespiau const struct drm_file *file_priv) 174461d8e328SDamien Lespiau { 174561d8e328SDamien Lespiau /* 174661d8e328SDamien Lespiau * If user-space hasn't configured the driver to expose the stereo 3D 174761d8e328SDamien Lespiau * modes, don't expose them. 174861d8e328SDamien Lespiau */ 174961d8e328SDamien Lespiau if (!file_priv->stereo_allowed && drm_mode_is_stereo(mode)) 175061d8e328SDamien Lespiau return false; 175161d8e328SDamien Lespiau 175261d8e328SDamien Lespiau return true; 175361d8e328SDamien Lespiau } 175461d8e328SDamien Lespiau 1755f453ba04SDave Airlie /** 1756f453ba04SDave Airlie * drm_mode_getconnector - get connector configuration 1757065a50edSDaniel Vetter * @dev: drm device for the ioctl 1758065a50edSDaniel Vetter * @data: data pointer for the ioctl 1759065a50edSDaniel Vetter * @file_priv: drm file for the ioctl call 1760f453ba04SDave Airlie * 1761f453ba04SDave Airlie * Construct a connector configuration structure to return to the user. 1762f453ba04SDave Airlie * 1763f453ba04SDave Airlie * Called by the user via ioctl. 1764f453ba04SDave Airlie * 1765c8e32cc1SDaniel Vetter * Returns: 1766f453ba04SDave Airlie * Zero on success, errno on failure. 1767f453ba04SDave Airlie */ 1768f453ba04SDave Airlie int drm_mode_getconnector(struct drm_device *dev, void *data, 1769f453ba04SDave Airlie struct drm_file *file_priv) 1770f453ba04SDave Airlie { 1771f453ba04SDave Airlie struct drm_mode_get_connector *out_resp = data; 1772f453ba04SDave Airlie struct drm_mode_object *obj; 1773f453ba04SDave Airlie struct drm_connector *connector; 1774f453ba04SDave Airlie struct drm_display_mode *mode; 1775f453ba04SDave Airlie int mode_count = 0; 1776f453ba04SDave Airlie int props_count = 0; 1777f453ba04SDave Airlie int encoders_count = 0; 1778f453ba04SDave Airlie int ret = 0; 1779f453ba04SDave Airlie int copied = 0; 1780f453ba04SDave Airlie int i; 1781f453ba04SDave Airlie struct drm_mode_modeinfo u_mode; 1782f453ba04SDave Airlie struct drm_mode_modeinfo __user *mode_ptr; 1783f453ba04SDave Airlie uint32_t __user *prop_ptr; 1784f453ba04SDave Airlie uint64_t __user *prop_values; 1785f453ba04SDave Airlie uint32_t __user *encoder_ptr; 1786f453ba04SDave Airlie 1787fb3b06c8SDave Airlie if (!drm_core_check_feature(dev, DRIVER_MODESET)) 1788fb3b06c8SDave Airlie return -EINVAL; 1789fb3b06c8SDave Airlie 1790f453ba04SDave Airlie memset(&u_mode, 0, sizeof(struct drm_mode_modeinfo)); 1791f453ba04SDave Airlie 17929440106bSJerome Glisse DRM_DEBUG_KMS("[CONNECTOR:%d:?]\n", out_resp->connector_id); 1793f453ba04SDave Airlie 17947b24056bSDaniel Vetter mutex_lock(&dev->mode_config.mutex); 1795f453ba04SDave Airlie 1796f453ba04SDave Airlie obj = drm_mode_object_find(dev, out_resp->connector_id, 1797f453ba04SDave Airlie DRM_MODE_OBJECT_CONNECTOR); 1798f453ba04SDave Airlie if (!obj) { 1799f27657f2SVille Syrjälä ret = -ENOENT; 1800f453ba04SDave Airlie goto out; 1801f453ba04SDave Airlie } 1802f453ba04SDave Airlie connector = obj_to_connector(obj); 1803f453ba04SDave Airlie 18047f88a9beSPaulo Zanoni props_count = connector->properties.count; 1805f453ba04SDave Airlie 1806f453ba04SDave Airlie for (i = 0; i < DRM_CONNECTOR_MAX_ENCODER; i++) { 1807f453ba04SDave Airlie if (connector->encoder_ids[i] != 0) { 1808f453ba04SDave Airlie encoders_count++; 1809f453ba04SDave Airlie } 1810f453ba04SDave Airlie } 1811f453ba04SDave Airlie 1812f453ba04SDave Airlie if (out_resp->count_modes == 0) { 1813f453ba04SDave Airlie connector->funcs->fill_modes(connector, 1814f453ba04SDave Airlie dev->mode_config.max_width, 1815f453ba04SDave Airlie dev->mode_config.max_height); 1816f453ba04SDave Airlie } 1817f453ba04SDave Airlie 1818f453ba04SDave Airlie /* delayed so we get modes regardless of pre-fill_modes state */ 1819f453ba04SDave Airlie list_for_each_entry(mode, &connector->modes, head) 182061d8e328SDamien Lespiau if (drm_mode_expose_to_userspace(mode, file_priv)) 1821f453ba04SDave Airlie mode_count++; 1822f453ba04SDave Airlie 1823f453ba04SDave Airlie out_resp->connector_id = connector->base.id; 1824f453ba04SDave Airlie out_resp->connector_type = connector->connector_type; 1825f453ba04SDave Airlie out_resp->connector_type_id = connector->connector_type_id; 1826f453ba04SDave Airlie out_resp->mm_width = connector->display_info.width_mm; 1827f453ba04SDave Airlie out_resp->mm_height = connector->display_info.height_mm; 1828f453ba04SDave Airlie out_resp->subpixel = connector->display_info.subpixel_order; 1829f453ba04SDave Airlie out_resp->connection = connector->status; 1830f453ba04SDave Airlie if (connector->encoder) 1831f453ba04SDave Airlie out_resp->encoder_id = connector->encoder->base.id; 1832f453ba04SDave Airlie else 1833f453ba04SDave Airlie out_resp->encoder_id = 0; 1834f453ba04SDave Airlie 1835f453ba04SDave Airlie /* 1836f453ba04SDave Airlie * This ioctl is called twice, once to determine how much space is 1837f453ba04SDave Airlie * needed, and the 2nd time to fill it. 1838f453ba04SDave Airlie */ 1839f453ba04SDave Airlie if ((out_resp->count_modes >= mode_count) && mode_count) { 1840f453ba04SDave Airlie copied = 0; 184181f6c7f8SVille Syrjälä mode_ptr = (struct drm_mode_modeinfo __user *)(unsigned long)out_resp->modes_ptr; 1842f453ba04SDave Airlie list_for_each_entry(mode, &connector->modes, head) { 184361d8e328SDamien Lespiau if (!drm_mode_expose_to_userspace(mode, file_priv)) 184461d8e328SDamien Lespiau continue; 184561d8e328SDamien Lespiau 1846f453ba04SDave Airlie drm_crtc_convert_to_umode(&u_mode, mode); 1847f453ba04SDave Airlie if (copy_to_user(mode_ptr + copied, 1848f453ba04SDave Airlie &u_mode, sizeof(u_mode))) { 1849f453ba04SDave Airlie ret = -EFAULT; 1850f453ba04SDave Airlie goto out; 1851f453ba04SDave Airlie } 1852f453ba04SDave Airlie copied++; 1853f453ba04SDave Airlie } 1854f453ba04SDave Airlie } 1855f453ba04SDave Airlie out_resp->count_modes = mode_count; 1856f453ba04SDave Airlie 1857f453ba04SDave Airlie if ((out_resp->count_props >= props_count) && props_count) { 1858f453ba04SDave Airlie copied = 0; 185981f6c7f8SVille Syrjälä prop_ptr = (uint32_t __user *)(unsigned long)(out_resp->props_ptr); 186081f6c7f8SVille Syrjälä prop_values = (uint64_t __user *)(unsigned long)(out_resp->prop_values_ptr); 18617f88a9beSPaulo Zanoni for (i = 0; i < connector->properties.count; i++) { 18627e3bdf4aSPaulo Zanoni if (put_user(connector->properties.ids[i], 1863f453ba04SDave Airlie prop_ptr + copied)) { 1864f453ba04SDave Airlie ret = -EFAULT; 1865f453ba04SDave Airlie goto out; 1866f453ba04SDave Airlie } 1867f453ba04SDave Airlie 18687e3bdf4aSPaulo Zanoni if (put_user(connector->properties.values[i], 1869f453ba04SDave Airlie prop_values + copied)) { 1870f453ba04SDave Airlie ret = -EFAULT; 1871f453ba04SDave Airlie goto out; 1872f453ba04SDave Airlie } 1873f453ba04SDave Airlie copied++; 1874f453ba04SDave Airlie } 1875f453ba04SDave Airlie } 1876f453ba04SDave Airlie out_resp->count_props = props_count; 1877f453ba04SDave Airlie 1878f453ba04SDave Airlie if ((out_resp->count_encoders >= encoders_count) && encoders_count) { 1879f453ba04SDave Airlie copied = 0; 188081f6c7f8SVille Syrjälä encoder_ptr = (uint32_t __user *)(unsigned long)(out_resp->encoders_ptr); 1881f453ba04SDave Airlie for (i = 0; i < DRM_CONNECTOR_MAX_ENCODER; i++) { 1882f453ba04SDave Airlie if (connector->encoder_ids[i] != 0) { 1883f453ba04SDave Airlie if (put_user(connector->encoder_ids[i], 1884f453ba04SDave Airlie encoder_ptr + copied)) { 1885f453ba04SDave Airlie ret = -EFAULT; 1886f453ba04SDave Airlie goto out; 1887f453ba04SDave Airlie } 1888f453ba04SDave Airlie copied++; 1889f453ba04SDave Airlie } 1890f453ba04SDave Airlie } 1891f453ba04SDave Airlie } 1892f453ba04SDave Airlie out_resp->count_encoders = encoders_count; 1893f453ba04SDave Airlie 1894f453ba04SDave Airlie out: 18957b24056bSDaniel Vetter mutex_unlock(&dev->mode_config.mutex); 18967b24056bSDaniel Vetter 1897f453ba04SDave Airlie return ret; 1898f453ba04SDave Airlie } 1899f453ba04SDave Airlie 1900c8e32cc1SDaniel Vetter /** 1901c8e32cc1SDaniel Vetter * drm_mode_getencoder - get encoder configuration 1902c8e32cc1SDaniel Vetter * @dev: drm device for the ioctl 1903c8e32cc1SDaniel Vetter * @data: data pointer for the ioctl 1904c8e32cc1SDaniel Vetter * @file_priv: drm file for the ioctl call 1905c8e32cc1SDaniel Vetter * 1906c8e32cc1SDaniel Vetter * Construct a encoder configuration structure to return to the user. 1907c8e32cc1SDaniel Vetter * 1908c8e32cc1SDaniel Vetter * Called by the user via ioctl. 1909c8e32cc1SDaniel Vetter * 1910c8e32cc1SDaniel Vetter * Returns: 1911c8e32cc1SDaniel Vetter * Zero on success, errno on failure. 1912c8e32cc1SDaniel Vetter */ 1913f453ba04SDave Airlie int drm_mode_getencoder(struct drm_device *dev, void *data, 1914f453ba04SDave Airlie struct drm_file *file_priv) 1915f453ba04SDave Airlie { 1916f453ba04SDave Airlie struct drm_mode_get_encoder *enc_resp = data; 1917f453ba04SDave Airlie struct drm_mode_object *obj; 1918f453ba04SDave Airlie struct drm_encoder *encoder; 1919f453ba04SDave Airlie int ret = 0; 1920f453ba04SDave Airlie 1921fb3b06c8SDave Airlie if (!drm_core_check_feature(dev, DRIVER_MODESET)) 1922fb3b06c8SDave Airlie return -EINVAL; 1923fb3b06c8SDave Airlie 192484849903SDaniel Vetter drm_modeset_lock_all(dev); 1925f453ba04SDave Airlie obj = drm_mode_object_find(dev, enc_resp->encoder_id, 1926f453ba04SDave Airlie DRM_MODE_OBJECT_ENCODER); 1927f453ba04SDave Airlie if (!obj) { 1928f27657f2SVille Syrjälä ret = -ENOENT; 1929f453ba04SDave Airlie goto out; 1930f453ba04SDave Airlie } 1931f453ba04SDave Airlie encoder = obj_to_encoder(obj); 1932f453ba04SDave Airlie 1933f453ba04SDave Airlie if (encoder->crtc) 1934f453ba04SDave Airlie enc_resp->crtc_id = encoder->crtc->base.id; 1935f453ba04SDave Airlie else 1936f453ba04SDave Airlie enc_resp->crtc_id = 0; 1937f453ba04SDave Airlie enc_resp->encoder_type = encoder->encoder_type; 1938f453ba04SDave Airlie enc_resp->encoder_id = encoder->base.id; 1939f453ba04SDave Airlie enc_resp->possible_crtcs = encoder->possible_crtcs; 1940f453ba04SDave Airlie enc_resp->possible_clones = encoder->possible_clones; 1941f453ba04SDave Airlie 1942f453ba04SDave Airlie out: 194384849903SDaniel Vetter drm_modeset_unlock_all(dev); 1944f453ba04SDave Airlie return ret; 1945f453ba04SDave Airlie } 1946f453ba04SDave Airlie 1947f453ba04SDave Airlie /** 1948c8e32cc1SDaniel Vetter * drm_mode_getplane_res - enumerate all plane resources 19498cf5c917SJesse Barnes * @dev: DRM device 19508cf5c917SJesse Barnes * @data: ioctl data 19518cf5c917SJesse Barnes * @file_priv: DRM file info 19528cf5c917SJesse Barnes * 1953c8e32cc1SDaniel Vetter * Construct a list of plane ids to return to the user. 1954c8e32cc1SDaniel Vetter * 1955c8e32cc1SDaniel Vetter * Called by the user via ioctl. 1956c8e32cc1SDaniel Vetter * 1957c8e32cc1SDaniel Vetter * Returns: 1958c8e32cc1SDaniel Vetter * Zero on success, errno on failure. 19598cf5c917SJesse Barnes */ 19608cf5c917SJesse Barnes int drm_mode_getplane_res(struct drm_device *dev, void *data, 19618cf5c917SJesse Barnes struct drm_file *file_priv) 19628cf5c917SJesse Barnes { 19638cf5c917SJesse Barnes struct drm_mode_get_plane_res *plane_resp = data; 19648cf5c917SJesse Barnes struct drm_mode_config *config; 19658cf5c917SJesse Barnes struct drm_plane *plane; 19668cf5c917SJesse Barnes uint32_t __user *plane_ptr; 19678cf5c917SJesse Barnes int copied = 0, ret = 0; 1968681e7ec7SMatt Roper unsigned num_planes; 19698cf5c917SJesse Barnes 19708cf5c917SJesse Barnes if (!drm_core_check_feature(dev, DRIVER_MODESET)) 19718cf5c917SJesse Barnes return -EINVAL; 19728cf5c917SJesse Barnes 197384849903SDaniel Vetter drm_modeset_lock_all(dev); 19748cf5c917SJesse Barnes config = &dev->mode_config; 19758cf5c917SJesse Barnes 1976681e7ec7SMatt Roper if (file_priv->universal_planes) 1977681e7ec7SMatt Roper num_planes = config->num_total_plane; 1978681e7ec7SMatt Roper else 1979681e7ec7SMatt Roper num_planes = config->num_overlay_plane; 1980681e7ec7SMatt Roper 19818cf5c917SJesse Barnes /* 19828cf5c917SJesse Barnes * This ioctl is called twice, once to determine how much space is 19838cf5c917SJesse Barnes * needed, and the 2nd time to fill it. 19848cf5c917SJesse Barnes */ 1985681e7ec7SMatt Roper if (num_planes && 1986681e7ec7SMatt Roper (plane_resp->count_planes >= num_planes)) { 198781f6c7f8SVille Syrjälä plane_ptr = (uint32_t __user *)(unsigned long)plane_resp->plane_id_ptr; 19888cf5c917SJesse Barnes 19898cf5c917SJesse Barnes list_for_each_entry(plane, &config->plane_list, head) { 1990681e7ec7SMatt Roper /* 1991681e7ec7SMatt Roper * Unless userspace set the 'universal planes' 1992681e7ec7SMatt Roper * capability bit, only advertise overlays. 1993681e7ec7SMatt Roper */ 1994681e7ec7SMatt Roper if (plane->type != DRM_PLANE_TYPE_OVERLAY && 1995681e7ec7SMatt Roper !file_priv->universal_planes) 1996e27dde3eSMatt Roper continue; 1997e27dde3eSMatt Roper 19988cf5c917SJesse Barnes if (put_user(plane->base.id, plane_ptr + copied)) { 19998cf5c917SJesse Barnes ret = -EFAULT; 20008cf5c917SJesse Barnes goto out; 20018cf5c917SJesse Barnes } 20028cf5c917SJesse Barnes copied++; 20038cf5c917SJesse Barnes } 20048cf5c917SJesse Barnes } 2005681e7ec7SMatt Roper plane_resp->count_planes = num_planes; 20068cf5c917SJesse Barnes 20078cf5c917SJesse Barnes out: 200884849903SDaniel Vetter drm_modeset_unlock_all(dev); 20098cf5c917SJesse Barnes return ret; 20108cf5c917SJesse Barnes } 20118cf5c917SJesse Barnes 20128cf5c917SJesse Barnes /** 2013c8e32cc1SDaniel Vetter * drm_mode_getplane - get plane configuration 20148cf5c917SJesse Barnes * @dev: DRM device 20158cf5c917SJesse Barnes * @data: ioctl data 20168cf5c917SJesse Barnes * @file_priv: DRM file info 20178cf5c917SJesse Barnes * 2018c8e32cc1SDaniel Vetter * Construct a plane configuration structure to return to the user. 2019c8e32cc1SDaniel Vetter * 2020c8e32cc1SDaniel Vetter * Called by the user via ioctl. 2021c8e32cc1SDaniel Vetter * 2022c8e32cc1SDaniel Vetter * Returns: 2023c8e32cc1SDaniel Vetter * Zero on success, errno on failure. 20248cf5c917SJesse Barnes */ 20258cf5c917SJesse Barnes int drm_mode_getplane(struct drm_device *dev, void *data, 20268cf5c917SJesse Barnes struct drm_file *file_priv) 20278cf5c917SJesse Barnes { 20288cf5c917SJesse Barnes struct drm_mode_get_plane *plane_resp = data; 20298cf5c917SJesse Barnes struct drm_mode_object *obj; 20308cf5c917SJesse Barnes struct drm_plane *plane; 20318cf5c917SJesse Barnes uint32_t __user *format_ptr; 20328cf5c917SJesse Barnes int ret = 0; 20338cf5c917SJesse Barnes 20348cf5c917SJesse Barnes if (!drm_core_check_feature(dev, DRIVER_MODESET)) 20358cf5c917SJesse Barnes return -EINVAL; 20368cf5c917SJesse Barnes 203784849903SDaniel Vetter drm_modeset_lock_all(dev); 20388cf5c917SJesse Barnes obj = drm_mode_object_find(dev, plane_resp->plane_id, 20398cf5c917SJesse Barnes DRM_MODE_OBJECT_PLANE); 20408cf5c917SJesse Barnes if (!obj) { 20418cf5c917SJesse Barnes ret = -ENOENT; 20428cf5c917SJesse Barnes goto out; 20438cf5c917SJesse Barnes } 20448cf5c917SJesse Barnes plane = obj_to_plane(obj); 20458cf5c917SJesse Barnes 20468cf5c917SJesse Barnes if (plane->crtc) 20478cf5c917SJesse Barnes plane_resp->crtc_id = plane->crtc->base.id; 20488cf5c917SJesse Barnes else 20498cf5c917SJesse Barnes plane_resp->crtc_id = 0; 20508cf5c917SJesse Barnes 20518cf5c917SJesse Barnes if (plane->fb) 20528cf5c917SJesse Barnes plane_resp->fb_id = plane->fb->base.id; 20538cf5c917SJesse Barnes else 20548cf5c917SJesse Barnes plane_resp->fb_id = 0; 20558cf5c917SJesse Barnes 20568cf5c917SJesse Barnes plane_resp->plane_id = plane->base.id; 20578cf5c917SJesse Barnes plane_resp->possible_crtcs = plane->possible_crtcs; 2058778ad903SVille Syrjälä plane_resp->gamma_size = 0; 20598cf5c917SJesse Barnes 20608cf5c917SJesse Barnes /* 20618cf5c917SJesse Barnes * This ioctl is called twice, once to determine how much space is 20628cf5c917SJesse Barnes * needed, and the 2nd time to fill it. 20638cf5c917SJesse Barnes */ 20648cf5c917SJesse Barnes if (plane->format_count && 20658cf5c917SJesse Barnes (plane_resp->count_format_types >= plane->format_count)) { 206681f6c7f8SVille Syrjälä format_ptr = (uint32_t __user *)(unsigned long)plane_resp->format_type_ptr; 20678cf5c917SJesse Barnes if (copy_to_user(format_ptr, 20688cf5c917SJesse Barnes plane->format_types, 20698cf5c917SJesse Barnes sizeof(uint32_t) * plane->format_count)) { 20708cf5c917SJesse Barnes ret = -EFAULT; 20718cf5c917SJesse Barnes goto out; 20728cf5c917SJesse Barnes } 20738cf5c917SJesse Barnes } 20748cf5c917SJesse Barnes plane_resp->count_format_types = plane->format_count; 20758cf5c917SJesse Barnes 20768cf5c917SJesse Barnes out: 207784849903SDaniel Vetter drm_modeset_unlock_all(dev); 20788cf5c917SJesse Barnes return ret; 20798cf5c917SJesse Barnes } 20808cf5c917SJesse Barnes 20818cf5c917SJesse Barnes /** 2082c8e32cc1SDaniel Vetter * drm_mode_setplane - configure a plane's configuration 20838cf5c917SJesse Barnes * @dev: DRM device 20848cf5c917SJesse Barnes * @data: ioctl data* 2085065a50edSDaniel Vetter * @file_priv: DRM file info 20868cf5c917SJesse Barnes * 2087c8e32cc1SDaniel Vetter * Set plane configuration, including placement, fb, scaling, and other factors. 20888cf5c917SJesse Barnes * Or pass a NULL fb to disable. 2089c8e32cc1SDaniel Vetter * 2090c8e32cc1SDaniel Vetter * Returns: 2091c8e32cc1SDaniel Vetter * Zero on success, errno on failure. 20928cf5c917SJesse Barnes */ 20938cf5c917SJesse Barnes int drm_mode_setplane(struct drm_device *dev, void *data, 20948cf5c917SJesse Barnes struct drm_file *file_priv) 20958cf5c917SJesse Barnes { 20968cf5c917SJesse Barnes struct drm_mode_set_plane *plane_req = data; 20978cf5c917SJesse Barnes struct drm_mode_object *obj; 20988cf5c917SJesse Barnes struct drm_plane *plane; 20998cf5c917SJesse Barnes struct drm_crtc *crtc; 21006c2a7532SDaniel Vetter struct drm_framebuffer *fb = NULL, *old_fb = NULL; 21018cf5c917SJesse Barnes int ret = 0; 210242ef8789SVille Syrjälä unsigned int fb_width, fb_height; 210362443be6SVille Syrjälä int i; 21048cf5c917SJesse Barnes 21058cf5c917SJesse Barnes if (!drm_core_check_feature(dev, DRIVER_MODESET)) 21068cf5c917SJesse Barnes return -EINVAL; 21078cf5c917SJesse Barnes 21088cf5c917SJesse Barnes /* 21098cf5c917SJesse Barnes * First, find the plane, crtc, and fb objects. If not available, 21108cf5c917SJesse Barnes * we don't bother to call the driver. 21118cf5c917SJesse Barnes */ 21128cf5c917SJesse Barnes obj = drm_mode_object_find(dev, plane_req->plane_id, 21138cf5c917SJesse Barnes DRM_MODE_OBJECT_PLANE); 21148cf5c917SJesse Barnes if (!obj) { 21158cf5c917SJesse Barnes DRM_DEBUG_KMS("Unknown plane ID %d\n", 21168cf5c917SJesse Barnes plane_req->plane_id); 21176c2a7532SDaniel Vetter return -ENOENT; 21188cf5c917SJesse Barnes } 21198cf5c917SJesse Barnes plane = obj_to_plane(obj); 21208cf5c917SJesse Barnes 21218cf5c917SJesse Barnes /* No fb means shut it down */ 21228cf5c917SJesse Barnes if (!plane_req->fb_id) { 21236c2a7532SDaniel Vetter drm_modeset_lock_all(dev); 21246c2a7532SDaniel Vetter old_fb = plane->fb; 21258cf5c917SJesse Barnes plane->funcs->disable_plane(plane); 2126e5e3b44cSVille Syrjälä plane->crtc = NULL; 2127e5e3b44cSVille Syrjälä plane->fb = NULL; 21286c2a7532SDaniel Vetter drm_modeset_unlock_all(dev); 21298cf5c917SJesse Barnes goto out; 21308cf5c917SJesse Barnes } 21318cf5c917SJesse Barnes 21328cf5c917SJesse Barnes obj = drm_mode_object_find(dev, plane_req->crtc_id, 21338cf5c917SJesse Barnes DRM_MODE_OBJECT_CRTC); 21348cf5c917SJesse Barnes if (!obj) { 21358cf5c917SJesse Barnes DRM_DEBUG_KMS("Unknown crtc ID %d\n", 21368cf5c917SJesse Barnes plane_req->crtc_id); 21378cf5c917SJesse Barnes ret = -ENOENT; 21388cf5c917SJesse Barnes goto out; 21398cf5c917SJesse Barnes } 21408cf5c917SJesse Barnes crtc = obj_to_crtc(obj); 21418cf5c917SJesse Barnes 2142786b99edSDaniel Vetter fb = drm_framebuffer_lookup(dev, plane_req->fb_id); 2143786b99edSDaniel Vetter if (!fb) { 21448cf5c917SJesse Barnes DRM_DEBUG_KMS("Unknown framebuffer ID %d\n", 21458cf5c917SJesse Barnes plane_req->fb_id); 21468cf5c917SJesse Barnes ret = -ENOENT; 21478cf5c917SJesse Barnes goto out; 21488cf5c917SJesse Barnes } 21498cf5c917SJesse Barnes 215062443be6SVille Syrjälä /* Check whether this plane supports the fb pixel format. */ 215162443be6SVille Syrjälä for (i = 0; i < plane->format_count; i++) 215262443be6SVille Syrjälä if (fb->pixel_format == plane->format_types[i]) 215362443be6SVille Syrjälä break; 215462443be6SVille Syrjälä if (i == plane->format_count) { 21556ba6d03eSVille Syrjälä DRM_DEBUG_KMS("Invalid pixel format %s\n", 21566ba6d03eSVille Syrjälä drm_get_format_name(fb->pixel_format)); 215762443be6SVille Syrjälä ret = -EINVAL; 215862443be6SVille Syrjälä goto out; 215962443be6SVille Syrjälä } 216062443be6SVille Syrjälä 216142ef8789SVille Syrjälä fb_width = fb->width << 16; 216242ef8789SVille Syrjälä fb_height = fb->height << 16; 216342ef8789SVille Syrjälä 216442ef8789SVille Syrjälä /* Make sure source coordinates are inside the fb. */ 216542ef8789SVille Syrjälä if (plane_req->src_w > fb_width || 216642ef8789SVille Syrjälä plane_req->src_x > fb_width - plane_req->src_w || 216742ef8789SVille Syrjälä plane_req->src_h > fb_height || 216842ef8789SVille Syrjälä plane_req->src_y > fb_height - plane_req->src_h) { 216942ef8789SVille Syrjälä DRM_DEBUG_KMS("Invalid source coordinates " 217042ef8789SVille Syrjälä "%u.%06ux%u.%06u+%u.%06u+%u.%06u\n", 217142ef8789SVille Syrjälä plane_req->src_w >> 16, 217242ef8789SVille Syrjälä ((plane_req->src_w & 0xffff) * 15625) >> 10, 217342ef8789SVille Syrjälä plane_req->src_h >> 16, 217442ef8789SVille Syrjälä ((plane_req->src_h & 0xffff) * 15625) >> 10, 217542ef8789SVille Syrjälä plane_req->src_x >> 16, 217642ef8789SVille Syrjälä ((plane_req->src_x & 0xffff) * 15625) >> 10, 217742ef8789SVille Syrjälä plane_req->src_y >> 16, 217842ef8789SVille Syrjälä ((plane_req->src_y & 0xffff) * 15625) >> 10); 217942ef8789SVille Syrjälä ret = -ENOSPC; 218042ef8789SVille Syrjälä goto out; 218142ef8789SVille Syrjälä } 218242ef8789SVille Syrjälä 2183687a0400SVille Syrjälä /* Give drivers some help against integer overflows */ 2184687a0400SVille Syrjälä if (plane_req->crtc_w > INT_MAX || 2185687a0400SVille Syrjälä plane_req->crtc_x > INT_MAX - (int32_t) plane_req->crtc_w || 2186687a0400SVille Syrjälä plane_req->crtc_h > INT_MAX || 2187687a0400SVille Syrjälä plane_req->crtc_y > INT_MAX - (int32_t) plane_req->crtc_h) { 2188687a0400SVille Syrjälä DRM_DEBUG_KMS("Invalid CRTC coordinates %ux%u+%d+%d\n", 2189687a0400SVille Syrjälä plane_req->crtc_w, plane_req->crtc_h, 2190687a0400SVille Syrjälä plane_req->crtc_x, plane_req->crtc_y); 2191687a0400SVille Syrjälä ret = -ERANGE; 2192687a0400SVille Syrjälä goto out; 2193687a0400SVille Syrjälä } 2194687a0400SVille Syrjälä 21956c2a7532SDaniel Vetter drm_modeset_lock_all(dev); 21968cf5c917SJesse Barnes ret = plane->funcs->update_plane(plane, crtc, fb, 21978cf5c917SJesse Barnes plane_req->crtc_x, plane_req->crtc_y, 21988cf5c917SJesse Barnes plane_req->crtc_w, plane_req->crtc_h, 21998cf5c917SJesse Barnes plane_req->src_x, plane_req->src_y, 22008cf5c917SJesse Barnes plane_req->src_w, plane_req->src_h); 22018cf5c917SJesse Barnes if (!ret) { 22026c2a7532SDaniel Vetter old_fb = plane->fb; 22038cf5c917SJesse Barnes plane->crtc = crtc; 22048cf5c917SJesse Barnes plane->fb = fb; 220535f8badcSDaniel Vetter fb = NULL; 22068cf5c917SJesse Barnes } 22076c2a7532SDaniel Vetter drm_modeset_unlock_all(dev); 22088cf5c917SJesse Barnes 22098cf5c917SJesse Barnes out: 22106c2a7532SDaniel Vetter if (fb) 22116c2a7532SDaniel Vetter drm_framebuffer_unreference(fb); 22126c2a7532SDaniel Vetter if (old_fb) 22136c2a7532SDaniel Vetter drm_framebuffer_unreference(old_fb); 22148cf5c917SJesse Barnes 22158cf5c917SJesse Barnes return ret; 22168cf5c917SJesse Barnes } 22178cf5c917SJesse Barnes 22188cf5c917SJesse Barnes /** 22192d13b679SDaniel Vetter * drm_mode_set_config_internal - helper to call ->set_config 22202d13b679SDaniel Vetter * @set: modeset config to set 22212d13b679SDaniel Vetter * 22222d13b679SDaniel Vetter * This is a little helper to wrap internal calls to the ->set_config driver 22232d13b679SDaniel Vetter * interface. The only thing it adds is correct refcounting dance. 2224c8e32cc1SDaniel Vetter * 2225c8e32cc1SDaniel Vetter * Returns: 2226c8e32cc1SDaniel Vetter * Zero on success, errno on failure. 22272d13b679SDaniel Vetter */ 22282d13b679SDaniel Vetter int drm_mode_set_config_internal(struct drm_mode_set *set) 22292d13b679SDaniel Vetter { 22302d13b679SDaniel Vetter struct drm_crtc *crtc = set->crtc; 22315cef29aaSDaniel Vetter struct drm_framebuffer *fb; 22325cef29aaSDaniel Vetter struct drm_crtc *tmp; 2233b0d12325SDaniel Vetter int ret; 22342d13b679SDaniel Vetter 22355cef29aaSDaniel Vetter /* 22365cef29aaSDaniel Vetter * NOTE: ->set_config can also disable other crtcs (if we steal all 22375cef29aaSDaniel Vetter * connectors from it), hence we need to refcount the fbs across all 22385cef29aaSDaniel Vetter * crtcs. Atomic modeset will have saner semantics ... 22395cef29aaSDaniel Vetter */ 22405cef29aaSDaniel Vetter list_for_each_entry(tmp, &crtc->dev->mode_config.crtc_list, head) 2241f4510a27SMatt Roper tmp->old_fb = tmp->primary->fb; 22425cef29aaSDaniel Vetter 2243b0d12325SDaniel Vetter fb = set->fb; 2244b0d12325SDaniel Vetter 2245b0d12325SDaniel Vetter ret = crtc->funcs->set_config(set); 2246b0d12325SDaniel Vetter if (ret == 0) { 2247e13161afSMatt Roper crtc->primary->crtc = crtc; 2248e13161afSMatt Roper 2249cc85e121SDaniel Vetter /* crtc->fb must be updated by ->set_config, enforces this. */ 2250f4510a27SMatt Roper WARN_ON(fb != crtc->primary->fb); 22515cef29aaSDaniel Vetter } 2252cc85e121SDaniel Vetter 22535cef29aaSDaniel Vetter list_for_each_entry(tmp, &crtc->dev->mode_config.crtc_list, head) { 2254f4510a27SMatt Roper if (tmp->primary->fb) 2255f4510a27SMatt Roper drm_framebuffer_reference(tmp->primary->fb); 22565cef29aaSDaniel Vetter if (tmp->old_fb) 22575cef29aaSDaniel Vetter drm_framebuffer_unreference(tmp->old_fb); 2258b0d12325SDaniel Vetter } 2259b0d12325SDaniel Vetter 2260b0d12325SDaniel Vetter return ret; 22612d13b679SDaniel Vetter } 22622d13b679SDaniel Vetter EXPORT_SYMBOL(drm_mode_set_config_internal); 22632d13b679SDaniel Vetter 2264af93629dSMatt Roper /** 2265af93629dSMatt Roper * drm_crtc_check_viewport - Checks that a framebuffer is big enough for the 2266af93629dSMatt Roper * CRTC viewport 2267af93629dSMatt Roper * @crtc: CRTC that framebuffer will be displayed on 2268af93629dSMatt Roper * @x: x panning 2269af93629dSMatt Roper * @y: y panning 2270af93629dSMatt Roper * @mode: mode that framebuffer will be displayed under 2271af93629dSMatt Roper * @fb: framebuffer to check size of 2272c11e9283SDamien Lespiau */ 2273af93629dSMatt Roper int drm_crtc_check_viewport(const struct drm_crtc *crtc, 2274c11e9283SDamien Lespiau int x, int y, 2275c11e9283SDamien Lespiau const struct drm_display_mode *mode, 2276c11e9283SDamien Lespiau const struct drm_framebuffer *fb) 2277c11e9283SDamien Lespiau 2278c11e9283SDamien Lespiau { 2279c11e9283SDamien Lespiau int hdisplay, vdisplay; 2280c11e9283SDamien Lespiau 2281c11e9283SDamien Lespiau hdisplay = mode->hdisplay; 2282c11e9283SDamien Lespiau vdisplay = mode->vdisplay; 2283c11e9283SDamien Lespiau 2284a0c1bbb0SDamien Lespiau if (drm_mode_is_stereo(mode)) { 2285a0c1bbb0SDamien Lespiau struct drm_display_mode adjusted = *mode; 2286a0c1bbb0SDamien Lespiau 2287a0c1bbb0SDamien Lespiau drm_mode_set_crtcinfo(&adjusted, CRTC_STEREO_DOUBLE); 2288a0c1bbb0SDamien Lespiau hdisplay = adjusted.crtc_hdisplay; 2289a0c1bbb0SDamien Lespiau vdisplay = adjusted.crtc_vdisplay; 2290a0c1bbb0SDamien Lespiau } 2291a0c1bbb0SDamien Lespiau 2292c11e9283SDamien Lespiau if (crtc->invert_dimensions) 2293c11e9283SDamien Lespiau swap(hdisplay, vdisplay); 2294c11e9283SDamien Lespiau 2295c11e9283SDamien Lespiau if (hdisplay > fb->width || 2296c11e9283SDamien Lespiau vdisplay > fb->height || 2297c11e9283SDamien Lespiau x > fb->width - hdisplay || 2298c11e9283SDamien Lespiau y > fb->height - vdisplay) { 2299c11e9283SDamien Lespiau DRM_DEBUG_KMS("Invalid fb size %ux%u for CRTC viewport %ux%u+%d+%d%s.\n", 2300c11e9283SDamien Lespiau fb->width, fb->height, hdisplay, vdisplay, x, y, 2301c11e9283SDamien Lespiau crtc->invert_dimensions ? " (inverted)" : ""); 2302c11e9283SDamien Lespiau return -ENOSPC; 2303c11e9283SDamien Lespiau } 2304c11e9283SDamien Lespiau 2305c11e9283SDamien Lespiau return 0; 2306c11e9283SDamien Lespiau } 2307af93629dSMatt Roper EXPORT_SYMBOL(drm_crtc_check_viewport); 2308c11e9283SDamien Lespiau 23092d13b679SDaniel Vetter /** 2310f453ba04SDave Airlie * drm_mode_setcrtc - set CRTC configuration 2311065a50edSDaniel Vetter * @dev: drm device for the ioctl 2312065a50edSDaniel Vetter * @data: data pointer for the ioctl 2313065a50edSDaniel Vetter * @file_priv: drm file for the ioctl call 2314f453ba04SDave Airlie * 2315f453ba04SDave Airlie * Build a new CRTC configuration based on user request. 2316f453ba04SDave Airlie * 2317f453ba04SDave Airlie * Called by the user via ioctl. 2318f453ba04SDave Airlie * 2319c8e32cc1SDaniel Vetter * Returns: 2320f453ba04SDave Airlie * Zero on success, errno on failure. 2321f453ba04SDave Airlie */ 2322f453ba04SDave Airlie int drm_mode_setcrtc(struct drm_device *dev, void *data, 2323f453ba04SDave Airlie struct drm_file *file_priv) 2324f453ba04SDave Airlie { 2325f453ba04SDave Airlie struct drm_mode_config *config = &dev->mode_config; 2326f453ba04SDave Airlie struct drm_mode_crtc *crtc_req = data; 2327f453ba04SDave Airlie struct drm_mode_object *obj; 23286653cc8dSVille Syrjälä struct drm_crtc *crtc; 2329f453ba04SDave Airlie struct drm_connector **connector_set = NULL, *connector; 2330f453ba04SDave Airlie struct drm_framebuffer *fb = NULL; 2331f453ba04SDave Airlie struct drm_display_mode *mode = NULL; 2332f453ba04SDave Airlie struct drm_mode_set set; 2333f453ba04SDave Airlie uint32_t __user *set_connectors_ptr; 23344a1b0714SLaurent Pinchart int ret; 2335f453ba04SDave Airlie int i; 2336f453ba04SDave Airlie 2337fb3b06c8SDave Airlie if (!drm_core_check_feature(dev, DRIVER_MODESET)) 2338fb3b06c8SDave Airlie return -EINVAL; 2339fb3b06c8SDave Airlie 23401d97e915SVille Syrjälä /* For some reason crtc x/y offsets are signed internally. */ 23411d97e915SVille Syrjälä if (crtc_req->x > INT_MAX || crtc_req->y > INT_MAX) 23421d97e915SVille Syrjälä return -ERANGE; 23431d97e915SVille Syrjälä 234484849903SDaniel Vetter drm_modeset_lock_all(dev); 2345f453ba04SDave Airlie obj = drm_mode_object_find(dev, crtc_req->crtc_id, 2346f453ba04SDave Airlie DRM_MODE_OBJECT_CRTC); 2347f453ba04SDave Airlie if (!obj) { 234858367ed6SZhao Yakui DRM_DEBUG_KMS("Unknown CRTC ID %d\n", crtc_req->crtc_id); 2349f27657f2SVille Syrjälä ret = -ENOENT; 2350f453ba04SDave Airlie goto out; 2351f453ba04SDave Airlie } 2352f453ba04SDave Airlie crtc = obj_to_crtc(obj); 23539440106bSJerome Glisse DRM_DEBUG_KMS("[CRTC:%d]\n", crtc->base.id); 2354f453ba04SDave Airlie 2355f453ba04SDave Airlie if (crtc_req->mode_valid) { 2356f453ba04SDave Airlie /* If we have a mode we need a framebuffer. */ 2357f453ba04SDave Airlie /* If we pass -1, set the mode with the currently bound fb */ 2358f453ba04SDave Airlie if (crtc_req->fb_id == -1) { 2359f4510a27SMatt Roper if (!crtc->primary->fb) { 23606653cc8dSVille Syrjälä DRM_DEBUG_KMS("CRTC doesn't have current FB\n"); 23616653cc8dSVille Syrjälä ret = -EINVAL; 23626653cc8dSVille Syrjälä goto out; 23636653cc8dSVille Syrjälä } 2364f4510a27SMatt Roper fb = crtc->primary->fb; 2365b0d12325SDaniel Vetter /* Make refcounting symmetric with the lookup path. */ 2366b0d12325SDaniel Vetter drm_framebuffer_reference(fb); 2367f453ba04SDave Airlie } else { 2368786b99edSDaniel Vetter fb = drm_framebuffer_lookup(dev, crtc_req->fb_id); 2369786b99edSDaniel Vetter if (!fb) { 237058367ed6SZhao Yakui DRM_DEBUG_KMS("Unknown FB ID%d\n", 237158367ed6SZhao Yakui crtc_req->fb_id); 237237c4e705SVille Syrjälä ret = -ENOENT; 2373f453ba04SDave Airlie goto out; 2374f453ba04SDave Airlie } 2375f453ba04SDave Airlie } 2376f453ba04SDave Airlie 2377f453ba04SDave Airlie mode = drm_mode_create(dev); 2378ee34ab5bSVille Syrjälä if (!mode) { 2379ee34ab5bSVille Syrjälä ret = -ENOMEM; 2380ee34ab5bSVille Syrjälä goto out; 2381ee34ab5bSVille Syrjälä } 2382ee34ab5bSVille Syrjälä 238390367bf6SVille Syrjälä ret = drm_crtc_convert_umode(mode, &crtc_req->mode); 238490367bf6SVille Syrjälä if (ret) { 238590367bf6SVille Syrjälä DRM_DEBUG_KMS("Invalid mode\n"); 238690367bf6SVille Syrjälä goto out; 238790367bf6SVille Syrjälä } 238890367bf6SVille Syrjälä 2389f453ba04SDave Airlie drm_mode_set_crtcinfo(mode, CRTC_INTERLACE_HALVE_V); 23905f61bb42SVille Syrjälä 2391c11e9283SDamien Lespiau ret = drm_crtc_check_viewport(crtc, crtc_req->x, crtc_req->y, 2392c11e9283SDamien Lespiau mode, fb); 2393c11e9283SDamien Lespiau if (ret) 23945f61bb42SVille Syrjälä goto out; 2395c11e9283SDamien Lespiau 2396f453ba04SDave Airlie } 2397f453ba04SDave Airlie 2398f453ba04SDave Airlie if (crtc_req->count_connectors == 0 && mode) { 239958367ed6SZhao Yakui DRM_DEBUG_KMS("Count connectors is 0 but mode set\n"); 2400f453ba04SDave Airlie ret = -EINVAL; 2401f453ba04SDave Airlie goto out; 2402f453ba04SDave Airlie } 2403f453ba04SDave Airlie 24047781de74SJakob Bornecrantz if (crtc_req->count_connectors > 0 && (!mode || !fb)) { 240558367ed6SZhao Yakui DRM_DEBUG_KMS("Count connectors is %d but no mode or fb set\n", 2406f453ba04SDave Airlie crtc_req->count_connectors); 2407f453ba04SDave Airlie ret = -EINVAL; 2408f453ba04SDave Airlie goto out; 2409f453ba04SDave Airlie } 2410f453ba04SDave Airlie 2411f453ba04SDave Airlie if (crtc_req->count_connectors > 0) { 2412f453ba04SDave Airlie u32 out_id; 2413f453ba04SDave Airlie 2414f453ba04SDave Airlie /* Avoid unbounded kernel memory allocation */ 2415f453ba04SDave Airlie if (crtc_req->count_connectors > config->num_connector) { 2416f453ba04SDave Airlie ret = -EINVAL; 2417f453ba04SDave Airlie goto out; 2418f453ba04SDave Airlie } 2419f453ba04SDave Airlie 2420f453ba04SDave Airlie connector_set = kmalloc(crtc_req->count_connectors * 2421f453ba04SDave Airlie sizeof(struct drm_connector *), 2422f453ba04SDave Airlie GFP_KERNEL); 2423f453ba04SDave Airlie if (!connector_set) { 2424f453ba04SDave Airlie ret = -ENOMEM; 2425f453ba04SDave Airlie goto out; 2426f453ba04SDave Airlie } 2427f453ba04SDave Airlie 2428f453ba04SDave Airlie for (i = 0; i < crtc_req->count_connectors; i++) { 242981f6c7f8SVille Syrjälä set_connectors_ptr = (uint32_t __user *)(unsigned long)crtc_req->set_connectors_ptr; 2430f453ba04SDave Airlie if (get_user(out_id, &set_connectors_ptr[i])) { 2431f453ba04SDave Airlie ret = -EFAULT; 2432f453ba04SDave Airlie goto out; 2433f453ba04SDave Airlie } 2434f453ba04SDave Airlie 2435f453ba04SDave Airlie obj = drm_mode_object_find(dev, out_id, 2436f453ba04SDave Airlie DRM_MODE_OBJECT_CONNECTOR); 2437f453ba04SDave Airlie if (!obj) { 243858367ed6SZhao Yakui DRM_DEBUG_KMS("Connector id %d unknown\n", 243958367ed6SZhao Yakui out_id); 2440f27657f2SVille Syrjälä ret = -ENOENT; 2441f453ba04SDave Airlie goto out; 2442f453ba04SDave Airlie } 2443f453ba04SDave Airlie connector = obj_to_connector(obj); 24449440106bSJerome Glisse DRM_DEBUG_KMS("[CONNECTOR:%d:%s]\n", 24459440106bSJerome Glisse connector->base.id, 24469440106bSJerome Glisse drm_get_connector_name(connector)); 2447f453ba04SDave Airlie 2448f453ba04SDave Airlie connector_set[i] = connector; 2449f453ba04SDave Airlie } 2450f453ba04SDave Airlie } 2451f453ba04SDave Airlie 2452f453ba04SDave Airlie set.crtc = crtc; 2453f453ba04SDave Airlie set.x = crtc_req->x; 2454f453ba04SDave Airlie set.y = crtc_req->y; 2455f453ba04SDave Airlie set.mode = mode; 2456f453ba04SDave Airlie set.connectors = connector_set; 2457f453ba04SDave Airlie set.num_connectors = crtc_req->count_connectors; 2458f453ba04SDave Airlie set.fb = fb; 24592d13b679SDaniel Vetter ret = drm_mode_set_config_internal(&set); 2460f453ba04SDave Airlie 2461f453ba04SDave Airlie out: 2462b0d12325SDaniel Vetter if (fb) 2463b0d12325SDaniel Vetter drm_framebuffer_unreference(fb); 2464b0d12325SDaniel Vetter 2465f453ba04SDave Airlie kfree(connector_set); 2466ee34ab5bSVille Syrjälä drm_mode_destroy(dev, mode); 246784849903SDaniel Vetter drm_modeset_unlock_all(dev); 2468f453ba04SDave Airlie return ret; 2469f453ba04SDave Airlie } 2470f453ba04SDave Airlie 24714c813d4dSDave Airlie static int drm_mode_cursor_common(struct drm_device *dev, 24724c813d4dSDave Airlie struct drm_mode_cursor2 *req, 24734c813d4dSDave Airlie struct drm_file *file_priv) 2474f453ba04SDave Airlie { 2475f453ba04SDave Airlie struct drm_mode_object *obj; 2476f453ba04SDave Airlie struct drm_crtc *crtc; 2477f453ba04SDave Airlie int ret = 0; 2478f453ba04SDave Airlie 2479fb3b06c8SDave Airlie if (!drm_core_check_feature(dev, DRIVER_MODESET)) 2480fb3b06c8SDave Airlie return -EINVAL; 2481fb3b06c8SDave Airlie 24827c4eaca4SJakob Bornecrantz if (!req->flags || (~DRM_MODE_CURSOR_FLAGS & req->flags)) 2483f453ba04SDave Airlie return -EINVAL; 2484f453ba04SDave Airlie 2485e0c8463aSJakob Bornecrantz obj = drm_mode_object_find(dev, req->crtc_id, DRM_MODE_OBJECT_CRTC); 2486f453ba04SDave Airlie if (!obj) { 248758367ed6SZhao Yakui DRM_DEBUG_KMS("Unknown CRTC ID %d\n", req->crtc_id); 2488f27657f2SVille Syrjälä return -ENOENT; 2489f453ba04SDave Airlie } 2490f453ba04SDave Airlie crtc = obj_to_crtc(obj); 2491f453ba04SDave Airlie 2492dac35663SDaniel Vetter mutex_lock(&crtc->mutex); 2493f453ba04SDave Airlie if (req->flags & DRM_MODE_CURSOR_BO) { 24944c813d4dSDave Airlie if (!crtc->funcs->cursor_set && !crtc->funcs->cursor_set2) { 2495f453ba04SDave Airlie ret = -ENXIO; 2496f453ba04SDave Airlie goto out; 2497f453ba04SDave Airlie } 2498f453ba04SDave Airlie /* Turns off the cursor if handle is 0 */ 24994c813d4dSDave Airlie if (crtc->funcs->cursor_set2) 25004c813d4dSDave Airlie ret = crtc->funcs->cursor_set2(crtc, file_priv, req->handle, 25014c813d4dSDave Airlie req->width, req->height, req->hot_x, req->hot_y); 25024c813d4dSDave Airlie else 2503f453ba04SDave Airlie ret = crtc->funcs->cursor_set(crtc, file_priv, req->handle, 2504f453ba04SDave Airlie req->width, req->height); 2505f453ba04SDave Airlie } 2506f453ba04SDave Airlie 2507f453ba04SDave Airlie if (req->flags & DRM_MODE_CURSOR_MOVE) { 2508f453ba04SDave Airlie if (crtc->funcs->cursor_move) { 2509f453ba04SDave Airlie ret = crtc->funcs->cursor_move(crtc, req->x, req->y); 2510f453ba04SDave Airlie } else { 2511f453ba04SDave Airlie ret = -EFAULT; 2512f453ba04SDave Airlie goto out; 2513f453ba04SDave Airlie } 2514f453ba04SDave Airlie } 2515f453ba04SDave Airlie out: 2516dac35663SDaniel Vetter mutex_unlock(&crtc->mutex); 2517dac35663SDaniel Vetter 2518f453ba04SDave Airlie return ret; 25194c813d4dSDave Airlie 25204c813d4dSDave Airlie } 2521c8e32cc1SDaniel Vetter 2522c8e32cc1SDaniel Vetter 2523c8e32cc1SDaniel Vetter /** 2524c8e32cc1SDaniel Vetter * drm_mode_cursor_ioctl - set CRTC's cursor configuration 2525c8e32cc1SDaniel Vetter * @dev: drm device for the ioctl 2526c8e32cc1SDaniel Vetter * @data: data pointer for the ioctl 2527c8e32cc1SDaniel Vetter * @file_priv: drm file for the ioctl call 2528c8e32cc1SDaniel Vetter * 2529c8e32cc1SDaniel Vetter * Set the cursor configuration based on user request. 2530c8e32cc1SDaniel Vetter * 2531c8e32cc1SDaniel Vetter * Called by the user via ioctl. 2532c8e32cc1SDaniel Vetter * 2533c8e32cc1SDaniel Vetter * Returns: 2534c8e32cc1SDaniel Vetter * Zero on success, errno on failure. 2535c8e32cc1SDaniel Vetter */ 25364c813d4dSDave Airlie int drm_mode_cursor_ioctl(struct drm_device *dev, 25374c813d4dSDave Airlie void *data, struct drm_file *file_priv) 25384c813d4dSDave Airlie { 25394c813d4dSDave Airlie struct drm_mode_cursor *req = data; 25404c813d4dSDave Airlie struct drm_mode_cursor2 new_req; 25414c813d4dSDave Airlie 25424c813d4dSDave Airlie memcpy(&new_req, req, sizeof(struct drm_mode_cursor)); 25434c813d4dSDave Airlie new_req.hot_x = new_req.hot_y = 0; 25444c813d4dSDave Airlie 25454c813d4dSDave Airlie return drm_mode_cursor_common(dev, &new_req, file_priv); 25464c813d4dSDave Airlie } 25474c813d4dSDave Airlie 2548c8e32cc1SDaniel Vetter /** 2549c8e32cc1SDaniel Vetter * drm_mode_cursor2_ioctl - set CRTC's cursor configuration 2550c8e32cc1SDaniel Vetter * @dev: drm device for the ioctl 2551c8e32cc1SDaniel Vetter * @data: data pointer for the ioctl 2552c8e32cc1SDaniel Vetter * @file_priv: drm file for the ioctl call 2553c8e32cc1SDaniel Vetter * 2554c8e32cc1SDaniel Vetter * Set the cursor configuration based on user request. This implements the 2nd 2555c8e32cc1SDaniel Vetter * version of the cursor ioctl, which allows userspace to additionally specify 2556c8e32cc1SDaniel Vetter * the hotspot of the pointer. 2557c8e32cc1SDaniel Vetter * 2558c8e32cc1SDaniel Vetter * Called by the user via ioctl. 2559c8e32cc1SDaniel Vetter * 2560c8e32cc1SDaniel Vetter * Returns: 2561c8e32cc1SDaniel Vetter * Zero on success, errno on failure. 2562c8e32cc1SDaniel Vetter */ 25634c813d4dSDave Airlie int drm_mode_cursor2_ioctl(struct drm_device *dev, 25644c813d4dSDave Airlie void *data, struct drm_file *file_priv) 25654c813d4dSDave Airlie { 25664c813d4dSDave Airlie struct drm_mode_cursor2 *req = data; 25674c813d4dSDave Airlie return drm_mode_cursor_common(dev, req, file_priv); 2568f453ba04SDave Airlie } 2569f453ba04SDave Airlie 2570c8e32cc1SDaniel Vetter /** 2571c8e32cc1SDaniel Vetter * drm_mode_legacy_fb_format - compute drm fourcc code from legacy description 2572c8e32cc1SDaniel Vetter * @bpp: bits per pixels 2573c8e32cc1SDaniel Vetter * @depth: bit depth per pixel 2574c8e32cc1SDaniel Vetter * 2575c8e32cc1SDaniel Vetter * Computes a drm fourcc pixel format code for the given @bpp/@depth values. 2576c8e32cc1SDaniel Vetter * Useful in fbdev emulation code, since that deals in those values. 2577c8e32cc1SDaniel Vetter */ 2578308e5bcbSJesse Barnes uint32_t drm_mode_legacy_fb_format(uint32_t bpp, uint32_t depth) 2579308e5bcbSJesse Barnes { 2580308e5bcbSJesse Barnes uint32_t fmt; 2581308e5bcbSJesse Barnes 2582308e5bcbSJesse Barnes switch (bpp) { 2583308e5bcbSJesse Barnes case 8: 2584d84f031bSVille Syrjälä fmt = DRM_FORMAT_C8; 2585308e5bcbSJesse Barnes break; 2586308e5bcbSJesse Barnes case 16: 2587308e5bcbSJesse Barnes if (depth == 15) 258804b3924dSVille Syrjälä fmt = DRM_FORMAT_XRGB1555; 2589308e5bcbSJesse Barnes else 259004b3924dSVille Syrjälä fmt = DRM_FORMAT_RGB565; 2591308e5bcbSJesse Barnes break; 2592308e5bcbSJesse Barnes case 24: 259304b3924dSVille Syrjälä fmt = DRM_FORMAT_RGB888; 2594308e5bcbSJesse Barnes break; 2595308e5bcbSJesse Barnes case 32: 2596308e5bcbSJesse Barnes if (depth == 24) 259704b3924dSVille Syrjälä fmt = DRM_FORMAT_XRGB8888; 2598308e5bcbSJesse Barnes else if (depth == 30) 259904b3924dSVille Syrjälä fmt = DRM_FORMAT_XRGB2101010; 2600308e5bcbSJesse Barnes else 260104b3924dSVille Syrjälä fmt = DRM_FORMAT_ARGB8888; 2602308e5bcbSJesse Barnes break; 2603308e5bcbSJesse Barnes default: 260404b3924dSVille Syrjälä DRM_ERROR("bad bpp, assuming x8r8g8b8 pixel format\n"); 260504b3924dSVille Syrjälä fmt = DRM_FORMAT_XRGB8888; 2606308e5bcbSJesse Barnes break; 2607308e5bcbSJesse Barnes } 2608308e5bcbSJesse Barnes 2609308e5bcbSJesse Barnes return fmt; 2610308e5bcbSJesse Barnes } 2611308e5bcbSJesse Barnes EXPORT_SYMBOL(drm_mode_legacy_fb_format); 2612308e5bcbSJesse Barnes 2613f453ba04SDave Airlie /** 2614f453ba04SDave Airlie * drm_mode_addfb - add an FB to the graphics configuration 2615065a50edSDaniel Vetter * @dev: drm device for the ioctl 2616065a50edSDaniel Vetter * @data: data pointer for the ioctl 2617065a50edSDaniel Vetter * @file_priv: drm file for the ioctl call 2618f453ba04SDave Airlie * 2619c8e32cc1SDaniel Vetter * Add a new FB to the specified CRTC, given a user request. This is the 2620c8e32cc1SDaniel Vetter * original addfb ioclt which only supported RGB formats. 2621f453ba04SDave Airlie * 2622f453ba04SDave Airlie * Called by the user via ioctl. 2623f453ba04SDave Airlie * 2624c8e32cc1SDaniel Vetter * Returns: 2625f453ba04SDave Airlie * Zero on success, errno on failure. 2626f453ba04SDave Airlie */ 2627f453ba04SDave Airlie int drm_mode_addfb(struct drm_device *dev, 2628f453ba04SDave Airlie void *data, struct drm_file *file_priv) 2629f453ba04SDave Airlie { 2630308e5bcbSJesse Barnes struct drm_mode_fb_cmd *or = data; 2631308e5bcbSJesse Barnes struct drm_mode_fb_cmd2 r = {}; 2632308e5bcbSJesse Barnes struct drm_mode_config *config = &dev->mode_config; 2633308e5bcbSJesse Barnes struct drm_framebuffer *fb; 2634308e5bcbSJesse Barnes int ret = 0; 2635308e5bcbSJesse Barnes 2636308e5bcbSJesse Barnes /* Use new struct with format internally */ 2637308e5bcbSJesse Barnes r.fb_id = or->fb_id; 2638308e5bcbSJesse Barnes r.width = or->width; 2639308e5bcbSJesse Barnes r.height = or->height; 2640308e5bcbSJesse Barnes r.pitches[0] = or->pitch; 2641308e5bcbSJesse Barnes r.pixel_format = drm_mode_legacy_fb_format(or->bpp, or->depth); 2642308e5bcbSJesse Barnes r.handles[0] = or->handle; 2643308e5bcbSJesse Barnes 2644308e5bcbSJesse Barnes if (!drm_core_check_feature(dev, DRIVER_MODESET)) 2645308e5bcbSJesse Barnes return -EINVAL; 2646308e5bcbSJesse Barnes 2647acb4b992SJesse Barnes if ((config->min_width > r.width) || (r.width > config->max_width)) 2648308e5bcbSJesse Barnes return -EINVAL; 2649acb4b992SJesse Barnes 2650acb4b992SJesse Barnes if ((config->min_height > r.height) || (r.height > config->max_height)) 2651308e5bcbSJesse Barnes return -EINVAL; 2652308e5bcbSJesse Barnes 2653308e5bcbSJesse Barnes fb = dev->mode_config.funcs->fb_create(dev, file_priv, &r); 2654308e5bcbSJesse Barnes if (IS_ERR(fb)) { 26551aa1b11cSDave Airlie DRM_DEBUG_KMS("could not create framebuffer\n"); 26564b096ac1SDaniel Vetter return PTR_ERR(fb); 2657308e5bcbSJesse Barnes } 2658308e5bcbSJesse Barnes 26594b096ac1SDaniel Vetter mutex_lock(&file_priv->fbs_lock); 2660308e5bcbSJesse Barnes or->fb_id = fb->base.id; 2661308e5bcbSJesse Barnes list_add(&fb->filp_head, &file_priv->fbs); 2662308e5bcbSJesse Barnes DRM_DEBUG_KMS("[FB:%d]\n", fb->base.id); 26634b096ac1SDaniel Vetter mutex_unlock(&file_priv->fbs_lock); 26644b096ac1SDaniel Vetter 2665308e5bcbSJesse Barnes return ret; 2666308e5bcbSJesse Barnes } 2667308e5bcbSJesse Barnes 2668cff91b62SVille Syrjälä static int format_check(const struct drm_mode_fb_cmd2 *r) 2669935b5977SVille Syrjälä { 2670935b5977SVille Syrjälä uint32_t format = r->pixel_format & ~DRM_FORMAT_BIG_ENDIAN; 2671935b5977SVille Syrjälä 2672935b5977SVille Syrjälä switch (format) { 2673935b5977SVille Syrjälä case DRM_FORMAT_C8: 2674935b5977SVille Syrjälä case DRM_FORMAT_RGB332: 2675935b5977SVille Syrjälä case DRM_FORMAT_BGR233: 2676935b5977SVille Syrjälä case DRM_FORMAT_XRGB4444: 2677935b5977SVille Syrjälä case DRM_FORMAT_XBGR4444: 2678935b5977SVille Syrjälä case DRM_FORMAT_RGBX4444: 2679935b5977SVille Syrjälä case DRM_FORMAT_BGRX4444: 2680935b5977SVille Syrjälä case DRM_FORMAT_ARGB4444: 2681935b5977SVille Syrjälä case DRM_FORMAT_ABGR4444: 2682935b5977SVille Syrjälä case DRM_FORMAT_RGBA4444: 2683935b5977SVille Syrjälä case DRM_FORMAT_BGRA4444: 2684935b5977SVille Syrjälä case DRM_FORMAT_XRGB1555: 2685935b5977SVille Syrjälä case DRM_FORMAT_XBGR1555: 2686935b5977SVille Syrjälä case DRM_FORMAT_RGBX5551: 2687935b5977SVille Syrjälä case DRM_FORMAT_BGRX5551: 2688935b5977SVille Syrjälä case DRM_FORMAT_ARGB1555: 2689935b5977SVille Syrjälä case DRM_FORMAT_ABGR1555: 2690935b5977SVille Syrjälä case DRM_FORMAT_RGBA5551: 2691935b5977SVille Syrjälä case DRM_FORMAT_BGRA5551: 2692935b5977SVille Syrjälä case DRM_FORMAT_RGB565: 2693935b5977SVille Syrjälä case DRM_FORMAT_BGR565: 2694935b5977SVille Syrjälä case DRM_FORMAT_RGB888: 2695935b5977SVille Syrjälä case DRM_FORMAT_BGR888: 2696935b5977SVille Syrjälä case DRM_FORMAT_XRGB8888: 2697935b5977SVille Syrjälä case DRM_FORMAT_XBGR8888: 2698935b5977SVille Syrjälä case DRM_FORMAT_RGBX8888: 2699935b5977SVille Syrjälä case DRM_FORMAT_BGRX8888: 2700935b5977SVille Syrjälä case DRM_FORMAT_ARGB8888: 2701935b5977SVille Syrjälä case DRM_FORMAT_ABGR8888: 2702935b5977SVille Syrjälä case DRM_FORMAT_RGBA8888: 2703935b5977SVille Syrjälä case DRM_FORMAT_BGRA8888: 2704935b5977SVille Syrjälä case DRM_FORMAT_XRGB2101010: 2705935b5977SVille Syrjälä case DRM_FORMAT_XBGR2101010: 2706935b5977SVille Syrjälä case DRM_FORMAT_RGBX1010102: 2707935b5977SVille Syrjälä case DRM_FORMAT_BGRX1010102: 2708935b5977SVille Syrjälä case DRM_FORMAT_ARGB2101010: 2709935b5977SVille Syrjälä case DRM_FORMAT_ABGR2101010: 2710935b5977SVille Syrjälä case DRM_FORMAT_RGBA1010102: 2711935b5977SVille Syrjälä case DRM_FORMAT_BGRA1010102: 2712935b5977SVille Syrjälä case DRM_FORMAT_YUYV: 2713935b5977SVille Syrjälä case DRM_FORMAT_YVYU: 2714935b5977SVille Syrjälä case DRM_FORMAT_UYVY: 2715935b5977SVille Syrjälä case DRM_FORMAT_VYUY: 2716935b5977SVille Syrjälä case DRM_FORMAT_AYUV: 2717935b5977SVille Syrjälä case DRM_FORMAT_NV12: 2718935b5977SVille Syrjälä case DRM_FORMAT_NV21: 2719935b5977SVille Syrjälä case DRM_FORMAT_NV16: 2720935b5977SVille Syrjälä case DRM_FORMAT_NV61: 2721ba623f6aSLaurent Pinchart case DRM_FORMAT_NV24: 2722ba623f6aSLaurent Pinchart case DRM_FORMAT_NV42: 2723935b5977SVille Syrjälä case DRM_FORMAT_YUV410: 2724935b5977SVille Syrjälä case DRM_FORMAT_YVU410: 2725935b5977SVille Syrjälä case DRM_FORMAT_YUV411: 2726935b5977SVille Syrjälä case DRM_FORMAT_YVU411: 2727935b5977SVille Syrjälä case DRM_FORMAT_YUV420: 2728935b5977SVille Syrjälä case DRM_FORMAT_YVU420: 2729935b5977SVille Syrjälä case DRM_FORMAT_YUV422: 2730935b5977SVille Syrjälä case DRM_FORMAT_YVU422: 2731935b5977SVille Syrjälä case DRM_FORMAT_YUV444: 2732935b5977SVille Syrjälä case DRM_FORMAT_YVU444: 2733935b5977SVille Syrjälä return 0; 2734935b5977SVille Syrjälä default: 273523c453a4SVille Syrjälä DRM_DEBUG_KMS("invalid pixel format %s\n", 273623c453a4SVille Syrjälä drm_get_format_name(r->pixel_format)); 2737935b5977SVille Syrjälä return -EINVAL; 2738935b5977SVille Syrjälä } 2739935b5977SVille Syrjälä } 2740935b5977SVille Syrjälä 2741cff91b62SVille Syrjälä static int framebuffer_check(const struct drm_mode_fb_cmd2 *r) 2742d1b45d5fSVille Syrjälä { 2743d1b45d5fSVille Syrjälä int ret, hsub, vsub, num_planes, i; 2744d1b45d5fSVille Syrjälä 2745d1b45d5fSVille Syrjälä ret = format_check(r); 2746d1b45d5fSVille Syrjälä if (ret) { 27476ba6d03eSVille Syrjälä DRM_DEBUG_KMS("bad framebuffer format %s\n", 27486ba6d03eSVille Syrjälä drm_get_format_name(r->pixel_format)); 2749d1b45d5fSVille Syrjälä return ret; 2750d1b45d5fSVille Syrjälä } 2751d1b45d5fSVille Syrjälä 2752d1b45d5fSVille Syrjälä hsub = drm_format_horz_chroma_subsampling(r->pixel_format); 2753d1b45d5fSVille Syrjälä vsub = drm_format_vert_chroma_subsampling(r->pixel_format); 2754d1b45d5fSVille Syrjälä num_planes = drm_format_num_planes(r->pixel_format); 2755d1b45d5fSVille Syrjälä 2756d1b45d5fSVille Syrjälä if (r->width == 0 || r->width % hsub) { 27571aa1b11cSDave Airlie DRM_DEBUG_KMS("bad framebuffer width %u\n", r->height); 2758d1b45d5fSVille Syrjälä return -EINVAL; 2759d1b45d5fSVille Syrjälä } 2760d1b45d5fSVille Syrjälä 2761d1b45d5fSVille Syrjälä if (r->height == 0 || r->height % vsub) { 27621aa1b11cSDave Airlie DRM_DEBUG_KMS("bad framebuffer height %u\n", r->height); 2763d1b45d5fSVille Syrjälä return -EINVAL; 2764d1b45d5fSVille Syrjälä } 2765d1b45d5fSVille Syrjälä 2766d1b45d5fSVille Syrjälä for (i = 0; i < num_planes; i++) { 2767d1b45d5fSVille Syrjälä unsigned int width = r->width / (i != 0 ? hsub : 1); 2768b180b5d1SVille Syrjälä unsigned int height = r->height / (i != 0 ? vsub : 1); 2769b180b5d1SVille Syrjälä unsigned int cpp = drm_format_plane_cpp(r->pixel_format, i); 2770d1b45d5fSVille Syrjälä 2771d1b45d5fSVille Syrjälä if (!r->handles[i]) { 27721aa1b11cSDave Airlie DRM_DEBUG_KMS("no buffer object handle for plane %d\n", i); 2773d1b45d5fSVille Syrjälä return -EINVAL; 2774d1b45d5fSVille Syrjälä } 2775d1b45d5fSVille Syrjälä 2776b180b5d1SVille Syrjälä if ((uint64_t) width * cpp > UINT_MAX) 2777b180b5d1SVille Syrjälä return -ERANGE; 2778b180b5d1SVille Syrjälä 2779b180b5d1SVille Syrjälä if ((uint64_t) height * r->pitches[i] + r->offsets[i] > UINT_MAX) 2780b180b5d1SVille Syrjälä return -ERANGE; 2781b180b5d1SVille Syrjälä 2782b180b5d1SVille Syrjälä if (r->pitches[i] < width * cpp) { 27831aa1b11cSDave Airlie DRM_DEBUG_KMS("bad pitch %u for plane %d\n", r->pitches[i], i); 2784d1b45d5fSVille Syrjälä return -EINVAL; 2785d1b45d5fSVille Syrjälä } 2786d1b45d5fSVille Syrjälä } 2787d1b45d5fSVille Syrjälä 2788d1b45d5fSVille Syrjälä return 0; 2789d1b45d5fSVille Syrjälä } 2790d1b45d5fSVille Syrjälä 2791308e5bcbSJesse Barnes /** 2792308e5bcbSJesse Barnes * drm_mode_addfb2 - add an FB to the graphics configuration 2793065a50edSDaniel Vetter * @dev: drm device for the ioctl 2794065a50edSDaniel Vetter * @data: data pointer for the ioctl 2795065a50edSDaniel Vetter * @file_priv: drm file for the ioctl call 2796308e5bcbSJesse Barnes * 2797c8e32cc1SDaniel Vetter * Add a new FB to the specified CRTC, given a user request with format. This is 2798c8e32cc1SDaniel Vetter * the 2nd version of the addfb ioctl, which supports multi-planar framebuffers 2799c8e32cc1SDaniel Vetter * and uses fourcc codes as pixel format specifiers. 2800308e5bcbSJesse Barnes * 2801308e5bcbSJesse Barnes * Called by the user via ioctl. 2802308e5bcbSJesse Barnes * 2803c8e32cc1SDaniel Vetter * Returns: 2804308e5bcbSJesse Barnes * Zero on success, errno on failure. 2805308e5bcbSJesse Barnes */ 2806308e5bcbSJesse Barnes int drm_mode_addfb2(struct drm_device *dev, 2807308e5bcbSJesse Barnes void *data, struct drm_file *file_priv) 2808308e5bcbSJesse Barnes { 2809308e5bcbSJesse Barnes struct drm_mode_fb_cmd2 *r = data; 2810f453ba04SDave Airlie struct drm_mode_config *config = &dev->mode_config; 2811f453ba04SDave Airlie struct drm_framebuffer *fb; 28124a1b0714SLaurent Pinchart int ret; 2813f453ba04SDave Airlie 2814fb3b06c8SDave Airlie if (!drm_core_check_feature(dev, DRIVER_MODESET)) 2815fb3b06c8SDave Airlie return -EINVAL; 2816fb3b06c8SDave Airlie 2817e3cc3520SVille Syrjälä if (r->flags & ~DRM_MODE_FB_INTERLACED) { 2818e3cc3520SVille Syrjälä DRM_DEBUG_KMS("bad framebuffer flags 0x%08x\n", r->flags); 2819e3cc3520SVille Syrjälä return -EINVAL; 2820e3cc3520SVille Syrjälä } 2821e3cc3520SVille Syrjälä 2822f453ba04SDave Airlie if ((config->min_width > r->width) || (r->width > config->max_width)) { 28231aa1b11cSDave Airlie DRM_DEBUG_KMS("bad framebuffer width %d, should be >= %d && <= %d\n", 28248cf5c917SJesse Barnes r->width, config->min_width, config->max_width); 2825f453ba04SDave Airlie return -EINVAL; 2826f453ba04SDave Airlie } 2827f453ba04SDave Airlie if ((config->min_height > r->height) || (r->height > config->max_height)) { 28281aa1b11cSDave Airlie DRM_DEBUG_KMS("bad framebuffer height %d, should be >= %d && <= %d\n", 28298cf5c917SJesse Barnes r->height, config->min_height, config->max_height); 2830f453ba04SDave Airlie return -EINVAL; 2831f453ba04SDave Airlie } 2832f453ba04SDave Airlie 2833d1b45d5fSVille Syrjälä ret = framebuffer_check(r); 2834d1b45d5fSVille Syrjälä if (ret) 2835935b5977SVille Syrjälä return ret; 2836935b5977SVille Syrjälä 2837f453ba04SDave Airlie fb = dev->mode_config.funcs->fb_create(dev, file_priv, r); 2838cce13ff7SChris Wilson if (IS_ERR(fb)) { 28391aa1b11cSDave Airlie DRM_DEBUG_KMS("could not create framebuffer\n"); 28404b096ac1SDaniel Vetter return PTR_ERR(fb); 2841f453ba04SDave Airlie } 2842f453ba04SDave Airlie 28434b096ac1SDaniel Vetter mutex_lock(&file_priv->fbs_lock); 2844e0c8463aSJakob Bornecrantz r->fb_id = fb->base.id; 2845f453ba04SDave Airlie list_add(&fb->filp_head, &file_priv->fbs); 28469440106bSJerome Glisse DRM_DEBUG_KMS("[FB:%d]\n", fb->base.id); 28474b096ac1SDaniel Vetter mutex_unlock(&file_priv->fbs_lock); 2848f453ba04SDave Airlie 28494b096ac1SDaniel Vetter 2850f453ba04SDave Airlie return ret; 2851f453ba04SDave Airlie } 2852f453ba04SDave Airlie 2853f453ba04SDave Airlie /** 2854f453ba04SDave Airlie * drm_mode_rmfb - remove an FB from the configuration 2855065a50edSDaniel Vetter * @dev: drm device for the ioctl 2856065a50edSDaniel Vetter * @data: data pointer for the ioctl 2857065a50edSDaniel Vetter * @file_priv: drm file for the ioctl call 2858f453ba04SDave Airlie * 2859f453ba04SDave Airlie * Remove the FB specified by the user. 2860f453ba04SDave Airlie * 2861f453ba04SDave Airlie * Called by the user via ioctl. 2862f453ba04SDave Airlie * 2863c8e32cc1SDaniel Vetter * Returns: 2864f453ba04SDave Airlie * Zero on success, errno on failure. 2865f453ba04SDave Airlie */ 2866f453ba04SDave Airlie int drm_mode_rmfb(struct drm_device *dev, 2867f453ba04SDave Airlie void *data, struct drm_file *file_priv) 2868f453ba04SDave Airlie { 2869f453ba04SDave Airlie struct drm_framebuffer *fb = NULL; 2870f453ba04SDave Airlie struct drm_framebuffer *fbl = NULL; 2871f453ba04SDave Airlie uint32_t *id = data; 2872f453ba04SDave Airlie int found = 0; 2873f453ba04SDave Airlie 2874fb3b06c8SDave Airlie if (!drm_core_check_feature(dev, DRIVER_MODESET)) 2875fb3b06c8SDave Airlie return -EINVAL; 2876fb3b06c8SDave Airlie 28774b096ac1SDaniel Vetter mutex_lock(&file_priv->fbs_lock); 28782b677e8cSDaniel Vetter mutex_lock(&dev->mode_config.fb_lock); 28792b677e8cSDaniel Vetter fb = __drm_framebuffer_lookup(dev, *id); 28802b677e8cSDaniel Vetter if (!fb) 28812b677e8cSDaniel Vetter goto fail_lookup; 28822b677e8cSDaniel Vetter 2883f453ba04SDave Airlie list_for_each_entry(fbl, &file_priv->fbs, filp_head) 2884f453ba04SDave Airlie if (fb == fbl) 2885f453ba04SDave Airlie found = 1; 28862b677e8cSDaniel Vetter if (!found) 28872b677e8cSDaniel Vetter goto fail_lookup; 28882b677e8cSDaniel Vetter 28892b677e8cSDaniel Vetter /* Mark fb as reaped, we still have a ref from fpriv->fbs. */ 28902b677e8cSDaniel Vetter __drm_framebuffer_unregister(dev, fb); 2891f453ba04SDave Airlie 28924b096ac1SDaniel Vetter list_del_init(&fb->filp_head); 28932b677e8cSDaniel Vetter mutex_unlock(&dev->mode_config.fb_lock); 28944b096ac1SDaniel Vetter mutex_unlock(&file_priv->fbs_lock); 2895f453ba04SDave Airlie 28964b096ac1SDaniel Vetter drm_framebuffer_remove(fb); 28974b096ac1SDaniel Vetter 28982b677e8cSDaniel Vetter return 0; 28992b677e8cSDaniel Vetter 29002b677e8cSDaniel Vetter fail_lookup: 29012b677e8cSDaniel Vetter mutex_unlock(&dev->mode_config.fb_lock); 29022b677e8cSDaniel Vetter mutex_unlock(&file_priv->fbs_lock); 29032b677e8cSDaniel Vetter 290437c4e705SVille Syrjälä return -ENOENT; 2905f453ba04SDave Airlie } 2906f453ba04SDave Airlie 2907f453ba04SDave Airlie /** 2908f453ba04SDave Airlie * drm_mode_getfb - get FB info 2909065a50edSDaniel Vetter * @dev: drm device for the ioctl 2910065a50edSDaniel Vetter * @data: data pointer for the ioctl 2911065a50edSDaniel Vetter * @file_priv: drm file for the ioctl call 2912f453ba04SDave Airlie * 2913f453ba04SDave Airlie * Lookup the FB given its ID and return info about it. 2914f453ba04SDave Airlie * 2915f453ba04SDave Airlie * Called by the user via ioctl. 2916f453ba04SDave Airlie * 2917c8e32cc1SDaniel Vetter * Returns: 2918f453ba04SDave Airlie * Zero on success, errno on failure. 2919f453ba04SDave Airlie */ 2920f453ba04SDave Airlie int drm_mode_getfb(struct drm_device *dev, 2921f453ba04SDave Airlie void *data, struct drm_file *file_priv) 2922f453ba04SDave Airlie { 2923f453ba04SDave Airlie struct drm_mode_fb_cmd *r = data; 2924f453ba04SDave Airlie struct drm_framebuffer *fb; 292558c0dca1SDaniel Vetter int ret; 2926f453ba04SDave Airlie 2927fb3b06c8SDave Airlie if (!drm_core_check_feature(dev, DRIVER_MODESET)) 2928fb3b06c8SDave Airlie return -EINVAL; 2929fb3b06c8SDave Airlie 2930786b99edSDaniel Vetter fb = drm_framebuffer_lookup(dev, r->fb_id); 293158c0dca1SDaniel Vetter if (!fb) 293237c4e705SVille Syrjälä return -ENOENT; 2933f453ba04SDave Airlie 2934f453ba04SDave Airlie r->height = fb->height; 2935f453ba04SDave Airlie r->width = fb->width; 2936f453ba04SDave Airlie r->depth = fb->depth; 2937f453ba04SDave Airlie r->bpp = fb->bits_per_pixel; 293801f2c773SVille Syrjälä r->pitch = fb->pitches[0]; 2939101b96f3SDavid Herrmann if (fb->funcs->create_handle) { 294009f308f7SThomas Hellstrom if (file_priv->is_master || capable(CAP_SYS_ADMIN) || 294143683057SThomas Hellstrom drm_is_control_client(file_priv)) { 2942101b96f3SDavid Herrmann ret = fb->funcs->create_handle(fb, file_priv, 2943101b96f3SDavid Herrmann &r->handle); 2944101b96f3SDavid Herrmann } else { 2945101b96f3SDavid Herrmann /* GET_FB() is an unprivileged ioctl so we must not 2946101b96f3SDavid Herrmann * return a buffer-handle to non-master processes! For 2947101b96f3SDavid Herrmann * backwards-compatibility reasons, we cannot make 2948101b96f3SDavid Herrmann * GET_FB() privileged, so just return an invalid handle 2949101b96f3SDavid Herrmann * for non-masters. */ 2950101b96f3SDavid Herrmann r->handle = 0; 2951101b96f3SDavid Herrmann ret = 0; 2952101b96f3SDavid Herrmann } 2953101b96f3SDavid Herrmann } else { 2954af26ef3bSDaniel Vetter ret = -ENODEV; 2955101b96f3SDavid Herrmann } 2956f453ba04SDave Airlie 295758c0dca1SDaniel Vetter drm_framebuffer_unreference(fb); 295858c0dca1SDaniel Vetter 2959f453ba04SDave Airlie return ret; 2960f453ba04SDave Airlie } 2961f453ba04SDave Airlie 2962c8e32cc1SDaniel Vetter /** 2963c8e32cc1SDaniel Vetter * drm_mode_dirtyfb_ioctl - flush frontbuffer rendering on an FB 2964c8e32cc1SDaniel Vetter * @dev: drm device for the ioctl 2965c8e32cc1SDaniel Vetter * @data: data pointer for the ioctl 2966c8e32cc1SDaniel Vetter * @file_priv: drm file for the ioctl call 2967c8e32cc1SDaniel Vetter * 2968c8e32cc1SDaniel Vetter * Lookup the FB and flush out the damaged area supplied by userspace as a clip 2969c8e32cc1SDaniel Vetter * rectangle list. Generic userspace which does frontbuffer rendering must call 2970c8e32cc1SDaniel Vetter * this ioctl to flush out the changes on manual-update display outputs, e.g. 2971c8e32cc1SDaniel Vetter * usb display-link, mipi manual update panels or edp panel self refresh modes. 2972c8e32cc1SDaniel Vetter * 2973c8e32cc1SDaniel Vetter * Modesetting drivers which always update the frontbuffer do not need to 2974c8e32cc1SDaniel Vetter * implement the corresponding ->dirty framebuffer callback. 2975c8e32cc1SDaniel Vetter * 2976c8e32cc1SDaniel Vetter * Called by the user via ioctl. 2977c8e32cc1SDaniel Vetter * 2978c8e32cc1SDaniel Vetter * Returns: 2979c8e32cc1SDaniel Vetter * Zero on success, errno on failure. 2980c8e32cc1SDaniel Vetter */ 2981884840aaSJakob Bornecrantz int drm_mode_dirtyfb_ioctl(struct drm_device *dev, 2982884840aaSJakob Bornecrantz void *data, struct drm_file *file_priv) 2983884840aaSJakob Bornecrantz { 2984884840aaSJakob Bornecrantz struct drm_clip_rect __user *clips_ptr; 2985884840aaSJakob Bornecrantz struct drm_clip_rect *clips = NULL; 2986884840aaSJakob Bornecrantz struct drm_mode_fb_dirty_cmd *r = data; 2987884840aaSJakob Bornecrantz struct drm_framebuffer *fb; 2988884840aaSJakob Bornecrantz unsigned flags; 2989884840aaSJakob Bornecrantz int num_clips; 29904a1b0714SLaurent Pinchart int ret; 2991884840aaSJakob Bornecrantz 2992fb3b06c8SDave Airlie if (!drm_core_check_feature(dev, DRIVER_MODESET)) 2993fb3b06c8SDave Airlie return -EINVAL; 2994fb3b06c8SDave Airlie 2995786b99edSDaniel Vetter fb = drm_framebuffer_lookup(dev, r->fb_id); 29964ccf097fSDaniel Vetter if (!fb) 299737c4e705SVille Syrjälä return -ENOENT; 2998884840aaSJakob Bornecrantz 2999884840aaSJakob Bornecrantz num_clips = r->num_clips; 300081f6c7f8SVille Syrjälä clips_ptr = (struct drm_clip_rect __user *)(unsigned long)r->clips_ptr; 3001884840aaSJakob Bornecrantz 3002884840aaSJakob Bornecrantz if (!num_clips != !clips_ptr) { 3003884840aaSJakob Bornecrantz ret = -EINVAL; 3004884840aaSJakob Bornecrantz goto out_err1; 3005884840aaSJakob Bornecrantz } 3006884840aaSJakob Bornecrantz 3007884840aaSJakob Bornecrantz flags = DRM_MODE_FB_DIRTY_FLAGS & r->flags; 3008884840aaSJakob Bornecrantz 3009884840aaSJakob Bornecrantz /* If userspace annotates copy, clips must come in pairs */ 3010884840aaSJakob Bornecrantz if (flags & DRM_MODE_FB_DIRTY_ANNOTATE_COPY && (num_clips % 2)) { 3011884840aaSJakob Bornecrantz ret = -EINVAL; 3012884840aaSJakob Bornecrantz goto out_err1; 3013884840aaSJakob Bornecrantz } 3014884840aaSJakob Bornecrantz 3015884840aaSJakob Bornecrantz if (num_clips && clips_ptr) { 3016a5cd3351SXi Wang if (num_clips < 0 || num_clips > DRM_MODE_FB_DIRTY_MAX_CLIPS) { 3017a5cd3351SXi Wang ret = -EINVAL; 3018a5cd3351SXi Wang goto out_err1; 3019a5cd3351SXi Wang } 3020884840aaSJakob Bornecrantz clips = kzalloc(num_clips * sizeof(*clips), GFP_KERNEL); 3021884840aaSJakob Bornecrantz if (!clips) { 3022884840aaSJakob Bornecrantz ret = -ENOMEM; 3023884840aaSJakob Bornecrantz goto out_err1; 3024884840aaSJakob Bornecrantz } 3025884840aaSJakob Bornecrantz 3026884840aaSJakob Bornecrantz ret = copy_from_user(clips, clips_ptr, 3027884840aaSJakob Bornecrantz num_clips * sizeof(*clips)); 3028e902a358SDan Carpenter if (ret) { 3029e902a358SDan Carpenter ret = -EFAULT; 3030884840aaSJakob Bornecrantz goto out_err2; 3031884840aaSJakob Bornecrantz } 3032e902a358SDan Carpenter } 3033884840aaSJakob Bornecrantz 3034884840aaSJakob Bornecrantz if (fb->funcs->dirty) { 303502b00162SThomas Hellstrom ret = fb->funcs->dirty(fb, file_priv, flags, r->color, 303602b00162SThomas Hellstrom clips, num_clips); 3037884840aaSJakob Bornecrantz } else { 3038884840aaSJakob Bornecrantz ret = -ENOSYS; 3039884840aaSJakob Bornecrantz } 3040884840aaSJakob Bornecrantz 3041884840aaSJakob Bornecrantz out_err2: 3042884840aaSJakob Bornecrantz kfree(clips); 3043884840aaSJakob Bornecrantz out_err1: 30444ccf097fSDaniel Vetter drm_framebuffer_unreference(fb); 30454ccf097fSDaniel Vetter 3046884840aaSJakob Bornecrantz return ret; 3047884840aaSJakob Bornecrantz } 3048884840aaSJakob Bornecrantz 3049884840aaSJakob Bornecrantz 3050f453ba04SDave Airlie /** 3051f453ba04SDave Airlie * drm_fb_release - remove and free the FBs on this file 3052065a50edSDaniel Vetter * @priv: drm file for the ioctl 3053f453ba04SDave Airlie * 3054f453ba04SDave Airlie * Destroy all the FBs associated with @filp. 3055f453ba04SDave Airlie * 3056f453ba04SDave Airlie * Called by the user via ioctl. 3057f453ba04SDave Airlie * 3058c8e32cc1SDaniel Vetter * Returns: 3059f453ba04SDave Airlie * Zero on success, errno on failure. 3060f453ba04SDave Airlie */ 3061ea39f835SKristian Høgsberg void drm_fb_release(struct drm_file *priv) 3062f453ba04SDave Airlie { 3063f453ba04SDave Airlie struct drm_device *dev = priv->minor->dev; 3064f453ba04SDave Airlie struct drm_framebuffer *fb, *tfb; 3065f453ba04SDave Airlie 30664b096ac1SDaniel Vetter mutex_lock(&priv->fbs_lock); 3067f453ba04SDave Airlie list_for_each_entry_safe(fb, tfb, &priv->fbs, filp_head) { 30682b677e8cSDaniel Vetter 30692b677e8cSDaniel Vetter mutex_lock(&dev->mode_config.fb_lock); 30702b677e8cSDaniel Vetter /* Mark fb as reaped, we still have a ref from fpriv->fbs. */ 30712b677e8cSDaniel Vetter __drm_framebuffer_unregister(dev, fb); 30722b677e8cSDaniel Vetter mutex_unlock(&dev->mode_config.fb_lock); 30732b677e8cSDaniel Vetter 30744b096ac1SDaniel Vetter list_del_init(&fb->filp_head); 30752b677e8cSDaniel Vetter 30762b677e8cSDaniel Vetter /* This will also drop the fpriv->fbs reference. */ 3077f7eff60eSRob Clark drm_framebuffer_remove(fb); 3078f453ba04SDave Airlie } 30794b096ac1SDaniel Vetter mutex_unlock(&priv->fbs_lock); 3080f453ba04SDave Airlie } 3081f453ba04SDave Airlie 3082c8e32cc1SDaniel Vetter /** 3083c8e32cc1SDaniel Vetter * drm_property_create - create a new property type 3084c8e32cc1SDaniel Vetter * @dev: drm device 3085c8e32cc1SDaniel Vetter * @flags: flags specifying the property type 3086c8e32cc1SDaniel Vetter * @name: name of the property 3087c8e32cc1SDaniel Vetter * @num_values: number of pre-defined values 3088c8e32cc1SDaniel Vetter * 3089c8e32cc1SDaniel Vetter * This creates a new generic drm property which can then be attached to a drm 3090c8e32cc1SDaniel Vetter * object with drm_object_attach_property. The returned property object must be 3091c8e32cc1SDaniel Vetter * freed with drm_property_destroy. 3092c8e32cc1SDaniel Vetter * 3093c8e32cc1SDaniel Vetter * Returns: 3094c8e32cc1SDaniel Vetter * A pointer to the newly created property on success, NULL on failure. 3095c8e32cc1SDaniel Vetter */ 3096f453ba04SDave Airlie struct drm_property *drm_property_create(struct drm_device *dev, int flags, 3097f453ba04SDave Airlie const char *name, int num_values) 3098f453ba04SDave Airlie { 3099f453ba04SDave Airlie struct drm_property *property = NULL; 31006bfc56aaSVille Syrjälä int ret; 3101f453ba04SDave Airlie 3102f453ba04SDave Airlie property = kzalloc(sizeof(struct drm_property), GFP_KERNEL); 3103f453ba04SDave Airlie if (!property) 3104f453ba04SDave Airlie return NULL; 3105f453ba04SDave Airlie 3106f453ba04SDave Airlie if (num_values) { 3107f453ba04SDave Airlie property->values = kzalloc(sizeof(uint64_t)*num_values, GFP_KERNEL); 3108f453ba04SDave Airlie if (!property->values) 3109f453ba04SDave Airlie goto fail; 3110f453ba04SDave Airlie } 3111f453ba04SDave Airlie 31126bfc56aaSVille Syrjälä ret = drm_mode_object_get(dev, &property->base, DRM_MODE_OBJECT_PROPERTY); 31136bfc56aaSVille Syrjälä if (ret) 31146bfc56aaSVille Syrjälä goto fail; 31156bfc56aaSVille Syrjälä 3116f453ba04SDave Airlie property->flags = flags; 3117f453ba04SDave Airlie property->num_values = num_values; 3118f453ba04SDave Airlie INIT_LIST_HEAD(&property->enum_blob_list); 3119f453ba04SDave Airlie 3120471dd2efSVinson Lee if (name) { 3121f453ba04SDave Airlie strncpy(property->name, name, DRM_PROP_NAME_LEN); 3122471dd2efSVinson Lee property->name[DRM_PROP_NAME_LEN-1] = '\0'; 3123471dd2efSVinson Lee } 3124f453ba04SDave Airlie 3125f453ba04SDave Airlie list_add_tail(&property->head, &dev->mode_config.property_list); 3126f453ba04SDave Airlie return property; 3127f453ba04SDave Airlie fail: 31286bfc56aaSVille Syrjälä kfree(property->values); 3129f453ba04SDave Airlie kfree(property); 3130f453ba04SDave Airlie return NULL; 3131f453ba04SDave Airlie } 3132f453ba04SDave Airlie EXPORT_SYMBOL(drm_property_create); 3133f453ba04SDave Airlie 3134c8e32cc1SDaniel Vetter /** 3135c8e32cc1SDaniel Vetter * drm_property_create - create a new enumeration property type 3136c8e32cc1SDaniel Vetter * @dev: drm device 3137c8e32cc1SDaniel Vetter * @flags: flags specifying the property type 3138c8e32cc1SDaniel Vetter * @name: name of the property 3139c8e32cc1SDaniel Vetter * @props: enumeration lists with property values 3140c8e32cc1SDaniel Vetter * @num_values: number of pre-defined values 3141c8e32cc1SDaniel Vetter * 3142c8e32cc1SDaniel Vetter * This creates a new generic drm property which can then be attached to a drm 3143c8e32cc1SDaniel Vetter * object with drm_object_attach_property. The returned property object must be 3144c8e32cc1SDaniel Vetter * freed with drm_property_destroy. 3145c8e32cc1SDaniel Vetter * 3146c8e32cc1SDaniel Vetter * Userspace is only allowed to set one of the predefined values for enumeration 3147c8e32cc1SDaniel Vetter * properties. 3148c8e32cc1SDaniel Vetter * 3149c8e32cc1SDaniel Vetter * Returns: 3150c8e32cc1SDaniel Vetter * A pointer to the newly created property on success, NULL on failure. 3151c8e32cc1SDaniel Vetter */ 31524a67d391SSascha Hauer struct drm_property *drm_property_create_enum(struct drm_device *dev, int flags, 31534a67d391SSascha Hauer const char *name, 31544a67d391SSascha Hauer const struct drm_prop_enum_list *props, 31554a67d391SSascha Hauer int num_values) 31564a67d391SSascha Hauer { 31574a67d391SSascha Hauer struct drm_property *property; 31584a67d391SSascha Hauer int i, ret; 31594a67d391SSascha Hauer 31604a67d391SSascha Hauer flags |= DRM_MODE_PROP_ENUM; 31614a67d391SSascha Hauer 31624a67d391SSascha Hauer property = drm_property_create(dev, flags, name, num_values); 31634a67d391SSascha Hauer if (!property) 31644a67d391SSascha Hauer return NULL; 31654a67d391SSascha Hauer 31664a67d391SSascha Hauer for (i = 0; i < num_values; i++) { 31674a67d391SSascha Hauer ret = drm_property_add_enum(property, i, 31684a67d391SSascha Hauer props[i].type, 31694a67d391SSascha Hauer props[i].name); 31704a67d391SSascha Hauer if (ret) { 31714a67d391SSascha Hauer drm_property_destroy(dev, property); 31724a67d391SSascha Hauer return NULL; 31734a67d391SSascha Hauer } 31744a67d391SSascha Hauer } 31754a67d391SSascha Hauer 31764a67d391SSascha Hauer return property; 31774a67d391SSascha Hauer } 31784a67d391SSascha Hauer EXPORT_SYMBOL(drm_property_create_enum); 31794a67d391SSascha Hauer 3180c8e32cc1SDaniel Vetter /** 3181c8e32cc1SDaniel Vetter * drm_property_create - create a new bitmask property type 3182c8e32cc1SDaniel Vetter * @dev: drm device 3183c8e32cc1SDaniel Vetter * @flags: flags specifying the property type 3184c8e32cc1SDaniel Vetter * @name: name of the property 3185c8e32cc1SDaniel Vetter * @props: enumeration lists with property bitflags 3186c8e32cc1SDaniel Vetter * @num_values: number of pre-defined values 3187c8e32cc1SDaniel Vetter * 3188c8e32cc1SDaniel Vetter * This creates a new generic drm property which can then be attached to a drm 3189c8e32cc1SDaniel Vetter * object with drm_object_attach_property. The returned property object must be 3190c8e32cc1SDaniel Vetter * freed with drm_property_destroy. 3191c8e32cc1SDaniel Vetter * 3192c8e32cc1SDaniel Vetter * Compared to plain enumeration properties userspace is allowed to set any 3193c8e32cc1SDaniel Vetter * or'ed together combination of the predefined property bitflag values 3194c8e32cc1SDaniel Vetter * 3195c8e32cc1SDaniel Vetter * Returns: 3196c8e32cc1SDaniel Vetter * A pointer to the newly created property on success, NULL on failure. 3197c8e32cc1SDaniel Vetter */ 319849e27545SRob Clark struct drm_property *drm_property_create_bitmask(struct drm_device *dev, 319949e27545SRob Clark int flags, const char *name, 320049e27545SRob Clark const struct drm_prop_enum_list *props, 320149e27545SRob Clark int num_values) 320249e27545SRob Clark { 320349e27545SRob Clark struct drm_property *property; 320449e27545SRob Clark int i, ret; 320549e27545SRob Clark 320649e27545SRob Clark flags |= DRM_MODE_PROP_BITMASK; 320749e27545SRob Clark 320849e27545SRob Clark property = drm_property_create(dev, flags, name, num_values); 320949e27545SRob Clark if (!property) 321049e27545SRob Clark return NULL; 321149e27545SRob Clark 321249e27545SRob Clark for (i = 0; i < num_values; i++) { 321349e27545SRob Clark ret = drm_property_add_enum(property, i, 321449e27545SRob Clark props[i].type, 321549e27545SRob Clark props[i].name); 321649e27545SRob Clark if (ret) { 321749e27545SRob Clark drm_property_destroy(dev, property); 321849e27545SRob Clark return NULL; 321949e27545SRob Clark } 322049e27545SRob Clark } 322149e27545SRob Clark 322249e27545SRob Clark return property; 322349e27545SRob Clark } 322449e27545SRob Clark EXPORT_SYMBOL(drm_property_create_bitmask); 322549e27545SRob Clark 3226c8e32cc1SDaniel Vetter /** 3227c8e32cc1SDaniel Vetter * drm_property_create - create a new ranged property type 3228c8e32cc1SDaniel Vetter * @dev: drm device 3229c8e32cc1SDaniel Vetter * @flags: flags specifying the property type 3230c8e32cc1SDaniel Vetter * @name: name of the property 3231c8e32cc1SDaniel Vetter * @min: minimum value of the property 3232c8e32cc1SDaniel Vetter * @max: maximum value of the property 3233c8e32cc1SDaniel Vetter * 3234c8e32cc1SDaniel Vetter * This creates a new generic drm property which can then be attached to a drm 3235c8e32cc1SDaniel Vetter * object with drm_object_attach_property. The returned property object must be 3236c8e32cc1SDaniel Vetter * freed with drm_property_destroy. 3237c8e32cc1SDaniel Vetter * 3238c8e32cc1SDaniel Vetter * Userspace is allowed to set any interger value in the (min, max) range 3239c8e32cc1SDaniel Vetter * inclusive. 3240c8e32cc1SDaniel Vetter * 3241c8e32cc1SDaniel Vetter * Returns: 3242c8e32cc1SDaniel Vetter * A pointer to the newly created property on success, NULL on failure. 3243c8e32cc1SDaniel Vetter */ 3244d9bc3c02SSascha Hauer struct drm_property *drm_property_create_range(struct drm_device *dev, int flags, 3245d9bc3c02SSascha Hauer const char *name, 3246d9bc3c02SSascha Hauer uint64_t min, uint64_t max) 3247d9bc3c02SSascha Hauer { 3248d9bc3c02SSascha Hauer struct drm_property *property; 3249d9bc3c02SSascha Hauer 3250d9bc3c02SSascha Hauer flags |= DRM_MODE_PROP_RANGE; 3251d9bc3c02SSascha Hauer 3252d9bc3c02SSascha Hauer property = drm_property_create(dev, flags, name, 2); 3253d9bc3c02SSascha Hauer if (!property) 3254d9bc3c02SSascha Hauer return NULL; 3255d9bc3c02SSascha Hauer 3256d9bc3c02SSascha Hauer property->values[0] = min; 3257d9bc3c02SSascha Hauer property->values[1] = max; 3258d9bc3c02SSascha Hauer 3259d9bc3c02SSascha Hauer return property; 3260d9bc3c02SSascha Hauer } 3261d9bc3c02SSascha Hauer EXPORT_SYMBOL(drm_property_create_range); 3262d9bc3c02SSascha Hauer 3263c8e32cc1SDaniel Vetter /** 3264c8e32cc1SDaniel Vetter * drm_property_add_enum - add a possible value to an enumeration property 3265c8e32cc1SDaniel Vetter * @property: enumeration property to change 3266c8e32cc1SDaniel Vetter * @index: index of the new enumeration 3267c8e32cc1SDaniel Vetter * @value: value of the new enumeration 3268c8e32cc1SDaniel Vetter * @name: symbolic name of the new enumeration 3269c8e32cc1SDaniel Vetter * 3270c8e32cc1SDaniel Vetter * This functions adds enumerations to a property. 3271c8e32cc1SDaniel Vetter * 3272c8e32cc1SDaniel Vetter * It's use is deprecated, drivers should use one of the more specific helpers 3273c8e32cc1SDaniel Vetter * to directly create the property with all enumerations already attached. 3274c8e32cc1SDaniel Vetter * 3275c8e32cc1SDaniel Vetter * Returns: 3276c8e32cc1SDaniel Vetter * Zero on success, error code on failure. 3277c8e32cc1SDaniel Vetter */ 3278f453ba04SDave Airlie int drm_property_add_enum(struct drm_property *property, int index, 3279f453ba04SDave Airlie uint64_t value, const char *name) 3280f453ba04SDave Airlie { 3281f453ba04SDave Airlie struct drm_property_enum *prop_enum; 3282f453ba04SDave Airlie 328349e27545SRob Clark if (!(property->flags & (DRM_MODE_PROP_ENUM | DRM_MODE_PROP_BITMASK))) 328449e27545SRob Clark return -EINVAL; 328549e27545SRob Clark 328649e27545SRob Clark /* 328749e27545SRob Clark * Bitmask enum properties have the additional constraint of values 328849e27545SRob Clark * from 0 to 63 328949e27545SRob Clark */ 329049e27545SRob Clark if ((property->flags & DRM_MODE_PROP_BITMASK) && (value > 63)) 3291f453ba04SDave Airlie return -EINVAL; 3292f453ba04SDave Airlie 3293f453ba04SDave Airlie if (!list_empty(&property->enum_blob_list)) { 3294f453ba04SDave Airlie list_for_each_entry(prop_enum, &property->enum_blob_list, head) { 3295f453ba04SDave Airlie if (prop_enum->value == value) { 3296f453ba04SDave Airlie strncpy(prop_enum->name, name, DRM_PROP_NAME_LEN); 3297f453ba04SDave Airlie prop_enum->name[DRM_PROP_NAME_LEN-1] = '\0'; 3298f453ba04SDave Airlie return 0; 3299f453ba04SDave Airlie } 3300f453ba04SDave Airlie } 3301f453ba04SDave Airlie } 3302f453ba04SDave Airlie 3303f453ba04SDave Airlie prop_enum = kzalloc(sizeof(struct drm_property_enum), GFP_KERNEL); 3304f453ba04SDave Airlie if (!prop_enum) 3305f453ba04SDave Airlie return -ENOMEM; 3306f453ba04SDave Airlie 3307f453ba04SDave Airlie strncpy(prop_enum->name, name, DRM_PROP_NAME_LEN); 3308f453ba04SDave Airlie prop_enum->name[DRM_PROP_NAME_LEN-1] = '\0'; 3309f453ba04SDave Airlie prop_enum->value = value; 3310f453ba04SDave Airlie 3311f453ba04SDave Airlie property->values[index] = value; 3312f453ba04SDave Airlie list_add_tail(&prop_enum->head, &property->enum_blob_list); 3313f453ba04SDave Airlie return 0; 3314f453ba04SDave Airlie } 3315f453ba04SDave Airlie EXPORT_SYMBOL(drm_property_add_enum); 3316f453ba04SDave Airlie 3317c8e32cc1SDaniel Vetter /** 3318c8e32cc1SDaniel Vetter * drm_property_destroy - destroy a drm property 3319c8e32cc1SDaniel Vetter * @dev: drm device 3320c8e32cc1SDaniel Vetter * @property: property to destry 3321c8e32cc1SDaniel Vetter * 3322c8e32cc1SDaniel Vetter * This function frees a property including any attached resources like 3323c8e32cc1SDaniel Vetter * enumeration values. 3324c8e32cc1SDaniel Vetter */ 3325f453ba04SDave Airlie void drm_property_destroy(struct drm_device *dev, struct drm_property *property) 3326f453ba04SDave Airlie { 3327f453ba04SDave Airlie struct drm_property_enum *prop_enum, *pt; 3328f453ba04SDave Airlie 3329f453ba04SDave Airlie list_for_each_entry_safe(prop_enum, pt, &property->enum_blob_list, head) { 3330f453ba04SDave Airlie list_del(&prop_enum->head); 3331f453ba04SDave Airlie kfree(prop_enum); 3332f453ba04SDave Airlie } 3333f453ba04SDave Airlie 3334f453ba04SDave Airlie if (property->num_values) 3335f453ba04SDave Airlie kfree(property->values); 3336f453ba04SDave Airlie drm_mode_object_put(dev, &property->base); 3337f453ba04SDave Airlie list_del(&property->head); 3338f453ba04SDave Airlie kfree(property); 3339f453ba04SDave Airlie } 3340f453ba04SDave Airlie EXPORT_SYMBOL(drm_property_destroy); 3341f453ba04SDave Airlie 3342c8e32cc1SDaniel Vetter /** 3343c8e32cc1SDaniel Vetter * drm_object_attach_property - attach a property to a modeset object 3344c8e32cc1SDaniel Vetter * @obj: drm modeset object 3345c8e32cc1SDaniel Vetter * @property: property to attach 3346c8e32cc1SDaniel Vetter * @init_val: initial value of the property 3347c8e32cc1SDaniel Vetter * 3348c8e32cc1SDaniel Vetter * This attaches the given property to the modeset object with the given initial 3349c8e32cc1SDaniel Vetter * value. Currently this function cannot fail since the properties are stored in 3350c8e32cc1SDaniel Vetter * a statically sized array. 3351c8e32cc1SDaniel Vetter */ 3352c543188aSPaulo Zanoni void drm_object_attach_property(struct drm_mode_object *obj, 3353c543188aSPaulo Zanoni struct drm_property *property, 3354c543188aSPaulo Zanoni uint64_t init_val) 3355c543188aSPaulo Zanoni { 33567f88a9beSPaulo Zanoni int count = obj->properties->count; 3357c543188aSPaulo Zanoni 33587f88a9beSPaulo Zanoni if (count == DRM_OBJECT_MAX_PROPERTY) { 33597f88a9beSPaulo Zanoni WARN(1, "Failed to attach object property (type: 0x%x). Please " 33607f88a9beSPaulo Zanoni "increase DRM_OBJECT_MAX_PROPERTY by 1 for each time " 33617f88a9beSPaulo Zanoni "you see this message on the same object type.\n", 33627f88a9beSPaulo Zanoni obj->type); 3363c543188aSPaulo Zanoni return; 3364c543188aSPaulo Zanoni } 3365c543188aSPaulo Zanoni 33667f88a9beSPaulo Zanoni obj->properties->ids[count] = property->base.id; 33677f88a9beSPaulo Zanoni obj->properties->values[count] = init_val; 33687f88a9beSPaulo Zanoni obj->properties->count++; 3369c543188aSPaulo Zanoni } 3370c543188aSPaulo Zanoni EXPORT_SYMBOL(drm_object_attach_property); 3371c543188aSPaulo Zanoni 3372c8e32cc1SDaniel Vetter /** 3373c8e32cc1SDaniel Vetter * drm_object_property_set_value - set the value of a property 3374c8e32cc1SDaniel Vetter * @obj: drm mode object to set property value for 3375c8e32cc1SDaniel Vetter * @property: property to set 3376c8e32cc1SDaniel Vetter * @val: value the property should be set to 3377c8e32cc1SDaniel Vetter * 3378c8e32cc1SDaniel Vetter * This functions sets a given property on a given object. This function only 3379c8e32cc1SDaniel Vetter * changes the software state of the property, it does not call into the 3380c8e32cc1SDaniel Vetter * driver's ->set_property callback. 3381c8e32cc1SDaniel Vetter * 3382c8e32cc1SDaniel Vetter * Returns: 3383c8e32cc1SDaniel Vetter * Zero on success, error code on failure. 3384c8e32cc1SDaniel Vetter */ 3385c543188aSPaulo Zanoni int drm_object_property_set_value(struct drm_mode_object *obj, 3386c543188aSPaulo Zanoni struct drm_property *property, uint64_t val) 3387c543188aSPaulo Zanoni { 3388c543188aSPaulo Zanoni int i; 3389c543188aSPaulo Zanoni 33907f88a9beSPaulo Zanoni for (i = 0; i < obj->properties->count; i++) { 3391c543188aSPaulo Zanoni if (obj->properties->ids[i] == property->base.id) { 3392c543188aSPaulo Zanoni obj->properties->values[i] = val; 3393c543188aSPaulo Zanoni return 0; 3394c543188aSPaulo Zanoni } 3395c543188aSPaulo Zanoni } 3396c543188aSPaulo Zanoni 3397c543188aSPaulo Zanoni return -EINVAL; 3398c543188aSPaulo Zanoni } 3399c543188aSPaulo Zanoni EXPORT_SYMBOL(drm_object_property_set_value); 3400c543188aSPaulo Zanoni 3401c8e32cc1SDaniel Vetter /** 3402c8e32cc1SDaniel Vetter * drm_object_property_get_value - retrieve the value of a property 3403c8e32cc1SDaniel Vetter * @obj: drm mode object to get property value from 3404c8e32cc1SDaniel Vetter * @property: property to retrieve 3405c8e32cc1SDaniel Vetter * @val: storage for the property value 3406c8e32cc1SDaniel Vetter * 3407c8e32cc1SDaniel Vetter * This function retrieves the softare state of the given property for the given 3408c8e32cc1SDaniel Vetter * property. Since there is no driver callback to retrieve the current property 3409c8e32cc1SDaniel Vetter * value this might be out of sync with the hardware, depending upon the driver 3410c8e32cc1SDaniel Vetter * and property. 3411c8e32cc1SDaniel Vetter * 3412c8e32cc1SDaniel Vetter * Returns: 3413c8e32cc1SDaniel Vetter * Zero on success, error code on failure. 3414c8e32cc1SDaniel Vetter */ 3415c543188aSPaulo Zanoni int drm_object_property_get_value(struct drm_mode_object *obj, 3416c543188aSPaulo Zanoni struct drm_property *property, uint64_t *val) 3417c543188aSPaulo Zanoni { 3418c543188aSPaulo Zanoni int i; 3419c543188aSPaulo Zanoni 34207f88a9beSPaulo Zanoni for (i = 0; i < obj->properties->count; i++) { 3421c543188aSPaulo Zanoni if (obj->properties->ids[i] == property->base.id) { 3422c543188aSPaulo Zanoni *val = obj->properties->values[i]; 3423c543188aSPaulo Zanoni return 0; 3424c543188aSPaulo Zanoni } 3425c543188aSPaulo Zanoni } 3426c543188aSPaulo Zanoni 3427c543188aSPaulo Zanoni return -EINVAL; 3428c543188aSPaulo Zanoni } 3429c543188aSPaulo Zanoni EXPORT_SYMBOL(drm_object_property_get_value); 3430c543188aSPaulo Zanoni 3431c8e32cc1SDaniel Vetter /** 3432c8e32cc1SDaniel Vetter * drm_mode_getproperty_ioctl - get the current value of a connector's property 3433c8e32cc1SDaniel Vetter * @dev: DRM device 3434c8e32cc1SDaniel Vetter * @data: ioctl data 3435c8e32cc1SDaniel Vetter * @file_priv: DRM file info 3436c8e32cc1SDaniel Vetter * 3437c8e32cc1SDaniel Vetter * This function retrieves the current value for an connectors's property. 3438c8e32cc1SDaniel Vetter * 3439c8e32cc1SDaniel Vetter * Called by the user via ioctl. 3440c8e32cc1SDaniel Vetter * 3441c8e32cc1SDaniel Vetter * Returns: 3442c8e32cc1SDaniel Vetter * Zero on success, errno on failure. 3443c8e32cc1SDaniel Vetter */ 3444f453ba04SDave Airlie int drm_mode_getproperty_ioctl(struct drm_device *dev, 3445f453ba04SDave Airlie void *data, struct drm_file *file_priv) 3446f453ba04SDave Airlie { 3447f453ba04SDave Airlie struct drm_mode_object *obj; 3448f453ba04SDave Airlie struct drm_mode_get_property *out_resp = data; 3449f453ba04SDave Airlie struct drm_property *property; 3450f453ba04SDave Airlie int enum_count = 0; 3451f453ba04SDave Airlie int blob_count = 0; 3452f453ba04SDave Airlie int value_count = 0; 3453f453ba04SDave Airlie int ret = 0, i; 3454f453ba04SDave Airlie int copied; 3455f453ba04SDave Airlie struct drm_property_enum *prop_enum; 3456f453ba04SDave Airlie struct drm_mode_property_enum __user *enum_ptr; 3457f453ba04SDave Airlie struct drm_property_blob *prop_blob; 345881f6c7f8SVille Syrjälä uint32_t __user *blob_id_ptr; 3459f453ba04SDave Airlie uint64_t __user *values_ptr; 3460f453ba04SDave Airlie uint32_t __user *blob_length_ptr; 3461f453ba04SDave Airlie 3462fb3b06c8SDave Airlie if (!drm_core_check_feature(dev, DRIVER_MODESET)) 3463fb3b06c8SDave Airlie return -EINVAL; 3464fb3b06c8SDave Airlie 346584849903SDaniel Vetter drm_modeset_lock_all(dev); 3466f453ba04SDave Airlie obj = drm_mode_object_find(dev, out_resp->prop_id, DRM_MODE_OBJECT_PROPERTY); 3467f453ba04SDave Airlie if (!obj) { 3468f27657f2SVille Syrjälä ret = -ENOENT; 3469f453ba04SDave Airlie goto done; 3470f453ba04SDave Airlie } 3471f453ba04SDave Airlie property = obj_to_property(obj); 3472f453ba04SDave Airlie 347349e27545SRob Clark if (property->flags & (DRM_MODE_PROP_ENUM | DRM_MODE_PROP_BITMASK)) { 3474f453ba04SDave Airlie list_for_each_entry(prop_enum, &property->enum_blob_list, head) 3475f453ba04SDave Airlie enum_count++; 3476f453ba04SDave Airlie } else if (property->flags & DRM_MODE_PROP_BLOB) { 3477f453ba04SDave Airlie list_for_each_entry(prop_blob, &property->enum_blob_list, head) 3478f453ba04SDave Airlie blob_count++; 3479f453ba04SDave Airlie } 3480f453ba04SDave Airlie 3481f453ba04SDave Airlie value_count = property->num_values; 3482f453ba04SDave Airlie 3483f453ba04SDave Airlie strncpy(out_resp->name, property->name, DRM_PROP_NAME_LEN); 3484f453ba04SDave Airlie out_resp->name[DRM_PROP_NAME_LEN-1] = 0; 3485f453ba04SDave Airlie out_resp->flags = property->flags; 3486f453ba04SDave Airlie 3487f453ba04SDave Airlie if ((out_resp->count_values >= value_count) && value_count) { 348881f6c7f8SVille Syrjälä values_ptr = (uint64_t __user *)(unsigned long)out_resp->values_ptr; 3489f453ba04SDave Airlie for (i = 0; i < value_count; i++) { 3490f453ba04SDave Airlie if (copy_to_user(values_ptr + i, &property->values[i], sizeof(uint64_t))) { 3491f453ba04SDave Airlie ret = -EFAULT; 3492f453ba04SDave Airlie goto done; 3493f453ba04SDave Airlie } 3494f453ba04SDave Airlie } 3495f453ba04SDave Airlie } 3496f453ba04SDave Airlie out_resp->count_values = value_count; 3497f453ba04SDave Airlie 349849e27545SRob Clark if (property->flags & (DRM_MODE_PROP_ENUM | DRM_MODE_PROP_BITMASK)) { 3499f453ba04SDave Airlie if ((out_resp->count_enum_blobs >= enum_count) && enum_count) { 3500f453ba04SDave Airlie copied = 0; 350181f6c7f8SVille Syrjälä enum_ptr = (struct drm_mode_property_enum __user *)(unsigned long)out_resp->enum_blob_ptr; 3502f453ba04SDave Airlie list_for_each_entry(prop_enum, &property->enum_blob_list, head) { 3503f453ba04SDave Airlie 3504f453ba04SDave Airlie if (copy_to_user(&enum_ptr[copied].value, &prop_enum->value, sizeof(uint64_t))) { 3505f453ba04SDave Airlie ret = -EFAULT; 3506f453ba04SDave Airlie goto done; 3507f453ba04SDave Airlie } 3508f453ba04SDave Airlie 3509f453ba04SDave Airlie if (copy_to_user(&enum_ptr[copied].name, 3510f453ba04SDave Airlie &prop_enum->name, DRM_PROP_NAME_LEN)) { 3511f453ba04SDave Airlie ret = -EFAULT; 3512f453ba04SDave Airlie goto done; 3513f453ba04SDave Airlie } 3514f453ba04SDave Airlie copied++; 3515f453ba04SDave Airlie } 3516f453ba04SDave Airlie } 3517f453ba04SDave Airlie out_resp->count_enum_blobs = enum_count; 3518f453ba04SDave Airlie } 3519f453ba04SDave Airlie 3520f453ba04SDave Airlie if (property->flags & DRM_MODE_PROP_BLOB) { 3521f453ba04SDave Airlie if ((out_resp->count_enum_blobs >= blob_count) && blob_count) { 3522f453ba04SDave Airlie copied = 0; 352381f6c7f8SVille Syrjälä blob_id_ptr = (uint32_t __user *)(unsigned long)out_resp->enum_blob_ptr; 352481f6c7f8SVille Syrjälä blob_length_ptr = (uint32_t __user *)(unsigned long)out_resp->values_ptr; 3525f453ba04SDave Airlie 3526f453ba04SDave Airlie list_for_each_entry(prop_blob, &property->enum_blob_list, head) { 3527f453ba04SDave Airlie if (put_user(prop_blob->base.id, blob_id_ptr + copied)) { 3528f453ba04SDave Airlie ret = -EFAULT; 3529f453ba04SDave Airlie goto done; 3530f453ba04SDave Airlie } 3531f453ba04SDave Airlie 3532f453ba04SDave Airlie if (put_user(prop_blob->length, blob_length_ptr + copied)) { 3533f453ba04SDave Airlie ret = -EFAULT; 3534f453ba04SDave Airlie goto done; 3535f453ba04SDave Airlie } 3536f453ba04SDave Airlie 3537f453ba04SDave Airlie copied++; 3538f453ba04SDave Airlie } 3539f453ba04SDave Airlie } 3540f453ba04SDave Airlie out_resp->count_enum_blobs = blob_count; 3541f453ba04SDave Airlie } 3542f453ba04SDave Airlie done: 354384849903SDaniel Vetter drm_modeset_unlock_all(dev); 3544f453ba04SDave Airlie return ret; 3545f453ba04SDave Airlie } 3546f453ba04SDave Airlie 3547f453ba04SDave Airlie static struct drm_property_blob *drm_property_create_blob(struct drm_device *dev, int length, 3548f453ba04SDave Airlie void *data) 3549f453ba04SDave Airlie { 3550f453ba04SDave Airlie struct drm_property_blob *blob; 35516bfc56aaSVille Syrjälä int ret; 3552f453ba04SDave Airlie 3553f453ba04SDave Airlie if (!length || !data) 3554f453ba04SDave Airlie return NULL; 3555f453ba04SDave Airlie 3556f453ba04SDave Airlie blob = kzalloc(sizeof(struct drm_property_blob)+length, GFP_KERNEL); 3557f453ba04SDave Airlie if (!blob) 3558f453ba04SDave Airlie return NULL; 3559f453ba04SDave Airlie 35606bfc56aaSVille Syrjälä ret = drm_mode_object_get(dev, &blob->base, DRM_MODE_OBJECT_BLOB); 35616bfc56aaSVille Syrjälä if (ret) { 35626bfc56aaSVille Syrjälä kfree(blob); 35636bfc56aaSVille Syrjälä return NULL; 35646bfc56aaSVille Syrjälä } 35656bfc56aaSVille Syrjälä 3566f453ba04SDave Airlie blob->length = length; 3567f453ba04SDave Airlie 3568f453ba04SDave Airlie memcpy(blob->data, data, length); 3569f453ba04SDave Airlie 3570f453ba04SDave Airlie list_add_tail(&blob->head, &dev->mode_config.property_blob_list); 3571f453ba04SDave Airlie return blob; 3572f453ba04SDave Airlie } 3573f453ba04SDave Airlie 3574f453ba04SDave Airlie static void drm_property_destroy_blob(struct drm_device *dev, 3575f453ba04SDave Airlie struct drm_property_blob *blob) 3576f453ba04SDave Airlie { 3577f453ba04SDave Airlie drm_mode_object_put(dev, &blob->base); 3578f453ba04SDave Airlie list_del(&blob->head); 3579f453ba04SDave Airlie kfree(blob); 3580f453ba04SDave Airlie } 3581f453ba04SDave Airlie 3582c8e32cc1SDaniel Vetter /** 3583c8e32cc1SDaniel Vetter * drm_mode_getblob_ioctl - get the contents of a blob property value 3584c8e32cc1SDaniel Vetter * @dev: DRM device 3585c8e32cc1SDaniel Vetter * @data: ioctl data 3586c8e32cc1SDaniel Vetter * @file_priv: DRM file info 3587c8e32cc1SDaniel Vetter * 3588c8e32cc1SDaniel Vetter * This function retrieves the contents of a blob property. The value stored in 3589c8e32cc1SDaniel Vetter * an object's blob property is just a normal modeset object id. 3590c8e32cc1SDaniel Vetter * 3591c8e32cc1SDaniel Vetter * Called by the user via ioctl. 3592c8e32cc1SDaniel Vetter * 3593c8e32cc1SDaniel Vetter * Returns: 3594c8e32cc1SDaniel Vetter * Zero on success, errno on failure. 3595c8e32cc1SDaniel Vetter */ 3596f453ba04SDave Airlie int drm_mode_getblob_ioctl(struct drm_device *dev, 3597f453ba04SDave Airlie void *data, struct drm_file *file_priv) 3598f453ba04SDave Airlie { 3599f453ba04SDave Airlie struct drm_mode_object *obj; 3600f453ba04SDave Airlie struct drm_mode_get_blob *out_resp = data; 3601f453ba04SDave Airlie struct drm_property_blob *blob; 3602f453ba04SDave Airlie int ret = 0; 360381f6c7f8SVille Syrjälä void __user *blob_ptr; 3604f453ba04SDave Airlie 3605fb3b06c8SDave Airlie if (!drm_core_check_feature(dev, DRIVER_MODESET)) 3606fb3b06c8SDave Airlie return -EINVAL; 3607fb3b06c8SDave Airlie 360884849903SDaniel Vetter drm_modeset_lock_all(dev); 3609f453ba04SDave Airlie obj = drm_mode_object_find(dev, out_resp->blob_id, DRM_MODE_OBJECT_BLOB); 3610f453ba04SDave Airlie if (!obj) { 3611f27657f2SVille Syrjälä ret = -ENOENT; 3612f453ba04SDave Airlie goto done; 3613f453ba04SDave Airlie } 3614f453ba04SDave Airlie blob = obj_to_blob(obj); 3615f453ba04SDave Airlie 3616f453ba04SDave Airlie if (out_resp->length == blob->length) { 361781f6c7f8SVille Syrjälä blob_ptr = (void __user *)(unsigned long)out_resp->data; 3618f453ba04SDave Airlie if (copy_to_user(blob_ptr, blob->data, blob->length)){ 3619f453ba04SDave Airlie ret = -EFAULT; 3620f453ba04SDave Airlie goto done; 3621f453ba04SDave Airlie } 3622f453ba04SDave Airlie } 3623f453ba04SDave Airlie out_resp->length = blob->length; 3624f453ba04SDave Airlie 3625f453ba04SDave Airlie done: 362684849903SDaniel Vetter drm_modeset_unlock_all(dev); 3627f453ba04SDave Airlie return ret; 3628f453ba04SDave Airlie } 3629f453ba04SDave Airlie 3630c8e32cc1SDaniel Vetter /** 3631c8e32cc1SDaniel Vetter * drm_mode_connector_update_edid_property - update the edid property of a connector 3632c8e32cc1SDaniel Vetter * @connector: drm connector 3633c8e32cc1SDaniel Vetter * @edid: new value of the edid property 3634c8e32cc1SDaniel Vetter * 3635c8e32cc1SDaniel Vetter * This function creates a new blob modeset object and assigns its id to the 3636c8e32cc1SDaniel Vetter * connector's edid property. 3637c8e32cc1SDaniel Vetter * 3638c8e32cc1SDaniel Vetter * Returns: 3639c8e32cc1SDaniel Vetter * Zero on success, errno on failure. 3640c8e32cc1SDaniel Vetter */ 3641f453ba04SDave Airlie int drm_mode_connector_update_edid_property(struct drm_connector *connector, 3642f453ba04SDave Airlie struct edid *edid) 3643f453ba04SDave Airlie { 3644f453ba04SDave Airlie struct drm_device *dev = connector->dev; 36454a1b0714SLaurent Pinchart int ret, size; 3646f453ba04SDave Airlie 3647f453ba04SDave Airlie if (connector->edid_blob_ptr) 3648f453ba04SDave Airlie drm_property_destroy_blob(dev, connector->edid_blob_ptr); 3649f453ba04SDave Airlie 3650f453ba04SDave Airlie /* Delete edid, when there is none. */ 3651f453ba04SDave Airlie if (!edid) { 3652f453ba04SDave Airlie connector->edid_blob_ptr = NULL; 365358495563SRob Clark ret = drm_object_property_set_value(&connector->base, dev->mode_config.edid_property, 0); 3654f453ba04SDave Airlie return ret; 3655f453ba04SDave Airlie } 3656f453ba04SDave Airlie 36577466f4ccSAdam Jackson size = EDID_LENGTH * (1 + edid->extensions); 36587466f4ccSAdam Jackson connector->edid_blob_ptr = drm_property_create_blob(connector->dev, 36597466f4ccSAdam Jackson size, edid); 3660e655d122SSachin Kamat if (!connector->edid_blob_ptr) 3661e655d122SSachin Kamat return -EINVAL; 3662f453ba04SDave Airlie 366358495563SRob Clark ret = drm_object_property_set_value(&connector->base, 3664f453ba04SDave Airlie dev->mode_config.edid_property, 3665f453ba04SDave Airlie connector->edid_blob_ptr->base.id); 3666f453ba04SDave Airlie 3667f453ba04SDave Airlie return ret; 3668f453ba04SDave Airlie } 3669f453ba04SDave Airlie EXPORT_SYMBOL(drm_mode_connector_update_edid_property); 3670f453ba04SDave Airlie 367126a34815SPaulo Zanoni static bool drm_property_change_is_valid(struct drm_property *property, 3672592c20eeSVille Syrjälä uint64_t value) 367326a34815SPaulo Zanoni { 367426a34815SPaulo Zanoni if (property->flags & DRM_MODE_PROP_IMMUTABLE) 367526a34815SPaulo Zanoni return false; 367626a34815SPaulo Zanoni if (property->flags & DRM_MODE_PROP_RANGE) { 367726a34815SPaulo Zanoni if (value < property->values[0] || value > property->values[1]) 367826a34815SPaulo Zanoni return false; 367926a34815SPaulo Zanoni return true; 368049e27545SRob Clark } else if (property->flags & DRM_MODE_PROP_BITMASK) { 368149e27545SRob Clark int i; 3682592c20eeSVille Syrjälä uint64_t valid_mask = 0; 368349e27545SRob Clark for (i = 0; i < property->num_values; i++) 368449e27545SRob Clark valid_mask |= (1ULL << property->values[i]); 368549e27545SRob Clark return !(value & ~valid_mask); 3686c4a56750SVille Syrjälä } else if (property->flags & DRM_MODE_PROP_BLOB) { 3687c4a56750SVille Syrjälä /* Only the driver knows */ 3688c4a56750SVille Syrjälä return true; 368926a34815SPaulo Zanoni } else { 369026a34815SPaulo Zanoni int i; 369126a34815SPaulo Zanoni for (i = 0; i < property->num_values; i++) 369226a34815SPaulo Zanoni if (property->values[i] == value) 369326a34815SPaulo Zanoni return true; 369426a34815SPaulo Zanoni return false; 369526a34815SPaulo Zanoni } 369626a34815SPaulo Zanoni } 369726a34815SPaulo Zanoni 3698c8e32cc1SDaniel Vetter /** 3699c8e32cc1SDaniel Vetter * drm_mode_connector_property_set_ioctl - set the current value of a connector property 3700c8e32cc1SDaniel Vetter * @dev: DRM device 3701c8e32cc1SDaniel Vetter * @data: ioctl data 3702c8e32cc1SDaniel Vetter * @file_priv: DRM file info 3703c8e32cc1SDaniel Vetter * 3704c8e32cc1SDaniel Vetter * This function sets the current value for a connectors's property. It also 3705c8e32cc1SDaniel Vetter * calls into a driver's ->set_property callback to update the hardware state 3706c8e32cc1SDaniel Vetter * 3707c8e32cc1SDaniel Vetter * Called by the user via ioctl. 3708c8e32cc1SDaniel Vetter * 3709c8e32cc1SDaniel Vetter * Returns: 3710c8e32cc1SDaniel Vetter * Zero on success, errno on failure. 3711c8e32cc1SDaniel Vetter */ 3712f453ba04SDave Airlie int drm_mode_connector_property_set_ioctl(struct drm_device *dev, 3713f453ba04SDave Airlie void *data, struct drm_file *file_priv) 3714f453ba04SDave Airlie { 37150057d8ddSPaulo Zanoni struct drm_mode_connector_set_property *conn_set_prop = data; 37160057d8ddSPaulo Zanoni struct drm_mode_obj_set_property obj_set_prop = { 37170057d8ddSPaulo Zanoni .value = conn_set_prop->value, 37180057d8ddSPaulo Zanoni .prop_id = conn_set_prop->prop_id, 37190057d8ddSPaulo Zanoni .obj_id = conn_set_prop->connector_id, 37200057d8ddSPaulo Zanoni .obj_type = DRM_MODE_OBJECT_CONNECTOR 37210057d8ddSPaulo Zanoni }; 3722f453ba04SDave Airlie 37230057d8ddSPaulo Zanoni /* It does all the locking and checking we need */ 37240057d8ddSPaulo Zanoni return drm_mode_obj_set_property_ioctl(dev, &obj_set_prop, file_priv); 3725f453ba04SDave Airlie } 3726f453ba04SDave Airlie 3727c543188aSPaulo Zanoni static int drm_mode_connector_set_obj_prop(struct drm_mode_object *obj, 3728c543188aSPaulo Zanoni struct drm_property *property, 3729c543188aSPaulo Zanoni uint64_t value) 3730c543188aSPaulo Zanoni { 3731c543188aSPaulo Zanoni int ret = -EINVAL; 3732c543188aSPaulo Zanoni struct drm_connector *connector = obj_to_connector(obj); 3733c543188aSPaulo Zanoni 3734c543188aSPaulo Zanoni /* Do DPMS ourselves */ 3735c543188aSPaulo Zanoni if (property == connector->dev->mode_config.dpms_property) { 3736c543188aSPaulo Zanoni if (connector->funcs->dpms) 3737c543188aSPaulo Zanoni (*connector->funcs->dpms)(connector, (int)value); 3738c543188aSPaulo Zanoni ret = 0; 3739c543188aSPaulo Zanoni } else if (connector->funcs->set_property) 3740c543188aSPaulo Zanoni ret = connector->funcs->set_property(connector, property, value); 3741c543188aSPaulo Zanoni 3742c543188aSPaulo Zanoni /* store the property value if successful */ 3743c543188aSPaulo Zanoni if (!ret) 374458495563SRob Clark drm_object_property_set_value(&connector->base, property, value); 3745c543188aSPaulo Zanoni return ret; 3746c543188aSPaulo Zanoni } 3747c543188aSPaulo Zanoni 3748bffd9de0SPaulo Zanoni static int drm_mode_crtc_set_obj_prop(struct drm_mode_object *obj, 3749bffd9de0SPaulo Zanoni struct drm_property *property, 3750bffd9de0SPaulo Zanoni uint64_t value) 3751bffd9de0SPaulo Zanoni { 3752bffd9de0SPaulo Zanoni int ret = -EINVAL; 3753bffd9de0SPaulo Zanoni struct drm_crtc *crtc = obj_to_crtc(obj); 3754bffd9de0SPaulo Zanoni 3755bffd9de0SPaulo Zanoni if (crtc->funcs->set_property) 3756bffd9de0SPaulo Zanoni ret = crtc->funcs->set_property(crtc, property, value); 3757bffd9de0SPaulo Zanoni if (!ret) 3758bffd9de0SPaulo Zanoni drm_object_property_set_value(obj, property, value); 3759bffd9de0SPaulo Zanoni 3760bffd9de0SPaulo Zanoni return ret; 3761bffd9de0SPaulo Zanoni } 3762bffd9de0SPaulo Zanoni 37634d93914aSRob Clark static int drm_mode_plane_set_obj_prop(struct drm_mode_object *obj, 37644d93914aSRob Clark struct drm_property *property, 37654d93914aSRob Clark uint64_t value) 37664d93914aSRob Clark { 37674d93914aSRob Clark int ret = -EINVAL; 37684d93914aSRob Clark struct drm_plane *plane = obj_to_plane(obj); 37694d93914aSRob Clark 37704d93914aSRob Clark if (plane->funcs->set_property) 37714d93914aSRob Clark ret = plane->funcs->set_property(plane, property, value); 37724d93914aSRob Clark if (!ret) 37734d93914aSRob Clark drm_object_property_set_value(obj, property, value); 37744d93914aSRob Clark 37754d93914aSRob Clark return ret; 37764d93914aSRob Clark } 37774d93914aSRob Clark 3778c8e32cc1SDaniel Vetter /** 3779c8e32cc1SDaniel Vetter * drm_mode_getproperty_ioctl - get the current value of a object's property 3780c8e32cc1SDaniel Vetter * @dev: DRM device 3781c8e32cc1SDaniel Vetter * @data: ioctl data 3782c8e32cc1SDaniel Vetter * @file_priv: DRM file info 3783c8e32cc1SDaniel Vetter * 3784c8e32cc1SDaniel Vetter * This function retrieves the current value for an object's property. Compared 3785c8e32cc1SDaniel Vetter * to the connector specific ioctl this one is extended to also work on crtc and 3786c8e32cc1SDaniel Vetter * plane objects. 3787c8e32cc1SDaniel Vetter * 3788c8e32cc1SDaniel Vetter * Called by the user via ioctl. 3789c8e32cc1SDaniel Vetter * 3790c8e32cc1SDaniel Vetter * Returns: 3791c8e32cc1SDaniel Vetter * Zero on success, errno on failure. 3792c8e32cc1SDaniel Vetter */ 3793c543188aSPaulo Zanoni int drm_mode_obj_get_properties_ioctl(struct drm_device *dev, void *data, 3794c543188aSPaulo Zanoni struct drm_file *file_priv) 3795c543188aSPaulo Zanoni { 3796c543188aSPaulo Zanoni struct drm_mode_obj_get_properties *arg = data; 3797c543188aSPaulo Zanoni struct drm_mode_object *obj; 3798c543188aSPaulo Zanoni int ret = 0; 3799c543188aSPaulo Zanoni int i; 3800c543188aSPaulo Zanoni int copied = 0; 3801c543188aSPaulo Zanoni int props_count = 0; 3802c543188aSPaulo Zanoni uint32_t __user *props_ptr; 3803c543188aSPaulo Zanoni uint64_t __user *prop_values_ptr; 3804c543188aSPaulo Zanoni 3805c543188aSPaulo Zanoni if (!drm_core_check_feature(dev, DRIVER_MODESET)) 3806c543188aSPaulo Zanoni return -EINVAL; 3807c543188aSPaulo Zanoni 380884849903SDaniel Vetter drm_modeset_lock_all(dev); 3809c543188aSPaulo Zanoni 3810c543188aSPaulo Zanoni obj = drm_mode_object_find(dev, arg->obj_id, arg->obj_type); 3811c543188aSPaulo Zanoni if (!obj) { 3812f27657f2SVille Syrjälä ret = -ENOENT; 3813c543188aSPaulo Zanoni goto out; 3814c543188aSPaulo Zanoni } 3815c543188aSPaulo Zanoni if (!obj->properties) { 3816c543188aSPaulo Zanoni ret = -EINVAL; 3817c543188aSPaulo Zanoni goto out; 3818c543188aSPaulo Zanoni } 3819c543188aSPaulo Zanoni 38207f88a9beSPaulo Zanoni props_count = obj->properties->count; 3821c543188aSPaulo Zanoni 3822c543188aSPaulo Zanoni /* This ioctl is called twice, once to determine how much space is 3823c543188aSPaulo Zanoni * needed, and the 2nd time to fill it. */ 3824c543188aSPaulo Zanoni if ((arg->count_props >= props_count) && props_count) { 3825c543188aSPaulo Zanoni copied = 0; 3826c543188aSPaulo Zanoni props_ptr = (uint32_t __user *)(unsigned long)(arg->props_ptr); 3827c543188aSPaulo Zanoni prop_values_ptr = (uint64_t __user *)(unsigned long) 3828c543188aSPaulo Zanoni (arg->prop_values_ptr); 3829c543188aSPaulo Zanoni for (i = 0; i < props_count; i++) { 3830c543188aSPaulo Zanoni if (put_user(obj->properties->ids[i], 3831c543188aSPaulo Zanoni props_ptr + copied)) { 3832c543188aSPaulo Zanoni ret = -EFAULT; 3833c543188aSPaulo Zanoni goto out; 3834c543188aSPaulo Zanoni } 3835c543188aSPaulo Zanoni if (put_user(obj->properties->values[i], 3836c543188aSPaulo Zanoni prop_values_ptr + copied)) { 3837c543188aSPaulo Zanoni ret = -EFAULT; 3838c543188aSPaulo Zanoni goto out; 3839c543188aSPaulo Zanoni } 3840c543188aSPaulo Zanoni copied++; 3841c543188aSPaulo Zanoni } 3842c543188aSPaulo Zanoni } 3843c543188aSPaulo Zanoni arg->count_props = props_count; 3844c543188aSPaulo Zanoni out: 384584849903SDaniel Vetter drm_modeset_unlock_all(dev); 3846c543188aSPaulo Zanoni return ret; 3847c543188aSPaulo Zanoni } 3848c543188aSPaulo Zanoni 3849c8e32cc1SDaniel Vetter /** 3850c8e32cc1SDaniel Vetter * drm_mode_obj_set_property_ioctl - set the current value of an object's property 3851c8e32cc1SDaniel Vetter * @dev: DRM device 3852c8e32cc1SDaniel Vetter * @data: ioctl data 3853c8e32cc1SDaniel Vetter * @file_priv: DRM file info 3854c8e32cc1SDaniel Vetter * 3855c8e32cc1SDaniel Vetter * This function sets the current value for an object's property. It also calls 3856c8e32cc1SDaniel Vetter * into a driver's ->set_property callback to update the hardware state. 3857c8e32cc1SDaniel Vetter * Compared to the connector specific ioctl this one is extended to also work on 3858c8e32cc1SDaniel Vetter * crtc and plane objects. 3859c8e32cc1SDaniel Vetter * 3860c8e32cc1SDaniel Vetter * Called by the user via ioctl. 3861c8e32cc1SDaniel Vetter * 3862c8e32cc1SDaniel Vetter * Returns: 3863c8e32cc1SDaniel Vetter * Zero on success, errno on failure. 3864c8e32cc1SDaniel Vetter */ 3865c543188aSPaulo Zanoni int drm_mode_obj_set_property_ioctl(struct drm_device *dev, void *data, 3866c543188aSPaulo Zanoni struct drm_file *file_priv) 3867c543188aSPaulo Zanoni { 3868c543188aSPaulo Zanoni struct drm_mode_obj_set_property *arg = data; 3869c543188aSPaulo Zanoni struct drm_mode_object *arg_obj; 3870c543188aSPaulo Zanoni struct drm_mode_object *prop_obj; 3871c543188aSPaulo Zanoni struct drm_property *property; 3872c543188aSPaulo Zanoni int ret = -EINVAL; 3873c543188aSPaulo Zanoni int i; 3874c543188aSPaulo Zanoni 3875c543188aSPaulo Zanoni if (!drm_core_check_feature(dev, DRIVER_MODESET)) 3876c543188aSPaulo Zanoni return -EINVAL; 3877c543188aSPaulo Zanoni 387884849903SDaniel Vetter drm_modeset_lock_all(dev); 3879c543188aSPaulo Zanoni 3880c543188aSPaulo Zanoni arg_obj = drm_mode_object_find(dev, arg->obj_id, arg->obj_type); 3881f27657f2SVille Syrjälä if (!arg_obj) { 3882f27657f2SVille Syrjälä ret = -ENOENT; 3883c543188aSPaulo Zanoni goto out; 3884f27657f2SVille Syrjälä } 3885c543188aSPaulo Zanoni if (!arg_obj->properties) 3886c543188aSPaulo Zanoni goto out; 3887c543188aSPaulo Zanoni 38887f88a9beSPaulo Zanoni for (i = 0; i < arg_obj->properties->count; i++) 3889c543188aSPaulo Zanoni if (arg_obj->properties->ids[i] == arg->prop_id) 3890c543188aSPaulo Zanoni break; 3891c543188aSPaulo Zanoni 38927f88a9beSPaulo Zanoni if (i == arg_obj->properties->count) 3893c543188aSPaulo Zanoni goto out; 3894c543188aSPaulo Zanoni 3895c543188aSPaulo Zanoni prop_obj = drm_mode_object_find(dev, arg->prop_id, 3896c543188aSPaulo Zanoni DRM_MODE_OBJECT_PROPERTY); 3897f27657f2SVille Syrjälä if (!prop_obj) { 3898f27657f2SVille Syrjälä ret = -ENOENT; 3899c543188aSPaulo Zanoni goto out; 3900f27657f2SVille Syrjälä } 3901c543188aSPaulo Zanoni property = obj_to_property(prop_obj); 3902c543188aSPaulo Zanoni 3903c543188aSPaulo Zanoni if (!drm_property_change_is_valid(property, arg->value)) 3904c543188aSPaulo Zanoni goto out; 3905c543188aSPaulo Zanoni 3906c543188aSPaulo Zanoni switch (arg_obj->type) { 3907c543188aSPaulo Zanoni case DRM_MODE_OBJECT_CONNECTOR: 3908c543188aSPaulo Zanoni ret = drm_mode_connector_set_obj_prop(arg_obj, property, 3909c543188aSPaulo Zanoni arg->value); 3910c543188aSPaulo Zanoni break; 3911bffd9de0SPaulo Zanoni case DRM_MODE_OBJECT_CRTC: 3912bffd9de0SPaulo Zanoni ret = drm_mode_crtc_set_obj_prop(arg_obj, property, arg->value); 3913bffd9de0SPaulo Zanoni break; 39144d93914aSRob Clark case DRM_MODE_OBJECT_PLANE: 39154d93914aSRob Clark ret = drm_mode_plane_set_obj_prop(arg_obj, property, arg->value); 39164d93914aSRob Clark break; 3917c543188aSPaulo Zanoni } 3918c543188aSPaulo Zanoni 3919c543188aSPaulo Zanoni out: 392084849903SDaniel Vetter drm_modeset_unlock_all(dev); 3921c543188aSPaulo Zanoni return ret; 3922c543188aSPaulo Zanoni } 3923c543188aSPaulo Zanoni 3924c8e32cc1SDaniel Vetter /** 3925c8e32cc1SDaniel Vetter * drm_mode_connector_attach_encoder - attach a connector to an encoder 3926c8e32cc1SDaniel Vetter * @connector: connector to attach 3927c8e32cc1SDaniel Vetter * @encoder: encoder to attach @connector to 3928c8e32cc1SDaniel Vetter * 3929c8e32cc1SDaniel Vetter * This function links up a connector to an encoder. Note that the routing 3930c8e32cc1SDaniel Vetter * restrictions between encoders and crtcs are exposed to userspace through the 3931c8e32cc1SDaniel Vetter * possible_clones and possible_crtcs bitmasks. 3932c8e32cc1SDaniel Vetter * 3933c8e32cc1SDaniel Vetter * Returns: 3934c8e32cc1SDaniel Vetter * Zero on success, errno on failure. 3935c8e32cc1SDaniel Vetter */ 3936f453ba04SDave Airlie int drm_mode_connector_attach_encoder(struct drm_connector *connector, 3937f453ba04SDave Airlie struct drm_encoder *encoder) 3938f453ba04SDave Airlie { 3939f453ba04SDave Airlie int i; 3940f453ba04SDave Airlie 3941f453ba04SDave Airlie for (i = 0; i < DRM_CONNECTOR_MAX_ENCODER; i++) { 3942f453ba04SDave Airlie if (connector->encoder_ids[i] == 0) { 3943f453ba04SDave Airlie connector->encoder_ids[i] = encoder->base.id; 3944f453ba04SDave Airlie return 0; 3945f453ba04SDave Airlie } 3946f453ba04SDave Airlie } 3947f453ba04SDave Airlie return -ENOMEM; 3948f453ba04SDave Airlie } 3949f453ba04SDave Airlie EXPORT_SYMBOL(drm_mode_connector_attach_encoder); 3950f453ba04SDave Airlie 3951c8e32cc1SDaniel Vetter /** 3952c8e32cc1SDaniel Vetter * drm_mode_crtc_set_gamma_size - set the gamma table size 3953c8e32cc1SDaniel Vetter * @crtc: CRTC to set the gamma table size for 3954c8e32cc1SDaniel Vetter * @gamma_size: size of the gamma table 3955c8e32cc1SDaniel Vetter * 3956c8e32cc1SDaniel Vetter * Drivers which support gamma tables should set this to the supported gamma 3957c8e32cc1SDaniel Vetter * table size when initializing the CRTC. Currently the drm core only supports a 3958c8e32cc1SDaniel Vetter * fixed gamma table size. 3959c8e32cc1SDaniel Vetter * 3960c8e32cc1SDaniel Vetter * Returns: 3961c8e32cc1SDaniel Vetter * Zero on success, errno on failure. 3962c8e32cc1SDaniel Vetter */ 39634cae5b84SSascha Hauer int drm_mode_crtc_set_gamma_size(struct drm_crtc *crtc, 3964f453ba04SDave Airlie int gamma_size) 3965f453ba04SDave Airlie { 3966f453ba04SDave Airlie crtc->gamma_size = gamma_size; 3967f453ba04SDave Airlie 3968f453ba04SDave Airlie crtc->gamma_store = kzalloc(gamma_size * sizeof(uint16_t) * 3, GFP_KERNEL); 3969f453ba04SDave Airlie if (!crtc->gamma_store) { 3970f453ba04SDave Airlie crtc->gamma_size = 0; 39714cae5b84SSascha Hauer return -ENOMEM; 3972f453ba04SDave Airlie } 3973f453ba04SDave Airlie 39744cae5b84SSascha Hauer return 0; 3975f453ba04SDave Airlie } 3976f453ba04SDave Airlie EXPORT_SYMBOL(drm_mode_crtc_set_gamma_size); 3977f453ba04SDave Airlie 3978c8e32cc1SDaniel Vetter /** 3979c8e32cc1SDaniel Vetter * drm_mode_gamma_set_ioctl - set the gamma table 3980c8e32cc1SDaniel Vetter * @dev: DRM device 3981c8e32cc1SDaniel Vetter * @data: ioctl data 3982c8e32cc1SDaniel Vetter * @file_priv: DRM file info 3983c8e32cc1SDaniel Vetter * 3984c8e32cc1SDaniel Vetter * Set the gamma table of a CRTC to the one passed in by the user. Userspace can 3985c8e32cc1SDaniel Vetter * inquire the required gamma table size through drm_mode_gamma_get_ioctl. 3986c8e32cc1SDaniel Vetter * 3987c8e32cc1SDaniel Vetter * Called by the user via ioctl. 3988c8e32cc1SDaniel Vetter * 3989c8e32cc1SDaniel Vetter * Returns: 3990c8e32cc1SDaniel Vetter * Zero on success, errno on failure. 3991c8e32cc1SDaniel Vetter */ 3992f453ba04SDave Airlie int drm_mode_gamma_set_ioctl(struct drm_device *dev, 3993f453ba04SDave Airlie void *data, struct drm_file *file_priv) 3994f453ba04SDave Airlie { 3995f453ba04SDave Airlie struct drm_mode_crtc_lut *crtc_lut = data; 3996f453ba04SDave Airlie struct drm_mode_object *obj; 3997f453ba04SDave Airlie struct drm_crtc *crtc; 3998f453ba04SDave Airlie void *r_base, *g_base, *b_base; 3999f453ba04SDave Airlie int size; 4000f453ba04SDave Airlie int ret = 0; 4001f453ba04SDave Airlie 4002fb3b06c8SDave Airlie if (!drm_core_check_feature(dev, DRIVER_MODESET)) 4003fb3b06c8SDave Airlie return -EINVAL; 4004fb3b06c8SDave Airlie 400584849903SDaniel Vetter drm_modeset_lock_all(dev); 4006f453ba04SDave Airlie obj = drm_mode_object_find(dev, crtc_lut->crtc_id, DRM_MODE_OBJECT_CRTC); 4007f453ba04SDave Airlie if (!obj) { 4008f27657f2SVille Syrjälä ret = -ENOENT; 4009f453ba04SDave Airlie goto out; 4010f453ba04SDave Airlie } 4011f453ba04SDave Airlie crtc = obj_to_crtc(obj); 4012f453ba04SDave Airlie 4013ebe0f244SLaurent Pinchart if (crtc->funcs->gamma_set == NULL) { 4014ebe0f244SLaurent Pinchart ret = -ENOSYS; 4015ebe0f244SLaurent Pinchart goto out; 4016ebe0f244SLaurent Pinchart } 4017ebe0f244SLaurent Pinchart 4018f453ba04SDave Airlie /* memcpy into gamma store */ 4019f453ba04SDave Airlie if (crtc_lut->gamma_size != crtc->gamma_size) { 4020f453ba04SDave Airlie ret = -EINVAL; 4021f453ba04SDave Airlie goto out; 4022f453ba04SDave Airlie } 4023f453ba04SDave Airlie 4024f453ba04SDave Airlie size = crtc_lut->gamma_size * (sizeof(uint16_t)); 4025f453ba04SDave Airlie r_base = crtc->gamma_store; 4026f453ba04SDave Airlie if (copy_from_user(r_base, (void __user *)(unsigned long)crtc_lut->red, size)) { 4027f453ba04SDave Airlie ret = -EFAULT; 4028f453ba04SDave Airlie goto out; 4029f453ba04SDave Airlie } 4030f453ba04SDave Airlie 4031f453ba04SDave Airlie g_base = r_base + size; 4032f453ba04SDave Airlie if (copy_from_user(g_base, (void __user *)(unsigned long)crtc_lut->green, size)) { 4033f453ba04SDave Airlie ret = -EFAULT; 4034f453ba04SDave Airlie goto out; 4035f453ba04SDave Airlie } 4036f453ba04SDave Airlie 4037f453ba04SDave Airlie b_base = g_base + size; 4038f453ba04SDave Airlie if (copy_from_user(b_base, (void __user *)(unsigned long)crtc_lut->blue, size)) { 4039f453ba04SDave Airlie ret = -EFAULT; 4040f453ba04SDave Airlie goto out; 4041f453ba04SDave Airlie } 4042f453ba04SDave Airlie 40437203425aSJames Simmons crtc->funcs->gamma_set(crtc, r_base, g_base, b_base, 0, crtc->gamma_size); 4044f453ba04SDave Airlie 4045f453ba04SDave Airlie out: 404684849903SDaniel Vetter drm_modeset_unlock_all(dev); 4047f453ba04SDave Airlie return ret; 4048f453ba04SDave Airlie 4049f453ba04SDave Airlie } 4050f453ba04SDave Airlie 4051c8e32cc1SDaniel Vetter /** 4052c8e32cc1SDaniel Vetter * drm_mode_gamma_get_ioctl - get the gamma table 4053c8e32cc1SDaniel Vetter * @dev: DRM device 4054c8e32cc1SDaniel Vetter * @data: ioctl data 4055c8e32cc1SDaniel Vetter * @file_priv: DRM file info 4056c8e32cc1SDaniel Vetter * 4057c8e32cc1SDaniel Vetter * Copy the current gamma table into the storage provided. This also provides 4058c8e32cc1SDaniel Vetter * the gamma table size the driver expects, which can be used to size the 4059c8e32cc1SDaniel Vetter * allocated storage. 4060c8e32cc1SDaniel Vetter * 4061c8e32cc1SDaniel Vetter * Called by the user via ioctl. 4062c8e32cc1SDaniel Vetter * 4063c8e32cc1SDaniel Vetter * Returns: 4064c8e32cc1SDaniel Vetter * Zero on success, errno on failure. 4065c8e32cc1SDaniel Vetter */ 4066f453ba04SDave Airlie int drm_mode_gamma_get_ioctl(struct drm_device *dev, 4067f453ba04SDave Airlie void *data, struct drm_file *file_priv) 4068f453ba04SDave Airlie { 4069f453ba04SDave Airlie struct drm_mode_crtc_lut *crtc_lut = data; 4070f453ba04SDave Airlie struct drm_mode_object *obj; 4071f453ba04SDave Airlie struct drm_crtc *crtc; 4072f453ba04SDave Airlie void *r_base, *g_base, *b_base; 4073f453ba04SDave Airlie int size; 4074f453ba04SDave Airlie int ret = 0; 4075f453ba04SDave Airlie 4076fb3b06c8SDave Airlie if (!drm_core_check_feature(dev, DRIVER_MODESET)) 4077fb3b06c8SDave Airlie return -EINVAL; 4078fb3b06c8SDave Airlie 407984849903SDaniel Vetter drm_modeset_lock_all(dev); 4080f453ba04SDave Airlie obj = drm_mode_object_find(dev, crtc_lut->crtc_id, DRM_MODE_OBJECT_CRTC); 4081f453ba04SDave Airlie if (!obj) { 4082f27657f2SVille Syrjälä ret = -ENOENT; 4083f453ba04SDave Airlie goto out; 4084f453ba04SDave Airlie } 4085f453ba04SDave Airlie crtc = obj_to_crtc(obj); 4086f453ba04SDave Airlie 4087f453ba04SDave Airlie /* memcpy into gamma store */ 4088f453ba04SDave Airlie if (crtc_lut->gamma_size != crtc->gamma_size) { 4089f453ba04SDave Airlie ret = -EINVAL; 4090f453ba04SDave Airlie goto out; 4091f453ba04SDave Airlie } 4092f453ba04SDave Airlie 4093f453ba04SDave Airlie size = crtc_lut->gamma_size * (sizeof(uint16_t)); 4094f453ba04SDave Airlie r_base = crtc->gamma_store; 4095f453ba04SDave Airlie if (copy_to_user((void __user *)(unsigned long)crtc_lut->red, r_base, size)) { 4096f453ba04SDave Airlie ret = -EFAULT; 4097f453ba04SDave Airlie goto out; 4098f453ba04SDave Airlie } 4099f453ba04SDave Airlie 4100f453ba04SDave Airlie g_base = r_base + size; 4101f453ba04SDave Airlie if (copy_to_user((void __user *)(unsigned long)crtc_lut->green, g_base, size)) { 4102f453ba04SDave Airlie ret = -EFAULT; 4103f453ba04SDave Airlie goto out; 4104f453ba04SDave Airlie } 4105f453ba04SDave Airlie 4106f453ba04SDave Airlie b_base = g_base + size; 4107f453ba04SDave Airlie if (copy_to_user((void __user *)(unsigned long)crtc_lut->blue, b_base, size)) { 4108f453ba04SDave Airlie ret = -EFAULT; 4109f453ba04SDave Airlie goto out; 4110f453ba04SDave Airlie } 4111f453ba04SDave Airlie out: 411284849903SDaniel Vetter drm_modeset_unlock_all(dev); 4113f453ba04SDave Airlie return ret; 4114f453ba04SDave Airlie } 4115d91d8a3fSKristian Høgsberg 4116c8e32cc1SDaniel Vetter /** 4117c8e32cc1SDaniel Vetter * drm_mode_page_flip_ioctl - schedule an asynchronous fb update 4118c8e32cc1SDaniel Vetter * @dev: DRM device 4119c8e32cc1SDaniel Vetter * @data: ioctl data 4120c8e32cc1SDaniel Vetter * @file_priv: DRM file info 4121c8e32cc1SDaniel Vetter * 4122c8e32cc1SDaniel Vetter * This schedules an asynchronous update on a given CRTC, called page flip. 4123c8e32cc1SDaniel Vetter * Optionally a drm event is generated to signal the completion of the event. 4124c8e32cc1SDaniel Vetter * Generic drivers cannot assume that a pageflip with changed framebuffer 4125c8e32cc1SDaniel Vetter * properties (including driver specific metadata like tiling layout) will work, 4126c8e32cc1SDaniel Vetter * but some drivers support e.g. pixel format changes through the pageflip 4127c8e32cc1SDaniel Vetter * ioctl. 4128c8e32cc1SDaniel Vetter * 4129c8e32cc1SDaniel Vetter * Called by the user via ioctl. 4130c8e32cc1SDaniel Vetter * 4131c8e32cc1SDaniel Vetter * Returns: 4132c8e32cc1SDaniel Vetter * Zero on success, errno on failure. 4133c8e32cc1SDaniel Vetter */ 4134d91d8a3fSKristian Høgsberg int drm_mode_page_flip_ioctl(struct drm_device *dev, 4135d91d8a3fSKristian Høgsberg void *data, struct drm_file *file_priv) 4136d91d8a3fSKristian Høgsberg { 4137d91d8a3fSKristian Høgsberg struct drm_mode_crtc_page_flip *page_flip = data; 4138d91d8a3fSKristian Høgsberg struct drm_mode_object *obj; 4139d91d8a3fSKristian Høgsberg struct drm_crtc *crtc; 4140b0d12325SDaniel Vetter struct drm_framebuffer *fb = NULL, *old_fb = NULL; 4141d91d8a3fSKristian Høgsberg struct drm_pending_vblank_event *e = NULL; 4142d91d8a3fSKristian Høgsberg unsigned long flags; 4143d91d8a3fSKristian Høgsberg int ret = -EINVAL; 4144d91d8a3fSKristian Høgsberg 4145d91d8a3fSKristian Høgsberg if (page_flip->flags & ~DRM_MODE_PAGE_FLIP_FLAGS || 4146d91d8a3fSKristian Høgsberg page_flip->reserved != 0) 4147d91d8a3fSKristian Høgsberg return -EINVAL; 4148d91d8a3fSKristian Høgsberg 414962f2104fSKeith Packard if ((page_flip->flags & DRM_MODE_PAGE_FLIP_ASYNC) && !dev->mode_config.async_page_flip) 415062f2104fSKeith Packard return -EINVAL; 415162f2104fSKeith Packard 4152d91d8a3fSKristian Høgsberg obj = drm_mode_object_find(dev, page_flip->crtc_id, DRM_MODE_OBJECT_CRTC); 4153d91d8a3fSKristian Høgsberg if (!obj) 4154f27657f2SVille Syrjälä return -ENOENT; 4155d91d8a3fSKristian Høgsberg crtc = obj_to_crtc(obj); 4156d91d8a3fSKristian Høgsberg 4157b4d5e7d1SDaniel Vetter mutex_lock(&crtc->mutex); 4158f4510a27SMatt Roper if (crtc->primary->fb == NULL) { 415990c1efddSChris Wilson /* The framebuffer is currently unbound, presumably 416090c1efddSChris Wilson * due to a hotplug event, that userspace has not 416190c1efddSChris Wilson * yet discovered. 416290c1efddSChris Wilson */ 416390c1efddSChris Wilson ret = -EBUSY; 416490c1efddSChris Wilson goto out; 416590c1efddSChris Wilson } 416690c1efddSChris Wilson 4167d91d8a3fSKristian Høgsberg if (crtc->funcs->page_flip == NULL) 4168d91d8a3fSKristian Høgsberg goto out; 4169d91d8a3fSKristian Høgsberg 4170786b99edSDaniel Vetter fb = drm_framebuffer_lookup(dev, page_flip->fb_id); 417137c4e705SVille Syrjälä if (!fb) { 417237c4e705SVille Syrjälä ret = -ENOENT; 4173d91d8a3fSKristian Høgsberg goto out; 417437c4e705SVille Syrjälä } 4175d91d8a3fSKristian Høgsberg 4176c11e9283SDamien Lespiau ret = drm_crtc_check_viewport(crtc, crtc->x, crtc->y, &crtc->mode, fb); 4177c11e9283SDamien Lespiau if (ret) 41785f61bb42SVille Syrjälä goto out; 41795f61bb42SVille Syrjälä 4180f4510a27SMatt Roper if (crtc->primary->fb->pixel_format != fb->pixel_format) { 4181909d9cdaSLaurent Pinchart DRM_DEBUG_KMS("Page flip is not allowed to change frame buffer format.\n"); 4182909d9cdaSLaurent Pinchart ret = -EINVAL; 4183909d9cdaSLaurent Pinchart goto out; 4184909d9cdaSLaurent Pinchart } 4185909d9cdaSLaurent Pinchart 4186d91d8a3fSKristian Høgsberg if (page_flip->flags & DRM_MODE_PAGE_FLIP_EVENT) { 4187d91d8a3fSKristian Høgsberg ret = -ENOMEM; 4188d91d8a3fSKristian Høgsberg spin_lock_irqsave(&dev->event_lock, flags); 4189d91d8a3fSKristian Høgsberg if (file_priv->event_space < sizeof e->event) { 4190d91d8a3fSKristian Høgsberg spin_unlock_irqrestore(&dev->event_lock, flags); 4191d91d8a3fSKristian Høgsberg goto out; 4192d91d8a3fSKristian Høgsberg } 4193d91d8a3fSKristian Høgsberg file_priv->event_space -= sizeof e->event; 4194d91d8a3fSKristian Høgsberg spin_unlock_irqrestore(&dev->event_lock, flags); 4195d91d8a3fSKristian Høgsberg 4196d91d8a3fSKristian Høgsberg e = kzalloc(sizeof *e, GFP_KERNEL); 4197d91d8a3fSKristian Høgsberg if (e == NULL) { 4198d91d8a3fSKristian Høgsberg spin_lock_irqsave(&dev->event_lock, flags); 4199d91d8a3fSKristian Høgsberg file_priv->event_space += sizeof e->event; 4200d91d8a3fSKristian Høgsberg spin_unlock_irqrestore(&dev->event_lock, flags); 4201d91d8a3fSKristian Høgsberg goto out; 4202d91d8a3fSKristian Høgsberg } 4203d91d8a3fSKristian Høgsberg 42047bd4d7beSJesse Barnes e->event.base.type = DRM_EVENT_FLIP_COMPLETE; 4205d91d8a3fSKristian Høgsberg e->event.base.length = sizeof e->event; 4206d91d8a3fSKristian Høgsberg e->event.user_data = page_flip->user_data; 4207d91d8a3fSKristian Høgsberg e->base.event = &e->event.base; 4208d91d8a3fSKristian Høgsberg e->base.file_priv = file_priv; 4209d91d8a3fSKristian Høgsberg e->base.destroy = 4210d91d8a3fSKristian Høgsberg (void (*) (struct drm_pending_event *)) kfree; 4211d91d8a3fSKristian Høgsberg } 4212d91d8a3fSKristian Høgsberg 4213f4510a27SMatt Roper old_fb = crtc->primary->fb; 4214ed8d1975SKeith Packard ret = crtc->funcs->page_flip(crtc, fb, e, page_flip->flags); 4215d91d8a3fSKristian Høgsberg if (ret) { 4216aef6a7eeSJoonyoung Shim if (page_flip->flags & DRM_MODE_PAGE_FLIP_EVENT) { 4217d91d8a3fSKristian Høgsberg spin_lock_irqsave(&dev->event_lock, flags); 4218d91d8a3fSKristian Høgsberg file_priv->event_space += sizeof e->event; 4219d91d8a3fSKristian Høgsberg spin_unlock_irqrestore(&dev->event_lock, flags); 4220d91d8a3fSKristian Høgsberg kfree(e); 4221d91d8a3fSKristian Høgsberg } 4222b0d12325SDaniel Vetter /* Keep the old fb, don't unref it. */ 4223b0d12325SDaniel Vetter old_fb = NULL; 4224b0d12325SDaniel Vetter } else { 42258cf1e981SThierry Reding /* 42268cf1e981SThierry Reding * Warn if the driver hasn't properly updated the crtc->fb 42278cf1e981SThierry Reding * field to reflect that the new framebuffer is now used. 42288cf1e981SThierry Reding * Failing to do so will screw with the reference counting 42298cf1e981SThierry Reding * on framebuffers. 42308cf1e981SThierry Reding */ 4231f4510a27SMatt Roper WARN_ON(crtc->primary->fb != fb); 4232b0d12325SDaniel Vetter /* Unref only the old framebuffer. */ 4233b0d12325SDaniel Vetter fb = NULL; 4234aef6a7eeSJoonyoung Shim } 4235d91d8a3fSKristian Høgsberg 4236d91d8a3fSKristian Høgsberg out: 4237b0d12325SDaniel Vetter if (fb) 4238b0d12325SDaniel Vetter drm_framebuffer_unreference(fb); 4239b0d12325SDaniel Vetter if (old_fb) 4240b0d12325SDaniel Vetter drm_framebuffer_unreference(old_fb); 4241b4d5e7d1SDaniel Vetter mutex_unlock(&crtc->mutex); 4242b4d5e7d1SDaniel Vetter 4243d91d8a3fSKristian Høgsberg return ret; 4244d91d8a3fSKristian Høgsberg } 4245eb033556SChris Wilson 4246c8e32cc1SDaniel Vetter /** 4247c8e32cc1SDaniel Vetter * drm_mode_config_reset - call ->reset callbacks 4248c8e32cc1SDaniel Vetter * @dev: drm device 4249c8e32cc1SDaniel Vetter * 4250c8e32cc1SDaniel Vetter * This functions calls all the crtc's, encoder's and connector's ->reset 4251c8e32cc1SDaniel Vetter * callback. Drivers can use this in e.g. their driver load or resume code to 4252c8e32cc1SDaniel Vetter * reset hardware and software state. 4253c8e32cc1SDaniel Vetter */ 4254eb033556SChris Wilson void drm_mode_config_reset(struct drm_device *dev) 4255eb033556SChris Wilson { 4256eb033556SChris Wilson struct drm_crtc *crtc; 4257eb033556SChris Wilson struct drm_encoder *encoder; 4258eb033556SChris Wilson struct drm_connector *connector; 4259eb033556SChris Wilson 4260eb033556SChris Wilson list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) 4261eb033556SChris Wilson if (crtc->funcs->reset) 4262eb033556SChris Wilson crtc->funcs->reset(crtc); 4263eb033556SChris Wilson 4264eb033556SChris Wilson list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) 4265eb033556SChris Wilson if (encoder->funcs->reset) 4266eb033556SChris Wilson encoder->funcs->reset(encoder); 4267eb033556SChris Wilson 42685e2cb2f6SDaniel Vetter list_for_each_entry(connector, &dev->mode_config.connector_list, head) { 42695e2cb2f6SDaniel Vetter connector->status = connector_status_unknown; 42705e2cb2f6SDaniel Vetter 4271eb033556SChris Wilson if (connector->funcs->reset) 4272eb033556SChris Wilson connector->funcs->reset(connector); 4273eb033556SChris Wilson } 42745e2cb2f6SDaniel Vetter } 4275eb033556SChris Wilson EXPORT_SYMBOL(drm_mode_config_reset); 4276ff72145bSDave Airlie 4277c8e32cc1SDaniel Vetter /** 4278c8e32cc1SDaniel Vetter * drm_mode_create_dumb_ioctl - create a dumb backing storage buffer 4279c8e32cc1SDaniel Vetter * @dev: DRM device 4280c8e32cc1SDaniel Vetter * @data: ioctl data 4281c8e32cc1SDaniel Vetter * @file_priv: DRM file info 4282c8e32cc1SDaniel Vetter * 4283c8e32cc1SDaniel Vetter * This creates a new dumb buffer in the driver's backing storage manager (GEM, 4284c8e32cc1SDaniel Vetter * TTM or something else entirely) and returns the resulting buffer handle. This 4285c8e32cc1SDaniel Vetter * handle can then be wrapped up into a framebuffer modeset object. 4286c8e32cc1SDaniel Vetter * 4287c8e32cc1SDaniel Vetter * Note that userspace is not allowed to use such objects for render 4288c8e32cc1SDaniel Vetter * acceleration - drivers must create their own private ioctls for such a use 4289c8e32cc1SDaniel Vetter * case. 4290c8e32cc1SDaniel Vetter * 4291c8e32cc1SDaniel Vetter * Called by the user via ioctl. 4292c8e32cc1SDaniel Vetter * 4293c8e32cc1SDaniel Vetter * Returns: 4294c8e32cc1SDaniel Vetter * Zero on success, errno on failure. 4295c8e32cc1SDaniel Vetter */ 4296ff72145bSDave Airlie int drm_mode_create_dumb_ioctl(struct drm_device *dev, 4297ff72145bSDave Airlie void *data, struct drm_file *file_priv) 4298ff72145bSDave Airlie { 4299ff72145bSDave Airlie struct drm_mode_create_dumb *args = data; 4300b28cd41fSDavid Herrmann u32 cpp, stride, size; 4301ff72145bSDave Airlie 4302ff72145bSDave Airlie if (!dev->driver->dumb_create) 4303ff72145bSDave Airlie return -ENOSYS; 4304b28cd41fSDavid Herrmann if (!args->width || !args->height || !args->bpp) 4305b28cd41fSDavid Herrmann return -EINVAL; 4306b28cd41fSDavid Herrmann 4307b28cd41fSDavid Herrmann /* overflow checks for 32bit size calculations */ 4308b28cd41fSDavid Herrmann cpp = DIV_ROUND_UP(args->bpp, 8); 4309b28cd41fSDavid Herrmann if (cpp > 0xffffffffU / args->width) 4310b28cd41fSDavid Herrmann return -EINVAL; 4311b28cd41fSDavid Herrmann stride = cpp * args->width; 4312b28cd41fSDavid Herrmann if (args->height > 0xffffffffU / stride) 4313b28cd41fSDavid Herrmann return -EINVAL; 4314b28cd41fSDavid Herrmann 4315b28cd41fSDavid Herrmann /* test for wrap-around */ 4316b28cd41fSDavid Herrmann size = args->height * stride; 4317b28cd41fSDavid Herrmann if (PAGE_ALIGN(size) == 0) 4318b28cd41fSDavid Herrmann return -EINVAL; 4319b28cd41fSDavid Herrmann 4320ff72145bSDave Airlie return dev->driver->dumb_create(file_priv, dev, args); 4321ff72145bSDave Airlie } 4322ff72145bSDave Airlie 4323c8e32cc1SDaniel Vetter /** 4324c8e32cc1SDaniel Vetter * drm_mode_mmap_dumb_ioctl - create an mmap offset for a dumb backing storage buffer 4325c8e32cc1SDaniel Vetter * @dev: DRM device 4326c8e32cc1SDaniel Vetter * @data: ioctl data 4327c8e32cc1SDaniel Vetter * @file_priv: DRM file info 4328c8e32cc1SDaniel Vetter * 4329c8e32cc1SDaniel Vetter * Allocate an offset in the drm device node's address space to be able to 4330c8e32cc1SDaniel Vetter * memory map a dumb buffer. 4331c8e32cc1SDaniel Vetter * 4332c8e32cc1SDaniel Vetter * Called by the user via ioctl. 4333c8e32cc1SDaniel Vetter * 4334c8e32cc1SDaniel Vetter * Returns: 4335c8e32cc1SDaniel Vetter * Zero on success, errno on failure. 4336c8e32cc1SDaniel Vetter */ 4337ff72145bSDave Airlie int drm_mode_mmap_dumb_ioctl(struct drm_device *dev, 4338ff72145bSDave Airlie void *data, struct drm_file *file_priv) 4339ff72145bSDave Airlie { 4340ff72145bSDave Airlie struct drm_mode_map_dumb *args = data; 4341ff72145bSDave Airlie 4342ff72145bSDave Airlie /* call driver ioctl to get mmap offset */ 4343ff72145bSDave Airlie if (!dev->driver->dumb_map_offset) 4344ff72145bSDave Airlie return -ENOSYS; 4345ff72145bSDave Airlie 4346ff72145bSDave Airlie return dev->driver->dumb_map_offset(file_priv, dev, args->handle, &args->offset); 4347ff72145bSDave Airlie } 4348ff72145bSDave Airlie 4349c8e32cc1SDaniel Vetter /** 4350c8e32cc1SDaniel Vetter * drm_mode_destroy_dumb_ioctl - destroy a dumb backing strage buffer 4351c8e32cc1SDaniel Vetter * @dev: DRM device 4352c8e32cc1SDaniel Vetter * @data: ioctl data 4353c8e32cc1SDaniel Vetter * @file_priv: DRM file info 4354c8e32cc1SDaniel Vetter * 4355c8e32cc1SDaniel Vetter * This destroys the userspace handle for the given dumb backing storage buffer. 4356c8e32cc1SDaniel Vetter * Since buffer objects must be reference counted in the kernel a buffer object 4357c8e32cc1SDaniel Vetter * won't be immediately freed if a framebuffer modeset object still uses it. 4358c8e32cc1SDaniel Vetter * 4359c8e32cc1SDaniel Vetter * Called by the user via ioctl. 4360c8e32cc1SDaniel Vetter * 4361c8e32cc1SDaniel Vetter * Returns: 4362c8e32cc1SDaniel Vetter * Zero on success, errno on failure. 4363c8e32cc1SDaniel Vetter */ 4364ff72145bSDave Airlie int drm_mode_destroy_dumb_ioctl(struct drm_device *dev, 4365ff72145bSDave Airlie void *data, struct drm_file *file_priv) 4366ff72145bSDave Airlie { 4367ff72145bSDave Airlie struct drm_mode_destroy_dumb *args = data; 4368ff72145bSDave Airlie 4369ff72145bSDave Airlie if (!dev->driver->dumb_destroy) 4370ff72145bSDave Airlie return -ENOSYS; 4371ff72145bSDave Airlie 4372ff72145bSDave Airlie return dev->driver->dumb_destroy(file_priv, dev, args->handle); 4373ff72145bSDave Airlie } 4374248dbc23SDave Airlie 4375c8e32cc1SDaniel Vetter /** 4376c8e32cc1SDaniel Vetter * drm_fb_get_bpp_depth - get the bpp/depth values for format 4377c8e32cc1SDaniel Vetter * @format: pixel format (DRM_FORMAT_*) 4378c8e32cc1SDaniel Vetter * @depth: storage for the depth value 4379c8e32cc1SDaniel Vetter * @bpp: storage for the bpp value 4380c8e32cc1SDaniel Vetter * 4381c8e32cc1SDaniel Vetter * This only supports RGB formats here for compat with code that doesn't use 4382c8e32cc1SDaniel Vetter * pixel formats directly yet. 4383248dbc23SDave Airlie */ 4384248dbc23SDave Airlie void drm_fb_get_bpp_depth(uint32_t format, unsigned int *depth, 4385248dbc23SDave Airlie int *bpp) 4386248dbc23SDave Airlie { 4387248dbc23SDave Airlie switch (format) { 4388c51a6bc5SVille Syrjälä case DRM_FORMAT_C8: 438904b3924dSVille Syrjälä case DRM_FORMAT_RGB332: 439004b3924dSVille Syrjälä case DRM_FORMAT_BGR233: 4391248dbc23SDave Airlie *depth = 8; 4392248dbc23SDave Airlie *bpp = 8; 4393248dbc23SDave Airlie break; 439404b3924dSVille Syrjälä case DRM_FORMAT_XRGB1555: 439504b3924dSVille Syrjälä case DRM_FORMAT_XBGR1555: 439604b3924dSVille Syrjälä case DRM_FORMAT_RGBX5551: 439704b3924dSVille Syrjälä case DRM_FORMAT_BGRX5551: 439804b3924dSVille Syrjälä case DRM_FORMAT_ARGB1555: 439904b3924dSVille Syrjälä case DRM_FORMAT_ABGR1555: 440004b3924dSVille Syrjälä case DRM_FORMAT_RGBA5551: 440104b3924dSVille Syrjälä case DRM_FORMAT_BGRA5551: 4402248dbc23SDave Airlie *depth = 15; 4403248dbc23SDave Airlie *bpp = 16; 4404248dbc23SDave Airlie break; 440504b3924dSVille Syrjälä case DRM_FORMAT_RGB565: 440604b3924dSVille Syrjälä case DRM_FORMAT_BGR565: 4407248dbc23SDave Airlie *depth = 16; 4408248dbc23SDave Airlie *bpp = 16; 4409248dbc23SDave Airlie break; 441004b3924dSVille Syrjälä case DRM_FORMAT_RGB888: 441104b3924dSVille Syrjälä case DRM_FORMAT_BGR888: 441204b3924dSVille Syrjälä *depth = 24; 441304b3924dSVille Syrjälä *bpp = 24; 441404b3924dSVille Syrjälä break; 441504b3924dSVille Syrjälä case DRM_FORMAT_XRGB8888: 441604b3924dSVille Syrjälä case DRM_FORMAT_XBGR8888: 441704b3924dSVille Syrjälä case DRM_FORMAT_RGBX8888: 441804b3924dSVille Syrjälä case DRM_FORMAT_BGRX8888: 4419248dbc23SDave Airlie *depth = 24; 4420248dbc23SDave Airlie *bpp = 32; 4421248dbc23SDave Airlie break; 442204b3924dSVille Syrjälä case DRM_FORMAT_XRGB2101010: 442304b3924dSVille Syrjälä case DRM_FORMAT_XBGR2101010: 442404b3924dSVille Syrjälä case DRM_FORMAT_RGBX1010102: 442504b3924dSVille Syrjälä case DRM_FORMAT_BGRX1010102: 442604b3924dSVille Syrjälä case DRM_FORMAT_ARGB2101010: 442704b3924dSVille Syrjälä case DRM_FORMAT_ABGR2101010: 442804b3924dSVille Syrjälä case DRM_FORMAT_RGBA1010102: 442904b3924dSVille Syrjälä case DRM_FORMAT_BGRA1010102: 4430248dbc23SDave Airlie *depth = 30; 4431248dbc23SDave Airlie *bpp = 32; 4432248dbc23SDave Airlie break; 443304b3924dSVille Syrjälä case DRM_FORMAT_ARGB8888: 443404b3924dSVille Syrjälä case DRM_FORMAT_ABGR8888: 443504b3924dSVille Syrjälä case DRM_FORMAT_RGBA8888: 443604b3924dSVille Syrjälä case DRM_FORMAT_BGRA8888: 4437248dbc23SDave Airlie *depth = 32; 4438248dbc23SDave Airlie *bpp = 32; 4439248dbc23SDave Airlie break; 4440248dbc23SDave Airlie default: 444123c453a4SVille Syrjälä DRM_DEBUG_KMS("unsupported pixel format %s\n", 444223c453a4SVille Syrjälä drm_get_format_name(format)); 4443248dbc23SDave Airlie *depth = 0; 4444248dbc23SDave Airlie *bpp = 0; 4445248dbc23SDave Airlie break; 4446248dbc23SDave Airlie } 4447248dbc23SDave Airlie } 4448248dbc23SDave Airlie EXPORT_SYMBOL(drm_fb_get_bpp_depth); 4449141670e9SVille Syrjälä 4450141670e9SVille Syrjälä /** 4451141670e9SVille Syrjälä * drm_format_num_planes - get the number of planes for format 4452141670e9SVille Syrjälä * @format: pixel format (DRM_FORMAT_*) 4453141670e9SVille Syrjälä * 4454c8e32cc1SDaniel Vetter * Returns: 4455141670e9SVille Syrjälä * The number of planes used by the specified pixel format. 4456141670e9SVille Syrjälä */ 4457141670e9SVille Syrjälä int drm_format_num_planes(uint32_t format) 4458141670e9SVille Syrjälä { 4459141670e9SVille Syrjälä switch (format) { 4460141670e9SVille Syrjälä case DRM_FORMAT_YUV410: 4461141670e9SVille Syrjälä case DRM_FORMAT_YVU410: 4462141670e9SVille Syrjälä case DRM_FORMAT_YUV411: 4463141670e9SVille Syrjälä case DRM_FORMAT_YVU411: 4464141670e9SVille Syrjälä case DRM_FORMAT_YUV420: 4465141670e9SVille Syrjälä case DRM_FORMAT_YVU420: 4466141670e9SVille Syrjälä case DRM_FORMAT_YUV422: 4467141670e9SVille Syrjälä case DRM_FORMAT_YVU422: 4468141670e9SVille Syrjälä case DRM_FORMAT_YUV444: 4469141670e9SVille Syrjälä case DRM_FORMAT_YVU444: 4470141670e9SVille Syrjälä return 3; 4471141670e9SVille Syrjälä case DRM_FORMAT_NV12: 4472141670e9SVille Syrjälä case DRM_FORMAT_NV21: 4473141670e9SVille Syrjälä case DRM_FORMAT_NV16: 4474141670e9SVille Syrjälä case DRM_FORMAT_NV61: 4475ba623f6aSLaurent Pinchart case DRM_FORMAT_NV24: 4476ba623f6aSLaurent Pinchart case DRM_FORMAT_NV42: 4477141670e9SVille Syrjälä return 2; 4478141670e9SVille Syrjälä default: 4479141670e9SVille Syrjälä return 1; 4480141670e9SVille Syrjälä } 4481141670e9SVille Syrjälä } 4482141670e9SVille Syrjälä EXPORT_SYMBOL(drm_format_num_planes); 44835a86bd55SVille Syrjälä 44845a86bd55SVille Syrjälä /** 44855a86bd55SVille Syrjälä * drm_format_plane_cpp - determine the bytes per pixel value 44865a86bd55SVille Syrjälä * @format: pixel format (DRM_FORMAT_*) 44875a86bd55SVille Syrjälä * @plane: plane index 44885a86bd55SVille Syrjälä * 4489c8e32cc1SDaniel Vetter * Returns: 44905a86bd55SVille Syrjälä * The bytes per pixel value for the specified plane. 44915a86bd55SVille Syrjälä */ 44925a86bd55SVille Syrjälä int drm_format_plane_cpp(uint32_t format, int plane) 44935a86bd55SVille Syrjälä { 44945a86bd55SVille Syrjälä unsigned int depth; 44955a86bd55SVille Syrjälä int bpp; 44965a86bd55SVille Syrjälä 44975a86bd55SVille Syrjälä if (plane >= drm_format_num_planes(format)) 44985a86bd55SVille Syrjälä return 0; 44995a86bd55SVille Syrjälä 45005a86bd55SVille Syrjälä switch (format) { 45015a86bd55SVille Syrjälä case DRM_FORMAT_YUYV: 45025a86bd55SVille Syrjälä case DRM_FORMAT_YVYU: 45035a86bd55SVille Syrjälä case DRM_FORMAT_UYVY: 45045a86bd55SVille Syrjälä case DRM_FORMAT_VYUY: 45055a86bd55SVille Syrjälä return 2; 45065a86bd55SVille Syrjälä case DRM_FORMAT_NV12: 45075a86bd55SVille Syrjälä case DRM_FORMAT_NV21: 45085a86bd55SVille Syrjälä case DRM_FORMAT_NV16: 45095a86bd55SVille Syrjälä case DRM_FORMAT_NV61: 4510ba623f6aSLaurent Pinchart case DRM_FORMAT_NV24: 4511ba623f6aSLaurent Pinchart case DRM_FORMAT_NV42: 45125a86bd55SVille Syrjälä return plane ? 2 : 1; 45135a86bd55SVille Syrjälä case DRM_FORMAT_YUV410: 45145a86bd55SVille Syrjälä case DRM_FORMAT_YVU410: 45155a86bd55SVille Syrjälä case DRM_FORMAT_YUV411: 45165a86bd55SVille Syrjälä case DRM_FORMAT_YVU411: 45175a86bd55SVille Syrjälä case DRM_FORMAT_YUV420: 45185a86bd55SVille Syrjälä case DRM_FORMAT_YVU420: 45195a86bd55SVille Syrjälä case DRM_FORMAT_YUV422: 45205a86bd55SVille Syrjälä case DRM_FORMAT_YVU422: 45215a86bd55SVille Syrjälä case DRM_FORMAT_YUV444: 45225a86bd55SVille Syrjälä case DRM_FORMAT_YVU444: 45235a86bd55SVille Syrjälä return 1; 45245a86bd55SVille Syrjälä default: 45255a86bd55SVille Syrjälä drm_fb_get_bpp_depth(format, &depth, &bpp); 45265a86bd55SVille Syrjälä return bpp >> 3; 45275a86bd55SVille Syrjälä } 45285a86bd55SVille Syrjälä } 45295a86bd55SVille Syrjälä EXPORT_SYMBOL(drm_format_plane_cpp); 453001b68b04SVille Syrjälä 453101b68b04SVille Syrjälä /** 453201b68b04SVille Syrjälä * drm_format_horz_chroma_subsampling - get the horizontal chroma subsampling factor 453301b68b04SVille Syrjälä * @format: pixel format (DRM_FORMAT_*) 453401b68b04SVille Syrjälä * 4535c8e32cc1SDaniel Vetter * Returns: 453601b68b04SVille Syrjälä * The horizontal chroma subsampling factor for the 453701b68b04SVille Syrjälä * specified pixel format. 453801b68b04SVille Syrjälä */ 453901b68b04SVille Syrjälä int drm_format_horz_chroma_subsampling(uint32_t format) 454001b68b04SVille Syrjälä { 454101b68b04SVille Syrjälä switch (format) { 454201b68b04SVille Syrjälä case DRM_FORMAT_YUV411: 454301b68b04SVille Syrjälä case DRM_FORMAT_YVU411: 454401b68b04SVille Syrjälä case DRM_FORMAT_YUV410: 454501b68b04SVille Syrjälä case DRM_FORMAT_YVU410: 454601b68b04SVille Syrjälä return 4; 454701b68b04SVille Syrjälä case DRM_FORMAT_YUYV: 454801b68b04SVille Syrjälä case DRM_FORMAT_YVYU: 454901b68b04SVille Syrjälä case DRM_FORMAT_UYVY: 455001b68b04SVille Syrjälä case DRM_FORMAT_VYUY: 455101b68b04SVille Syrjälä case DRM_FORMAT_NV12: 455201b68b04SVille Syrjälä case DRM_FORMAT_NV21: 455301b68b04SVille Syrjälä case DRM_FORMAT_NV16: 455401b68b04SVille Syrjälä case DRM_FORMAT_NV61: 455501b68b04SVille Syrjälä case DRM_FORMAT_YUV422: 455601b68b04SVille Syrjälä case DRM_FORMAT_YVU422: 455701b68b04SVille Syrjälä case DRM_FORMAT_YUV420: 455801b68b04SVille Syrjälä case DRM_FORMAT_YVU420: 455901b68b04SVille Syrjälä return 2; 456001b68b04SVille Syrjälä default: 456101b68b04SVille Syrjälä return 1; 456201b68b04SVille Syrjälä } 456301b68b04SVille Syrjälä } 456401b68b04SVille Syrjälä EXPORT_SYMBOL(drm_format_horz_chroma_subsampling); 456501b68b04SVille Syrjälä 456601b68b04SVille Syrjälä /** 456701b68b04SVille Syrjälä * drm_format_vert_chroma_subsampling - get the vertical chroma subsampling factor 456801b68b04SVille Syrjälä * @format: pixel format (DRM_FORMAT_*) 456901b68b04SVille Syrjälä * 4570c8e32cc1SDaniel Vetter * Returns: 457101b68b04SVille Syrjälä * The vertical chroma subsampling factor for the 457201b68b04SVille Syrjälä * specified pixel format. 457301b68b04SVille Syrjälä */ 457401b68b04SVille Syrjälä int drm_format_vert_chroma_subsampling(uint32_t format) 457501b68b04SVille Syrjälä { 457601b68b04SVille Syrjälä switch (format) { 457701b68b04SVille Syrjälä case DRM_FORMAT_YUV410: 457801b68b04SVille Syrjälä case DRM_FORMAT_YVU410: 457901b68b04SVille Syrjälä return 4; 458001b68b04SVille Syrjälä case DRM_FORMAT_YUV420: 458101b68b04SVille Syrjälä case DRM_FORMAT_YVU420: 458201b68b04SVille Syrjälä case DRM_FORMAT_NV12: 458301b68b04SVille Syrjälä case DRM_FORMAT_NV21: 458401b68b04SVille Syrjälä return 2; 458501b68b04SVille Syrjälä default: 458601b68b04SVille Syrjälä return 1; 458701b68b04SVille Syrjälä } 458801b68b04SVille Syrjälä } 458901b68b04SVille Syrjälä EXPORT_SYMBOL(drm_format_vert_chroma_subsampling); 459087d24fc3SLaurent Pinchart 459187d24fc3SLaurent Pinchart /** 459287d24fc3SLaurent Pinchart * drm_mode_config_init - initialize DRM mode_configuration structure 459387d24fc3SLaurent Pinchart * @dev: DRM device 459487d24fc3SLaurent Pinchart * 459587d24fc3SLaurent Pinchart * Initialize @dev's mode_config structure, used for tracking the graphics 459687d24fc3SLaurent Pinchart * configuration of @dev. 459787d24fc3SLaurent Pinchart * 459887d24fc3SLaurent Pinchart * Since this initializes the modeset locks, no locking is possible. Which is no 459987d24fc3SLaurent Pinchart * problem, since this should happen single threaded at init time. It is the 460087d24fc3SLaurent Pinchart * driver's problem to ensure this guarantee. 460187d24fc3SLaurent Pinchart * 460287d24fc3SLaurent Pinchart */ 460387d24fc3SLaurent Pinchart void drm_mode_config_init(struct drm_device *dev) 460487d24fc3SLaurent Pinchart { 460587d24fc3SLaurent Pinchart mutex_init(&dev->mode_config.mutex); 460687d24fc3SLaurent Pinchart mutex_init(&dev->mode_config.idr_mutex); 460787d24fc3SLaurent Pinchart mutex_init(&dev->mode_config.fb_lock); 460887d24fc3SLaurent Pinchart INIT_LIST_HEAD(&dev->mode_config.fb_list); 460987d24fc3SLaurent Pinchart INIT_LIST_HEAD(&dev->mode_config.crtc_list); 461087d24fc3SLaurent Pinchart INIT_LIST_HEAD(&dev->mode_config.connector_list); 46113b336ec4SSean Paul INIT_LIST_HEAD(&dev->mode_config.bridge_list); 461287d24fc3SLaurent Pinchart INIT_LIST_HEAD(&dev->mode_config.encoder_list); 461387d24fc3SLaurent Pinchart INIT_LIST_HEAD(&dev->mode_config.property_list); 461487d24fc3SLaurent Pinchart INIT_LIST_HEAD(&dev->mode_config.property_blob_list); 461587d24fc3SLaurent Pinchart INIT_LIST_HEAD(&dev->mode_config.plane_list); 461687d24fc3SLaurent Pinchart idr_init(&dev->mode_config.crtc_idr); 461787d24fc3SLaurent Pinchart 461887d24fc3SLaurent Pinchart drm_modeset_lock_all(dev); 461987d24fc3SLaurent Pinchart drm_mode_create_standard_connector_properties(dev); 46209922ab5aSRob Clark drm_mode_create_standard_plane_properties(dev); 462187d24fc3SLaurent Pinchart drm_modeset_unlock_all(dev); 462287d24fc3SLaurent Pinchart 462387d24fc3SLaurent Pinchart /* Just to be sure */ 462487d24fc3SLaurent Pinchart dev->mode_config.num_fb = 0; 462587d24fc3SLaurent Pinchart dev->mode_config.num_connector = 0; 462687d24fc3SLaurent Pinchart dev->mode_config.num_crtc = 0; 462787d24fc3SLaurent Pinchart dev->mode_config.num_encoder = 0; 4628e27dde3eSMatt Roper dev->mode_config.num_overlay_plane = 0; 4629e27dde3eSMatt Roper dev->mode_config.num_total_plane = 0; 463087d24fc3SLaurent Pinchart } 463187d24fc3SLaurent Pinchart EXPORT_SYMBOL(drm_mode_config_init); 463287d24fc3SLaurent Pinchart 463387d24fc3SLaurent Pinchart /** 463487d24fc3SLaurent Pinchart * drm_mode_config_cleanup - free up DRM mode_config info 463587d24fc3SLaurent Pinchart * @dev: DRM device 463687d24fc3SLaurent Pinchart * 463787d24fc3SLaurent Pinchart * Free up all the connectors and CRTCs associated with this DRM device, then 463887d24fc3SLaurent Pinchart * free up the framebuffers and associated buffer objects. 463987d24fc3SLaurent Pinchart * 464087d24fc3SLaurent Pinchart * Note that since this /should/ happen single-threaded at driver/device 464187d24fc3SLaurent Pinchart * teardown time, no locking is required. It's the driver's job to ensure that 464287d24fc3SLaurent Pinchart * this guarantee actually holds true. 464387d24fc3SLaurent Pinchart * 464487d24fc3SLaurent Pinchart * FIXME: cleanup any dangling user buffer objects too 464587d24fc3SLaurent Pinchart */ 464687d24fc3SLaurent Pinchart void drm_mode_config_cleanup(struct drm_device *dev) 464787d24fc3SLaurent Pinchart { 464887d24fc3SLaurent Pinchart struct drm_connector *connector, *ot; 464987d24fc3SLaurent Pinchart struct drm_crtc *crtc, *ct; 465087d24fc3SLaurent Pinchart struct drm_encoder *encoder, *enct; 46513b336ec4SSean Paul struct drm_bridge *bridge, *brt; 465287d24fc3SLaurent Pinchart struct drm_framebuffer *fb, *fbt; 465387d24fc3SLaurent Pinchart struct drm_property *property, *pt; 465487d24fc3SLaurent Pinchart struct drm_property_blob *blob, *bt; 465587d24fc3SLaurent Pinchart struct drm_plane *plane, *plt; 465687d24fc3SLaurent Pinchart 465787d24fc3SLaurent Pinchart list_for_each_entry_safe(encoder, enct, &dev->mode_config.encoder_list, 465887d24fc3SLaurent Pinchart head) { 465987d24fc3SLaurent Pinchart encoder->funcs->destroy(encoder); 466087d24fc3SLaurent Pinchart } 466187d24fc3SLaurent Pinchart 46623b336ec4SSean Paul list_for_each_entry_safe(bridge, brt, 46633b336ec4SSean Paul &dev->mode_config.bridge_list, head) { 46643b336ec4SSean Paul bridge->funcs->destroy(bridge); 46653b336ec4SSean Paul } 46663b336ec4SSean Paul 466787d24fc3SLaurent Pinchart list_for_each_entry_safe(connector, ot, 466887d24fc3SLaurent Pinchart &dev->mode_config.connector_list, head) { 466987d24fc3SLaurent Pinchart connector->funcs->destroy(connector); 467087d24fc3SLaurent Pinchart } 467187d24fc3SLaurent Pinchart 467287d24fc3SLaurent Pinchart list_for_each_entry_safe(property, pt, &dev->mode_config.property_list, 467387d24fc3SLaurent Pinchart head) { 467487d24fc3SLaurent Pinchart drm_property_destroy(dev, property); 467587d24fc3SLaurent Pinchart } 467687d24fc3SLaurent Pinchart 467787d24fc3SLaurent Pinchart list_for_each_entry_safe(blob, bt, &dev->mode_config.property_blob_list, 467887d24fc3SLaurent Pinchart head) { 467987d24fc3SLaurent Pinchart drm_property_destroy_blob(dev, blob); 468087d24fc3SLaurent Pinchart } 468187d24fc3SLaurent Pinchart 468287d24fc3SLaurent Pinchart /* 468387d24fc3SLaurent Pinchart * Single-threaded teardown context, so it's not required to grab the 468487d24fc3SLaurent Pinchart * fb_lock to protect against concurrent fb_list access. Contrary, it 468587d24fc3SLaurent Pinchart * would actually deadlock with the drm_framebuffer_cleanup function. 468687d24fc3SLaurent Pinchart * 468787d24fc3SLaurent Pinchart * Also, if there are any framebuffers left, that's a driver leak now, 468887d24fc3SLaurent Pinchart * so politely WARN about this. 468987d24fc3SLaurent Pinchart */ 469087d24fc3SLaurent Pinchart WARN_ON(!list_empty(&dev->mode_config.fb_list)); 469187d24fc3SLaurent Pinchart list_for_each_entry_safe(fb, fbt, &dev->mode_config.fb_list, head) { 469287d24fc3SLaurent Pinchart drm_framebuffer_remove(fb); 469387d24fc3SLaurent Pinchart } 469487d24fc3SLaurent Pinchart 469587d24fc3SLaurent Pinchart list_for_each_entry_safe(plane, plt, &dev->mode_config.plane_list, 469687d24fc3SLaurent Pinchart head) { 469787d24fc3SLaurent Pinchart plane->funcs->destroy(plane); 469887d24fc3SLaurent Pinchart } 469987d24fc3SLaurent Pinchart 470087d24fc3SLaurent Pinchart list_for_each_entry_safe(crtc, ct, &dev->mode_config.crtc_list, head) { 470187d24fc3SLaurent Pinchart crtc->funcs->destroy(crtc); 470287d24fc3SLaurent Pinchart } 470387d24fc3SLaurent Pinchart 470487d24fc3SLaurent Pinchart idr_destroy(&dev->mode_config.crtc_idr); 470587d24fc3SLaurent Pinchart } 470687d24fc3SLaurent Pinchart EXPORT_SYMBOL(drm_mode_config_cleanup); 4707