152217195SDaniel Vetter /* 252217195SDaniel Vetter * Copyright (c) 2016 Intel Corporation 352217195SDaniel Vetter * 452217195SDaniel Vetter * Permission to use, copy, modify, distribute, and sell this software and its 552217195SDaniel Vetter * documentation for any purpose is hereby granted without fee, provided that 652217195SDaniel Vetter * the above copyright notice appear in all copies and that both that copyright 752217195SDaniel Vetter * notice and this permission notice appear in supporting documentation, and 852217195SDaniel Vetter * that the name of the copyright holders not be used in advertising or 952217195SDaniel Vetter * publicity pertaining to distribution of the software without specific, 1052217195SDaniel Vetter * written prior permission. The copyright holders make no representations 1152217195SDaniel Vetter * about the suitability of this software for any purpose. It is provided "as 1252217195SDaniel Vetter * is" without express or implied warranty. 1352217195SDaniel Vetter * 1452217195SDaniel Vetter * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, 1552217195SDaniel Vetter * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO 1652217195SDaniel Vetter * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR 1752217195SDaniel Vetter * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, 1852217195SDaniel Vetter * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER 1952217195SDaniel Vetter * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE 2052217195SDaniel Vetter * OF THIS SOFTWARE. 2152217195SDaniel Vetter */ 2252217195SDaniel Vetter 238f86c82aSSimon Ser #include <drm/drm_auth.h> 2452217195SDaniel Vetter #include <drm/drm_connector.h> 25d71d8a4bSMaxime Ripard #include <drm/drm_drv.h> 2652217195SDaniel Vetter #include <drm/drm_edid.h> 279338203cSLaurent Pinchart #include <drm/drm_encoder.h> 2899f45e32SDaniel Vetter #include <drm/drm_file.h> 2935a3b82fSMaxime Ripard #include <drm/drm_managed.h> 30d71d8a4bSMaxime Ripard #include <drm/drm_panel.h> 31d71d8a4bSMaxime Ripard #include <drm/drm_print.h> 32334f74eeSHans de Goede #include <drm/drm_privacy_screen_consumer.h> 33968d81a6SJeykumar Sankaran #include <drm/drm_sysfs.h> 34d71d8a4bSMaxime Ripard #include <drm/drm_utils.h> 3599f45e32SDaniel Vetter 3673289afeSVille Syrjälä #include <linux/fb.h> 3799f45e32SDaniel Vetter #include <linux/uaccess.h> 3852217195SDaniel Vetter 3952217195SDaniel Vetter #include "drm_crtc_internal.h" 4052217195SDaniel Vetter #include "drm_internal.h" 4152217195SDaniel Vetter 42ae2a6da8SDaniel Vetter /** 43ae2a6da8SDaniel Vetter * DOC: overview 44ae2a6da8SDaniel Vetter * 45ae2a6da8SDaniel Vetter * In DRM connectors are the general abstraction for display sinks, and include 4684e543bcSAntonio Borneo * also fixed panels or anything else that can display pixels in some form. As 47ae2a6da8SDaniel Vetter * opposed to all other KMS objects representing hardware (like CRTC, encoder or 48ae2a6da8SDaniel Vetter * plane abstractions) connectors can be hotplugged and unplugged at runtime. 49ad093607SThierry Reding * Hence they are reference-counted using drm_connector_get() and 50ad093607SThierry Reding * drm_connector_put(). 51ae2a6da8SDaniel Vetter * 52d574528aSDaniel Vetter * KMS driver must create, initialize, register and attach at a &struct 53d574528aSDaniel Vetter * drm_connector for each such sink. The instance is created as other KMS 54aec97460SDaniel Vetter * objects and initialized by setting the following fields. The connector is 55aec97460SDaniel Vetter * initialized with a call to drm_connector_init() with a pointer to the 56aec97460SDaniel Vetter * &struct drm_connector_funcs and a connector type, and then exposed to 57aec97460SDaniel Vetter * userspace with a call to drm_connector_register(). 58ae2a6da8SDaniel Vetter * 59ae2a6da8SDaniel Vetter * Connectors must be attached to an encoder to be used. For devices that map 60ae2a6da8SDaniel Vetter * connectors to encoders 1:1, the connector should be attached at 61cde4c44dSDaniel Vetter * initialization time with a call to drm_connector_attach_encoder(). The 62d574528aSDaniel Vetter * driver must also set the &drm_connector.encoder field to point to the 63ae2a6da8SDaniel Vetter * attached encoder. 64ae2a6da8SDaniel Vetter * 65ae2a6da8SDaniel Vetter * For connectors which are not fixed (like built-in panels) the driver needs to 66ae2a6da8SDaniel Vetter * support hotplug notifications. The simplest way to do that is by using the 67ae2a6da8SDaniel Vetter * probe helpers, see drm_kms_helper_poll_init() for connectors which don't have 68ae2a6da8SDaniel Vetter * hardware support for hotplug interrupts. Connectors with hardware hotplug 69ae2a6da8SDaniel Vetter * support can instead use e.g. drm_helper_hpd_irq_event(). 70ae2a6da8SDaniel Vetter */ 71ae2a6da8SDaniel Vetter 723d3f7c1eSHans de Goede /* 733d3f7c1eSHans de Goede * Global connector list for drm_connector_find_by_fwnode(). 743d3f7c1eSHans de Goede * Note drm_connector_[un]register() first take connector->lock and then 753d3f7c1eSHans de Goede * take the connector_list_lock. 763d3f7c1eSHans de Goede */ 773d3f7c1eSHans de Goede static DEFINE_MUTEX(connector_list_lock); 783d3f7c1eSHans de Goede static LIST_HEAD(connector_list); 793d3f7c1eSHans de Goede 8052217195SDaniel Vetter struct drm_conn_prop_enum_list { 8152217195SDaniel Vetter int type; 8252217195SDaniel Vetter const char *name; 8352217195SDaniel Vetter struct ida ida; 8452217195SDaniel Vetter }; 8552217195SDaniel Vetter 8652217195SDaniel Vetter /* 8752217195SDaniel Vetter * Connector and encoder types. 8852217195SDaniel Vetter */ 8952217195SDaniel Vetter static struct drm_conn_prop_enum_list drm_connector_enum_list[] = { 9052217195SDaniel Vetter { DRM_MODE_CONNECTOR_Unknown, "Unknown" }, 9152217195SDaniel Vetter { DRM_MODE_CONNECTOR_VGA, "VGA" }, 9252217195SDaniel Vetter { DRM_MODE_CONNECTOR_DVII, "DVI-I" }, 9352217195SDaniel Vetter { DRM_MODE_CONNECTOR_DVID, "DVI-D" }, 9452217195SDaniel Vetter { DRM_MODE_CONNECTOR_DVIA, "DVI-A" }, 9552217195SDaniel Vetter { DRM_MODE_CONNECTOR_Composite, "Composite" }, 9652217195SDaniel Vetter { DRM_MODE_CONNECTOR_SVIDEO, "SVIDEO" }, 9752217195SDaniel Vetter { DRM_MODE_CONNECTOR_LVDS, "LVDS" }, 9852217195SDaniel Vetter { DRM_MODE_CONNECTOR_Component, "Component" }, 9952217195SDaniel Vetter { DRM_MODE_CONNECTOR_9PinDIN, "DIN" }, 10052217195SDaniel Vetter { DRM_MODE_CONNECTOR_DisplayPort, "DP" }, 10152217195SDaniel Vetter { DRM_MODE_CONNECTOR_HDMIA, "HDMI-A" }, 10252217195SDaniel Vetter { DRM_MODE_CONNECTOR_HDMIB, "HDMI-B" }, 10352217195SDaniel Vetter { DRM_MODE_CONNECTOR_TV, "TV" }, 10452217195SDaniel Vetter { DRM_MODE_CONNECTOR_eDP, "eDP" }, 10552217195SDaniel Vetter { DRM_MODE_CONNECTOR_VIRTUAL, "Virtual" }, 10652217195SDaniel Vetter { DRM_MODE_CONNECTOR_DSI, "DSI" }, 10752217195SDaniel Vetter { DRM_MODE_CONNECTOR_DPI, "DPI" }, 108935774cdSBrian Starkey { DRM_MODE_CONNECTOR_WRITEBACK, "Writeback" }, 109fc06bf1dSNoralf Trønnes { DRM_MODE_CONNECTOR_SPI, "SPI" }, 110757e2671SNoralf Trønnes { DRM_MODE_CONNECTOR_USB, "USB" }, 11152217195SDaniel Vetter }; 11252217195SDaniel Vetter 11352217195SDaniel Vetter void drm_connector_ida_init(void) 11452217195SDaniel Vetter { 11552217195SDaniel Vetter int i; 11652217195SDaniel Vetter 11752217195SDaniel Vetter for (i = 0; i < ARRAY_SIZE(drm_connector_enum_list); i++) 11852217195SDaniel Vetter ida_init(&drm_connector_enum_list[i].ida); 11952217195SDaniel Vetter } 12052217195SDaniel Vetter 12152217195SDaniel Vetter void drm_connector_ida_destroy(void) 12252217195SDaniel Vetter { 12352217195SDaniel Vetter int i; 12452217195SDaniel Vetter 12552217195SDaniel Vetter for (i = 0; i < ARRAY_SIZE(drm_connector_enum_list); i++) 12652217195SDaniel Vetter ida_destroy(&drm_connector_enum_list[i].ida); 12752217195SDaniel Vetter } 12852217195SDaniel Vetter 12952217195SDaniel Vetter /** 130b35f90f2SLaurent Pinchart * drm_get_connector_type_name - return a string for connector type 131b35f90f2SLaurent Pinchart * @type: The connector type (DRM_MODE_CONNECTOR_*) 132b35f90f2SLaurent Pinchart * 133b35f90f2SLaurent Pinchart * Returns: the name of the connector type, or NULL if the type is not valid. 134b35f90f2SLaurent Pinchart */ 135b35f90f2SLaurent Pinchart const char *drm_get_connector_type_name(unsigned int type) 136b35f90f2SLaurent Pinchart { 137b35f90f2SLaurent Pinchart if (type < ARRAY_SIZE(drm_connector_enum_list)) 138b35f90f2SLaurent Pinchart return drm_connector_enum_list[type].name; 139b35f90f2SLaurent Pinchart 140b35f90f2SLaurent Pinchart return NULL; 141b35f90f2SLaurent Pinchart } 142b35f90f2SLaurent Pinchart EXPORT_SYMBOL(drm_get_connector_type_name); 143b35f90f2SLaurent Pinchart 144b35f90f2SLaurent Pinchart /** 14552217195SDaniel Vetter * drm_connector_get_cmdline_mode - reads the user's cmdline mode 14684e543bcSAntonio Borneo * @connector: connector to query 14752217195SDaniel Vetter * 148ae2a6da8SDaniel Vetter * The kernel supports per-connector configuration of its consoles through 14952217195SDaniel Vetter * use of the video= parameter. This function parses that option and 15052217195SDaniel Vetter * extracts the user's specified mode (or enable/disable status) for a 15152217195SDaniel Vetter * particular connector. This is typically only used during the early fbdev 15252217195SDaniel Vetter * setup. 15352217195SDaniel Vetter */ 15452217195SDaniel Vetter static void drm_connector_get_cmdline_mode(struct drm_connector *connector) 15552217195SDaniel Vetter { 15652217195SDaniel Vetter struct drm_cmdline_mode *mode = &connector->cmdline_mode; 15752217195SDaniel Vetter char *option = NULL; 15852217195SDaniel Vetter 15952217195SDaniel Vetter if (fb_get_options(connector->name, &option)) 16052217195SDaniel Vetter return; 16152217195SDaniel Vetter 16252217195SDaniel Vetter if (!drm_mode_parse_command_line_for_connector(option, 16352217195SDaniel Vetter connector, 16452217195SDaniel Vetter mode)) 16552217195SDaniel Vetter return; 16652217195SDaniel Vetter 16752217195SDaniel Vetter if (mode->force) { 1686140cf20SJani Nikula DRM_INFO("forcing %s connector %s\n", connector->name, 1696140cf20SJani Nikula drm_get_connector_force_name(mode->force)); 17052217195SDaniel Vetter connector->force = mode->force; 17152217195SDaniel Vetter } 17252217195SDaniel Vetter 1730980939dSHans de Goede if (mode->panel_orientation != DRM_MODE_PANEL_ORIENTATION_UNKNOWN) { 1740980939dSHans de Goede DRM_INFO("cmdline forces connector %s panel_orientation to %d\n", 1750980939dSHans de Goede connector->name, mode->panel_orientation); 1760980939dSHans de Goede drm_connector_set_panel_orientation(connector, 1770980939dSHans de Goede mode->panel_orientation); 1780980939dSHans de Goede } 1790980939dSHans de Goede 1803aeeb13dSMaxime Ripard DRM_DEBUG_KMS("cmdline mode for connector %s %s %dx%d@%dHz%s%s%s\n", 18150b0946dSMaxime Ripard connector->name, mode->name, 18252217195SDaniel Vetter mode->xres, mode->yres, 18352217195SDaniel Vetter mode->refresh_specified ? mode->refresh : 60, 18452217195SDaniel Vetter mode->rb ? " reduced blanking" : "", 18552217195SDaniel Vetter mode->margins ? " with margins" : "", 18652217195SDaniel Vetter mode->interlace ? " interlaced" : ""); 18752217195SDaniel Vetter } 18852217195SDaniel Vetter 18952217195SDaniel Vetter static void drm_connector_free(struct kref *kref) 19052217195SDaniel Vetter { 19152217195SDaniel Vetter struct drm_connector *connector = 19252217195SDaniel Vetter container_of(kref, struct drm_connector, base.refcount); 19352217195SDaniel Vetter struct drm_device *dev = connector->dev; 19452217195SDaniel Vetter 19552217195SDaniel Vetter drm_mode_object_unregister(dev, &connector->base); 19652217195SDaniel Vetter connector->funcs->destroy(connector); 19752217195SDaniel Vetter } 19852217195SDaniel Vetter 199ea497bb9SDaniel Vetter void drm_connector_free_work_fn(struct work_struct *work) 200a703c550SDaniel Vetter { 201ea497bb9SDaniel Vetter struct drm_connector *connector, *n; 202ea497bb9SDaniel Vetter struct drm_device *dev = 203ea497bb9SDaniel Vetter container_of(work, struct drm_device, mode_config.connector_free_work); 204ea497bb9SDaniel Vetter struct drm_mode_config *config = &dev->mode_config; 205ea497bb9SDaniel Vetter unsigned long flags; 206ea497bb9SDaniel Vetter struct llist_node *freed; 207a703c550SDaniel Vetter 208ea497bb9SDaniel Vetter spin_lock_irqsave(&config->connector_list_lock, flags); 209ea497bb9SDaniel Vetter freed = llist_del_all(&config->connector_free_list); 210ea497bb9SDaniel Vetter spin_unlock_irqrestore(&config->connector_list_lock, flags); 211ea497bb9SDaniel Vetter 212ea497bb9SDaniel Vetter llist_for_each_entry_safe(connector, n, freed, free_node) { 213a703c550SDaniel Vetter drm_mode_object_unregister(dev, &connector->base); 214a703c550SDaniel Vetter connector->funcs->destroy(connector); 215a703c550SDaniel Vetter } 216ea497bb9SDaniel Vetter } 217a703c550SDaniel Vetter 218b11af8a2SMaxime Ripard static int __drm_connector_init(struct drm_device *dev, 21952217195SDaniel Vetter struct drm_connector *connector, 22052217195SDaniel Vetter const struct drm_connector_funcs *funcs, 221b11af8a2SMaxime Ripard int connector_type, 222b11af8a2SMaxime Ripard struct i2c_adapter *ddc) 22352217195SDaniel Vetter { 22452217195SDaniel Vetter struct drm_mode_config *config = &dev->mode_config; 22552217195SDaniel Vetter int ret; 22652217195SDaniel Vetter struct ida *connector_ida = 22752217195SDaniel Vetter &drm_connector_enum_list[connector_type].ida; 22852217195SDaniel Vetter 229ba1f665fSHaneen Mohammed WARN_ON(drm_drv_uses_atomic_modeset(dev) && 230ba1f665fSHaneen Mohammed (!funcs->atomic_destroy_state || 231ba1f665fSHaneen Mohammed !funcs->atomic_duplicate_state)); 232ba1f665fSHaneen Mohammed 2332135ea7aSThierry Reding ret = __drm_mode_object_add(dev, &connector->base, 23452217195SDaniel Vetter DRM_MODE_OBJECT_CONNECTOR, 23552217195SDaniel Vetter false, drm_connector_free); 23652217195SDaniel Vetter if (ret) 237613051daSDaniel Vetter return ret; 23852217195SDaniel Vetter 23952217195SDaniel Vetter connector->base.properties = &connector->properties; 24052217195SDaniel Vetter connector->dev = dev; 24152217195SDaniel Vetter connector->funcs = funcs; 24252217195SDaniel Vetter 2432a8d3eacSVille Syrjälä /* connector index is used with 32bit bitmasks */ 244e5d6eeeaSBo Liu ret = ida_alloc_max(&config->connector_ida, 31, GFP_KERNEL); 2452a8d3eacSVille Syrjälä if (ret < 0) { 2462a8d3eacSVille Syrjälä DRM_DEBUG_KMS("Failed to allocate %s connector index: %d\n", 2472a8d3eacSVille Syrjälä drm_connector_enum_list[connector_type].name, 2482a8d3eacSVille Syrjälä ret); 24952217195SDaniel Vetter goto out_put; 2502a8d3eacSVille Syrjälä } 25152217195SDaniel Vetter connector->index = ret; 25252217195SDaniel Vetter ret = 0; 25352217195SDaniel Vetter 25452217195SDaniel Vetter connector->connector_type = connector_type; 25552217195SDaniel Vetter connector->connector_type_id = 256e5d6eeeaSBo Liu ida_alloc_min(connector_ida, 1, GFP_KERNEL); 25752217195SDaniel Vetter if (connector->connector_type_id < 0) { 25852217195SDaniel Vetter ret = connector->connector_type_id; 25952217195SDaniel Vetter goto out_put_id; 26052217195SDaniel Vetter } 26152217195SDaniel Vetter connector->name = 26252217195SDaniel Vetter kasprintf(GFP_KERNEL, "%s-%d", 26352217195SDaniel Vetter drm_connector_enum_list[connector_type].name, 26452217195SDaniel Vetter connector->connector_type_id); 26552217195SDaniel Vetter if (!connector->name) { 26652217195SDaniel Vetter ret = -ENOMEM; 26752217195SDaniel Vetter goto out_put_type_id; 26852217195SDaniel Vetter } 26952217195SDaniel Vetter 270b11af8a2SMaxime Ripard /* provide ddc symlink in sysfs */ 271b11af8a2SMaxime Ripard connector->ddc = ddc; 272b11af8a2SMaxime Ripard 2733d3f7c1eSHans de Goede INIT_LIST_HEAD(&connector->global_connector_list_entry); 27452217195SDaniel Vetter INIT_LIST_HEAD(&connector->probed_modes); 27552217195SDaniel Vetter INIT_LIST_HEAD(&connector->modes); 276e73ab00eSDaniel Vetter mutex_init(&connector->mutex); 277*90b575f5SJani Nikula mutex_init(&connector->edid_override_mutex); 27852217195SDaniel Vetter connector->edid_blob_ptr = NULL; 2795186421cSStanislav Lisovskiy connector->epoch_counter = 0; 2802de3a078SManasi Navare connector->tile_blob_ptr = NULL; 28152217195SDaniel Vetter connector->status = connector_status_unknown; 2828d70f395SHans de Goede connector->display_info.panel_orientation = 2838d70f395SHans de Goede DRM_MODE_PANEL_ORIENTATION_UNKNOWN; 28452217195SDaniel Vetter 28552217195SDaniel Vetter drm_connector_get_cmdline_mode(connector); 28652217195SDaniel Vetter 28752217195SDaniel Vetter /* We should add connectors at the end to avoid upsetting the connector 288c2ce66daSBeatriz Martins de Carvalho * index too much. 289c2ce66daSBeatriz Martins de Carvalho */ 290613051daSDaniel Vetter spin_lock_irq(&config->connector_list_lock); 29152217195SDaniel Vetter list_add_tail(&connector->head, &config->connector_list); 29252217195SDaniel Vetter config->num_connector++; 293613051daSDaniel Vetter spin_unlock_irq(&config->connector_list_lock); 29452217195SDaniel Vetter 295935774cdSBrian Starkey if (connector_type != DRM_MODE_CONNECTOR_VIRTUAL && 296935774cdSBrian Starkey connector_type != DRM_MODE_CONNECTOR_WRITEBACK) 2976b7e2d5cSGerd Hoffmann drm_connector_attach_edid_property(connector); 29852217195SDaniel Vetter 29952217195SDaniel Vetter drm_object_attach_property(&connector->base, 30052217195SDaniel Vetter config->dpms_property, 0); 30152217195SDaniel Vetter 30240ee6fbeSManasi Navare drm_object_attach_property(&connector->base, 30340ee6fbeSManasi Navare config->link_status_property, 30440ee6fbeSManasi Navare 0); 30540ee6fbeSManasi Navare 30666660d4cSDave Airlie drm_object_attach_property(&connector->base, 30766660d4cSDave Airlie config->non_desktop_property, 30866660d4cSDave Airlie 0); 3092de3a078SManasi Navare drm_object_attach_property(&connector->base, 3102de3a078SManasi Navare config->tile_property, 3112de3a078SManasi Navare 0); 31266660d4cSDave Airlie 31352217195SDaniel Vetter if (drm_core_check_feature(dev, DRIVER_ATOMIC)) { 31452217195SDaniel Vetter drm_object_attach_property(&connector->base, config->prop_crtc_id, 0); 31552217195SDaniel Vetter } 31652217195SDaniel Vetter 31752217195SDaniel Vetter connector->debugfs_entry = NULL; 31852217195SDaniel Vetter out_put_type_id: 31952217195SDaniel Vetter if (ret) 320e5d6eeeaSBo Liu ida_free(connector_ida, connector->connector_type_id); 32152217195SDaniel Vetter out_put_id: 32252217195SDaniel Vetter if (ret) 323e5d6eeeaSBo Liu ida_free(&config->connector_ida, connector->index); 32452217195SDaniel Vetter out_put: 32552217195SDaniel Vetter if (ret) 32652217195SDaniel Vetter drm_mode_object_unregister(dev, &connector->base); 32752217195SDaniel Vetter 32852217195SDaniel Vetter return ret; 32952217195SDaniel Vetter } 330b11af8a2SMaxime Ripard 331b11af8a2SMaxime Ripard /** 332b11af8a2SMaxime Ripard * drm_connector_init - Init a preallocated connector 333b11af8a2SMaxime Ripard * @dev: DRM device 334b11af8a2SMaxime Ripard * @connector: the connector to init 335b11af8a2SMaxime Ripard * @funcs: callbacks for this connector 336b11af8a2SMaxime Ripard * @connector_type: user visible type of the connector 337b11af8a2SMaxime Ripard * 338b11af8a2SMaxime Ripard * Initialises a preallocated connector. Connectors should be 339b11af8a2SMaxime Ripard * subclassed as part of driver connector objects. 340b11af8a2SMaxime Ripard * 341b11af8a2SMaxime Ripard * At driver unload time the driver's &drm_connector_funcs.destroy hook 342b11af8a2SMaxime Ripard * should call drm_connector_cleanup() and free the connector structure. 343b11af8a2SMaxime Ripard * The connector structure should not be allocated with devm_kzalloc(). 344b11af8a2SMaxime Ripard * 34535a3b82fSMaxime Ripard * Note: consider using drmm_connector_init() instead of 34635a3b82fSMaxime Ripard * drm_connector_init() to let the DRM managed resource infrastructure 34735a3b82fSMaxime Ripard * take care of cleanup and deallocation. 34835a3b82fSMaxime Ripard * 349b11af8a2SMaxime Ripard * Returns: 350b11af8a2SMaxime Ripard * Zero on success, error code on failure. 351b11af8a2SMaxime Ripard */ 352b11af8a2SMaxime Ripard int drm_connector_init(struct drm_device *dev, 353b11af8a2SMaxime Ripard struct drm_connector *connector, 354b11af8a2SMaxime Ripard const struct drm_connector_funcs *funcs, 355b11af8a2SMaxime Ripard int connector_type) 356b11af8a2SMaxime Ripard { 357a961b197SMaxime Ripard if (drm_WARN_ON(dev, !(funcs && funcs->destroy))) 358a961b197SMaxime Ripard return -EINVAL; 359a961b197SMaxime Ripard 360b11af8a2SMaxime Ripard return __drm_connector_init(dev, connector, funcs, connector_type, NULL); 361b11af8a2SMaxime Ripard } 36252217195SDaniel Vetter EXPORT_SYMBOL(drm_connector_init); 36352217195SDaniel Vetter 36452217195SDaniel Vetter /** 365100163dfSAndrzej Pietrasiewicz * drm_connector_init_with_ddc - Init a preallocated connector 366100163dfSAndrzej Pietrasiewicz * @dev: DRM device 367100163dfSAndrzej Pietrasiewicz * @connector: the connector to init 368100163dfSAndrzej Pietrasiewicz * @funcs: callbacks for this connector 369100163dfSAndrzej Pietrasiewicz * @connector_type: user visible type of the connector 370100163dfSAndrzej Pietrasiewicz * @ddc: pointer to the associated ddc adapter 371100163dfSAndrzej Pietrasiewicz * 372100163dfSAndrzej Pietrasiewicz * Initialises a preallocated connector. Connectors should be 373100163dfSAndrzej Pietrasiewicz * subclassed as part of driver connector objects. 374100163dfSAndrzej Pietrasiewicz * 37500ec947cSMaxime Ripard * At driver unload time the driver's &drm_connector_funcs.destroy hook 37600ec947cSMaxime Ripard * should call drm_connector_cleanup() and free the connector structure. 37700ec947cSMaxime Ripard * The connector structure should not be allocated with devm_kzalloc(). 37800ec947cSMaxime Ripard * 379100163dfSAndrzej Pietrasiewicz * Ensures that the ddc field of the connector is correctly set. 380100163dfSAndrzej Pietrasiewicz * 38135a3b82fSMaxime Ripard * Note: consider using drmm_connector_init() instead of 38235a3b82fSMaxime Ripard * drm_connector_init_with_ddc() to let the DRM managed resource 38335a3b82fSMaxime Ripard * infrastructure take care of cleanup and deallocation. 38435a3b82fSMaxime Ripard * 385100163dfSAndrzej Pietrasiewicz * Returns: 386100163dfSAndrzej Pietrasiewicz * Zero on success, error code on failure. 387100163dfSAndrzej Pietrasiewicz */ 388100163dfSAndrzej Pietrasiewicz int drm_connector_init_with_ddc(struct drm_device *dev, 389100163dfSAndrzej Pietrasiewicz struct drm_connector *connector, 390100163dfSAndrzej Pietrasiewicz const struct drm_connector_funcs *funcs, 391100163dfSAndrzej Pietrasiewicz int connector_type, 392100163dfSAndrzej Pietrasiewicz struct i2c_adapter *ddc) 393100163dfSAndrzej Pietrasiewicz { 394a961b197SMaxime Ripard if (drm_WARN_ON(dev, !(funcs && funcs->destroy))) 395a961b197SMaxime Ripard return -EINVAL; 396a961b197SMaxime Ripard 397b11af8a2SMaxime Ripard return __drm_connector_init(dev, connector, funcs, connector_type, ddc); 398100163dfSAndrzej Pietrasiewicz } 399100163dfSAndrzej Pietrasiewicz EXPORT_SYMBOL(drm_connector_init_with_ddc); 400100163dfSAndrzej Pietrasiewicz 40135a3b82fSMaxime Ripard static void drm_connector_cleanup_action(struct drm_device *dev, 40235a3b82fSMaxime Ripard void *ptr) 40335a3b82fSMaxime Ripard { 40435a3b82fSMaxime Ripard struct drm_connector *connector = ptr; 40535a3b82fSMaxime Ripard 40635a3b82fSMaxime Ripard drm_connector_cleanup(connector); 40735a3b82fSMaxime Ripard } 40835a3b82fSMaxime Ripard 40935a3b82fSMaxime Ripard /** 41035a3b82fSMaxime Ripard * drmm_connector_init - Init a preallocated connector 41135a3b82fSMaxime Ripard * @dev: DRM device 41235a3b82fSMaxime Ripard * @connector: the connector to init 41335a3b82fSMaxime Ripard * @funcs: callbacks for this connector 41435a3b82fSMaxime Ripard * @connector_type: user visible type of the connector 41535a3b82fSMaxime Ripard * @ddc: optional pointer to the associated ddc adapter 41635a3b82fSMaxime Ripard * 41735a3b82fSMaxime Ripard * Initialises a preallocated connector. Connectors should be 41835a3b82fSMaxime Ripard * subclassed as part of driver connector objects. 41935a3b82fSMaxime Ripard * 42035a3b82fSMaxime Ripard * Cleanup is automatically handled with a call to 42135a3b82fSMaxime Ripard * drm_connector_cleanup() in a DRM-managed action. 42235a3b82fSMaxime Ripard * 42335a3b82fSMaxime Ripard * The connector structure should be allocated with drmm_kzalloc(). 42435a3b82fSMaxime Ripard * 42535a3b82fSMaxime Ripard * Returns: 42635a3b82fSMaxime Ripard * Zero on success, error code on failure. 42735a3b82fSMaxime Ripard */ 42835a3b82fSMaxime Ripard int drmm_connector_init(struct drm_device *dev, 42935a3b82fSMaxime Ripard struct drm_connector *connector, 43035a3b82fSMaxime Ripard const struct drm_connector_funcs *funcs, 43135a3b82fSMaxime Ripard int connector_type, 43235a3b82fSMaxime Ripard struct i2c_adapter *ddc) 43335a3b82fSMaxime Ripard { 43435a3b82fSMaxime Ripard int ret; 43535a3b82fSMaxime Ripard 43635a3b82fSMaxime Ripard if (drm_WARN_ON(dev, funcs && funcs->destroy)) 43735a3b82fSMaxime Ripard return -EINVAL; 43835a3b82fSMaxime Ripard 43935a3b82fSMaxime Ripard ret = __drm_connector_init(dev, connector, funcs, connector_type, NULL); 44035a3b82fSMaxime Ripard if (ret) 44135a3b82fSMaxime Ripard return ret; 44235a3b82fSMaxime Ripard 44335a3b82fSMaxime Ripard ret = drmm_add_action_or_reset(dev, drm_connector_cleanup_action, 44435a3b82fSMaxime Ripard connector); 44535a3b82fSMaxime Ripard if (ret) 44635a3b82fSMaxime Ripard return ret; 44735a3b82fSMaxime Ripard 44835a3b82fSMaxime Ripard return 0; 44935a3b82fSMaxime Ripard } 45035a3b82fSMaxime Ripard EXPORT_SYMBOL(drmm_connector_init); 45135a3b82fSMaxime Ripard 452100163dfSAndrzej Pietrasiewicz /** 4536b7e2d5cSGerd Hoffmann * drm_connector_attach_edid_property - attach edid property. 4546b7e2d5cSGerd Hoffmann * @connector: the connector 4556b7e2d5cSGerd Hoffmann * 4566b7e2d5cSGerd Hoffmann * Some connector types like DRM_MODE_CONNECTOR_VIRTUAL do not get a 4576b7e2d5cSGerd Hoffmann * edid property attached by default. This function can be used to 4586b7e2d5cSGerd Hoffmann * explicitly enable the edid property in these cases. 4596b7e2d5cSGerd Hoffmann */ 4606b7e2d5cSGerd Hoffmann void drm_connector_attach_edid_property(struct drm_connector *connector) 4616b7e2d5cSGerd Hoffmann { 4626b7e2d5cSGerd Hoffmann struct drm_mode_config *config = &connector->dev->mode_config; 4636b7e2d5cSGerd Hoffmann 4646b7e2d5cSGerd Hoffmann drm_object_attach_property(&connector->base, 4656b7e2d5cSGerd Hoffmann config->edid_property, 4666b7e2d5cSGerd Hoffmann 0); 4676b7e2d5cSGerd Hoffmann } 4686b7e2d5cSGerd Hoffmann EXPORT_SYMBOL(drm_connector_attach_edid_property); 4696b7e2d5cSGerd Hoffmann 4706b7e2d5cSGerd Hoffmann /** 471cde4c44dSDaniel Vetter * drm_connector_attach_encoder - attach a connector to an encoder 47252217195SDaniel Vetter * @connector: connector to attach 47352217195SDaniel Vetter * @encoder: encoder to attach @connector to 47452217195SDaniel Vetter * 47552217195SDaniel Vetter * This function links up a connector to an encoder. Note that the routing 47652217195SDaniel Vetter * restrictions between encoders and crtcs are exposed to userspace through the 47752217195SDaniel Vetter * possible_clones and possible_crtcs bitmasks. 47852217195SDaniel Vetter * 47952217195SDaniel Vetter * Returns: 48052217195SDaniel Vetter * Zero on success, negative errno on failure. 48152217195SDaniel Vetter */ 482cde4c44dSDaniel Vetter int drm_connector_attach_encoder(struct drm_connector *connector, 48352217195SDaniel Vetter struct drm_encoder *encoder) 48452217195SDaniel Vetter { 48552217195SDaniel Vetter /* 48652217195SDaniel Vetter * In the past, drivers have attempted to model the static association 48752217195SDaniel Vetter * of connector to encoder in simple connector/encoder devices using a 48852217195SDaniel Vetter * direct assignment of connector->encoder = encoder. This connection 48952217195SDaniel Vetter * is a logical one and the responsibility of the core, so drivers are 49052217195SDaniel Vetter * expected not to mess with this. 49152217195SDaniel Vetter * 49252217195SDaniel Vetter * Note that the error return should've been enough here, but a large 49352217195SDaniel Vetter * majority of drivers ignores the return value, so add in a big WARN 49452217195SDaniel Vetter * to get people's attention. 49552217195SDaniel Vetter */ 49652217195SDaniel Vetter if (WARN_ON(connector->encoder)) 49752217195SDaniel Vetter return -EINVAL; 49852217195SDaniel Vetter 49962afb4adSJosé Roberto de Souza connector->possible_encoders |= drm_encoder_mask(encoder); 50062afb4adSJosé Roberto de Souza 50152217195SDaniel Vetter return 0; 50252217195SDaniel Vetter } 503cde4c44dSDaniel Vetter EXPORT_SYMBOL(drm_connector_attach_encoder); 50452217195SDaniel Vetter 50538cb8d96SVille Syrjälä /** 50662afb4adSJosé Roberto de Souza * drm_connector_has_possible_encoder - check if the connector and encoder are 50762afb4adSJosé Roberto de Souza * associated with each other 50838cb8d96SVille Syrjälä * @connector: the connector 50938cb8d96SVille Syrjälä * @encoder: the encoder 51038cb8d96SVille Syrjälä * 51138cb8d96SVille Syrjälä * Returns: 51238cb8d96SVille Syrjälä * True if @encoder is one of the possible encoders for @connector. 51338cb8d96SVille Syrjälä */ 51438cb8d96SVille Syrjälä bool drm_connector_has_possible_encoder(struct drm_connector *connector, 51538cb8d96SVille Syrjälä struct drm_encoder *encoder) 51638cb8d96SVille Syrjälä { 51762afb4adSJosé Roberto de Souza return connector->possible_encoders & drm_encoder_mask(encoder); 51838cb8d96SVille Syrjälä } 51938cb8d96SVille Syrjälä EXPORT_SYMBOL(drm_connector_has_possible_encoder); 52038cb8d96SVille Syrjälä 52152217195SDaniel Vetter static void drm_mode_remove(struct drm_connector *connector, 52252217195SDaniel Vetter struct drm_display_mode *mode) 52352217195SDaniel Vetter { 52452217195SDaniel Vetter list_del(&mode->head); 52552217195SDaniel Vetter drm_mode_destroy(connector->dev, mode); 52652217195SDaniel Vetter } 52752217195SDaniel Vetter 52852217195SDaniel Vetter /** 52952217195SDaniel Vetter * drm_connector_cleanup - cleans up an initialised connector 53052217195SDaniel Vetter * @connector: connector to cleanup 53152217195SDaniel Vetter * 53252217195SDaniel Vetter * Cleans up the connector but doesn't free the object. 53352217195SDaniel Vetter */ 53452217195SDaniel Vetter void drm_connector_cleanup(struct drm_connector *connector) 53552217195SDaniel Vetter { 53652217195SDaniel Vetter struct drm_device *dev = connector->dev; 53752217195SDaniel Vetter struct drm_display_mode *mode, *t; 53852217195SDaniel Vetter 53952217195SDaniel Vetter /* The connector should have been removed from userspace long before 54052217195SDaniel Vetter * it is finally destroyed. 54152217195SDaniel Vetter */ 54239b50c60SLyude Paul if (WARN_ON(connector->registration_state == 54339b50c60SLyude Paul DRM_CONNECTOR_REGISTERED)) 54452217195SDaniel Vetter drm_connector_unregister(connector); 54552217195SDaniel Vetter 546334f74eeSHans de Goede if (connector->privacy_screen) { 547334f74eeSHans de Goede drm_privacy_screen_put(connector->privacy_screen); 548334f74eeSHans de Goede connector->privacy_screen = NULL; 549334f74eeSHans de Goede } 550334f74eeSHans de Goede 55152217195SDaniel Vetter if (connector->tile_group) { 55252217195SDaniel Vetter drm_mode_put_tile_group(dev, connector->tile_group); 55352217195SDaniel Vetter connector->tile_group = NULL; 55452217195SDaniel Vetter } 55552217195SDaniel Vetter 55652217195SDaniel Vetter list_for_each_entry_safe(mode, t, &connector->probed_modes, head) 55752217195SDaniel Vetter drm_mode_remove(connector, mode); 55852217195SDaniel Vetter 55952217195SDaniel Vetter list_for_each_entry_safe(mode, t, &connector->modes, head) 56052217195SDaniel Vetter drm_mode_remove(connector, mode); 56152217195SDaniel Vetter 562e5d6eeeaSBo Liu ida_free(&drm_connector_enum_list[connector->connector_type].ida, 56352217195SDaniel Vetter connector->connector_type_id); 56452217195SDaniel Vetter 565e5d6eeeaSBo Liu ida_free(&dev->mode_config.connector_ida, connector->index); 56652217195SDaniel Vetter 56752217195SDaniel Vetter kfree(connector->display_info.bus_formats); 56852217195SDaniel Vetter drm_mode_object_unregister(dev, &connector->base); 56952217195SDaniel Vetter kfree(connector->name); 57052217195SDaniel Vetter connector->name = NULL; 57148c429c6SHans de Goede fwnode_handle_put(connector->fwnode); 57248c429c6SHans de Goede connector->fwnode = NULL; 573613051daSDaniel Vetter spin_lock_irq(&dev->mode_config.connector_list_lock); 57452217195SDaniel Vetter list_del(&connector->head); 57552217195SDaniel Vetter dev->mode_config.num_connector--; 576613051daSDaniel Vetter spin_unlock_irq(&dev->mode_config.connector_list_lock); 57752217195SDaniel Vetter 57852217195SDaniel Vetter WARN_ON(connector->state && !connector->funcs->atomic_destroy_state); 57952217195SDaniel Vetter if (connector->state && connector->funcs->atomic_destroy_state) 58052217195SDaniel Vetter connector->funcs->atomic_destroy_state(connector, 58152217195SDaniel Vetter connector->state); 58252217195SDaniel Vetter 583e73ab00eSDaniel Vetter mutex_destroy(&connector->mutex); 584e73ab00eSDaniel Vetter 58552217195SDaniel Vetter memset(connector, 0, sizeof(*connector)); 5866fdc2d49SSimon Ser 5876fdc2d49SSimon Ser if (dev->registered) 5886fdc2d49SSimon Ser drm_sysfs_hotplug_event(dev); 58952217195SDaniel Vetter } 59052217195SDaniel Vetter EXPORT_SYMBOL(drm_connector_cleanup); 59152217195SDaniel Vetter 59252217195SDaniel Vetter /** 59352217195SDaniel Vetter * drm_connector_register - register a connector 59452217195SDaniel Vetter * @connector: the connector to register 59552217195SDaniel Vetter * 59669b22f51SDaniel Vetter * Register userspace interfaces for a connector. Only call this for connectors 59769b22f51SDaniel Vetter * which can be hotplugged after drm_dev_register() has been called already, 59869b22f51SDaniel Vetter * e.g. DP MST connectors. All other connectors will be registered automatically 59969b22f51SDaniel Vetter * when calling drm_dev_register(). 60052217195SDaniel Vetter * 601d87fbea5SMaxime Ripard * When the connector is no longer available, callers must call 602d87fbea5SMaxime Ripard * drm_connector_unregister(). 603d87fbea5SMaxime Ripard * 60452217195SDaniel Vetter * Returns: 60552217195SDaniel Vetter * Zero on success, error code on failure. 60652217195SDaniel Vetter */ 60752217195SDaniel Vetter int drm_connector_register(struct drm_connector *connector) 60852217195SDaniel Vetter { 609e73ab00eSDaniel Vetter int ret = 0; 61052217195SDaniel Vetter 611e6e7b48bSDaniel Vetter if (!connector->dev->registered) 612e6e7b48bSDaniel Vetter return 0; 613e6e7b48bSDaniel Vetter 614e73ab00eSDaniel Vetter mutex_lock(&connector->mutex); 61539b50c60SLyude Paul if (connector->registration_state != DRM_CONNECTOR_INITIALIZING) 616e73ab00eSDaniel Vetter goto unlock; 61752217195SDaniel Vetter 61852217195SDaniel Vetter ret = drm_sysfs_connector_add(connector); 61952217195SDaniel Vetter if (ret) 620e73ab00eSDaniel Vetter goto unlock; 62152217195SDaniel Vetter 622b792e640SGreg Kroah-Hartman drm_debugfs_connector_add(connector); 62352217195SDaniel Vetter 62452217195SDaniel Vetter if (connector->funcs->late_register) { 62552217195SDaniel Vetter ret = connector->funcs->late_register(connector); 62652217195SDaniel Vetter if (ret) 62752217195SDaniel Vetter goto err_debugfs; 62852217195SDaniel Vetter } 62952217195SDaniel Vetter 63052217195SDaniel Vetter drm_mode_object_register(connector->dev, &connector->base); 63152217195SDaniel Vetter 63239b50c60SLyude Paul connector->registration_state = DRM_CONNECTOR_REGISTERED; 633968d81a6SJeykumar Sankaran 634968d81a6SJeykumar Sankaran /* Let userspace know we have a new connector */ 635ad935754SSimon Ser drm_sysfs_connector_hotplug_event(connector); 636968d81a6SJeykumar Sankaran 637334f74eeSHans de Goede if (connector->privacy_screen) 638334f74eeSHans de Goede drm_privacy_screen_register_notifier(connector->privacy_screen, 639334f74eeSHans de Goede &connector->privacy_screen_notifier); 640334f74eeSHans de Goede 6413d3f7c1eSHans de Goede mutex_lock(&connector_list_lock); 6423d3f7c1eSHans de Goede list_add_tail(&connector->global_connector_list_entry, &connector_list); 6433d3f7c1eSHans de Goede mutex_unlock(&connector_list_lock); 644e73ab00eSDaniel Vetter goto unlock; 64552217195SDaniel Vetter 64652217195SDaniel Vetter err_debugfs: 64752217195SDaniel Vetter drm_debugfs_connector_remove(connector); 64852217195SDaniel Vetter drm_sysfs_connector_remove(connector); 649e73ab00eSDaniel Vetter unlock: 650e73ab00eSDaniel Vetter mutex_unlock(&connector->mutex); 65152217195SDaniel Vetter return ret; 65252217195SDaniel Vetter } 65352217195SDaniel Vetter EXPORT_SYMBOL(drm_connector_register); 65452217195SDaniel Vetter 65552217195SDaniel Vetter /** 65652217195SDaniel Vetter * drm_connector_unregister - unregister a connector 65752217195SDaniel Vetter * @connector: the connector to unregister 65852217195SDaniel Vetter * 65969b22f51SDaniel Vetter * Unregister userspace interfaces for a connector. Only call this for 660d87fbea5SMaxime Ripard * connectors which have been registered explicitly by calling 661d87fbea5SMaxime Ripard * drm_connector_register(). 66252217195SDaniel Vetter */ 66352217195SDaniel Vetter void drm_connector_unregister(struct drm_connector *connector) 66452217195SDaniel Vetter { 665e73ab00eSDaniel Vetter mutex_lock(&connector->mutex); 66639b50c60SLyude Paul if (connector->registration_state != DRM_CONNECTOR_REGISTERED) { 667e73ab00eSDaniel Vetter mutex_unlock(&connector->mutex); 66852217195SDaniel Vetter return; 669e73ab00eSDaniel Vetter } 67052217195SDaniel Vetter 6713d3f7c1eSHans de Goede mutex_lock(&connector_list_lock); 6723d3f7c1eSHans de Goede list_del_init(&connector->global_connector_list_entry); 6733d3f7c1eSHans de Goede mutex_unlock(&connector_list_lock); 6743d3f7c1eSHans de Goede 675334f74eeSHans de Goede if (connector->privacy_screen) 676334f74eeSHans de Goede drm_privacy_screen_unregister_notifier( 677334f74eeSHans de Goede connector->privacy_screen, 678334f74eeSHans de Goede &connector->privacy_screen_notifier); 679334f74eeSHans de Goede 68052217195SDaniel Vetter if (connector->funcs->early_unregister) 68152217195SDaniel Vetter connector->funcs->early_unregister(connector); 68252217195SDaniel Vetter 68352217195SDaniel Vetter drm_sysfs_connector_remove(connector); 68452217195SDaniel Vetter drm_debugfs_connector_remove(connector); 68552217195SDaniel Vetter 68639b50c60SLyude Paul connector->registration_state = DRM_CONNECTOR_UNREGISTERED; 687e73ab00eSDaniel Vetter mutex_unlock(&connector->mutex); 68852217195SDaniel Vetter } 68952217195SDaniel Vetter EXPORT_SYMBOL(drm_connector_unregister); 69052217195SDaniel Vetter 69152217195SDaniel Vetter void drm_connector_unregister_all(struct drm_device *dev) 69252217195SDaniel Vetter { 69352217195SDaniel Vetter struct drm_connector *connector; 694613051daSDaniel Vetter struct drm_connector_list_iter conn_iter; 69552217195SDaniel Vetter 696b982dab1SThierry Reding drm_connector_list_iter_begin(dev, &conn_iter); 697613051daSDaniel Vetter drm_for_each_connector_iter(connector, &conn_iter) 69852217195SDaniel Vetter drm_connector_unregister(connector); 699b982dab1SThierry Reding drm_connector_list_iter_end(&conn_iter); 70052217195SDaniel Vetter } 70152217195SDaniel Vetter 70252217195SDaniel Vetter int drm_connector_register_all(struct drm_device *dev) 70352217195SDaniel Vetter { 70452217195SDaniel Vetter struct drm_connector *connector; 705613051daSDaniel Vetter struct drm_connector_list_iter conn_iter; 706613051daSDaniel Vetter int ret = 0; 70752217195SDaniel Vetter 708b982dab1SThierry Reding drm_connector_list_iter_begin(dev, &conn_iter); 709613051daSDaniel Vetter drm_for_each_connector_iter(connector, &conn_iter) { 71052217195SDaniel Vetter ret = drm_connector_register(connector); 71152217195SDaniel Vetter if (ret) 712613051daSDaniel Vetter break; 71352217195SDaniel Vetter } 714b982dab1SThierry Reding drm_connector_list_iter_end(&conn_iter); 71552217195SDaniel Vetter 716613051daSDaniel Vetter if (ret) 71752217195SDaniel Vetter drm_connector_unregister_all(dev); 71852217195SDaniel Vetter return ret; 71952217195SDaniel Vetter } 72052217195SDaniel Vetter 72152217195SDaniel Vetter /** 72252217195SDaniel Vetter * drm_get_connector_status_name - return a string for connector status 72352217195SDaniel Vetter * @status: connector status to compute name of 72452217195SDaniel Vetter * 72552217195SDaniel Vetter * In contrast to the other drm_get_*_name functions this one here returns a 72652217195SDaniel Vetter * const pointer and hence is threadsafe. 727f85d9e59SRandy Dunlap * 728f85d9e59SRandy Dunlap * Returns: connector status string 72952217195SDaniel Vetter */ 73052217195SDaniel Vetter const char *drm_get_connector_status_name(enum drm_connector_status status) 73152217195SDaniel Vetter { 73252217195SDaniel Vetter if (status == connector_status_connected) 73352217195SDaniel Vetter return "connected"; 73452217195SDaniel Vetter else if (status == connector_status_disconnected) 73552217195SDaniel Vetter return "disconnected"; 73652217195SDaniel Vetter else 73752217195SDaniel Vetter return "unknown"; 73852217195SDaniel Vetter } 73952217195SDaniel Vetter EXPORT_SYMBOL(drm_get_connector_status_name); 74052217195SDaniel Vetter 7416140cf20SJani Nikula /** 7426140cf20SJani Nikula * drm_get_connector_force_name - return a string for connector force 7436140cf20SJani Nikula * @force: connector force to get name of 7446140cf20SJani Nikula * 7456140cf20SJani Nikula * Returns: const pointer to name. 7466140cf20SJani Nikula */ 7476140cf20SJani Nikula const char *drm_get_connector_force_name(enum drm_connector_force force) 7486140cf20SJani Nikula { 7496140cf20SJani Nikula switch (force) { 7506140cf20SJani Nikula case DRM_FORCE_UNSPECIFIED: 7516140cf20SJani Nikula return "unspecified"; 7526140cf20SJani Nikula case DRM_FORCE_OFF: 7536140cf20SJani Nikula return "off"; 7546140cf20SJani Nikula case DRM_FORCE_ON: 7556140cf20SJani Nikula return "on"; 7566140cf20SJani Nikula case DRM_FORCE_ON_DIGITAL: 7576140cf20SJani Nikula return "digital"; 7586140cf20SJani Nikula default: 7596140cf20SJani Nikula return "unknown"; 7606140cf20SJani Nikula } 7616140cf20SJani Nikula } 7626140cf20SJani Nikula 763613051daSDaniel Vetter #ifdef CONFIG_LOCKDEP 764613051daSDaniel Vetter static struct lockdep_map connector_list_iter_dep_map = { 765613051daSDaniel Vetter .name = "drm_connector_list_iter" 766613051daSDaniel Vetter }; 767613051daSDaniel Vetter #endif 768613051daSDaniel Vetter 769613051daSDaniel Vetter /** 770b982dab1SThierry Reding * drm_connector_list_iter_begin - initialize a connector_list iterator 771613051daSDaniel Vetter * @dev: DRM device 772613051daSDaniel Vetter * @iter: connector_list iterator 773613051daSDaniel Vetter * 774d574528aSDaniel Vetter * Sets @iter up to walk the &drm_mode_config.connector_list of @dev. @iter 775b982dab1SThierry Reding * must always be cleaned up again by calling drm_connector_list_iter_end(). 776613051daSDaniel Vetter * Iteration itself happens using drm_connector_list_iter_next() or 777613051daSDaniel Vetter * drm_for_each_connector_iter(). 778613051daSDaniel Vetter */ 779b982dab1SThierry Reding void drm_connector_list_iter_begin(struct drm_device *dev, 780613051daSDaniel Vetter struct drm_connector_list_iter *iter) 781613051daSDaniel Vetter { 782613051daSDaniel Vetter iter->dev = dev; 783613051daSDaniel Vetter iter->conn = NULL; 784613051daSDaniel Vetter lock_acquire_shared_recursive(&connector_list_iter_dep_map, 0, 1, NULL, _RET_IP_); 785613051daSDaniel Vetter } 786b982dab1SThierry Reding EXPORT_SYMBOL(drm_connector_list_iter_begin); 787613051daSDaniel Vetter 788a703c550SDaniel Vetter /* 789a703c550SDaniel Vetter * Extra-safe connector put function that works in any context. Should only be 790a703c550SDaniel Vetter * used from the connector_iter functions, where we never really expect to 791a703c550SDaniel Vetter * actually release the connector when dropping our final reference. 792a703c550SDaniel Vetter */ 793a703c550SDaniel Vetter static void 794ea497bb9SDaniel Vetter __drm_connector_put_safe(struct drm_connector *conn) 795a703c550SDaniel Vetter { 796ea497bb9SDaniel Vetter struct drm_mode_config *config = &conn->dev->mode_config; 797ea497bb9SDaniel Vetter 798ea497bb9SDaniel Vetter lockdep_assert_held(&config->connector_list_lock); 799ea497bb9SDaniel Vetter 800ea497bb9SDaniel Vetter if (!refcount_dec_and_test(&conn->base.refcount.refcount)) 801ea497bb9SDaniel Vetter return; 802ea497bb9SDaniel Vetter 803ea497bb9SDaniel Vetter llist_add(&conn->free_node, &config->connector_free_list); 804ea497bb9SDaniel Vetter schedule_work(&config->connector_free_work); 805a703c550SDaniel Vetter } 806a703c550SDaniel Vetter 807613051daSDaniel Vetter /** 808613051daSDaniel Vetter * drm_connector_list_iter_next - return next connector 8094f45c778SLyude Paul * @iter: connector_list iterator 810613051daSDaniel Vetter * 811f85d9e59SRandy Dunlap * Returns: the next connector for @iter, or NULL when the list walk has 812613051daSDaniel Vetter * completed. 813613051daSDaniel Vetter */ 814613051daSDaniel Vetter struct drm_connector * 815613051daSDaniel Vetter drm_connector_list_iter_next(struct drm_connector_list_iter *iter) 816613051daSDaniel Vetter { 817613051daSDaniel Vetter struct drm_connector *old_conn = iter->conn; 818613051daSDaniel Vetter struct drm_mode_config *config = &iter->dev->mode_config; 819613051daSDaniel Vetter struct list_head *lhead; 820613051daSDaniel Vetter unsigned long flags; 821613051daSDaniel Vetter 822613051daSDaniel Vetter spin_lock_irqsave(&config->connector_list_lock, flags); 823613051daSDaniel Vetter lhead = old_conn ? &old_conn->head : &config->connector_list; 824613051daSDaniel Vetter 825613051daSDaniel Vetter do { 826613051daSDaniel Vetter if (lhead->next == &config->connector_list) { 827613051daSDaniel Vetter iter->conn = NULL; 828613051daSDaniel Vetter break; 829613051daSDaniel Vetter } 830613051daSDaniel Vetter 831613051daSDaniel Vetter lhead = lhead->next; 832613051daSDaniel Vetter iter->conn = list_entry(lhead, struct drm_connector, head); 833613051daSDaniel Vetter 834613051daSDaniel Vetter /* loop until it's not a zombie connector */ 835613051daSDaniel Vetter } while (!kref_get_unless_zero(&iter->conn->base.refcount)); 836613051daSDaniel Vetter 837613051daSDaniel Vetter if (old_conn) 838ea497bb9SDaniel Vetter __drm_connector_put_safe(old_conn); 839ea497bb9SDaniel Vetter spin_unlock_irqrestore(&config->connector_list_lock, flags); 840613051daSDaniel Vetter 841613051daSDaniel Vetter return iter->conn; 842613051daSDaniel Vetter } 843613051daSDaniel Vetter EXPORT_SYMBOL(drm_connector_list_iter_next); 844613051daSDaniel Vetter 845613051daSDaniel Vetter /** 846b982dab1SThierry Reding * drm_connector_list_iter_end - tear down a connector_list iterator 847613051daSDaniel Vetter * @iter: connector_list iterator 848613051daSDaniel Vetter * 849613051daSDaniel Vetter * Tears down @iter and releases any resources (like &drm_connector references) 850613051daSDaniel Vetter * acquired while walking the list. This must always be called, both when the 851613051daSDaniel Vetter * iteration completes fully or when it was aborted without walking the entire 852613051daSDaniel Vetter * list. 853613051daSDaniel Vetter */ 854b982dab1SThierry Reding void drm_connector_list_iter_end(struct drm_connector_list_iter *iter) 855613051daSDaniel Vetter { 856ea497bb9SDaniel Vetter struct drm_mode_config *config = &iter->dev->mode_config; 857ea497bb9SDaniel Vetter unsigned long flags; 858ea497bb9SDaniel Vetter 859613051daSDaniel Vetter iter->dev = NULL; 860ea497bb9SDaniel Vetter if (iter->conn) { 861ea497bb9SDaniel Vetter spin_lock_irqsave(&config->connector_list_lock, flags); 862ea497bb9SDaniel Vetter __drm_connector_put_safe(iter->conn); 863ea497bb9SDaniel Vetter spin_unlock_irqrestore(&config->connector_list_lock, flags); 864ea497bb9SDaniel Vetter } 8655facae4fSQian Cai lock_release(&connector_list_iter_dep_map, _RET_IP_); 866613051daSDaniel Vetter } 867b982dab1SThierry Reding EXPORT_SYMBOL(drm_connector_list_iter_end); 868613051daSDaniel Vetter 86952217195SDaniel Vetter static const struct drm_prop_enum_list drm_subpixel_enum_list[] = { 87052217195SDaniel Vetter { SubPixelUnknown, "Unknown" }, 87152217195SDaniel Vetter { SubPixelHorizontalRGB, "Horizontal RGB" }, 87252217195SDaniel Vetter { SubPixelHorizontalBGR, "Horizontal BGR" }, 87352217195SDaniel Vetter { SubPixelVerticalRGB, "Vertical RGB" }, 87452217195SDaniel Vetter { SubPixelVerticalBGR, "Vertical BGR" }, 87552217195SDaniel Vetter { SubPixelNone, "None" }, 87652217195SDaniel Vetter }; 87752217195SDaniel Vetter 87852217195SDaniel Vetter /** 87952217195SDaniel Vetter * drm_get_subpixel_order_name - return a string for a given subpixel enum 88052217195SDaniel Vetter * @order: enum of subpixel_order 88152217195SDaniel Vetter * 88252217195SDaniel Vetter * Note you could abuse this and return something out of bounds, but that 88352217195SDaniel Vetter * would be a caller error. No unscrubbed user data should make it here. 884f85d9e59SRandy Dunlap * 885f85d9e59SRandy Dunlap * Returns: string describing an enumerated subpixel property 88652217195SDaniel Vetter */ 88752217195SDaniel Vetter const char *drm_get_subpixel_order_name(enum subpixel_order order) 88852217195SDaniel Vetter { 88952217195SDaniel Vetter return drm_subpixel_enum_list[order].name; 89052217195SDaniel Vetter } 89152217195SDaniel Vetter EXPORT_SYMBOL(drm_get_subpixel_order_name); 89252217195SDaniel Vetter 89352217195SDaniel Vetter static const struct drm_prop_enum_list drm_dpms_enum_list[] = { 89452217195SDaniel Vetter { DRM_MODE_DPMS_ON, "On" }, 89552217195SDaniel Vetter { DRM_MODE_DPMS_STANDBY, "Standby" }, 89652217195SDaniel Vetter { DRM_MODE_DPMS_SUSPEND, "Suspend" }, 89752217195SDaniel Vetter { DRM_MODE_DPMS_OFF, "Off" } 89852217195SDaniel Vetter }; 89952217195SDaniel Vetter DRM_ENUM_NAME_FN(drm_get_dpms_name, drm_dpms_enum_list) 90052217195SDaniel Vetter 90140ee6fbeSManasi Navare static const struct drm_prop_enum_list drm_link_status_enum_list[] = { 90240ee6fbeSManasi Navare { DRM_MODE_LINK_STATUS_GOOD, "Good" }, 90340ee6fbeSManasi Navare { DRM_MODE_LINK_STATUS_BAD, "Bad" }, 90440ee6fbeSManasi Navare }; 90540ee6fbeSManasi Navare 906b3c6c8bfSDaniel Vetter /** 907b3c6c8bfSDaniel Vetter * drm_display_info_set_bus_formats - set the supported bus formats 908b3c6c8bfSDaniel Vetter * @info: display info to store bus formats in 909b3c6c8bfSDaniel Vetter * @formats: array containing the supported bus formats 910b3c6c8bfSDaniel Vetter * @num_formats: the number of entries in the fmts array 911b3c6c8bfSDaniel Vetter * 912b3c6c8bfSDaniel Vetter * Store the supported bus formats in display info structure. 913b3c6c8bfSDaniel Vetter * See MEDIA_BUS_FMT_* definitions in include/uapi/linux/media-bus-format.h for 914b3c6c8bfSDaniel Vetter * a full list of available formats. 915f85d9e59SRandy Dunlap * 916f85d9e59SRandy Dunlap * Returns: 917f85d9e59SRandy Dunlap * 0 on success or a negative error code on failure. 918b3c6c8bfSDaniel Vetter */ 919b3c6c8bfSDaniel Vetter int drm_display_info_set_bus_formats(struct drm_display_info *info, 920b3c6c8bfSDaniel Vetter const u32 *formats, 921b3c6c8bfSDaniel Vetter unsigned int num_formats) 922b3c6c8bfSDaniel Vetter { 923b3c6c8bfSDaniel Vetter u32 *fmts = NULL; 924b3c6c8bfSDaniel Vetter 925b3c6c8bfSDaniel Vetter if (!formats && num_formats) 926b3c6c8bfSDaniel Vetter return -EINVAL; 927b3c6c8bfSDaniel Vetter 928b3c6c8bfSDaniel Vetter if (formats && num_formats) { 929b3c6c8bfSDaniel Vetter fmts = kmemdup(formats, sizeof(*formats) * num_formats, 930b3c6c8bfSDaniel Vetter GFP_KERNEL); 931b3c6c8bfSDaniel Vetter if (!fmts) 932b3c6c8bfSDaniel Vetter return -ENOMEM; 933b3c6c8bfSDaniel Vetter } 934b3c6c8bfSDaniel Vetter 935b3c6c8bfSDaniel Vetter kfree(info->bus_formats); 936b3c6c8bfSDaniel Vetter info->bus_formats = fmts; 937b3c6c8bfSDaniel Vetter info->num_bus_formats = num_formats; 938b3c6c8bfSDaniel Vetter 939b3c6c8bfSDaniel Vetter return 0; 940b3c6c8bfSDaniel Vetter } 941b3c6c8bfSDaniel Vetter EXPORT_SYMBOL(drm_display_info_set_bus_formats); 942b3c6c8bfSDaniel Vetter 94352217195SDaniel Vetter /* Optional connector properties. */ 94452217195SDaniel Vetter static const struct drm_prop_enum_list drm_scaling_mode_enum_list[] = { 94552217195SDaniel Vetter { DRM_MODE_SCALE_NONE, "None" }, 94652217195SDaniel Vetter { DRM_MODE_SCALE_FULLSCREEN, "Full" }, 94752217195SDaniel Vetter { DRM_MODE_SCALE_CENTER, "Center" }, 94852217195SDaniel Vetter { DRM_MODE_SCALE_ASPECT, "Full aspect" }, 94952217195SDaniel Vetter }; 95052217195SDaniel Vetter 95152217195SDaniel Vetter static const struct drm_prop_enum_list drm_aspect_ratio_enum_list[] = { 95252217195SDaniel Vetter { DRM_MODE_PICTURE_ASPECT_NONE, "Automatic" }, 95352217195SDaniel Vetter { DRM_MODE_PICTURE_ASPECT_4_3, "4:3" }, 95452217195SDaniel Vetter { DRM_MODE_PICTURE_ASPECT_16_9, "16:9" }, 95552217195SDaniel Vetter }; 95652217195SDaniel Vetter 95750525c33SStanislav Lisovskiy static const struct drm_prop_enum_list drm_content_type_enum_list[] = { 95850525c33SStanislav Lisovskiy { DRM_MODE_CONTENT_TYPE_NO_DATA, "No Data" }, 95950525c33SStanislav Lisovskiy { DRM_MODE_CONTENT_TYPE_GRAPHICS, "Graphics" }, 96050525c33SStanislav Lisovskiy { DRM_MODE_CONTENT_TYPE_PHOTO, "Photo" }, 96150525c33SStanislav Lisovskiy { DRM_MODE_CONTENT_TYPE_CINEMA, "Cinema" }, 96250525c33SStanislav Lisovskiy { DRM_MODE_CONTENT_TYPE_GAME, "Game" }, 96350525c33SStanislav Lisovskiy }; 96450525c33SStanislav Lisovskiy 9658d70f395SHans de Goede static const struct drm_prop_enum_list drm_panel_orientation_enum_list[] = { 9668d70f395SHans de Goede { DRM_MODE_PANEL_ORIENTATION_NORMAL, "Normal" }, 9678d70f395SHans de Goede { DRM_MODE_PANEL_ORIENTATION_BOTTOM_UP, "Upside Down" }, 9688d70f395SHans de Goede { DRM_MODE_PANEL_ORIENTATION_LEFT_UP, "Left Side Up" }, 9698d70f395SHans de Goede { DRM_MODE_PANEL_ORIENTATION_RIGHT_UP, "Right Side Up" }, 9708d70f395SHans de Goede }; 9718d70f395SHans de Goede 97252217195SDaniel Vetter static const struct drm_prop_enum_list drm_dvi_i_select_enum_list[] = { 97352217195SDaniel Vetter { DRM_MODE_SUBCONNECTOR_Automatic, "Automatic" }, /* DVI-I and TV-out */ 97452217195SDaniel Vetter { DRM_MODE_SUBCONNECTOR_DVID, "DVI-D" }, /* DVI-I */ 97552217195SDaniel Vetter { DRM_MODE_SUBCONNECTOR_DVIA, "DVI-A" }, /* DVI-I */ 97652217195SDaniel Vetter }; 97752217195SDaniel Vetter DRM_ENUM_NAME_FN(drm_get_dvi_i_select_name, drm_dvi_i_select_enum_list) 97852217195SDaniel Vetter 97952217195SDaniel Vetter static const struct drm_prop_enum_list drm_dvi_i_subconnector_enum_list[] = { 980e5b92773SOleg Vasilev { DRM_MODE_SUBCONNECTOR_Unknown, "Unknown" }, /* DVI-I, TV-out and DP */ 98152217195SDaniel Vetter { DRM_MODE_SUBCONNECTOR_DVID, "DVI-D" }, /* DVI-I */ 98252217195SDaniel Vetter { DRM_MODE_SUBCONNECTOR_DVIA, "DVI-A" }, /* DVI-I */ 98352217195SDaniel Vetter }; 98452217195SDaniel Vetter DRM_ENUM_NAME_FN(drm_get_dvi_i_subconnector_name, 98552217195SDaniel Vetter drm_dvi_i_subconnector_enum_list) 98652217195SDaniel Vetter 98752217195SDaniel Vetter static const struct drm_prop_enum_list drm_tv_select_enum_list[] = { 98852217195SDaniel Vetter { DRM_MODE_SUBCONNECTOR_Automatic, "Automatic" }, /* DVI-I and TV-out */ 98952217195SDaniel Vetter { DRM_MODE_SUBCONNECTOR_Composite, "Composite" }, /* TV-out */ 99052217195SDaniel Vetter { DRM_MODE_SUBCONNECTOR_SVIDEO, "SVIDEO" }, /* TV-out */ 99152217195SDaniel Vetter { DRM_MODE_SUBCONNECTOR_Component, "Component" }, /* TV-out */ 99252217195SDaniel Vetter { DRM_MODE_SUBCONNECTOR_SCART, "SCART" }, /* TV-out */ 99352217195SDaniel Vetter }; 99452217195SDaniel Vetter DRM_ENUM_NAME_FN(drm_get_tv_select_name, drm_tv_select_enum_list) 99552217195SDaniel Vetter 99652217195SDaniel Vetter static const struct drm_prop_enum_list drm_tv_subconnector_enum_list[] = { 997e5b92773SOleg Vasilev { DRM_MODE_SUBCONNECTOR_Unknown, "Unknown" }, /* DVI-I, TV-out and DP */ 99852217195SDaniel Vetter { DRM_MODE_SUBCONNECTOR_Composite, "Composite" }, /* TV-out */ 99952217195SDaniel Vetter { DRM_MODE_SUBCONNECTOR_SVIDEO, "SVIDEO" }, /* TV-out */ 100052217195SDaniel Vetter { DRM_MODE_SUBCONNECTOR_Component, "Component" }, /* TV-out */ 100152217195SDaniel Vetter { DRM_MODE_SUBCONNECTOR_SCART, "SCART" }, /* TV-out */ 100252217195SDaniel Vetter }; 100352217195SDaniel Vetter DRM_ENUM_NAME_FN(drm_get_tv_subconnector_name, 100452217195SDaniel Vetter drm_tv_subconnector_enum_list) 100552217195SDaniel Vetter 1006e5b92773SOleg Vasilev static const struct drm_prop_enum_list drm_dp_subconnector_enum_list[] = { 1007e5b92773SOleg Vasilev { DRM_MODE_SUBCONNECTOR_Unknown, "Unknown" }, /* DVI-I, TV-out and DP */ 1008e5b92773SOleg Vasilev { DRM_MODE_SUBCONNECTOR_VGA, "VGA" }, /* DP */ 1009e5b92773SOleg Vasilev { DRM_MODE_SUBCONNECTOR_DVID, "DVI-D" }, /* DP */ 1010e5b92773SOleg Vasilev { DRM_MODE_SUBCONNECTOR_HDMIA, "HDMI" }, /* DP */ 1011e5b92773SOleg Vasilev { DRM_MODE_SUBCONNECTOR_DisplayPort, "DP" }, /* DP */ 1012e5b92773SOleg Vasilev { DRM_MODE_SUBCONNECTOR_Wireless, "Wireless" }, /* DP */ 1013e5b92773SOleg Vasilev { DRM_MODE_SUBCONNECTOR_Native, "Native" }, /* DP */ 1014e5b92773SOleg Vasilev }; 1015e5b92773SOleg Vasilev 1016e5b92773SOleg Vasilev DRM_ENUM_NAME_FN(drm_get_dp_subconnector_name, 1017e5b92773SOleg Vasilev drm_dp_subconnector_enum_list) 1018e5b92773SOleg Vasilev 1019d2c6a405SUma Shankar static const struct drm_prop_enum_list hdmi_colorspaces[] = { 1020d2c6a405SUma Shankar /* For Default case, driver will set the colorspace */ 1021d2c6a405SUma Shankar { DRM_MODE_COLORIMETRY_DEFAULT, "Default" }, 1022d2c6a405SUma Shankar /* Standard Definition Colorimetry based on CEA 861 */ 1023d2c6a405SUma Shankar { DRM_MODE_COLORIMETRY_SMPTE_170M_YCC, "SMPTE_170M_YCC" }, 1024d2c6a405SUma Shankar { DRM_MODE_COLORIMETRY_BT709_YCC, "BT709_YCC" }, 1025d2c6a405SUma Shankar /* Standard Definition Colorimetry based on IEC 61966-2-4 */ 1026d2c6a405SUma Shankar { DRM_MODE_COLORIMETRY_XVYCC_601, "XVYCC_601" }, 1027d2c6a405SUma Shankar /* High Definition Colorimetry based on IEC 61966-2-4 */ 1028d2c6a405SUma Shankar { DRM_MODE_COLORIMETRY_XVYCC_709, "XVYCC_709" }, 1029d2c6a405SUma Shankar /* Colorimetry based on IEC 61966-2-1/Amendment 1 */ 1030d2c6a405SUma Shankar { DRM_MODE_COLORIMETRY_SYCC_601, "SYCC_601" }, 1031d2c6a405SUma Shankar /* Colorimetry based on IEC 61966-2-5 [33] */ 1032d2c6a405SUma Shankar { DRM_MODE_COLORIMETRY_OPYCC_601, "opYCC_601" }, 1033d2c6a405SUma Shankar /* Colorimetry based on IEC 61966-2-5 */ 1034d2c6a405SUma Shankar { DRM_MODE_COLORIMETRY_OPRGB, "opRGB" }, 1035d2c6a405SUma Shankar /* Colorimetry based on ITU-R BT.2020 */ 1036d2c6a405SUma Shankar { DRM_MODE_COLORIMETRY_BT2020_CYCC, "BT2020_CYCC" }, 1037d2c6a405SUma Shankar /* Colorimetry based on ITU-R BT.2020 */ 1038d2c6a405SUma Shankar { DRM_MODE_COLORIMETRY_BT2020_RGB, "BT2020_RGB" }, 1039d2c6a405SUma Shankar /* Colorimetry based on ITU-R BT.2020 */ 1040d2c6a405SUma Shankar { DRM_MODE_COLORIMETRY_BT2020_YCC, "BT2020_YCC" }, 1041d2c6a405SUma Shankar /* Added as part of Additional Colorimetry Extension in 861.G */ 1042d2c6a405SUma Shankar { DRM_MODE_COLORIMETRY_DCI_P3_RGB_D65, "DCI-P3_RGB_D65" }, 1043d2c6a405SUma Shankar { DRM_MODE_COLORIMETRY_DCI_P3_RGB_THEATER, "DCI-P3_RGB_Theater" }, 1044d2c6a405SUma Shankar }; 1045d2c6a405SUma Shankar 104645cf0e91SGwan-gyeong Mun /* 104745cf0e91SGwan-gyeong Mun * As per DP 1.4a spec, 2.2.5.7.5 VSC SDP Payload for Pixel Encoding/Colorimetry 104845cf0e91SGwan-gyeong Mun * Format Table 2-120 104945cf0e91SGwan-gyeong Mun */ 105045cf0e91SGwan-gyeong Mun static const struct drm_prop_enum_list dp_colorspaces[] = { 105145cf0e91SGwan-gyeong Mun /* For Default case, driver will set the colorspace */ 105245cf0e91SGwan-gyeong Mun { DRM_MODE_COLORIMETRY_DEFAULT, "Default" }, 105345cf0e91SGwan-gyeong Mun { DRM_MODE_COLORIMETRY_RGB_WIDE_FIXED, "RGB_Wide_Gamut_Fixed_Point" }, 105445cf0e91SGwan-gyeong Mun /* Colorimetry based on scRGB (IEC 61966-2-2) */ 105545cf0e91SGwan-gyeong Mun { DRM_MODE_COLORIMETRY_RGB_WIDE_FLOAT, "RGB_Wide_Gamut_Floating_Point" }, 105645cf0e91SGwan-gyeong Mun /* Colorimetry based on IEC 61966-2-5 */ 105745cf0e91SGwan-gyeong Mun { DRM_MODE_COLORIMETRY_OPRGB, "opRGB" }, 105845cf0e91SGwan-gyeong Mun /* Colorimetry based on SMPTE RP 431-2 */ 105945cf0e91SGwan-gyeong Mun { DRM_MODE_COLORIMETRY_DCI_P3_RGB_D65, "DCI-P3_RGB_D65" }, 106045cf0e91SGwan-gyeong Mun /* Colorimetry based on ITU-R BT.2020 */ 106145cf0e91SGwan-gyeong Mun { DRM_MODE_COLORIMETRY_BT2020_RGB, "BT2020_RGB" }, 106245cf0e91SGwan-gyeong Mun { DRM_MODE_COLORIMETRY_BT601_YCC, "BT601_YCC" }, 106345cf0e91SGwan-gyeong Mun { DRM_MODE_COLORIMETRY_BT709_YCC, "BT709_YCC" }, 106445cf0e91SGwan-gyeong Mun /* Standard Definition Colorimetry based on IEC 61966-2-4 */ 106545cf0e91SGwan-gyeong Mun { DRM_MODE_COLORIMETRY_XVYCC_601, "XVYCC_601" }, 106645cf0e91SGwan-gyeong Mun /* High Definition Colorimetry based on IEC 61966-2-4 */ 106745cf0e91SGwan-gyeong Mun { DRM_MODE_COLORIMETRY_XVYCC_709, "XVYCC_709" }, 106845cf0e91SGwan-gyeong Mun /* Colorimetry based on IEC 61966-2-1/Amendment 1 */ 106945cf0e91SGwan-gyeong Mun { DRM_MODE_COLORIMETRY_SYCC_601, "SYCC_601" }, 107045cf0e91SGwan-gyeong Mun /* Colorimetry based on IEC 61966-2-5 [33] */ 107145cf0e91SGwan-gyeong Mun { DRM_MODE_COLORIMETRY_OPYCC_601, "opYCC_601" }, 107245cf0e91SGwan-gyeong Mun /* Colorimetry based on ITU-R BT.2020 */ 107345cf0e91SGwan-gyeong Mun { DRM_MODE_COLORIMETRY_BT2020_CYCC, "BT2020_CYCC" }, 107445cf0e91SGwan-gyeong Mun /* Colorimetry based on ITU-R BT.2020 */ 107545cf0e91SGwan-gyeong Mun { DRM_MODE_COLORIMETRY_BT2020_YCC, "BT2020_YCC" }, 107645cf0e91SGwan-gyeong Mun }; 107745cf0e91SGwan-gyeong Mun 10784ada6f22SDaniel Vetter /** 10794ada6f22SDaniel Vetter * DOC: standard connector properties 10804ada6f22SDaniel Vetter * 10814ada6f22SDaniel Vetter * DRM connectors have a few standardized properties: 10824ada6f22SDaniel Vetter * 10834ada6f22SDaniel Vetter * EDID: 10844ada6f22SDaniel Vetter * Blob property which contains the current EDID read from the sink. This 10854ada6f22SDaniel Vetter * is useful to parse sink identification information like vendor, model 10864ada6f22SDaniel Vetter * and serial. Drivers should update this property by calling 1087c555f023SDaniel Vetter * drm_connector_update_edid_property(), usually after having parsed 10884ada6f22SDaniel Vetter * the EDID using drm_add_edid_modes(). Userspace cannot change this 10894ada6f22SDaniel Vetter * property. 109012767469SSimon Ser * 109112767469SSimon Ser * User-space should not parse the EDID to obtain information exposed via 109212767469SSimon Ser * other KMS properties (because the kernel might apply limits, quirks or 109312767469SSimon Ser * fixups to the EDID). For instance, user-space should not try to parse 109412767469SSimon Ser * mode lists from the EDID. 10954ada6f22SDaniel Vetter * DPMS: 10964ada6f22SDaniel Vetter * Legacy property for setting the power state of the connector. For atomic 10974ada6f22SDaniel Vetter * drivers this is only provided for backwards compatibility with existing 10984ada6f22SDaniel Vetter * drivers, it remaps to controlling the "ACTIVE" property on the CRTC the 10994ada6f22SDaniel Vetter * connector is linked to. Drivers should never set this property directly, 1100d574528aSDaniel Vetter * it is handled by the DRM core by calling the &drm_connector_funcs.dpms 1101144a7999SDaniel Vetter * callback. For atomic drivers the remapping to the "ACTIVE" property is 11021e3e4caeSSimon Ser * implemented in the DRM core. 1103d0d1aee5SDaniel Vetter * 1104d0d1aee5SDaniel Vetter * Note that this property cannot be set through the MODE_ATOMIC ioctl, 1105d0d1aee5SDaniel Vetter * userspace must use "ACTIVE" on the CRTC instead. 1106d0d1aee5SDaniel Vetter * 1107d0d1aee5SDaniel Vetter * WARNING: 1108d0d1aee5SDaniel Vetter * 1109d0d1aee5SDaniel Vetter * For userspace also running on legacy drivers the "DPMS" semantics are a 1110d0d1aee5SDaniel Vetter * lot more complicated. First, userspace cannot rely on the "DPMS" value 1111d0d1aee5SDaniel Vetter * returned by the GETCONNECTOR actually reflecting reality, because many 1112d0d1aee5SDaniel Vetter * drivers fail to update it. For atomic drivers this is taken care of in 1113d0d1aee5SDaniel Vetter * drm_atomic_helper_update_legacy_modeset_state(). 1114d0d1aee5SDaniel Vetter * 1115d0d1aee5SDaniel Vetter * The second issue is that the DPMS state is only well-defined when the 1116d0d1aee5SDaniel Vetter * connector is connected to a CRTC. In atomic the DRM core enforces that 1117d0d1aee5SDaniel Vetter * "ACTIVE" is off in such a case, no such checks exists for "DPMS". 1118d0d1aee5SDaniel Vetter * 1119d0d1aee5SDaniel Vetter * Finally, when enabling an output using the legacy SETCONFIG ioctl then 1120d0d1aee5SDaniel Vetter * "DPMS" is forced to ON. But see above, that might not be reflected in 1121d0d1aee5SDaniel Vetter * the software value on legacy drivers. 1122d0d1aee5SDaniel Vetter * 1123d0d1aee5SDaniel Vetter * Summarizing: Only set "DPMS" when the connector is known to be enabled, 1124d0d1aee5SDaniel Vetter * assume that a successful SETCONFIG call also sets "DPMS" to on, and 1125d0d1aee5SDaniel Vetter * never read back the value of "DPMS" because it can be incorrect. 11264ada6f22SDaniel Vetter * PATH: 11274ada6f22SDaniel Vetter * Connector path property to identify how this sink is physically 11284ada6f22SDaniel Vetter * connected. Used by DP MST. This should be set by calling 112997e14fbeSDaniel Vetter * drm_connector_set_path_property(), in the case of DP MST with the 11304ada6f22SDaniel Vetter * path property the MST manager created. Userspace cannot change this 11314ada6f22SDaniel Vetter * property. 11324ada6f22SDaniel Vetter * TILE: 11334ada6f22SDaniel Vetter * Connector tile group property to indicate how a set of DRM connector 11344ada6f22SDaniel Vetter * compose together into one logical screen. This is used by both high-res 11354ada6f22SDaniel Vetter * external screens (often only using a single cable, but exposing multiple 11364ada6f22SDaniel Vetter * DP MST sinks), or high-res integrated panels (like dual-link DSI) which 11374ada6f22SDaniel Vetter * are not gen-locked. Note that for tiled panels which are genlocked, like 11384ada6f22SDaniel Vetter * dual-link LVDS or dual-link DSI, the driver should try to not expose the 113984e543bcSAntonio Borneo * tiling and virtualise both &drm_crtc and &drm_plane if needed. Drivers 114097e14fbeSDaniel Vetter * should update this value using drm_connector_set_tile_property(). 11414ada6f22SDaniel Vetter * Userspace cannot change this property. 114240ee6fbeSManasi Navare * link-status: 1143716719a3SSean Paul * Connector link-status property to indicate the status of link. The 1144716719a3SSean Paul * default value of link-status is "GOOD". If something fails during or 1145716719a3SSean Paul * after modeset, the kernel driver may set this to "BAD" and issue a 1146716719a3SSean Paul * hotplug uevent. Drivers should update this value using 114797e14fbeSDaniel Vetter * drm_connector_set_link_status_property(). 1148a66da873SSimon Ser * 1149a66da873SSimon Ser * When user-space receives the hotplug uevent and detects a "BAD" 1150a66da873SSimon Ser * link-status, the sink doesn't receive pixels anymore (e.g. the screen 1151a66da873SSimon Ser * becomes completely black). The list of available modes may have 1152a66da873SSimon Ser * changed. User-space is expected to pick a new mode if the current one 1153a66da873SSimon Ser * has disappeared and perform a new modeset with link-status set to 1154a66da873SSimon Ser * "GOOD" to re-enable the connector. 1155a66da873SSimon Ser * 1156a66da873SSimon Ser * If multiple connectors share the same CRTC and one of them gets a "BAD" 1157a66da873SSimon Ser * link-status, the other are unaffected (ie. the sinks still continue to 1158a66da873SSimon Ser * receive pixels). 1159a66da873SSimon Ser * 1160a66da873SSimon Ser * When user-space performs an atomic commit on a connector with a "BAD" 1161a66da873SSimon Ser * link-status without resetting the property to "GOOD", the sink may 1162a66da873SSimon Ser * still not receive pixels. When user-space performs an atomic commit 1163a66da873SSimon Ser * which resets the link-status property to "GOOD" without the 1164a66da873SSimon Ser * ALLOW_MODESET flag set, it might fail because a modeset is required. 1165a66da873SSimon Ser * 1166a66da873SSimon Ser * User-space can only change link-status to "GOOD", changing it to "BAD" 1167a66da873SSimon Ser * is a no-op. 1168a66da873SSimon Ser * 1169a66da873SSimon Ser * For backwards compatibility with non-atomic userspace the kernel 1170a66da873SSimon Ser * tries to automatically set the link-status back to "GOOD" in the 1171a66da873SSimon Ser * SETCRTC IOCTL. This might fail if the mode is no longer valid, similar 1172a66da873SSimon Ser * to how it might fail if a different screen has been connected in the 1173a66da873SSimon Ser * interim. 117466660d4cSDave Airlie * non_desktop: 117566660d4cSDave Airlie * Indicates the output should be ignored for purposes of displaying a 117666660d4cSDave Airlie * standard desktop environment or console. This is most likely because 117766660d4cSDave Airlie * the output device is not rectilinear. 117824557865SSean Paul * Content Protection: 117924557865SSean Paul * This property is used by userspace to request the kernel protect future 118024557865SSean Paul * content communicated over the link. When requested, kernel will apply 118124557865SSean Paul * the appropriate means of protection (most often HDCP), and use the 118224557865SSean Paul * property to tell userspace the protection is active. 118324557865SSean Paul * 118424557865SSean Paul * Drivers can set this up by calling 118524557865SSean Paul * drm_connector_attach_content_protection_property() on initialization. 118624557865SSean Paul * 118724557865SSean Paul * The value of this property can be one of the following: 118824557865SSean Paul * 1189bbeba09fSDaniel Vetter * DRM_MODE_CONTENT_PROTECTION_UNDESIRED = 0 119024557865SSean Paul * The link is not protected, content is transmitted in the clear. 1191bbeba09fSDaniel Vetter * DRM_MODE_CONTENT_PROTECTION_DESIRED = 1 119224557865SSean Paul * Userspace has requested content protection, but the link is not 119324557865SSean Paul * currently protected. When in this state, kernel should enable 119424557865SSean Paul * Content Protection as soon as possible. 1195bbeba09fSDaniel Vetter * DRM_MODE_CONTENT_PROTECTION_ENABLED = 2 119624557865SSean Paul * Userspace has requested content protection, and the link is 119724557865SSean Paul * protected. Only the driver can set the property to this value. 119824557865SSean Paul * If userspace attempts to set to ENABLED, kernel will return 119924557865SSean Paul * -EINVAL. 120024557865SSean Paul * 120124557865SSean Paul * A few guidelines: 120224557865SSean Paul * 120324557865SSean Paul * - DESIRED state should be preserved until userspace de-asserts it by 120424557865SSean Paul * setting the property to UNDESIRED. This means ENABLED should only 120524557865SSean Paul * transition to UNDESIRED when the user explicitly requests it. 120624557865SSean Paul * - If the state is DESIRED, kernel should attempt to re-authenticate the 120724557865SSean Paul * link whenever possible. This includes across disable/enable, dpms, 120824557865SSean Paul * hotplug, downstream device changes, link status failures, etc.. 1209bb5a45d4SRamalingam C * - Kernel sends uevent with the connector id and property id through 1210bb5a45d4SRamalingam C * @drm_hdcp_update_content_protection, upon below kernel triggered 1211bb5a45d4SRamalingam C * scenarios: 121212db36bcSSean Paul * 121312db36bcSSean Paul * - DESIRED -> ENABLED (authentication success) 121412db36bcSSean Paul * - ENABLED -> DESIRED (termination of authentication) 1215bb5a45d4SRamalingam C * - Please note no uevents for userspace triggered property state changes, 1216bb5a45d4SRamalingam C * which can't fail such as 121712db36bcSSean Paul * 121812db36bcSSean Paul * - DESIRED/ENABLED -> UNDESIRED 121912db36bcSSean Paul * - UNDESIRED -> DESIRED 1220bb5a45d4SRamalingam C * - Userspace is responsible for polling the property or listen to uevents 1221bb5a45d4SRamalingam C * to determine when the value transitions from ENABLED to DESIRED. 1222bb5a45d4SRamalingam C * This signifies the link is no longer protected and userspace should 1223bb5a45d4SRamalingam C * take appropriate action (whatever that might be). 12244ada6f22SDaniel Vetter * 12257672dbbaSRamalingam C * HDCP Content Type: 12267672dbbaSRamalingam C * This Enum property is used by the userspace to declare the content type 12277672dbbaSRamalingam C * of the display stream, to kernel. Here display stream stands for any 12287672dbbaSRamalingam C * display content that userspace intended to display through HDCP 12297672dbbaSRamalingam C * encryption. 12307672dbbaSRamalingam C * 12317672dbbaSRamalingam C * Content Type of a stream is decided by the owner of the stream, as 12327672dbbaSRamalingam C * "HDCP Type0" or "HDCP Type1". 12337672dbbaSRamalingam C * 12347672dbbaSRamalingam C * The value of the property can be one of the below: 12357672dbbaSRamalingam C * - "HDCP Type0": DRM_MODE_HDCP_CONTENT_TYPE0 = 0 12367672dbbaSRamalingam C * - "HDCP Type1": DRM_MODE_HDCP_CONTENT_TYPE1 = 1 12377672dbbaSRamalingam C * 12387672dbbaSRamalingam C * When kernel starts the HDCP authentication (see "Content Protection" 12397672dbbaSRamalingam C * for details), it uses the content type in "HDCP Content Type" 12407672dbbaSRamalingam C * for performing the HDCP authentication with the display sink. 12417672dbbaSRamalingam C * 12427672dbbaSRamalingam C * Please note in HDCP spec versions, a link can be authenticated with 12437672dbbaSRamalingam C * HDCP 2.2 for Content Type 0/Content Type 1. Where as a link can be 12447672dbbaSRamalingam C * authenticated with HDCP1.4 only for Content Type 0(though it is implicit 12457672dbbaSRamalingam C * in nature. As there is no reference for Content Type in HDCP1.4). 12467672dbbaSRamalingam C * 12477672dbbaSRamalingam C * HDCP2.2 authentication protocol itself takes the "Content Type" as a 12487672dbbaSRamalingam C * parameter, which is a input for the DP HDCP2.2 encryption algo. 12497672dbbaSRamalingam C * 12507672dbbaSRamalingam C * In case of Type 0 content protection request, kernel driver can choose 12517672dbbaSRamalingam C * either of HDCP spec versions 1.4 and 2.2. When HDCP2.2 is used for 12527672dbbaSRamalingam C * "HDCP Type 0", a HDCP 2.2 capable repeater in the downstream can send 12537672dbbaSRamalingam C * that content to a HDCP 1.4 authenticated HDCP sink (Type0 link). 12547672dbbaSRamalingam C * But if the content is classified as "HDCP Type 1", above mentioned 12557672dbbaSRamalingam C * HDCP 2.2 repeater wont send the content to the HDCP sink as it can't 12567672dbbaSRamalingam C * authenticate the HDCP1.4 capable sink for "HDCP Type 1". 12577672dbbaSRamalingam C * 12587672dbbaSRamalingam C * Please note userspace can be ignorant of the HDCP versions used by the 12597672dbbaSRamalingam C * kernel driver to achieve the "HDCP Content Type". 12607672dbbaSRamalingam C * 12617672dbbaSRamalingam C * At current scenario, classifying a content as Type 1 ensures that the 12627672dbbaSRamalingam C * content will be displayed only through the HDCP2.2 encrypted link. 12637672dbbaSRamalingam C * 12647672dbbaSRamalingam C * Note that the HDCP Content Type property is introduced at HDCP 2.2, and 12657672dbbaSRamalingam C * defaults to type 0. It is only exposed by drivers supporting HDCP 2.2 12667672dbbaSRamalingam C * (hence supporting Type 0 and Type 1). Based on how next versions of 12677672dbbaSRamalingam C * HDCP specs are defined content Type could be used for higher versions 12687672dbbaSRamalingam C * too. 12697672dbbaSRamalingam C * 12707672dbbaSRamalingam C * If content type is changed when "Content Protection" is not UNDESIRED, 12717672dbbaSRamalingam C * then kernel will disable the HDCP and re-enable with new type in the 12727672dbbaSRamalingam C * same atomic commit. And when "Content Protection" is ENABLED, it means 12737672dbbaSRamalingam C * that link is HDCP authenticated and encrypted, for the transmission of 12747672dbbaSRamalingam C * the Type of stream mentioned at "HDCP Content Type". 12757672dbbaSRamalingam C * 1276a09db883SUma Shankar * HDR_OUTPUT_METADATA: 1277a09db883SUma Shankar * Connector property to enable userspace to send HDR Metadata to 1278a09db883SUma Shankar * driver. This metadata is based on the composition and blending 1279a09db883SUma Shankar * policies decided by user, taking into account the hardware and 1280a09db883SUma Shankar * sink capabilities. The driver gets this metadata and creates a 1281a09db883SUma Shankar * Dynamic Range and Mastering Infoframe (DRM) in case of HDMI, 1282a09db883SUma Shankar * SDP packet (Non-audio INFOFRAME SDP v1.3) for DP. This is then 1283a09db883SUma Shankar * sent to sink. This notifies the sink of the upcoming frame's Color 1284a09db883SUma Shankar * Encoding and Luminance parameters. 1285a09db883SUma Shankar * 1286a09db883SUma Shankar * Userspace first need to detect the HDR capabilities of sink by 1287a09db883SUma Shankar * reading and parsing the EDID. Details of HDR metadata for HDMI 1288a09db883SUma Shankar * are added in CTA 861.G spec. For DP , its defined in VESA DP 1289a09db883SUma Shankar * Standard v1.4. It needs to then get the metadata information 1290a09db883SUma Shankar * of the video/game/app content which are encoded in HDR (basically 1291a09db883SUma Shankar * using HDR transfer functions). With this information it needs to 1292a09db883SUma Shankar * decide on a blending policy and compose the relevant 1293a09db883SUma Shankar * layers/overlays into a common format. Once this blending is done, 1294a09db883SUma Shankar * userspace will be aware of the metadata of the composed frame to 1295a09db883SUma Shankar * be send to sink. It then uses this property to communicate this 1296a09db883SUma Shankar * metadata to driver which then make a Infoframe packet and sends 1297a09db883SUma Shankar * to sink based on the type of encoder connected. 1298a09db883SUma Shankar * 1299a09db883SUma Shankar * Userspace will be responsible to do Tone mapping operation in case: 1300a09db883SUma Shankar * - Some layers are HDR and others are SDR 1301a09db883SUma Shankar * - HDR layers luminance is not same as sink 13029f9b2559SSean Paul * 1303a09db883SUma Shankar * It will even need to do colorspace conversion and get all layers 1304a09db883SUma Shankar * to one common colorspace for blending. It can use either GL, Media 130584e543bcSAntonio Borneo * or display engine to get this done based on the capabilities of the 1306a09db883SUma Shankar * associated hardware. 1307a09db883SUma Shankar * 1308a09db883SUma Shankar * Driver expects metadata to be put in &struct hdr_output_metadata 1309a09db883SUma Shankar * structure from userspace. This is received as blob and stored in 1310a09db883SUma Shankar * &drm_connector_state.hdr_output_metadata. It parses EDID and saves the 1311a09db883SUma Shankar * sink metadata in &struct hdr_sink_metadata, as 1312a09db883SUma Shankar * &drm_connector.hdr_sink_metadata. Driver uses 1313a09db883SUma Shankar * drm_hdmi_infoframe_set_hdr_metadata() helper to set the HDR metadata, 1314a09db883SUma Shankar * hdmi_drm_infoframe_pack() to pack the infoframe as per spec, in case of 1315a09db883SUma Shankar * HDMI encoder. 1316a09db883SUma Shankar * 131747e22ff1SRadhakrishna Sripada * max bpc: 131847e22ff1SRadhakrishna Sripada * This range property is used by userspace to limit the bit depth. When 131947e22ff1SRadhakrishna Sripada * used the driver would limit the bpc in accordance with the valid range 132047e22ff1SRadhakrishna Sripada * supported by the hardware and sink. Drivers to use the function 132147e22ff1SRadhakrishna Sripada * drm_connector_attach_max_bpc_property() to create and attach the 132247e22ff1SRadhakrishna Sripada * property to the connector during initialization. 132347e22ff1SRadhakrishna Sripada * 13244ada6f22SDaniel Vetter * Connectors also have one standardized atomic property: 13254ada6f22SDaniel Vetter * 13264ada6f22SDaniel Vetter * CRTC_ID: 13274ada6f22SDaniel Vetter * Mode object ID of the &drm_crtc this connector should be connected to. 13288d70f395SHans de Goede * 13298d70f395SHans de Goede * Connectors for LCD panels may also have one standardized property: 13308d70f395SHans de Goede * 13318d70f395SHans de Goede * panel orientation: 13328d70f395SHans de Goede * On some devices the LCD panel is mounted in the casing in such a way 13338d70f395SHans de Goede * that the up/top side of the panel does not match with the top side of 13348d70f395SHans de Goede * the device. Userspace can use this property to check for this. 13358d70f395SHans de Goede * Note that input coordinates from touchscreens (input devices with 13368d70f395SHans de Goede * INPUT_PROP_DIRECT) will still map 1:1 to the actual LCD panel 13378d70f395SHans de Goede * coordinates, so if userspace rotates the picture to adjust for 13388d70f395SHans de Goede * the orientation it must also apply the same transformation to the 1339bbeba09fSDaniel Vetter * touchscreen input coordinates. This property is initialized by calling 134069654c63SDerek Basehore * drm_connector_set_panel_orientation() or 134169654c63SDerek Basehore * drm_connector_set_panel_orientation_with_quirk() 1342bbeba09fSDaniel Vetter * 1343bbeba09fSDaniel Vetter * scaling mode: 1344bbeba09fSDaniel Vetter * This property defines how a non-native mode is upscaled to the native 1345bbeba09fSDaniel Vetter * mode of an LCD panel: 1346bbeba09fSDaniel Vetter * 1347bbeba09fSDaniel Vetter * None: 1348bbeba09fSDaniel Vetter * No upscaling happens, scaling is left to the panel. Not all 1349bbeba09fSDaniel Vetter * drivers expose this mode. 1350bbeba09fSDaniel Vetter * Full: 1351bbeba09fSDaniel Vetter * The output is upscaled to the full resolution of the panel, 1352bbeba09fSDaniel Vetter * ignoring the aspect ratio. 1353bbeba09fSDaniel Vetter * Center: 1354bbeba09fSDaniel Vetter * No upscaling happens, the output is centered within the native 1355bbeba09fSDaniel Vetter * resolution the panel. 1356bbeba09fSDaniel Vetter * Full aspect: 1357bbeba09fSDaniel Vetter * The output is upscaled to maximize either the width or height 1358bbeba09fSDaniel Vetter * while retaining the aspect ratio. 1359bbeba09fSDaniel Vetter * 1360bbeba09fSDaniel Vetter * This property should be set up by calling 1361bbeba09fSDaniel Vetter * drm_connector_attach_scaling_mode_property(). Note that drivers 1362bbeba09fSDaniel Vetter * can also expose this property to external outputs, in which case they 1363bbeba09fSDaniel Vetter * must support "None", which should be the default (since external screens 1364bbeba09fSDaniel Vetter * have a built-in scaler). 1365e5b92773SOleg Vasilev * 1366e5b92773SOleg Vasilev * subconnector: 1367e5b92773SOleg Vasilev * This property is used by DVI-I, TVout and DisplayPort to indicate different 1368e5b92773SOleg Vasilev * connector subtypes. Enum values more or less match with those from main 1369e5b92773SOleg Vasilev * connector types. 1370e5b92773SOleg Vasilev * For DVI-I and TVout there is also a matching property "select subconnector" 1371e5b92773SOleg Vasilev * allowing to switch between signal types. 1372e5b92773SOleg Vasilev * DP subconnector corresponds to a downstream port. 1373107fe904SRajat Jain * 1374107fe904SRajat Jain * privacy-screen sw-state, privacy-screen hw-state: 1375107fe904SRajat Jain * These 2 optional properties can be used to query the state of the 1376107fe904SRajat Jain * electronic privacy screen that is available on some displays; and in 1377107fe904SRajat Jain * some cases also control the state. If a driver implements these 1378107fe904SRajat Jain * properties then both properties must be present. 1379107fe904SRajat Jain * 1380107fe904SRajat Jain * "privacy-screen hw-state" is read-only and reflects the actual state 1381107fe904SRajat Jain * of the privacy-screen, possible values: "Enabled", "Disabled, 1382107fe904SRajat Jain * "Enabled-locked", "Disabled-locked". The locked states indicate 1383107fe904SRajat Jain * that the state cannot be changed through the DRM API. E.g. there 1384107fe904SRajat Jain * might be devices where the firmware-setup options, or a hardware 1385107fe904SRajat Jain * slider-switch, offer always on / off modes. 1386107fe904SRajat Jain * 1387107fe904SRajat Jain * "privacy-screen sw-state" can be set to change the privacy-screen state 1388107fe904SRajat Jain * when not locked. In this case the driver must update the hw-state 1389107fe904SRajat Jain * property to reflect the new state on completion of the commit of the 1390107fe904SRajat Jain * sw-state property. Setting the sw-state property when the hw-state is 1391107fe904SRajat Jain * locked must be interpreted by the driver as a request to change the 1392107fe904SRajat Jain * state to the set state when the hw-state becomes unlocked. E.g. if 1393107fe904SRajat Jain * "privacy-screen hw-state" is "Enabled-locked" and the sw-state 1394107fe904SRajat Jain * gets set to "Disabled" followed by the user unlocking the state by 1395107fe904SRajat Jain * changing the slider-switch position, then the driver must set the 1396107fe904SRajat Jain * state to "Disabled" upon receiving the unlock event. 1397107fe904SRajat Jain * 1398107fe904SRajat Jain * In some cases the privacy-screen's actual state might change outside of 1399107fe904SRajat Jain * control of the DRM code. E.g. there might be a firmware handled hotkey 1400107fe904SRajat Jain * which toggles the actual state, or the actual state might be changed 1401107fe904SRajat Jain * through another userspace API such as writing /proc/acpi/ibm/lcdshadow. 1402107fe904SRajat Jain * In this case the driver must update both the hw-state and the sw-state 1403107fe904SRajat Jain * to reflect the new value, overwriting any pending state requests in the 1404107fe904SRajat Jain * sw-state. Any pending sw-state requests are thus discarded. 1405107fe904SRajat Jain * 1406107fe904SRajat Jain * Note that the ability for the state to change outside of control of 1407107fe904SRajat Jain * the DRM master process means that userspace must not cache the value 1408107fe904SRajat Jain * of the sw-state. Caching the sw-state value and including it in later 1409107fe904SRajat Jain * atomic commits may lead to overriding a state change done through e.g. 1410107fe904SRajat Jain * a firmware handled hotkey. Therefor userspace must not include the 1411107fe904SRajat Jain * privacy-screen sw-state in an atomic commit unless it wants to change 1412107fe904SRajat Jain * its value. 14134ada6f22SDaniel Vetter */ 14144ada6f22SDaniel Vetter 141552217195SDaniel Vetter int drm_connector_create_standard_properties(struct drm_device *dev) 141652217195SDaniel Vetter { 141752217195SDaniel Vetter struct drm_property *prop; 141852217195SDaniel Vetter 141952217195SDaniel Vetter prop = drm_property_create(dev, DRM_MODE_PROP_BLOB | 142052217195SDaniel Vetter DRM_MODE_PROP_IMMUTABLE, 142152217195SDaniel Vetter "EDID", 0); 142252217195SDaniel Vetter if (!prop) 142352217195SDaniel Vetter return -ENOMEM; 142452217195SDaniel Vetter dev->mode_config.edid_property = prop; 142552217195SDaniel Vetter 142652217195SDaniel Vetter prop = drm_property_create_enum(dev, 0, 142752217195SDaniel Vetter "DPMS", drm_dpms_enum_list, 142852217195SDaniel Vetter ARRAY_SIZE(drm_dpms_enum_list)); 142952217195SDaniel Vetter if (!prop) 143052217195SDaniel Vetter return -ENOMEM; 143152217195SDaniel Vetter dev->mode_config.dpms_property = prop; 143252217195SDaniel Vetter 143352217195SDaniel Vetter prop = drm_property_create(dev, 143452217195SDaniel Vetter DRM_MODE_PROP_BLOB | 143552217195SDaniel Vetter DRM_MODE_PROP_IMMUTABLE, 143652217195SDaniel Vetter "PATH", 0); 143752217195SDaniel Vetter if (!prop) 143852217195SDaniel Vetter return -ENOMEM; 143952217195SDaniel Vetter dev->mode_config.path_property = prop; 144052217195SDaniel Vetter 144152217195SDaniel Vetter prop = drm_property_create(dev, 144252217195SDaniel Vetter DRM_MODE_PROP_BLOB | 144352217195SDaniel Vetter DRM_MODE_PROP_IMMUTABLE, 144452217195SDaniel Vetter "TILE", 0); 144552217195SDaniel Vetter if (!prop) 144652217195SDaniel Vetter return -ENOMEM; 144752217195SDaniel Vetter dev->mode_config.tile_property = prop; 144852217195SDaniel Vetter 144940ee6fbeSManasi Navare prop = drm_property_create_enum(dev, 0, "link-status", 145040ee6fbeSManasi Navare drm_link_status_enum_list, 145140ee6fbeSManasi Navare ARRAY_SIZE(drm_link_status_enum_list)); 145240ee6fbeSManasi Navare if (!prop) 145340ee6fbeSManasi Navare return -ENOMEM; 145440ee6fbeSManasi Navare dev->mode_config.link_status_property = prop; 145540ee6fbeSManasi Navare 145666660d4cSDave Airlie prop = drm_property_create_bool(dev, DRM_MODE_PROP_IMMUTABLE, "non-desktop"); 145766660d4cSDave Airlie if (!prop) 145866660d4cSDave Airlie return -ENOMEM; 145966660d4cSDave Airlie dev->mode_config.non_desktop_property = prop; 146066660d4cSDave Airlie 1461fbb5d035SUma Shankar prop = drm_property_create(dev, DRM_MODE_PROP_BLOB, 1462fbb5d035SUma Shankar "HDR_OUTPUT_METADATA", 0); 1463fbb5d035SUma Shankar if (!prop) 1464fbb5d035SUma Shankar return -ENOMEM; 1465fbb5d035SUma Shankar dev->mode_config.hdr_output_metadata_property = prop; 1466fbb5d035SUma Shankar 146752217195SDaniel Vetter return 0; 146852217195SDaniel Vetter } 146952217195SDaniel Vetter 147052217195SDaniel Vetter /** 147152217195SDaniel Vetter * drm_mode_create_dvi_i_properties - create DVI-I specific connector properties 147252217195SDaniel Vetter * @dev: DRM device 147352217195SDaniel Vetter * 147452217195SDaniel Vetter * Called by a driver the first time a DVI-I connector is made. 1475f85d9e59SRandy Dunlap * 1476f85d9e59SRandy Dunlap * Returns: %0 147752217195SDaniel Vetter */ 147852217195SDaniel Vetter int drm_mode_create_dvi_i_properties(struct drm_device *dev) 147952217195SDaniel Vetter { 148052217195SDaniel Vetter struct drm_property *dvi_i_selector; 148152217195SDaniel Vetter struct drm_property *dvi_i_subconnector; 148252217195SDaniel Vetter 148352217195SDaniel Vetter if (dev->mode_config.dvi_i_select_subconnector_property) 148452217195SDaniel Vetter return 0; 148552217195SDaniel Vetter 148652217195SDaniel Vetter dvi_i_selector = 148752217195SDaniel Vetter drm_property_create_enum(dev, 0, 148852217195SDaniel Vetter "select subconnector", 148952217195SDaniel Vetter drm_dvi_i_select_enum_list, 149052217195SDaniel Vetter ARRAY_SIZE(drm_dvi_i_select_enum_list)); 149152217195SDaniel Vetter dev->mode_config.dvi_i_select_subconnector_property = dvi_i_selector; 149252217195SDaniel Vetter 149352217195SDaniel Vetter dvi_i_subconnector = drm_property_create_enum(dev, DRM_MODE_PROP_IMMUTABLE, 149452217195SDaniel Vetter "subconnector", 149552217195SDaniel Vetter drm_dvi_i_subconnector_enum_list, 149652217195SDaniel Vetter ARRAY_SIZE(drm_dvi_i_subconnector_enum_list)); 149752217195SDaniel Vetter dev->mode_config.dvi_i_subconnector_property = dvi_i_subconnector; 149852217195SDaniel Vetter 149952217195SDaniel Vetter return 0; 150052217195SDaniel Vetter } 150152217195SDaniel Vetter EXPORT_SYMBOL(drm_mode_create_dvi_i_properties); 150252217195SDaniel Vetter 150352217195SDaniel Vetter /** 1504e5b92773SOleg Vasilev * drm_connector_attach_dp_subconnector_property - create subconnector property for DP 1505e5b92773SOleg Vasilev * @connector: drm_connector to attach property 1506e5b92773SOleg Vasilev * 1507e5b92773SOleg Vasilev * Called by a driver when DP connector is created. 1508e5b92773SOleg Vasilev */ 1509e5b92773SOleg Vasilev void drm_connector_attach_dp_subconnector_property(struct drm_connector *connector) 1510e5b92773SOleg Vasilev { 1511e5b92773SOleg Vasilev struct drm_mode_config *mode_config = &connector->dev->mode_config; 1512e5b92773SOleg Vasilev 1513e5b92773SOleg Vasilev if (!mode_config->dp_subconnector_property) 1514e5b92773SOleg Vasilev mode_config->dp_subconnector_property = 1515e5b92773SOleg Vasilev drm_property_create_enum(connector->dev, 1516e5b92773SOleg Vasilev DRM_MODE_PROP_IMMUTABLE, 1517e5b92773SOleg Vasilev "subconnector", 1518e5b92773SOleg Vasilev drm_dp_subconnector_enum_list, 1519e5b92773SOleg Vasilev ARRAY_SIZE(drm_dp_subconnector_enum_list)); 1520e5b92773SOleg Vasilev 1521e5b92773SOleg Vasilev drm_object_attach_property(&connector->base, 1522e5b92773SOleg Vasilev mode_config->dp_subconnector_property, 1523e5b92773SOleg Vasilev DRM_MODE_SUBCONNECTOR_Unknown); 1524e5b92773SOleg Vasilev } 1525e5b92773SOleg Vasilev EXPORT_SYMBOL(drm_connector_attach_dp_subconnector_property); 1526e5b92773SOleg Vasilev 1527e5b92773SOleg Vasilev /** 152850525c33SStanislav Lisovskiy * DOC: HDMI connector properties 152950525c33SStanislav Lisovskiy * 153050525c33SStanislav Lisovskiy * content type (HDMI specific): 153150525c33SStanislav Lisovskiy * Indicates content type setting to be used in HDMI infoframes to indicate 15321e55a53aSMatt Roper * content type for the external device, so that it adjusts its display 153350525c33SStanislav Lisovskiy * settings accordingly. 153450525c33SStanislav Lisovskiy * 153550525c33SStanislav Lisovskiy * The value of this property can be one of the following: 153650525c33SStanislav Lisovskiy * 153750525c33SStanislav Lisovskiy * No Data: 153850525c33SStanislav Lisovskiy * Content type is unknown 153950525c33SStanislav Lisovskiy * Graphics: 154050525c33SStanislav Lisovskiy * Content type is graphics 154150525c33SStanislav Lisovskiy * Photo: 154250525c33SStanislav Lisovskiy * Content type is photo 154350525c33SStanislav Lisovskiy * Cinema: 154450525c33SStanislav Lisovskiy * Content type is cinema 154550525c33SStanislav Lisovskiy * Game: 154650525c33SStanislav Lisovskiy * Content type is game 154750525c33SStanislav Lisovskiy * 1548a0a33067SSimon Ser * The meaning of each content type is defined in CTA-861-G table 15. 1549a0a33067SSimon Ser * 155050525c33SStanislav Lisovskiy * Drivers can set up this property by calling 155150525c33SStanislav Lisovskiy * drm_connector_attach_content_type_property(). Decoding to 1552ba609631SDaniel Vetter * infoframe values is done through drm_hdmi_avi_infoframe_content_type(). 155350525c33SStanislav Lisovskiy */ 155450525c33SStanislav Lisovskiy 155550525c33SStanislav Lisovskiy /** 155650525c33SStanislav Lisovskiy * drm_connector_attach_content_type_property - attach content-type property 155750525c33SStanislav Lisovskiy * @connector: connector to attach content type property on. 155850525c33SStanislav Lisovskiy * 155950525c33SStanislav Lisovskiy * Called by a driver the first time a HDMI connector is made. 1560f85d9e59SRandy Dunlap * 1561f85d9e59SRandy Dunlap * Returns: %0 156250525c33SStanislav Lisovskiy */ 156350525c33SStanislav Lisovskiy int drm_connector_attach_content_type_property(struct drm_connector *connector) 156450525c33SStanislav Lisovskiy { 156550525c33SStanislav Lisovskiy if (!drm_mode_create_content_type_property(connector->dev)) 156650525c33SStanislav Lisovskiy drm_object_attach_property(&connector->base, 156750525c33SStanislav Lisovskiy connector->dev->mode_config.content_type_property, 156850525c33SStanislav Lisovskiy DRM_MODE_CONTENT_TYPE_NO_DATA); 156950525c33SStanislav Lisovskiy return 0; 157050525c33SStanislav Lisovskiy } 157150525c33SStanislav Lisovskiy EXPORT_SYMBOL(drm_connector_attach_content_type_property); 157250525c33SStanislav Lisovskiy 157350525c33SStanislav Lisovskiy /** 1574e9d2871fSMauro Carvalho Chehab * drm_connector_attach_tv_margin_properties - attach TV connector margin 1575e9d2871fSMauro Carvalho Chehab * properties 15766c4f52dcSBoris Brezillon * @connector: DRM connector 15776c4f52dcSBoris Brezillon * 15786c4f52dcSBoris Brezillon * Called by a driver when it needs to attach TV margin props to a connector. 15796c4f52dcSBoris Brezillon * Typically used on SDTV and HDMI connectors. 15806c4f52dcSBoris Brezillon */ 15816c4f52dcSBoris Brezillon void drm_connector_attach_tv_margin_properties(struct drm_connector *connector) 15826c4f52dcSBoris Brezillon { 15836c4f52dcSBoris Brezillon struct drm_device *dev = connector->dev; 15846c4f52dcSBoris Brezillon 15856c4f52dcSBoris Brezillon drm_object_attach_property(&connector->base, 15866c4f52dcSBoris Brezillon dev->mode_config.tv_left_margin_property, 15876c4f52dcSBoris Brezillon 0); 15886c4f52dcSBoris Brezillon drm_object_attach_property(&connector->base, 15896c4f52dcSBoris Brezillon dev->mode_config.tv_right_margin_property, 15906c4f52dcSBoris Brezillon 0); 15916c4f52dcSBoris Brezillon drm_object_attach_property(&connector->base, 15926c4f52dcSBoris Brezillon dev->mode_config.tv_top_margin_property, 15936c4f52dcSBoris Brezillon 0); 15946c4f52dcSBoris Brezillon drm_object_attach_property(&connector->base, 15956c4f52dcSBoris Brezillon dev->mode_config.tv_bottom_margin_property, 15966c4f52dcSBoris Brezillon 0); 15976c4f52dcSBoris Brezillon } 15986c4f52dcSBoris Brezillon EXPORT_SYMBOL(drm_connector_attach_tv_margin_properties); 15996c4f52dcSBoris Brezillon 16006c4f52dcSBoris Brezillon /** 16016c4f52dcSBoris Brezillon * drm_mode_create_tv_margin_properties - create TV connector margin properties 16026c4f52dcSBoris Brezillon * @dev: DRM device 16036c4f52dcSBoris Brezillon * 16046c4f52dcSBoris Brezillon * Called by a driver's HDMI connector initialization routine, this function 16056c4f52dcSBoris Brezillon * creates the TV margin properties for a given device. No need to call this 16066c4f52dcSBoris Brezillon * function for an SDTV connector, it's already called from 16076c4f52dcSBoris Brezillon * drm_mode_create_tv_properties(). 1608f85d9e59SRandy Dunlap * 1609f85d9e59SRandy Dunlap * Returns: 1610f85d9e59SRandy Dunlap * 0 on success or a negative error code on failure. 16116c4f52dcSBoris Brezillon */ 16126c4f52dcSBoris Brezillon int drm_mode_create_tv_margin_properties(struct drm_device *dev) 16136c4f52dcSBoris Brezillon { 16146c4f52dcSBoris Brezillon if (dev->mode_config.tv_left_margin_property) 16156c4f52dcSBoris Brezillon return 0; 16166c4f52dcSBoris Brezillon 16176c4f52dcSBoris Brezillon dev->mode_config.tv_left_margin_property = 16186c4f52dcSBoris Brezillon drm_property_create_range(dev, 0, "left margin", 0, 100); 16196c4f52dcSBoris Brezillon if (!dev->mode_config.tv_left_margin_property) 16206c4f52dcSBoris Brezillon return -ENOMEM; 16216c4f52dcSBoris Brezillon 16226c4f52dcSBoris Brezillon dev->mode_config.tv_right_margin_property = 16236c4f52dcSBoris Brezillon drm_property_create_range(dev, 0, "right margin", 0, 100); 16246c4f52dcSBoris Brezillon if (!dev->mode_config.tv_right_margin_property) 16256c4f52dcSBoris Brezillon return -ENOMEM; 16266c4f52dcSBoris Brezillon 16276c4f52dcSBoris Brezillon dev->mode_config.tv_top_margin_property = 16286c4f52dcSBoris Brezillon drm_property_create_range(dev, 0, "top margin", 0, 100); 16296c4f52dcSBoris Brezillon if (!dev->mode_config.tv_top_margin_property) 16306c4f52dcSBoris Brezillon return -ENOMEM; 16316c4f52dcSBoris Brezillon 16326c4f52dcSBoris Brezillon dev->mode_config.tv_bottom_margin_property = 16336c4f52dcSBoris Brezillon drm_property_create_range(dev, 0, "bottom margin", 0, 100); 16346c4f52dcSBoris Brezillon if (!dev->mode_config.tv_bottom_margin_property) 16356c4f52dcSBoris Brezillon return -ENOMEM; 16366c4f52dcSBoris Brezillon 16376c4f52dcSBoris Brezillon return 0; 16386c4f52dcSBoris Brezillon } 16396c4f52dcSBoris Brezillon EXPORT_SYMBOL(drm_mode_create_tv_margin_properties); 16406c4f52dcSBoris Brezillon 16416c4f52dcSBoris Brezillon /** 1642eda6887fSBoris Brezillon * drm_mode_create_tv_properties - create TV specific connector properties 164352217195SDaniel Vetter * @dev: DRM device 164452217195SDaniel Vetter * @num_modes: number of different TV formats (modes) supported 164552217195SDaniel Vetter * @modes: array of pointers to strings containing name of each format 164652217195SDaniel Vetter * 164752217195SDaniel Vetter * Called by a driver's TV initialization routine, this function creates 164852217195SDaniel Vetter * the TV specific connector properties for a given device. Caller is 164952217195SDaniel Vetter * responsible for allocating a list of format names and passing them to 165052217195SDaniel Vetter * this routine. 1651f85d9e59SRandy Dunlap * 1652f85d9e59SRandy Dunlap * Returns: 1653f85d9e59SRandy Dunlap * 0 on success or a negative error code on failure. 165452217195SDaniel Vetter */ 165552217195SDaniel Vetter int drm_mode_create_tv_properties(struct drm_device *dev, 165652217195SDaniel Vetter unsigned int num_modes, 165752217195SDaniel Vetter const char * const modes[]) 165852217195SDaniel Vetter { 165952217195SDaniel Vetter struct drm_property *tv_selector; 166052217195SDaniel Vetter struct drm_property *tv_subconnector; 166152217195SDaniel Vetter unsigned int i; 166252217195SDaniel Vetter 166352217195SDaniel Vetter if (dev->mode_config.tv_select_subconnector_property) 166452217195SDaniel Vetter return 0; 166552217195SDaniel Vetter 166652217195SDaniel Vetter /* 166752217195SDaniel Vetter * Basic connector properties 166852217195SDaniel Vetter */ 166952217195SDaniel Vetter tv_selector = drm_property_create_enum(dev, 0, 167052217195SDaniel Vetter "select subconnector", 167152217195SDaniel Vetter drm_tv_select_enum_list, 167252217195SDaniel Vetter ARRAY_SIZE(drm_tv_select_enum_list)); 167352217195SDaniel Vetter if (!tv_selector) 167452217195SDaniel Vetter goto nomem; 167552217195SDaniel Vetter 167652217195SDaniel Vetter dev->mode_config.tv_select_subconnector_property = tv_selector; 167752217195SDaniel Vetter 167852217195SDaniel Vetter tv_subconnector = 167952217195SDaniel Vetter drm_property_create_enum(dev, DRM_MODE_PROP_IMMUTABLE, 168052217195SDaniel Vetter "subconnector", 168152217195SDaniel Vetter drm_tv_subconnector_enum_list, 168252217195SDaniel Vetter ARRAY_SIZE(drm_tv_subconnector_enum_list)); 168352217195SDaniel Vetter if (!tv_subconnector) 168452217195SDaniel Vetter goto nomem; 168552217195SDaniel Vetter dev->mode_config.tv_subconnector_property = tv_subconnector; 168652217195SDaniel Vetter 168752217195SDaniel Vetter /* 168852217195SDaniel Vetter * Other, TV specific properties: margins & TV modes. 168952217195SDaniel Vetter */ 16906c4f52dcSBoris Brezillon if (drm_mode_create_tv_margin_properties(dev)) 169152217195SDaniel Vetter goto nomem; 169252217195SDaniel Vetter 169352217195SDaniel Vetter dev->mode_config.tv_mode_property = 169452217195SDaniel Vetter drm_property_create(dev, DRM_MODE_PROP_ENUM, 169552217195SDaniel Vetter "mode", num_modes); 169652217195SDaniel Vetter if (!dev->mode_config.tv_mode_property) 169752217195SDaniel Vetter goto nomem; 169852217195SDaniel Vetter 169952217195SDaniel Vetter for (i = 0; i < num_modes; i++) 170030e9db6dSVille Syrjälä drm_property_add_enum(dev->mode_config.tv_mode_property, 170152217195SDaniel Vetter i, modes[i]); 170252217195SDaniel Vetter 170352217195SDaniel Vetter dev->mode_config.tv_brightness_property = 170452217195SDaniel Vetter drm_property_create_range(dev, 0, "brightness", 0, 100); 170552217195SDaniel Vetter if (!dev->mode_config.tv_brightness_property) 170652217195SDaniel Vetter goto nomem; 170752217195SDaniel Vetter 170852217195SDaniel Vetter dev->mode_config.tv_contrast_property = 170952217195SDaniel Vetter drm_property_create_range(dev, 0, "contrast", 0, 100); 171052217195SDaniel Vetter if (!dev->mode_config.tv_contrast_property) 171152217195SDaniel Vetter goto nomem; 171252217195SDaniel Vetter 171352217195SDaniel Vetter dev->mode_config.tv_flicker_reduction_property = 171452217195SDaniel Vetter drm_property_create_range(dev, 0, "flicker reduction", 0, 100); 171552217195SDaniel Vetter if (!dev->mode_config.tv_flicker_reduction_property) 171652217195SDaniel Vetter goto nomem; 171752217195SDaniel Vetter 171852217195SDaniel Vetter dev->mode_config.tv_overscan_property = 171952217195SDaniel Vetter drm_property_create_range(dev, 0, "overscan", 0, 100); 172052217195SDaniel Vetter if (!dev->mode_config.tv_overscan_property) 172152217195SDaniel Vetter goto nomem; 172252217195SDaniel Vetter 172352217195SDaniel Vetter dev->mode_config.tv_saturation_property = 172452217195SDaniel Vetter drm_property_create_range(dev, 0, "saturation", 0, 100); 172552217195SDaniel Vetter if (!dev->mode_config.tv_saturation_property) 172652217195SDaniel Vetter goto nomem; 172752217195SDaniel Vetter 172852217195SDaniel Vetter dev->mode_config.tv_hue_property = 172952217195SDaniel Vetter drm_property_create_range(dev, 0, "hue", 0, 100); 173052217195SDaniel Vetter if (!dev->mode_config.tv_hue_property) 173152217195SDaniel Vetter goto nomem; 173252217195SDaniel Vetter 173352217195SDaniel Vetter return 0; 173452217195SDaniel Vetter nomem: 173552217195SDaniel Vetter return -ENOMEM; 173652217195SDaniel Vetter } 173752217195SDaniel Vetter EXPORT_SYMBOL(drm_mode_create_tv_properties); 173852217195SDaniel Vetter 173952217195SDaniel Vetter /** 174052217195SDaniel Vetter * drm_mode_create_scaling_mode_property - create scaling mode property 174152217195SDaniel Vetter * @dev: DRM device 174252217195SDaniel Vetter * 174352217195SDaniel Vetter * Called by a driver the first time it's needed, must be attached to desired 174452217195SDaniel Vetter * connectors. 17458f6e1e22SMaarten Lankhorst * 17468f6e1e22SMaarten Lankhorst * Atomic drivers should use drm_connector_attach_scaling_mode_property() 17479c2fce13SVille Syrjälä * instead to correctly assign &drm_connector_state.scaling_mode 17488f6e1e22SMaarten Lankhorst * in the atomic state. 1749f85d9e59SRandy Dunlap * 1750f85d9e59SRandy Dunlap * Returns: %0 175152217195SDaniel Vetter */ 175252217195SDaniel Vetter int drm_mode_create_scaling_mode_property(struct drm_device *dev) 175352217195SDaniel Vetter { 175452217195SDaniel Vetter struct drm_property *scaling_mode; 175552217195SDaniel Vetter 175652217195SDaniel Vetter if (dev->mode_config.scaling_mode_property) 175752217195SDaniel Vetter return 0; 175852217195SDaniel Vetter 175952217195SDaniel Vetter scaling_mode = 176052217195SDaniel Vetter drm_property_create_enum(dev, 0, "scaling mode", 176152217195SDaniel Vetter drm_scaling_mode_enum_list, 176252217195SDaniel Vetter ARRAY_SIZE(drm_scaling_mode_enum_list)); 176352217195SDaniel Vetter 176452217195SDaniel Vetter dev->mode_config.scaling_mode_property = scaling_mode; 176552217195SDaniel Vetter 176652217195SDaniel Vetter return 0; 176752217195SDaniel Vetter } 176852217195SDaniel Vetter EXPORT_SYMBOL(drm_mode_create_scaling_mode_property); 176952217195SDaniel Vetter 177052217195SDaniel Vetter /** 1771ab7a664fSNicholas Kazlauskas * DOC: Variable refresh properties 1772ab7a664fSNicholas Kazlauskas * 1773ab7a664fSNicholas Kazlauskas * Variable refresh rate capable displays can dynamically adjust their 1774ab7a664fSNicholas Kazlauskas * refresh rate by extending the duration of their vertical front porch 1775ab7a664fSNicholas Kazlauskas * until page flip or timeout occurs. This can reduce or remove stuttering 1776ab7a664fSNicholas Kazlauskas * and latency in scenarios where the page flip does not align with the 1777ab7a664fSNicholas Kazlauskas * vblank interval. 1778ab7a664fSNicholas Kazlauskas * 1779ab7a664fSNicholas Kazlauskas * An example scenario would be an application flipping at a constant rate 1780ab7a664fSNicholas Kazlauskas * of 48Hz on a 60Hz display. The page flip will frequently miss the vblank 1781ab7a664fSNicholas Kazlauskas * interval and the same contents will be displayed twice. This can be 1782ab7a664fSNicholas Kazlauskas * observed as stuttering for content with motion. 1783ab7a664fSNicholas Kazlauskas * 1784ab7a664fSNicholas Kazlauskas * If variable refresh rate was active on a display that supported a 1785ab7a664fSNicholas Kazlauskas * variable refresh range from 35Hz to 60Hz no stuttering would be observable 1786ab7a664fSNicholas Kazlauskas * for the example scenario. The minimum supported variable refresh rate of 1787ab7a664fSNicholas Kazlauskas * 35Hz is below the page flip frequency and the vertical front porch can 1788ab7a664fSNicholas Kazlauskas * be extended until the page flip occurs. The vblank interval will be 1789ab7a664fSNicholas Kazlauskas * directly aligned to the page flip rate. 1790ab7a664fSNicholas Kazlauskas * 1791ab7a664fSNicholas Kazlauskas * Not all userspace content is suitable for use with variable refresh rate. 1792ab7a664fSNicholas Kazlauskas * Large and frequent changes in vertical front porch duration may worsen 1793ab7a664fSNicholas Kazlauskas * perceived stuttering for input sensitive applications. 1794ab7a664fSNicholas Kazlauskas * 1795ab7a664fSNicholas Kazlauskas * Panel brightness will also vary with vertical front porch duration. Some 1796ab7a664fSNicholas Kazlauskas * panels may have noticeable differences in brightness between the minimum 1797ab7a664fSNicholas Kazlauskas * vertical front porch duration and the maximum vertical front porch duration. 1798ab7a664fSNicholas Kazlauskas * Large and frequent changes in vertical front porch duration may produce 1799ab7a664fSNicholas Kazlauskas * observable flickering for such panels. 1800ab7a664fSNicholas Kazlauskas * 1801ab7a664fSNicholas Kazlauskas * Userspace control for variable refresh rate is supported via properties 1802ab7a664fSNicholas Kazlauskas * on the &drm_connector and &drm_crtc objects. 1803ab7a664fSNicholas Kazlauskas * 1804ab7a664fSNicholas Kazlauskas * "vrr_capable": 1805ab7a664fSNicholas Kazlauskas * Optional &drm_connector boolean property that drivers should attach 1806ab7a664fSNicholas Kazlauskas * with drm_connector_attach_vrr_capable_property() on connectors that 1807ab7a664fSNicholas Kazlauskas * could support variable refresh rates. Drivers should update the 1808ab7a664fSNicholas Kazlauskas * property value by calling drm_connector_set_vrr_capable_property(). 1809ab7a664fSNicholas Kazlauskas * 1810ab7a664fSNicholas Kazlauskas * Absence of the property should indicate absence of support. 1811ab7a664fSNicholas Kazlauskas * 181277086014SDaniel Vetter * "VRR_ENABLED": 1813ab7a664fSNicholas Kazlauskas * Default &drm_crtc boolean property that notifies the driver that the 1814ab7a664fSNicholas Kazlauskas * content on the CRTC is suitable for variable refresh rate presentation. 1815ab7a664fSNicholas Kazlauskas * The driver will take this property as a hint to enable variable 1816ab7a664fSNicholas Kazlauskas * refresh rate support if the receiver supports it, ie. if the 1817ab7a664fSNicholas Kazlauskas * "vrr_capable" property is true on the &drm_connector object. The 1818ab7a664fSNicholas Kazlauskas * vertical front porch duration will be extended until page-flip or 1819ab7a664fSNicholas Kazlauskas * timeout when enabled. 1820ab7a664fSNicholas Kazlauskas * 1821ab7a664fSNicholas Kazlauskas * The minimum vertical front porch duration is defined as the vertical 1822ab7a664fSNicholas Kazlauskas * front porch duration for the current mode. 1823ab7a664fSNicholas Kazlauskas * 1824ab7a664fSNicholas Kazlauskas * The maximum vertical front porch duration is greater than or equal to 1825ab7a664fSNicholas Kazlauskas * the minimum vertical front porch duration. The duration is derived 1826ab7a664fSNicholas Kazlauskas * from the minimum supported variable refresh rate for the connector. 1827ab7a664fSNicholas Kazlauskas * 1828ab7a664fSNicholas Kazlauskas * The driver may place further restrictions within these minimum 1829ab7a664fSNicholas Kazlauskas * and maximum bounds. 1830ab7a664fSNicholas Kazlauskas */ 1831ab7a664fSNicholas Kazlauskas 1832ab7a664fSNicholas Kazlauskas /** 1833ba1b0f6cSNicholas Kazlauskas * drm_connector_attach_vrr_capable_property - creates the 1834ba1b0f6cSNicholas Kazlauskas * vrr_capable property 1835ba1b0f6cSNicholas Kazlauskas * @connector: connector to create the vrr_capable property on. 1836ba1b0f6cSNicholas Kazlauskas * 1837ba1b0f6cSNicholas Kazlauskas * This is used by atomic drivers to add support for querying 1838ba1b0f6cSNicholas Kazlauskas * variable refresh rate capability for a connector. 1839ba1b0f6cSNicholas Kazlauskas * 1840ba1b0f6cSNicholas Kazlauskas * Returns: 184184e543bcSAntonio Borneo * Zero on success, negative errno on failure. 1842ba1b0f6cSNicholas Kazlauskas */ 1843ba1b0f6cSNicholas Kazlauskas int drm_connector_attach_vrr_capable_property( 1844ba1b0f6cSNicholas Kazlauskas struct drm_connector *connector) 1845ba1b0f6cSNicholas Kazlauskas { 1846ba1b0f6cSNicholas Kazlauskas struct drm_device *dev = connector->dev; 1847ba1b0f6cSNicholas Kazlauskas struct drm_property *prop; 1848ba1b0f6cSNicholas Kazlauskas 1849ba1b0f6cSNicholas Kazlauskas if (!connector->vrr_capable_property) { 1850ba1b0f6cSNicholas Kazlauskas prop = drm_property_create_bool(dev, DRM_MODE_PROP_IMMUTABLE, 1851ba1b0f6cSNicholas Kazlauskas "vrr_capable"); 1852ba1b0f6cSNicholas Kazlauskas if (!prop) 1853ba1b0f6cSNicholas Kazlauskas return -ENOMEM; 1854ba1b0f6cSNicholas Kazlauskas 1855ba1b0f6cSNicholas Kazlauskas connector->vrr_capable_property = prop; 1856ba1b0f6cSNicholas Kazlauskas drm_object_attach_property(&connector->base, prop, 0); 1857ba1b0f6cSNicholas Kazlauskas } 1858ba1b0f6cSNicholas Kazlauskas 1859ba1b0f6cSNicholas Kazlauskas return 0; 1860ba1b0f6cSNicholas Kazlauskas } 1861ba1b0f6cSNicholas Kazlauskas EXPORT_SYMBOL(drm_connector_attach_vrr_capable_property); 1862ba1b0f6cSNicholas Kazlauskas 1863ba1b0f6cSNicholas Kazlauskas /** 18648f6e1e22SMaarten Lankhorst * drm_connector_attach_scaling_mode_property - attach atomic scaling mode property 18658f6e1e22SMaarten Lankhorst * @connector: connector to attach scaling mode property on. 18668f6e1e22SMaarten Lankhorst * @scaling_mode_mask: or'ed mask of BIT(%DRM_MODE_SCALE_\*). 18678f6e1e22SMaarten Lankhorst * 18688f6e1e22SMaarten Lankhorst * This is used to add support for scaling mode to atomic drivers. 18699c2fce13SVille Syrjälä * The scaling mode will be set to &drm_connector_state.scaling_mode 18708f6e1e22SMaarten Lankhorst * and can be used from &drm_connector_helper_funcs->atomic_check for validation. 18718f6e1e22SMaarten Lankhorst * 18728f6e1e22SMaarten Lankhorst * This is the atomic version of drm_mode_create_scaling_mode_property(). 18738f6e1e22SMaarten Lankhorst * 18748f6e1e22SMaarten Lankhorst * Returns: 18758f6e1e22SMaarten Lankhorst * Zero on success, negative errno on failure. 18768f6e1e22SMaarten Lankhorst */ 18778f6e1e22SMaarten Lankhorst int drm_connector_attach_scaling_mode_property(struct drm_connector *connector, 18788f6e1e22SMaarten Lankhorst u32 scaling_mode_mask) 18798f6e1e22SMaarten Lankhorst { 18808f6e1e22SMaarten Lankhorst struct drm_device *dev = connector->dev; 18818f6e1e22SMaarten Lankhorst struct drm_property *scaling_mode_property; 188230e9db6dSVille Syrjälä int i; 18838f6e1e22SMaarten Lankhorst const unsigned valid_scaling_mode_mask = 18848f6e1e22SMaarten Lankhorst (1U << ARRAY_SIZE(drm_scaling_mode_enum_list)) - 1; 18858f6e1e22SMaarten Lankhorst 18868f6e1e22SMaarten Lankhorst if (WARN_ON(hweight32(scaling_mode_mask) < 2 || 18878f6e1e22SMaarten Lankhorst scaling_mode_mask & ~valid_scaling_mode_mask)) 18888f6e1e22SMaarten Lankhorst return -EINVAL; 18898f6e1e22SMaarten Lankhorst 18908f6e1e22SMaarten Lankhorst scaling_mode_property = 18918f6e1e22SMaarten Lankhorst drm_property_create(dev, DRM_MODE_PROP_ENUM, "scaling mode", 18928f6e1e22SMaarten Lankhorst hweight32(scaling_mode_mask)); 18938f6e1e22SMaarten Lankhorst 18948f6e1e22SMaarten Lankhorst if (!scaling_mode_property) 18958f6e1e22SMaarten Lankhorst return -ENOMEM; 18968f6e1e22SMaarten Lankhorst 18978f6e1e22SMaarten Lankhorst for (i = 0; i < ARRAY_SIZE(drm_scaling_mode_enum_list); i++) { 18988f6e1e22SMaarten Lankhorst int ret; 18998f6e1e22SMaarten Lankhorst 19008f6e1e22SMaarten Lankhorst if (!(BIT(i) & scaling_mode_mask)) 19018f6e1e22SMaarten Lankhorst continue; 19028f6e1e22SMaarten Lankhorst 190330e9db6dSVille Syrjälä ret = drm_property_add_enum(scaling_mode_property, 19048f6e1e22SMaarten Lankhorst drm_scaling_mode_enum_list[i].type, 19058f6e1e22SMaarten Lankhorst drm_scaling_mode_enum_list[i].name); 19068f6e1e22SMaarten Lankhorst 19078f6e1e22SMaarten Lankhorst if (ret) { 19088f6e1e22SMaarten Lankhorst drm_property_destroy(dev, scaling_mode_property); 19098f6e1e22SMaarten Lankhorst 19108f6e1e22SMaarten Lankhorst return ret; 19118f6e1e22SMaarten Lankhorst } 19128f6e1e22SMaarten Lankhorst } 19138f6e1e22SMaarten Lankhorst 19148f6e1e22SMaarten Lankhorst drm_object_attach_property(&connector->base, 19158f6e1e22SMaarten Lankhorst scaling_mode_property, 0); 19168f6e1e22SMaarten Lankhorst 19178f6e1e22SMaarten Lankhorst connector->scaling_mode_property = scaling_mode_property; 19188f6e1e22SMaarten Lankhorst 19198f6e1e22SMaarten Lankhorst return 0; 19208f6e1e22SMaarten Lankhorst } 19218f6e1e22SMaarten Lankhorst EXPORT_SYMBOL(drm_connector_attach_scaling_mode_property); 19228f6e1e22SMaarten Lankhorst 19238f6e1e22SMaarten Lankhorst /** 192452217195SDaniel Vetter * drm_mode_create_aspect_ratio_property - create aspect ratio property 192552217195SDaniel Vetter * @dev: DRM device 192652217195SDaniel Vetter * 192752217195SDaniel Vetter * Called by a driver the first time it's needed, must be attached to desired 192852217195SDaniel Vetter * connectors. 192952217195SDaniel Vetter * 193052217195SDaniel Vetter * Returns: 193152217195SDaniel Vetter * Zero on success, negative errno on failure. 193252217195SDaniel Vetter */ 193352217195SDaniel Vetter int drm_mode_create_aspect_ratio_property(struct drm_device *dev) 193452217195SDaniel Vetter { 193552217195SDaniel Vetter if (dev->mode_config.aspect_ratio_property) 193652217195SDaniel Vetter return 0; 193752217195SDaniel Vetter 193852217195SDaniel Vetter dev->mode_config.aspect_ratio_property = 193952217195SDaniel Vetter drm_property_create_enum(dev, 0, "aspect ratio", 194052217195SDaniel Vetter drm_aspect_ratio_enum_list, 194152217195SDaniel Vetter ARRAY_SIZE(drm_aspect_ratio_enum_list)); 194252217195SDaniel Vetter 194352217195SDaniel Vetter if (dev->mode_config.aspect_ratio_property == NULL) 194452217195SDaniel Vetter return -ENOMEM; 194552217195SDaniel Vetter 194652217195SDaniel Vetter return 0; 194752217195SDaniel Vetter } 194852217195SDaniel Vetter EXPORT_SYMBOL(drm_mode_create_aspect_ratio_property); 194952217195SDaniel Vetter 195052217195SDaniel Vetter /** 1951d2c6a405SUma Shankar * DOC: standard connector properties 1952d2c6a405SUma Shankar * 1953d2c6a405SUma Shankar * Colorspace: 1954d2c6a405SUma Shankar * This property helps select a suitable colorspace based on the sink 1955d2c6a405SUma Shankar * capability. Modern sink devices support wider gamut like BT2020. 1956d2c6a405SUma Shankar * This helps switch to BT2020 mode if the BT2020 encoded video stream 1957d2c6a405SUma Shankar * is being played by the user, same for any other colorspace. Thereby 1958d2c6a405SUma Shankar * giving a good visual experience to users. 1959d2c6a405SUma Shankar * 1960d2c6a405SUma Shankar * The expectation from userspace is that it should parse the EDID 1961d2c6a405SUma Shankar * and get supported colorspaces. Use this property and switch to the 1962d2c6a405SUma Shankar * one supported. Sink supported colorspaces should be retrieved by 1963d2c6a405SUma Shankar * userspace from EDID and driver will not explicitly expose them. 1964d2c6a405SUma Shankar * 1965d2c6a405SUma Shankar * Basically the expectation from userspace is: 1966d2c6a405SUma Shankar * - Set up CRTC DEGAMMA/CTM/GAMMA to convert to some sink 1967d2c6a405SUma Shankar * colorspace 1968d2c6a405SUma Shankar * - Set this new property to let the sink know what it 1969d2c6a405SUma Shankar * converted the CRTC output to. 1970d2c6a405SUma Shankar * - This property is just to inform sink what colorspace 1971d2c6a405SUma Shankar * source is trying to drive. 1972d2c6a405SUma Shankar * 19738806cd3aSGwan-gyeong Mun * Because between HDMI and DP have different colorspaces, 197445cf0e91SGwan-gyeong Mun * drm_mode_create_hdmi_colorspace_property() is used for HDMI connector and 197545cf0e91SGwan-gyeong Mun * drm_mode_create_dp_colorspace_property() is used for DP connector. 1976d2c6a405SUma Shankar */ 19778806cd3aSGwan-gyeong Mun 19788806cd3aSGwan-gyeong Mun /** 19798806cd3aSGwan-gyeong Mun * drm_mode_create_hdmi_colorspace_property - create hdmi colorspace property 19808806cd3aSGwan-gyeong Mun * @connector: connector to create the Colorspace property on. 19818806cd3aSGwan-gyeong Mun * 19828806cd3aSGwan-gyeong Mun * Called by a driver the first time it's needed, must be attached to desired 19838806cd3aSGwan-gyeong Mun * HDMI connectors. 19848806cd3aSGwan-gyeong Mun * 19858806cd3aSGwan-gyeong Mun * Returns: 198684e543bcSAntonio Borneo * Zero on success, negative errno on failure. 19878806cd3aSGwan-gyeong Mun */ 19888806cd3aSGwan-gyeong Mun int drm_mode_create_hdmi_colorspace_property(struct drm_connector *connector) 1989d2c6a405SUma Shankar { 1990d2c6a405SUma Shankar struct drm_device *dev = connector->dev; 1991d2c6a405SUma Shankar 19928806cd3aSGwan-gyeong Mun if (connector->colorspace_property) 19938806cd3aSGwan-gyeong Mun return 0; 19948806cd3aSGwan-gyeong Mun 19958806cd3aSGwan-gyeong Mun connector->colorspace_property = 19968806cd3aSGwan-gyeong Mun drm_property_create_enum(dev, DRM_MODE_PROP_ENUM, "Colorspace", 1997d2c6a405SUma Shankar hdmi_colorspaces, 1998d2c6a405SUma Shankar ARRAY_SIZE(hdmi_colorspaces)); 19998806cd3aSGwan-gyeong Mun 20008806cd3aSGwan-gyeong Mun if (!connector->colorspace_property) 2001d2c6a405SUma Shankar return -ENOMEM; 2002d2c6a405SUma Shankar 2003d2c6a405SUma Shankar return 0; 2004d2c6a405SUma Shankar } 20058806cd3aSGwan-gyeong Mun EXPORT_SYMBOL(drm_mode_create_hdmi_colorspace_property); 2006d2c6a405SUma Shankar 2007d2c6a405SUma Shankar /** 200845cf0e91SGwan-gyeong Mun * drm_mode_create_dp_colorspace_property - create dp colorspace property 200945cf0e91SGwan-gyeong Mun * @connector: connector to create the Colorspace property on. 201045cf0e91SGwan-gyeong Mun * 201145cf0e91SGwan-gyeong Mun * Called by a driver the first time it's needed, must be attached to desired 201245cf0e91SGwan-gyeong Mun * DP connectors. 201345cf0e91SGwan-gyeong Mun * 201445cf0e91SGwan-gyeong Mun * Returns: 201584e543bcSAntonio Borneo * Zero on success, negative errno on failure. 201645cf0e91SGwan-gyeong Mun */ 201745cf0e91SGwan-gyeong Mun int drm_mode_create_dp_colorspace_property(struct drm_connector *connector) 201845cf0e91SGwan-gyeong Mun { 201945cf0e91SGwan-gyeong Mun struct drm_device *dev = connector->dev; 202045cf0e91SGwan-gyeong Mun 202145cf0e91SGwan-gyeong Mun if (connector->colorspace_property) 202245cf0e91SGwan-gyeong Mun return 0; 202345cf0e91SGwan-gyeong Mun 202445cf0e91SGwan-gyeong Mun connector->colorspace_property = 202545cf0e91SGwan-gyeong Mun drm_property_create_enum(dev, DRM_MODE_PROP_ENUM, "Colorspace", 202645cf0e91SGwan-gyeong Mun dp_colorspaces, 202745cf0e91SGwan-gyeong Mun ARRAY_SIZE(dp_colorspaces)); 202845cf0e91SGwan-gyeong Mun 202945cf0e91SGwan-gyeong Mun if (!connector->colorspace_property) 203045cf0e91SGwan-gyeong Mun return -ENOMEM; 203145cf0e91SGwan-gyeong Mun 203245cf0e91SGwan-gyeong Mun return 0; 203345cf0e91SGwan-gyeong Mun } 203445cf0e91SGwan-gyeong Mun EXPORT_SYMBOL(drm_mode_create_dp_colorspace_property); 203552217195SDaniel Vetter 203697e14fbeSDaniel Vetter /** 203752217195SDaniel Vetter * drm_mode_create_content_type_property - create content type property 203852217195SDaniel Vetter * @dev: DRM device 203997e14fbeSDaniel Vetter * 204052217195SDaniel Vetter * Called by a driver the first time it's needed, must be attached to desired 204152217195SDaniel Vetter * connectors. 204252217195SDaniel Vetter * 204352217195SDaniel Vetter * Returns: 204452217195SDaniel Vetter * Zero on success, negative errno on failure. 204552217195SDaniel Vetter */ 204652217195SDaniel Vetter int drm_mode_create_content_type_property(struct drm_device *dev) 204752217195SDaniel Vetter { 204852217195SDaniel Vetter if (dev->mode_config.content_type_property) 204997e14fbeSDaniel Vetter return 0; 205052217195SDaniel Vetter 205152217195SDaniel Vetter dev->mode_config.content_type_property = 205252217195SDaniel Vetter drm_property_create_enum(dev, 0, "content type", 205352217195SDaniel Vetter drm_content_type_enum_list, 205452217195SDaniel Vetter ARRAY_SIZE(drm_content_type_enum_list)); 205552217195SDaniel Vetter 205652217195SDaniel Vetter if (dev->mode_config.content_type_property == NULL) 205752217195SDaniel Vetter return -ENOMEM; 205852217195SDaniel Vetter 205952217195SDaniel Vetter return 0; 206052217195SDaniel Vetter } 206152217195SDaniel Vetter EXPORT_SYMBOL(drm_mode_create_content_type_property); 206252217195SDaniel Vetter 206352217195SDaniel Vetter /** 206452217195SDaniel Vetter * drm_mode_create_suggested_offset_properties - create suggests offset properties 206552217195SDaniel Vetter * @dev: DRM device 206652217195SDaniel Vetter * 206784e543bcSAntonio Borneo * Create the suggested x/y offset property for connectors. 2068f85d9e59SRandy Dunlap * 2069f85d9e59SRandy Dunlap * Returns: 2070f85d9e59SRandy Dunlap * 0 on success or a negative error code on failure. 207152217195SDaniel Vetter */ 207252217195SDaniel Vetter int drm_mode_create_suggested_offset_properties(struct drm_device *dev) 207352217195SDaniel Vetter { 207452217195SDaniel Vetter if (dev->mode_config.suggested_x_property && dev->mode_config.suggested_y_property) 207552217195SDaniel Vetter return 0; 207652217195SDaniel Vetter 207752217195SDaniel Vetter dev->mode_config.suggested_x_property = 207852217195SDaniel Vetter drm_property_create_range(dev, DRM_MODE_PROP_IMMUTABLE, "suggested X", 0, 0xffffffff); 207952217195SDaniel Vetter 208052217195SDaniel Vetter dev->mode_config.suggested_y_property = 208152217195SDaniel Vetter drm_property_create_range(dev, DRM_MODE_PROP_IMMUTABLE, "suggested Y", 0, 0xffffffff); 208252217195SDaniel Vetter 208352217195SDaniel Vetter if (dev->mode_config.suggested_x_property == NULL || 208452217195SDaniel Vetter dev->mode_config.suggested_y_property == NULL) 208552217195SDaniel Vetter return -ENOMEM; 208652217195SDaniel Vetter return 0; 208752217195SDaniel Vetter } 208852217195SDaniel Vetter EXPORT_SYMBOL(drm_mode_create_suggested_offset_properties); 208952217195SDaniel Vetter 209052217195SDaniel Vetter /** 209152217195SDaniel Vetter * drm_connector_set_path_property - set tile property on connector 209252217195SDaniel Vetter * @connector: connector to set property on. 209352217195SDaniel Vetter * @path: path to use for property; must not be NULL. 209452217195SDaniel Vetter * 209552217195SDaniel Vetter * This creates a property to expose to userspace to specify a 209652217195SDaniel Vetter * connector path. This is mainly used for DisplayPort MST where 209752217195SDaniel Vetter * connectors have a topology and we want to allow userspace to give 209852217195SDaniel Vetter * them more meaningful names. 209952217195SDaniel Vetter * 210052217195SDaniel Vetter * Returns: 210152217195SDaniel Vetter * Zero on success, negative errno on failure. 210252217195SDaniel Vetter */ 210352217195SDaniel Vetter int drm_connector_set_path_property(struct drm_connector *connector, 210452217195SDaniel Vetter const char *path) 210552217195SDaniel Vetter { 210652217195SDaniel Vetter struct drm_device *dev = connector->dev; 210752217195SDaniel Vetter int ret; 210852217195SDaniel Vetter 210952217195SDaniel Vetter ret = drm_property_replace_global_blob(dev, 211052217195SDaniel Vetter &connector->path_blob_ptr, 211152217195SDaniel Vetter strlen(path) + 1, 211252217195SDaniel Vetter path, 211352217195SDaniel Vetter &connector->base, 211452217195SDaniel Vetter dev->mode_config.path_property); 211552217195SDaniel Vetter return ret; 211652217195SDaniel Vetter } 211752217195SDaniel Vetter EXPORT_SYMBOL(drm_connector_set_path_property); 211852217195SDaniel Vetter 211952217195SDaniel Vetter /** 212052217195SDaniel Vetter * drm_connector_set_tile_property - set tile property on connector 212152217195SDaniel Vetter * @connector: connector to set property on. 212252217195SDaniel Vetter * 212352217195SDaniel Vetter * This looks up the tile information for a connector, and creates a 212452217195SDaniel Vetter * property for userspace to parse if it exists. The property is of 212552217195SDaniel Vetter * the form of 8 integers using ':' as a separator. 21262de3a078SManasi Navare * This is used for dual port tiled displays with DisplayPort SST 21272de3a078SManasi Navare * or DisplayPort MST connectors. 212852217195SDaniel Vetter * 212952217195SDaniel Vetter * Returns: 213052217195SDaniel Vetter * Zero on success, errno on failure. 213152217195SDaniel Vetter */ 213252217195SDaniel Vetter int drm_connector_set_tile_property(struct drm_connector *connector) 213352217195SDaniel Vetter { 213452217195SDaniel Vetter struct drm_device *dev = connector->dev; 213552217195SDaniel Vetter char tile[256]; 213652217195SDaniel Vetter int ret; 213752217195SDaniel Vetter 213852217195SDaniel Vetter if (!connector->has_tile) { 213952217195SDaniel Vetter ret = drm_property_replace_global_blob(dev, 214052217195SDaniel Vetter &connector->tile_blob_ptr, 214152217195SDaniel Vetter 0, 214252217195SDaniel Vetter NULL, 214352217195SDaniel Vetter &connector->base, 214452217195SDaniel Vetter dev->mode_config.tile_property); 214552217195SDaniel Vetter return ret; 214652217195SDaniel Vetter } 214752217195SDaniel Vetter 214852217195SDaniel Vetter snprintf(tile, 256, "%d:%d:%d:%d:%d:%d:%d:%d", 214952217195SDaniel Vetter connector->tile_group->id, connector->tile_is_single_monitor, 215052217195SDaniel Vetter connector->num_h_tile, connector->num_v_tile, 215152217195SDaniel Vetter connector->tile_h_loc, connector->tile_v_loc, 215252217195SDaniel Vetter connector->tile_h_size, connector->tile_v_size); 215352217195SDaniel Vetter 215452217195SDaniel Vetter ret = drm_property_replace_global_blob(dev, 215552217195SDaniel Vetter &connector->tile_blob_ptr, 215652217195SDaniel Vetter strlen(tile) + 1, 215752217195SDaniel Vetter tile, 215852217195SDaniel Vetter &connector->base, 215952217195SDaniel Vetter dev->mode_config.tile_property); 216052217195SDaniel Vetter return ret; 216152217195SDaniel Vetter } 216297e14fbeSDaniel Vetter EXPORT_SYMBOL(drm_connector_set_tile_property); 216352217195SDaniel Vetter 216452217195SDaniel Vetter /** 216597e14fbeSDaniel Vetter * drm_connector_set_link_status_property - Set link status property of a connector 216640ee6fbeSManasi Navare * @connector: drm connector 216740ee6fbeSManasi Navare * @link_status: new value of link status property (0: Good, 1: Bad) 216840ee6fbeSManasi Navare * 216940ee6fbeSManasi Navare * In usual working scenario, this link status property will always be set to 217040ee6fbeSManasi Navare * "GOOD". If something fails during or after a mode set, the kernel driver 217140ee6fbeSManasi Navare * may set this link status property to "BAD". The caller then needs to send a 217240ee6fbeSManasi Navare * hotplug uevent for userspace to re-check the valid modes through 217340ee6fbeSManasi Navare * GET_CONNECTOR_IOCTL and retry modeset. 217440ee6fbeSManasi Navare * 217540ee6fbeSManasi Navare * Note: Drivers cannot rely on userspace to support this property and 217640ee6fbeSManasi Navare * issue a modeset. As such, they may choose to handle issues (like 217740ee6fbeSManasi Navare * re-training a link) without userspace's intervention. 217840ee6fbeSManasi Navare * 217940ee6fbeSManasi Navare * The reason for adding this property is to handle link training failures, but 218040ee6fbeSManasi Navare * it is not limited to DP or link training. For example, if we implement 218140ee6fbeSManasi Navare * asynchronous setcrtc, this property can be used to report any failures in that. 218240ee6fbeSManasi Navare */ 218397e14fbeSDaniel Vetter void drm_connector_set_link_status_property(struct drm_connector *connector, 218440ee6fbeSManasi Navare uint64_t link_status) 218540ee6fbeSManasi Navare { 218640ee6fbeSManasi Navare struct drm_device *dev = connector->dev; 218740ee6fbeSManasi Navare 218840ee6fbeSManasi Navare drm_modeset_lock(&dev->mode_config.connection_mutex, NULL); 218940ee6fbeSManasi Navare connector->state->link_status = link_status; 219040ee6fbeSManasi Navare drm_modeset_unlock(&dev->mode_config.connection_mutex); 219140ee6fbeSManasi Navare } 219297e14fbeSDaniel Vetter EXPORT_SYMBOL(drm_connector_set_link_status_property); 219340ee6fbeSManasi Navare 21948d70f395SHans de Goede /** 219547e22ff1SRadhakrishna Sripada * drm_connector_attach_max_bpc_property - attach "max bpc" property 219647e22ff1SRadhakrishna Sripada * @connector: connector to attach max bpc property on. 219747e22ff1SRadhakrishna Sripada * @min: The minimum bit depth supported by the connector. 219847e22ff1SRadhakrishna Sripada * @max: The maximum bit depth supported by the connector. 219947e22ff1SRadhakrishna Sripada * 220047e22ff1SRadhakrishna Sripada * This is used to add support for limiting the bit depth on a connector. 220147e22ff1SRadhakrishna Sripada * 220247e22ff1SRadhakrishna Sripada * Returns: 220347e22ff1SRadhakrishna Sripada * Zero on success, negative errno on failure. 220447e22ff1SRadhakrishna Sripada */ 220547e22ff1SRadhakrishna Sripada int drm_connector_attach_max_bpc_property(struct drm_connector *connector, 220647e22ff1SRadhakrishna Sripada int min, int max) 220747e22ff1SRadhakrishna Sripada { 220847e22ff1SRadhakrishna Sripada struct drm_device *dev = connector->dev; 220947e22ff1SRadhakrishna Sripada struct drm_property *prop; 221047e22ff1SRadhakrishna Sripada 221147e22ff1SRadhakrishna Sripada prop = connector->max_bpc_property; 221247e22ff1SRadhakrishna Sripada if (!prop) { 221347e22ff1SRadhakrishna Sripada prop = drm_property_create_range(dev, 0, "max bpc", min, max); 221447e22ff1SRadhakrishna Sripada if (!prop) 221547e22ff1SRadhakrishna Sripada return -ENOMEM; 221647e22ff1SRadhakrishna Sripada 221747e22ff1SRadhakrishna Sripada connector->max_bpc_property = prop; 221847e22ff1SRadhakrishna Sripada } 221947e22ff1SRadhakrishna Sripada 222047e22ff1SRadhakrishna Sripada drm_object_attach_property(&connector->base, prop, max); 222147e22ff1SRadhakrishna Sripada connector->state->max_requested_bpc = max; 222247e22ff1SRadhakrishna Sripada connector->state->max_bpc = max; 222347e22ff1SRadhakrishna Sripada 222447e22ff1SRadhakrishna Sripada return 0; 222547e22ff1SRadhakrishna Sripada } 222647e22ff1SRadhakrishna Sripada EXPORT_SYMBOL(drm_connector_attach_max_bpc_property); 222747e22ff1SRadhakrishna Sripada 222847e22ff1SRadhakrishna Sripada /** 2229e057b52cSMaxime Ripard * drm_connector_attach_hdr_output_metadata_property - attach "HDR_OUTPUT_METADA" property 2230e057b52cSMaxime Ripard * @connector: connector to attach the property on. 2231e057b52cSMaxime Ripard * 2232e057b52cSMaxime Ripard * This is used to allow the userspace to send HDR Metadata to the 2233e057b52cSMaxime Ripard * driver. 2234e057b52cSMaxime Ripard * 2235e057b52cSMaxime Ripard * Returns: 2236e057b52cSMaxime Ripard * Zero on success, negative errno on failure. 2237e057b52cSMaxime Ripard */ 2238e057b52cSMaxime Ripard int drm_connector_attach_hdr_output_metadata_property(struct drm_connector *connector) 2239e057b52cSMaxime Ripard { 2240e057b52cSMaxime Ripard struct drm_device *dev = connector->dev; 2241e057b52cSMaxime Ripard struct drm_property *prop = dev->mode_config.hdr_output_metadata_property; 2242e057b52cSMaxime Ripard 2243e057b52cSMaxime Ripard drm_object_attach_property(&connector->base, prop, 0); 2244e057b52cSMaxime Ripard 2245e057b52cSMaxime Ripard return 0; 2246e057b52cSMaxime Ripard } 2247e057b52cSMaxime Ripard EXPORT_SYMBOL(drm_connector_attach_hdr_output_metadata_property); 2248e057b52cSMaxime Ripard 2249e057b52cSMaxime Ripard /** 225021f79128SMaxime Ripard * drm_connector_attach_colorspace_property - attach "Colorspace" property 225121f79128SMaxime Ripard * @connector: connector to attach the property on. 225221f79128SMaxime Ripard * 225321f79128SMaxime Ripard * This is used to allow the userspace to signal the output colorspace 225421f79128SMaxime Ripard * to the driver. 225521f79128SMaxime Ripard * 225621f79128SMaxime Ripard * Returns: 225721f79128SMaxime Ripard * Zero on success, negative errno on failure. 225821f79128SMaxime Ripard */ 225921f79128SMaxime Ripard int drm_connector_attach_colorspace_property(struct drm_connector *connector) 226021f79128SMaxime Ripard { 226121f79128SMaxime Ripard struct drm_property *prop = connector->colorspace_property; 226221f79128SMaxime Ripard 226321f79128SMaxime Ripard drm_object_attach_property(&connector->base, prop, DRM_MODE_COLORIMETRY_DEFAULT); 226421f79128SMaxime Ripard 226521f79128SMaxime Ripard return 0; 226621f79128SMaxime Ripard } 226721f79128SMaxime Ripard EXPORT_SYMBOL(drm_connector_attach_colorspace_property); 226821f79128SMaxime Ripard 226921f79128SMaxime Ripard /** 227072921cdfSMaxime Ripard * drm_connector_atomic_hdr_metadata_equal - checks if the hdr metadata changed 227172921cdfSMaxime Ripard * @old_state: old connector state to compare 227272921cdfSMaxime Ripard * @new_state: new connector state to compare 227372921cdfSMaxime Ripard * 227472921cdfSMaxime Ripard * This is used by HDR-enabled drivers to test whether the HDR metadata 227572921cdfSMaxime Ripard * have changed between two different connector state (and thus probably 227672921cdfSMaxime Ripard * requires a full blown mode change). 227772921cdfSMaxime Ripard * 227872921cdfSMaxime Ripard * Returns: 227972921cdfSMaxime Ripard * True if the metadata are equal, False otherwise 228072921cdfSMaxime Ripard */ 228172921cdfSMaxime Ripard bool drm_connector_atomic_hdr_metadata_equal(struct drm_connector_state *old_state, 228272921cdfSMaxime Ripard struct drm_connector_state *new_state) 228372921cdfSMaxime Ripard { 228472921cdfSMaxime Ripard struct drm_property_blob *old_blob = old_state->hdr_output_metadata; 228572921cdfSMaxime Ripard struct drm_property_blob *new_blob = new_state->hdr_output_metadata; 228672921cdfSMaxime Ripard 228772921cdfSMaxime Ripard if (!old_blob || !new_blob) 228872921cdfSMaxime Ripard return old_blob == new_blob; 228972921cdfSMaxime Ripard 229072921cdfSMaxime Ripard if (old_blob->length != new_blob->length) 229172921cdfSMaxime Ripard return false; 229272921cdfSMaxime Ripard 229372921cdfSMaxime Ripard return !memcmp(old_blob->data, new_blob->data, old_blob->length); 229472921cdfSMaxime Ripard } 229572921cdfSMaxime Ripard EXPORT_SYMBOL(drm_connector_atomic_hdr_metadata_equal); 229672921cdfSMaxime Ripard 229772921cdfSMaxime Ripard /** 2298ba1b0f6cSNicholas Kazlauskas * drm_connector_set_vrr_capable_property - sets the variable refresh rate 2299ba1b0f6cSNicholas Kazlauskas * capable property for a connector 2300ba1b0f6cSNicholas Kazlauskas * @connector: drm connector 2301ba1b0f6cSNicholas Kazlauskas * @capable: True if the connector is variable refresh rate capable 2302ba1b0f6cSNicholas Kazlauskas * 2303ba1b0f6cSNicholas Kazlauskas * Should be used by atomic drivers to update the indicated support for 2304ba1b0f6cSNicholas Kazlauskas * variable refresh rate over a connector. 2305ba1b0f6cSNicholas Kazlauskas */ 2306ba1b0f6cSNicholas Kazlauskas void drm_connector_set_vrr_capable_property( 2307ba1b0f6cSNicholas Kazlauskas struct drm_connector *connector, bool capable) 2308ba1b0f6cSNicholas Kazlauskas { 230962929726SManasi Navare if (!connector->vrr_capable_property) 231062929726SManasi Navare return; 231162929726SManasi Navare 2312ba1b0f6cSNicholas Kazlauskas drm_object_property_set_value(&connector->base, 2313ba1b0f6cSNicholas Kazlauskas connector->vrr_capable_property, 2314ba1b0f6cSNicholas Kazlauskas capable); 2315ba1b0f6cSNicholas Kazlauskas } 2316ba1b0f6cSNicholas Kazlauskas EXPORT_SYMBOL(drm_connector_set_vrr_capable_property); 2317ba1b0f6cSNicholas Kazlauskas 2318ba1b0f6cSNicholas Kazlauskas /** 231984e543bcSAntonio Borneo * drm_connector_set_panel_orientation - sets the connector's panel_orientation 232069654c63SDerek Basehore * @connector: connector for which to set the panel-orientation property. 232169654c63SDerek Basehore * @panel_orientation: drm_panel_orientation value to set 23228d70f395SHans de Goede * 232369654c63SDerek Basehore * This function sets the connector's panel_orientation and attaches 232469654c63SDerek Basehore * a "panel orientation" property to the connector. 23258d70f395SHans de Goede * 232669654c63SDerek Basehore * Calling this function on a connector where the panel_orientation has 232769654c63SDerek Basehore * already been set is a no-op (e.g. the orientation has been overridden with 232869654c63SDerek Basehore * a kernel commandline option). 232969654c63SDerek Basehore * 233069654c63SDerek Basehore * It is allowed to call this function with a panel_orientation of 233169654c63SDerek Basehore * DRM_MODE_PANEL_ORIENTATION_UNKNOWN, in which case it is a no-op. 23328d70f395SHans de Goede * 23335e41b01aSHsin-Yi Wang * The function shouldn't be called in panel after drm is registered (i.e. 23345e41b01aSHsin-Yi Wang * drm_dev_register() is called in drm). 23355e41b01aSHsin-Yi Wang * 23368d70f395SHans de Goede * Returns: 23378d70f395SHans de Goede * Zero on success, negative errno on failure. 23388d70f395SHans de Goede */ 233969654c63SDerek Basehore int drm_connector_set_panel_orientation( 234069654c63SDerek Basehore struct drm_connector *connector, 234169654c63SDerek Basehore enum drm_panel_orientation panel_orientation) 23428d70f395SHans de Goede { 23438d70f395SHans de Goede struct drm_device *dev = connector->dev; 23448d70f395SHans de Goede struct drm_display_info *info = &connector->display_info; 23458d70f395SHans de Goede struct drm_property *prop; 23468d70f395SHans de Goede 234769654c63SDerek Basehore /* Already set? */ 234869654c63SDerek Basehore if (info->panel_orientation != DRM_MODE_PANEL_ORIENTATION_UNKNOWN) 23498d70f395SHans de Goede return 0; 23508d70f395SHans de Goede 235169654c63SDerek Basehore /* Don't attach the property if the orientation is unknown */ 235269654c63SDerek Basehore if (panel_orientation == DRM_MODE_PANEL_ORIENTATION_UNKNOWN) 235369654c63SDerek Basehore return 0; 235469654c63SDerek Basehore 235569654c63SDerek Basehore info->panel_orientation = panel_orientation; 235669654c63SDerek Basehore 23578d70f395SHans de Goede prop = dev->mode_config.panel_orientation_property; 23588d70f395SHans de Goede if (!prop) { 23598d70f395SHans de Goede prop = drm_property_create_enum(dev, DRM_MODE_PROP_IMMUTABLE, 23608d70f395SHans de Goede "panel orientation", 23618d70f395SHans de Goede drm_panel_orientation_enum_list, 23628d70f395SHans de Goede ARRAY_SIZE(drm_panel_orientation_enum_list)); 23638d70f395SHans de Goede if (!prop) 23648d70f395SHans de Goede return -ENOMEM; 23658d70f395SHans de Goede 23668d70f395SHans de Goede dev->mode_config.panel_orientation_property = prop; 23678d70f395SHans de Goede } 23688d70f395SHans de Goede 23698d70f395SHans de Goede drm_object_attach_property(&connector->base, prop, 23708d70f395SHans de Goede info->panel_orientation); 23718d70f395SHans de Goede return 0; 23728d70f395SHans de Goede } 237369654c63SDerek Basehore EXPORT_SYMBOL(drm_connector_set_panel_orientation); 237469654c63SDerek Basehore 237569654c63SDerek Basehore /** 2376f85d9e59SRandy Dunlap * drm_connector_set_panel_orientation_with_quirk - set the 2377f85d9e59SRandy Dunlap * connector's panel_orientation after checking for quirks 237869654c63SDerek Basehore * @connector: connector for which to init the panel-orientation property. 237969654c63SDerek Basehore * @panel_orientation: drm_panel_orientation value to set 238069654c63SDerek Basehore * @width: width in pixels of the panel, used for panel quirk detection 238169654c63SDerek Basehore * @height: height in pixels of the panel, used for panel quirk detection 238269654c63SDerek Basehore * 238369654c63SDerek Basehore * Like drm_connector_set_panel_orientation(), but with a check for platform 238469654c63SDerek Basehore * specific (e.g. DMI based) quirks overriding the passed in panel_orientation. 238569654c63SDerek Basehore * 238669654c63SDerek Basehore * Returns: 238769654c63SDerek Basehore * Zero on success, negative errno on failure. 238869654c63SDerek Basehore */ 238969654c63SDerek Basehore int drm_connector_set_panel_orientation_with_quirk( 239069654c63SDerek Basehore struct drm_connector *connector, 239169654c63SDerek Basehore enum drm_panel_orientation panel_orientation, 239269654c63SDerek Basehore int width, int height) 239369654c63SDerek Basehore { 239469654c63SDerek Basehore int orientation_quirk; 239569654c63SDerek Basehore 239669654c63SDerek Basehore orientation_quirk = drm_get_panel_orientation_quirk(width, height); 239769654c63SDerek Basehore if (orientation_quirk != DRM_MODE_PANEL_ORIENTATION_UNKNOWN) 239869654c63SDerek Basehore panel_orientation = orientation_quirk; 239969654c63SDerek Basehore 240069654c63SDerek Basehore return drm_connector_set_panel_orientation(connector, 240169654c63SDerek Basehore panel_orientation); 240269654c63SDerek Basehore } 240369654c63SDerek Basehore EXPORT_SYMBOL(drm_connector_set_panel_orientation_with_quirk); 24048d70f395SHans de Goede 24055e41b01aSHsin-Yi Wang /** 24065e41b01aSHsin-Yi Wang * drm_connector_set_orientation_from_panel - 24075e41b01aSHsin-Yi Wang * set the connector's panel_orientation from panel's callback. 24085e41b01aSHsin-Yi Wang * @connector: connector for which to init the panel-orientation property. 24095e41b01aSHsin-Yi Wang * @panel: panel that can provide orientation information. 24105e41b01aSHsin-Yi Wang * 24115e41b01aSHsin-Yi Wang * Drm drivers should call this function before drm_dev_register(). 24125e41b01aSHsin-Yi Wang * Orientation is obtained from panel's .get_orientation() callback. 24135e41b01aSHsin-Yi Wang * 24145e41b01aSHsin-Yi Wang * Returns: 24155e41b01aSHsin-Yi Wang * Zero on success, negative errno on failure. 24165e41b01aSHsin-Yi Wang */ 24175e41b01aSHsin-Yi Wang int drm_connector_set_orientation_from_panel( 24185e41b01aSHsin-Yi Wang struct drm_connector *connector, 24195e41b01aSHsin-Yi Wang struct drm_panel *panel) 24205e41b01aSHsin-Yi Wang { 24215e41b01aSHsin-Yi Wang enum drm_panel_orientation orientation; 24225e41b01aSHsin-Yi Wang 24235e41b01aSHsin-Yi Wang if (panel && panel->funcs && panel->funcs->get_orientation) 24245e41b01aSHsin-Yi Wang orientation = panel->funcs->get_orientation(panel); 24255e41b01aSHsin-Yi Wang else 24265e41b01aSHsin-Yi Wang orientation = DRM_MODE_PANEL_ORIENTATION_UNKNOWN; 24275e41b01aSHsin-Yi Wang 24285e41b01aSHsin-Yi Wang return drm_connector_set_panel_orientation(connector, orientation); 24295e41b01aSHsin-Yi Wang } 24305e41b01aSHsin-Yi Wang EXPORT_SYMBOL(drm_connector_set_orientation_from_panel); 24315e41b01aSHsin-Yi Wang 2432107fe904SRajat Jain static const struct drm_prop_enum_list privacy_screen_enum[] = { 2433107fe904SRajat Jain { PRIVACY_SCREEN_DISABLED, "Disabled" }, 2434107fe904SRajat Jain { PRIVACY_SCREEN_ENABLED, "Enabled" }, 2435107fe904SRajat Jain { PRIVACY_SCREEN_DISABLED_LOCKED, "Disabled-locked" }, 2436107fe904SRajat Jain { PRIVACY_SCREEN_ENABLED_LOCKED, "Enabled-locked" }, 2437107fe904SRajat Jain }; 2438107fe904SRajat Jain 2439107fe904SRajat Jain /** 2440107fe904SRajat Jain * drm_connector_create_privacy_screen_properties - create the drm connecter's 2441107fe904SRajat Jain * privacy-screen properties. 2442107fe904SRajat Jain * @connector: connector for which to create the privacy-screen properties 2443107fe904SRajat Jain * 2444107fe904SRajat Jain * This function creates the "privacy-screen sw-state" and "privacy-screen 2445107fe904SRajat Jain * hw-state" properties for the connector. They are not attached. 2446107fe904SRajat Jain */ 2447107fe904SRajat Jain void 2448107fe904SRajat Jain drm_connector_create_privacy_screen_properties(struct drm_connector *connector) 2449107fe904SRajat Jain { 2450107fe904SRajat Jain if (connector->privacy_screen_sw_state_property) 2451107fe904SRajat Jain return; 2452107fe904SRajat Jain 2453107fe904SRajat Jain /* Note sw-state only supports the first 2 values of the enum */ 2454107fe904SRajat Jain connector->privacy_screen_sw_state_property = 2455107fe904SRajat Jain drm_property_create_enum(connector->dev, DRM_MODE_PROP_ENUM, 2456107fe904SRajat Jain "privacy-screen sw-state", 2457107fe904SRajat Jain privacy_screen_enum, 2); 2458107fe904SRajat Jain 2459107fe904SRajat Jain connector->privacy_screen_hw_state_property = 2460107fe904SRajat Jain drm_property_create_enum(connector->dev, 2461107fe904SRajat Jain DRM_MODE_PROP_IMMUTABLE | DRM_MODE_PROP_ENUM, 2462107fe904SRajat Jain "privacy-screen hw-state", 2463107fe904SRajat Jain privacy_screen_enum, 2464107fe904SRajat Jain ARRAY_SIZE(privacy_screen_enum)); 2465107fe904SRajat Jain } 2466107fe904SRajat Jain EXPORT_SYMBOL(drm_connector_create_privacy_screen_properties); 2467107fe904SRajat Jain 2468107fe904SRajat Jain /** 2469107fe904SRajat Jain * drm_connector_attach_privacy_screen_properties - attach the drm connecter's 2470107fe904SRajat Jain * privacy-screen properties. 2471107fe904SRajat Jain * @connector: connector on which to attach the privacy-screen properties 2472107fe904SRajat Jain * 2473107fe904SRajat Jain * This function attaches the "privacy-screen sw-state" and "privacy-screen 2474107fe904SRajat Jain * hw-state" properties to the connector. The initial state of both is set 2475107fe904SRajat Jain * to "Disabled". 2476107fe904SRajat Jain */ 2477107fe904SRajat Jain void 2478107fe904SRajat Jain drm_connector_attach_privacy_screen_properties(struct drm_connector *connector) 2479107fe904SRajat Jain { 2480107fe904SRajat Jain if (!connector->privacy_screen_sw_state_property) 2481107fe904SRajat Jain return; 2482107fe904SRajat Jain 2483107fe904SRajat Jain drm_object_attach_property(&connector->base, 2484107fe904SRajat Jain connector->privacy_screen_sw_state_property, 2485107fe904SRajat Jain PRIVACY_SCREEN_DISABLED); 2486107fe904SRajat Jain 2487107fe904SRajat Jain drm_object_attach_property(&connector->base, 2488107fe904SRajat Jain connector->privacy_screen_hw_state_property, 2489107fe904SRajat Jain PRIVACY_SCREEN_DISABLED); 2490107fe904SRajat Jain } 2491107fe904SRajat Jain EXPORT_SYMBOL(drm_connector_attach_privacy_screen_properties); 2492107fe904SRajat Jain 2493334f74eeSHans de Goede static void drm_connector_update_privacy_screen_properties( 2494334f74eeSHans de Goede struct drm_connector *connector, bool set_sw_state) 2495334f74eeSHans de Goede { 2496334f74eeSHans de Goede enum drm_privacy_screen_status sw_state, hw_state; 2497334f74eeSHans de Goede 2498334f74eeSHans de Goede drm_privacy_screen_get_state(connector->privacy_screen, 2499334f74eeSHans de Goede &sw_state, &hw_state); 2500334f74eeSHans de Goede 2501334f74eeSHans de Goede if (set_sw_state) 2502334f74eeSHans de Goede connector->state->privacy_screen_sw_state = sw_state; 2503334f74eeSHans de Goede drm_object_property_set_value(&connector->base, 2504334f74eeSHans de Goede connector->privacy_screen_hw_state_property, hw_state); 2505334f74eeSHans de Goede } 2506334f74eeSHans de Goede 2507334f74eeSHans de Goede static int drm_connector_privacy_screen_notifier( 2508334f74eeSHans de Goede struct notifier_block *nb, unsigned long action, void *data) 2509334f74eeSHans de Goede { 2510334f74eeSHans de Goede struct drm_connector *connector = 2511334f74eeSHans de Goede container_of(nb, struct drm_connector, privacy_screen_notifier); 2512334f74eeSHans de Goede struct drm_device *dev = connector->dev; 2513334f74eeSHans de Goede 2514334f74eeSHans de Goede drm_modeset_lock(&dev->mode_config.connection_mutex, NULL); 2515334f74eeSHans de Goede drm_connector_update_privacy_screen_properties(connector, true); 2516334f74eeSHans de Goede drm_modeset_unlock(&dev->mode_config.connection_mutex); 2517334f74eeSHans de Goede 2518334f74eeSHans de Goede drm_sysfs_connector_status_event(connector, 2519334f74eeSHans de Goede connector->privacy_screen_sw_state_property); 2520334f74eeSHans de Goede drm_sysfs_connector_status_event(connector, 2521334f74eeSHans de Goede connector->privacy_screen_hw_state_property); 2522334f74eeSHans de Goede 2523334f74eeSHans de Goede return NOTIFY_DONE; 2524334f74eeSHans de Goede } 2525334f74eeSHans de Goede 2526334f74eeSHans de Goede /** 2527334f74eeSHans de Goede * drm_connector_attach_privacy_screen_provider - attach a privacy-screen to 2528334f74eeSHans de Goede * the connector 2529334f74eeSHans de Goede * @connector: connector to attach the privacy-screen to 2530334f74eeSHans de Goede * @priv: drm_privacy_screen to attach 2531334f74eeSHans de Goede * 2532334f74eeSHans de Goede * Create and attach the standard privacy-screen properties and register 2533334f74eeSHans de Goede * a generic notifier for generating sysfs-connector-status-events 2534334f74eeSHans de Goede * on external changes to the privacy-screen status. 2535334f74eeSHans de Goede * This function takes ownership of the passed in drm_privacy_screen and will 2536334f74eeSHans de Goede * call drm_privacy_screen_put() on it when the connector is destroyed. 2537334f74eeSHans de Goede */ 2538334f74eeSHans de Goede void drm_connector_attach_privacy_screen_provider( 2539334f74eeSHans de Goede struct drm_connector *connector, struct drm_privacy_screen *priv) 2540334f74eeSHans de Goede { 2541334f74eeSHans de Goede connector->privacy_screen = priv; 2542334f74eeSHans de Goede connector->privacy_screen_notifier.notifier_call = 2543334f74eeSHans de Goede drm_connector_privacy_screen_notifier; 2544334f74eeSHans de Goede 2545334f74eeSHans de Goede drm_connector_create_privacy_screen_properties(connector); 2546334f74eeSHans de Goede drm_connector_update_privacy_screen_properties(connector, true); 2547334f74eeSHans de Goede drm_connector_attach_privacy_screen_properties(connector); 2548334f74eeSHans de Goede } 2549334f74eeSHans de Goede EXPORT_SYMBOL(drm_connector_attach_privacy_screen_provider); 2550334f74eeSHans de Goede 2551334f74eeSHans de Goede /** 2552334f74eeSHans de Goede * drm_connector_update_privacy_screen - update connector's privacy-screen sw-state 2553334f74eeSHans de Goede * @connector_state: connector-state to update the privacy-screen for 2554334f74eeSHans de Goede * 2555334f74eeSHans de Goede * This function calls drm_privacy_screen_set_sw_state() on the connector's 2556334f74eeSHans de Goede * privacy-screen. 2557334f74eeSHans de Goede * 2558334f74eeSHans de Goede * If the connector has no privacy-screen, then this is a no-op. 2559334f74eeSHans de Goede */ 2560334f74eeSHans de Goede void drm_connector_update_privacy_screen(const struct drm_connector_state *connector_state) 2561334f74eeSHans de Goede { 2562334f74eeSHans de Goede struct drm_connector *connector = connector_state->connector; 2563334f74eeSHans de Goede int ret; 2564334f74eeSHans de Goede 2565334f74eeSHans de Goede if (!connector->privacy_screen) 2566334f74eeSHans de Goede return; 2567334f74eeSHans de Goede 2568334f74eeSHans de Goede ret = drm_privacy_screen_set_sw_state(connector->privacy_screen, 2569334f74eeSHans de Goede connector_state->privacy_screen_sw_state); 2570334f74eeSHans de Goede if (ret) { 2571334f74eeSHans de Goede drm_err(connector->dev, "Error updating privacy-screen sw_state\n"); 2572334f74eeSHans de Goede return; 2573334f74eeSHans de Goede } 2574334f74eeSHans de Goede 2575334f74eeSHans de Goede /* The hw_state property value may have changed, update it. */ 2576334f74eeSHans de Goede drm_connector_update_privacy_screen_properties(connector, false); 2577334f74eeSHans de Goede } 2578334f74eeSHans de Goede EXPORT_SYMBOL(drm_connector_update_privacy_screen); 2579334f74eeSHans de Goede 258097e14fbeSDaniel Vetter int drm_connector_set_obj_prop(struct drm_mode_object *obj, 258152217195SDaniel Vetter struct drm_property *property, 258252217195SDaniel Vetter uint64_t value) 258352217195SDaniel Vetter { 258452217195SDaniel Vetter int ret = -EINVAL; 258552217195SDaniel Vetter struct drm_connector *connector = obj_to_connector(obj); 258652217195SDaniel Vetter 258752217195SDaniel Vetter /* Do DPMS ourselves */ 258852217195SDaniel Vetter if (property == connector->dev->mode_config.dpms_property) { 258952217195SDaniel Vetter ret = (*connector->funcs->dpms)(connector, (int)value); 259052217195SDaniel Vetter } else if (connector->funcs->set_property) 259152217195SDaniel Vetter ret = connector->funcs->set_property(connector, property, value); 259252217195SDaniel Vetter 2593144a7999SDaniel Vetter if (!ret) 259452217195SDaniel Vetter drm_object_property_set_value(&connector->base, property, value); 259552217195SDaniel Vetter return ret; 259652217195SDaniel Vetter } 259752217195SDaniel Vetter 259897e14fbeSDaniel Vetter int drm_connector_property_set_ioctl(struct drm_device *dev, 259952217195SDaniel Vetter void *data, struct drm_file *file_priv) 260052217195SDaniel Vetter { 260152217195SDaniel Vetter struct drm_mode_connector_set_property *conn_set_prop = data; 260252217195SDaniel Vetter struct drm_mode_obj_set_property obj_set_prop = { 260352217195SDaniel Vetter .value = conn_set_prop->value, 260452217195SDaniel Vetter .prop_id = conn_set_prop->prop_id, 260552217195SDaniel Vetter .obj_id = conn_set_prop->connector_id, 260652217195SDaniel Vetter .obj_type = DRM_MODE_OBJECT_CONNECTOR 260752217195SDaniel Vetter }; 260852217195SDaniel Vetter 260952217195SDaniel Vetter /* It does all the locking and checking we need */ 261052217195SDaniel Vetter return drm_mode_obj_set_property_ioctl(dev, &obj_set_prop, file_priv); 261152217195SDaniel Vetter } 261252217195SDaniel Vetter 261352217195SDaniel Vetter static struct drm_encoder *drm_connector_get_encoder(struct drm_connector *connector) 261452217195SDaniel Vetter { 261552217195SDaniel Vetter /* For atomic drivers only state objects are synchronously updated and 2616c2ce66daSBeatriz Martins de Carvalho * protected by modeset locks, so check those first. 2617c2ce66daSBeatriz Martins de Carvalho */ 261852217195SDaniel Vetter if (connector->state) 261952217195SDaniel Vetter return connector->state->best_encoder; 262052217195SDaniel Vetter return connector->encoder; 262152217195SDaniel Vetter } 262252217195SDaniel Vetter 2623c3ff0cdbSAnkit Nautiyal static bool 2624c3ff0cdbSAnkit Nautiyal drm_mode_expose_to_userspace(const struct drm_display_mode *mode, 26258445e2c5SVille Syrjälä const struct list_head *modes, 262652217195SDaniel Vetter const struct drm_file *file_priv) 262752217195SDaniel Vetter { 262852217195SDaniel Vetter /* 262952217195SDaniel Vetter * If user-space hasn't configured the driver to expose the stereo 3D 263052217195SDaniel Vetter * modes, don't expose them. 263152217195SDaniel Vetter */ 263252217195SDaniel Vetter if (!file_priv->stereo_allowed && drm_mode_is_stereo(mode)) 263352217195SDaniel Vetter return false; 2634c3ff0cdbSAnkit Nautiyal /* 2635c3ff0cdbSAnkit Nautiyal * If user-space hasn't configured the driver to expose the modes 2636c3ff0cdbSAnkit Nautiyal * with aspect-ratio, don't expose them. However if such a mode 2637c3ff0cdbSAnkit Nautiyal * is unique, let it be exposed, but reset the aspect-ratio flags 2638c3ff0cdbSAnkit Nautiyal * while preparing the list of user-modes. 2639c3ff0cdbSAnkit Nautiyal */ 2640c3ff0cdbSAnkit Nautiyal if (!file_priv->aspect_ratio_allowed) { 26418445e2c5SVille Syrjälä const struct drm_display_mode *mode_itr; 2642c3ff0cdbSAnkit Nautiyal 26438445e2c5SVille Syrjälä list_for_each_entry(mode_itr, modes, head) { 26448445e2c5SVille Syrjälä if (mode_itr->expose_to_userspace && 26458445e2c5SVille Syrjälä drm_mode_match(mode_itr, mode, 2646c3ff0cdbSAnkit Nautiyal DRM_MODE_MATCH_TIMINGS | 2647c3ff0cdbSAnkit Nautiyal DRM_MODE_MATCH_CLOCK | 2648c3ff0cdbSAnkit Nautiyal DRM_MODE_MATCH_FLAGS | 2649c3ff0cdbSAnkit Nautiyal DRM_MODE_MATCH_3D_FLAGS)) 2650c3ff0cdbSAnkit Nautiyal return false; 2651c3ff0cdbSAnkit Nautiyal } 26528445e2c5SVille Syrjälä } 265352217195SDaniel Vetter 265452217195SDaniel Vetter return true; 265552217195SDaniel Vetter } 265652217195SDaniel Vetter 265752217195SDaniel Vetter int drm_mode_getconnector(struct drm_device *dev, void *data, 265852217195SDaniel Vetter struct drm_file *file_priv) 265952217195SDaniel Vetter { 266052217195SDaniel Vetter struct drm_mode_get_connector *out_resp = data; 266152217195SDaniel Vetter struct drm_connector *connector; 266252217195SDaniel Vetter struct drm_encoder *encoder; 266352217195SDaniel Vetter struct drm_display_mode *mode; 266452217195SDaniel Vetter int mode_count = 0; 266552217195SDaniel Vetter int encoders_count = 0; 266652217195SDaniel Vetter int ret = 0; 266752217195SDaniel Vetter int copied = 0; 266852217195SDaniel Vetter struct drm_mode_modeinfo u_mode; 266952217195SDaniel Vetter struct drm_mode_modeinfo __user *mode_ptr; 267052217195SDaniel Vetter uint32_t __user *encoder_ptr; 2671869e76f7SDesmond Cheong Zhi Xi bool is_current_master; 267252217195SDaniel Vetter 267352217195SDaniel Vetter if (!drm_core_check_feature(dev, DRIVER_MODESET)) 267469fdf420SChris Wilson return -EOPNOTSUPP; 267552217195SDaniel Vetter 267652217195SDaniel Vetter memset(&u_mode, 0, sizeof(struct drm_mode_modeinfo)); 267752217195SDaniel Vetter 2678418da172SKeith Packard connector = drm_connector_lookup(dev, file_priv, out_resp->connector_id); 267991eefc05SDaniel Vetter if (!connector) 268091eefc05SDaniel Vetter return -ENOENT; 268152217195SDaniel Vetter 268262afb4adSJosé Roberto de Souza encoders_count = hweight32(connector->possible_encoders); 268391eefc05SDaniel Vetter 268491eefc05SDaniel Vetter if ((out_resp->count_encoders >= encoders_count) && encoders_count) { 268591eefc05SDaniel Vetter copied = 0; 268691eefc05SDaniel Vetter encoder_ptr = (uint32_t __user *)(unsigned long)(out_resp->encoders_ptr); 268783aefbb8SVille Syrjälä 268862afb4adSJosé Roberto de Souza drm_connector_for_each_possible_encoder(connector, encoder) { 268983aefbb8SVille Syrjälä if (put_user(encoder->base.id, encoder_ptr + copied)) { 269091eefc05SDaniel Vetter ret = -EFAULT; 2691e94ac351SDaniel Vetter goto out; 269291eefc05SDaniel Vetter } 269391eefc05SDaniel Vetter copied++; 269491eefc05SDaniel Vetter } 269591eefc05SDaniel Vetter } 269691eefc05SDaniel Vetter out_resp->count_encoders = encoders_count; 269791eefc05SDaniel Vetter 269891eefc05SDaniel Vetter out_resp->connector_id = connector->base.id; 269991eefc05SDaniel Vetter out_resp->connector_type = connector->connector_type; 270091eefc05SDaniel Vetter out_resp->connector_type_id = connector->connector_type_id; 270191eefc05SDaniel Vetter 2702869e76f7SDesmond Cheong Zhi Xi is_current_master = drm_is_current_master(file_priv); 2703869e76f7SDesmond Cheong Zhi Xi 270491eefc05SDaniel Vetter mutex_lock(&dev->mode_config.mutex); 270591eefc05SDaniel Vetter if (out_resp->count_modes == 0) { 2706869e76f7SDesmond Cheong Zhi Xi if (is_current_master) 270791eefc05SDaniel Vetter connector->funcs->fill_modes(connector, 270891eefc05SDaniel Vetter dev->mode_config.max_width, 270991eefc05SDaniel Vetter dev->mode_config.max_height); 27108f86c82aSSimon Ser else 27118f86c82aSSimon Ser drm_dbg_kms(dev, "User-space requested a forced probe on [CONNECTOR:%d:%s] but is not the DRM master, demoting to read-only probe", 27128f86c82aSSimon Ser connector->base.id, connector->name); 271391eefc05SDaniel Vetter } 271491eefc05SDaniel Vetter 271591eefc05SDaniel Vetter out_resp->mm_width = connector->display_info.width_mm; 271691eefc05SDaniel Vetter out_resp->mm_height = connector->display_info.height_mm; 271791eefc05SDaniel Vetter out_resp->subpixel = connector->display_info.subpixel_order; 271891eefc05SDaniel Vetter out_resp->connection = connector->status; 271991eefc05SDaniel Vetter 272091eefc05SDaniel Vetter /* delayed so we get modes regardless of pre-fill_modes state */ 27218445e2c5SVille Syrjälä list_for_each_entry(mode, &connector->modes, head) { 27228445e2c5SVille Syrjälä WARN_ON(mode->expose_to_userspace); 27238445e2c5SVille Syrjälä 27248445e2c5SVille Syrjälä if (drm_mode_expose_to_userspace(mode, &connector->modes, 2725c3ff0cdbSAnkit Nautiyal file_priv)) { 27268445e2c5SVille Syrjälä mode->expose_to_userspace = true; 272791eefc05SDaniel Vetter mode_count++; 2728c3ff0cdbSAnkit Nautiyal } 27298445e2c5SVille Syrjälä } 273091eefc05SDaniel Vetter 273152217195SDaniel Vetter /* 273252217195SDaniel Vetter * This ioctl is called twice, once to determine how much space is 273352217195SDaniel Vetter * needed, and the 2nd time to fill it. 273452217195SDaniel Vetter */ 273552217195SDaniel Vetter if ((out_resp->count_modes >= mode_count) && mode_count) { 273652217195SDaniel Vetter copied = 0; 273752217195SDaniel Vetter mode_ptr = (struct drm_mode_modeinfo __user *)(unsigned long)out_resp->modes_ptr; 27388445e2c5SVille Syrjälä list_for_each_entry(mode, &connector->modes, head) { 27398445e2c5SVille Syrjälä if (!mode->expose_to_userspace) 27408445e2c5SVille Syrjälä continue; 27418445e2c5SVille Syrjälä 27428445e2c5SVille Syrjälä /* Clear the tag for the next time around */ 27438445e2c5SVille Syrjälä mode->expose_to_userspace = false; 27448445e2c5SVille Syrjälä 274552217195SDaniel Vetter drm_mode_convert_to_umode(&u_mode, mode); 2746c3ff0cdbSAnkit Nautiyal /* 2747c3ff0cdbSAnkit Nautiyal * Reset aspect ratio flags of user-mode, if modes with 2748c3ff0cdbSAnkit Nautiyal * aspect-ratio are not supported. 2749c3ff0cdbSAnkit Nautiyal */ 2750c3ff0cdbSAnkit Nautiyal if (!file_priv->aspect_ratio_allowed) 2751c3ff0cdbSAnkit Nautiyal u_mode.flags &= ~DRM_MODE_FLAG_PIC_AR_MASK; 275252217195SDaniel Vetter if (copy_to_user(mode_ptr + copied, 275352217195SDaniel Vetter &u_mode, sizeof(u_mode))) { 275452217195SDaniel Vetter ret = -EFAULT; 27558445e2c5SVille Syrjälä 27568445e2c5SVille Syrjälä /* 27578445e2c5SVille Syrjälä * Clear the tag for the rest of 27588445e2c5SVille Syrjälä * the modes for the next time around. 27598445e2c5SVille Syrjälä */ 27608445e2c5SVille Syrjälä list_for_each_entry_continue(mode, &connector->modes, head) 27618445e2c5SVille Syrjälä mode->expose_to_userspace = false; 27628445e2c5SVille Syrjälä 2763e94ac351SDaniel Vetter mutex_unlock(&dev->mode_config.mutex); 2764e94ac351SDaniel Vetter 276552217195SDaniel Vetter goto out; 276652217195SDaniel Vetter } 276752217195SDaniel Vetter copied++; 276852217195SDaniel Vetter } 27698445e2c5SVille Syrjälä } else { 27708445e2c5SVille Syrjälä /* Clear the tag for the next time around */ 27718445e2c5SVille Syrjälä list_for_each_entry(mode, &connector->modes, head) 27728445e2c5SVille Syrjälä mode->expose_to_userspace = false; 277352217195SDaniel Vetter } 27748445e2c5SVille Syrjälä 277552217195SDaniel Vetter out_resp->count_modes = mode_count; 277652217195SDaniel Vetter mutex_unlock(&dev->mode_config.mutex); 2777e94ac351SDaniel Vetter 2778e94ac351SDaniel Vetter drm_modeset_lock(&dev->mode_config.connection_mutex, NULL); 2779e94ac351SDaniel Vetter encoder = drm_connector_get_encoder(connector); 2780e94ac351SDaniel Vetter if (encoder) 2781e94ac351SDaniel Vetter out_resp->encoder_id = encoder->base.id; 2782e94ac351SDaniel Vetter else 2783e94ac351SDaniel Vetter out_resp->encoder_id = 0; 2784e94ac351SDaniel Vetter 2785e94ac351SDaniel Vetter /* Only grab properties after probing, to make sure EDID and other 2786c2ce66daSBeatriz Martins de Carvalho * properties reflect the latest status. 2787c2ce66daSBeatriz Martins de Carvalho */ 2788e94ac351SDaniel Vetter ret = drm_mode_object_get_properties(&connector->base, file_priv->atomic, 2789e94ac351SDaniel Vetter (uint32_t __user *)(unsigned long)(out_resp->props_ptr), 2790e94ac351SDaniel Vetter (uint64_t __user *)(unsigned long)(out_resp->prop_values_ptr), 2791e94ac351SDaniel Vetter &out_resp->count_props); 2792e94ac351SDaniel Vetter drm_modeset_unlock(&dev->mode_config.connection_mutex); 2793e94ac351SDaniel Vetter 2794e94ac351SDaniel Vetter out: 2795ad093607SThierry Reding drm_connector_put(connector); 279652217195SDaniel Vetter 279752217195SDaniel Vetter return ret; 279852217195SDaniel Vetter } 279952217195SDaniel Vetter 28003d3f7c1eSHans de Goede /** 28013d3f7c1eSHans de Goede * drm_connector_find_by_fwnode - Find a connector based on the associated fwnode 28023d3f7c1eSHans de Goede * @fwnode: fwnode for which to find the matching drm_connector 28033d3f7c1eSHans de Goede * 28043d3f7c1eSHans de Goede * This functions looks up a drm_connector based on its associated fwnode. When 28053d3f7c1eSHans de Goede * a connector is found a reference to the connector is returned. The caller must 28063d3f7c1eSHans de Goede * call drm_connector_put() to release this reference when it is done with the 28073d3f7c1eSHans de Goede * connector. 28083d3f7c1eSHans de Goede * 28093d3f7c1eSHans de Goede * Returns: A reference to the found connector or an ERR_PTR(). 28103d3f7c1eSHans de Goede */ 28113d3f7c1eSHans de Goede struct drm_connector *drm_connector_find_by_fwnode(struct fwnode_handle *fwnode) 28123d3f7c1eSHans de Goede { 28133d3f7c1eSHans de Goede struct drm_connector *connector, *found = ERR_PTR(-ENODEV); 28143d3f7c1eSHans de Goede 28153d3f7c1eSHans de Goede if (!fwnode) 28163d3f7c1eSHans de Goede return ERR_PTR(-ENODEV); 28173d3f7c1eSHans de Goede 28183d3f7c1eSHans de Goede mutex_lock(&connector_list_lock); 28193d3f7c1eSHans de Goede 28203d3f7c1eSHans de Goede list_for_each_entry(connector, &connector_list, global_connector_list_entry) { 28213d3f7c1eSHans de Goede if (connector->fwnode == fwnode || 28223d3f7c1eSHans de Goede (connector->fwnode && connector->fwnode->secondary == fwnode)) { 28233d3f7c1eSHans de Goede drm_connector_get(connector); 28243d3f7c1eSHans de Goede found = connector; 28253d3f7c1eSHans de Goede break; 28263d3f7c1eSHans de Goede } 28273d3f7c1eSHans de Goede } 28283d3f7c1eSHans de Goede 28293d3f7c1eSHans de Goede mutex_unlock(&connector_list_lock); 28303d3f7c1eSHans de Goede 28313d3f7c1eSHans de Goede return found; 28323d3f7c1eSHans de Goede } 28333d3f7c1eSHans de Goede 283472ad4968SHans de Goede /** 283572ad4968SHans de Goede * drm_connector_oob_hotplug_event - Report out-of-band hotplug event to connector 2836f85d9e59SRandy Dunlap * @connector_fwnode: fwnode_handle to report the event on 283772ad4968SHans de Goede * 283872ad4968SHans de Goede * On some hardware a hotplug event notification may come from outside the display 283972ad4968SHans de Goede * driver / device. An example of this is some USB Type-C setups where the hardware 284072ad4968SHans de Goede * muxes the DisplayPort data and aux-lines but does not pass the altmode HPD 284172ad4968SHans de Goede * status bit to the GPU's DP HPD pin. 284272ad4968SHans de Goede * 284372ad4968SHans de Goede * This function can be used to report these out-of-band events after obtaining 284472ad4968SHans de Goede * a drm_connector reference through calling drm_connector_find_by_fwnode(). 284572ad4968SHans de Goede */ 284672ad4968SHans de Goede void drm_connector_oob_hotplug_event(struct fwnode_handle *connector_fwnode) 284772ad4968SHans de Goede { 284872ad4968SHans de Goede struct drm_connector *connector; 284972ad4968SHans de Goede 285072ad4968SHans de Goede connector = drm_connector_find_by_fwnode(connector_fwnode); 285172ad4968SHans de Goede if (IS_ERR(connector)) 285272ad4968SHans de Goede return; 285372ad4968SHans de Goede 285472ad4968SHans de Goede if (connector->funcs->oob_hotplug_event) 285572ad4968SHans de Goede connector->funcs->oob_hotplug_event(connector); 285672ad4968SHans de Goede 285772ad4968SHans de Goede drm_connector_put(connector); 285872ad4968SHans de Goede } 285972ad4968SHans de Goede EXPORT_SYMBOL(drm_connector_oob_hotplug_event); 286072ad4968SHans de Goede 28619498c19bSDaniel Vetter 28629498c19bSDaniel Vetter /** 28639498c19bSDaniel Vetter * DOC: Tile group 28649498c19bSDaniel Vetter * 28659498c19bSDaniel Vetter * Tile groups are used to represent tiled monitors with a unique integer 28669498c19bSDaniel Vetter * identifier. Tiled monitors using DisplayID v1.3 have a unique 8-byte handle, 28679498c19bSDaniel Vetter * we store this in a tile group, so we have a common identifier for all tiles 28689498c19bSDaniel Vetter * in a monitor group. The property is called "TILE". Drivers can manage tile 28699498c19bSDaniel Vetter * groups using drm_mode_create_tile_group(), drm_mode_put_tile_group() and 28709498c19bSDaniel Vetter * drm_mode_get_tile_group(). But this is only needed for internal panels where 28719498c19bSDaniel Vetter * the tile group information is exposed through a non-standard way. 28729498c19bSDaniel Vetter */ 28739498c19bSDaniel Vetter 28749498c19bSDaniel Vetter static void drm_tile_group_free(struct kref *kref) 28759498c19bSDaniel Vetter { 28769498c19bSDaniel Vetter struct drm_tile_group *tg = container_of(kref, struct drm_tile_group, refcount); 28779498c19bSDaniel Vetter struct drm_device *dev = tg->dev; 2878948de842SSuraj Upadhyay 28799498c19bSDaniel Vetter mutex_lock(&dev->mode_config.idr_mutex); 28809498c19bSDaniel Vetter idr_remove(&dev->mode_config.tile_idr, tg->id); 28819498c19bSDaniel Vetter mutex_unlock(&dev->mode_config.idr_mutex); 28829498c19bSDaniel Vetter kfree(tg); 28839498c19bSDaniel Vetter } 28849498c19bSDaniel Vetter 28859498c19bSDaniel Vetter /** 28869498c19bSDaniel Vetter * drm_mode_put_tile_group - drop a reference to a tile group. 28879498c19bSDaniel Vetter * @dev: DRM device 28889498c19bSDaniel Vetter * @tg: tile group to drop reference to. 28899498c19bSDaniel Vetter * 28909498c19bSDaniel Vetter * drop reference to tile group and free if 0. 28919498c19bSDaniel Vetter */ 28929498c19bSDaniel Vetter void drm_mode_put_tile_group(struct drm_device *dev, 28939498c19bSDaniel Vetter struct drm_tile_group *tg) 28949498c19bSDaniel Vetter { 28959498c19bSDaniel Vetter kref_put(&tg->refcount, drm_tile_group_free); 28969498c19bSDaniel Vetter } 28979498c19bSDaniel Vetter EXPORT_SYMBOL(drm_mode_put_tile_group); 28989498c19bSDaniel Vetter 28999498c19bSDaniel Vetter /** 29009498c19bSDaniel Vetter * drm_mode_get_tile_group - get a reference to an existing tile group 29019498c19bSDaniel Vetter * @dev: DRM device 29029498c19bSDaniel Vetter * @topology: 8-bytes unique per monitor. 29039498c19bSDaniel Vetter * 29049498c19bSDaniel Vetter * Use the unique bytes to get a reference to an existing tile group. 29059498c19bSDaniel Vetter * 29069498c19bSDaniel Vetter * RETURNS: 29079498c19bSDaniel Vetter * tile group or NULL if not found. 29089498c19bSDaniel Vetter */ 29099498c19bSDaniel Vetter struct drm_tile_group *drm_mode_get_tile_group(struct drm_device *dev, 2910267ea759SVille Syrjälä const char topology[8]) 29119498c19bSDaniel Vetter { 29129498c19bSDaniel Vetter struct drm_tile_group *tg; 29139498c19bSDaniel Vetter int id; 2914948de842SSuraj Upadhyay 29159498c19bSDaniel Vetter mutex_lock(&dev->mode_config.idr_mutex); 29169498c19bSDaniel Vetter idr_for_each_entry(&dev->mode_config.tile_idr, tg, id) { 29179498c19bSDaniel Vetter if (!memcmp(tg->group_data, topology, 8)) { 29189498c19bSDaniel Vetter if (!kref_get_unless_zero(&tg->refcount)) 29199498c19bSDaniel Vetter tg = NULL; 29209498c19bSDaniel Vetter mutex_unlock(&dev->mode_config.idr_mutex); 29219498c19bSDaniel Vetter return tg; 29229498c19bSDaniel Vetter } 29239498c19bSDaniel Vetter } 29249498c19bSDaniel Vetter mutex_unlock(&dev->mode_config.idr_mutex); 29259498c19bSDaniel Vetter return NULL; 29269498c19bSDaniel Vetter } 29279498c19bSDaniel Vetter EXPORT_SYMBOL(drm_mode_get_tile_group); 29289498c19bSDaniel Vetter 29299498c19bSDaniel Vetter /** 29309498c19bSDaniel Vetter * drm_mode_create_tile_group - create a tile group from a displayid description 29319498c19bSDaniel Vetter * @dev: DRM device 29329498c19bSDaniel Vetter * @topology: 8-bytes unique per monitor. 29339498c19bSDaniel Vetter * 29349498c19bSDaniel Vetter * Create a tile group for the unique monitor, and get a unique 29359498c19bSDaniel Vetter * identifier for the tile group. 29369498c19bSDaniel Vetter * 29379498c19bSDaniel Vetter * RETURNS: 2938705c8160SDan Carpenter * new tile group or NULL. 29399498c19bSDaniel Vetter */ 29409498c19bSDaniel Vetter struct drm_tile_group *drm_mode_create_tile_group(struct drm_device *dev, 2941267ea759SVille Syrjälä const char topology[8]) 29429498c19bSDaniel Vetter { 29439498c19bSDaniel Vetter struct drm_tile_group *tg; 29449498c19bSDaniel Vetter int ret; 29459498c19bSDaniel Vetter 29469498c19bSDaniel Vetter tg = kzalloc(sizeof(*tg), GFP_KERNEL); 29479498c19bSDaniel Vetter if (!tg) 2948705c8160SDan Carpenter return NULL; 29499498c19bSDaniel Vetter 29509498c19bSDaniel Vetter kref_init(&tg->refcount); 29519498c19bSDaniel Vetter memcpy(tg->group_data, topology, 8); 29529498c19bSDaniel Vetter tg->dev = dev; 29539498c19bSDaniel Vetter 29549498c19bSDaniel Vetter mutex_lock(&dev->mode_config.idr_mutex); 29559498c19bSDaniel Vetter ret = idr_alloc(&dev->mode_config.tile_idr, tg, 1, 0, GFP_KERNEL); 29569498c19bSDaniel Vetter if (ret >= 0) { 29579498c19bSDaniel Vetter tg->id = ret; 29589498c19bSDaniel Vetter } else { 29599498c19bSDaniel Vetter kfree(tg); 2960705c8160SDan Carpenter tg = NULL; 29619498c19bSDaniel Vetter } 29629498c19bSDaniel Vetter 29639498c19bSDaniel Vetter mutex_unlock(&dev->mode_config.idr_mutex); 29649498c19bSDaniel Vetter return tg; 29659498c19bSDaniel Vetter } 29669498c19bSDaniel Vetter EXPORT_SYMBOL(drm_mode_create_tile_group); 2967