drm: Remove unnecessary drm_panel_attach and drm_panel_detach
[linux-2.6-microblaze.git] / drivers / gpu / drm / drm_connector.c
index b1099e1..00e40a2 100644 (file)
@@ -27,6 +27,7 @@
 #include <drm/drm_print.h>
 #include <drm/drm_drv.h>
 #include <drm/drm_file.h>
+#include <drm/drm_sysfs.h>
 
 #include <linux/uaccess.h>
 
@@ -37,7 +38,7 @@
  * DOC: overview
  *
  * In DRM connectors are the general abstraction for display sinks, and include
- * als fixed panels or anything else that can display pixels in some form. As
+ * also fixed panels or anything else that can display pixels in some form. As
  * opposed to all other KMS objects representing hardware (like CRTC, encoder or
  * plane abstractions) connectors can be hotplugged and unplugged at runtime.
  * Hence they are reference-counted using drm_connector_get() and
@@ -128,7 +129,7 @@ EXPORT_SYMBOL(drm_get_connector_type_name);
 
 /**
  * drm_connector_get_cmdline_mode - reads the user's cmdline mode
- * @connector: connector to quwery
+ * @connector: connector to query
  *
  * The kernel supports per-connector configuration of its consoles through
  * use of the video= parameter. This function parses that option and
@@ -268,6 +269,7 @@ int drm_connector_init(struct drm_device *dev,
        INIT_LIST_HEAD(&connector->modes);
        mutex_init(&connector->mutex);
        connector->edid_blob_ptr = NULL;
+       connector->epoch_counter = 0;
        connector->tile_blob_ptr = NULL;
        connector->status = connector_status_unknown;
        connector->display_info.panel_orientation =
@@ -523,6 +525,10 @@ int drm_connector_register(struct drm_connector *connector)
        drm_mode_object_register(connector->dev, &connector->base);
 
        connector->registration_state = DRM_CONNECTOR_REGISTERED;
+
+       /* Let userspace know we have a new connector */
+       drm_sysfs_hotplug_event(connector->dev);
+
        goto unlock;
 
 err_debugfs:
@@ -948,8 +954,7 @@ static const struct drm_prop_enum_list dp_colorspaces[] = {
  *     connector is linked to. Drivers should never set this property directly,
  *     it is handled by the DRM core by calling the &drm_connector_funcs.dpms
  *     callback. For atomic drivers the remapping to the "ACTIVE" property is
- *     implemented in the DRM core.  This is the only standard connector
- *     property that userspace can change.
+ *     implemented in the DRM core.
  *
  *     Note that this property cannot be set through the MODE_ATOMIC ioctl,
  *     userspace must use "ACTIVE" on the CRTC instead.
@@ -986,7 +991,7 @@ static const struct drm_prop_enum_list dp_colorspaces[] = {
  *     DP MST sinks), or high-res integrated panels (like dual-link DSI) which
  *     are not gen-locked. Note that for tiled panels which are genlocked, like
  *     dual-link LVDS or dual-link DSI, the driver should try to not expose the
- *     tiling and virtualize both &drm_crtc and &drm_plane if needed. Drivers
+ *     tiling and virtualise both &drm_crtc and &drm_plane if needed. Drivers
  *     should update this value using drm_connector_set_tile_property().
  *     Userspace cannot change this property.
  * link-status:
@@ -995,6 +1000,32 @@ static const struct drm_prop_enum_list dp_colorspaces[] = {
  *      after modeset, the kernel driver may set this to "BAD" and issue a
  *      hotplug uevent. Drivers should update this value using
  *      drm_connector_set_link_status_property().
+ *
+ *      When user-space receives the hotplug uevent and detects a "BAD"
+ *      link-status, the sink doesn't receive pixels anymore (e.g. the screen
+ *      becomes completely black). The list of available modes may have
+ *      changed. User-space is expected to pick a new mode if the current one
+ *      has disappeared and perform a new modeset with link-status set to
+ *      "GOOD" to re-enable the connector.
+ *
+ *      If multiple connectors share the same CRTC and one of them gets a "BAD"
+ *      link-status, the other are unaffected (ie. the sinks still continue to
+ *      receive pixels).
+ *
+ *      When user-space performs an atomic commit on a connector with a "BAD"
+ *      link-status without resetting the property to "GOOD", the sink may
+ *      still not receive pixels. When user-space performs an atomic commit
+ *      which resets the link-status property to "GOOD" without the
+ *      ALLOW_MODESET flag set, it might fail because a modeset is required.
+ *
+ *      User-space can only change link-status to "GOOD", changing it to "BAD"
+ *      is a no-op.
+ *
+ *      For backwards compatibility with non-atomic userspace the kernel
+ *      tries to automatically set the link-status back to "GOOD" in the
+ *      SETCRTC IOCTL. This might fail if the mode is no longer valid, similar
+ *      to how it might fail if a different screen has been connected in the
+ *      interim.
  * non_desktop:
  *     Indicates the output should be ignored for purposes of displaying a
  *     standard desktop environment or console. This is most likely because
@@ -1126,7 +1157,7 @@ static const struct drm_prop_enum_list dp_colorspaces[] = {
  *
  *     It will even need to do colorspace conversion and get all layers
  *     to one common colorspace for blending. It can use either GL, Media
- *     or display engine to get this done based on the capabilties of the
+ *     or display engine to get this done based on the capabilities of the
  *     associated hardware.
  *
  *     Driver expects metadata to be put in &struct hdr_output_metadata
@@ -1609,7 +1640,7 @@ EXPORT_SYMBOL(drm_mode_create_scaling_mode_property);
  * variable refresh rate capability for a connector.
  *
  * Returns:
- * Zero on success, negative errono on failure.
+ * Zero on success, negative errno on failure.
  */
 int drm_connector_attach_vrr_capable_property(
        struct drm_connector *connector)
@@ -1754,7 +1785,7 @@ EXPORT_SYMBOL(drm_mode_create_aspect_ratio_property);
  * HDMI connectors.
  *
  * Returns:
- * Zero on success, negative errono on failure.
+ * Zero on success, negative errno on failure.
  */
 int drm_mode_create_hdmi_colorspace_property(struct drm_connector *connector)
 {
@@ -1783,7 +1814,7 @@ EXPORT_SYMBOL(drm_mode_create_hdmi_colorspace_property);
  * DP connectors.
  *
  * Returns:
- * Zero on success, negative errono on failure.
+ * Zero on success, negative errno on failure.
  */
 int drm_mode_create_dp_colorspace_property(struct drm_connector *connector)
 {
@@ -1835,7 +1866,7 @@ EXPORT_SYMBOL(drm_mode_create_content_type_property);
  * drm_mode_create_suggested_offset_properties - create suggests offset properties
  * @dev: DRM device
  *
- * Create the the suggested x/y offset property for connectors.
+ * Create the suggested x/y offset property for connectors.
  */
 int drm_mode_create_suggested_offset_properties(struct drm_device *dev)
 {
@@ -1949,6 +1980,7 @@ int drm_connector_update_edid_property(struct drm_connector *connector,
        struct drm_device *dev = connector->dev;
        size_t size = 0;
        int ret;
+       const struct edid *old_edid;
 
        /* ignore requests to set edid when overridden */
        if (connector->override_edid)
@@ -1958,7 +1990,7 @@ int drm_connector_update_edid_property(struct drm_connector *connector,
                size = EDID_LENGTH * (1 + edid->extensions);
 
        /* Set the display info, using edid if available, otherwise
-        * reseting the values to defaults. This duplicates the work
+        * resetting the values to defaults. This duplicates the work
         * done in drm_add_edid_modes, but that function is not
         * consistently called before this one in all drivers and the
         * computation is cheap enough that it seems better to
@@ -1972,6 +2004,20 @@ int drm_connector_update_edid_property(struct drm_connector *connector,
 
        drm_update_tile_info(connector, edid);
 
+       if (connector->edid_blob_ptr) {
+               old_edid = (const struct edid *)connector->edid_blob_ptr->data;
+               if (old_edid) {
+                       if (!drm_edid_are_equal(edid, old_edid)) {
+                               DRM_DEBUG_KMS("[CONNECTOR:%d:%s] Edid was changed.\n",
+                                             connector->base.id, connector->name);
+
+                               connector->epoch_counter += 1;
+                               DRM_DEBUG_KMS("Updating change counter to %llu\n",
+                                             connector->epoch_counter);
+                       }
+               }
+       }
+
        drm_object_property_set_value(&connector->base,
                                      dev->mode_config.non_desktop_property,
                                      connector->display_info.non_desktop);
@@ -2071,7 +2117,7 @@ void drm_connector_set_vrr_capable_property(
 EXPORT_SYMBOL(drm_connector_set_vrr_capable_property);
 
 /**
- * drm_connector_set_panel_orientation - sets the connecter's panel_orientation
+ * drm_connector_set_panel_orientation - sets the connector's panel_orientation
  * @connector: connector for which to set the panel-orientation property.
  * @panel_orientation: drm_panel_orientation value to set
  *
@@ -2126,7 +2172,7 @@ EXPORT_SYMBOL(drm_connector_set_panel_orientation);
 
 /**
  * drm_connector_set_panel_orientation_with_quirk -
- *     set the connecter's panel_orientation after checking for quirks
+ *     set the connector's panel_orientation after checking for quirks
  * @connector: connector for which to init the panel-orientation property.
  * @panel_orientation: drm_panel_orientation value to set
  * @width: width in pixels of the panel, used for panel quirk detection
@@ -2363,6 +2409,7 @@ static void drm_tile_group_free(struct kref *kref)
 {
        struct drm_tile_group *tg = container_of(kref, struct drm_tile_group, refcount);
        struct drm_device *dev = tg->dev;
+
        mutex_lock(&dev->mode_config.idr_mutex);
        idr_remove(&dev->mode_config.tile_idr, tg->id);
        mutex_unlock(&dev->mode_config.idr_mutex);
@@ -2398,6 +2445,7 @@ struct drm_tile_group *drm_mode_get_tile_group(struct drm_device *dev,
 {
        struct drm_tile_group *tg;
        int id;
+
        mutex_lock(&dev->mode_config.idr_mutex);
        idr_for_each_entry(&dev->mode_config.tile_idr, tg, id) {
                if (!memcmp(tg->group_data, topology, 8)) {