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> 2752217195SDaniel Vetter 2852217195SDaniel Vetter #include "drm_crtc_internal.h" 2952217195SDaniel Vetter #include "drm_internal.h" 3052217195SDaniel Vetter 31ae2a6da8SDaniel Vetter /** 32ae2a6da8SDaniel Vetter * DOC: overview 33ae2a6da8SDaniel Vetter * 34ae2a6da8SDaniel Vetter * In DRM connectors are the general abstraction for display sinks, and include 35ae2a6da8SDaniel Vetter * als fixed panels or anything else that can display pixels in some form. As 36ae2a6da8SDaniel Vetter * opposed to all other KMS objects representing hardware (like CRTC, encoder or 37ae2a6da8SDaniel Vetter * plane abstractions) connectors can be hotplugged and unplugged at runtime. 38ae2a6da8SDaniel Vetter * Hence they are reference-counted using drm_connector_reference() and 39ae2a6da8SDaniel Vetter * drm_connector_unreference(). 40ae2a6da8SDaniel Vetter * 41d574528aSDaniel Vetter * KMS driver must create, initialize, register and attach at a &struct 42d574528aSDaniel Vetter * drm_connector for each such sink. The instance is created as other KMS 43aec97460SDaniel Vetter * objects and initialized by setting the following fields. The connector is 44aec97460SDaniel Vetter * initialized with a call to drm_connector_init() with a pointer to the 45aec97460SDaniel Vetter * &struct drm_connector_funcs and a connector type, and then exposed to 46aec97460SDaniel Vetter * userspace with a call to drm_connector_register(). 47ae2a6da8SDaniel Vetter * 48ae2a6da8SDaniel Vetter * Connectors must be attached to an encoder to be used. For devices that map 49ae2a6da8SDaniel Vetter * connectors to encoders 1:1, the connector should be attached at 50ae2a6da8SDaniel Vetter * initialization time with a call to drm_mode_connector_attach_encoder(). The 51d574528aSDaniel Vetter * driver must also set the &drm_connector.encoder field to point to the 52ae2a6da8SDaniel Vetter * attached encoder. 53ae2a6da8SDaniel Vetter * 54ae2a6da8SDaniel Vetter * For connectors which are not fixed (like built-in panels) the driver needs to 55ae2a6da8SDaniel Vetter * support hotplug notifications. The simplest way to do that is by using the 56ae2a6da8SDaniel Vetter * probe helpers, see drm_kms_helper_poll_init() for connectors which don't have 57ae2a6da8SDaniel Vetter * hardware support for hotplug interrupts. Connectors with hardware hotplug 58ae2a6da8SDaniel Vetter * support can instead use e.g. drm_helper_hpd_irq_event(). 59ae2a6da8SDaniel Vetter */ 60ae2a6da8SDaniel Vetter 6152217195SDaniel Vetter struct drm_conn_prop_enum_list { 6252217195SDaniel Vetter int type; 6352217195SDaniel Vetter const char *name; 6452217195SDaniel Vetter struct ida ida; 6552217195SDaniel Vetter }; 6652217195SDaniel Vetter 6752217195SDaniel Vetter /* 6852217195SDaniel Vetter * Connector and encoder types. 6952217195SDaniel Vetter */ 7052217195SDaniel Vetter static struct drm_conn_prop_enum_list drm_connector_enum_list[] = { 7152217195SDaniel Vetter { DRM_MODE_CONNECTOR_Unknown, "Unknown" }, 7252217195SDaniel Vetter { DRM_MODE_CONNECTOR_VGA, "VGA" }, 7352217195SDaniel Vetter { DRM_MODE_CONNECTOR_DVII, "DVI-I" }, 7452217195SDaniel Vetter { DRM_MODE_CONNECTOR_DVID, "DVI-D" }, 7552217195SDaniel Vetter { DRM_MODE_CONNECTOR_DVIA, "DVI-A" }, 7652217195SDaniel Vetter { DRM_MODE_CONNECTOR_Composite, "Composite" }, 7752217195SDaniel Vetter { DRM_MODE_CONNECTOR_SVIDEO, "SVIDEO" }, 7852217195SDaniel Vetter { DRM_MODE_CONNECTOR_LVDS, "LVDS" }, 7952217195SDaniel Vetter { DRM_MODE_CONNECTOR_Component, "Component" }, 8052217195SDaniel Vetter { DRM_MODE_CONNECTOR_9PinDIN, "DIN" }, 8152217195SDaniel Vetter { DRM_MODE_CONNECTOR_DisplayPort, "DP" }, 8252217195SDaniel Vetter { DRM_MODE_CONNECTOR_HDMIA, "HDMI-A" }, 8352217195SDaniel Vetter { DRM_MODE_CONNECTOR_HDMIB, "HDMI-B" }, 8452217195SDaniel Vetter { DRM_MODE_CONNECTOR_TV, "TV" }, 8552217195SDaniel Vetter { DRM_MODE_CONNECTOR_eDP, "eDP" }, 8652217195SDaniel Vetter { DRM_MODE_CONNECTOR_VIRTUAL, "Virtual" }, 8752217195SDaniel Vetter { DRM_MODE_CONNECTOR_DSI, "DSI" }, 8852217195SDaniel Vetter { DRM_MODE_CONNECTOR_DPI, "DPI" }, 8952217195SDaniel Vetter }; 9052217195SDaniel Vetter 9152217195SDaniel Vetter void drm_connector_ida_init(void) 9252217195SDaniel Vetter { 9352217195SDaniel Vetter int i; 9452217195SDaniel Vetter 9552217195SDaniel Vetter for (i = 0; i < ARRAY_SIZE(drm_connector_enum_list); i++) 9652217195SDaniel Vetter ida_init(&drm_connector_enum_list[i].ida); 9752217195SDaniel Vetter } 9852217195SDaniel Vetter 9952217195SDaniel Vetter void drm_connector_ida_destroy(void) 10052217195SDaniel Vetter { 10152217195SDaniel Vetter int i; 10252217195SDaniel Vetter 10352217195SDaniel Vetter for (i = 0; i < ARRAY_SIZE(drm_connector_enum_list); i++) 10452217195SDaniel Vetter ida_destroy(&drm_connector_enum_list[i].ida); 10552217195SDaniel Vetter } 10652217195SDaniel Vetter 10752217195SDaniel Vetter /** 10852217195SDaniel Vetter * drm_connector_get_cmdline_mode - reads the user's cmdline mode 10952217195SDaniel Vetter * @connector: connector to quwery 11052217195SDaniel Vetter * 111ae2a6da8SDaniel Vetter * The kernel supports per-connector configuration of its consoles through 11252217195SDaniel Vetter * use of the video= parameter. This function parses that option and 11352217195SDaniel Vetter * extracts the user's specified mode (or enable/disable status) for a 11452217195SDaniel Vetter * particular connector. This is typically only used during the early fbdev 11552217195SDaniel Vetter * setup. 11652217195SDaniel Vetter */ 11752217195SDaniel Vetter static void drm_connector_get_cmdline_mode(struct drm_connector *connector) 11852217195SDaniel Vetter { 11952217195SDaniel Vetter struct drm_cmdline_mode *mode = &connector->cmdline_mode; 12052217195SDaniel Vetter char *option = NULL; 12152217195SDaniel Vetter 12252217195SDaniel Vetter if (fb_get_options(connector->name, &option)) 12352217195SDaniel Vetter return; 12452217195SDaniel Vetter 12552217195SDaniel Vetter if (!drm_mode_parse_command_line_for_connector(option, 12652217195SDaniel Vetter connector, 12752217195SDaniel Vetter mode)) 12852217195SDaniel Vetter return; 12952217195SDaniel Vetter 13052217195SDaniel Vetter if (mode->force) { 131*6140cf20SJani Nikula DRM_INFO("forcing %s connector %s\n", connector->name, 132*6140cf20SJani Nikula drm_get_connector_force_name(mode->force)); 13352217195SDaniel Vetter connector->force = mode->force; 13452217195SDaniel Vetter } 13552217195SDaniel Vetter 13652217195SDaniel Vetter DRM_DEBUG_KMS("cmdline mode for connector %s %dx%d@%dHz%s%s%s\n", 13752217195SDaniel Vetter connector->name, 13852217195SDaniel Vetter mode->xres, mode->yres, 13952217195SDaniel Vetter mode->refresh_specified ? mode->refresh : 60, 14052217195SDaniel Vetter mode->rb ? " reduced blanking" : "", 14152217195SDaniel Vetter mode->margins ? " with margins" : "", 14252217195SDaniel Vetter mode->interlace ? " interlaced" : ""); 14352217195SDaniel Vetter } 14452217195SDaniel Vetter 14552217195SDaniel Vetter static void drm_connector_free(struct kref *kref) 14652217195SDaniel Vetter { 14752217195SDaniel Vetter struct drm_connector *connector = 14852217195SDaniel Vetter container_of(kref, struct drm_connector, base.refcount); 14952217195SDaniel Vetter struct drm_device *dev = connector->dev; 15052217195SDaniel Vetter 15152217195SDaniel Vetter drm_mode_object_unregister(dev, &connector->base); 15252217195SDaniel Vetter connector->funcs->destroy(connector); 15352217195SDaniel Vetter } 15452217195SDaniel Vetter 15552217195SDaniel Vetter /** 15652217195SDaniel Vetter * drm_connector_init - Init a preallocated connector 15752217195SDaniel Vetter * @dev: DRM device 15852217195SDaniel Vetter * @connector: the connector to init 15952217195SDaniel Vetter * @funcs: callbacks for this connector 16052217195SDaniel Vetter * @connector_type: user visible type of the connector 16152217195SDaniel Vetter * 16252217195SDaniel Vetter * Initialises a preallocated connector. Connectors should be 16352217195SDaniel Vetter * subclassed as part of driver connector objects. 16452217195SDaniel Vetter * 16552217195SDaniel Vetter * Returns: 16652217195SDaniel Vetter * Zero on success, error code on failure. 16752217195SDaniel Vetter */ 16852217195SDaniel Vetter int drm_connector_init(struct drm_device *dev, 16952217195SDaniel Vetter struct drm_connector *connector, 17052217195SDaniel Vetter const struct drm_connector_funcs *funcs, 17152217195SDaniel Vetter int connector_type) 17252217195SDaniel Vetter { 17352217195SDaniel Vetter struct drm_mode_config *config = &dev->mode_config; 17452217195SDaniel Vetter int ret; 17552217195SDaniel Vetter struct ida *connector_ida = 17652217195SDaniel Vetter &drm_connector_enum_list[connector_type].ida; 17752217195SDaniel Vetter 17852217195SDaniel Vetter ret = drm_mode_object_get_reg(dev, &connector->base, 17952217195SDaniel Vetter DRM_MODE_OBJECT_CONNECTOR, 18052217195SDaniel Vetter false, drm_connector_free); 18152217195SDaniel Vetter if (ret) 182613051daSDaniel Vetter return ret; 18352217195SDaniel Vetter 18452217195SDaniel Vetter connector->base.properties = &connector->properties; 18552217195SDaniel Vetter connector->dev = dev; 18652217195SDaniel Vetter connector->funcs = funcs; 18752217195SDaniel Vetter 18852217195SDaniel Vetter ret = ida_simple_get(&config->connector_ida, 0, 0, GFP_KERNEL); 18952217195SDaniel Vetter if (ret < 0) 19052217195SDaniel Vetter goto out_put; 19152217195SDaniel Vetter connector->index = ret; 19252217195SDaniel Vetter ret = 0; 19352217195SDaniel Vetter 19452217195SDaniel Vetter connector->connector_type = connector_type; 19552217195SDaniel Vetter connector->connector_type_id = 19652217195SDaniel Vetter ida_simple_get(connector_ida, 1, 0, GFP_KERNEL); 19752217195SDaniel Vetter if (connector->connector_type_id < 0) { 19852217195SDaniel Vetter ret = connector->connector_type_id; 19952217195SDaniel Vetter goto out_put_id; 20052217195SDaniel Vetter } 20152217195SDaniel Vetter connector->name = 20252217195SDaniel Vetter kasprintf(GFP_KERNEL, "%s-%d", 20352217195SDaniel Vetter drm_connector_enum_list[connector_type].name, 20452217195SDaniel Vetter connector->connector_type_id); 20552217195SDaniel Vetter if (!connector->name) { 20652217195SDaniel Vetter ret = -ENOMEM; 20752217195SDaniel Vetter goto out_put_type_id; 20852217195SDaniel Vetter } 20952217195SDaniel Vetter 21052217195SDaniel Vetter INIT_LIST_HEAD(&connector->probed_modes); 21152217195SDaniel Vetter INIT_LIST_HEAD(&connector->modes); 212e73ab00eSDaniel Vetter mutex_init(&connector->mutex); 21352217195SDaniel Vetter connector->edid_blob_ptr = NULL; 21452217195SDaniel Vetter connector->status = connector_status_unknown; 21552217195SDaniel Vetter 21652217195SDaniel Vetter drm_connector_get_cmdline_mode(connector); 21752217195SDaniel Vetter 21852217195SDaniel Vetter /* We should add connectors at the end to avoid upsetting the connector 21952217195SDaniel Vetter * index too much. */ 220613051daSDaniel Vetter spin_lock_irq(&config->connector_list_lock); 22152217195SDaniel Vetter list_add_tail(&connector->head, &config->connector_list); 22252217195SDaniel Vetter config->num_connector++; 223613051daSDaniel Vetter spin_unlock_irq(&config->connector_list_lock); 22452217195SDaniel Vetter 22552217195SDaniel Vetter if (connector_type != DRM_MODE_CONNECTOR_VIRTUAL) 22652217195SDaniel Vetter drm_object_attach_property(&connector->base, 22752217195SDaniel Vetter config->edid_property, 22852217195SDaniel Vetter 0); 22952217195SDaniel Vetter 23052217195SDaniel Vetter drm_object_attach_property(&connector->base, 23152217195SDaniel Vetter config->dpms_property, 0); 23252217195SDaniel Vetter 23340ee6fbeSManasi Navare drm_object_attach_property(&connector->base, 23440ee6fbeSManasi Navare config->link_status_property, 23540ee6fbeSManasi Navare 0); 23640ee6fbeSManasi Navare 23752217195SDaniel Vetter if (drm_core_check_feature(dev, DRIVER_ATOMIC)) { 23852217195SDaniel Vetter drm_object_attach_property(&connector->base, config->prop_crtc_id, 0); 23952217195SDaniel Vetter } 24052217195SDaniel Vetter 24152217195SDaniel Vetter connector->debugfs_entry = NULL; 24252217195SDaniel Vetter out_put_type_id: 24352217195SDaniel Vetter if (ret) 244587680c1SChristophe JAILLET ida_simple_remove(connector_ida, connector->connector_type_id); 24552217195SDaniel Vetter out_put_id: 24652217195SDaniel Vetter if (ret) 247587680c1SChristophe JAILLET ida_simple_remove(&config->connector_ida, connector->index); 24852217195SDaniel Vetter out_put: 24952217195SDaniel Vetter if (ret) 25052217195SDaniel Vetter drm_mode_object_unregister(dev, &connector->base); 25152217195SDaniel Vetter 25252217195SDaniel Vetter return ret; 25352217195SDaniel Vetter } 25452217195SDaniel Vetter EXPORT_SYMBOL(drm_connector_init); 25552217195SDaniel Vetter 25652217195SDaniel Vetter /** 25752217195SDaniel Vetter * drm_mode_connector_attach_encoder - attach a connector to an encoder 25852217195SDaniel Vetter * @connector: connector to attach 25952217195SDaniel Vetter * @encoder: encoder to attach @connector to 26052217195SDaniel Vetter * 26152217195SDaniel Vetter * This function links up a connector to an encoder. Note that the routing 26252217195SDaniel Vetter * restrictions between encoders and crtcs are exposed to userspace through the 26352217195SDaniel Vetter * possible_clones and possible_crtcs bitmasks. 26452217195SDaniel Vetter * 26552217195SDaniel Vetter * Returns: 26652217195SDaniel Vetter * Zero on success, negative errno on failure. 26752217195SDaniel Vetter */ 26852217195SDaniel Vetter int drm_mode_connector_attach_encoder(struct drm_connector *connector, 26952217195SDaniel Vetter struct drm_encoder *encoder) 27052217195SDaniel Vetter { 27152217195SDaniel Vetter int i; 27252217195SDaniel Vetter 27352217195SDaniel Vetter /* 27452217195SDaniel Vetter * In the past, drivers have attempted to model the static association 27552217195SDaniel Vetter * of connector to encoder in simple connector/encoder devices using a 27652217195SDaniel Vetter * direct assignment of connector->encoder = encoder. This connection 27752217195SDaniel Vetter * is a logical one and the responsibility of the core, so drivers are 27852217195SDaniel Vetter * expected not to mess with this. 27952217195SDaniel Vetter * 28052217195SDaniel Vetter * Note that the error return should've been enough here, but a large 28152217195SDaniel Vetter * majority of drivers ignores the return value, so add in a big WARN 28252217195SDaniel Vetter * to get people's attention. 28352217195SDaniel Vetter */ 28452217195SDaniel Vetter if (WARN_ON(connector->encoder)) 28552217195SDaniel Vetter return -EINVAL; 28652217195SDaniel Vetter 28752217195SDaniel Vetter for (i = 0; i < DRM_CONNECTOR_MAX_ENCODER; i++) { 28852217195SDaniel Vetter if (connector->encoder_ids[i] == 0) { 28952217195SDaniel Vetter connector->encoder_ids[i] = encoder->base.id; 29052217195SDaniel Vetter return 0; 29152217195SDaniel Vetter } 29252217195SDaniel Vetter } 29352217195SDaniel Vetter return -ENOMEM; 29452217195SDaniel Vetter } 29552217195SDaniel Vetter EXPORT_SYMBOL(drm_mode_connector_attach_encoder); 29652217195SDaniel Vetter 29752217195SDaniel Vetter static void drm_mode_remove(struct drm_connector *connector, 29852217195SDaniel Vetter struct drm_display_mode *mode) 29952217195SDaniel Vetter { 30052217195SDaniel Vetter list_del(&mode->head); 30152217195SDaniel Vetter drm_mode_destroy(connector->dev, mode); 30252217195SDaniel Vetter } 30352217195SDaniel Vetter 30452217195SDaniel Vetter /** 30552217195SDaniel Vetter * drm_connector_cleanup - cleans up an initialised connector 30652217195SDaniel Vetter * @connector: connector to cleanup 30752217195SDaniel Vetter * 30852217195SDaniel Vetter * Cleans up the connector but doesn't free the object. 30952217195SDaniel Vetter */ 31052217195SDaniel Vetter void drm_connector_cleanup(struct drm_connector *connector) 31152217195SDaniel Vetter { 31252217195SDaniel Vetter struct drm_device *dev = connector->dev; 31352217195SDaniel Vetter struct drm_display_mode *mode, *t; 31452217195SDaniel Vetter 31552217195SDaniel Vetter /* The connector should have been removed from userspace long before 31652217195SDaniel Vetter * it is finally destroyed. 31752217195SDaniel Vetter */ 31852217195SDaniel Vetter if (WARN_ON(connector->registered)) 31952217195SDaniel Vetter drm_connector_unregister(connector); 32052217195SDaniel Vetter 32152217195SDaniel Vetter if (connector->tile_group) { 32252217195SDaniel Vetter drm_mode_put_tile_group(dev, connector->tile_group); 32352217195SDaniel Vetter connector->tile_group = NULL; 32452217195SDaniel Vetter } 32552217195SDaniel Vetter 32652217195SDaniel Vetter list_for_each_entry_safe(mode, t, &connector->probed_modes, head) 32752217195SDaniel Vetter drm_mode_remove(connector, mode); 32852217195SDaniel Vetter 32952217195SDaniel Vetter list_for_each_entry_safe(mode, t, &connector->modes, head) 33052217195SDaniel Vetter drm_mode_remove(connector, mode); 33152217195SDaniel Vetter 3329a47dba1SChristophe JAILLET ida_simple_remove(&drm_connector_enum_list[connector->connector_type].ida, 33352217195SDaniel Vetter connector->connector_type_id); 33452217195SDaniel Vetter 3359a47dba1SChristophe JAILLET ida_simple_remove(&dev->mode_config.connector_ida, 33652217195SDaniel Vetter connector->index); 33752217195SDaniel Vetter 33852217195SDaniel Vetter kfree(connector->display_info.bus_formats); 33952217195SDaniel Vetter drm_mode_object_unregister(dev, &connector->base); 34052217195SDaniel Vetter kfree(connector->name); 34152217195SDaniel Vetter connector->name = NULL; 342613051daSDaniel Vetter spin_lock_irq(&dev->mode_config.connector_list_lock); 34352217195SDaniel Vetter list_del(&connector->head); 34452217195SDaniel Vetter dev->mode_config.num_connector--; 345613051daSDaniel Vetter spin_unlock_irq(&dev->mode_config.connector_list_lock); 34652217195SDaniel Vetter 34752217195SDaniel Vetter WARN_ON(connector->state && !connector->funcs->atomic_destroy_state); 34852217195SDaniel Vetter if (connector->state && connector->funcs->atomic_destroy_state) 34952217195SDaniel Vetter connector->funcs->atomic_destroy_state(connector, 35052217195SDaniel Vetter connector->state); 35152217195SDaniel Vetter 352e73ab00eSDaniel Vetter mutex_destroy(&connector->mutex); 353e73ab00eSDaniel Vetter 35452217195SDaniel Vetter memset(connector, 0, sizeof(*connector)); 35552217195SDaniel Vetter } 35652217195SDaniel Vetter EXPORT_SYMBOL(drm_connector_cleanup); 35752217195SDaniel Vetter 35852217195SDaniel Vetter /** 35952217195SDaniel Vetter * drm_connector_register - register a connector 36052217195SDaniel Vetter * @connector: the connector to register 36152217195SDaniel Vetter * 36252217195SDaniel Vetter * Register userspace interfaces for a connector 36352217195SDaniel Vetter * 36452217195SDaniel Vetter * Returns: 36552217195SDaniel Vetter * Zero on success, error code on failure. 36652217195SDaniel Vetter */ 36752217195SDaniel Vetter int drm_connector_register(struct drm_connector *connector) 36852217195SDaniel Vetter { 369e73ab00eSDaniel Vetter int ret = 0; 37052217195SDaniel Vetter 371e6e7b48bSDaniel Vetter if (!connector->dev->registered) 372e6e7b48bSDaniel Vetter return 0; 373e6e7b48bSDaniel Vetter 374e73ab00eSDaniel Vetter mutex_lock(&connector->mutex); 37552217195SDaniel Vetter if (connector->registered) 376e73ab00eSDaniel Vetter goto unlock; 37752217195SDaniel Vetter 37852217195SDaniel Vetter ret = drm_sysfs_connector_add(connector); 37952217195SDaniel Vetter if (ret) 380e73ab00eSDaniel Vetter goto unlock; 38152217195SDaniel Vetter 38252217195SDaniel Vetter ret = drm_debugfs_connector_add(connector); 38352217195SDaniel Vetter if (ret) { 38452217195SDaniel Vetter goto err_sysfs; 38552217195SDaniel Vetter } 38652217195SDaniel Vetter 38752217195SDaniel Vetter if (connector->funcs->late_register) { 38852217195SDaniel Vetter ret = connector->funcs->late_register(connector); 38952217195SDaniel Vetter if (ret) 39052217195SDaniel Vetter goto err_debugfs; 39152217195SDaniel Vetter } 39252217195SDaniel Vetter 39352217195SDaniel Vetter drm_mode_object_register(connector->dev, &connector->base); 39452217195SDaniel Vetter 39552217195SDaniel Vetter connector->registered = true; 396e73ab00eSDaniel Vetter goto unlock; 39752217195SDaniel Vetter 39852217195SDaniel Vetter err_debugfs: 39952217195SDaniel Vetter drm_debugfs_connector_remove(connector); 40052217195SDaniel Vetter err_sysfs: 40152217195SDaniel Vetter drm_sysfs_connector_remove(connector); 402e73ab00eSDaniel Vetter unlock: 403e73ab00eSDaniel Vetter mutex_unlock(&connector->mutex); 40452217195SDaniel Vetter return ret; 40552217195SDaniel Vetter } 40652217195SDaniel Vetter EXPORT_SYMBOL(drm_connector_register); 40752217195SDaniel Vetter 40852217195SDaniel Vetter /** 40952217195SDaniel Vetter * drm_connector_unregister - unregister a connector 41052217195SDaniel Vetter * @connector: the connector to unregister 41152217195SDaniel Vetter * 41252217195SDaniel Vetter * Unregister userspace interfaces for a connector 41352217195SDaniel Vetter */ 41452217195SDaniel Vetter void drm_connector_unregister(struct drm_connector *connector) 41552217195SDaniel Vetter { 416e73ab00eSDaniel Vetter mutex_lock(&connector->mutex); 417e73ab00eSDaniel Vetter if (!connector->registered) { 418e73ab00eSDaniel Vetter mutex_unlock(&connector->mutex); 41952217195SDaniel Vetter return; 420e73ab00eSDaniel Vetter } 42152217195SDaniel Vetter 42252217195SDaniel Vetter if (connector->funcs->early_unregister) 42352217195SDaniel Vetter connector->funcs->early_unregister(connector); 42452217195SDaniel Vetter 42552217195SDaniel Vetter drm_sysfs_connector_remove(connector); 42652217195SDaniel Vetter drm_debugfs_connector_remove(connector); 42752217195SDaniel Vetter 42852217195SDaniel Vetter connector->registered = false; 429e73ab00eSDaniel Vetter mutex_unlock(&connector->mutex); 43052217195SDaniel Vetter } 43152217195SDaniel Vetter EXPORT_SYMBOL(drm_connector_unregister); 43252217195SDaniel Vetter 43352217195SDaniel Vetter void drm_connector_unregister_all(struct drm_device *dev) 43452217195SDaniel Vetter { 43552217195SDaniel Vetter struct drm_connector *connector; 436613051daSDaniel Vetter struct drm_connector_list_iter conn_iter; 43752217195SDaniel Vetter 438613051daSDaniel Vetter drm_connector_list_iter_get(dev, &conn_iter); 439613051daSDaniel Vetter drm_for_each_connector_iter(connector, &conn_iter) 44052217195SDaniel Vetter drm_connector_unregister(connector); 441613051daSDaniel Vetter drm_connector_list_iter_put(&conn_iter); 44252217195SDaniel Vetter } 44352217195SDaniel Vetter 44452217195SDaniel Vetter int drm_connector_register_all(struct drm_device *dev) 44552217195SDaniel Vetter { 44652217195SDaniel Vetter struct drm_connector *connector; 447613051daSDaniel Vetter struct drm_connector_list_iter conn_iter; 448613051daSDaniel Vetter int ret = 0; 44952217195SDaniel Vetter 450613051daSDaniel Vetter drm_connector_list_iter_get(dev, &conn_iter); 451613051daSDaniel Vetter drm_for_each_connector_iter(connector, &conn_iter) { 45252217195SDaniel Vetter ret = drm_connector_register(connector); 45352217195SDaniel Vetter if (ret) 454613051daSDaniel Vetter break; 45552217195SDaniel Vetter } 456613051daSDaniel Vetter drm_connector_list_iter_put(&conn_iter); 45752217195SDaniel Vetter 458613051daSDaniel Vetter if (ret) 45952217195SDaniel Vetter drm_connector_unregister_all(dev); 46052217195SDaniel Vetter return ret; 46152217195SDaniel Vetter } 46252217195SDaniel Vetter 46352217195SDaniel Vetter /** 46452217195SDaniel Vetter * drm_get_connector_status_name - return a string for connector status 46552217195SDaniel Vetter * @status: connector status to compute name of 46652217195SDaniel Vetter * 46752217195SDaniel Vetter * In contrast to the other drm_get_*_name functions this one here returns a 46852217195SDaniel Vetter * const pointer and hence is threadsafe. 46952217195SDaniel Vetter */ 47052217195SDaniel Vetter const char *drm_get_connector_status_name(enum drm_connector_status status) 47152217195SDaniel Vetter { 47252217195SDaniel Vetter if (status == connector_status_connected) 47352217195SDaniel Vetter return "connected"; 47452217195SDaniel Vetter else if (status == connector_status_disconnected) 47552217195SDaniel Vetter return "disconnected"; 47652217195SDaniel Vetter else 47752217195SDaniel Vetter return "unknown"; 47852217195SDaniel Vetter } 47952217195SDaniel Vetter EXPORT_SYMBOL(drm_get_connector_status_name); 48052217195SDaniel Vetter 481*6140cf20SJani Nikula /** 482*6140cf20SJani Nikula * drm_get_connector_force_name - return a string for connector force 483*6140cf20SJani Nikula * @force: connector force to get name of 484*6140cf20SJani Nikula * 485*6140cf20SJani Nikula * Returns: const pointer to name. 486*6140cf20SJani Nikula */ 487*6140cf20SJani Nikula const char *drm_get_connector_force_name(enum drm_connector_force force) 488*6140cf20SJani Nikula { 489*6140cf20SJani Nikula switch (force) { 490*6140cf20SJani Nikula case DRM_FORCE_UNSPECIFIED: 491*6140cf20SJani Nikula return "unspecified"; 492*6140cf20SJani Nikula case DRM_FORCE_OFF: 493*6140cf20SJani Nikula return "off"; 494*6140cf20SJani Nikula case DRM_FORCE_ON: 495*6140cf20SJani Nikula return "on"; 496*6140cf20SJani Nikula case DRM_FORCE_ON_DIGITAL: 497*6140cf20SJani Nikula return "digital"; 498*6140cf20SJani Nikula default: 499*6140cf20SJani Nikula return "unknown"; 500*6140cf20SJani Nikula } 501*6140cf20SJani Nikula } 502*6140cf20SJani Nikula 503613051daSDaniel Vetter #ifdef CONFIG_LOCKDEP 504613051daSDaniel Vetter static struct lockdep_map connector_list_iter_dep_map = { 505613051daSDaniel Vetter .name = "drm_connector_list_iter" 506613051daSDaniel Vetter }; 507613051daSDaniel Vetter #endif 508613051daSDaniel Vetter 509613051daSDaniel Vetter /** 510613051daSDaniel Vetter * drm_connector_list_iter_get - initialize a connector_list iterator 511613051daSDaniel Vetter * @dev: DRM device 512613051daSDaniel Vetter * @iter: connector_list iterator 513613051daSDaniel Vetter * 514d574528aSDaniel Vetter * Sets @iter up to walk the &drm_mode_config.connector_list of @dev. @iter 515613051daSDaniel Vetter * must always be cleaned up again by calling drm_connector_list_iter_put(). 516613051daSDaniel Vetter * Iteration itself happens using drm_connector_list_iter_next() or 517613051daSDaniel Vetter * drm_for_each_connector_iter(). 518613051daSDaniel Vetter */ 519613051daSDaniel Vetter void drm_connector_list_iter_get(struct drm_device *dev, 520613051daSDaniel Vetter struct drm_connector_list_iter *iter) 521613051daSDaniel Vetter { 522613051daSDaniel Vetter iter->dev = dev; 523613051daSDaniel Vetter iter->conn = NULL; 524613051daSDaniel Vetter lock_acquire_shared_recursive(&connector_list_iter_dep_map, 0, 1, NULL, _RET_IP_); 525613051daSDaniel Vetter } 526613051daSDaniel Vetter EXPORT_SYMBOL(drm_connector_list_iter_get); 527613051daSDaniel Vetter 528613051daSDaniel Vetter /** 529613051daSDaniel Vetter * drm_connector_list_iter_next - return next connector 530613051daSDaniel Vetter * @iter: connectr_list iterator 531613051daSDaniel Vetter * 532613051daSDaniel Vetter * Returns the next connector for @iter, or NULL when the list walk has 533613051daSDaniel Vetter * completed. 534613051daSDaniel Vetter */ 535613051daSDaniel Vetter struct drm_connector * 536613051daSDaniel Vetter drm_connector_list_iter_next(struct drm_connector_list_iter *iter) 537613051daSDaniel Vetter { 538613051daSDaniel Vetter struct drm_connector *old_conn = iter->conn; 539613051daSDaniel Vetter struct drm_mode_config *config = &iter->dev->mode_config; 540613051daSDaniel Vetter struct list_head *lhead; 541613051daSDaniel Vetter unsigned long flags; 542613051daSDaniel Vetter 543613051daSDaniel Vetter spin_lock_irqsave(&config->connector_list_lock, flags); 544613051daSDaniel Vetter lhead = old_conn ? &old_conn->head : &config->connector_list; 545613051daSDaniel Vetter 546613051daSDaniel Vetter do { 547613051daSDaniel Vetter if (lhead->next == &config->connector_list) { 548613051daSDaniel Vetter iter->conn = NULL; 549613051daSDaniel Vetter break; 550613051daSDaniel Vetter } 551613051daSDaniel Vetter 552613051daSDaniel Vetter lhead = lhead->next; 553613051daSDaniel Vetter iter->conn = list_entry(lhead, struct drm_connector, head); 554613051daSDaniel Vetter 555613051daSDaniel Vetter /* loop until it's not a zombie connector */ 556613051daSDaniel Vetter } while (!kref_get_unless_zero(&iter->conn->base.refcount)); 557613051daSDaniel Vetter spin_unlock_irqrestore(&config->connector_list_lock, flags); 558613051daSDaniel Vetter 559613051daSDaniel Vetter if (old_conn) 560613051daSDaniel Vetter drm_connector_unreference(old_conn); 561613051daSDaniel Vetter 562613051daSDaniel Vetter return iter->conn; 563613051daSDaniel Vetter } 564613051daSDaniel Vetter EXPORT_SYMBOL(drm_connector_list_iter_next); 565613051daSDaniel Vetter 566613051daSDaniel Vetter /** 567613051daSDaniel Vetter * drm_connector_list_iter_put - tear down a connector_list iterator 568613051daSDaniel Vetter * @iter: connector_list iterator 569613051daSDaniel Vetter * 570613051daSDaniel Vetter * Tears down @iter and releases any resources (like &drm_connector references) 571613051daSDaniel Vetter * acquired while walking the list. This must always be called, both when the 572613051daSDaniel Vetter * iteration completes fully or when it was aborted without walking the entire 573613051daSDaniel Vetter * list. 574613051daSDaniel Vetter */ 575613051daSDaniel Vetter void drm_connector_list_iter_put(struct drm_connector_list_iter *iter) 576613051daSDaniel Vetter { 577613051daSDaniel Vetter iter->dev = NULL; 578613051daSDaniel Vetter if (iter->conn) 579613051daSDaniel Vetter drm_connector_unreference(iter->conn); 580613051daSDaniel Vetter lock_release(&connector_list_iter_dep_map, 0, _RET_IP_); 581613051daSDaniel Vetter } 582613051daSDaniel Vetter EXPORT_SYMBOL(drm_connector_list_iter_put); 583613051daSDaniel Vetter 58452217195SDaniel Vetter static const struct drm_prop_enum_list drm_subpixel_enum_list[] = { 58552217195SDaniel Vetter { SubPixelUnknown, "Unknown" }, 58652217195SDaniel Vetter { SubPixelHorizontalRGB, "Horizontal RGB" }, 58752217195SDaniel Vetter { SubPixelHorizontalBGR, "Horizontal BGR" }, 58852217195SDaniel Vetter { SubPixelVerticalRGB, "Vertical RGB" }, 58952217195SDaniel Vetter { SubPixelVerticalBGR, "Vertical BGR" }, 59052217195SDaniel Vetter { SubPixelNone, "None" }, 59152217195SDaniel Vetter }; 59252217195SDaniel Vetter 59352217195SDaniel Vetter /** 59452217195SDaniel Vetter * drm_get_subpixel_order_name - return a string for a given subpixel enum 59552217195SDaniel Vetter * @order: enum of subpixel_order 59652217195SDaniel Vetter * 59752217195SDaniel Vetter * Note you could abuse this and return something out of bounds, but that 59852217195SDaniel Vetter * would be a caller error. No unscrubbed user data should make it here. 59952217195SDaniel Vetter */ 60052217195SDaniel Vetter const char *drm_get_subpixel_order_name(enum subpixel_order order) 60152217195SDaniel Vetter { 60252217195SDaniel Vetter return drm_subpixel_enum_list[order].name; 60352217195SDaniel Vetter } 60452217195SDaniel Vetter EXPORT_SYMBOL(drm_get_subpixel_order_name); 60552217195SDaniel Vetter 60652217195SDaniel Vetter static const struct drm_prop_enum_list drm_dpms_enum_list[] = { 60752217195SDaniel Vetter { DRM_MODE_DPMS_ON, "On" }, 60852217195SDaniel Vetter { DRM_MODE_DPMS_STANDBY, "Standby" }, 60952217195SDaniel Vetter { DRM_MODE_DPMS_SUSPEND, "Suspend" }, 61052217195SDaniel Vetter { DRM_MODE_DPMS_OFF, "Off" } 61152217195SDaniel Vetter }; 61252217195SDaniel Vetter DRM_ENUM_NAME_FN(drm_get_dpms_name, drm_dpms_enum_list) 61352217195SDaniel Vetter 61440ee6fbeSManasi Navare static const struct drm_prop_enum_list drm_link_status_enum_list[] = { 61540ee6fbeSManasi Navare { DRM_MODE_LINK_STATUS_GOOD, "Good" }, 61640ee6fbeSManasi Navare { DRM_MODE_LINK_STATUS_BAD, "Bad" }, 61740ee6fbeSManasi Navare }; 61840ee6fbeSManasi Navare DRM_ENUM_NAME_FN(drm_get_link_status_name, drm_link_status_enum_list) 61940ee6fbeSManasi Navare 620b3c6c8bfSDaniel Vetter /** 621b3c6c8bfSDaniel Vetter * drm_display_info_set_bus_formats - set the supported bus formats 622b3c6c8bfSDaniel Vetter * @info: display info to store bus formats in 623b3c6c8bfSDaniel Vetter * @formats: array containing the supported bus formats 624b3c6c8bfSDaniel Vetter * @num_formats: the number of entries in the fmts array 625b3c6c8bfSDaniel Vetter * 626b3c6c8bfSDaniel Vetter * Store the supported bus formats in display info structure. 627b3c6c8bfSDaniel Vetter * See MEDIA_BUS_FMT_* definitions in include/uapi/linux/media-bus-format.h for 628b3c6c8bfSDaniel Vetter * a full list of available formats. 629b3c6c8bfSDaniel Vetter */ 630b3c6c8bfSDaniel Vetter int drm_display_info_set_bus_formats(struct drm_display_info *info, 631b3c6c8bfSDaniel Vetter const u32 *formats, 632b3c6c8bfSDaniel Vetter unsigned int num_formats) 633b3c6c8bfSDaniel Vetter { 634b3c6c8bfSDaniel Vetter u32 *fmts = NULL; 635b3c6c8bfSDaniel Vetter 636b3c6c8bfSDaniel Vetter if (!formats && num_formats) 637b3c6c8bfSDaniel Vetter return -EINVAL; 638b3c6c8bfSDaniel Vetter 639b3c6c8bfSDaniel Vetter if (formats && num_formats) { 640b3c6c8bfSDaniel Vetter fmts = kmemdup(formats, sizeof(*formats) * num_formats, 641b3c6c8bfSDaniel Vetter GFP_KERNEL); 642b3c6c8bfSDaniel Vetter if (!fmts) 643b3c6c8bfSDaniel Vetter return -ENOMEM; 644b3c6c8bfSDaniel Vetter } 645b3c6c8bfSDaniel Vetter 646b3c6c8bfSDaniel Vetter kfree(info->bus_formats); 647b3c6c8bfSDaniel Vetter info->bus_formats = fmts; 648b3c6c8bfSDaniel Vetter info->num_bus_formats = num_formats; 649b3c6c8bfSDaniel Vetter 650b3c6c8bfSDaniel Vetter return 0; 651b3c6c8bfSDaniel Vetter } 652b3c6c8bfSDaniel Vetter EXPORT_SYMBOL(drm_display_info_set_bus_formats); 653b3c6c8bfSDaniel Vetter 65452217195SDaniel Vetter /* Optional connector properties. */ 65552217195SDaniel Vetter static const struct drm_prop_enum_list drm_scaling_mode_enum_list[] = { 65652217195SDaniel Vetter { DRM_MODE_SCALE_NONE, "None" }, 65752217195SDaniel Vetter { DRM_MODE_SCALE_FULLSCREEN, "Full" }, 65852217195SDaniel Vetter { DRM_MODE_SCALE_CENTER, "Center" }, 65952217195SDaniel Vetter { DRM_MODE_SCALE_ASPECT, "Full aspect" }, 66052217195SDaniel Vetter }; 66152217195SDaniel Vetter 66252217195SDaniel Vetter static const struct drm_prop_enum_list drm_aspect_ratio_enum_list[] = { 66352217195SDaniel Vetter { DRM_MODE_PICTURE_ASPECT_NONE, "Automatic" }, 66452217195SDaniel Vetter { DRM_MODE_PICTURE_ASPECT_4_3, "4:3" }, 66552217195SDaniel Vetter { DRM_MODE_PICTURE_ASPECT_16_9, "16:9" }, 66652217195SDaniel Vetter }; 66752217195SDaniel Vetter 66852217195SDaniel Vetter static const struct drm_prop_enum_list drm_dvi_i_select_enum_list[] = { 66952217195SDaniel Vetter { DRM_MODE_SUBCONNECTOR_Automatic, "Automatic" }, /* DVI-I and TV-out */ 67052217195SDaniel Vetter { DRM_MODE_SUBCONNECTOR_DVID, "DVI-D" }, /* DVI-I */ 67152217195SDaniel Vetter { DRM_MODE_SUBCONNECTOR_DVIA, "DVI-A" }, /* DVI-I */ 67252217195SDaniel Vetter }; 67352217195SDaniel Vetter DRM_ENUM_NAME_FN(drm_get_dvi_i_select_name, drm_dvi_i_select_enum_list) 67452217195SDaniel Vetter 67552217195SDaniel Vetter static const struct drm_prop_enum_list drm_dvi_i_subconnector_enum_list[] = { 67652217195SDaniel Vetter { DRM_MODE_SUBCONNECTOR_Unknown, "Unknown" }, /* DVI-I and TV-out */ 67752217195SDaniel Vetter { DRM_MODE_SUBCONNECTOR_DVID, "DVI-D" }, /* DVI-I */ 67852217195SDaniel Vetter { DRM_MODE_SUBCONNECTOR_DVIA, "DVI-A" }, /* DVI-I */ 67952217195SDaniel Vetter }; 68052217195SDaniel Vetter DRM_ENUM_NAME_FN(drm_get_dvi_i_subconnector_name, 68152217195SDaniel Vetter drm_dvi_i_subconnector_enum_list) 68252217195SDaniel Vetter 68352217195SDaniel Vetter static const struct drm_prop_enum_list drm_tv_select_enum_list[] = { 68452217195SDaniel Vetter { DRM_MODE_SUBCONNECTOR_Automatic, "Automatic" }, /* DVI-I and TV-out */ 68552217195SDaniel Vetter { DRM_MODE_SUBCONNECTOR_Composite, "Composite" }, /* TV-out */ 68652217195SDaniel Vetter { DRM_MODE_SUBCONNECTOR_SVIDEO, "SVIDEO" }, /* TV-out */ 68752217195SDaniel Vetter { DRM_MODE_SUBCONNECTOR_Component, "Component" }, /* TV-out */ 68852217195SDaniel Vetter { DRM_MODE_SUBCONNECTOR_SCART, "SCART" }, /* TV-out */ 68952217195SDaniel Vetter }; 69052217195SDaniel Vetter DRM_ENUM_NAME_FN(drm_get_tv_select_name, drm_tv_select_enum_list) 69152217195SDaniel Vetter 69252217195SDaniel Vetter static const struct drm_prop_enum_list drm_tv_subconnector_enum_list[] = { 69352217195SDaniel Vetter { DRM_MODE_SUBCONNECTOR_Unknown, "Unknown" }, /* DVI-I and TV-out */ 69452217195SDaniel Vetter { DRM_MODE_SUBCONNECTOR_Composite, "Composite" }, /* TV-out */ 69552217195SDaniel Vetter { DRM_MODE_SUBCONNECTOR_SVIDEO, "SVIDEO" }, /* TV-out */ 69652217195SDaniel Vetter { DRM_MODE_SUBCONNECTOR_Component, "Component" }, /* TV-out */ 69752217195SDaniel Vetter { DRM_MODE_SUBCONNECTOR_SCART, "SCART" }, /* TV-out */ 69852217195SDaniel Vetter }; 69952217195SDaniel Vetter DRM_ENUM_NAME_FN(drm_get_tv_subconnector_name, 70052217195SDaniel Vetter drm_tv_subconnector_enum_list) 70152217195SDaniel Vetter 7024ada6f22SDaniel Vetter /** 7034ada6f22SDaniel Vetter * DOC: standard connector properties 7044ada6f22SDaniel Vetter * 7054ada6f22SDaniel Vetter * DRM connectors have a few standardized properties: 7064ada6f22SDaniel Vetter * 7074ada6f22SDaniel Vetter * EDID: 7084ada6f22SDaniel Vetter * Blob property which contains the current EDID read from the sink. This 7094ada6f22SDaniel Vetter * is useful to parse sink identification information like vendor, model 7104ada6f22SDaniel Vetter * and serial. Drivers should update this property by calling 7114ada6f22SDaniel Vetter * drm_mode_connector_update_edid_property(), usually after having parsed 7124ada6f22SDaniel Vetter * the EDID using drm_add_edid_modes(). Userspace cannot change this 7134ada6f22SDaniel Vetter * property. 7144ada6f22SDaniel Vetter * DPMS: 7154ada6f22SDaniel Vetter * Legacy property for setting the power state of the connector. For atomic 7164ada6f22SDaniel Vetter * drivers this is only provided for backwards compatibility with existing 7174ada6f22SDaniel Vetter * drivers, it remaps to controlling the "ACTIVE" property on the CRTC the 7184ada6f22SDaniel Vetter * connector is linked to. Drivers should never set this property directly, 719d574528aSDaniel Vetter * it is handled by the DRM core by calling the &drm_connector_funcs.dpms 720d574528aSDaniel Vetter * callback. Atomic drivers should implement this hook using 7214ada6f22SDaniel Vetter * drm_atomic_helper_connector_dpms(). This is the only property standard 7224ada6f22SDaniel Vetter * connector property that userspace can change. 7234ada6f22SDaniel Vetter * PATH: 7244ada6f22SDaniel Vetter * Connector path property to identify how this sink is physically 7254ada6f22SDaniel Vetter * connected. Used by DP MST. This should be set by calling 7264ada6f22SDaniel Vetter * drm_mode_connector_set_path_property(), in the case of DP MST with the 7274ada6f22SDaniel Vetter * path property the MST manager created. Userspace cannot change this 7284ada6f22SDaniel Vetter * property. 7294ada6f22SDaniel Vetter * TILE: 7304ada6f22SDaniel Vetter * Connector tile group property to indicate how a set of DRM connector 7314ada6f22SDaniel Vetter * compose together into one logical screen. This is used by both high-res 7324ada6f22SDaniel Vetter * external screens (often only using a single cable, but exposing multiple 7334ada6f22SDaniel Vetter * DP MST sinks), or high-res integrated panels (like dual-link DSI) which 7344ada6f22SDaniel Vetter * are not gen-locked. Note that for tiled panels which are genlocked, like 7354ada6f22SDaniel Vetter * dual-link LVDS or dual-link DSI, the driver should try to not expose the 7364ada6f22SDaniel Vetter * tiling and virtualize both &drm_crtc and &drm_plane if needed. Drivers 7374ada6f22SDaniel Vetter * should update this value using drm_mode_connector_set_tile_property(). 7384ada6f22SDaniel Vetter * Userspace cannot change this property. 73940ee6fbeSManasi Navare * link-status: 74040ee6fbeSManasi Navare * Connector link-status property to indicate the status of link. The default 74140ee6fbeSManasi Navare * value of link-status is "GOOD". If something fails during or after modeset, 74240ee6fbeSManasi Navare * the kernel driver may set this to "BAD" and issue a hotplug uevent. Drivers 74340ee6fbeSManasi Navare * should update this value using drm_mode_connector_set_link_status_property(). 7444ada6f22SDaniel Vetter * 7454ada6f22SDaniel Vetter * Connectors also have one standardized atomic property: 7464ada6f22SDaniel Vetter * 7474ada6f22SDaniel Vetter * CRTC_ID: 7484ada6f22SDaniel Vetter * Mode object ID of the &drm_crtc this connector should be connected to. 7494ada6f22SDaniel Vetter */ 7504ada6f22SDaniel Vetter 75152217195SDaniel Vetter int drm_connector_create_standard_properties(struct drm_device *dev) 75252217195SDaniel Vetter { 75352217195SDaniel Vetter struct drm_property *prop; 75452217195SDaniel Vetter 75552217195SDaniel Vetter prop = drm_property_create(dev, DRM_MODE_PROP_BLOB | 75652217195SDaniel Vetter DRM_MODE_PROP_IMMUTABLE, 75752217195SDaniel Vetter "EDID", 0); 75852217195SDaniel Vetter if (!prop) 75952217195SDaniel Vetter return -ENOMEM; 76052217195SDaniel Vetter dev->mode_config.edid_property = prop; 76152217195SDaniel Vetter 76252217195SDaniel Vetter prop = drm_property_create_enum(dev, 0, 76352217195SDaniel Vetter "DPMS", drm_dpms_enum_list, 76452217195SDaniel Vetter ARRAY_SIZE(drm_dpms_enum_list)); 76552217195SDaniel Vetter if (!prop) 76652217195SDaniel Vetter return -ENOMEM; 76752217195SDaniel Vetter dev->mode_config.dpms_property = prop; 76852217195SDaniel Vetter 76952217195SDaniel Vetter prop = drm_property_create(dev, 77052217195SDaniel Vetter DRM_MODE_PROP_BLOB | 77152217195SDaniel Vetter DRM_MODE_PROP_IMMUTABLE, 77252217195SDaniel Vetter "PATH", 0); 77352217195SDaniel Vetter if (!prop) 77452217195SDaniel Vetter return -ENOMEM; 77552217195SDaniel Vetter dev->mode_config.path_property = prop; 77652217195SDaniel Vetter 77752217195SDaniel Vetter prop = drm_property_create(dev, 77852217195SDaniel Vetter DRM_MODE_PROP_BLOB | 77952217195SDaniel Vetter DRM_MODE_PROP_IMMUTABLE, 78052217195SDaniel Vetter "TILE", 0); 78152217195SDaniel Vetter if (!prop) 78252217195SDaniel Vetter return -ENOMEM; 78352217195SDaniel Vetter dev->mode_config.tile_property = prop; 78452217195SDaniel Vetter 78540ee6fbeSManasi Navare prop = drm_property_create_enum(dev, 0, "link-status", 78640ee6fbeSManasi Navare drm_link_status_enum_list, 78740ee6fbeSManasi Navare ARRAY_SIZE(drm_link_status_enum_list)); 78840ee6fbeSManasi Navare if (!prop) 78940ee6fbeSManasi Navare return -ENOMEM; 79040ee6fbeSManasi Navare dev->mode_config.link_status_property = prop; 79140ee6fbeSManasi Navare 79252217195SDaniel Vetter return 0; 79352217195SDaniel Vetter } 79452217195SDaniel Vetter 79552217195SDaniel Vetter /** 79652217195SDaniel Vetter * drm_mode_create_dvi_i_properties - create DVI-I specific connector properties 79752217195SDaniel Vetter * @dev: DRM device 79852217195SDaniel Vetter * 79952217195SDaniel Vetter * Called by a driver the first time a DVI-I connector is made. 80052217195SDaniel Vetter */ 80152217195SDaniel Vetter int drm_mode_create_dvi_i_properties(struct drm_device *dev) 80252217195SDaniel Vetter { 80352217195SDaniel Vetter struct drm_property *dvi_i_selector; 80452217195SDaniel Vetter struct drm_property *dvi_i_subconnector; 80552217195SDaniel Vetter 80652217195SDaniel Vetter if (dev->mode_config.dvi_i_select_subconnector_property) 80752217195SDaniel Vetter return 0; 80852217195SDaniel Vetter 80952217195SDaniel Vetter dvi_i_selector = 81052217195SDaniel Vetter drm_property_create_enum(dev, 0, 81152217195SDaniel Vetter "select subconnector", 81252217195SDaniel Vetter drm_dvi_i_select_enum_list, 81352217195SDaniel Vetter ARRAY_SIZE(drm_dvi_i_select_enum_list)); 81452217195SDaniel Vetter dev->mode_config.dvi_i_select_subconnector_property = dvi_i_selector; 81552217195SDaniel Vetter 81652217195SDaniel Vetter dvi_i_subconnector = drm_property_create_enum(dev, DRM_MODE_PROP_IMMUTABLE, 81752217195SDaniel Vetter "subconnector", 81852217195SDaniel Vetter drm_dvi_i_subconnector_enum_list, 81952217195SDaniel Vetter ARRAY_SIZE(drm_dvi_i_subconnector_enum_list)); 82052217195SDaniel Vetter dev->mode_config.dvi_i_subconnector_property = dvi_i_subconnector; 82152217195SDaniel Vetter 82252217195SDaniel Vetter return 0; 82352217195SDaniel Vetter } 82452217195SDaniel Vetter EXPORT_SYMBOL(drm_mode_create_dvi_i_properties); 82552217195SDaniel Vetter 82652217195SDaniel Vetter /** 82752217195SDaniel Vetter * drm_create_tv_properties - create TV specific connector properties 82852217195SDaniel Vetter * @dev: DRM device 82952217195SDaniel Vetter * @num_modes: number of different TV formats (modes) supported 83052217195SDaniel Vetter * @modes: array of pointers to strings containing name of each format 83152217195SDaniel Vetter * 83252217195SDaniel Vetter * Called by a driver's TV initialization routine, this function creates 83352217195SDaniel Vetter * the TV specific connector properties for a given device. Caller is 83452217195SDaniel Vetter * responsible for allocating a list of format names and passing them to 83552217195SDaniel Vetter * this routine. 83652217195SDaniel Vetter */ 83752217195SDaniel Vetter int drm_mode_create_tv_properties(struct drm_device *dev, 83852217195SDaniel Vetter unsigned int num_modes, 83952217195SDaniel Vetter const char * const modes[]) 84052217195SDaniel Vetter { 84152217195SDaniel Vetter struct drm_property *tv_selector; 84252217195SDaniel Vetter struct drm_property *tv_subconnector; 84352217195SDaniel Vetter unsigned int i; 84452217195SDaniel Vetter 84552217195SDaniel Vetter if (dev->mode_config.tv_select_subconnector_property) 84652217195SDaniel Vetter return 0; 84752217195SDaniel Vetter 84852217195SDaniel Vetter /* 84952217195SDaniel Vetter * Basic connector properties 85052217195SDaniel Vetter */ 85152217195SDaniel Vetter tv_selector = drm_property_create_enum(dev, 0, 85252217195SDaniel Vetter "select subconnector", 85352217195SDaniel Vetter drm_tv_select_enum_list, 85452217195SDaniel Vetter ARRAY_SIZE(drm_tv_select_enum_list)); 85552217195SDaniel Vetter if (!tv_selector) 85652217195SDaniel Vetter goto nomem; 85752217195SDaniel Vetter 85852217195SDaniel Vetter dev->mode_config.tv_select_subconnector_property = tv_selector; 85952217195SDaniel Vetter 86052217195SDaniel Vetter tv_subconnector = 86152217195SDaniel Vetter drm_property_create_enum(dev, DRM_MODE_PROP_IMMUTABLE, 86252217195SDaniel Vetter "subconnector", 86352217195SDaniel Vetter drm_tv_subconnector_enum_list, 86452217195SDaniel Vetter ARRAY_SIZE(drm_tv_subconnector_enum_list)); 86552217195SDaniel Vetter if (!tv_subconnector) 86652217195SDaniel Vetter goto nomem; 86752217195SDaniel Vetter dev->mode_config.tv_subconnector_property = tv_subconnector; 86852217195SDaniel Vetter 86952217195SDaniel Vetter /* 87052217195SDaniel Vetter * Other, TV specific properties: margins & TV modes. 87152217195SDaniel Vetter */ 87252217195SDaniel Vetter dev->mode_config.tv_left_margin_property = 87352217195SDaniel Vetter drm_property_create_range(dev, 0, "left margin", 0, 100); 87452217195SDaniel Vetter if (!dev->mode_config.tv_left_margin_property) 87552217195SDaniel Vetter goto nomem; 87652217195SDaniel Vetter 87752217195SDaniel Vetter dev->mode_config.tv_right_margin_property = 87852217195SDaniel Vetter drm_property_create_range(dev, 0, "right margin", 0, 100); 87952217195SDaniel Vetter if (!dev->mode_config.tv_right_margin_property) 88052217195SDaniel Vetter goto nomem; 88152217195SDaniel Vetter 88252217195SDaniel Vetter dev->mode_config.tv_top_margin_property = 88352217195SDaniel Vetter drm_property_create_range(dev, 0, "top margin", 0, 100); 88452217195SDaniel Vetter if (!dev->mode_config.tv_top_margin_property) 88552217195SDaniel Vetter goto nomem; 88652217195SDaniel Vetter 88752217195SDaniel Vetter dev->mode_config.tv_bottom_margin_property = 88852217195SDaniel Vetter drm_property_create_range(dev, 0, "bottom margin", 0, 100); 88952217195SDaniel Vetter if (!dev->mode_config.tv_bottom_margin_property) 89052217195SDaniel Vetter goto nomem; 89152217195SDaniel Vetter 89252217195SDaniel Vetter dev->mode_config.tv_mode_property = 89352217195SDaniel Vetter drm_property_create(dev, DRM_MODE_PROP_ENUM, 89452217195SDaniel Vetter "mode", num_modes); 89552217195SDaniel Vetter if (!dev->mode_config.tv_mode_property) 89652217195SDaniel Vetter goto nomem; 89752217195SDaniel Vetter 89852217195SDaniel Vetter for (i = 0; i < num_modes; i++) 89952217195SDaniel Vetter drm_property_add_enum(dev->mode_config.tv_mode_property, i, 90052217195SDaniel Vetter i, modes[i]); 90152217195SDaniel Vetter 90252217195SDaniel Vetter dev->mode_config.tv_brightness_property = 90352217195SDaniel Vetter drm_property_create_range(dev, 0, "brightness", 0, 100); 90452217195SDaniel Vetter if (!dev->mode_config.tv_brightness_property) 90552217195SDaniel Vetter goto nomem; 90652217195SDaniel Vetter 90752217195SDaniel Vetter dev->mode_config.tv_contrast_property = 90852217195SDaniel Vetter drm_property_create_range(dev, 0, "contrast", 0, 100); 90952217195SDaniel Vetter if (!dev->mode_config.tv_contrast_property) 91052217195SDaniel Vetter goto nomem; 91152217195SDaniel Vetter 91252217195SDaniel Vetter dev->mode_config.tv_flicker_reduction_property = 91352217195SDaniel Vetter drm_property_create_range(dev, 0, "flicker reduction", 0, 100); 91452217195SDaniel Vetter if (!dev->mode_config.tv_flicker_reduction_property) 91552217195SDaniel Vetter goto nomem; 91652217195SDaniel Vetter 91752217195SDaniel Vetter dev->mode_config.tv_overscan_property = 91852217195SDaniel Vetter drm_property_create_range(dev, 0, "overscan", 0, 100); 91952217195SDaniel Vetter if (!dev->mode_config.tv_overscan_property) 92052217195SDaniel Vetter goto nomem; 92152217195SDaniel Vetter 92252217195SDaniel Vetter dev->mode_config.tv_saturation_property = 92352217195SDaniel Vetter drm_property_create_range(dev, 0, "saturation", 0, 100); 92452217195SDaniel Vetter if (!dev->mode_config.tv_saturation_property) 92552217195SDaniel Vetter goto nomem; 92652217195SDaniel Vetter 92752217195SDaniel Vetter dev->mode_config.tv_hue_property = 92852217195SDaniel Vetter drm_property_create_range(dev, 0, "hue", 0, 100); 92952217195SDaniel Vetter if (!dev->mode_config.tv_hue_property) 93052217195SDaniel Vetter goto nomem; 93152217195SDaniel Vetter 93252217195SDaniel Vetter return 0; 93352217195SDaniel Vetter nomem: 93452217195SDaniel Vetter return -ENOMEM; 93552217195SDaniel Vetter } 93652217195SDaniel Vetter EXPORT_SYMBOL(drm_mode_create_tv_properties); 93752217195SDaniel Vetter 93852217195SDaniel Vetter /** 93952217195SDaniel Vetter * drm_mode_create_scaling_mode_property - create scaling mode property 94052217195SDaniel Vetter * @dev: DRM device 94152217195SDaniel Vetter * 94252217195SDaniel Vetter * Called by a driver the first time it's needed, must be attached to desired 94352217195SDaniel Vetter * connectors. 94452217195SDaniel Vetter */ 94552217195SDaniel Vetter int drm_mode_create_scaling_mode_property(struct drm_device *dev) 94652217195SDaniel Vetter { 94752217195SDaniel Vetter struct drm_property *scaling_mode; 94852217195SDaniel Vetter 94952217195SDaniel Vetter if (dev->mode_config.scaling_mode_property) 95052217195SDaniel Vetter return 0; 95152217195SDaniel Vetter 95252217195SDaniel Vetter scaling_mode = 95352217195SDaniel Vetter drm_property_create_enum(dev, 0, "scaling mode", 95452217195SDaniel Vetter drm_scaling_mode_enum_list, 95552217195SDaniel Vetter ARRAY_SIZE(drm_scaling_mode_enum_list)); 95652217195SDaniel Vetter 95752217195SDaniel Vetter dev->mode_config.scaling_mode_property = scaling_mode; 95852217195SDaniel Vetter 95952217195SDaniel Vetter return 0; 96052217195SDaniel Vetter } 96152217195SDaniel Vetter EXPORT_SYMBOL(drm_mode_create_scaling_mode_property); 96252217195SDaniel Vetter 96352217195SDaniel Vetter /** 96452217195SDaniel Vetter * drm_mode_create_aspect_ratio_property - create aspect ratio property 96552217195SDaniel Vetter * @dev: DRM device 96652217195SDaniel Vetter * 96752217195SDaniel Vetter * Called by a driver the first time it's needed, must be attached to desired 96852217195SDaniel Vetter * connectors. 96952217195SDaniel Vetter * 97052217195SDaniel Vetter * Returns: 97152217195SDaniel Vetter * Zero on success, negative errno on failure. 97252217195SDaniel Vetter */ 97352217195SDaniel Vetter int drm_mode_create_aspect_ratio_property(struct drm_device *dev) 97452217195SDaniel Vetter { 97552217195SDaniel Vetter if (dev->mode_config.aspect_ratio_property) 97652217195SDaniel Vetter return 0; 97752217195SDaniel Vetter 97852217195SDaniel Vetter dev->mode_config.aspect_ratio_property = 97952217195SDaniel Vetter drm_property_create_enum(dev, 0, "aspect ratio", 98052217195SDaniel Vetter drm_aspect_ratio_enum_list, 98152217195SDaniel Vetter ARRAY_SIZE(drm_aspect_ratio_enum_list)); 98252217195SDaniel Vetter 98352217195SDaniel Vetter if (dev->mode_config.aspect_ratio_property == NULL) 98452217195SDaniel Vetter return -ENOMEM; 98552217195SDaniel Vetter 98652217195SDaniel Vetter return 0; 98752217195SDaniel Vetter } 98852217195SDaniel Vetter EXPORT_SYMBOL(drm_mode_create_aspect_ratio_property); 98952217195SDaniel Vetter 99052217195SDaniel Vetter /** 99152217195SDaniel Vetter * drm_mode_create_suggested_offset_properties - create suggests offset properties 99252217195SDaniel Vetter * @dev: DRM device 99352217195SDaniel Vetter * 99452217195SDaniel Vetter * Create the the suggested x/y offset property for connectors. 99552217195SDaniel Vetter */ 99652217195SDaniel Vetter int drm_mode_create_suggested_offset_properties(struct drm_device *dev) 99752217195SDaniel Vetter { 99852217195SDaniel Vetter if (dev->mode_config.suggested_x_property && dev->mode_config.suggested_y_property) 99952217195SDaniel Vetter return 0; 100052217195SDaniel Vetter 100152217195SDaniel Vetter dev->mode_config.suggested_x_property = 100252217195SDaniel Vetter drm_property_create_range(dev, DRM_MODE_PROP_IMMUTABLE, "suggested X", 0, 0xffffffff); 100352217195SDaniel Vetter 100452217195SDaniel Vetter dev->mode_config.suggested_y_property = 100552217195SDaniel Vetter drm_property_create_range(dev, DRM_MODE_PROP_IMMUTABLE, "suggested Y", 0, 0xffffffff); 100652217195SDaniel Vetter 100752217195SDaniel Vetter if (dev->mode_config.suggested_x_property == NULL || 100852217195SDaniel Vetter dev->mode_config.suggested_y_property == NULL) 100952217195SDaniel Vetter return -ENOMEM; 101052217195SDaniel Vetter return 0; 101152217195SDaniel Vetter } 101252217195SDaniel Vetter EXPORT_SYMBOL(drm_mode_create_suggested_offset_properties); 101352217195SDaniel Vetter 101452217195SDaniel Vetter /** 101552217195SDaniel Vetter * drm_mode_connector_set_path_property - set tile property on connector 101652217195SDaniel Vetter * @connector: connector to set property on. 101752217195SDaniel Vetter * @path: path to use for property; must not be NULL. 101852217195SDaniel Vetter * 101952217195SDaniel Vetter * This creates a property to expose to userspace to specify a 102052217195SDaniel Vetter * connector path. This is mainly used for DisplayPort MST where 102152217195SDaniel Vetter * connectors have a topology and we want to allow userspace to give 102252217195SDaniel Vetter * them more meaningful names. 102352217195SDaniel Vetter * 102452217195SDaniel Vetter * Returns: 102552217195SDaniel Vetter * Zero on success, negative errno on failure. 102652217195SDaniel Vetter */ 102752217195SDaniel Vetter int drm_mode_connector_set_path_property(struct drm_connector *connector, 102852217195SDaniel Vetter const char *path) 102952217195SDaniel Vetter { 103052217195SDaniel Vetter struct drm_device *dev = connector->dev; 103152217195SDaniel Vetter int ret; 103252217195SDaniel Vetter 103352217195SDaniel Vetter ret = drm_property_replace_global_blob(dev, 103452217195SDaniel Vetter &connector->path_blob_ptr, 103552217195SDaniel Vetter strlen(path) + 1, 103652217195SDaniel Vetter path, 103752217195SDaniel Vetter &connector->base, 103852217195SDaniel Vetter dev->mode_config.path_property); 103952217195SDaniel Vetter return ret; 104052217195SDaniel Vetter } 104152217195SDaniel Vetter EXPORT_SYMBOL(drm_mode_connector_set_path_property); 104252217195SDaniel Vetter 104352217195SDaniel Vetter /** 104452217195SDaniel Vetter * drm_mode_connector_set_tile_property - set tile property on connector 104552217195SDaniel Vetter * @connector: connector to set property on. 104652217195SDaniel Vetter * 104752217195SDaniel Vetter * This looks up the tile information for a connector, and creates a 104852217195SDaniel Vetter * property for userspace to parse if it exists. The property is of 104952217195SDaniel Vetter * the form of 8 integers using ':' as a separator. 105052217195SDaniel Vetter * 105152217195SDaniel Vetter * Returns: 105252217195SDaniel Vetter * Zero on success, errno on failure. 105352217195SDaniel Vetter */ 105452217195SDaniel Vetter int drm_mode_connector_set_tile_property(struct drm_connector *connector) 105552217195SDaniel Vetter { 105652217195SDaniel Vetter struct drm_device *dev = connector->dev; 105752217195SDaniel Vetter char tile[256]; 105852217195SDaniel Vetter int ret; 105952217195SDaniel Vetter 106052217195SDaniel Vetter if (!connector->has_tile) { 106152217195SDaniel Vetter ret = drm_property_replace_global_blob(dev, 106252217195SDaniel Vetter &connector->tile_blob_ptr, 106352217195SDaniel Vetter 0, 106452217195SDaniel Vetter NULL, 106552217195SDaniel Vetter &connector->base, 106652217195SDaniel Vetter dev->mode_config.tile_property); 106752217195SDaniel Vetter return ret; 106852217195SDaniel Vetter } 106952217195SDaniel Vetter 107052217195SDaniel Vetter snprintf(tile, 256, "%d:%d:%d:%d:%d:%d:%d:%d", 107152217195SDaniel Vetter connector->tile_group->id, connector->tile_is_single_monitor, 107252217195SDaniel Vetter connector->num_h_tile, connector->num_v_tile, 107352217195SDaniel Vetter connector->tile_h_loc, connector->tile_v_loc, 107452217195SDaniel Vetter connector->tile_h_size, connector->tile_v_size); 107552217195SDaniel Vetter 107652217195SDaniel Vetter ret = drm_property_replace_global_blob(dev, 107752217195SDaniel Vetter &connector->tile_blob_ptr, 107852217195SDaniel Vetter strlen(tile) + 1, 107952217195SDaniel Vetter tile, 108052217195SDaniel Vetter &connector->base, 108152217195SDaniel Vetter dev->mode_config.tile_property); 108252217195SDaniel Vetter return ret; 108352217195SDaniel Vetter } 108452217195SDaniel Vetter EXPORT_SYMBOL(drm_mode_connector_set_tile_property); 108552217195SDaniel Vetter 108652217195SDaniel Vetter /** 108752217195SDaniel Vetter * drm_mode_connector_update_edid_property - update the edid property of a connector 108852217195SDaniel Vetter * @connector: drm connector 108952217195SDaniel Vetter * @edid: new value of the edid property 109052217195SDaniel Vetter * 109152217195SDaniel Vetter * This function creates a new blob modeset object and assigns its id to the 109252217195SDaniel Vetter * connector's edid property. 109352217195SDaniel Vetter * 109452217195SDaniel Vetter * Returns: 109552217195SDaniel Vetter * Zero on success, negative errno on failure. 109652217195SDaniel Vetter */ 109752217195SDaniel Vetter int drm_mode_connector_update_edid_property(struct drm_connector *connector, 109852217195SDaniel Vetter const struct edid *edid) 109952217195SDaniel Vetter { 110052217195SDaniel Vetter struct drm_device *dev = connector->dev; 110152217195SDaniel Vetter size_t size = 0; 110252217195SDaniel Vetter int ret; 110352217195SDaniel Vetter 110452217195SDaniel Vetter /* ignore requests to set edid when overridden */ 110552217195SDaniel Vetter if (connector->override_edid) 110652217195SDaniel Vetter return 0; 110752217195SDaniel Vetter 110852217195SDaniel Vetter if (edid) 110952217195SDaniel Vetter size = EDID_LENGTH * (1 + edid->extensions); 111052217195SDaniel Vetter 111152217195SDaniel Vetter ret = drm_property_replace_global_blob(dev, 111252217195SDaniel Vetter &connector->edid_blob_ptr, 111352217195SDaniel Vetter size, 111452217195SDaniel Vetter edid, 111552217195SDaniel Vetter &connector->base, 111652217195SDaniel Vetter dev->mode_config.edid_property); 111752217195SDaniel Vetter return ret; 111852217195SDaniel Vetter } 111952217195SDaniel Vetter EXPORT_SYMBOL(drm_mode_connector_update_edid_property); 112052217195SDaniel Vetter 112140ee6fbeSManasi Navare /** 112240ee6fbeSManasi Navare * drm_mode_connector_set_link_status_property - Set link status property of a connector 112340ee6fbeSManasi Navare * @connector: drm connector 112440ee6fbeSManasi Navare * @link_status: new value of link status property (0: Good, 1: Bad) 112540ee6fbeSManasi Navare * 112640ee6fbeSManasi Navare * In usual working scenario, this link status property will always be set to 112740ee6fbeSManasi Navare * "GOOD". If something fails during or after a mode set, the kernel driver 112840ee6fbeSManasi Navare * may set this link status property to "BAD". The caller then needs to send a 112940ee6fbeSManasi Navare * hotplug uevent for userspace to re-check the valid modes through 113040ee6fbeSManasi Navare * GET_CONNECTOR_IOCTL and retry modeset. 113140ee6fbeSManasi Navare * 113240ee6fbeSManasi Navare * Note: Drivers cannot rely on userspace to support this property and 113340ee6fbeSManasi Navare * issue a modeset. As such, they may choose to handle issues (like 113440ee6fbeSManasi Navare * re-training a link) without userspace's intervention. 113540ee6fbeSManasi Navare * 113640ee6fbeSManasi Navare * The reason for adding this property is to handle link training failures, but 113740ee6fbeSManasi Navare * it is not limited to DP or link training. For example, if we implement 113840ee6fbeSManasi Navare * asynchronous setcrtc, this property can be used to report any failures in that. 113940ee6fbeSManasi Navare */ 114040ee6fbeSManasi Navare void drm_mode_connector_set_link_status_property(struct drm_connector *connector, 114140ee6fbeSManasi Navare uint64_t link_status) 114240ee6fbeSManasi Navare { 114340ee6fbeSManasi Navare struct drm_device *dev = connector->dev; 114440ee6fbeSManasi Navare 114540ee6fbeSManasi Navare drm_modeset_lock(&dev->mode_config.connection_mutex, NULL); 114640ee6fbeSManasi Navare connector->state->link_status = link_status; 114740ee6fbeSManasi Navare drm_modeset_unlock(&dev->mode_config.connection_mutex); 114840ee6fbeSManasi Navare } 114940ee6fbeSManasi Navare EXPORT_SYMBOL(drm_mode_connector_set_link_status_property); 115040ee6fbeSManasi Navare 115152217195SDaniel Vetter int drm_mode_connector_set_obj_prop(struct drm_mode_object *obj, 115252217195SDaniel Vetter struct drm_property *property, 115352217195SDaniel Vetter uint64_t value) 115452217195SDaniel Vetter { 115552217195SDaniel Vetter int ret = -EINVAL; 115652217195SDaniel Vetter struct drm_connector *connector = obj_to_connector(obj); 115752217195SDaniel Vetter 115852217195SDaniel Vetter /* Do DPMS ourselves */ 115952217195SDaniel Vetter if (property == connector->dev->mode_config.dpms_property) { 116052217195SDaniel Vetter ret = (*connector->funcs->dpms)(connector, (int)value); 116152217195SDaniel Vetter } else if (connector->funcs->set_property) 116252217195SDaniel Vetter ret = connector->funcs->set_property(connector, property, value); 116352217195SDaniel Vetter 116452217195SDaniel Vetter /* store the property value if successful */ 116552217195SDaniel Vetter if (!ret) 116652217195SDaniel Vetter drm_object_property_set_value(&connector->base, property, value); 116752217195SDaniel Vetter return ret; 116852217195SDaniel Vetter } 116952217195SDaniel Vetter 117052217195SDaniel Vetter int drm_mode_connector_property_set_ioctl(struct drm_device *dev, 117152217195SDaniel Vetter void *data, struct drm_file *file_priv) 117252217195SDaniel Vetter { 117352217195SDaniel Vetter struct drm_mode_connector_set_property *conn_set_prop = data; 117452217195SDaniel Vetter struct drm_mode_obj_set_property obj_set_prop = { 117552217195SDaniel Vetter .value = conn_set_prop->value, 117652217195SDaniel Vetter .prop_id = conn_set_prop->prop_id, 117752217195SDaniel Vetter .obj_id = conn_set_prop->connector_id, 117852217195SDaniel Vetter .obj_type = DRM_MODE_OBJECT_CONNECTOR 117952217195SDaniel Vetter }; 118052217195SDaniel Vetter 118152217195SDaniel Vetter /* It does all the locking and checking we need */ 118252217195SDaniel Vetter return drm_mode_obj_set_property_ioctl(dev, &obj_set_prop, file_priv); 118352217195SDaniel Vetter } 118452217195SDaniel Vetter 118552217195SDaniel Vetter static struct drm_encoder *drm_connector_get_encoder(struct drm_connector *connector) 118652217195SDaniel Vetter { 118752217195SDaniel Vetter /* For atomic drivers only state objects are synchronously updated and 118852217195SDaniel Vetter * protected by modeset locks, so check those first. */ 118952217195SDaniel Vetter if (connector->state) 119052217195SDaniel Vetter return connector->state->best_encoder; 119152217195SDaniel Vetter return connector->encoder; 119252217195SDaniel Vetter } 119352217195SDaniel Vetter 119452217195SDaniel Vetter static bool drm_mode_expose_to_userspace(const struct drm_display_mode *mode, 119552217195SDaniel Vetter const struct drm_file *file_priv) 119652217195SDaniel Vetter { 119752217195SDaniel Vetter /* 119852217195SDaniel Vetter * If user-space hasn't configured the driver to expose the stereo 3D 119952217195SDaniel Vetter * modes, don't expose them. 120052217195SDaniel Vetter */ 120152217195SDaniel Vetter if (!file_priv->stereo_allowed && drm_mode_is_stereo(mode)) 120252217195SDaniel Vetter return false; 120352217195SDaniel Vetter 120452217195SDaniel Vetter return true; 120552217195SDaniel Vetter } 120652217195SDaniel Vetter 120752217195SDaniel Vetter int drm_mode_getconnector(struct drm_device *dev, void *data, 120852217195SDaniel Vetter struct drm_file *file_priv) 120952217195SDaniel Vetter { 121052217195SDaniel Vetter struct drm_mode_get_connector *out_resp = data; 121152217195SDaniel Vetter struct drm_connector *connector; 121252217195SDaniel Vetter struct drm_encoder *encoder; 121352217195SDaniel Vetter struct drm_display_mode *mode; 121452217195SDaniel Vetter int mode_count = 0; 121552217195SDaniel Vetter int encoders_count = 0; 121652217195SDaniel Vetter int ret = 0; 121752217195SDaniel Vetter int copied = 0; 121852217195SDaniel Vetter int i; 121952217195SDaniel Vetter struct drm_mode_modeinfo u_mode; 122052217195SDaniel Vetter struct drm_mode_modeinfo __user *mode_ptr; 122152217195SDaniel Vetter uint32_t __user *encoder_ptr; 122252217195SDaniel Vetter 122352217195SDaniel Vetter if (!drm_core_check_feature(dev, DRIVER_MODESET)) 122452217195SDaniel Vetter return -EINVAL; 122552217195SDaniel Vetter 122652217195SDaniel Vetter memset(&u_mode, 0, sizeof(struct drm_mode_modeinfo)); 122752217195SDaniel Vetter 122852217195SDaniel Vetter connector = drm_connector_lookup(dev, out_resp->connector_id); 122991eefc05SDaniel Vetter if (!connector) 123091eefc05SDaniel Vetter return -ENOENT; 123152217195SDaniel Vetter 123252217195SDaniel Vetter drm_modeset_lock(&dev->mode_config.connection_mutex, NULL); 123352217195SDaniel Vetter encoder = drm_connector_get_encoder(connector); 123452217195SDaniel Vetter if (encoder) 123552217195SDaniel Vetter out_resp->encoder_id = encoder->base.id; 123652217195SDaniel Vetter else 123752217195SDaniel Vetter out_resp->encoder_id = 0; 123852217195SDaniel Vetter 123991eefc05SDaniel Vetter ret = drm_mode_object_get_properties(&connector->base, file_priv->atomic, 124091eefc05SDaniel Vetter (uint32_t __user *)(unsigned long)(out_resp->props_ptr), 124191eefc05SDaniel Vetter (uint64_t __user *)(unsigned long)(out_resp->prop_values_ptr), 124291eefc05SDaniel Vetter &out_resp->count_props); 124391eefc05SDaniel Vetter drm_modeset_unlock(&dev->mode_config.connection_mutex); 124491eefc05SDaniel Vetter if (ret) 124591eefc05SDaniel Vetter goto out_unref; 124691eefc05SDaniel Vetter 124791eefc05SDaniel Vetter for (i = 0; i < DRM_CONNECTOR_MAX_ENCODER; i++) 124891eefc05SDaniel Vetter if (connector->encoder_ids[i] != 0) 124991eefc05SDaniel Vetter encoders_count++; 125091eefc05SDaniel Vetter 125191eefc05SDaniel Vetter if ((out_resp->count_encoders >= encoders_count) && encoders_count) { 125291eefc05SDaniel Vetter copied = 0; 125391eefc05SDaniel Vetter encoder_ptr = (uint32_t __user *)(unsigned long)(out_resp->encoders_ptr); 125491eefc05SDaniel Vetter for (i = 0; i < DRM_CONNECTOR_MAX_ENCODER; i++) { 125591eefc05SDaniel Vetter if (connector->encoder_ids[i] != 0) { 125691eefc05SDaniel Vetter if (put_user(connector->encoder_ids[i], 125791eefc05SDaniel Vetter encoder_ptr + copied)) { 125891eefc05SDaniel Vetter ret = -EFAULT; 125991eefc05SDaniel Vetter goto out_unref; 126091eefc05SDaniel Vetter } 126191eefc05SDaniel Vetter copied++; 126291eefc05SDaniel Vetter } 126391eefc05SDaniel Vetter } 126491eefc05SDaniel Vetter } 126591eefc05SDaniel Vetter out_resp->count_encoders = encoders_count; 126691eefc05SDaniel Vetter 126791eefc05SDaniel Vetter out_resp->connector_id = connector->base.id; 126891eefc05SDaniel Vetter out_resp->connector_type = connector->connector_type; 126991eefc05SDaniel Vetter out_resp->connector_type_id = connector->connector_type_id; 127091eefc05SDaniel Vetter 127191eefc05SDaniel Vetter mutex_lock(&dev->mode_config.mutex); 127291eefc05SDaniel Vetter if (out_resp->count_modes == 0) { 127391eefc05SDaniel Vetter connector->funcs->fill_modes(connector, 127491eefc05SDaniel Vetter dev->mode_config.max_width, 127591eefc05SDaniel Vetter dev->mode_config.max_height); 127691eefc05SDaniel Vetter } 127791eefc05SDaniel Vetter 127891eefc05SDaniel Vetter out_resp->mm_width = connector->display_info.width_mm; 127991eefc05SDaniel Vetter out_resp->mm_height = connector->display_info.height_mm; 128091eefc05SDaniel Vetter out_resp->subpixel = connector->display_info.subpixel_order; 128191eefc05SDaniel Vetter out_resp->connection = connector->status; 128291eefc05SDaniel Vetter 128391eefc05SDaniel Vetter /* delayed so we get modes regardless of pre-fill_modes state */ 128491eefc05SDaniel Vetter list_for_each_entry(mode, &connector->modes, head) 128591eefc05SDaniel Vetter if (drm_mode_expose_to_userspace(mode, file_priv)) 128691eefc05SDaniel Vetter mode_count++; 128791eefc05SDaniel Vetter 128852217195SDaniel Vetter /* 128952217195SDaniel Vetter * This ioctl is called twice, once to determine how much space is 129052217195SDaniel Vetter * needed, and the 2nd time to fill it. 129152217195SDaniel Vetter */ 129252217195SDaniel Vetter if ((out_resp->count_modes >= mode_count) && mode_count) { 129352217195SDaniel Vetter copied = 0; 129452217195SDaniel Vetter mode_ptr = (struct drm_mode_modeinfo __user *)(unsigned long)out_resp->modes_ptr; 129552217195SDaniel Vetter list_for_each_entry(mode, &connector->modes, head) { 129652217195SDaniel Vetter if (!drm_mode_expose_to_userspace(mode, file_priv)) 129752217195SDaniel Vetter continue; 129852217195SDaniel Vetter 129952217195SDaniel Vetter drm_mode_convert_to_umode(&u_mode, mode); 130052217195SDaniel Vetter if (copy_to_user(mode_ptr + copied, 130152217195SDaniel Vetter &u_mode, sizeof(u_mode))) { 130252217195SDaniel Vetter ret = -EFAULT; 130352217195SDaniel Vetter goto out; 130452217195SDaniel Vetter } 130552217195SDaniel Vetter copied++; 130652217195SDaniel Vetter } 130752217195SDaniel Vetter } 130852217195SDaniel Vetter out_resp->count_modes = mode_count; 130952217195SDaniel Vetter out: 131052217195SDaniel Vetter mutex_unlock(&dev->mode_config.mutex); 131191eefc05SDaniel Vetter out_unref: 131291eefc05SDaniel Vetter drm_connector_unreference(connector); 131352217195SDaniel Vetter 131452217195SDaniel Vetter return ret; 131552217195SDaniel Vetter } 131652217195SDaniel Vetter 13179498c19bSDaniel Vetter 13189498c19bSDaniel Vetter /** 13199498c19bSDaniel Vetter * DOC: Tile group 13209498c19bSDaniel Vetter * 13219498c19bSDaniel Vetter * Tile groups are used to represent tiled monitors with a unique integer 13229498c19bSDaniel Vetter * identifier. Tiled monitors using DisplayID v1.3 have a unique 8-byte handle, 13239498c19bSDaniel Vetter * we store this in a tile group, so we have a common identifier for all tiles 13249498c19bSDaniel Vetter * in a monitor group. The property is called "TILE". Drivers can manage tile 13259498c19bSDaniel Vetter * groups using drm_mode_create_tile_group(), drm_mode_put_tile_group() and 13269498c19bSDaniel Vetter * drm_mode_get_tile_group(). But this is only needed for internal panels where 13279498c19bSDaniel Vetter * the tile group information is exposed through a non-standard way. 13289498c19bSDaniel Vetter */ 13299498c19bSDaniel Vetter 13309498c19bSDaniel Vetter static void drm_tile_group_free(struct kref *kref) 13319498c19bSDaniel Vetter { 13329498c19bSDaniel Vetter struct drm_tile_group *tg = container_of(kref, struct drm_tile_group, refcount); 13339498c19bSDaniel Vetter struct drm_device *dev = tg->dev; 13349498c19bSDaniel Vetter mutex_lock(&dev->mode_config.idr_mutex); 13359498c19bSDaniel Vetter idr_remove(&dev->mode_config.tile_idr, tg->id); 13369498c19bSDaniel Vetter mutex_unlock(&dev->mode_config.idr_mutex); 13379498c19bSDaniel Vetter kfree(tg); 13389498c19bSDaniel Vetter } 13399498c19bSDaniel Vetter 13409498c19bSDaniel Vetter /** 13419498c19bSDaniel Vetter * drm_mode_put_tile_group - drop a reference to a tile group. 13429498c19bSDaniel Vetter * @dev: DRM device 13439498c19bSDaniel Vetter * @tg: tile group to drop reference to. 13449498c19bSDaniel Vetter * 13459498c19bSDaniel Vetter * drop reference to tile group and free if 0. 13469498c19bSDaniel Vetter */ 13479498c19bSDaniel Vetter void drm_mode_put_tile_group(struct drm_device *dev, 13489498c19bSDaniel Vetter struct drm_tile_group *tg) 13499498c19bSDaniel Vetter { 13509498c19bSDaniel Vetter kref_put(&tg->refcount, drm_tile_group_free); 13519498c19bSDaniel Vetter } 13529498c19bSDaniel Vetter EXPORT_SYMBOL(drm_mode_put_tile_group); 13539498c19bSDaniel Vetter 13549498c19bSDaniel Vetter /** 13559498c19bSDaniel Vetter * drm_mode_get_tile_group - get a reference to an existing tile group 13569498c19bSDaniel Vetter * @dev: DRM device 13579498c19bSDaniel Vetter * @topology: 8-bytes unique per monitor. 13589498c19bSDaniel Vetter * 13599498c19bSDaniel Vetter * Use the unique bytes to get a reference to an existing tile group. 13609498c19bSDaniel Vetter * 13619498c19bSDaniel Vetter * RETURNS: 13629498c19bSDaniel Vetter * tile group or NULL if not found. 13639498c19bSDaniel Vetter */ 13649498c19bSDaniel Vetter struct drm_tile_group *drm_mode_get_tile_group(struct drm_device *dev, 13659498c19bSDaniel Vetter char topology[8]) 13669498c19bSDaniel Vetter { 13679498c19bSDaniel Vetter struct drm_tile_group *tg; 13689498c19bSDaniel Vetter int id; 13699498c19bSDaniel Vetter mutex_lock(&dev->mode_config.idr_mutex); 13709498c19bSDaniel Vetter idr_for_each_entry(&dev->mode_config.tile_idr, tg, id) { 13719498c19bSDaniel Vetter if (!memcmp(tg->group_data, topology, 8)) { 13729498c19bSDaniel Vetter if (!kref_get_unless_zero(&tg->refcount)) 13739498c19bSDaniel Vetter tg = NULL; 13749498c19bSDaniel Vetter mutex_unlock(&dev->mode_config.idr_mutex); 13759498c19bSDaniel Vetter return tg; 13769498c19bSDaniel Vetter } 13779498c19bSDaniel Vetter } 13789498c19bSDaniel Vetter mutex_unlock(&dev->mode_config.idr_mutex); 13799498c19bSDaniel Vetter return NULL; 13809498c19bSDaniel Vetter } 13819498c19bSDaniel Vetter EXPORT_SYMBOL(drm_mode_get_tile_group); 13829498c19bSDaniel Vetter 13839498c19bSDaniel Vetter /** 13849498c19bSDaniel Vetter * drm_mode_create_tile_group - create a tile group from a displayid description 13859498c19bSDaniel Vetter * @dev: DRM device 13869498c19bSDaniel Vetter * @topology: 8-bytes unique per monitor. 13879498c19bSDaniel Vetter * 13889498c19bSDaniel Vetter * Create a tile group for the unique monitor, and get a unique 13899498c19bSDaniel Vetter * identifier for the tile group. 13909498c19bSDaniel Vetter * 13919498c19bSDaniel Vetter * RETURNS: 13929498c19bSDaniel Vetter * new tile group or error. 13939498c19bSDaniel Vetter */ 13949498c19bSDaniel Vetter struct drm_tile_group *drm_mode_create_tile_group(struct drm_device *dev, 13959498c19bSDaniel Vetter char topology[8]) 13969498c19bSDaniel Vetter { 13979498c19bSDaniel Vetter struct drm_tile_group *tg; 13989498c19bSDaniel Vetter int ret; 13999498c19bSDaniel Vetter 14009498c19bSDaniel Vetter tg = kzalloc(sizeof(*tg), GFP_KERNEL); 14019498c19bSDaniel Vetter if (!tg) 14029498c19bSDaniel Vetter return ERR_PTR(-ENOMEM); 14039498c19bSDaniel Vetter 14049498c19bSDaniel Vetter kref_init(&tg->refcount); 14059498c19bSDaniel Vetter memcpy(tg->group_data, topology, 8); 14069498c19bSDaniel Vetter tg->dev = dev; 14079498c19bSDaniel Vetter 14089498c19bSDaniel Vetter mutex_lock(&dev->mode_config.idr_mutex); 14099498c19bSDaniel Vetter ret = idr_alloc(&dev->mode_config.tile_idr, tg, 1, 0, GFP_KERNEL); 14109498c19bSDaniel Vetter if (ret >= 0) { 14119498c19bSDaniel Vetter tg->id = ret; 14129498c19bSDaniel Vetter } else { 14139498c19bSDaniel Vetter kfree(tg); 14149498c19bSDaniel Vetter tg = ERR_PTR(ret); 14159498c19bSDaniel Vetter } 14169498c19bSDaniel Vetter 14179498c19bSDaniel Vetter mutex_unlock(&dev->mode_config.idr_mutex); 14189498c19bSDaniel Vetter return tg; 14199498c19bSDaniel Vetter } 14209498c19bSDaniel Vetter EXPORT_SYMBOL(drm_mode_create_tile_group); 1421