drm/atomic: Add drm_crtc_state->active
[firefly-linux-kernel-4.4.55.git] / drivers / gpu / drm / drm_crtc.c
index 46fa0945b53ef33cf9e3f12f63f93e36bff8d2a0..419f9d915c787101f60892939bd7a0438db29e8d 100644 (file)
@@ -691,6 +691,10 @@ int drm_crtc_init_with_planes(struct drm_device *dev, struct drm_crtc *crtc,
        if (cursor)
                cursor->possible_crtcs = 1 << drm_crtc_index(crtc);
 
+       if (drm_core_check_feature(dev, DRIVER_ATOMIC)) {
+               drm_object_attach_property(&crtc->base, config->prop_active, 0);
+       }
+
        return 0;
 }
 EXPORT_SYMBOL(drm_crtc_init_with_planes);
@@ -761,6 +765,40 @@ static void drm_mode_remove(struct drm_connector *connector,
        drm_mode_destroy(connector->dev, mode);
 }
 
+/**
+ * drm_display_info_set_bus_formats - set the supported bus formats
+ * @info: display info to store bus formats in
+ * @fmts: array containing the supported bus formats
+ * @nfmts: the number of entries in the fmts array
+ *
+ * Store the supported bus formats in display info structure.
+ * See MEDIA_BUS_FMT_* definitions in include/uapi/linux/media-bus-format.h for
+ * a full list of available formats.
+ */
+int drm_display_info_set_bus_formats(struct drm_display_info *info,
+                                    const u32 *formats,
+                                    unsigned int num_formats)
+{
+       u32 *fmts = NULL;
+
+       if (!formats && num_formats)
+               return -EINVAL;
+
+       if (formats && num_formats) {
+               fmts = kmemdup(formats, sizeof(*formats) * num_formats,
+                              GFP_KERNEL);
+               if (!formats)
+                       return -ENOMEM;
+       }
+
+       kfree(info->bus_formats);
+       info->bus_formats = fmts;
+       info->num_bus_formats = num_formats;
+
+       return 0;
+}
+EXPORT_SYMBOL(drm_display_info_set_bus_formats);
+
 /**
  * drm_connector_get_cmdline_mode - reads the user's cmdline mode
  * @connector: connector to quwery
@@ -831,6 +869,7 @@ int drm_connector_init(struct drm_device *dev,
                       const struct drm_connector_funcs *funcs,
                       int connector_type)
 {
+       struct drm_mode_config *config = &dev->mode_config;
        int ret;
        struct ida *connector_ida =
                &drm_connector_enum_list[connector_type].ida;
@@ -869,16 +908,20 @@ int drm_connector_init(struct drm_device *dev,
 
        /* We should add connectors at the end to avoid upsetting the connector
         * index too much. */
-       list_add_tail(&connector->head, &dev->mode_config.connector_list);
-       dev->mode_config.num_connector++;
+       list_add_tail(&connector->head, &config->connector_list);
+       config->num_connector++;
 
        if (connector_type != DRM_MODE_CONNECTOR_VIRTUAL)
                drm_object_attach_property(&connector->base,
-                                             dev->mode_config.edid_property,
+                                             config->edid_property,
                                              0);
 
        drm_object_attach_property(&connector->base,
-                                     dev->mode_config.dpms_property, 0);
+                                     config->dpms_property, 0);
+
+       if (drm_core_check_feature(dev, DRIVER_ATOMIC)) {
+               drm_object_attach_property(&connector->base, config->prop_crtc_id, 0);
+       }
 
        connector->debugfs_entry = NULL;
 
@@ -918,6 +961,7 @@ void drm_connector_cleanup(struct drm_connector *connector)
        ida_remove(&drm_connector_enum_list[connector->connector_type].ida,
                   connector->connector_type_id);
 
+       kfree(connector->display_info.bus_formats);
        drm_mode_object_put(dev, &connector->base);
        kfree(connector->name);
        connector->name = NULL;
@@ -1441,6 +1485,12 @@ static int drm_mode_create_standard_properties(struct drm_device *dev)
                return -ENOMEM;
        dev->mode_config.prop_crtc_id = prop;
 
+       prop = drm_property_create_bool(dev, DRM_MODE_PROP_ATOMIC,
+                       "ACTIVE");
+       if (!prop)
+               return -ENOMEM;
+       dev->mode_config.prop_active = prop;
+
        return 0;
 }
 
@@ -2653,6 +2703,27 @@ int drm_mode_set_config_internal(struct drm_mode_set *set)
 }
 EXPORT_SYMBOL(drm_mode_set_config_internal);
 
+/**
+ * drm_crtc_get_hv_timing - Fetches hdisplay/vdisplay for given mode
+ * @mode: mode to query
+ * @hdisplay: hdisplay value to fill in
+ * @vdisplay: vdisplay value to fill in
+ *
+ * The vdisplay value will be doubled if the specified mode is a stereo mode of
+ * the appropriate layout.
+ */
+void drm_crtc_get_hv_timing(const struct drm_display_mode *mode,
+                           int *hdisplay, int *vdisplay)
+{
+       struct drm_display_mode adjusted;
+
+       drm_mode_copy(&adjusted, mode);
+       drm_mode_set_crtcinfo(&adjusted, CRTC_STEREO_DOUBLE_ONLY);
+       *hdisplay = adjusted.crtc_hdisplay;
+       *vdisplay = adjusted.crtc_vdisplay;
+}
+EXPORT_SYMBOL(drm_crtc_get_hv_timing);
+
 /**
  * drm_crtc_check_viewport - Checks that a framebuffer is big enough for the
  *     CRTC viewport
@@ -2670,16 +2741,7 @@ int drm_crtc_check_viewport(const struct drm_crtc *crtc,
 {
        int hdisplay, vdisplay;
 
-       hdisplay = mode->hdisplay;
-       vdisplay = mode->vdisplay;
-
-       if (drm_mode_is_stereo(mode)) {
-               struct drm_display_mode adjusted = *mode;
-
-               drm_mode_set_crtcinfo(&adjusted, CRTC_STEREO_DOUBLE);
-               hdisplay = adjusted.crtc_hdisplay;
-               vdisplay = adjusted.crtc_vdisplay;
-       }
+       drm_crtc_get_hv_timing(mode, &hdisplay, &vdisplay);
 
        if (crtc->invert_dimensions)
                swap(hdisplay, vdisplay);
@@ -2775,6 +2837,12 @@ int drm_mode_setcrtc(struct drm_device *dev, void *data,
                        goto out;
                }
 
+               mode->status = drm_mode_validate_basic(mode);
+               if (mode->status != MODE_OK) {
+                       ret = -EINVAL;
+                       goto out;
+               }
+
                drm_mode_set_crtcinfo(mode, CRTC_INTERLACE_HALVE_V);
 
                ret = drm_crtc_check_viewport(crtc, crtc_req->x, crtc_req->y,
@@ -3752,7 +3820,7 @@ static struct drm_property *property_create_range(struct drm_device *dev,
 }
 
 /**
- * drm_property_create_range - create a new ranged property type
+ * drm_property_create_range - create a new unsigned ranged property type
  * @dev: drm device
  * @flags: flags specifying the property type
  * @name: name of the property
@@ -3763,8 +3831,8 @@ static struct drm_property *property_create_range(struct drm_device *dev,
  * object with drm_object_attach_property. The returned property object must be
  * freed with drm_property_destroy.
  *
- * Userspace is allowed to set any integer value in the (min, max) range
- * inclusive.
+ * Userspace is allowed to set any unsigned integer value in the (min, max)
+ * range inclusive.
  *
  * Returns:
  * A pointer to the newly created property on success, NULL on failure.
@@ -3778,6 +3846,24 @@ struct drm_property *drm_property_create_range(struct drm_device *dev, int flags
 }
 EXPORT_SYMBOL(drm_property_create_range);
 
+/**
+ * drm_property_create_signed_range - create a new signed ranged property type
+ * @dev: drm device
+ * @flags: flags specifying the property type
+ * @name: name of the property
+ * @min: minimum value of the property
+ * @max: maximum value of the property
+ *
+ * This creates a new generic drm property which can then be attached to a drm
+ * object with drm_object_attach_property. The returned property object must be
+ * freed with drm_property_destroy.
+ *
+ * Userspace is allowed to set any signed integer value in the (min, max)
+ * range inclusive.
+ *
+ * Returns:
+ * A pointer to the newly created property on success, NULL on failure.
+ */
 struct drm_property *drm_property_create_signed_range(struct drm_device *dev,
                                         int flags, const char *name,
                                         int64_t min, int64_t max)
@@ -3787,6 +3873,23 @@ struct drm_property *drm_property_create_signed_range(struct drm_device *dev,
 }
 EXPORT_SYMBOL(drm_property_create_signed_range);
 
+/**
+ * drm_property_create_object - create a new object property type
+ * @dev: drm device
+ * @flags: flags specifying the property type
+ * @name: name of the property
+ * @type: object type from DRM_MODE_OBJECT_* defines
+ *
+ * This creates a new generic drm property which can then be attached to a drm
+ * object with drm_object_attach_property. The returned property object must be
+ * freed with drm_property_destroy.
+ *
+ * Userspace is only allowed to set this to any property value of the given
+ * @type. Only useful for atomic properties, which is enforced.
+ *
+ * Returns:
+ * A pointer to the newly created property on success, NULL on failure.
+ */
 struct drm_property *drm_property_create_object(struct drm_device *dev,
                                         int flags, const char *name, uint32_t type)
 {
@@ -3794,6 +3897,9 @@ struct drm_property *drm_property_create_object(struct drm_device *dev,
 
        flags |= DRM_MODE_PROP_OBJECT;
 
+       if (WARN_ON(!(flags & DRM_MODE_PROP_ATOMIC)))
+               return NULL;
+
        property = drm_property_create(dev, flags, name, 1);
        if (!property)
                return NULL;
@@ -3804,6 +3910,28 @@ struct drm_property *drm_property_create_object(struct drm_device *dev,
 }
 EXPORT_SYMBOL(drm_property_create_object);
 
+/**
+ * drm_property_create_bool - create a new boolean property type
+ * @dev: drm device
+ * @flags: flags specifying the property type
+ * @name: name of the property
+ *
+ * This creates a new generic drm property which can then be attached to a drm
+ * object with drm_object_attach_property. The returned property object must be
+ * freed with drm_property_destroy.
+ *
+ * This is implemented as a ranged property with only {0, 1} as valid values.
+ *
+ * Returns:
+ * A pointer to the newly created property on success, NULL on failure.
+ */
+struct drm_property *drm_property_create_bool(struct drm_device *dev, int flags,
+                                        const char *name)
+{
+       return drm_property_create_range(dev, flags, name, 0, 1);
+}
+EXPORT_SYMBOL(drm_property_create_bool);
+
 /**
  * drm_property_add_enum - add a possible value to an enumeration property
  * @property: enumeration property to change
@@ -4298,7 +4426,7 @@ EXPORT_SYMBOL(drm_mode_connector_update_edid_property);
  * object to which the property is attached has a chance to take it's own
  * reference).
  */
-static bool drm_property_change_valid_get(struct drm_property *property,
+bool drm_property_change_valid_get(struct drm_property *property,
                                         uint64_t value, struct drm_mode_object **ref)
 {
        int i;
@@ -4346,12 +4474,6 @@ static bool drm_property_change_valid_get(struct drm_property *property,
                } else {
                        return _object_find(property->dev, value, property->values[0]) != NULL;
                }
-       } else {
-               int i;
-               for (i = 0; i < property->num_values; i++)
-                       if (property->values[i] == value)
-                               return true;
-               return false;
        }
 
        for (i = 0; i < property->num_values; i++)
@@ -4360,7 +4482,7 @@ static bool drm_property_change_valid_get(struct drm_property *property,
        return false;
 }
 
-static void drm_property_change_valid_put(struct drm_property *property,
+void drm_property_change_valid_put(struct drm_property *property,
                struct drm_mode_object *ref)
 {
        if (!ref)