Merge branch 'for-3.17/drivers' of git://git.kernel.dk/linux-block
[firefly-linux-kernel-4.4.55.git] / drivers / gpu / drm / drm_crtc.c
index f0a777747907eb2af0005d0f676147828082fb0b..fa2be249999c70711e1b19cbe0df92fd5e081631 100644 (file)
@@ -367,6 +367,32 @@ const char *drm_get_format_name(uint32_t format)
 }
 EXPORT_SYMBOL(drm_get_format_name);
 
+/*
+ * Internal function to assign a slot in the object idr and optionally
+ * register the object into the idr.
+ */
+static int drm_mode_object_get_reg(struct drm_device *dev,
+                                  struct drm_mode_object *obj,
+                                  uint32_t obj_type,
+                                  bool register_obj)
+{
+       int ret;
+
+       mutex_lock(&dev->mode_config.idr_mutex);
+       ret = idr_alloc(&dev->mode_config.crtc_idr, register_obj ? obj : NULL, 1, 0, GFP_KERNEL);
+       if (ret >= 0) {
+               /*
+                * Set up the object linking under the protection of the idr
+                * lock so that other users can't see inconsistent state.
+                */
+               obj->id = ret;
+               obj->type = obj_type;
+       }
+       mutex_unlock(&dev->mode_config.idr_mutex);
+
+       return ret < 0 ? ret : 0;
+}
+
 /**
  * drm_mode_object_get - allocate a new modeset identifier
  * @dev: DRM device
@@ -385,21 +411,15 @@ EXPORT_SYMBOL(drm_get_format_name);
 int drm_mode_object_get(struct drm_device *dev,
                        struct drm_mode_object *obj, uint32_t obj_type)
 {
-       int ret;
+       return drm_mode_object_get_reg(dev, obj, obj_type, true);
+}
 
+static void drm_mode_object_register(struct drm_device *dev,
+                                    struct drm_mode_object *obj)
+{
        mutex_lock(&dev->mode_config.idr_mutex);
-       ret = idr_alloc(&dev->mode_config.crtc_idr, obj, 1, 0, GFP_KERNEL);
-       if (ret >= 0) {
-               /*
-                * Set up the object linking under the protection of the idr
-                * lock so that other users can't see inconsistent state.
-                */
-               obj->id = ret;
-               obj->type = obj_type;
-       }
+       idr_replace(&dev->mode_config.crtc_idr, obj, obj->id);
        mutex_unlock(&dev->mode_config.idr_mutex);
-
-       return ret < 0 ? ret : 0;
 }
 
 /**
@@ -426,8 +446,12 @@ static struct drm_mode_object *_object_find(struct drm_device *dev,
 
        mutex_lock(&dev->mode_config.idr_mutex);
        obj = idr_find(&dev->mode_config.crtc_idr, id);
-       if (!obj || (type != DRM_MODE_OBJECT_ANY && obj->type != type) ||
-           (obj->id != id))
+       if (obj && type != DRM_MODE_OBJECT_ANY && obj->type != type)
+               obj = NULL;
+       if (obj && obj->id != id)
+               obj = NULL;
+       /* don't leak out unref'd fb's */
+       if (obj && (obj->type == DRM_MODE_OBJECT_FB))
                obj = NULL;
        mutex_unlock(&dev->mode_config.idr_mutex);
 
@@ -454,9 +478,6 @@ struct drm_mode_object *drm_mode_object_find(struct drm_device *dev,
         * function.*/
        WARN_ON(type == DRM_MODE_OBJECT_FB);
        obj = _object_find(dev, id, type);
-       /* don't leak out unref'd fb's */
-       if (obj && (obj->type == DRM_MODE_OBJECT_FB))
-               obj = NULL;
        return obj;
 }
 EXPORT_SYMBOL(drm_mode_object_find);
@@ -855,7 +876,7 @@ int drm_connector_init(struct drm_device *dev,
 
        drm_modeset_lock_all(dev);
 
-       ret = drm_mode_object_get(dev, &connector->base, DRM_MODE_OBJECT_CONNECTOR);
+       ret = drm_mode_object_get_reg(dev, &connector->base, DRM_MODE_OBJECT_CONNECTOR, false);
        if (ret)
                goto out_unlock;
 
@@ -894,6 +915,8 @@ int drm_connector_init(struct drm_device *dev,
        drm_object_attach_property(&connector->base,
                                      dev->mode_config.dpms_property, 0);
 
+       connector->debugfs_entry = NULL;
+
 out_put:
        if (ret)
                drm_mode_object_put(dev, &connector->base);
@@ -933,6 +956,49 @@ void drm_connector_cleanup(struct drm_connector *connector)
 }
 EXPORT_SYMBOL(drm_connector_cleanup);
 
+/**
+ * drm_connector_register - register a connector
+ * @connector: the connector to register
+ *
+ * Register userspace interfaces for a connector
+ *
+ * Returns:
+ * Zero on success, error code on failure.
+ */
+int drm_connector_register(struct drm_connector *connector)
+{
+       int ret;
+
+       drm_mode_object_register(connector->dev, &connector->base);
+
+       ret = drm_sysfs_connector_add(connector);
+       if (ret)
+               return ret;
+
+       ret = drm_debugfs_connector_add(connector);
+       if (ret) {
+               drm_sysfs_connector_remove(connector);
+               return ret;
+       }
+
+       return 0;
+}
+EXPORT_SYMBOL(drm_connector_register);
+
+/**
+ * drm_connector_unregister - unregister a connector
+ * @connector: the connector to unregister
+ *
+ * Unregister userspace interfaces for a connector
+ */
+void drm_connector_unregister(struct drm_connector *connector)
+{
+       drm_sysfs_connector_remove(connector);
+       drm_debugfs_connector_remove(connector);
+}
+EXPORT_SYMBOL(drm_connector_unregister);
+
+
 /**
  * drm_connector_unplug_all - unregister connector userspace interfaces
  * @dev: drm device
@@ -947,7 +1013,7 @@ void drm_connector_unplug_all(struct drm_device *dev)
 
        /* taking the mode config mutex ends up in a clash with sysfs */
        list_for_each_entry(connector, &dev->mode_config.connector_list, head)
-               drm_sysfs_connector_remove(connector);
+               drm_connector_unregister(connector);
 
 }
 EXPORT_SYMBOL(drm_connector_unplug_all);
@@ -1227,6 +1293,7 @@ static int drm_mode_create_standard_connector_properties(struct drm_device *dev)
 {
        struct drm_property *edid;
        struct drm_property *dpms;
+       struct drm_property *dev_path;
 
        /*
         * Standard properties (apply to all connectors)
@@ -1241,6 +1308,12 @@ static int drm_mode_create_standard_connector_properties(struct drm_device *dev)
                                   ARRAY_SIZE(drm_dpms_enum_list));
        dev->mode_config.dpms_property = dpms;
 
+       dev_path = drm_property_create(dev,
+                                      DRM_MODE_PROP_BLOB |
+                                      DRM_MODE_PROP_IMMUTABLE,
+                                      "PATH", 0);
+       dev->mode_config.path_property = dev_path;
+
        return 0;
 }
 
@@ -1510,6 +1583,15 @@ int drm_mode_group_init_legacy_group(struct drm_device *dev,
 }
 EXPORT_SYMBOL(drm_mode_group_init_legacy_group);
 
+void drm_reinit_primary_mode_group(struct drm_device *dev)
+{
+       drm_modeset_lock_all(dev);
+       drm_mode_group_destroy(&dev->primary->mode_group);
+       drm_mode_group_init_legacy_group(dev, &dev->primary->mode_group);
+       drm_modeset_unlock_all(dev);
+}
+EXPORT_SYMBOL(drm_reinit_primary_mode_group);
+
 /**
  * drm_crtc_convert_to_umode - convert a drm_display_mode into a modeinfo
  * @out: drm_mode_modeinfo struct to return to the user
@@ -3362,7 +3444,7 @@ fail:
 EXPORT_SYMBOL(drm_property_create);
 
 /**
- * drm_property_create - create a new enumeration property type
+ * drm_property_create_enum - create a new enumeration property type
  * @dev: drm device
  * @flags: flags specifying the property type
  * @name: name of the property
@@ -3408,7 +3490,7 @@ struct drm_property *drm_property_create_enum(struct drm_device *dev, int flags,
 EXPORT_SYMBOL(drm_property_create_enum);
 
 /**
- * drm_property_create - create a new bitmask property type
+ * drm_property_create_bitmask - create a new bitmask property type
  * @dev: drm device
  * @flags: flags specifying the property type
  * @name: name of the property
@@ -3479,7 +3561,7 @@ static struct drm_property *property_create_range(struct drm_device *dev,
 }
 
 /**
- * drm_property_create - create a new ranged property type
+ * drm_property_create_range - create a new ranged property type
  * @dev: drm device
  * @flags: flags specifying the property type
  * @name: name of the property
@@ -3898,6 +3980,25 @@ done:
        return ret;
 }
 
+int drm_mode_connector_set_path_property(struct drm_connector *connector,
+                                        char *path)
+{
+       struct drm_device *dev = connector->dev;
+       int ret, size;
+       size = strlen(path) + 1;
+
+       connector->path_blob_ptr = drm_property_create_blob(connector->dev,
+                                                           size, path);
+       if (!connector->path_blob_ptr)
+               return -EINVAL;
+
+       ret = drm_object_property_set_value(&connector->base,
+                                           dev->mode_config.path_property,
+                                           connector->path_blob_ptr->base.id);
+       return ret;
+}
+EXPORT_SYMBOL(drm_mode_connector_set_path_property);
+
 /**
  * drm_mode_connector_update_edid_property - update the edid property of a connector
  * @connector: drm connector
@@ -3915,6 +4016,10 @@ int drm_mode_connector_update_edid_property(struct drm_connector *connector,
        struct drm_device *dev = connector->dev;
        int ret, size;
 
+       /* ignore requests to set edid when overridden */
+       if (connector->override_edid)
+               return 0;
+
        if (connector->edid_blob_ptr)
                drm_property_destroy_blob(dev, connector->edid_blob_ptr);