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> 2652217195SDaniel Vetter 2752217195SDaniel Vetter #include "drm_crtc_internal.h" 2852217195SDaniel Vetter #include "drm_internal.h" 2952217195SDaniel Vetter 30ae2a6da8SDaniel Vetter /** 31ae2a6da8SDaniel Vetter * DOC: overview 32ae2a6da8SDaniel Vetter * 33ae2a6da8SDaniel Vetter * In DRM connectors are the general abstraction for display sinks, and include 34ae2a6da8SDaniel Vetter * als fixed panels or anything else that can display pixels in some form. As 35ae2a6da8SDaniel Vetter * opposed to all other KMS objects representing hardware (like CRTC, encoder or 36ae2a6da8SDaniel Vetter * plane abstractions) connectors can be hotplugged and unplugged at runtime. 37ae2a6da8SDaniel Vetter * Hence they are reference-counted using drm_connector_reference() and 38ae2a6da8SDaniel Vetter * drm_connector_unreference(). 39ae2a6da8SDaniel Vetter * 40ae2a6da8SDaniel Vetter * KMS driver must create, initialize, register and attach at a struct 41ae2a6da8SDaniel Vetter * &drm_connector for each such sink. The instance is created as other KMS 42ae2a6da8SDaniel Vetter * objects and initialized by setting the following fields. 43ae2a6da8SDaniel Vetter * 44ae2a6da8SDaniel Vetter * The connector is then registered with a call to drm_connector_init() with a 45ae2a6da8SDaniel Vetter * pointer to the connector functions and a connector type, and exposed through 46ae2a6da8SDaniel Vetter * sysfs 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 51ae2a6da8SDaniel Vetter * driver must also set the struct &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) { 13152217195SDaniel Vetter const char *s; 13252217195SDaniel Vetter 13352217195SDaniel Vetter switch (mode->force) { 13452217195SDaniel Vetter case DRM_FORCE_OFF: 13552217195SDaniel Vetter s = "OFF"; 13652217195SDaniel Vetter break; 13752217195SDaniel Vetter case DRM_FORCE_ON_DIGITAL: 13852217195SDaniel Vetter s = "ON - dig"; 13952217195SDaniel Vetter break; 14052217195SDaniel Vetter default: 14152217195SDaniel Vetter case DRM_FORCE_ON: 14252217195SDaniel Vetter s = "ON"; 14352217195SDaniel Vetter break; 14452217195SDaniel Vetter } 14552217195SDaniel Vetter 14652217195SDaniel Vetter DRM_INFO("forcing %s connector %s\n", connector->name, s); 14752217195SDaniel Vetter connector->force = mode->force; 14852217195SDaniel Vetter } 14952217195SDaniel Vetter 15052217195SDaniel Vetter DRM_DEBUG_KMS("cmdline mode for connector %s %dx%d@%dHz%s%s%s\n", 15152217195SDaniel Vetter connector->name, 15252217195SDaniel Vetter mode->xres, mode->yres, 15352217195SDaniel Vetter mode->refresh_specified ? mode->refresh : 60, 15452217195SDaniel Vetter mode->rb ? " reduced blanking" : "", 15552217195SDaniel Vetter mode->margins ? " with margins" : "", 15652217195SDaniel Vetter mode->interlace ? " interlaced" : ""); 15752217195SDaniel Vetter } 15852217195SDaniel Vetter 15952217195SDaniel Vetter static void drm_connector_free(struct kref *kref) 16052217195SDaniel Vetter { 16152217195SDaniel Vetter struct drm_connector *connector = 16252217195SDaniel Vetter container_of(kref, struct drm_connector, base.refcount); 16352217195SDaniel Vetter struct drm_device *dev = connector->dev; 16452217195SDaniel Vetter 16552217195SDaniel Vetter drm_mode_object_unregister(dev, &connector->base); 16652217195SDaniel Vetter connector->funcs->destroy(connector); 16752217195SDaniel Vetter } 16852217195SDaniel Vetter 16952217195SDaniel Vetter /** 17052217195SDaniel Vetter * drm_connector_init - Init a preallocated connector 17152217195SDaniel Vetter * @dev: DRM device 17252217195SDaniel Vetter * @connector: the connector to init 17352217195SDaniel Vetter * @funcs: callbacks for this connector 17452217195SDaniel Vetter * @connector_type: user visible type of the connector 17552217195SDaniel Vetter * 17652217195SDaniel Vetter * Initialises a preallocated connector. Connectors should be 17752217195SDaniel Vetter * subclassed as part of driver connector objects. 17852217195SDaniel Vetter * 17952217195SDaniel Vetter * Returns: 18052217195SDaniel Vetter * Zero on success, error code on failure. 18152217195SDaniel Vetter */ 18252217195SDaniel Vetter int drm_connector_init(struct drm_device *dev, 18352217195SDaniel Vetter struct drm_connector *connector, 18452217195SDaniel Vetter const struct drm_connector_funcs *funcs, 18552217195SDaniel Vetter int connector_type) 18652217195SDaniel Vetter { 18752217195SDaniel Vetter struct drm_mode_config *config = &dev->mode_config; 18852217195SDaniel Vetter int ret; 18952217195SDaniel Vetter struct ida *connector_ida = 19052217195SDaniel Vetter &drm_connector_enum_list[connector_type].ida; 19152217195SDaniel Vetter 19252217195SDaniel Vetter drm_modeset_lock_all(dev); 19352217195SDaniel Vetter 19452217195SDaniel Vetter ret = drm_mode_object_get_reg(dev, &connector->base, 19552217195SDaniel Vetter DRM_MODE_OBJECT_CONNECTOR, 19652217195SDaniel Vetter false, drm_connector_free); 19752217195SDaniel Vetter if (ret) 19852217195SDaniel Vetter goto out_unlock; 19952217195SDaniel Vetter 20052217195SDaniel Vetter connector->base.properties = &connector->properties; 20152217195SDaniel Vetter connector->dev = dev; 20252217195SDaniel Vetter connector->funcs = funcs; 20352217195SDaniel Vetter 20452217195SDaniel Vetter ret = ida_simple_get(&config->connector_ida, 0, 0, GFP_KERNEL); 20552217195SDaniel Vetter if (ret < 0) 20652217195SDaniel Vetter goto out_put; 20752217195SDaniel Vetter connector->index = ret; 20852217195SDaniel Vetter ret = 0; 20952217195SDaniel Vetter 21052217195SDaniel Vetter connector->connector_type = connector_type; 21152217195SDaniel Vetter connector->connector_type_id = 21252217195SDaniel Vetter ida_simple_get(connector_ida, 1, 0, GFP_KERNEL); 21352217195SDaniel Vetter if (connector->connector_type_id < 0) { 21452217195SDaniel Vetter ret = connector->connector_type_id; 21552217195SDaniel Vetter goto out_put_id; 21652217195SDaniel Vetter } 21752217195SDaniel Vetter connector->name = 21852217195SDaniel Vetter kasprintf(GFP_KERNEL, "%s-%d", 21952217195SDaniel Vetter drm_connector_enum_list[connector_type].name, 22052217195SDaniel Vetter connector->connector_type_id); 22152217195SDaniel Vetter if (!connector->name) { 22252217195SDaniel Vetter ret = -ENOMEM; 22352217195SDaniel Vetter goto out_put_type_id; 22452217195SDaniel Vetter } 22552217195SDaniel Vetter 22652217195SDaniel Vetter INIT_LIST_HEAD(&connector->probed_modes); 22752217195SDaniel Vetter INIT_LIST_HEAD(&connector->modes); 22852217195SDaniel Vetter connector->edid_blob_ptr = NULL; 22952217195SDaniel Vetter connector->status = connector_status_unknown; 23052217195SDaniel Vetter 23152217195SDaniel Vetter drm_connector_get_cmdline_mode(connector); 23252217195SDaniel Vetter 23352217195SDaniel Vetter /* We should add connectors at the end to avoid upsetting the connector 23452217195SDaniel Vetter * index too much. */ 23552217195SDaniel Vetter list_add_tail(&connector->head, &config->connector_list); 23652217195SDaniel Vetter config->num_connector++; 23752217195SDaniel Vetter 23852217195SDaniel Vetter if (connector_type != DRM_MODE_CONNECTOR_VIRTUAL) 23952217195SDaniel Vetter drm_object_attach_property(&connector->base, 24052217195SDaniel Vetter config->edid_property, 24152217195SDaniel Vetter 0); 24252217195SDaniel Vetter 24352217195SDaniel Vetter drm_object_attach_property(&connector->base, 24452217195SDaniel Vetter config->dpms_property, 0); 24552217195SDaniel Vetter 24652217195SDaniel Vetter if (drm_core_check_feature(dev, DRIVER_ATOMIC)) { 24752217195SDaniel Vetter drm_object_attach_property(&connector->base, config->prop_crtc_id, 0); 24852217195SDaniel Vetter } 24952217195SDaniel Vetter 25052217195SDaniel Vetter connector->debugfs_entry = NULL; 25152217195SDaniel Vetter out_put_type_id: 25252217195SDaniel Vetter if (ret) 253*587680c1SChristophe JAILLET ida_simple_remove(connector_ida, connector->connector_type_id); 25452217195SDaniel Vetter out_put_id: 25552217195SDaniel Vetter if (ret) 256*587680c1SChristophe JAILLET ida_simple_remove(&config->connector_ida, connector->index); 25752217195SDaniel Vetter out_put: 25852217195SDaniel Vetter if (ret) 25952217195SDaniel Vetter drm_mode_object_unregister(dev, &connector->base); 26052217195SDaniel Vetter 26152217195SDaniel Vetter out_unlock: 26252217195SDaniel Vetter drm_modeset_unlock_all(dev); 26352217195SDaniel Vetter 26452217195SDaniel Vetter return ret; 26552217195SDaniel Vetter } 26652217195SDaniel Vetter EXPORT_SYMBOL(drm_connector_init); 26752217195SDaniel Vetter 26852217195SDaniel Vetter /** 26952217195SDaniel Vetter * drm_mode_connector_attach_encoder - attach a connector to an encoder 27052217195SDaniel Vetter * @connector: connector to attach 27152217195SDaniel Vetter * @encoder: encoder to attach @connector to 27252217195SDaniel Vetter * 27352217195SDaniel Vetter * This function links up a connector to an encoder. Note that the routing 27452217195SDaniel Vetter * restrictions between encoders and crtcs are exposed to userspace through the 27552217195SDaniel Vetter * possible_clones and possible_crtcs bitmasks. 27652217195SDaniel Vetter * 27752217195SDaniel Vetter * Returns: 27852217195SDaniel Vetter * Zero on success, negative errno on failure. 27952217195SDaniel Vetter */ 28052217195SDaniel Vetter int drm_mode_connector_attach_encoder(struct drm_connector *connector, 28152217195SDaniel Vetter struct drm_encoder *encoder) 28252217195SDaniel Vetter { 28352217195SDaniel Vetter int i; 28452217195SDaniel Vetter 28552217195SDaniel Vetter /* 28652217195SDaniel Vetter * In the past, drivers have attempted to model the static association 28752217195SDaniel Vetter * of connector to encoder in simple connector/encoder devices using a 28852217195SDaniel Vetter * direct assignment of connector->encoder = encoder. This connection 28952217195SDaniel Vetter * is a logical one and the responsibility of the core, so drivers are 29052217195SDaniel Vetter * expected not to mess with this. 29152217195SDaniel Vetter * 29252217195SDaniel Vetter * Note that the error return should've been enough here, but a large 29352217195SDaniel Vetter * majority of drivers ignores the return value, so add in a big WARN 29452217195SDaniel Vetter * to get people's attention. 29552217195SDaniel Vetter */ 29652217195SDaniel Vetter if (WARN_ON(connector->encoder)) 29752217195SDaniel Vetter return -EINVAL; 29852217195SDaniel Vetter 29952217195SDaniel Vetter for (i = 0; i < DRM_CONNECTOR_MAX_ENCODER; i++) { 30052217195SDaniel Vetter if (connector->encoder_ids[i] == 0) { 30152217195SDaniel Vetter connector->encoder_ids[i] = encoder->base.id; 30252217195SDaniel Vetter return 0; 30352217195SDaniel Vetter } 30452217195SDaniel Vetter } 30552217195SDaniel Vetter return -ENOMEM; 30652217195SDaniel Vetter } 30752217195SDaniel Vetter EXPORT_SYMBOL(drm_mode_connector_attach_encoder); 30852217195SDaniel Vetter 30952217195SDaniel Vetter static void drm_mode_remove(struct drm_connector *connector, 31052217195SDaniel Vetter struct drm_display_mode *mode) 31152217195SDaniel Vetter { 31252217195SDaniel Vetter list_del(&mode->head); 31352217195SDaniel Vetter drm_mode_destroy(connector->dev, mode); 31452217195SDaniel Vetter } 31552217195SDaniel Vetter 31652217195SDaniel Vetter /** 31752217195SDaniel Vetter * drm_connector_cleanup - cleans up an initialised connector 31852217195SDaniel Vetter * @connector: connector to cleanup 31952217195SDaniel Vetter * 32052217195SDaniel Vetter * Cleans up the connector but doesn't free the object. 32152217195SDaniel Vetter */ 32252217195SDaniel Vetter void drm_connector_cleanup(struct drm_connector *connector) 32352217195SDaniel Vetter { 32452217195SDaniel Vetter struct drm_device *dev = connector->dev; 32552217195SDaniel Vetter struct drm_display_mode *mode, *t; 32652217195SDaniel Vetter 32752217195SDaniel Vetter /* The connector should have been removed from userspace long before 32852217195SDaniel Vetter * it is finally destroyed. 32952217195SDaniel Vetter */ 33052217195SDaniel Vetter if (WARN_ON(connector->registered)) 33152217195SDaniel Vetter drm_connector_unregister(connector); 33252217195SDaniel Vetter 33352217195SDaniel Vetter if (connector->tile_group) { 33452217195SDaniel Vetter drm_mode_put_tile_group(dev, connector->tile_group); 33552217195SDaniel Vetter connector->tile_group = NULL; 33652217195SDaniel Vetter } 33752217195SDaniel Vetter 33852217195SDaniel Vetter list_for_each_entry_safe(mode, t, &connector->probed_modes, head) 33952217195SDaniel Vetter drm_mode_remove(connector, mode); 34052217195SDaniel Vetter 34152217195SDaniel Vetter list_for_each_entry_safe(mode, t, &connector->modes, head) 34252217195SDaniel Vetter drm_mode_remove(connector, mode); 34352217195SDaniel Vetter 34452217195SDaniel Vetter ida_remove(&drm_connector_enum_list[connector->connector_type].ida, 34552217195SDaniel Vetter connector->connector_type_id); 34652217195SDaniel Vetter 34752217195SDaniel Vetter ida_remove(&dev->mode_config.connector_ida, 34852217195SDaniel Vetter connector->index); 34952217195SDaniel Vetter 35052217195SDaniel Vetter kfree(connector->display_info.bus_formats); 35152217195SDaniel Vetter drm_mode_object_unregister(dev, &connector->base); 35252217195SDaniel Vetter kfree(connector->name); 35352217195SDaniel Vetter connector->name = NULL; 35452217195SDaniel Vetter list_del(&connector->head); 35552217195SDaniel Vetter dev->mode_config.num_connector--; 35652217195SDaniel Vetter 35752217195SDaniel Vetter WARN_ON(connector->state && !connector->funcs->atomic_destroy_state); 35852217195SDaniel Vetter if (connector->state && connector->funcs->atomic_destroy_state) 35952217195SDaniel Vetter connector->funcs->atomic_destroy_state(connector, 36052217195SDaniel Vetter connector->state); 36152217195SDaniel Vetter 36252217195SDaniel Vetter memset(connector, 0, sizeof(*connector)); 36352217195SDaniel Vetter } 36452217195SDaniel Vetter EXPORT_SYMBOL(drm_connector_cleanup); 36552217195SDaniel Vetter 36652217195SDaniel Vetter /** 36752217195SDaniel Vetter * drm_connector_register - register a connector 36852217195SDaniel Vetter * @connector: the connector to register 36952217195SDaniel Vetter * 37052217195SDaniel Vetter * Register userspace interfaces for a connector 37152217195SDaniel Vetter * 37252217195SDaniel Vetter * Returns: 37352217195SDaniel Vetter * Zero on success, error code on failure. 37452217195SDaniel Vetter */ 37552217195SDaniel Vetter int drm_connector_register(struct drm_connector *connector) 37652217195SDaniel Vetter { 37752217195SDaniel Vetter int ret; 37852217195SDaniel Vetter 37952217195SDaniel Vetter if (connector->registered) 38052217195SDaniel Vetter return 0; 38152217195SDaniel Vetter 38252217195SDaniel Vetter ret = drm_sysfs_connector_add(connector); 38352217195SDaniel Vetter if (ret) 38452217195SDaniel Vetter return ret; 38552217195SDaniel Vetter 38652217195SDaniel Vetter ret = drm_debugfs_connector_add(connector); 38752217195SDaniel Vetter if (ret) { 38852217195SDaniel Vetter goto err_sysfs; 38952217195SDaniel Vetter } 39052217195SDaniel Vetter 39152217195SDaniel Vetter if (connector->funcs->late_register) { 39252217195SDaniel Vetter ret = connector->funcs->late_register(connector); 39352217195SDaniel Vetter if (ret) 39452217195SDaniel Vetter goto err_debugfs; 39552217195SDaniel Vetter } 39652217195SDaniel Vetter 39752217195SDaniel Vetter drm_mode_object_register(connector->dev, &connector->base); 39852217195SDaniel Vetter 39952217195SDaniel Vetter connector->registered = true; 40052217195SDaniel Vetter return 0; 40152217195SDaniel Vetter 40252217195SDaniel Vetter err_debugfs: 40352217195SDaniel Vetter drm_debugfs_connector_remove(connector); 40452217195SDaniel Vetter err_sysfs: 40552217195SDaniel Vetter drm_sysfs_connector_remove(connector); 40652217195SDaniel Vetter return ret; 40752217195SDaniel Vetter } 40852217195SDaniel Vetter EXPORT_SYMBOL(drm_connector_register); 40952217195SDaniel Vetter 41052217195SDaniel Vetter /** 41152217195SDaniel Vetter * drm_connector_unregister - unregister a connector 41252217195SDaniel Vetter * @connector: the connector to unregister 41352217195SDaniel Vetter * 41452217195SDaniel Vetter * Unregister userspace interfaces for a connector 41552217195SDaniel Vetter */ 41652217195SDaniel Vetter void drm_connector_unregister(struct drm_connector *connector) 41752217195SDaniel Vetter { 41852217195SDaniel Vetter if (!connector->registered) 41952217195SDaniel Vetter return; 42052217195SDaniel Vetter 42152217195SDaniel Vetter if (connector->funcs->early_unregister) 42252217195SDaniel Vetter connector->funcs->early_unregister(connector); 42352217195SDaniel Vetter 42452217195SDaniel Vetter drm_sysfs_connector_remove(connector); 42552217195SDaniel Vetter drm_debugfs_connector_remove(connector); 42652217195SDaniel Vetter 42752217195SDaniel Vetter connector->registered = false; 42852217195SDaniel Vetter } 42952217195SDaniel Vetter EXPORT_SYMBOL(drm_connector_unregister); 43052217195SDaniel Vetter 43152217195SDaniel Vetter void drm_connector_unregister_all(struct drm_device *dev) 43252217195SDaniel Vetter { 43352217195SDaniel Vetter struct drm_connector *connector; 43452217195SDaniel Vetter 43552217195SDaniel Vetter /* FIXME: taking the mode config mutex ends up in a clash with sysfs */ 43652217195SDaniel Vetter list_for_each_entry(connector, &dev->mode_config.connector_list, head) 43752217195SDaniel Vetter drm_connector_unregister(connector); 43852217195SDaniel Vetter } 43952217195SDaniel Vetter 44052217195SDaniel Vetter int drm_connector_register_all(struct drm_device *dev) 44152217195SDaniel Vetter { 44252217195SDaniel Vetter struct drm_connector *connector; 44352217195SDaniel Vetter int ret; 44452217195SDaniel Vetter 44552217195SDaniel Vetter /* FIXME: taking the mode config mutex ends up in a clash with 44652217195SDaniel Vetter * fbcon/backlight registration */ 44752217195SDaniel Vetter list_for_each_entry(connector, &dev->mode_config.connector_list, head) { 44852217195SDaniel Vetter ret = drm_connector_register(connector); 44952217195SDaniel Vetter if (ret) 45052217195SDaniel Vetter goto err; 45152217195SDaniel Vetter } 45252217195SDaniel Vetter 45352217195SDaniel Vetter return 0; 45452217195SDaniel Vetter 45552217195SDaniel Vetter err: 45652217195SDaniel Vetter mutex_unlock(&dev->mode_config.mutex); 45752217195SDaniel Vetter drm_connector_unregister_all(dev); 45852217195SDaniel Vetter return ret; 45952217195SDaniel Vetter } 46052217195SDaniel Vetter 46152217195SDaniel Vetter /** 46252217195SDaniel Vetter * drm_get_connector_status_name - return a string for connector status 46352217195SDaniel Vetter * @status: connector status to compute name of 46452217195SDaniel Vetter * 46552217195SDaniel Vetter * In contrast to the other drm_get_*_name functions this one here returns a 46652217195SDaniel Vetter * const pointer and hence is threadsafe. 46752217195SDaniel Vetter */ 46852217195SDaniel Vetter const char *drm_get_connector_status_name(enum drm_connector_status status) 46952217195SDaniel Vetter { 47052217195SDaniel Vetter if (status == connector_status_connected) 47152217195SDaniel Vetter return "connected"; 47252217195SDaniel Vetter else if (status == connector_status_disconnected) 47352217195SDaniel Vetter return "disconnected"; 47452217195SDaniel Vetter else 47552217195SDaniel Vetter return "unknown"; 47652217195SDaniel Vetter } 47752217195SDaniel Vetter EXPORT_SYMBOL(drm_get_connector_status_name); 47852217195SDaniel Vetter 47952217195SDaniel Vetter static const struct drm_prop_enum_list drm_subpixel_enum_list[] = { 48052217195SDaniel Vetter { SubPixelUnknown, "Unknown" }, 48152217195SDaniel Vetter { SubPixelHorizontalRGB, "Horizontal RGB" }, 48252217195SDaniel Vetter { SubPixelHorizontalBGR, "Horizontal BGR" }, 48352217195SDaniel Vetter { SubPixelVerticalRGB, "Vertical RGB" }, 48452217195SDaniel Vetter { SubPixelVerticalBGR, "Vertical BGR" }, 48552217195SDaniel Vetter { SubPixelNone, "None" }, 48652217195SDaniel Vetter }; 48752217195SDaniel Vetter 48852217195SDaniel Vetter /** 48952217195SDaniel Vetter * drm_get_subpixel_order_name - return a string for a given subpixel enum 49052217195SDaniel Vetter * @order: enum of subpixel_order 49152217195SDaniel Vetter * 49252217195SDaniel Vetter * Note you could abuse this and return something out of bounds, but that 49352217195SDaniel Vetter * would be a caller error. No unscrubbed user data should make it here. 49452217195SDaniel Vetter */ 49552217195SDaniel Vetter const char *drm_get_subpixel_order_name(enum subpixel_order order) 49652217195SDaniel Vetter { 49752217195SDaniel Vetter return drm_subpixel_enum_list[order].name; 49852217195SDaniel Vetter } 49952217195SDaniel Vetter EXPORT_SYMBOL(drm_get_subpixel_order_name); 50052217195SDaniel Vetter 50152217195SDaniel Vetter static const struct drm_prop_enum_list drm_dpms_enum_list[] = { 50252217195SDaniel Vetter { DRM_MODE_DPMS_ON, "On" }, 50352217195SDaniel Vetter { DRM_MODE_DPMS_STANDBY, "Standby" }, 50452217195SDaniel Vetter { DRM_MODE_DPMS_SUSPEND, "Suspend" }, 50552217195SDaniel Vetter { DRM_MODE_DPMS_OFF, "Off" } 50652217195SDaniel Vetter }; 50752217195SDaniel Vetter DRM_ENUM_NAME_FN(drm_get_dpms_name, drm_dpms_enum_list) 50852217195SDaniel Vetter 509b3c6c8bfSDaniel Vetter /** 510b3c6c8bfSDaniel Vetter * drm_display_info_set_bus_formats - set the supported bus formats 511b3c6c8bfSDaniel Vetter * @info: display info to store bus formats in 512b3c6c8bfSDaniel Vetter * @formats: array containing the supported bus formats 513b3c6c8bfSDaniel Vetter * @num_formats: the number of entries in the fmts array 514b3c6c8bfSDaniel Vetter * 515b3c6c8bfSDaniel Vetter * Store the supported bus formats in display info structure. 516b3c6c8bfSDaniel Vetter * See MEDIA_BUS_FMT_* definitions in include/uapi/linux/media-bus-format.h for 517b3c6c8bfSDaniel Vetter * a full list of available formats. 518b3c6c8bfSDaniel Vetter */ 519b3c6c8bfSDaniel Vetter int drm_display_info_set_bus_formats(struct drm_display_info *info, 520b3c6c8bfSDaniel Vetter const u32 *formats, 521b3c6c8bfSDaniel Vetter unsigned int num_formats) 522b3c6c8bfSDaniel Vetter { 523b3c6c8bfSDaniel Vetter u32 *fmts = NULL; 524b3c6c8bfSDaniel Vetter 525b3c6c8bfSDaniel Vetter if (!formats && num_formats) 526b3c6c8bfSDaniel Vetter return -EINVAL; 527b3c6c8bfSDaniel Vetter 528b3c6c8bfSDaniel Vetter if (formats && num_formats) { 529b3c6c8bfSDaniel Vetter fmts = kmemdup(formats, sizeof(*formats) * num_formats, 530b3c6c8bfSDaniel Vetter GFP_KERNEL); 531b3c6c8bfSDaniel Vetter if (!fmts) 532b3c6c8bfSDaniel Vetter return -ENOMEM; 533b3c6c8bfSDaniel Vetter } 534b3c6c8bfSDaniel Vetter 535b3c6c8bfSDaniel Vetter kfree(info->bus_formats); 536b3c6c8bfSDaniel Vetter info->bus_formats = fmts; 537b3c6c8bfSDaniel Vetter info->num_bus_formats = num_formats; 538b3c6c8bfSDaniel Vetter 539b3c6c8bfSDaniel Vetter return 0; 540b3c6c8bfSDaniel Vetter } 541b3c6c8bfSDaniel Vetter EXPORT_SYMBOL(drm_display_info_set_bus_formats); 542b3c6c8bfSDaniel Vetter 54352217195SDaniel Vetter /* Optional connector properties. */ 54452217195SDaniel Vetter static const struct drm_prop_enum_list drm_scaling_mode_enum_list[] = { 54552217195SDaniel Vetter { DRM_MODE_SCALE_NONE, "None" }, 54652217195SDaniel Vetter { DRM_MODE_SCALE_FULLSCREEN, "Full" }, 54752217195SDaniel Vetter { DRM_MODE_SCALE_CENTER, "Center" }, 54852217195SDaniel Vetter { DRM_MODE_SCALE_ASPECT, "Full aspect" }, 54952217195SDaniel Vetter }; 55052217195SDaniel Vetter 55152217195SDaniel Vetter static const struct drm_prop_enum_list drm_aspect_ratio_enum_list[] = { 55252217195SDaniel Vetter { DRM_MODE_PICTURE_ASPECT_NONE, "Automatic" }, 55352217195SDaniel Vetter { DRM_MODE_PICTURE_ASPECT_4_3, "4:3" }, 55452217195SDaniel Vetter { DRM_MODE_PICTURE_ASPECT_16_9, "16:9" }, 55552217195SDaniel Vetter }; 55652217195SDaniel Vetter 55752217195SDaniel Vetter static const struct drm_prop_enum_list drm_dvi_i_select_enum_list[] = { 55852217195SDaniel Vetter { DRM_MODE_SUBCONNECTOR_Automatic, "Automatic" }, /* DVI-I and TV-out */ 55952217195SDaniel Vetter { DRM_MODE_SUBCONNECTOR_DVID, "DVI-D" }, /* DVI-I */ 56052217195SDaniel Vetter { DRM_MODE_SUBCONNECTOR_DVIA, "DVI-A" }, /* DVI-I */ 56152217195SDaniel Vetter }; 56252217195SDaniel Vetter DRM_ENUM_NAME_FN(drm_get_dvi_i_select_name, drm_dvi_i_select_enum_list) 56352217195SDaniel Vetter 56452217195SDaniel Vetter static const struct drm_prop_enum_list drm_dvi_i_subconnector_enum_list[] = { 56552217195SDaniel Vetter { DRM_MODE_SUBCONNECTOR_Unknown, "Unknown" }, /* DVI-I and TV-out */ 56652217195SDaniel Vetter { DRM_MODE_SUBCONNECTOR_DVID, "DVI-D" }, /* DVI-I */ 56752217195SDaniel Vetter { DRM_MODE_SUBCONNECTOR_DVIA, "DVI-A" }, /* DVI-I */ 56852217195SDaniel Vetter }; 56952217195SDaniel Vetter DRM_ENUM_NAME_FN(drm_get_dvi_i_subconnector_name, 57052217195SDaniel Vetter drm_dvi_i_subconnector_enum_list) 57152217195SDaniel Vetter 57252217195SDaniel Vetter static const struct drm_prop_enum_list drm_tv_select_enum_list[] = { 57352217195SDaniel Vetter { DRM_MODE_SUBCONNECTOR_Automatic, "Automatic" }, /* DVI-I and TV-out */ 57452217195SDaniel Vetter { DRM_MODE_SUBCONNECTOR_Composite, "Composite" }, /* TV-out */ 57552217195SDaniel Vetter { DRM_MODE_SUBCONNECTOR_SVIDEO, "SVIDEO" }, /* TV-out */ 57652217195SDaniel Vetter { DRM_MODE_SUBCONNECTOR_Component, "Component" }, /* TV-out */ 57752217195SDaniel Vetter { DRM_MODE_SUBCONNECTOR_SCART, "SCART" }, /* TV-out */ 57852217195SDaniel Vetter }; 57952217195SDaniel Vetter DRM_ENUM_NAME_FN(drm_get_tv_select_name, drm_tv_select_enum_list) 58052217195SDaniel Vetter 58152217195SDaniel Vetter static const struct drm_prop_enum_list drm_tv_subconnector_enum_list[] = { 58252217195SDaniel Vetter { DRM_MODE_SUBCONNECTOR_Unknown, "Unknown" }, /* DVI-I and TV-out */ 58352217195SDaniel Vetter { DRM_MODE_SUBCONNECTOR_Composite, "Composite" }, /* TV-out */ 58452217195SDaniel Vetter { DRM_MODE_SUBCONNECTOR_SVIDEO, "SVIDEO" }, /* TV-out */ 58552217195SDaniel Vetter { DRM_MODE_SUBCONNECTOR_Component, "Component" }, /* TV-out */ 58652217195SDaniel Vetter { DRM_MODE_SUBCONNECTOR_SCART, "SCART" }, /* TV-out */ 58752217195SDaniel Vetter }; 58852217195SDaniel Vetter DRM_ENUM_NAME_FN(drm_get_tv_subconnector_name, 58952217195SDaniel Vetter drm_tv_subconnector_enum_list) 59052217195SDaniel Vetter 59152217195SDaniel Vetter int drm_connector_create_standard_properties(struct drm_device *dev) 59252217195SDaniel Vetter { 59352217195SDaniel Vetter struct drm_property *prop; 59452217195SDaniel Vetter 59552217195SDaniel Vetter prop = drm_property_create(dev, DRM_MODE_PROP_BLOB | 59652217195SDaniel Vetter DRM_MODE_PROP_IMMUTABLE, 59752217195SDaniel Vetter "EDID", 0); 59852217195SDaniel Vetter if (!prop) 59952217195SDaniel Vetter return -ENOMEM; 60052217195SDaniel Vetter dev->mode_config.edid_property = prop; 60152217195SDaniel Vetter 60252217195SDaniel Vetter prop = drm_property_create_enum(dev, 0, 60352217195SDaniel Vetter "DPMS", drm_dpms_enum_list, 60452217195SDaniel Vetter ARRAY_SIZE(drm_dpms_enum_list)); 60552217195SDaniel Vetter if (!prop) 60652217195SDaniel Vetter return -ENOMEM; 60752217195SDaniel Vetter dev->mode_config.dpms_property = prop; 60852217195SDaniel Vetter 60952217195SDaniel Vetter prop = drm_property_create(dev, 61052217195SDaniel Vetter DRM_MODE_PROP_BLOB | 61152217195SDaniel Vetter DRM_MODE_PROP_IMMUTABLE, 61252217195SDaniel Vetter "PATH", 0); 61352217195SDaniel Vetter if (!prop) 61452217195SDaniel Vetter return -ENOMEM; 61552217195SDaniel Vetter dev->mode_config.path_property = prop; 61652217195SDaniel Vetter 61752217195SDaniel Vetter prop = drm_property_create(dev, 61852217195SDaniel Vetter DRM_MODE_PROP_BLOB | 61952217195SDaniel Vetter DRM_MODE_PROP_IMMUTABLE, 62052217195SDaniel Vetter "TILE", 0); 62152217195SDaniel Vetter if (!prop) 62252217195SDaniel Vetter return -ENOMEM; 62352217195SDaniel Vetter dev->mode_config.tile_property = prop; 62452217195SDaniel Vetter 62552217195SDaniel Vetter return 0; 62652217195SDaniel Vetter } 62752217195SDaniel Vetter 62852217195SDaniel Vetter /** 62952217195SDaniel Vetter * drm_mode_create_dvi_i_properties - create DVI-I specific connector properties 63052217195SDaniel Vetter * @dev: DRM device 63152217195SDaniel Vetter * 63252217195SDaniel Vetter * Called by a driver the first time a DVI-I connector is made. 63352217195SDaniel Vetter */ 63452217195SDaniel Vetter int drm_mode_create_dvi_i_properties(struct drm_device *dev) 63552217195SDaniel Vetter { 63652217195SDaniel Vetter struct drm_property *dvi_i_selector; 63752217195SDaniel Vetter struct drm_property *dvi_i_subconnector; 63852217195SDaniel Vetter 63952217195SDaniel Vetter if (dev->mode_config.dvi_i_select_subconnector_property) 64052217195SDaniel Vetter return 0; 64152217195SDaniel Vetter 64252217195SDaniel Vetter dvi_i_selector = 64352217195SDaniel Vetter drm_property_create_enum(dev, 0, 64452217195SDaniel Vetter "select subconnector", 64552217195SDaniel Vetter drm_dvi_i_select_enum_list, 64652217195SDaniel Vetter ARRAY_SIZE(drm_dvi_i_select_enum_list)); 64752217195SDaniel Vetter dev->mode_config.dvi_i_select_subconnector_property = dvi_i_selector; 64852217195SDaniel Vetter 64952217195SDaniel Vetter dvi_i_subconnector = drm_property_create_enum(dev, DRM_MODE_PROP_IMMUTABLE, 65052217195SDaniel Vetter "subconnector", 65152217195SDaniel Vetter drm_dvi_i_subconnector_enum_list, 65252217195SDaniel Vetter ARRAY_SIZE(drm_dvi_i_subconnector_enum_list)); 65352217195SDaniel Vetter dev->mode_config.dvi_i_subconnector_property = dvi_i_subconnector; 65452217195SDaniel Vetter 65552217195SDaniel Vetter return 0; 65652217195SDaniel Vetter } 65752217195SDaniel Vetter EXPORT_SYMBOL(drm_mode_create_dvi_i_properties); 65852217195SDaniel Vetter 65952217195SDaniel Vetter /** 66052217195SDaniel Vetter * drm_create_tv_properties - create TV specific connector properties 66152217195SDaniel Vetter * @dev: DRM device 66252217195SDaniel Vetter * @num_modes: number of different TV formats (modes) supported 66352217195SDaniel Vetter * @modes: array of pointers to strings containing name of each format 66452217195SDaniel Vetter * 66552217195SDaniel Vetter * Called by a driver's TV initialization routine, this function creates 66652217195SDaniel Vetter * the TV specific connector properties for a given device. Caller is 66752217195SDaniel Vetter * responsible for allocating a list of format names and passing them to 66852217195SDaniel Vetter * this routine. 66952217195SDaniel Vetter */ 67052217195SDaniel Vetter int drm_mode_create_tv_properties(struct drm_device *dev, 67152217195SDaniel Vetter unsigned int num_modes, 67252217195SDaniel Vetter const char * const modes[]) 67352217195SDaniel Vetter { 67452217195SDaniel Vetter struct drm_property *tv_selector; 67552217195SDaniel Vetter struct drm_property *tv_subconnector; 67652217195SDaniel Vetter unsigned int i; 67752217195SDaniel Vetter 67852217195SDaniel Vetter if (dev->mode_config.tv_select_subconnector_property) 67952217195SDaniel Vetter return 0; 68052217195SDaniel Vetter 68152217195SDaniel Vetter /* 68252217195SDaniel Vetter * Basic connector properties 68352217195SDaniel Vetter */ 68452217195SDaniel Vetter tv_selector = drm_property_create_enum(dev, 0, 68552217195SDaniel Vetter "select subconnector", 68652217195SDaniel Vetter drm_tv_select_enum_list, 68752217195SDaniel Vetter ARRAY_SIZE(drm_tv_select_enum_list)); 68852217195SDaniel Vetter if (!tv_selector) 68952217195SDaniel Vetter goto nomem; 69052217195SDaniel Vetter 69152217195SDaniel Vetter dev->mode_config.tv_select_subconnector_property = tv_selector; 69252217195SDaniel Vetter 69352217195SDaniel Vetter tv_subconnector = 69452217195SDaniel Vetter drm_property_create_enum(dev, DRM_MODE_PROP_IMMUTABLE, 69552217195SDaniel Vetter "subconnector", 69652217195SDaniel Vetter drm_tv_subconnector_enum_list, 69752217195SDaniel Vetter ARRAY_SIZE(drm_tv_subconnector_enum_list)); 69852217195SDaniel Vetter if (!tv_subconnector) 69952217195SDaniel Vetter goto nomem; 70052217195SDaniel Vetter dev->mode_config.tv_subconnector_property = tv_subconnector; 70152217195SDaniel Vetter 70252217195SDaniel Vetter /* 70352217195SDaniel Vetter * Other, TV specific properties: margins & TV modes. 70452217195SDaniel Vetter */ 70552217195SDaniel Vetter dev->mode_config.tv_left_margin_property = 70652217195SDaniel Vetter drm_property_create_range(dev, 0, "left margin", 0, 100); 70752217195SDaniel Vetter if (!dev->mode_config.tv_left_margin_property) 70852217195SDaniel Vetter goto nomem; 70952217195SDaniel Vetter 71052217195SDaniel Vetter dev->mode_config.tv_right_margin_property = 71152217195SDaniel Vetter drm_property_create_range(dev, 0, "right margin", 0, 100); 71252217195SDaniel Vetter if (!dev->mode_config.tv_right_margin_property) 71352217195SDaniel Vetter goto nomem; 71452217195SDaniel Vetter 71552217195SDaniel Vetter dev->mode_config.tv_top_margin_property = 71652217195SDaniel Vetter drm_property_create_range(dev, 0, "top margin", 0, 100); 71752217195SDaniel Vetter if (!dev->mode_config.tv_top_margin_property) 71852217195SDaniel Vetter goto nomem; 71952217195SDaniel Vetter 72052217195SDaniel Vetter dev->mode_config.tv_bottom_margin_property = 72152217195SDaniel Vetter drm_property_create_range(dev, 0, "bottom margin", 0, 100); 72252217195SDaniel Vetter if (!dev->mode_config.tv_bottom_margin_property) 72352217195SDaniel Vetter goto nomem; 72452217195SDaniel Vetter 72552217195SDaniel Vetter dev->mode_config.tv_mode_property = 72652217195SDaniel Vetter drm_property_create(dev, DRM_MODE_PROP_ENUM, 72752217195SDaniel Vetter "mode", num_modes); 72852217195SDaniel Vetter if (!dev->mode_config.tv_mode_property) 72952217195SDaniel Vetter goto nomem; 73052217195SDaniel Vetter 73152217195SDaniel Vetter for (i = 0; i < num_modes; i++) 73252217195SDaniel Vetter drm_property_add_enum(dev->mode_config.tv_mode_property, i, 73352217195SDaniel Vetter i, modes[i]); 73452217195SDaniel Vetter 73552217195SDaniel Vetter dev->mode_config.tv_brightness_property = 73652217195SDaniel Vetter drm_property_create_range(dev, 0, "brightness", 0, 100); 73752217195SDaniel Vetter if (!dev->mode_config.tv_brightness_property) 73852217195SDaniel Vetter goto nomem; 73952217195SDaniel Vetter 74052217195SDaniel Vetter dev->mode_config.tv_contrast_property = 74152217195SDaniel Vetter drm_property_create_range(dev, 0, "contrast", 0, 100); 74252217195SDaniel Vetter if (!dev->mode_config.tv_contrast_property) 74352217195SDaniel Vetter goto nomem; 74452217195SDaniel Vetter 74552217195SDaniel Vetter dev->mode_config.tv_flicker_reduction_property = 74652217195SDaniel Vetter drm_property_create_range(dev, 0, "flicker reduction", 0, 100); 74752217195SDaniel Vetter if (!dev->mode_config.tv_flicker_reduction_property) 74852217195SDaniel Vetter goto nomem; 74952217195SDaniel Vetter 75052217195SDaniel Vetter dev->mode_config.tv_overscan_property = 75152217195SDaniel Vetter drm_property_create_range(dev, 0, "overscan", 0, 100); 75252217195SDaniel Vetter if (!dev->mode_config.tv_overscan_property) 75352217195SDaniel Vetter goto nomem; 75452217195SDaniel Vetter 75552217195SDaniel Vetter dev->mode_config.tv_saturation_property = 75652217195SDaniel Vetter drm_property_create_range(dev, 0, "saturation", 0, 100); 75752217195SDaniel Vetter if (!dev->mode_config.tv_saturation_property) 75852217195SDaniel Vetter goto nomem; 75952217195SDaniel Vetter 76052217195SDaniel Vetter dev->mode_config.tv_hue_property = 76152217195SDaniel Vetter drm_property_create_range(dev, 0, "hue", 0, 100); 76252217195SDaniel Vetter if (!dev->mode_config.tv_hue_property) 76352217195SDaniel Vetter goto nomem; 76452217195SDaniel Vetter 76552217195SDaniel Vetter return 0; 76652217195SDaniel Vetter nomem: 76752217195SDaniel Vetter return -ENOMEM; 76852217195SDaniel Vetter } 76952217195SDaniel Vetter EXPORT_SYMBOL(drm_mode_create_tv_properties); 77052217195SDaniel Vetter 77152217195SDaniel Vetter /** 77252217195SDaniel Vetter * drm_mode_create_scaling_mode_property - create scaling mode property 77352217195SDaniel Vetter * @dev: DRM device 77452217195SDaniel Vetter * 77552217195SDaniel Vetter * Called by a driver the first time it's needed, must be attached to desired 77652217195SDaniel Vetter * connectors. 77752217195SDaniel Vetter */ 77852217195SDaniel Vetter int drm_mode_create_scaling_mode_property(struct drm_device *dev) 77952217195SDaniel Vetter { 78052217195SDaniel Vetter struct drm_property *scaling_mode; 78152217195SDaniel Vetter 78252217195SDaniel Vetter if (dev->mode_config.scaling_mode_property) 78352217195SDaniel Vetter return 0; 78452217195SDaniel Vetter 78552217195SDaniel Vetter scaling_mode = 78652217195SDaniel Vetter drm_property_create_enum(dev, 0, "scaling mode", 78752217195SDaniel Vetter drm_scaling_mode_enum_list, 78852217195SDaniel Vetter ARRAY_SIZE(drm_scaling_mode_enum_list)); 78952217195SDaniel Vetter 79052217195SDaniel Vetter dev->mode_config.scaling_mode_property = scaling_mode; 79152217195SDaniel Vetter 79252217195SDaniel Vetter return 0; 79352217195SDaniel Vetter } 79452217195SDaniel Vetter EXPORT_SYMBOL(drm_mode_create_scaling_mode_property); 79552217195SDaniel Vetter 79652217195SDaniel Vetter /** 79752217195SDaniel Vetter * drm_mode_create_aspect_ratio_property - create aspect ratio property 79852217195SDaniel Vetter * @dev: DRM device 79952217195SDaniel Vetter * 80052217195SDaniel Vetter * Called by a driver the first time it's needed, must be attached to desired 80152217195SDaniel Vetter * connectors. 80252217195SDaniel Vetter * 80352217195SDaniel Vetter * Returns: 80452217195SDaniel Vetter * Zero on success, negative errno on failure. 80552217195SDaniel Vetter */ 80652217195SDaniel Vetter int drm_mode_create_aspect_ratio_property(struct drm_device *dev) 80752217195SDaniel Vetter { 80852217195SDaniel Vetter if (dev->mode_config.aspect_ratio_property) 80952217195SDaniel Vetter return 0; 81052217195SDaniel Vetter 81152217195SDaniel Vetter dev->mode_config.aspect_ratio_property = 81252217195SDaniel Vetter drm_property_create_enum(dev, 0, "aspect ratio", 81352217195SDaniel Vetter drm_aspect_ratio_enum_list, 81452217195SDaniel Vetter ARRAY_SIZE(drm_aspect_ratio_enum_list)); 81552217195SDaniel Vetter 81652217195SDaniel Vetter if (dev->mode_config.aspect_ratio_property == NULL) 81752217195SDaniel Vetter return -ENOMEM; 81852217195SDaniel Vetter 81952217195SDaniel Vetter return 0; 82052217195SDaniel Vetter } 82152217195SDaniel Vetter EXPORT_SYMBOL(drm_mode_create_aspect_ratio_property); 82252217195SDaniel Vetter 82352217195SDaniel Vetter /** 82452217195SDaniel Vetter * drm_mode_create_suggested_offset_properties - create suggests offset properties 82552217195SDaniel Vetter * @dev: DRM device 82652217195SDaniel Vetter * 82752217195SDaniel Vetter * Create the the suggested x/y offset property for connectors. 82852217195SDaniel Vetter */ 82952217195SDaniel Vetter int drm_mode_create_suggested_offset_properties(struct drm_device *dev) 83052217195SDaniel Vetter { 83152217195SDaniel Vetter if (dev->mode_config.suggested_x_property && dev->mode_config.suggested_y_property) 83252217195SDaniel Vetter return 0; 83352217195SDaniel Vetter 83452217195SDaniel Vetter dev->mode_config.suggested_x_property = 83552217195SDaniel Vetter drm_property_create_range(dev, DRM_MODE_PROP_IMMUTABLE, "suggested X", 0, 0xffffffff); 83652217195SDaniel Vetter 83752217195SDaniel Vetter dev->mode_config.suggested_y_property = 83852217195SDaniel Vetter drm_property_create_range(dev, DRM_MODE_PROP_IMMUTABLE, "suggested Y", 0, 0xffffffff); 83952217195SDaniel Vetter 84052217195SDaniel Vetter if (dev->mode_config.suggested_x_property == NULL || 84152217195SDaniel Vetter dev->mode_config.suggested_y_property == NULL) 84252217195SDaniel Vetter return -ENOMEM; 84352217195SDaniel Vetter return 0; 84452217195SDaniel Vetter } 84552217195SDaniel Vetter EXPORT_SYMBOL(drm_mode_create_suggested_offset_properties); 84652217195SDaniel Vetter 84752217195SDaniel Vetter /** 84852217195SDaniel Vetter * drm_mode_connector_set_path_property - set tile property on connector 84952217195SDaniel Vetter * @connector: connector to set property on. 85052217195SDaniel Vetter * @path: path to use for property; must not be NULL. 85152217195SDaniel Vetter * 85252217195SDaniel Vetter * This creates a property to expose to userspace to specify a 85352217195SDaniel Vetter * connector path. This is mainly used for DisplayPort MST where 85452217195SDaniel Vetter * connectors have a topology and we want to allow userspace to give 85552217195SDaniel Vetter * them more meaningful names. 85652217195SDaniel Vetter * 85752217195SDaniel Vetter * Returns: 85852217195SDaniel Vetter * Zero on success, negative errno on failure. 85952217195SDaniel Vetter */ 86052217195SDaniel Vetter int drm_mode_connector_set_path_property(struct drm_connector *connector, 86152217195SDaniel Vetter const char *path) 86252217195SDaniel Vetter { 86352217195SDaniel Vetter struct drm_device *dev = connector->dev; 86452217195SDaniel Vetter int ret; 86552217195SDaniel Vetter 86652217195SDaniel Vetter ret = drm_property_replace_global_blob(dev, 86752217195SDaniel Vetter &connector->path_blob_ptr, 86852217195SDaniel Vetter strlen(path) + 1, 86952217195SDaniel Vetter path, 87052217195SDaniel Vetter &connector->base, 87152217195SDaniel Vetter dev->mode_config.path_property); 87252217195SDaniel Vetter return ret; 87352217195SDaniel Vetter } 87452217195SDaniel Vetter EXPORT_SYMBOL(drm_mode_connector_set_path_property); 87552217195SDaniel Vetter 87652217195SDaniel Vetter /** 87752217195SDaniel Vetter * drm_mode_connector_set_tile_property - set tile property on connector 87852217195SDaniel Vetter * @connector: connector to set property on. 87952217195SDaniel Vetter * 88052217195SDaniel Vetter * This looks up the tile information for a connector, and creates a 88152217195SDaniel Vetter * property for userspace to parse if it exists. The property is of 88252217195SDaniel Vetter * the form of 8 integers using ':' as a separator. 88352217195SDaniel Vetter * 88452217195SDaniel Vetter * Returns: 88552217195SDaniel Vetter * Zero on success, errno on failure. 88652217195SDaniel Vetter */ 88752217195SDaniel Vetter int drm_mode_connector_set_tile_property(struct drm_connector *connector) 88852217195SDaniel Vetter { 88952217195SDaniel Vetter struct drm_device *dev = connector->dev; 89052217195SDaniel Vetter char tile[256]; 89152217195SDaniel Vetter int ret; 89252217195SDaniel Vetter 89352217195SDaniel Vetter if (!connector->has_tile) { 89452217195SDaniel Vetter ret = drm_property_replace_global_blob(dev, 89552217195SDaniel Vetter &connector->tile_blob_ptr, 89652217195SDaniel Vetter 0, 89752217195SDaniel Vetter NULL, 89852217195SDaniel Vetter &connector->base, 89952217195SDaniel Vetter dev->mode_config.tile_property); 90052217195SDaniel Vetter return ret; 90152217195SDaniel Vetter } 90252217195SDaniel Vetter 90352217195SDaniel Vetter snprintf(tile, 256, "%d:%d:%d:%d:%d:%d:%d:%d", 90452217195SDaniel Vetter connector->tile_group->id, connector->tile_is_single_monitor, 90552217195SDaniel Vetter connector->num_h_tile, connector->num_v_tile, 90652217195SDaniel Vetter connector->tile_h_loc, connector->tile_v_loc, 90752217195SDaniel Vetter connector->tile_h_size, connector->tile_v_size); 90852217195SDaniel Vetter 90952217195SDaniel Vetter ret = drm_property_replace_global_blob(dev, 91052217195SDaniel Vetter &connector->tile_blob_ptr, 91152217195SDaniel Vetter strlen(tile) + 1, 91252217195SDaniel Vetter tile, 91352217195SDaniel Vetter &connector->base, 91452217195SDaniel Vetter dev->mode_config.tile_property); 91552217195SDaniel Vetter return ret; 91652217195SDaniel Vetter } 91752217195SDaniel Vetter EXPORT_SYMBOL(drm_mode_connector_set_tile_property); 91852217195SDaniel Vetter 91952217195SDaniel Vetter /** 92052217195SDaniel Vetter * drm_mode_connector_update_edid_property - update the edid property of a connector 92152217195SDaniel Vetter * @connector: drm connector 92252217195SDaniel Vetter * @edid: new value of the edid property 92352217195SDaniel Vetter * 92452217195SDaniel Vetter * This function creates a new blob modeset object and assigns its id to the 92552217195SDaniel Vetter * connector's edid property. 92652217195SDaniel Vetter * 92752217195SDaniel Vetter * Returns: 92852217195SDaniel Vetter * Zero on success, negative errno on failure. 92952217195SDaniel Vetter */ 93052217195SDaniel Vetter int drm_mode_connector_update_edid_property(struct drm_connector *connector, 93152217195SDaniel Vetter const struct edid *edid) 93252217195SDaniel Vetter { 93352217195SDaniel Vetter struct drm_device *dev = connector->dev; 93452217195SDaniel Vetter size_t size = 0; 93552217195SDaniel Vetter int ret; 93652217195SDaniel Vetter 93752217195SDaniel Vetter /* ignore requests to set edid when overridden */ 93852217195SDaniel Vetter if (connector->override_edid) 93952217195SDaniel Vetter return 0; 94052217195SDaniel Vetter 94152217195SDaniel Vetter if (edid) 94252217195SDaniel Vetter size = EDID_LENGTH * (1 + edid->extensions); 94352217195SDaniel Vetter 94452217195SDaniel Vetter ret = drm_property_replace_global_blob(dev, 94552217195SDaniel Vetter &connector->edid_blob_ptr, 94652217195SDaniel Vetter size, 94752217195SDaniel Vetter edid, 94852217195SDaniel Vetter &connector->base, 94952217195SDaniel Vetter dev->mode_config.edid_property); 95052217195SDaniel Vetter return ret; 95152217195SDaniel Vetter } 95252217195SDaniel Vetter EXPORT_SYMBOL(drm_mode_connector_update_edid_property); 95352217195SDaniel Vetter 95452217195SDaniel Vetter int drm_mode_connector_set_obj_prop(struct drm_mode_object *obj, 95552217195SDaniel Vetter struct drm_property *property, 95652217195SDaniel Vetter uint64_t value) 95752217195SDaniel Vetter { 95852217195SDaniel Vetter int ret = -EINVAL; 95952217195SDaniel Vetter struct drm_connector *connector = obj_to_connector(obj); 96052217195SDaniel Vetter 96152217195SDaniel Vetter /* Do DPMS ourselves */ 96252217195SDaniel Vetter if (property == connector->dev->mode_config.dpms_property) { 96352217195SDaniel Vetter ret = (*connector->funcs->dpms)(connector, (int)value); 96452217195SDaniel Vetter } else if (connector->funcs->set_property) 96552217195SDaniel Vetter ret = connector->funcs->set_property(connector, property, value); 96652217195SDaniel Vetter 96752217195SDaniel Vetter /* store the property value if successful */ 96852217195SDaniel Vetter if (!ret) 96952217195SDaniel Vetter drm_object_property_set_value(&connector->base, property, value); 97052217195SDaniel Vetter return ret; 97152217195SDaniel Vetter } 97252217195SDaniel Vetter 97352217195SDaniel Vetter int drm_mode_connector_property_set_ioctl(struct drm_device *dev, 97452217195SDaniel Vetter void *data, struct drm_file *file_priv) 97552217195SDaniel Vetter { 97652217195SDaniel Vetter struct drm_mode_connector_set_property *conn_set_prop = data; 97752217195SDaniel Vetter struct drm_mode_obj_set_property obj_set_prop = { 97852217195SDaniel Vetter .value = conn_set_prop->value, 97952217195SDaniel Vetter .prop_id = conn_set_prop->prop_id, 98052217195SDaniel Vetter .obj_id = conn_set_prop->connector_id, 98152217195SDaniel Vetter .obj_type = DRM_MODE_OBJECT_CONNECTOR 98252217195SDaniel Vetter }; 98352217195SDaniel Vetter 98452217195SDaniel Vetter /* It does all the locking and checking we need */ 98552217195SDaniel Vetter return drm_mode_obj_set_property_ioctl(dev, &obj_set_prop, file_priv); 98652217195SDaniel Vetter } 98752217195SDaniel Vetter 98852217195SDaniel Vetter static struct drm_encoder *drm_connector_get_encoder(struct drm_connector *connector) 98952217195SDaniel Vetter { 99052217195SDaniel Vetter /* For atomic drivers only state objects are synchronously updated and 99152217195SDaniel Vetter * protected by modeset locks, so check those first. */ 99252217195SDaniel Vetter if (connector->state) 99352217195SDaniel Vetter return connector->state->best_encoder; 99452217195SDaniel Vetter return connector->encoder; 99552217195SDaniel Vetter } 99652217195SDaniel Vetter 99752217195SDaniel Vetter static bool drm_mode_expose_to_userspace(const struct drm_display_mode *mode, 99852217195SDaniel Vetter const struct drm_file *file_priv) 99952217195SDaniel Vetter { 100052217195SDaniel Vetter /* 100152217195SDaniel Vetter * If user-space hasn't configured the driver to expose the stereo 3D 100252217195SDaniel Vetter * modes, don't expose them. 100352217195SDaniel Vetter */ 100452217195SDaniel Vetter if (!file_priv->stereo_allowed && drm_mode_is_stereo(mode)) 100552217195SDaniel Vetter return false; 100652217195SDaniel Vetter 100752217195SDaniel Vetter return true; 100852217195SDaniel Vetter } 100952217195SDaniel Vetter 101052217195SDaniel Vetter int drm_mode_getconnector(struct drm_device *dev, void *data, 101152217195SDaniel Vetter struct drm_file *file_priv) 101252217195SDaniel Vetter { 101352217195SDaniel Vetter struct drm_mode_get_connector *out_resp = data; 101452217195SDaniel Vetter struct drm_connector *connector; 101552217195SDaniel Vetter struct drm_encoder *encoder; 101652217195SDaniel Vetter struct drm_display_mode *mode; 101752217195SDaniel Vetter int mode_count = 0; 101852217195SDaniel Vetter int encoders_count = 0; 101952217195SDaniel Vetter int ret = 0; 102052217195SDaniel Vetter int copied = 0; 102152217195SDaniel Vetter int i; 102252217195SDaniel Vetter struct drm_mode_modeinfo u_mode; 102352217195SDaniel Vetter struct drm_mode_modeinfo __user *mode_ptr; 102452217195SDaniel Vetter uint32_t __user *encoder_ptr; 102552217195SDaniel Vetter 102652217195SDaniel Vetter if (!drm_core_check_feature(dev, DRIVER_MODESET)) 102752217195SDaniel Vetter return -EINVAL; 102852217195SDaniel Vetter 102952217195SDaniel Vetter memset(&u_mode, 0, sizeof(struct drm_mode_modeinfo)); 103052217195SDaniel Vetter 103152217195SDaniel Vetter mutex_lock(&dev->mode_config.mutex); 103252217195SDaniel Vetter 103352217195SDaniel Vetter connector = drm_connector_lookup(dev, out_resp->connector_id); 103452217195SDaniel Vetter if (!connector) { 103552217195SDaniel Vetter ret = -ENOENT; 103652217195SDaniel Vetter goto out_unlock; 103752217195SDaniel Vetter } 103852217195SDaniel Vetter 103952217195SDaniel Vetter for (i = 0; i < DRM_CONNECTOR_MAX_ENCODER; i++) 104052217195SDaniel Vetter if (connector->encoder_ids[i] != 0) 104152217195SDaniel Vetter encoders_count++; 104252217195SDaniel Vetter 104352217195SDaniel Vetter if (out_resp->count_modes == 0) { 104452217195SDaniel Vetter connector->funcs->fill_modes(connector, 104552217195SDaniel Vetter dev->mode_config.max_width, 104652217195SDaniel Vetter dev->mode_config.max_height); 104752217195SDaniel Vetter } 104852217195SDaniel Vetter 104952217195SDaniel Vetter /* delayed so we get modes regardless of pre-fill_modes state */ 105052217195SDaniel Vetter list_for_each_entry(mode, &connector->modes, head) 105152217195SDaniel Vetter if (drm_mode_expose_to_userspace(mode, file_priv)) 105252217195SDaniel Vetter mode_count++; 105352217195SDaniel Vetter 105452217195SDaniel Vetter out_resp->connector_id = connector->base.id; 105552217195SDaniel Vetter out_resp->connector_type = connector->connector_type; 105652217195SDaniel Vetter out_resp->connector_type_id = connector->connector_type_id; 105752217195SDaniel Vetter out_resp->mm_width = connector->display_info.width_mm; 105852217195SDaniel Vetter out_resp->mm_height = connector->display_info.height_mm; 105952217195SDaniel Vetter out_resp->subpixel = connector->display_info.subpixel_order; 106052217195SDaniel Vetter out_resp->connection = connector->status; 106152217195SDaniel Vetter 106252217195SDaniel Vetter drm_modeset_lock(&dev->mode_config.connection_mutex, NULL); 106352217195SDaniel Vetter encoder = drm_connector_get_encoder(connector); 106452217195SDaniel Vetter if (encoder) 106552217195SDaniel Vetter out_resp->encoder_id = encoder->base.id; 106652217195SDaniel Vetter else 106752217195SDaniel Vetter out_resp->encoder_id = 0; 106852217195SDaniel Vetter 106952217195SDaniel Vetter /* 107052217195SDaniel Vetter * This ioctl is called twice, once to determine how much space is 107152217195SDaniel Vetter * needed, and the 2nd time to fill it. 107252217195SDaniel Vetter */ 107352217195SDaniel Vetter if ((out_resp->count_modes >= mode_count) && mode_count) { 107452217195SDaniel Vetter copied = 0; 107552217195SDaniel Vetter mode_ptr = (struct drm_mode_modeinfo __user *)(unsigned long)out_resp->modes_ptr; 107652217195SDaniel Vetter list_for_each_entry(mode, &connector->modes, head) { 107752217195SDaniel Vetter if (!drm_mode_expose_to_userspace(mode, file_priv)) 107852217195SDaniel Vetter continue; 107952217195SDaniel Vetter 108052217195SDaniel Vetter drm_mode_convert_to_umode(&u_mode, mode); 108152217195SDaniel Vetter if (copy_to_user(mode_ptr + copied, 108252217195SDaniel Vetter &u_mode, sizeof(u_mode))) { 108352217195SDaniel Vetter ret = -EFAULT; 108452217195SDaniel Vetter goto out; 108552217195SDaniel Vetter } 108652217195SDaniel Vetter copied++; 108752217195SDaniel Vetter } 108852217195SDaniel Vetter } 108952217195SDaniel Vetter out_resp->count_modes = mode_count; 109052217195SDaniel Vetter 109152217195SDaniel Vetter ret = drm_mode_object_get_properties(&connector->base, file_priv->atomic, 109252217195SDaniel Vetter (uint32_t __user *)(unsigned long)(out_resp->props_ptr), 109352217195SDaniel Vetter (uint64_t __user *)(unsigned long)(out_resp->prop_values_ptr), 109452217195SDaniel Vetter &out_resp->count_props); 109552217195SDaniel Vetter if (ret) 109652217195SDaniel Vetter goto out; 109752217195SDaniel Vetter 109852217195SDaniel Vetter if ((out_resp->count_encoders >= encoders_count) && encoders_count) { 109952217195SDaniel Vetter copied = 0; 110052217195SDaniel Vetter encoder_ptr = (uint32_t __user *)(unsigned long)(out_resp->encoders_ptr); 110152217195SDaniel Vetter for (i = 0; i < DRM_CONNECTOR_MAX_ENCODER; i++) { 110252217195SDaniel Vetter if (connector->encoder_ids[i] != 0) { 110352217195SDaniel Vetter if (put_user(connector->encoder_ids[i], 110452217195SDaniel Vetter encoder_ptr + copied)) { 110552217195SDaniel Vetter ret = -EFAULT; 110652217195SDaniel Vetter goto out; 110752217195SDaniel Vetter } 110852217195SDaniel Vetter copied++; 110952217195SDaniel Vetter } 111052217195SDaniel Vetter } 111152217195SDaniel Vetter } 111252217195SDaniel Vetter out_resp->count_encoders = encoders_count; 111352217195SDaniel Vetter 111452217195SDaniel Vetter out: 111552217195SDaniel Vetter drm_modeset_unlock(&dev->mode_config.connection_mutex); 111652217195SDaniel Vetter 111752217195SDaniel Vetter drm_connector_unreference(connector); 111852217195SDaniel Vetter out_unlock: 111952217195SDaniel Vetter mutex_unlock(&dev->mode_config.mutex); 112052217195SDaniel Vetter 112152217195SDaniel Vetter return ret; 112252217195SDaniel Vetter } 112352217195SDaniel Vetter 1124