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 2352217195SDaniel Vetter #include <drm/drmP.h> 2452217195SDaniel Vetter #include <drm/drm_connector.h> 2552217195SDaniel Vetter #include <drm/drm_edid.h> 269338203cSLaurent Pinchart #include <drm/drm_encoder.h> 278d70f395SHans de Goede #include <drm/drm_utils.h> 2852217195SDaniel Vetter 2952217195SDaniel Vetter #include "drm_crtc_internal.h" 3052217195SDaniel Vetter #include "drm_internal.h" 3152217195SDaniel Vetter 32ae2a6da8SDaniel Vetter /** 33ae2a6da8SDaniel Vetter * DOC: overview 34ae2a6da8SDaniel Vetter * 35ae2a6da8SDaniel Vetter * In DRM connectors are the general abstraction for display sinks, and include 36ae2a6da8SDaniel Vetter * als fixed panels or anything else that can display pixels in some form. As 37ae2a6da8SDaniel Vetter * opposed to all other KMS objects representing hardware (like CRTC, encoder or 38ae2a6da8SDaniel Vetter * plane abstractions) connectors can be hotplugged and unplugged at runtime. 39ad093607SThierry Reding * Hence they are reference-counted using drm_connector_get() and 40ad093607SThierry Reding * drm_connector_put(). 41ae2a6da8SDaniel Vetter * 42d574528aSDaniel Vetter * KMS driver must create, initialize, register and attach at a &struct 43d574528aSDaniel Vetter * drm_connector for each such sink. The instance is created as other KMS 44aec97460SDaniel Vetter * objects and initialized by setting the following fields. The connector is 45aec97460SDaniel Vetter * initialized with a call to drm_connector_init() with a pointer to the 46aec97460SDaniel Vetter * &struct drm_connector_funcs and a connector type, and then exposed to 47aec97460SDaniel Vetter * userspace with a call to drm_connector_register(). 48ae2a6da8SDaniel Vetter * 49ae2a6da8SDaniel Vetter * Connectors must be attached to an encoder to be used. For devices that map 50ae2a6da8SDaniel Vetter * connectors to encoders 1:1, the connector should be attached at 51ae2a6da8SDaniel Vetter * initialization time with a call to drm_mode_connector_attach_encoder(). The 52d574528aSDaniel Vetter * driver must also set the &drm_connector.encoder field to point to the 53ae2a6da8SDaniel Vetter * attached encoder. 54ae2a6da8SDaniel Vetter * 55ae2a6da8SDaniel Vetter * For connectors which are not fixed (like built-in panels) the driver needs to 56ae2a6da8SDaniel Vetter * support hotplug notifications. The simplest way to do that is by using the 57ae2a6da8SDaniel Vetter * probe helpers, see drm_kms_helper_poll_init() for connectors which don't have 58ae2a6da8SDaniel Vetter * hardware support for hotplug interrupts. Connectors with hardware hotplug 59ae2a6da8SDaniel Vetter * support can instead use e.g. drm_helper_hpd_irq_event(). 60ae2a6da8SDaniel Vetter */ 61ae2a6da8SDaniel Vetter 6252217195SDaniel Vetter struct drm_conn_prop_enum_list { 6352217195SDaniel Vetter int type; 6452217195SDaniel Vetter const char *name; 6552217195SDaniel Vetter struct ida ida; 6652217195SDaniel Vetter }; 6752217195SDaniel Vetter 6852217195SDaniel Vetter /* 6952217195SDaniel Vetter * Connector and encoder types. 7052217195SDaniel Vetter */ 7152217195SDaniel Vetter static struct drm_conn_prop_enum_list drm_connector_enum_list[] = { 7252217195SDaniel Vetter { DRM_MODE_CONNECTOR_Unknown, "Unknown" }, 7352217195SDaniel Vetter { DRM_MODE_CONNECTOR_VGA, "VGA" }, 7452217195SDaniel Vetter { DRM_MODE_CONNECTOR_DVII, "DVI-I" }, 7552217195SDaniel Vetter { DRM_MODE_CONNECTOR_DVID, "DVI-D" }, 7652217195SDaniel Vetter { DRM_MODE_CONNECTOR_DVIA, "DVI-A" }, 7752217195SDaniel Vetter { DRM_MODE_CONNECTOR_Composite, "Composite" }, 7852217195SDaniel Vetter { DRM_MODE_CONNECTOR_SVIDEO, "SVIDEO" }, 7952217195SDaniel Vetter { DRM_MODE_CONNECTOR_LVDS, "LVDS" }, 8052217195SDaniel Vetter { DRM_MODE_CONNECTOR_Component, "Component" }, 8152217195SDaniel Vetter { DRM_MODE_CONNECTOR_9PinDIN, "DIN" }, 8252217195SDaniel Vetter { DRM_MODE_CONNECTOR_DisplayPort, "DP" }, 8352217195SDaniel Vetter { DRM_MODE_CONNECTOR_HDMIA, "HDMI-A" }, 8452217195SDaniel Vetter { DRM_MODE_CONNECTOR_HDMIB, "HDMI-B" }, 8552217195SDaniel Vetter { DRM_MODE_CONNECTOR_TV, "TV" }, 8652217195SDaniel Vetter { DRM_MODE_CONNECTOR_eDP, "eDP" }, 8752217195SDaniel Vetter { DRM_MODE_CONNECTOR_VIRTUAL, "Virtual" }, 8852217195SDaniel Vetter { DRM_MODE_CONNECTOR_DSI, "DSI" }, 8952217195SDaniel Vetter { DRM_MODE_CONNECTOR_DPI, "DPI" }, 90935774cdSBrian Starkey { DRM_MODE_CONNECTOR_WRITEBACK, "Writeback" }, 9152217195SDaniel Vetter }; 9252217195SDaniel Vetter 9352217195SDaniel Vetter void drm_connector_ida_init(void) 9452217195SDaniel Vetter { 9552217195SDaniel Vetter int i; 9652217195SDaniel Vetter 9752217195SDaniel Vetter for (i = 0; i < ARRAY_SIZE(drm_connector_enum_list); i++) 9852217195SDaniel Vetter ida_init(&drm_connector_enum_list[i].ida); 9952217195SDaniel Vetter } 10052217195SDaniel Vetter 10152217195SDaniel Vetter void drm_connector_ida_destroy(void) 10252217195SDaniel Vetter { 10352217195SDaniel Vetter int i; 10452217195SDaniel Vetter 10552217195SDaniel Vetter for (i = 0; i < ARRAY_SIZE(drm_connector_enum_list); i++) 10652217195SDaniel Vetter ida_destroy(&drm_connector_enum_list[i].ida); 10752217195SDaniel Vetter } 10852217195SDaniel Vetter 10952217195SDaniel Vetter /** 11052217195SDaniel Vetter * drm_connector_get_cmdline_mode - reads the user's cmdline mode 11152217195SDaniel Vetter * @connector: connector to quwery 11252217195SDaniel Vetter * 113ae2a6da8SDaniel Vetter * The kernel supports per-connector configuration of its consoles through 11452217195SDaniel Vetter * use of the video= parameter. This function parses that option and 11552217195SDaniel Vetter * extracts the user's specified mode (or enable/disable status) for a 11652217195SDaniel Vetter * particular connector. This is typically only used during the early fbdev 11752217195SDaniel Vetter * setup. 11852217195SDaniel Vetter */ 11952217195SDaniel Vetter static void drm_connector_get_cmdline_mode(struct drm_connector *connector) 12052217195SDaniel Vetter { 12152217195SDaniel Vetter struct drm_cmdline_mode *mode = &connector->cmdline_mode; 12252217195SDaniel Vetter char *option = NULL; 12352217195SDaniel Vetter 12452217195SDaniel Vetter if (fb_get_options(connector->name, &option)) 12552217195SDaniel Vetter return; 12652217195SDaniel Vetter 12752217195SDaniel Vetter if (!drm_mode_parse_command_line_for_connector(option, 12852217195SDaniel Vetter connector, 12952217195SDaniel Vetter mode)) 13052217195SDaniel Vetter return; 13152217195SDaniel Vetter 13252217195SDaniel Vetter if (mode->force) { 1336140cf20SJani Nikula DRM_INFO("forcing %s connector %s\n", connector->name, 1346140cf20SJani Nikula drm_get_connector_force_name(mode->force)); 13552217195SDaniel Vetter connector->force = mode->force; 13652217195SDaniel Vetter } 13752217195SDaniel Vetter 13852217195SDaniel Vetter DRM_DEBUG_KMS("cmdline mode for connector %s %dx%d@%dHz%s%s%s\n", 13952217195SDaniel Vetter connector->name, 14052217195SDaniel Vetter mode->xres, mode->yres, 14152217195SDaniel Vetter mode->refresh_specified ? mode->refresh : 60, 14252217195SDaniel Vetter mode->rb ? " reduced blanking" : "", 14352217195SDaniel Vetter mode->margins ? " with margins" : "", 14452217195SDaniel Vetter mode->interlace ? " interlaced" : ""); 14552217195SDaniel Vetter } 14652217195SDaniel Vetter 14752217195SDaniel Vetter static void drm_connector_free(struct kref *kref) 14852217195SDaniel Vetter { 14952217195SDaniel Vetter struct drm_connector *connector = 15052217195SDaniel Vetter container_of(kref, struct drm_connector, base.refcount); 15152217195SDaniel Vetter struct drm_device *dev = connector->dev; 15252217195SDaniel Vetter 15352217195SDaniel Vetter drm_mode_object_unregister(dev, &connector->base); 15452217195SDaniel Vetter connector->funcs->destroy(connector); 15552217195SDaniel Vetter } 15652217195SDaniel Vetter 157ea497bb9SDaniel Vetter void drm_connector_free_work_fn(struct work_struct *work) 158a703c550SDaniel Vetter { 159ea497bb9SDaniel Vetter struct drm_connector *connector, *n; 160ea497bb9SDaniel Vetter struct drm_device *dev = 161ea497bb9SDaniel Vetter container_of(work, struct drm_device, mode_config.connector_free_work); 162ea497bb9SDaniel Vetter struct drm_mode_config *config = &dev->mode_config; 163ea497bb9SDaniel Vetter unsigned long flags; 164ea497bb9SDaniel Vetter struct llist_node *freed; 165a703c550SDaniel Vetter 166ea497bb9SDaniel Vetter spin_lock_irqsave(&config->connector_list_lock, flags); 167ea497bb9SDaniel Vetter freed = llist_del_all(&config->connector_free_list); 168ea497bb9SDaniel Vetter spin_unlock_irqrestore(&config->connector_list_lock, flags); 169ea497bb9SDaniel Vetter 170ea497bb9SDaniel Vetter llist_for_each_entry_safe(connector, n, freed, free_node) { 171a703c550SDaniel Vetter drm_mode_object_unregister(dev, &connector->base); 172a703c550SDaniel Vetter connector->funcs->destroy(connector); 173a703c550SDaniel Vetter } 174ea497bb9SDaniel Vetter } 175a703c550SDaniel Vetter 17652217195SDaniel Vetter /** 17752217195SDaniel Vetter * drm_connector_init - Init a preallocated connector 17852217195SDaniel Vetter * @dev: DRM device 17952217195SDaniel Vetter * @connector: the connector to init 18052217195SDaniel Vetter * @funcs: callbacks for this connector 18152217195SDaniel Vetter * @connector_type: user visible type of the connector 18252217195SDaniel Vetter * 18352217195SDaniel Vetter * Initialises a preallocated connector. Connectors should be 18452217195SDaniel Vetter * subclassed as part of driver connector objects. 18552217195SDaniel Vetter * 18652217195SDaniel Vetter * Returns: 18752217195SDaniel Vetter * Zero on success, error code on failure. 18852217195SDaniel Vetter */ 18952217195SDaniel Vetter int drm_connector_init(struct drm_device *dev, 19052217195SDaniel Vetter struct drm_connector *connector, 19152217195SDaniel Vetter const struct drm_connector_funcs *funcs, 19252217195SDaniel Vetter int connector_type) 19352217195SDaniel Vetter { 19452217195SDaniel Vetter struct drm_mode_config *config = &dev->mode_config; 19552217195SDaniel Vetter int ret; 19652217195SDaniel Vetter struct ida *connector_ida = 19752217195SDaniel Vetter &drm_connector_enum_list[connector_type].ida; 19852217195SDaniel Vetter 199ba1f665fSHaneen Mohammed WARN_ON(drm_drv_uses_atomic_modeset(dev) && 200ba1f665fSHaneen Mohammed (!funcs->atomic_destroy_state || 201ba1f665fSHaneen Mohammed !funcs->atomic_duplicate_state)); 202ba1f665fSHaneen Mohammed 2032135ea7aSThierry Reding ret = __drm_mode_object_add(dev, &connector->base, 20452217195SDaniel Vetter DRM_MODE_OBJECT_CONNECTOR, 20552217195SDaniel Vetter false, drm_connector_free); 20652217195SDaniel Vetter if (ret) 207613051daSDaniel Vetter return ret; 20852217195SDaniel Vetter 20952217195SDaniel Vetter connector->base.properties = &connector->properties; 21052217195SDaniel Vetter connector->dev = dev; 21152217195SDaniel Vetter connector->funcs = funcs; 21252217195SDaniel Vetter 2132a8d3eacSVille Syrjälä /* connector index is used with 32bit bitmasks */ 2142a8d3eacSVille Syrjälä ret = ida_simple_get(&config->connector_ida, 0, 32, GFP_KERNEL); 2152a8d3eacSVille Syrjälä if (ret < 0) { 2162a8d3eacSVille Syrjälä DRM_DEBUG_KMS("Failed to allocate %s connector index: %d\n", 2172a8d3eacSVille Syrjälä drm_connector_enum_list[connector_type].name, 2182a8d3eacSVille Syrjälä ret); 21952217195SDaniel Vetter goto out_put; 2202a8d3eacSVille Syrjälä } 22152217195SDaniel Vetter connector->index = ret; 22252217195SDaniel Vetter ret = 0; 22352217195SDaniel Vetter 22452217195SDaniel Vetter connector->connector_type = connector_type; 22552217195SDaniel Vetter connector->connector_type_id = 22652217195SDaniel Vetter ida_simple_get(connector_ida, 1, 0, GFP_KERNEL); 22752217195SDaniel Vetter if (connector->connector_type_id < 0) { 22852217195SDaniel Vetter ret = connector->connector_type_id; 22952217195SDaniel Vetter goto out_put_id; 23052217195SDaniel Vetter } 23152217195SDaniel Vetter connector->name = 23252217195SDaniel Vetter kasprintf(GFP_KERNEL, "%s-%d", 23352217195SDaniel Vetter drm_connector_enum_list[connector_type].name, 23452217195SDaniel Vetter connector->connector_type_id); 23552217195SDaniel Vetter if (!connector->name) { 23652217195SDaniel Vetter ret = -ENOMEM; 23752217195SDaniel Vetter goto out_put_type_id; 23852217195SDaniel Vetter } 23952217195SDaniel Vetter 24052217195SDaniel Vetter INIT_LIST_HEAD(&connector->probed_modes); 24152217195SDaniel Vetter INIT_LIST_HEAD(&connector->modes); 242e73ab00eSDaniel Vetter mutex_init(&connector->mutex); 24352217195SDaniel Vetter connector->edid_blob_ptr = NULL; 24452217195SDaniel Vetter connector->status = connector_status_unknown; 2458d70f395SHans de Goede connector->display_info.panel_orientation = 2468d70f395SHans de Goede DRM_MODE_PANEL_ORIENTATION_UNKNOWN; 24752217195SDaniel Vetter 24852217195SDaniel Vetter drm_connector_get_cmdline_mode(connector); 24952217195SDaniel Vetter 25052217195SDaniel Vetter /* We should add connectors at the end to avoid upsetting the connector 25152217195SDaniel Vetter * index too much. */ 252613051daSDaniel Vetter spin_lock_irq(&config->connector_list_lock); 25352217195SDaniel Vetter list_add_tail(&connector->head, &config->connector_list); 25452217195SDaniel Vetter config->num_connector++; 255613051daSDaniel Vetter spin_unlock_irq(&config->connector_list_lock); 25652217195SDaniel Vetter 257935774cdSBrian Starkey if (connector_type != DRM_MODE_CONNECTOR_VIRTUAL && 258935774cdSBrian Starkey connector_type != DRM_MODE_CONNECTOR_WRITEBACK) 25952217195SDaniel Vetter drm_object_attach_property(&connector->base, 26052217195SDaniel Vetter config->edid_property, 26152217195SDaniel Vetter 0); 26252217195SDaniel Vetter 26352217195SDaniel Vetter drm_object_attach_property(&connector->base, 26452217195SDaniel Vetter config->dpms_property, 0); 26552217195SDaniel Vetter 26640ee6fbeSManasi Navare drm_object_attach_property(&connector->base, 26740ee6fbeSManasi Navare config->link_status_property, 26840ee6fbeSManasi Navare 0); 26940ee6fbeSManasi Navare 27066660d4cSDave Airlie drm_object_attach_property(&connector->base, 27166660d4cSDave Airlie config->non_desktop_property, 27266660d4cSDave Airlie 0); 27366660d4cSDave Airlie 27452217195SDaniel Vetter if (drm_core_check_feature(dev, DRIVER_ATOMIC)) { 27552217195SDaniel Vetter drm_object_attach_property(&connector->base, config->prop_crtc_id, 0); 27652217195SDaniel Vetter } 27752217195SDaniel Vetter 27852217195SDaniel Vetter connector->debugfs_entry = NULL; 27952217195SDaniel Vetter out_put_type_id: 28052217195SDaniel Vetter if (ret) 281587680c1SChristophe JAILLET ida_simple_remove(connector_ida, connector->connector_type_id); 28252217195SDaniel Vetter out_put_id: 28352217195SDaniel Vetter if (ret) 284587680c1SChristophe JAILLET ida_simple_remove(&config->connector_ida, connector->index); 28552217195SDaniel Vetter out_put: 28652217195SDaniel Vetter if (ret) 28752217195SDaniel Vetter drm_mode_object_unregister(dev, &connector->base); 28852217195SDaniel Vetter 28952217195SDaniel Vetter return ret; 29052217195SDaniel Vetter } 29152217195SDaniel Vetter EXPORT_SYMBOL(drm_connector_init); 29252217195SDaniel Vetter 29352217195SDaniel Vetter /** 29452217195SDaniel Vetter * drm_mode_connector_attach_encoder - attach a connector to an encoder 29552217195SDaniel Vetter * @connector: connector to attach 29652217195SDaniel Vetter * @encoder: encoder to attach @connector to 29752217195SDaniel Vetter * 29852217195SDaniel Vetter * This function links up a connector to an encoder. Note that the routing 29952217195SDaniel Vetter * restrictions between encoders and crtcs are exposed to userspace through the 30052217195SDaniel Vetter * possible_clones and possible_crtcs bitmasks. 30152217195SDaniel Vetter * 30252217195SDaniel Vetter * Returns: 30352217195SDaniel Vetter * Zero on success, negative errno on failure. 30452217195SDaniel Vetter */ 30552217195SDaniel Vetter int drm_mode_connector_attach_encoder(struct drm_connector *connector, 30652217195SDaniel Vetter struct drm_encoder *encoder) 30752217195SDaniel Vetter { 30852217195SDaniel Vetter int i; 30952217195SDaniel Vetter 31052217195SDaniel Vetter /* 31152217195SDaniel Vetter * In the past, drivers have attempted to model the static association 31252217195SDaniel Vetter * of connector to encoder in simple connector/encoder devices using a 31352217195SDaniel Vetter * direct assignment of connector->encoder = encoder. This connection 31452217195SDaniel Vetter * is a logical one and the responsibility of the core, so drivers are 31552217195SDaniel Vetter * expected not to mess with this. 31652217195SDaniel Vetter * 31752217195SDaniel Vetter * Note that the error return should've been enough here, but a large 31852217195SDaniel Vetter * majority of drivers ignores the return value, so add in a big WARN 31952217195SDaniel Vetter * to get people's attention. 32052217195SDaniel Vetter */ 32152217195SDaniel Vetter if (WARN_ON(connector->encoder)) 32252217195SDaniel Vetter return -EINVAL; 32352217195SDaniel Vetter 32452217195SDaniel Vetter for (i = 0; i < DRM_CONNECTOR_MAX_ENCODER; i++) { 32552217195SDaniel Vetter if (connector->encoder_ids[i] == 0) { 32652217195SDaniel Vetter connector->encoder_ids[i] = encoder->base.id; 32752217195SDaniel Vetter return 0; 32852217195SDaniel Vetter } 32952217195SDaniel Vetter } 33052217195SDaniel Vetter return -ENOMEM; 33152217195SDaniel Vetter } 33252217195SDaniel Vetter EXPORT_SYMBOL(drm_mode_connector_attach_encoder); 33352217195SDaniel Vetter 33452217195SDaniel Vetter static void drm_mode_remove(struct drm_connector *connector, 33552217195SDaniel Vetter struct drm_display_mode *mode) 33652217195SDaniel Vetter { 33752217195SDaniel Vetter list_del(&mode->head); 33852217195SDaniel Vetter drm_mode_destroy(connector->dev, mode); 33952217195SDaniel Vetter } 34052217195SDaniel Vetter 34152217195SDaniel Vetter /** 34252217195SDaniel Vetter * drm_connector_cleanup - cleans up an initialised connector 34352217195SDaniel Vetter * @connector: connector to cleanup 34452217195SDaniel Vetter * 34552217195SDaniel Vetter * Cleans up the connector but doesn't free the object. 34652217195SDaniel Vetter */ 34752217195SDaniel Vetter void drm_connector_cleanup(struct drm_connector *connector) 34852217195SDaniel Vetter { 34952217195SDaniel Vetter struct drm_device *dev = connector->dev; 35052217195SDaniel Vetter struct drm_display_mode *mode, *t; 35152217195SDaniel Vetter 35252217195SDaniel Vetter /* The connector should have been removed from userspace long before 35352217195SDaniel Vetter * it is finally destroyed. 35452217195SDaniel Vetter */ 35552217195SDaniel Vetter if (WARN_ON(connector->registered)) 35652217195SDaniel Vetter drm_connector_unregister(connector); 35752217195SDaniel Vetter 35852217195SDaniel Vetter if (connector->tile_group) { 35952217195SDaniel Vetter drm_mode_put_tile_group(dev, connector->tile_group); 36052217195SDaniel Vetter connector->tile_group = NULL; 36152217195SDaniel Vetter } 36252217195SDaniel Vetter 36352217195SDaniel Vetter list_for_each_entry_safe(mode, t, &connector->probed_modes, head) 36452217195SDaniel Vetter drm_mode_remove(connector, mode); 36552217195SDaniel Vetter 36652217195SDaniel Vetter list_for_each_entry_safe(mode, t, &connector->modes, head) 36752217195SDaniel Vetter drm_mode_remove(connector, mode); 36852217195SDaniel Vetter 3699a47dba1SChristophe JAILLET ida_simple_remove(&drm_connector_enum_list[connector->connector_type].ida, 37052217195SDaniel Vetter connector->connector_type_id); 37152217195SDaniel Vetter 3729a47dba1SChristophe JAILLET ida_simple_remove(&dev->mode_config.connector_ida, 37352217195SDaniel Vetter connector->index); 37452217195SDaniel Vetter 37552217195SDaniel Vetter kfree(connector->display_info.bus_formats); 37652217195SDaniel Vetter drm_mode_object_unregister(dev, &connector->base); 37752217195SDaniel Vetter kfree(connector->name); 37852217195SDaniel Vetter connector->name = NULL; 379613051daSDaniel Vetter spin_lock_irq(&dev->mode_config.connector_list_lock); 38052217195SDaniel Vetter list_del(&connector->head); 38152217195SDaniel Vetter dev->mode_config.num_connector--; 382613051daSDaniel Vetter spin_unlock_irq(&dev->mode_config.connector_list_lock); 38352217195SDaniel Vetter 38452217195SDaniel Vetter WARN_ON(connector->state && !connector->funcs->atomic_destroy_state); 38552217195SDaniel Vetter if (connector->state && connector->funcs->atomic_destroy_state) 38652217195SDaniel Vetter connector->funcs->atomic_destroy_state(connector, 38752217195SDaniel Vetter connector->state); 38852217195SDaniel Vetter 389e73ab00eSDaniel Vetter mutex_destroy(&connector->mutex); 390e73ab00eSDaniel Vetter 39152217195SDaniel Vetter memset(connector, 0, sizeof(*connector)); 39252217195SDaniel Vetter } 39352217195SDaniel Vetter EXPORT_SYMBOL(drm_connector_cleanup); 39452217195SDaniel Vetter 39552217195SDaniel Vetter /** 39652217195SDaniel Vetter * drm_connector_register - register a connector 39752217195SDaniel Vetter * @connector: the connector to register 39852217195SDaniel Vetter * 39952217195SDaniel Vetter * Register userspace interfaces for a connector 40052217195SDaniel Vetter * 40152217195SDaniel Vetter * Returns: 40252217195SDaniel Vetter * Zero on success, error code on failure. 40352217195SDaniel Vetter */ 40452217195SDaniel Vetter int drm_connector_register(struct drm_connector *connector) 40552217195SDaniel Vetter { 406e73ab00eSDaniel Vetter int ret = 0; 40752217195SDaniel Vetter 408e6e7b48bSDaniel Vetter if (!connector->dev->registered) 409e6e7b48bSDaniel Vetter return 0; 410e6e7b48bSDaniel Vetter 411e73ab00eSDaniel Vetter mutex_lock(&connector->mutex); 41252217195SDaniel Vetter if (connector->registered) 413e73ab00eSDaniel Vetter goto unlock; 41452217195SDaniel Vetter 41552217195SDaniel Vetter ret = drm_sysfs_connector_add(connector); 41652217195SDaniel Vetter if (ret) 417e73ab00eSDaniel Vetter goto unlock; 41852217195SDaniel Vetter 41952217195SDaniel Vetter ret = drm_debugfs_connector_add(connector); 42052217195SDaniel Vetter if (ret) { 42152217195SDaniel Vetter goto err_sysfs; 42252217195SDaniel Vetter } 42352217195SDaniel Vetter 42452217195SDaniel Vetter if (connector->funcs->late_register) { 42552217195SDaniel Vetter ret = connector->funcs->late_register(connector); 42652217195SDaniel Vetter if (ret) 42752217195SDaniel Vetter goto err_debugfs; 42852217195SDaniel Vetter } 42952217195SDaniel Vetter 43052217195SDaniel Vetter drm_mode_object_register(connector->dev, &connector->base); 43152217195SDaniel Vetter 43252217195SDaniel Vetter connector->registered = true; 433e73ab00eSDaniel Vetter goto unlock; 43452217195SDaniel Vetter 43552217195SDaniel Vetter err_debugfs: 43652217195SDaniel Vetter drm_debugfs_connector_remove(connector); 43752217195SDaniel Vetter err_sysfs: 43852217195SDaniel Vetter drm_sysfs_connector_remove(connector); 439e73ab00eSDaniel Vetter unlock: 440e73ab00eSDaniel Vetter mutex_unlock(&connector->mutex); 44152217195SDaniel Vetter return ret; 44252217195SDaniel Vetter } 44352217195SDaniel Vetter EXPORT_SYMBOL(drm_connector_register); 44452217195SDaniel Vetter 44552217195SDaniel Vetter /** 44652217195SDaniel Vetter * drm_connector_unregister - unregister a connector 44752217195SDaniel Vetter * @connector: the connector to unregister 44852217195SDaniel Vetter * 44952217195SDaniel Vetter * Unregister userspace interfaces for a connector 45052217195SDaniel Vetter */ 45152217195SDaniel Vetter void drm_connector_unregister(struct drm_connector *connector) 45252217195SDaniel Vetter { 453e73ab00eSDaniel Vetter mutex_lock(&connector->mutex); 454e73ab00eSDaniel Vetter if (!connector->registered) { 455e73ab00eSDaniel Vetter mutex_unlock(&connector->mutex); 45652217195SDaniel Vetter return; 457e73ab00eSDaniel Vetter } 45852217195SDaniel Vetter 45952217195SDaniel Vetter if (connector->funcs->early_unregister) 46052217195SDaniel Vetter connector->funcs->early_unregister(connector); 46152217195SDaniel Vetter 46252217195SDaniel Vetter drm_sysfs_connector_remove(connector); 46352217195SDaniel Vetter drm_debugfs_connector_remove(connector); 46452217195SDaniel Vetter 46552217195SDaniel Vetter connector->registered = false; 466e73ab00eSDaniel Vetter mutex_unlock(&connector->mutex); 46752217195SDaniel Vetter } 46852217195SDaniel Vetter EXPORT_SYMBOL(drm_connector_unregister); 46952217195SDaniel Vetter 47052217195SDaniel Vetter void drm_connector_unregister_all(struct drm_device *dev) 47152217195SDaniel Vetter { 47252217195SDaniel Vetter struct drm_connector *connector; 473613051daSDaniel Vetter struct drm_connector_list_iter conn_iter; 47452217195SDaniel Vetter 475b982dab1SThierry Reding drm_connector_list_iter_begin(dev, &conn_iter); 476613051daSDaniel Vetter drm_for_each_connector_iter(connector, &conn_iter) 47752217195SDaniel Vetter drm_connector_unregister(connector); 478b982dab1SThierry Reding drm_connector_list_iter_end(&conn_iter); 47952217195SDaniel Vetter } 48052217195SDaniel Vetter 48152217195SDaniel Vetter int drm_connector_register_all(struct drm_device *dev) 48252217195SDaniel Vetter { 48352217195SDaniel Vetter struct drm_connector *connector; 484613051daSDaniel Vetter struct drm_connector_list_iter conn_iter; 485613051daSDaniel Vetter int ret = 0; 48652217195SDaniel Vetter 487b982dab1SThierry Reding drm_connector_list_iter_begin(dev, &conn_iter); 488613051daSDaniel Vetter drm_for_each_connector_iter(connector, &conn_iter) { 48952217195SDaniel Vetter ret = drm_connector_register(connector); 49052217195SDaniel Vetter if (ret) 491613051daSDaniel Vetter break; 49252217195SDaniel Vetter } 493b982dab1SThierry Reding drm_connector_list_iter_end(&conn_iter); 49452217195SDaniel Vetter 495613051daSDaniel Vetter if (ret) 49652217195SDaniel Vetter drm_connector_unregister_all(dev); 49752217195SDaniel Vetter return ret; 49852217195SDaniel Vetter } 49952217195SDaniel Vetter 50052217195SDaniel Vetter /** 50152217195SDaniel Vetter * drm_get_connector_status_name - return a string for connector status 50252217195SDaniel Vetter * @status: connector status to compute name of 50352217195SDaniel Vetter * 50452217195SDaniel Vetter * In contrast to the other drm_get_*_name functions this one here returns a 50552217195SDaniel Vetter * const pointer and hence is threadsafe. 50652217195SDaniel Vetter */ 50752217195SDaniel Vetter const char *drm_get_connector_status_name(enum drm_connector_status status) 50852217195SDaniel Vetter { 50952217195SDaniel Vetter if (status == connector_status_connected) 51052217195SDaniel Vetter return "connected"; 51152217195SDaniel Vetter else if (status == connector_status_disconnected) 51252217195SDaniel Vetter return "disconnected"; 51352217195SDaniel Vetter else 51452217195SDaniel Vetter return "unknown"; 51552217195SDaniel Vetter } 51652217195SDaniel Vetter EXPORT_SYMBOL(drm_get_connector_status_name); 51752217195SDaniel Vetter 5186140cf20SJani Nikula /** 5196140cf20SJani Nikula * drm_get_connector_force_name - return a string for connector force 5206140cf20SJani Nikula * @force: connector force to get name of 5216140cf20SJani Nikula * 5226140cf20SJani Nikula * Returns: const pointer to name. 5236140cf20SJani Nikula */ 5246140cf20SJani Nikula const char *drm_get_connector_force_name(enum drm_connector_force force) 5256140cf20SJani Nikula { 5266140cf20SJani Nikula switch (force) { 5276140cf20SJani Nikula case DRM_FORCE_UNSPECIFIED: 5286140cf20SJani Nikula return "unspecified"; 5296140cf20SJani Nikula case DRM_FORCE_OFF: 5306140cf20SJani Nikula return "off"; 5316140cf20SJani Nikula case DRM_FORCE_ON: 5326140cf20SJani Nikula return "on"; 5336140cf20SJani Nikula case DRM_FORCE_ON_DIGITAL: 5346140cf20SJani Nikula return "digital"; 5356140cf20SJani Nikula default: 5366140cf20SJani Nikula return "unknown"; 5376140cf20SJani Nikula } 5386140cf20SJani Nikula } 5396140cf20SJani Nikula 540613051daSDaniel Vetter #ifdef CONFIG_LOCKDEP 541613051daSDaniel Vetter static struct lockdep_map connector_list_iter_dep_map = { 542613051daSDaniel Vetter .name = "drm_connector_list_iter" 543613051daSDaniel Vetter }; 544613051daSDaniel Vetter #endif 545613051daSDaniel Vetter 546613051daSDaniel Vetter /** 547b982dab1SThierry Reding * drm_connector_list_iter_begin - initialize a connector_list iterator 548613051daSDaniel Vetter * @dev: DRM device 549613051daSDaniel Vetter * @iter: connector_list iterator 550613051daSDaniel Vetter * 551d574528aSDaniel Vetter * Sets @iter up to walk the &drm_mode_config.connector_list of @dev. @iter 552b982dab1SThierry Reding * must always be cleaned up again by calling drm_connector_list_iter_end(). 553613051daSDaniel Vetter * Iteration itself happens using drm_connector_list_iter_next() or 554613051daSDaniel Vetter * drm_for_each_connector_iter(). 555613051daSDaniel Vetter */ 556b982dab1SThierry Reding void drm_connector_list_iter_begin(struct drm_device *dev, 557613051daSDaniel Vetter struct drm_connector_list_iter *iter) 558613051daSDaniel Vetter { 559613051daSDaniel Vetter iter->dev = dev; 560613051daSDaniel Vetter iter->conn = NULL; 561613051daSDaniel Vetter lock_acquire_shared_recursive(&connector_list_iter_dep_map, 0, 1, NULL, _RET_IP_); 562613051daSDaniel Vetter } 563b982dab1SThierry Reding EXPORT_SYMBOL(drm_connector_list_iter_begin); 564613051daSDaniel Vetter 565a703c550SDaniel Vetter /* 566a703c550SDaniel Vetter * Extra-safe connector put function that works in any context. Should only be 567a703c550SDaniel Vetter * used from the connector_iter functions, where we never really expect to 568a703c550SDaniel Vetter * actually release the connector when dropping our final reference. 569a703c550SDaniel Vetter */ 570a703c550SDaniel Vetter static void 571ea497bb9SDaniel Vetter __drm_connector_put_safe(struct drm_connector *conn) 572a703c550SDaniel Vetter { 573ea497bb9SDaniel Vetter struct drm_mode_config *config = &conn->dev->mode_config; 574ea497bb9SDaniel Vetter 575ea497bb9SDaniel Vetter lockdep_assert_held(&config->connector_list_lock); 576ea497bb9SDaniel Vetter 577ea497bb9SDaniel Vetter if (!refcount_dec_and_test(&conn->base.refcount.refcount)) 578ea497bb9SDaniel Vetter return; 579ea497bb9SDaniel Vetter 580ea497bb9SDaniel Vetter llist_add(&conn->free_node, &config->connector_free_list); 581ea497bb9SDaniel Vetter schedule_work(&config->connector_free_work); 582a703c550SDaniel Vetter } 583a703c550SDaniel Vetter 584613051daSDaniel Vetter /** 585613051daSDaniel Vetter * drm_connector_list_iter_next - return next connector 586613051daSDaniel Vetter * @iter: connectr_list iterator 587613051daSDaniel Vetter * 588613051daSDaniel Vetter * Returns the next connector for @iter, or NULL when the list walk has 589613051daSDaniel Vetter * completed. 590613051daSDaniel Vetter */ 591613051daSDaniel Vetter struct drm_connector * 592613051daSDaniel Vetter drm_connector_list_iter_next(struct drm_connector_list_iter *iter) 593613051daSDaniel Vetter { 594613051daSDaniel Vetter struct drm_connector *old_conn = iter->conn; 595613051daSDaniel Vetter struct drm_mode_config *config = &iter->dev->mode_config; 596613051daSDaniel Vetter struct list_head *lhead; 597613051daSDaniel Vetter unsigned long flags; 598613051daSDaniel Vetter 599613051daSDaniel Vetter spin_lock_irqsave(&config->connector_list_lock, flags); 600613051daSDaniel Vetter lhead = old_conn ? &old_conn->head : &config->connector_list; 601613051daSDaniel Vetter 602613051daSDaniel Vetter do { 603613051daSDaniel Vetter if (lhead->next == &config->connector_list) { 604613051daSDaniel Vetter iter->conn = NULL; 605613051daSDaniel Vetter break; 606613051daSDaniel Vetter } 607613051daSDaniel Vetter 608613051daSDaniel Vetter lhead = lhead->next; 609613051daSDaniel Vetter iter->conn = list_entry(lhead, struct drm_connector, head); 610613051daSDaniel Vetter 611613051daSDaniel Vetter /* loop until it's not a zombie connector */ 612613051daSDaniel Vetter } while (!kref_get_unless_zero(&iter->conn->base.refcount)); 613613051daSDaniel Vetter 614613051daSDaniel Vetter if (old_conn) 615ea497bb9SDaniel Vetter __drm_connector_put_safe(old_conn); 616ea497bb9SDaniel Vetter spin_unlock_irqrestore(&config->connector_list_lock, flags); 617613051daSDaniel Vetter 618613051daSDaniel Vetter return iter->conn; 619613051daSDaniel Vetter } 620613051daSDaniel Vetter EXPORT_SYMBOL(drm_connector_list_iter_next); 621613051daSDaniel Vetter 622613051daSDaniel Vetter /** 623b982dab1SThierry Reding * drm_connector_list_iter_end - tear down a connector_list iterator 624613051daSDaniel Vetter * @iter: connector_list iterator 625613051daSDaniel Vetter * 626613051daSDaniel Vetter * Tears down @iter and releases any resources (like &drm_connector references) 627613051daSDaniel Vetter * acquired while walking the list. This must always be called, both when the 628613051daSDaniel Vetter * iteration completes fully or when it was aborted without walking the entire 629613051daSDaniel Vetter * list. 630613051daSDaniel Vetter */ 631b982dab1SThierry Reding void drm_connector_list_iter_end(struct drm_connector_list_iter *iter) 632613051daSDaniel Vetter { 633ea497bb9SDaniel Vetter struct drm_mode_config *config = &iter->dev->mode_config; 634ea497bb9SDaniel Vetter unsigned long flags; 635ea497bb9SDaniel Vetter 636613051daSDaniel Vetter iter->dev = NULL; 637ea497bb9SDaniel Vetter if (iter->conn) { 638ea497bb9SDaniel Vetter spin_lock_irqsave(&config->connector_list_lock, flags); 639ea497bb9SDaniel Vetter __drm_connector_put_safe(iter->conn); 640ea497bb9SDaniel Vetter spin_unlock_irqrestore(&config->connector_list_lock, flags); 641ea497bb9SDaniel Vetter } 642613051daSDaniel Vetter lock_release(&connector_list_iter_dep_map, 0, _RET_IP_); 643613051daSDaniel Vetter } 644b982dab1SThierry Reding EXPORT_SYMBOL(drm_connector_list_iter_end); 645613051daSDaniel Vetter 64652217195SDaniel Vetter static const struct drm_prop_enum_list drm_subpixel_enum_list[] = { 64752217195SDaniel Vetter { SubPixelUnknown, "Unknown" }, 64852217195SDaniel Vetter { SubPixelHorizontalRGB, "Horizontal RGB" }, 64952217195SDaniel Vetter { SubPixelHorizontalBGR, "Horizontal BGR" }, 65052217195SDaniel Vetter { SubPixelVerticalRGB, "Vertical RGB" }, 65152217195SDaniel Vetter { SubPixelVerticalBGR, "Vertical BGR" }, 65252217195SDaniel Vetter { SubPixelNone, "None" }, 65352217195SDaniel Vetter }; 65452217195SDaniel Vetter 65552217195SDaniel Vetter /** 65652217195SDaniel Vetter * drm_get_subpixel_order_name - return a string for a given subpixel enum 65752217195SDaniel Vetter * @order: enum of subpixel_order 65852217195SDaniel Vetter * 65952217195SDaniel Vetter * Note you could abuse this and return something out of bounds, but that 66052217195SDaniel Vetter * would be a caller error. No unscrubbed user data should make it here. 66152217195SDaniel Vetter */ 66252217195SDaniel Vetter const char *drm_get_subpixel_order_name(enum subpixel_order order) 66352217195SDaniel Vetter { 66452217195SDaniel Vetter return drm_subpixel_enum_list[order].name; 66552217195SDaniel Vetter } 66652217195SDaniel Vetter EXPORT_SYMBOL(drm_get_subpixel_order_name); 66752217195SDaniel Vetter 66852217195SDaniel Vetter static const struct drm_prop_enum_list drm_dpms_enum_list[] = { 66952217195SDaniel Vetter { DRM_MODE_DPMS_ON, "On" }, 67052217195SDaniel Vetter { DRM_MODE_DPMS_STANDBY, "Standby" }, 67152217195SDaniel Vetter { DRM_MODE_DPMS_SUSPEND, "Suspend" }, 67252217195SDaniel Vetter { DRM_MODE_DPMS_OFF, "Off" } 67352217195SDaniel Vetter }; 67452217195SDaniel Vetter DRM_ENUM_NAME_FN(drm_get_dpms_name, drm_dpms_enum_list) 67552217195SDaniel Vetter 67640ee6fbeSManasi Navare static const struct drm_prop_enum_list drm_link_status_enum_list[] = { 67740ee6fbeSManasi Navare { DRM_MODE_LINK_STATUS_GOOD, "Good" }, 67840ee6fbeSManasi Navare { DRM_MODE_LINK_STATUS_BAD, "Bad" }, 67940ee6fbeSManasi Navare }; 68040ee6fbeSManasi Navare 681b3c6c8bfSDaniel Vetter /** 682b3c6c8bfSDaniel Vetter * drm_display_info_set_bus_formats - set the supported bus formats 683b3c6c8bfSDaniel Vetter * @info: display info to store bus formats in 684b3c6c8bfSDaniel Vetter * @formats: array containing the supported bus formats 685b3c6c8bfSDaniel Vetter * @num_formats: the number of entries in the fmts array 686b3c6c8bfSDaniel Vetter * 687b3c6c8bfSDaniel Vetter * Store the supported bus formats in display info structure. 688b3c6c8bfSDaniel Vetter * See MEDIA_BUS_FMT_* definitions in include/uapi/linux/media-bus-format.h for 689b3c6c8bfSDaniel Vetter * a full list of available formats. 690b3c6c8bfSDaniel Vetter */ 691b3c6c8bfSDaniel Vetter int drm_display_info_set_bus_formats(struct drm_display_info *info, 692b3c6c8bfSDaniel Vetter const u32 *formats, 693b3c6c8bfSDaniel Vetter unsigned int num_formats) 694b3c6c8bfSDaniel Vetter { 695b3c6c8bfSDaniel Vetter u32 *fmts = NULL; 696b3c6c8bfSDaniel Vetter 697b3c6c8bfSDaniel Vetter if (!formats && num_formats) 698b3c6c8bfSDaniel Vetter return -EINVAL; 699b3c6c8bfSDaniel Vetter 700b3c6c8bfSDaniel Vetter if (formats && num_formats) { 701b3c6c8bfSDaniel Vetter fmts = kmemdup(formats, sizeof(*formats) * num_formats, 702b3c6c8bfSDaniel Vetter GFP_KERNEL); 703b3c6c8bfSDaniel Vetter if (!fmts) 704b3c6c8bfSDaniel Vetter return -ENOMEM; 705b3c6c8bfSDaniel Vetter } 706b3c6c8bfSDaniel Vetter 707b3c6c8bfSDaniel Vetter kfree(info->bus_formats); 708b3c6c8bfSDaniel Vetter info->bus_formats = fmts; 709b3c6c8bfSDaniel Vetter info->num_bus_formats = num_formats; 710b3c6c8bfSDaniel Vetter 711b3c6c8bfSDaniel Vetter return 0; 712b3c6c8bfSDaniel Vetter } 713b3c6c8bfSDaniel Vetter EXPORT_SYMBOL(drm_display_info_set_bus_formats); 714b3c6c8bfSDaniel Vetter 71552217195SDaniel Vetter /* Optional connector properties. */ 71652217195SDaniel Vetter static const struct drm_prop_enum_list drm_scaling_mode_enum_list[] = { 71752217195SDaniel Vetter { DRM_MODE_SCALE_NONE, "None" }, 71852217195SDaniel Vetter { DRM_MODE_SCALE_FULLSCREEN, "Full" }, 71952217195SDaniel Vetter { DRM_MODE_SCALE_CENTER, "Center" }, 72052217195SDaniel Vetter { DRM_MODE_SCALE_ASPECT, "Full aspect" }, 72152217195SDaniel Vetter }; 72252217195SDaniel Vetter 72352217195SDaniel Vetter static const struct drm_prop_enum_list drm_aspect_ratio_enum_list[] = { 72452217195SDaniel Vetter { DRM_MODE_PICTURE_ASPECT_NONE, "Automatic" }, 72552217195SDaniel Vetter { DRM_MODE_PICTURE_ASPECT_4_3, "4:3" }, 72652217195SDaniel Vetter { DRM_MODE_PICTURE_ASPECT_16_9, "16:9" }, 72752217195SDaniel Vetter }; 72852217195SDaniel Vetter 72950525c33SStanislav Lisovskiy static const struct drm_prop_enum_list drm_content_type_enum_list[] = { 73050525c33SStanislav Lisovskiy { DRM_MODE_CONTENT_TYPE_NO_DATA, "No Data" }, 73150525c33SStanislav Lisovskiy { DRM_MODE_CONTENT_TYPE_GRAPHICS, "Graphics" }, 73250525c33SStanislav Lisovskiy { DRM_MODE_CONTENT_TYPE_PHOTO, "Photo" }, 73350525c33SStanislav Lisovskiy { DRM_MODE_CONTENT_TYPE_CINEMA, "Cinema" }, 73450525c33SStanislav Lisovskiy { DRM_MODE_CONTENT_TYPE_GAME, "Game" }, 73550525c33SStanislav Lisovskiy }; 73650525c33SStanislav Lisovskiy 7378d70f395SHans de Goede static const struct drm_prop_enum_list drm_panel_orientation_enum_list[] = { 7388d70f395SHans de Goede { DRM_MODE_PANEL_ORIENTATION_NORMAL, "Normal" }, 7398d70f395SHans de Goede { DRM_MODE_PANEL_ORIENTATION_BOTTOM_UP, "Upside Down" }, 7408d70f395SHans de Goede { DRM_MODE_PANEL_ORIENTATION_LEFT_UP, "Left Side Up" }, 7418d70f395SHans de Goede { DRM_MODE_PANEL_ORIENTATION_RIGHT_UP, "Right Side Up" }, 7428d70f395SHans de Goede }; 7438d70f395SHans de Goede 74452217195SDaniel Vetter static const struct drm_prop_enum_list drm_dvi_i_select_enum_list[] = { 74552217195SDaniel Vetter { DRM_MODE_SUBCONNECTOR_Automatic, "Automatic" }, /* DVI-I and TV-out */ 74652217195SDaniel Vetter { DRM_MODE_SUBCONNECTOR_DVID, "DVI-D" }, /* DVI-I */ 74752217195SDaniel Vetter { DRM_MODE_SUBCONNECTOR_DVIA, "DVI-A" }, /* DVI-I */ 74852217195SDaniel Vetter }; 74952217195SDaniel Vetter DRM_ENUM_NAME_FN(drm_get_dvi_i_select_name, drm_dvi_i_select_enum_list) 75052217195SDaniel Vetter 75152217195SDaniel Vetter static const struct drm_prop_enum_list drm_dvi_i_subconnector_enum_list[] = { 75252217195SDaniel Vetter { DRM_MODE_SUBCONNECTOR_Unknown, "Unknown" }, /* DVI-I and TV-out */ 75352217195SDaniel Vetter { DRM_MODE_SUBCONNECTOR_DVID, "DVI-D" }, /* DVI-I */ 75452217195SDaniel Vetter { DRM_MODE_SUBCONNECTOR_DVIA, "DVI-A" }, /* DVI-I */ 75552217195SDaniel Vetter }; 75652217195SDaniel Vetter DRM_ENUM_NAME_FN(drm_get_dvi_i_subconnector_name, 75752217195SDaniel Vetter drm_dvi_i_subconnector_enum_list) 75852217195SDaniel Vetter 75952217195SDaniel Vetter static const struct drm_prop_enum_list drm_tv_select_enum_list[] = { 76052217195SDaniel Vetter { DRM_MODE_SUBCONNECTOR_Automatic, "Automatic" }, /* DVI-I and TV-out */ 76152217195SDaniel Vetter { DRM_MODE_SUBCONNECTOR_Composite, "Composite" }, /* TV-out */ 76252217195SDaniel Vetter { DRM_MODE_SUBCONNECTOR_SVIDEO, "SVIDEO" }, /* TV-out */ 76352217195SDaniel Vetter { DRM_MODE_SUBCONNECTOR_Component, "Component" }, /* TV-out */ 76452217195SDaniel Vetter { DRM_MODE_SUBCONNECTOR_SCART, "SCART" }, /* TV-out */ 76552217195SDaniel Vetter }; 76652217195SDaniel Vetter DRM_ENUM_NAME_FN(drm_get_tv_select_name, drm_tv_select_enum_list) 76752217195SDaniel Vetter 76852217195SDaniel Vetter static const struct drm_prop_enum_list drm_tv_subconnector_enum_list[] = { 76952217195SDaniel Vetter { DRM_MODE_SUBCONNECTOR_Unknown, "Unknown" }, /* DVI-I and TV-out */ 77052217195SDaniel Vetter { DRM_MODE_SUBCONNECTOR_Composite, "Composite" }, /* TV-out */ 77152217195SDaniel Vetter { DRM_MODE_SUBCONNECTOR_SVIDEO, "SVIDEO" }, /* TV-out */ 77252217195SDaniel Vetter { DRM_MODE_SUBCONNECTOR_Component, "Component" }, /* TV-out */ 77352217195SDaniel Vetter { DRM_MODE_SUBCONNECTOR_SCART, "SCART" }, /* TV-out */ 77452217195SDaniel Vetter }; 77552217195SDaniel Vetter DRM_ENUM_NAME_FN(drm_get_tv_subconnector_name, 77652217195SDaniel Vetter drm_tv_subconnector_enum_list) 77752217195SDaniel Vetter 77824557865SSean Paul static struct drm_prop_enum_list drm_cp_enum_list[] = { 77924557865SSean Paul { DRM_MODE_CONTENT_PROTECTION_UNDESIRED, "Undesired" }, 78024557865SSean Paul { DRM_MODE_CONTENT_PROTECTION_DESIRED, "Desired" }, 78124557865SSean Paul { DRM_MODE_CONTENT_PROTECTION_ENABLED, "Enabled" }, 78224557865SSean Paul }; 78324557865SSean Paul DRM_ENUM_NAME_FN(drm_get_content_protection_name, drm_cp_enum_list) 78424557865SSean Paul 7854ada6f22SDaniel Vetter /** 7864ada6f22SDaniel Vetter * DOC: standard connector properties 7874ada6f22SDaniel Vetter * 7884ada6f22SDaniel Vetter * DRM connectors have a few standardized properties: 7894ada6f22SDaniel Vetter * 7904ada6f22SDaniel Vetter * EDID: 7914ada6f22SDaniel Vetter * Blob property which contains the current EDID read from the sink. This 7924ada6f22SDaniel Vetter * is useful to parse sink identification information like vendor, model 7934ada6f22SDaniel Vetter * and serial. Drivers should update this property by calling 7944ada6f22SDaniel Vetter * drm_mode_connector_update_edid_property(), usually after having parsed 7954ada6f22SDaniel Vetter * the EDID using drm_add_edid_modes(). Userspace cannot change this 7964ada6f22SDaniel Vetter * property. 7974ada6f22SDaniel Vetter * DPMS: 7984ada6f22SDaniel Vetter * Legacy property for setting the power state of the connector. For atomic 7994ada6f22SDaniel Vetter * drivers this is only provided for backwards compatibility with existing 8004ada6f22SDaniel Vetter * drivers, it remaps to controlling the "ACTIVE" property on the CRTC the 8014ada6f22SDaniel Vetter * connector is linked to. Drivers should never set this property directly, 802d574528aSDaniel Vetter * it is handled by the DRM core by calling the &drm_connector_funcs.dpms 803144a7999SDaniel Vetter * callback. For atomic drivers the remapping to the "ACTIVE" property is 804144a7999SDaniel Vetter * implemented in the DRM core. This is the only standard connector 805144a7999SDaniel Vetter * property that userspace can change. 806d0d1aee5SDaniel Vetter * 807d0d1aee5SDaniel Vetter * Note that this property cannot be set through the MODE_ATOMIC ioctl, 808d0d1aee5SDaniel Vetter * userspace must use "ACTIVE" on the CRTC instead. 809d0d1aee5SDaniel Vetter * 810d0d1aee5SDaniel Vetter * WARNING: 811d0d1aee5SDaniel Vetter * 812d0d1aee5SDaniel Vetter * For userspace also running on legacy drivers the "DPMS" semantics are a 813d0d1aee5SDaniel Vetter * lot more complicated. First, userspace cannot rely on the "DPMS" value 814d0d1aee5SDaniel Vetter * returned by the GETCONNECTOR actually reflecting reality, because many 815d0d1aee5SDaniel Vetter * drivers fail to update it. For atomic drivers this is taken care of in 816d0d1aee5SDaniel Vetter * drm_atomic_helper_update_legacy_modeset_state(). 817d0d1aee5SDaniel Vetter * 818d0d1aee5SDaniel Vetter * The second issue is that the DPMS state is only well-defined when the 819d0d1aee5SDaniel Vetter * connector is connected to a CRTC. In atomic the DRM core enforces that 820d0d1aee5SDaniel Vetter * "ACTIVE" is off in such a case, no such checks exists for "DPMS". 821d0d1aee5SDaniel Vetter * 822d0d1aee5SDaniel Vetter * Finally, when enabling an output using the legacy SETCONFIG ioctl then 823d0d1aee5SDaniel Vetter * "DPMS" is forced to ON. But see above, that might not be reflected in 824d0d1aee5SDaniel Vetter * the software value on legacy drivers. 825d0d1aee5SDaniel Vetter * 826d0d1aee5SDaniel Vetter * Summarizing: Only set "DPMS" when the connector is known to be enabled, 827d0d1aee5SDaniel Vetter * assume that a successful SETCONFIG call also sets "DPMS" to on, and 828d0d1aee5SDaniel Vetter * never read back the value of "DPMS" because it can be incorrect. 8294ada6f22SDaniel Vetter * PATH: 8304ada6f22SDaniel Vetter * Connector path property to identify how this sink is physically 8314ada6f22SDaniel Vetter * connected. Used by DP MST. This should be set by calling 8324ada6f22SDaniel Vetter * drm_mode_connector_set_path_property(), in the case of DP MST with the 8334ada6f22SDaniel Vetter * path property the MST manager created. Userspace cannot change this 8344ada6f22SDaniel Vetter * property. 8354ada6f22SDaniel Vetter * TILE: 8364ada6f22SDaniel Vetter * Connector tile group property to indicate how a set of DRM connector 8374ada6f22SDaniel Vetter * compose together into one logical screen. This is used by both high-res 8384ada6f22SDaniel Vetter * external screens (often only using a single cable, but exposing multiple 8394ada6f22SDaniel Vetter * DP MST sinks), or high-res integrated panels (like dual-link DSI) which 8404ada6f22SDaniel Vetter * are not gen-locked. Note that for tiled panels which are genlocked, like 8414ada6f22SDaniel Vetter * dual-link LVDS or dual-link DSI, the driver should try to not expose the 8424ada6f22SDaniel Vetter * tiling and virtualize both &drm_crtc and &drm_plane if needed. Drivers 8434ada6f22SDaniel Vetter * should update this value using drm_mode_connector_set_tile_property(). 8444ada6f22SDaniel Vetter * Userspace cannot change this property. 84540ee6fbeSManasi Navare * link-status: 846716719a3SSean Paul * Connector link-status property to indicate the status of link. The 847716719a3SSean Paul * default value of link-status is "GOOD". If something fails during or 848716719a3SSean Paul * after modeset, the kernel driver may set this to "BAD" and issue a 849716719a3SSean Paul * hotplug uevent. Drivers should update this value using 850716719a3SSean Paul * drm_mode_connector_set_link_status_property(). 85166660d4cSDave Airlie * non_desktop: 85266660d4cSDave Airlie * Indicates the output should be ignored for purposes of displaying a 85366660d4cSDave Airlie * standard desktop environment or console. This is most likely because 85466660d4cSDave Airlie * the output device is not rectilinear. 85524557865SSean Paul * Content Protection: 85624557865SSean Paul * This property is used by userspace to request the kernel protect future 85724557865SSean Paul * content communicated over the link. When requested, kernel will apply 85824557865SSean Paul * the appropriate means of protection (most often HDCP), and use the 85924557865SSean Paul * property to tell userspace the protection is active. 86024557865SSean Paul * 86124557865SSean Paul * Drivers can set this up by calling 86224557865SSean Paul * drm_connector_attach_content_protection_property() on initialization. 86324557865SSean Paul * 86424557865SSean Paul * The value of this property can be one of the following: 86524557865SSean Paul * 866bbeba09fSDaniel Vetter * DRM_MODE_CONTENT_PROTECTION_UNDESIRED = 0 86724557865SSean Paul * The link is not protected, content is transmitted in the clear. 868bbeba09fSDaniel Vetter * DRM_MODE_CONTENT_PROTECTION_DESIRED = 1 86924557865SSean Paul * Userspace has requested content protection, but the link is not 87024557865SSean Paul * currently protected. When in this state, kernel should enable 87124557865SSean Paul * Content Protection as soon as possible. 872bbeba09fSDaniel Vetter * DRM_MODE_CONTENT_PROTECTION_ENABLED = 2 87324557865SSean Paul * Userspace has requested content protection, and the link is 87424557865SSean Paul * protected. Only the driver can set the property to this value. 87524557865SSean Paul * If userspace attempts to set to ENABLED, kernel will return 87624557865SSean Paul * -EINVAL. 87724557865SSean Paul * 87824557865SSean Paul * A few guidelines: 87924557865SSean Paul * 88024557865SSean Paul * - DESIRED state should be preserved until userspace de-asserts it by 88124557865SSean Paul * setting the property to UNDESIRED. This means ENABLED should only 88224557865SSean Paul * transition to UNDESIRED when the user explicitly requests it. 88324557865SSean Paul * - If the state is DESIRED, kernel should attempt to re-authenticate the 88424557865SSean Paul * link whenever possible. This includes across disable/enable, dpms, 88524557865SSean Paul * hotplug, downstream device changes, link status failures, etc.. 88624557865SSean Paul * - Userspace is responsible for polling the property to determine when 88724557865SSean Paul * the value transitions from ENABLED to DESIRED. This signifies the link 88824557865SSean Paul * is no longer protected and userspace should take appropriate action 88924557865SSean Paul * (whatever that might be). 8904ada6f22SDaniel Vetter * 8914ada6f22SDaniel Vetter * Connectors also have one standardized atomic property: 8924ada6f22SDaniel Vetter * 8934ada6f22SDaniel Vetter * CRTC_ID: 8944ada6f22SDaniel Vetter * Mode object ID of the &drm_crtc this connector should be connected to. 8958d70f395SHans de Goede * 8968d70f395SHans de Goede * Connectors for LCD panels may also have one standardized property: 8978d70f395SHans de Goede * 8988d70f395SHans de Goede * panel orientation: 8998d70f395SHans de Goede * On some devices the LCD panel is mounted in the casing in such a way 9008d70f395SHans de Goede * that the up/top side of the panel does not match with the top side of 9018d70f395SHans de Goede * the device. Userspace can use this property to check for this. 9028d70f395SHans de Goede * Note that input coordinates from touchscreens (input devices with 9038d70f395SHans de Goede * INPUT_PROP_DIRECT) will still map 1:1 to the actual LCD panel 9048d70f395SHans de Goede * coordinates, so if userspace rotates the picture to adjust for 9058d70f395SHans de Goede * the orientation it must also apply the same transformation to the 906bbeba09fSDaniel Vetter * touchscreen input coordinates. This property is initialized by calling 907bbeba09fSDaniel Vetter * drm_connector_init_panel_orientation_property(). 908bbeba09fSDaniel Vetter * 909bbeba09fSDaniel Vetter * scaling mode: 910bbeba09fSDaniel Vetter * This property defines how a non-native mode is upscaled to the native 911bbeba09fSDaniel Vetter * mode of an LCD panel: 912bbeba09fSDaniel Vetter * 913bbeba09fSDaniel Vetter * None: 914bbeba09fSDaniel Vetter * No upscaling happens, scaling is left to the panel. Not all 915bbeba09fSDaniel Vetter * drivers expose this mode. 916bbeba09fSDaniel Vetter * Full: 917bbeba09fSDaniel Vetter * The output is upscaled to the full resolution of the panel, 918bbeba09fSDaniel Vetter * ignoring the aspect ratio. 919bbeba09fSDaniel Vetter * Center: 920bbeba09fSDaniel Vetter * No upscaling happens, the output is centered within the native 921bbeba09fSDaniel Vetter * resolution the panel. 922bbeba09fSDaniel Vetter * Full aspect: 923bbeba09fSDaniel Vetter * The output is upscaled to maximize either the width or height 924bbeba09fSDaniel Vetter * while retaining the aspect ratio. 925bbeba09fSDaniel Vetter * 926bbeba09fSDaniel Vetter * This property should be set up by calling 927bbeba09fSDaniel Vetter * drm_connector_attach_scaling_mode_property(). Note that drivers 928bbeba09fSDaniel Vetter * can also expose this property to external outputs, in which case they 929bbeba09fSDaniel Vetter * must support "None", which should be the default (since external screens 930bbeba09fSDaniel Vetter * have a built-in scaler). 9314ada6f22SDaniel Vetter */ 9324ada6f22SDaniel Vetter 93352217195SDaniel Vetter int drm_connector_create_standard_properties(struct drm_device *dev) 93452217195SDaniel Vetter { 93552217195SDaniel Vetter struct drm_property *prop; 93652217195SDaniel Vetter 93752217195SDaniel Vetter prop = drm_property_create(dev, DRM_MODE_PROP_BLOB | 93852217195SDaniel Vetter DRM_MODE_PROP_IMMUTABLE, 93952217195SDaniel Vetter "EDID", 0); 94052217195SDaniel Vetter if (!prop) 94152217195SDaniel Vetter return -ENOMEM; 94252217195SDaniel Vetter dev->mode_config.edid_property = prop; 94352217195SDaniel Vetter 94452217195SDaniel Vetter prop = drm_property_create_enum(dev, 0, 94552217195SDaniel Vetter "DPMS", drm_dpms_enum_list, 94652217195SDaniel Vetter ARRAY_SIZE(drm_dpms_enum_list)); 94752217195SDaniel Vetter if (!prop) 94852217195SDaniel Vetter return -ENOMEM; 94952217195SDaniel Vetter dev->mode_config.dpms_property = prop; 95052217195SDaniel Vetter 95152217195SDaniel Vetter prop = drm_property_create(dev, 95252217195SDaniel Vetter DRM_MODE_PROP_BLOB | 95352217195SDaniel Vetter DRM_MODE_PROP_IMMUTABLE, 95452217195SDaniel Vetter "PATH", 0); 95552217195SDaniel Vetter if (!prop) 95652217195SDaniel Vetter return -ENOMEM; 95752217195SDaniel Vetter dev->mode_config.path_property = prop; 95852217195SDaniel Vetter 95952217195SDaniel Vetter prop = drm_property_create(dev, 96052217195SDaniel Vetter DRM_MODE_PROP_BLOB | 96152217195SDaniel Vetter DRM_MODE_PROP_IMMUTABLE, 96252217195SDaniel Vetter "TILE", 0); 96352217195SDaniel Vetter if (!prop) 96452217195SDaniel Vetter return -ENOMEM; 96552217195SDaniel Vetter dev->mode_config.tile_property = prop; 96652217195SDaniel Vetter 96740ee6fbeSManasi Navare prop = drm_property_create_enum(dev, 0, "link-status", 96840ee6fbeSManasi Navare drm_link_status_enum_list, 96940ee6fbeSManasi Navare ARRAY_SIZE(drm_link_status_enum_list)); 97040ee6fbeSManasi Navare if (!prop) 97140ee6fbeSManasi Navare return -ENOMEM; 97240ee6fbeSManasi Navare dev->mode_config.link_status_property = prop; 97340ee6fbeSManasi Navare 97466660d4cSDave Airlie prop = drm_property_create_bool(dev, DRM_MODE_PROP_IMMUTABLE, "non-desktop"); 97566660d4cSDave Airlie if (!prop) 97666660d4cSDave Airlie return -ENOMEM; 97766660d4cSDave Airlie dev->mode_config.non_desktop_property = prop; 97866660d4cSDave Airlie 97952217195SDaniel Vetter return 0; 98052217195SDaniel Vetter } 98152217195SDaniel Vetter 98252217195SDaniel Vetter /** 98352217195SDaniel Vetter * drm_mode_create_dvi_i_properties - create DVI-I specific connector properties 98452217195SDaniel Vetter * @dev: DRM device 98552217195SDaniel Vetter * 98652217195SDaniel Vetter * Called by a driver the first time a DVI-I connector is made. 98752217195SDaniel Vetter */ 98852217195SDaniel Vetter int drm_mode_create_dvi_i_properties(struct drm_device *dev) 98952217195SDaniel Vetter { 99052217195SDaniel Vetter struct drm_property *dvi_i_selector; 99152217195SDaniel Vetter struct drm_property *dvi_i_subconnector; 99252217195SDaniel Vetter 99352217195SDaniel Vetter if (dev->mode_config.dvi_i_select_subconnector_property) 99452217195SDaniel Vetter return 0; 99552217195SDaniel Vetter 99652217195SDaniel Vetter dvi_i_selector = 99752217195SDaniel Vetter drm_property_create_enum(dev, 0, 99852217195SDaniel Vetter "select subconnector", 99952217195SDaniel Vetter drm_dvi_i_select_enum_list, 100052217195SDaniel Vetter ARRAY_SIZE(drm_dvi_i_select_enum_list)); 100152217195SDaniel Vetter dev->mode_config.dvi_i_select_subconnector_property = dvi_i_selector; 100252217195SDaniel Vetter 100352217195SDaniel Vetter dvi_i_subconnector = drm_property_create_enum(dev, DRM_MODE_PROP_IMMUTABLE, 100452217195SDaniel Vetter "subconnector", 100552217195SDaniel Vetter drm_dvi_i_subconnector_enum_list, 100652217195SDaniel Vetter ARRAY_SIZE(drm_dvi_i_subconnector_enum_list)); 100752217195SDaniel Vetter dev->mode_config.dvi_i_subconnector_property = dvi_i_subconnector; 100852217195SDaniel Vetter 100952217195SDaniel Vetter return 0; 101052217195SDaniel Vetter } 101152217195SDaniel Vetter EXPORT_SYMBOL(drm_mode_create_dvi_i_properties); 101252217195SDaniel Vetter 101352217195SDaniel Vetter /** 101450525c33SStanislav Lisovskiy * DOC: HDMI connector properties 101550525c33SStanislav Lisovskiy * 101650525c33SStanislav Lisovskiy * content type (HDMI specific): 101750525c33SStanislav Lisovskiy * Indicates content type setting to be used in HDMI infoframes to indicate 101850525c33SStanislav Lisovskiy * content type for the external device, so that it adjusts it's display 101950525c33SStanislav Lisovskiy * settings accordingly. 102050525c33SStanislav Lisovskiy * 102150525c33SStanislav Lisovskiy * The value of this property can be one of the following: 102250525c33SStanislav Lisovskiy * 102350525c33SStanislav Lisovskiy * No Data: 102450525c33SStanislav Lisovskiy * Content type is unknown 102550525c33SStanislav Lisovskiy * Graphics: 102650525c33SStanislav Lisovskiy * Content type is graphics 102750525c33SStanislav Lisovskiy * Photo: 102850525c33SStanislav Lisovskiy * Content type is photo 102950525c33SStanislav Lisovskiy * Cinema: 103050525c33SStanislav Lisovskiy * Content type is cinema 103150525c33SStanislav Lisovskiy * Game: 103250525c33SStanislav Lisovskiy * Content type is game 103350525c33SStanislav Lisovskiy * 103450525c33SStanislav Lisovskiy * Drivers can set up this property by calling 103550525c33SStanislav Lisovskiy * drm_connector_attach_content_type_property(). Decoding to 1036*ba609631SDaniel Vetter * infoframe values is done through drm_hdmi_avi_infoframe_content_type(). 103750525c33SStanislav Lisovskiy */ 103850525c33SStanislav Lisovskiy 103950525c33SStanislav Lisovskiy /** 104050525c33SStanislav Lisovskiy * drm_connector_attach_content_type_property - attach content-type property 104150525c33SStanislav Lisovskiy * @connector: connector to attach content type property on. 104250525c33SStanislav Lisovskiy * 104350525c33SStanislav Lisovskiy * Called by a driver the first time a HDMI connector is made. 104450525c33SStanislav Lisovskiy */ 104550525c33SStanislav Lisovskiy int drm_connector_attach_content_type_property(struct drm_connector *connector) 104650525c33SStanislav Lisovskiy { 104750525c33SStanislav Lisovskiy if (!drm_mode_create_content_type_property(connector->dev)) 104850525c33SStanislav Lisovskiy drm_object_attach_property(&connector->base, 104950525c33SStanislav Lisovskiy connector->dev->mode_config.content_type_property, 105050525c33SStanislav Lisovskiy DRM_MODE_CONTENT_TYPE_NO_DATA); 105150525c33SStanislav Lisovskiy return 0; 105250525c33SStanislav Lisovskiy } 105350525c33SStanislav Lisovskiy EXPORT_SYMBOL(drm_connector_attach_content_type_property); 105450525c33SStanislav Lisovskiy 105550525c33SStanislav Lisovskiy 105650525c33SStanislav Lisovskiy /** 105750525c33SStanislav Lisovskiy * drm_hdmi_avi_infoframe_content_type() - fill the HDMI AVI infoframe 105850525c33SStanislav Lisovskiy * content type information, based 105950525c33SStanislav Lisovskiy * on correspondent DRM property. 106050525c33SStanislav Lisovskiy * @frame: HDMI AVI infoframe 106150525c33SStanislav Lisovskiy * @conn_state: DRM display connector state 106250525c33SStanislav Lisovskiy * 106350525c33SStanislav Lisovskiy */ 106450525c33SStanislav Lisovskiy void drm_hdmi_avi_infoframe_content_type(struct hdmi_avi_infoframe *frame, 106550525c33SStanislav Lisovskiy const struct drm_connector_state *conn_state) 106650525c33SStanislav Lisovskiy { 106750525c33SStanislav Lisovskiy switch (conn_state->content_type) { 106850525c33SStanislav Lisovskiy case DRM_MODE_CONTENT_TYPE_GRAPHICS: 106950525c33SStanislav Lisovskiy frame->content_type = HDMI_CONTENT_TYPE_GRAPHICS; 107050525c33SStanislav Lisovskiy break; 107150525c33SStanislav Lisovskiy case DRM_MODE_CONTENT_TYPE_CINEMA: 107250525c33SStanislav Lisovskiy frame->content_type = HDMI_CONTENT_TYPE_CINEMA; 107350525c33SStanislav Lisovskiy break; 107450525c33SStanislav Lisovskiy case DRM_MODE_CONTENT_TYPE_GAME: 107550525c33SStanislav Lisovskiy frame->content_type = HDMI_CONTENT_TYPE_GAME; 107650525c33SStanislav Lisovskiy break; 107750525c33SStanislav Lisovskiy case DRM_MODE_CONTENT_TYPE_PHOTO: 107850525c33SStanislav Lisovskiy frame->content_type = HDMI_CONTENT_TYPE_PHOTO; 107950525c33SStanislav Lisovskiy break; 108050525c33SStanislav Lisovskiy default: 108150525c33SStanislav Lisovskiy /* Graphics is the default(0) */ 108250525c33SStanislav Lisovskiy frame->content_type = HDMI_CONTENT_TYPE_GRAPHICS; 108350525c33SStanislav Lisovskiy } 108450525c33SStanislav Lisovskiy 108550525c33SStanislav Lisovskiy frame->itc = conn_state->content_type != DRM_MODE_CONTENT_TYPE_NO_DATA; 108650525c33SStanislav Lisovskiy } 108750525c33SStanislav Lisovskiy EXPORT_SYMBOL(drm_hdmi_avi_infoframe_content_type); 108850525c33SStanislav Lisovskiy 108950525c33SStanislav Lisovskiy /** 109052217195SDaniel Vetter * drm_create_tv_properties - create TV specific connector properties 109152217195SDaniel Vetter * @dev: DRM device 109252217195SDaniel Vetter * @num_modes: number of different TV formats (modes) supported 109352217195SDaniel Vetter * @modes: array of pointers to strings containing name of each format 109452217195SDaniel Vetter * 109552217195SDaniel Vetter * Called by a driver's TV initialization routine, this function creates 109652217195SDaniel Vetter * the TV specific connector properties for a given device. Caller is 109752217195SDaniel Vetter * responsible for allocating a list of format names and passing them to 109852217195SDaniel Vetter * this routine. 109952217195SDaniel Vetter */ 110052217195SDaniel Vetter int drm_mode_create_tv_properties(struct drm_device *dev, 110152217195SDaniel Vetter unsigned int num_modes, 110252217195SDaniel Vetter const char * const modes[]) 110352217195SDaniel Vetter { 110452217195SDaniel Vetter struct drm_property *tv_selector; 110552217195SDaniel Vetter struct drm_property *tv_subconnector; 110652217195SDaniel Vetter unsigned int i; 110752217195SDaniel Vetter 110852217195SDaniel Vetter if (dev->mode_config.tv_select_subconnector_property) 110952217195SDaniel Vetter return 0; 111052217195SDaniel Vetter 111152217195SDaniel Vetter /* 111252217195SDaniel Vetter * Basic connector properties 111352217195SDaniel Vetter */ 111452217195SDaniel Vetter tv_selector = drm_property_create_enum(dev, 0, 111552217195SDaniel Vetter "select subconnector", 111652217195SDaniel Vetter drm_tv_select_enum_list, 111752217195SDaniel Vetter ARRAY_SIZE(drm_tv_select_enum_list)); 111852217195SDaniel Vetter if (!tv_selector) 111952217195SDaniel Vetter goto nomem; 112052217195SDaniel Vetter 112152217195SDaniel Vetter dev->mode_config.tv_select_subconnector_property = tv_selector; 112252217195SDaniel Vetter 112352217195SDaniel Vetter tv_subconnector = 112452217195SDaniel Vetter drm_property_create_enum(dev, DRM_MODE_PROP_IMMUTABLE, 112552217195SDaniel Vetter "subconnector", 112652217195SDaniel Vetter drm_tv_subconnector_enum_list, 112752217195SDaniel Vetter ARRAY_SIZE(drm_tv_subconnector_enum_list)); 112852217195SDaniel Vetter if (!tv_subconnector) 112952217195SDaniel Vetter goto nomem; 113052217195SDaniel Vetter dev->mode_config.tv_subconnector_property = tv_subconnector; 113152217195SDaniel Vetter 113252217195SDaniel Vetter /* 113352217195SDaniel Vetter * Other, TV specific properties: margins & TV modes. 113452217195SDaniel Vetter */ 113552217195SDaniel Vetter dev->mode_config.tv_left_margin_property = 113652217195SDaniel Vetter drm_property_create_range(dev, 0, "left margin", 0, 100); 113752217195SDaniel Vetter if (!dev->mode_config.tv_left_margin_property) 113852217195SDaniel Vetter goto nomem; 113952217195SDaniel Vetter 114052217195SDaniel Vetter dev->mode_config.tv_right_margin_property = 114152217195SDaniel Vetter drm_property_create_range(dev, 0, "right margin", 0, 100); 114252217195SDaniel Vetter if (!dev->mode_config.tv_right_margin_property) 114352217195SDaniel Vetter goto nomem; 114452217195SDaniel Vetter 114552217195SDaniel Vetter dev->mode_config.tv_top_margin_property = 114652217195SDaniel Vetter drm_property_create_range(dev, 0, "top margin", 0, 100); 114752217195SDaniel Vetter if (!dev->mode_config.tv_top_margin_property) 114852217195SDaniel Vetter goto nomem; 114952217195SDaniel Vetter 115052217195SDaniel Vetter dev->mode_config.tv_bottom_margin_property = 115152217195SDaniel Vetter drm_property_create_range(dev, 0, "bottom margin", 0, 100); 115252217195SDaniel Vetter if (!dev->mode_config.tv_bottom_margin_property) 115352217195SDaniel Vetter goto nomem; 115452217195SDaniel Vetter 115552217195SDaniel Vetter dev->mode_config.tv_mode_property = 115652217195SDaniel Vetter drm_property_create(dev, DRM_MODE_PROP_ENUM, 115752217195SDaniel Vetter "mode", num_modes); 115852217195SDaniel Vetter if (!dev->mode_config.tv_mode_property) 115952217195SDaniel Vetter goto nomem; 116052217195SDaniel Vetter 116152217195SDaniel Vetter for (i = 0; i < num_modes; i++) 116230e9db6dSVille Syrjälä drm_property_add_enum(dev->mode_config.tv_mode_property, 116352217195SDaniel Vetter i, modes[i]); 116452217195SDaniel Vetter 116552217195SDaniel Vetter dev->mode_config.tv_brightness_property = 116652217195SDaniel Vetter drm_property_create_range(dev, 0, "brightness", 0, 100); 116752217195SDaniel Vetter if (!dev->mode_config.tv_brightness_property) 116852217195SDaniel Vetter goto nomem; 116952217195SDaniel Vetter 117052217195SDaniel Vetter dev->mode_config.tv_contrast_property = 117152217195SDaniel Vetter drm_property_create_range(dev, 0, "contrast", 0, 100); 117252217195SDaniel Vetter if (!dev->mode_config.tv_contrast_property) 117352217195SDaniel Vetter goto nomem; 117452217195SDaniel Vetter 117552217195SDaniel Vetter dev->mode_config.tv_flicker_reduction_property = 117652217195SDaniel Vetter drm_property_create_range(dev, 0, "flicker reduction", 0, 100); 117752217195SDaniel Vetter if (!dev->mode_config.tv_flicker_reduction_property) 117852217195SDaniel Vetter goto nomem; 117952217195SDaniel Vetter 118052217195SDaniel Vetter dev->mode_config.tv_overscan_property = 118152217195SDaniel Vetter drm_property_create_range(dev, 0, "overscan", 0, 100); 118252217195SDaniel Vetter if (!dev->mode_config.tv_overscan_property) 118352217195SDaniel Vetter goto nomem; 118452217195SDaniel Vetter 118552217195SDaniel Vetter dev->mode_config.tv_saturation_property = 118652217195SDaniel Vetter drm_property_create_range(dev, 0, "saturation", 0, 100); 118752217195SDaniel Vetter if (!dev->mode_config.tv_saturation_property) 118852217195SDaniel Vetter goto nomem; 118952217195SDaniel Vetter 119052217195SDaniel Vetter dev->mode_config.tv_hue_property = 119152217195SDaniel Vetter drm_property_create_range(dev, 0, "hue", 0, 100); 119252217195SDaniel Vetter if (!dev->mode_config.tv_hue_property) 119352217195SDaniel Vetter goto nomem; 119452217195SDaniel Vetter 119552217195SDaniel Vetter return 0; 119652217195SDaniel Vetter nomem: 119752217195SDaniel Vetter return -ENOMEM; 119852217195SDaniel Vetter } 119952217195SDaniel Vetter EXPORT_SYMBOL(drm_mode_create_tv_properties); 120052217195SDaniel Vetter 120152217195SDaniel Vetter /** 120252217195SDaniel Vetter * drm_mode_create_scaling_mode_property - create scaling mode property 120352217195SDaniel Vetter * @dev: DRM device 120452217195SDaniel Vetter * 120552217195SDaniel Vetter * Called by a driver the first time it's needed, must be attached to desired 120652217195SDaniel Vetter * connectors. 12078f6e1e22SMaarten Lankhorst * 12088f6e1e22SMaarten Lankhorst * Atomic drivers should use drm_connector_attach_scaling_mode_property() 12098f6e1e22SMaarten Lankhorst * instead to correctly assign &drm_connector_state.picture_aspect_ratio 12108f6e1e22SMaarten Lankhorst * in the atomic state. 121152217195SDaniel Vetter */ 121252217195SDaniel Vetter int drm_mode_create_scaling_mode_property(struct drm_device *dev) 121352217195SDaniel Vetter { 121452217195SDaniel Vetter struct drm_property *scaling_mode; 121552217195SDaniel Vetter 121652217195SDaniel Vetter if (dev->mode_config.scaling_mode_property) 121752217195SDaniel Vetter return 0; 121852217195SDaniel Vetter 121952217195SDaniel Vetter scaling_mode = 122052217195SDaniel Vetter drm_property_create_enum(dev, 0, "scaling mode", 122152217195SDaniel Vetter drm_scaling_mode_enum_list, 122252217195SDaniel Vetter ARRAY_SIZE(drm_scaling_mode_enum_list)); 122352217195SDaniel Vetter 122452217195SDaniel Vetter dev->mode_config.scaling_mode_property = scaling_mode; 122552217195SDaniel Vetter 122652217195SDaniel Vetter return 0; 122752217195SDaniel Vetter } 122852217195SDaniel Vetter EXPORT_SYMBOL(drm_mode_create_scaling_mode_property); 122952217195SDaniel Vetter 123052217195SDaniel Vetter /** 12318f6e1e22SMaarten Lankhorst * drm_connector_attach_scaling_mode_property - attach atomic scaling mode property 12328f6e1e22SMaarten Lankhorst * @connector: connector to attach scaling mode property on. 12338f6e1e22SMaarten Lankhorst * @scaling_mode_mask: or'ed mask of BIT(%DRM_MODE_SCALE_\*). 12348f6e1e22SMaarten Lankhorst * 12358f6e1e22SMaarten Lankhorst * This is used to add support for scaling mode to atomic drivers. 12368f6e1e22SMaarten Lankhorst * The scaling mode will be set to &drm_connector_state.picture_aspect_ratio 12378f6e1e22SMaarten Lankhorst * and can be used from &drm_connector_helper_funcs->atomic_check for validation. 12388f6e1e22SMaarten Lankhorst * 12398f6e1e22SMaarten Lankhorst * This is the atomic version of drm_mode_create_scaling_mode_property(). 12408f6e1e22SMaarten Lankhorst * 12418f6e1e22SMaarten Lankhorst * Returns: 12428f6e1e22SMaarten Lankhorst * Zero on success, negative errno on failure. 12438f6e1e22SMaarten Lankhorst */ 12448f6e1e22SMaarten Lankhorst int drm_connector_attach_scaling_mode_property(struct drm_connector *connector, 12458f6e1e22SMaarten Lankhorst u32 scaling_mode_mask) 12468f6e1e22SMaarten Lankhorst { 12478f6e1e22SMaarten Lankhorst struct drm_device *dev = connector->dev; 12488f6e1e22SMaarten Lankhorst struct drm_property *scaling_mode_property; 124930e9db6dSVille Syrjälä int i; 12508f6e1e22SMaarten Lankhorst const unsigned valid_scaling_mode_mask = 12518f6e1e22SMaarten Lankhorst (1U << ARRAY_SIZE(drm_scaling_mode_enum_list)) - 1; 12528f6e1e22SMaarten Lankhorst 12538f6e1e22SMaarten Lankhorst if (WARN_ON(hweight32(scaling_mode_mask) < 2 || 12548f6e1e22SMaarten Lankhorst scaling_mode_mask & ~valid_scaling_mode_mask)) 12558f6e1e22SMaarten Lankhorst return -EINVAL; 12568f6e1e22SMaarten Lankhorst 12578f6e1e22SMaarten Lankhorst scaling_mode_property = 12588f6e1e22SMaarten Lankhorst drm_property_create(dev, DRM_MODE_PROP_ENUM, "scaling mode", 12598f6e1e22SMaarten Lankhorst hweight32(scaling_mode_mask)); 12608f6e1e22SMaarten Lankhorst 12618f6e1e22SMaarten Lankhorst if (!scaling_mode_property) 12628f6e1e22SMaarten Lankhorst return -ENOMEM; 12638f6e1e22SMaarten Lankhorst 12648f6e1e22SMaarten Lankhorst for (i = 0; i < ARRAY_SIZE(drm_scaling_mode_enum_list); i++) { 12658f6e1e22SMaarten Lankhorst int ret; 12668f6e1e22SMaarten Lankhorst 12678f6e1e22SMaarten Lankhorst if (!(BIT(i) & scaling_mode_mask)) 12688f6e1e22SMaarten Lankhorst continue; 12698f6e1e22SMaarten Lankhorst 127030e9db6dSVille Syrjälä ret = drm_property_add_enum(scaling_mode_property, 12718f6e1e22SMaarten Lankhorst drm_scaling_mode_enum_list[i].type, 12728f6e1e22SMaarten Lankhorst drm_scaling_mode_enum_list[i].name); 12738f6e1e22SMaarten Lankhorst 12748f6e1e22SMaarten Lankhorst if (ret) { 12758f6e1e22SMaarten Lankhorst drm_property_destroy(dev, scaling_mode_property); 12768f6e1e22SMaarten Lankhorst 12778f6e1e22SMaarten Lankhorst return ret; 12788f6e1e22SMaarten Lankhorst } 12798f6e1e22SMaarten Lankhorst } 12808f6e1e22SMaarten Lankhorst 12818f6e1e22SMaarten Lankhorst drm_object_attach_property(&connector->base, 12828f6e1e22SMaarten Lankhorst scaling_mode_property, 0); 12838f6e1e22SMaarten Lankhorst 12848f6e1e22SMaarten Lankhorst connector->scaling_mode_property = scaling_mode_property; 12858f6e1e22SMaarten Lankhorst 12868f6e1e22SMaarten Lankhorst return 0; 12878f6e1e22SMaarten Lankhorst } 12888f6e1e22SMaarten Lankhorst EXPORT_SYMBOL(drm_connector_attach_scaling_mode_property); 12898f6e1e22SMaarten Lankhorst 12908f6e1e22SMaarten Lankhorst /** 129124557865SSean Paul * drm_connector_attach_content_protection_property - attach content protection 129224557865SSean Paul * property 129324557865SSean Paul * 129424557865SSean Paul * @connector: connector to attach CP property on. 129524557865SSean Paul * 129624557865SSean Paul * This is used to add support for content protection on select connectors. 129724557865SSean Paul * Content Protection is intentionally vague to allow for different underlying 129824557865SSean Paul * technologies, however it is most implemented by HDCP. 129924557865SSean Paul * 130024557865SSean Paul * The content protection will be set to &drm_connector_state.content_protection 130124557865SSean Paul * 130224557865SSean Paul * Returns: 130324557865SSean Paul * Zero on success, negative errno on failure. 130424557865SSean Paul */ 130524557865SSean Paul int drm_connector_attach_content_protection_property( 130624557865SSean Paul struct drm_connector *connector) 130724557865SSean Paul { 130824557865SSean Paul struct drm_device *dev = connector->dev; 130924557865SSean Paul struct drm_property *prop; 131024557865SSean Paul 131124557865SSean Paul prop = drm_property_create_enum(dev, 0, "Content Protection", 131224557865SSean Paul drm_cp_enum_list, 131324557865SSean Paul ARRAY_SIZE(drm_cp_enum_list)); 131424557865SSean Paul if (!prop) 131524557865SSean Paul return -ENOMEM; 131624557865SSean Paul 131724557865SSean Paul drm_object_attach_property(&connector->base, prop, 131824557865SSean Paul DRM_MODE_CONTENT_PROTECTION_UNDESIRED); 131924557865SSean Paul 132024557865SSean Paul connector->content_protection_property = prop; 132124557865SSean Paul 132224557865SSean Paul return 0; 132324557865SSean Paul } 132424557865SSean Paul EXPORT_SYMBOL(drm_connector_attach_content_protection_property); 132524557865SSean Paul 132624557865SSean Paul /** 132752217195SDaniel Vetter * drm_mode_create_aspect_ratio_property - create aspect ratio property 132852217195SDaniel Vetter * @dev: DRM device 132952217195SDaniel Vetter * 133052217195SDaniel Vetter * Called by a driver the first time it's needed, must be attached to desired 133152217195SDaniel Vetter * connectors. 133252217195SDaniel Vetter * 133352217195SDaniel Vetter * Returns: 133452217195SDaniel Vetter * Zero on success, negative errno on failure. 133552217195SDaniel Vetter */ 133652217195SDaniel Vetter int drm_mode_create_aspect_ratio_property(struct drm_device *dev) 133752217195SDaniel Vetter { 133852217195SDaniel Vetter if (dev->mode_config.aspect_ratio_property) 133952217195SDaniel Vetter return 0; 134052217195SDaniel Vetter 134152217195SDaniel Vetter dev->mode_config.aspect_ratio_property = 134252217195SDaniel Vetter drm_property_create_enum(dev, 0, "aspect ratio", 134352217195SDaniel Vetter drm_aspect_ratio_enum_list, 134452217195SDaniel Vetter ARRAY_SIZE(drm_aspect_ratio_enum_list)); 134552217195SDaniel Vetter 134652217195SDaniel Vetter if (dev->mode_config.aspect_ratio_property == NULL) 134752217195SDaniel Vetter return -ENOMEM; 134852217195SDaniel Vetter 134952217195SDaniel Vetter return 0; 135052217195SDaniel Vetter } 135152217195SDaniel Vetter EXPORT_SYMBOL(drm_mode_create_aspect_ratio_property); 135252217195SDaniel Vetter 135352217195SDaniel Vetter /** 135450525c33SStanislav Lisovskiy * drm_mode_create_content_type_property - create content type property 135550525c33SStanislav Lisovskiy * @dev: DRM device 135650525c33SStanislav Lisovskiy * 135750525c33SStanislav Lisovskiy * Called by a driver the first time it's needed, must be attached to desired 135850525c33SStanislav Lisovskiy * connectors. 135950525c33SStanislav Lisovskiy * 136050525c33SStanislav Lisovskiy * Returns: 136150525c33SStanislav Lisovskiy * Zero on success, negative errno on failure. 136250525c33SStanislav Lisovskiy */ 136350525c33SStanislav Lisovskiy int drm_mode_create_content_type_property(struct drm_device *dev) 136450525c33SStanislav Lisovskiy { 136550525c33SStanislav Lisovskiy if (dev->mode_config.content_type_property) 136650525c33SStanislav Lisovskiy return 0; 136750525c33SStanislav Lisovskiy 136850525c33SStanislav Lisovskiy dev->mode_config.content_type_property = 136950525c33SStanislav Lisovskiy drm_property_create_enum(dev, 0, "content type", 137050525c33SStanislav Lisovskiy drm_content_type_enum_list, 137150525c33SStanislav Lisovskiy ARRAY_SIZE(drm_content_type_enum_list)); 137250525c33SStanislav Lisovskiy 137350525c33SStanislav Lisovskiy if (dev->mode_config.content_type_property == NULL) 137450525c33SStanislav Lisovskiy return -ENOMEM; 137550525c33SStanislav Lisovskiy 137650525c33SStanislav Lisovskiy return 0; 137750525c33SStanislav Lisovskiy } 137850525c33SStanislav Lisovskiy EXPORT_SYMBOL(drm_mode_create_content_type_property); 137950525c33SStanislav Lisovskiy 138050525c33SStanislav Lisovskiy /** 138152217195SDaniel Vetter * drm_mode_create_suggested_offset_properties - create suggests offset properties 138252217195SDaniel Vetter * @dev: DRM device 138352217195SDaniel Vetter * 138452217195SDaniel Vetter * Create the the suggested x/y offset property for connectors. 138552217195SDaniel Vetter */ 138652217195SDaniel Vetter int drm_mode_create_suggested_offset_properties(struct drm_device *dev) 138752217195SDaniel Vetter { 138852217195SDaniel Vetter if (dev->mode_config.suggested_x_property && dev->mode_config.suggested_y_property) 138952217195SDaniel Vetter return 0; 139052217195SDaniel Vetter 139152217195SDaniel Vetter dev->mode_config.suggested_x_property = 139252217195SDaniel Vetter drm_property_create_range(dev, DRM_MODE_PROP_IMMUTABLE, "suggested X", 0, 0xffffffff); 139352217195SDaniel Vetter 139452217195SDaniel Vetter dev->mode_config.suggested_y_property = 139552217195SDaniel Vetter drm_property_create_range(dev, DRM_MODE_PROP_IMMUTABLE, "suggested Y", 0, 0xffffffff); 139652217195SDaniel Vetter 139752217195SDaniel Vetter if (dev->mode_config.suggested_x_property == NULL || 139852217195SDaniel Vetter dev->mode_config.suggested_y_property == NULL) 139952217195SDaniel Vetter return -ENOMEM; 140052217195SDaniel Vetter return 0; 140152217195SDaniel Vetter } 140252217195SDaniel Vetter EXPORT_SYMBOL(drm_mode_create_suggested_offset_properties); 140352217195SDaniel Vetter 140452217195SDaniel Vetter /** 140552217195SDaniel Vetter * drm_mode_connector_set_path_property - set tile property on connector 140652217195SDaniel Vetter * @connector: connector to set property on. 140752217195SDaniel Vetter * @path: path to use for property; must not be NULL. 140852217195SDaniel Vetter * 140952217195SDaniel Vetter * This creates a property to expose to userspace to specify a 141052217195SDaniel Vetter * connector path. This is mainly used for DisplayPort MST where 141152217195SDaniel Vetter * connectors have a topology and we want to allow userspace to give 141252217195SDaniel Vetter * them more meaningful names. 141352217195SDaniel Vetter * 141452217195SDaniel Vetter * Returns: 141552217195SDaniel Vetter * Zero on success, negative errno on failure. 141652217195SDaniel Vetter */ 141752217195SDaniel Vetter int drm_mode_connector_set_path_property(struct drm_connector *connector, 141852217195SDaniel Vetter const char *path) 141952217195SDaniel Vetter { 142052217195SDaniel Vetter struct drm_device *dev = connector->dev; 142152217195SDaniel Vetter int ret; 142252217195SDaniel Vetter 142352217195SDaniel Vetter ret = drm_property_replace_global_blob(dev, 142452217195SDaniel Vetter &connector->path_blob_ptr, 142552217195SDaniel Vetter strlen(path) + 1, 142652217195SDaniel Vetter path, 142752217195SDaniel Vetter &connector->base, 142852217195SDaniel Vetter dev->mode_config.path_property); 142952217195SDaniel Vetter return ret; 143052217195SDaniel Vetter } 143152217195SDaniel Vetter EXPORT_SYMBOL(drm_mode_connector_set_path_property); 143252217195SDaniel Vetter 143352217195SDaniel Vetter /** 143452217195SDaniel Vetter * drm_mode_connector_set_tile_property - set tile property on connector 143552217195SDaniel Vetter * @connector: connector to set property on. 143652217195SDaniel Vetter * 143752217195SDaniel Vetter * This looks up the tile information for a connector, and creates a 143852217195SDaniel Vetter * property for userspace to parse if it exists. The property is of 143952217195SDaniel Vetter * the form of 8 integers using ':' as a separator. 144052217195SDaniel Vetter * 144152217195SDaniel Vetter * Returns: 144252217195SDaniel Vetter * Zero on success, errno on failure. 144352217195SDaniel Vetter */ 144452217195SDaniel Vetter int drm_mode_connector_set_tile_property(struct drm_connector *connector) 144552217195SDaniel Vetter { 144652217195SDaniel Vetter struct drm_device *dev = connector->dev; 144752217195SDaniel Vetter char tile[256]; 144852217195SDaniel Vetter int ret; 144952217195SDaniel Vetter 145052217195SDaniel Vetter if (!connector->has_tile) { 145152217195SDaniel Vetter ret = drm_property_replace_global_blob(dev, 145252217195SDaniel Vetter &connector->tile_blob_ptr, 145352217195SDaniel Vetter 0, 145452217195SDaniel Vetter NULL, 145552217195SDaniel Vetter &connector->base, 145652217195SDaniel Vetter dev->mode_config.tile_property); 145752217195SDaniel Vetter return ret; 145852217195SDaniel Vetter } 145952217195SDaniel Vetter 146052217195SDaniel Vetter snprintf(tile, 256, "%d:%d:%d:%d:%d:%d:%d:%d", 146152217195SDaniel Vetter connector->tile_group->id, connector->tile_is_single_monitor, 146252217195SDaniel Vetter connector->num_h_tile, connector->num_v_tile, 146352217195SDaniel Vetter connector->tile_h_loc, connector->tile_v_loc, 146452217195SDaniel Vetter connector->tile_h_size, connector->tile_v_size); 146552217195SDaniel Vetter 146652217195SDaniel Vetter ret = drm_property_replace_global_blob(dev, 146752217195SDaniel Vetter &connector->tile_blob_ptr, 146852217195SDaniel Vetter strlen(tile) + 1, 146952217195SDaniel Vetter tile, 147052217195SDaniel Vetter &connector->base, 147152217195SDaniel Vetter dev->mode_config.tile_property); 147252217195SDaniel Vetter return ret; 147352217195SDaniel Vetter } 147452217195SDaniel Vetter EXPORT_SYMBOL(drm_mode_connector_set_tile_property); 147552217195SDaniel Vetter 147652217195SDaniel Vetter /** 147752217195SDaniel Vetter * drm_mode_connector_update_edid_property - update the edid property of a connector 147852217195SDaniel Vetter * @connector: drm connector 147952217195SDaniel Vetter * @edid: new value of the edid property 148052217195SDaniel Vetter * 148152217195SDaniel Vetter * This function creates a new blob modeset object and assigns its id to the 148252217195SDaniel Vetter * connector's edid property. 148352217195SDaniel Vetter * 148452217195SDaniel Vetter * Returns: 148552217195SDaniel Vetter * Zero on success, negative errno on failure. 148652217195SDaniel Vetter */ 148752217195SDaniel Vetter int drm_mode_connector_update_edid_property(struct drm_connector *connector, 148852217195SDaniel Vetter const struct edid *edid) 148952217195SDaniel Vetter { 149052217195SDaniel Vetter struct drm_device *dev = connector->dev; 149152217195SDaniel Vetter size_t size = 0; 149252217195SDaniel Vetter int ret; 149352217195SDaniel Vetter 149452217195SDaniel Vetter /* ignore requests to set edid when overridden */ 149552217195SDaniel Vetter if (connector->override_edid) 149652217195SDaniel Vetter return 0; 149752217195SDaniel Vetter 149852217195SDaniel Vetter if (edid) 149952217195SDaniel Vetter size = EDID_LENGTH * (1 + edid->extensions); 150052217195SDaniel Vetter 1501170178feSKeith Packard /* Set the display info, using edid if available, otherwise 1502170178feSKeith Packard * reseting the values to defaults. This duplicates the work 1503170178feSKeith Packard * done in drm_add_edid_modes, but that function is not 1504170178feSKeith Packard * consistently called before this one in all drivers and the 1505170178feSKeith Packard * computation is cheap enough that it seems better to 1506170178feSKeith Packard * duplicate it rather than attempt to ensure some arbitrary 1507170178feSKeith Packard * ordering of calls. 1508170178feSKeith Packard */ 1509170178feSKeith Packard if (edid) 1510170178feSKeith Packard drm_add_display_info(connector, edid); 1511170178feSKeith Packard else 1512170178feSKeith Packard drm_reset_display_info(connector); 1513170178feSKeith Packard 151466660d4cSDave Airlie drm_object_property_set_value(&connector->base, 151566660d4cSDave Airlie dev->mode_config.non_desktop_property, 151666660d4cSDave Airlie connector->display_info.non_desktop); 151766660d4cSDave Airlie 151852217195SDaniel Vetter ret = drm_property_replace_global_blob(dev, 151952217195SDaniel Vetter &connector->edid_blob_ptr, 152052217195SDaniel Vetter size, 152152217195SDaniel Vetter edid, 152252217195SDaniel Vetter &connector->base, 152352217195SDaniel Vetter dev->mode_config.edid_property); 152452217195SDaniel Vetter return ret; 152552217195SDaniel Vetter } 152652217195SDaniel Vetter EXPORT_SYMBOL(drm_mode_connector_update_edid_property); 152752217195SDaniel Vetter 152840ee6fbeSManasi Navare /** 152940ee6fbeSManasi Navare * drm_mode_connector_set_link_status_property - Set link status property of a connector 153040ee6fbeSManasi Navare * @connector: drm connector 153140ee6fbeSManasi Navare * @link_status: new value of link status property (0: Good, 1: Bad) 153240ee6fbeSManasi Navare * 153340ee6fbeSManasi Navare * In usual working scenario, this link status property will always be set to 153440ee6fbeSManasi Navare * "GOOD". If something fails during or after a mode set, the kernel driver 153540ee6fbeSManasi Navare * may set this link status property to "BAD". The caller then needs to send a 153640ee6fbeSManasi Navare * hotplug uevent for userspace to re-check the valid modes through 153740ee6fbeSManasi Navare * GET_CONNECTOR_IOCTL and retry modeset. 153840ee6fbeSManasi Navare * 153940ee6fbeSManasi Navare * Note: Drivers cannot rely on userspace to support this property and 154040ee6fbeSManasi Navare * issue a modeset. As such, they may choose to handle issues (like 154140ee6fbeSManasi Navare * re-training a link) without userspace's intervention. 154240ee6fbeSManasi Navare * 154340ee6fbeSManasi Navare * The reason for adding this property is to handle link training failures, but 154440ee6fbeSManasi Navare * it is not limited to DP or link training. For example, if we implement 154540ee6fbeSManasi Navare * asynchronous setcrtc, this property can be used to report any failures in that. 154640ee6fbeSManasi Navare */ 154740ee6fbeSManasi Navare void drm_mode_connector_set_link_status_property(struct drm_connector *connector, 154840ee6fbeSManasi Navare uint64_t link_status) 154940ee6fbeSManasi Navare { 155040ee6fbeSManasi Navare struct drm_device *dev = connector->dev; 155140ee6fbeSManasi Navare 155240ee6fbeSManasi Navare drm_modeset_lock(&dev->mode_config.connection_mutex, NULL); 155340ee6fbeSManasi Navare connector->state->link_status = link_status; 155440ee6fbeSManasi Navare drm_modeset_unlock(&dev->mode_config.connection_mutex); 155540ee6fbeSManasi Navare } 155640ee6fbeSManasi Navare EXPORT_SYMBOL(drm_mode_connector_set_link_status_property); 155740ee6fbeSManasi Navare 15588d70f395SHans de Goede /** 15598d70f395SHans de Goede * drm_connector_init_panel_orientation_property - 15608d70f395SHans de Goede * initialize the connecters panel_orientation property 15618d70f395SHans de Goede * @connector: connector for which to init the panel-orientation property. 15628d70f395SHans de Goede * @width: width in pixels of the panel, used for panel quirk detection 15638d70f395SHans de Goede * @height: height in pixels of the panel, used for panel quirk detection 15648d70f395SHans de Goede * 15658d70f395SHans de Goede * This function should only be called for built-in panels, after setting 15668d70f395SHans de Goede * connector->display_info.panel_orientation first (if known). 15678d70f395SHans de Goede * 15688d70f395SHans de Goede * This function will check for platform specific (e.g. DMI based) quirks 15698d70f395SHans de Goede * overriding display_info.panel_orientation first, then if panel_orientation 15708d70f395SHans de Goede * is not DRM_MODE_PANEL_ORIENTATION_UNKNOWN it will attach the 15718d70f395SHans de Goede * "panel orientation" property to the connector. 15728d70f395SHans de Goede * 15738d70f395SHans de Goede * Returns: 15748d70f395SHans de Goede * Zero on success, negative errno on failure. 15758d70f395SHans de Goede */ 15768d70f395SHans de Goede int drm_connector_init_panel_orientation_property( 15778d70f395SHans de Goede struct drm_connector *connector, int width, int height) 15788d70f395SHans de Goede { 15798d70f395SHans de Goede struct drm_device *dev = connector->dev; 15808d70f395SHans de Goede struct drm_display_info *info = &connector->display_info; 15818d70f395SHans de Goede struct drm_property *prop; 15828d70f395SHans de Goede int orientation_quirk; 15838d70f395SHans de Goede 15848d70f395SHans de Goede orientation_quirk = drm_get_panel_orientation_quirk(width, height); 15858d70f395SHans de Goede if (orientation_quirk != DRM_MODE_PANEL_ORIENTATION_UNKNOWN) 15868d70f395SHans de Goede info->panel_orientation = orientation_quirk; 15878d70f395SHans de Goede 15888d70f395SHans de Goede if (info->panel_orientation == DRM_MODE_PANEL_ORIENTATION_UNKNOWN) 15898d70f395SHans de Goede return 0; 15908d70f395SHans de Goede 15918d70f395SHans de Goede prop = dev->mode_config.panel_orientation_property; 15928d70f395SHans de Goede if (!prop) { 15938d70f395SHans de Goede prop = drm_property_create_enum(dev, DRM_MODE_PROP_IMMUTABLE, 15948d70f395SHans de Goede "panel orientation", 15958d70f395SHans de Goede drm_panel_orientation_enum_list, 15968d70f395SHans de Goede ARRAY_SIZE(drm_panel_orientation_enum_list)); 15978d70f395SHans de Goede if (!prop) 15988d70f395SHans de Goede return -ENOMEM; 15998d70f395SHans de Goede 16008d70f395SHans de Goede dev->mode_config.panel_orientation_property = prop; 16018d70f395SHans de Goede } 16028d70f395SHans de Goede 16038d70f395SHans de Goede drm_object_attach_property(&connector->base, prop, 16048d70f395SHans de Goede info->panel_orientation); 16058d70f395SHans de Goede return 0; 16068d70f395SHans de Goede } 16078d70f395SHans de Goede EXPORT_SYMBOL(drm_connector_init_panel_orientation_property); 16088d70f395SHans de Goede 160952217195SDaniel Vetter int drm_mode_connector_set_obj_prop(struct drm_mode_object *obj, 161052217195SDaniel Vetter struct drm_property *property, 161152217195SDaniel Vetter uint64_t value) 161252217195SDaniel Vetter { 161352217195SDaniel Vetter int ret = -EINVAL; 161452217195SDaniel Vetter struct drm_connector *connector = obj_to_connector(obj); 161552217195SDaniel Vetter 161652217195SDaniel Vetter /* Do DPMS ourselves */ 161752217195SDaniel Vetter if (property == connector->dev->mode_config.dpms_property) { 161852217195SDaniel Vetter ret = (*connector->funcs->dpms)(connector, (int)value); 161952217195SDaniel Vetter } else if (connector->funcs->set_property) 162052217195SDaniel Vetter ret = connector->funcs->set_property(connector, property, value); 162152217195SDaniel Vetter 1622144a7999SDaniel Vetter if (!ret) 162352217195SDaniel Vetter drm_object_property_set_value(&connector->base, property, value); 162452217195SDaniel Vetter return ret; 162552217195SDaniel Vetter } 162652217195SDaniel Vetter 162752217195SDaniel Vetter int drm_mode_connector_property_set_ioctl(struct drm_device *dev, 162852217195SDaniel Vetter void *data, struct drm_file *file_priv) 162952217195SDaniel Vetter { 163052217195SDaniel Vetter struct drm_mode_connector_set_property *conn_set_prop = data; 163152217195SDaniel Vetter struct drm_mode_obj_set_property obj_set_prop = { 163252217195SDaniel Vetter .value = conn_set_prop->value, 163352217195SDaniel Vetter .prop_id = conn_set_prop->prop_id, 163452217195SDaniel Vetter .obj_id = conn_set_prop->connector_id, 163552217195SDaniel Vetter .obj_type = DRM_MODE_OBJECT_CONNECTOR 163652217195SDaniel Vetter }; 163752217195SDaniel Vetter 163852217195SDaniel Vetter /* It does all the locking and checking we need */ 163952217195SDaniel Vetter return drm_mode_obj_set_property_ioctl(dev, &obj_set_prop, file_priv); 164052217195SDaniel Vetter } 164152217195SDaniel Vetter 164252217195SDaniel Vetter static struct drm_encoder *drm_connector_get_encoder(struct drm_connector *connector) 164352217195SDaniel Vetter { 164452217195SDaniel Vetter /* For atomic drivers only state objects are synchronously updated and 164552217195SDaniel Vetter * protected by modeset locks, so check those first. */ 164652217195SDaniel Vetter if (connector->state) 164752217195SDaniel Vetter return connector->state->best_encoder; 164852217195SDaniel Vetter return connector->encoder; 164952217195SDaniel Vetter } 165052217195SDaniel Vetter 1651c3ff0cdbSAnkit Nautiyal static bool 1652c3ff0cdbSAnkit Nautiyal drm_mode_expose_to_userspace(const struct drm_display_mode *mode, 1653c3ff0cdbSAnkit Nautiyal const struct list_head *export_list, 165452217195SDaniel Vetter const struct drm_file *file_priv) 165552217195SDaniel Vetter { 165652217195SDaniel Vetter /* 165752217195SDaniel Vetter * If user-space hasn't configured the driver to expose the stereo 3D 165852217195SDaniel Vetter * modes, don't expose them. 165952217195SDaniel Vetter */ 166052217195SDaniel Vetter if (!file_priv->stereo_allowed && drm_mode_is_stereo(mode)) 166152217195SDaniel Vetter return false; 1662c3ff0cdbSAnkit Nautiyal /* 1663c3ff0cdbSAnkit Nautiyal * If user-space hasn't configured the driver to expose the modes 1664c3ff0cdbSAnkit Nautiyal * with aspect-ratio, don't expose them. However if such a mode 1665c3ff0cdbSAnkit Nautiyal * is unique, let it be exposed, but reset the aspect-ratio flags 1666c3ff0cdbSAnkit Nautiyal * while preparing the list of user-modes. 1667c3ff0cdbSAnkit Nautiyal */ 1668c3ff0cdbSAnkit Nautiyal if (!file_priv->aspect_ratio_allowed) { 1669c3ff0cdbSAnkit Nautiyal struct drm_display_mode *mode_itr; 1670c3ff0cdbSAnkit Nautiyal 1671c3ff0cdbSAnkit Nautiyal list_for_each_entry(mode_itr, export_list, export_head) 1672c3ff0cdbSAnkit Nautiyal if (drm_mode_match(mode_itr, mode, 1673c3ff0cdbSAnkit Nautiyal DRM_MODE_MATCH_TIMINGS | 1674c3ff0cdbSAnkit Nautiyal DRM_MODE_MATCH_CLOCK | 1675c3ff0cdbSAnkit Nautiyal DRM_MODE_MATCH_FLAGS | 1676c3ff0cdbSAnkit Nautiyal DRM_MODE_MATCH_3D_FLAGS)) 1677c3ff0cdbSAnkit Nautiyal return false; 1678c3ff0cdbSAnkit Nautiyal } 167952217195SDaniel Vetter 168052217195SDaniel Vetter return true; 168152217195SDaniel Vetter } 168252217195SDaniel Vetter 168352217195SDaniel Vetter int drm_mode_getconnector(struct drm_device *dev, void *data, 168452217195SDaniel Vetter struct drm_file *file_priv) 168552217195SDaniel Vetter { 168652217195SDaniel Vetter struct drm_mode_get_connector *out_resp = data; 168752217195SDaniel Vetter struct drm_connector *connector; 168852217195SDaniel Vetter struct drm_encoder *encoder; 168952217195SDaniel Vetter struct drm_display_mode *mode; 169052217195SDaniel Vetter int mode_count = 0; 169152217195SDaniel Vetter int encoders_count = 0; 169252217195SDaniel Vetter int ret = 0; 169352217195SDaniel Vetter int copied = 0; 169452217195SDaniel Vetter int i; 169552217195SDaniel Vetter struct drm_mode_modeinfo u_mode; 169652217195SDaniel Vetter struct drm_mode_modeinfo __user *mode_ptr; 169752217195SDaniel Vetter uint32_t __user *encoder_ptr; 1698c3ff0cdbSAnkit Nautiyal LIST_HEAD(export_list); 169952217195SDaniel Vetter 170052217195SDaniel Vetter if (!drm_core_check_feature(dev, DRIVER_MODESET)) 170152217195SDaniel Vetter return -EINVAL; 170252217195SDaniel Vetter 170352217195SDaniel Vetter memset(&u_mode, 0, sizeof(struct drm_mode_modeinfo)); 170452217195SDaniel Vetter 1705418da172SKeith Packard connector = drm_connector_lookup(dev, file_priv, out_resp->connector_id); 170691eefc05SDaniel Vetter if (!connector) 170791eefc05SDaniel Vetter return -ENOENT; 170852217195SDaniel Vetter 170991eefc05SDaniel Vetter for (i = 0; i < DRM_CONNECTOR_MAX_ENCODER; i++) 171091eefc05SDaniel Vetter if (connector->encoder_ids[i] != 0) 171191eefc05SDaniel Vetter encoders_count++; 171291eefc05SDaniel Vetter 171391eefc05SDaniel Vetter if ((out_resp->count_encoders >= encoders_count) && encoders_count) { 171491eefc05SDaniel Vetter copied = 0; 171591eefc05SDaniel Vetter encoder_ptr = (uint32_t __user *)(unsigned long)(out_resp->encoders_ptr); 171691eefc05SDaniel Vetter for (i = 0; i < DRM_CONNECTOR_MAX_ENCODER; i++) { 171791eefc05SDaniel Vetter if (connector->encoder_ids[i] != 0) { 171891eefc05SDaniel Vetter if (put_user(connector->encoder_ids[i], 171991eefc05SDaniel Vetter encoder_ptr + copied)) { 172091eefc05SDaniel Vetter ret = -EFAULT; 1721e94ac351SDaniel Vetter goto out; 172291eefc05SDaniel Vetter } 172391eefc05SDaniel Vetter copied++; 172491eefc05SDaniel Vetter } 172591eefc05SDaniel Vetter } 172691eefc05SDaniel Vetter } 172791eefc05SDaniel Vetter out_resp->count_encoders = encoders_count; 172891eefc05SDaniel Vetter 172991eefc05SDaniel Vetter out_resp->connector_id = connector->base.id; 173091eefc05SDaniel Vetter out_resp->connector_type = connector->connector_type; 173191eefc05SDaniel Vetter out_resp->connector_type_id = connector->connector_type_id; 173291eefc05SDaniel Vetter 173391eefc05SDaniel Vetter mutex_lock(&dev->mode_config.mutex); 173491eefc05SDaniel Vetter if (out_resp->count_modes == 0) { 173591eefc05SDaniel Vetter connector->funcs->fill_modes(connector, 173691eefc05SDaniel Vetter dev->mode_config.max_width, 173791eefc05SDaniel Vetter dev->mode_config.max_height); 173891eefc05SDaniel Vetter } 173991eefc05SDaniel Vetter 174091eefc05SDaniel Vetter out_resp->mm_width = connector->display_info.width_mm; 174191eefc05SDaniel Vetter out_resp->mm_height = connector->display_info.height_mm; 174291eefc05SDaniel Vetter out_resp->subpixel = connector->display_info.subpixel_order; 174391eefc05SDaniel Vetter out_resp->connection = connector->status; 174491eefc05SDaniel Vetter 174591eefc05SDaniel Vetter /* delayed so we get modes regardless of pre-fill_modes state */ 174691eefc05SDaniel Vetter list_for_each_entry(mode, &connector->modes, head) 1747c3ff0cdbSAnkit Nautiyal if (drm_mode_expose_to_userspace(mode, &export_list, 1748c3ff0cdbSAnkit Nautiyal file_priv)) { 1749c3ff0cdbSAnkit Nautiyal list_add_tail(&mode->export_head, &export_list); 175091eefc05SDaniel Vetter mode_count++; 1751c3ff0cdbSAnkit Nautiyal } 175291eefc05SDaniel Vetter 175352217195SDaniel Vetter /* 175452217195SDaniel Vetter * This ioctl is called twice, once to determine how much space is 175552217195SDaniel Vetter * needed, and the 2nd time to fill it. 1756c3ff0cdbSAnkit Nautiyal * The modes that need to be exposed to the user are maintained in the 1757c3ff0cdbSAnkit Nautiyal * 'export_list'. When the ioctl is called first time to determine the, 1758c3ff0cdbSAnkit Nautiyal * space, the export_list gets filled, to find the no.of modes. In the 1759c3ff0cdbSAnkit Nautiyal * 2nd time, the user modes are filled, one by one from the export_list. 176052217195SDaniel Vetter */ 176152217195SDaniel Vetter if ((out_resp->count_modes >= mode_count) && mode_count) { 176252217195SDaniel Vetter copied = 0; 176352217195SDaniel Vetter mode_ptr = (struct drm_mode_modeinfo __user *)(unsigned long)out_resp->modes_ptr; 1764c3ff0cdbSAnkit Nautiyal list_for_each_entry(mode, &export_list, export_head) { 176552217195SDaniel Vetter drm_mode_convert_to_umode(&u_mode, mode); 1766c3ff0cdbSAnkit Nautiyal /* 1767c3ff0cdbSAnkit Nautiyal * Reset aspect ratio flags of user-mode, if modes with 1768c3ff0cdbSAnkit Nautiyal * aspect-ratio are not supported. 1769c3ff0cdbSAnkit Nautiyal */ 1770c3ff0cdbSAnkit Nautiyal if (!file_priv->aspect_ratio_allowed) 1771c3ff0cdbSAnkit Nautiyal u_mode.flags &= ~DRM_MODE_FLAG_PIC_AR_MASK; 177252217195SDaniel Vetter if (copy_to_user(mode_ptr + copied, 177352217195SDaniel Vetter &u_mode, sizeof(u_mode))) { 177452217195SDaniel Vetter ret = -EFAULT; 1775e94ac351SDaniel Vetter mutex_unlock(&dev->mode_config.mutex); 1776e94ac351SDaniel Vetter 177752217195SDaniel Vetter goto out; 177852217195SDaniel Vetter } 177952217195SDaniel Vetter copied++; 178052217195SDaniel Vetter } 178152217195SDaniel Vetter } 178252217195SDaniel Vetter out_resp->count_modes = mode_count; 178352217195SDaniel Vetter mutex_unlock(&dev->mode_config.mutex); 1784e94ac351SDaniel Vetter 1785e94ac351SDaniel Vetter drm_modeset_lock(&dev->mode_config.connection_mutex, NULL); 1786e94ac351SDaniel Vetter encoder = drm_connector_get_encoder(connector); 1787e94ac351SDaniel Vetter if (encoder) 1788e94ac351SDaniel Vetter out_resp->encoder_id = encoder->base.id; 1789e94ac351SDaniel Vetter else 1790e94ac351SDaniel Vetter out_resp->encoder_id = 0; 1791e94ac351SDaniel Vetter 1792e94ac351SDaniel Vetter /* Only grab properties after probing, to make sure EDID and other 1793e94ac351SDaniel Vetter * properties reflect the latest status. */ 1794e94ac351SDaniel Vetter ret = drm_mode_object_get_properties(&connector->base, file_priv->atomic, 1795e94ac351SDaniel Vetter (uint32_t __user *)(unsigned long)(out_resp->props_ptr), 1796e94ac351SDaniel Vetter (uint64_t __user *)(unsigned long)(out_resp->prop_values_ptr), 1797e94ac351SDaniel Vetter &out_resp->count_props); 1798e94ac351SDaniel Vetter drm_modeset_unlock(&dev->mode_config.connection_mutex); 1799e94ac351SDaniel Vetter 1800e94ac351SDaniel Vetter out: 1801ad093607SThierry Reding drm_connector_put(connector); 180252217195SDaniel Vetter 180352217195SDaniel Vetter return ret; 180452217195SDaniel Vetter } 180552217195SDaniel Vetter 18069498c19bSDaniel Vetter 18079498c19bSDaniel Vetter /** 18089498c19bSDaniel Vetter * DOC: Tile group 18099498c19bSDaniel Vetter * 18109498c19bSDaniel Vetter * Tile groups are used to represent tiled monitors with a unique integer 18119498c19bSDaniel Vetter * identifier. Tiled monitors using DisplayID v1.3 have a unique 8-byte handle, 18129498c19bSDaniel Vetter * we store this in a tile group, so we have a common identifier for all tiles 18139498c19bSDaniel Vetter * in a monitor group. The property is called "TILE". Drivers can manage tile 18149498c19bSDaniel Vetter * groups using drm_mode_create_tile_group(), drm_mode_put_tile_group() and 18159498c19bSDaniel Vetter * drm_mode_get_tile_group(). But this is only needed for internal panels where 18169498c19bSDaniel Vetter * the tile group information is exposed through a non-standard way. 18179498c19bSDaniel Vetter */ 18189498c19bSDaniel Vetter 18199498c19bSDaniel Vetter static void drm_tile_group_free(struct kref *kref) 18209498c19bSDaniel Vetter { 18219498c19bSDaniel Vetter struct drm_tile_group *tg = container_of(kref, struct drm_tile_group, refcount); 18229498c19bSDaniel Vetter struct drm_device *dev = tg->dev; 18239498c19bSDaniel Vetter mutex_lock(&dev->mode_config.idr_mutex); 18249498c19bSDaniel Vetter idr_remove(&dev->mode_config.tile_idr, tg->id); 18259498c19bSDaniel Vetter mutex_unlock(&dev->mode_config.idr_mutex); 18269498c19bSDaniel Vetter kfree(tg); 18279498c19bSDaniel Vetter } 18289498c19bSDaniel Vetter 18299498c19bSDaniel Vetter /** 18309498c19bSDaniel Vetter * drm_mode_put_tile_group - drop a reference to a tile group. 18319498c19bSDaniel Vetter * @dev: DRM device 18329498c19bSDaniel Vetter * @tg: tile group to drop reference to. 18339498c19bSDaniel Vetter * 18349498c19bSDaniel Vetter * drop reference to tile group and free if 0. 18359498c19bSDaniel Vetter */ 18369498c19bSDaniel Vetter void drm_mode_put_tile_group(struct drm_device *dev, 18379498c19bSDaniel Vetter struct drm_tile_group *tg) 18389498c19bSDaniel Vetter { 18399498c19bSDaniel Vetter kref_put(&tg->refcount, drm_tile_group_free); 18409498c19bSDaniel Vetter } 18419498c19bSDaniel Vetter EXPORT_SYMBOL(drm_mode_put_tile_group); 18429498c19bSDaniel Vetter 18439498c19bSDaniel Vetter /** 18449498c19bSDaniel Vetter * drm_mode_get_tile_group - get a reference to an existing tile group 18459498c19bSDaniel Vetter * @dev: DRM device 18469498c19bSDaniel Vetter * @topology: 8-bytes unique per monitor. 18479498c19bSDaniel Vetter * 18489498c19bSDaniel Vetter * Use the unique bytes to get a reference to an existing tile group. 18499498c19bSDaniel Vetter * 18509498c19bSDaniel Vetter * RETURNS: 18519498c19bSDaniel Vetter * tile group or NULL if not found. 18529498c19bSDaniel Vetter */ 18539498c19bSDaniel Vetter struct drm_tile_group *drm_mode_get_tile_group(struct drm_device *dev, 18549498c19bSDaniel Vetter char topology[8]) 18559498c19bSDaniel Vetter { 18569498c19bSDaniel Vetter struct drm_tile_group *tg; 18579498c19bSDaniel Vetter int id; 18589498c19bSDaniel Vetter mutex_lock(&dev->mode_config.idr_mutex); 18599498c19bSDaniel Vetter idr_for_each_entry(&dev->mode_config.tile_idr, tg, id) { 18609498c19bSDaniel Vetter if (!memcmp(tg->group_data, topology, 8)) { 18619498c19bSDaniel Vetter if (!kref_get_unless_zero(&tg->refcount)) 18629498c19bSDaniel Vetter tg = NULL; 18639498c19bSDaniel Vetter mutex_unlock(&dev->mode_config.idr_mutex); 18649498c19bSDaniel Vetter return tg; 18659498c19bSDaniel Vetter } 18669498c19bSDaniel Vetter } 18679498c19bSDaniel Vetter mutex_unlock(&dev->mode_config.idr_mutex); 18689498c19bSDaniel Vetter return NULL; 18699498c19bSDaniel Vetter } 18709498c19bSDaniel Vetter EXPORT_SYMBOL(drm_mode_get_tile_group); 18719498c19bSDaniel Vetter 18729498c19bSDaniel Vetter /** 18739498c19bSDaniel Vetter * drm_mode_create_tile_group - create a tile group from a displayid description 18749498c19bSDaniel Vetter * @dev: DRM device 18759498c19bSDaniel Vetter * @topology: 8-bytes unique per monitor. 18769498c19bSDaniel Vetter * 18779498c19bSDaniel Vetter * Create a tile group for the unique monitor, and get a unique 18789498c19bSDaniel Vetter * identifier for the tile group. 18799498c19bSDaniel Vetter * 18809498c19bSDaniel Vetter * RETURNS: 18819498c19bSDaniel Vetter * new tile group or error. 18829498c19bSDaniel Vetter */ 18839498c19bSDaniel Vetter struct drm_tile_group *drm_mode_create_tile_group(struct drm_device *dev, 18849498c19bSDaniel Vetter char topology[8]) 18859498c19bSDaniel Vetter { 18869498c19bSDaniel Vetter struct drm_tile_group *tg; 18879498c19bSDaniel Vetter int ret; 18889498c19bSDaniel Vetter 18899498c19bSDaniel Vetter tg = kzalloc(sizeof(*tg), GFP_KERNEL); 18909498c19bSDaniel Vetter if (!tg) 18919498c19bSDaniel Vetter return ERR_PTR(-ENOMEM); 18929498c19bSDaniel Vetter 18939498c19bSDaniel Vetter kref_init(&tg->refcount); 18949498c19bSDaniel Vetter memcpy(tg->group_data, topology, 8); 18959498c19bSDaniel Vetter tg->dev = dev; 18969498c19bSDaniel Vetter 18979498c19bSDaniel Vetter mutex_lock(&dev->mode_config.idr_mutex); 18989498c19bSDaniel Vetter ret = idr_alloc(&dev->mode_config.tile_idr, tg, 1, 0, GFP_KERNEL); 18999498c19bSDaniel Vetter if (ret >= 0) { 19009498c19bSDaniel Vetter tg->id = ret; 19019498c19bSDaniel Vetter } else { 19029498c19bSDaniel Vetter kfree(tg); 19039498c19bSDaniel Vetter tg = ERR_PTR(ret); 19049498c19bSDaniel Vetter } 19059498c19bSDaniel Vetter 19069498c19bSDaniel Vetter mutex_unlock(&dev->mode_config.idr_mutex); 19079498c19bSDaniel Vetter return tg; 19089498c19bSDaniel Vetter } 19099498c19bSDaniel Vetter EXPORT_SYMBOL(drm_mode_create_tile_group); 1910