Merge tag 'at91-dt-for-3.17' of git://git.kernel.org/pub/scm/linux/kernel/git/mripard...
[firefly-linux-kernel-4.4.55.git] / drivers / gpu / drm / drm_crtc.c
index c3a5a8f0825b3a073dc5b368dbd69c109b9c37cb..fa2be249999c70711e1b19cbe0df92fd5e081631 100644 (file)
@@ -182,6 +182,12 @@ static const struct drm_prop_enum_list drm_scaling_mode_enum_list[] =
        { DRM_MODE_SCALE_ASPECT, "Full aspect" },
 };
 
+static const struct drm_prop_enum_list drm_aspect_ratio_enum_list[] = {
+       { DRM_MODE_PICTURE_ASPECT_NONE, "Automatic" },
+       { DRM_MODE_PICTURE_ASPECT_4_3, "4:3" },
+       { DRM_MODE_PICTURE_ASPECT_16_9, "16:9" },
+};
+
 /*
  * Non-global properties, but "required" for certain connectors.
  */
@@ -440,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);
 
@@ -468,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);
@@ -1462,6 +1469,33 @@ int drm_mode_create_scaling_mode_property(struct drm_device *dev)
 }
 EXPORT_SYMBOL(drm_mode_create_scaling_mode_property);
 
+/**
+ * drm_mode_create_aspect_ratio_property - create aspect ratio property
+ * @dev: DRM device
+ *
+ * Called by a driver the first time it's needed, must be attached to desired
+ * connectors.
+ *
+ * Returns:
+ * Zero on success, errno on failure.
+ */
+int drm_mode_create_aspect_ratio_property(struct drm_device *dev)
+{
+       if (dev->mode_config.aspect_ratio_property)
+               return 0;
+
+       dev->mode_config.aspect_ratio_property =
+               drm_property_create_enum(dev, 0, "aspect ratio",
+                               drm_aspect_ratio_enum_list,
+                               ARRAY_SIZE(drm_aspect_ratio_enum_list));
+
+       if (dev->mode_config.aspect_ratio_property == NULL)
+               return -ENOMEM;
+
+       return 0;
+}
+EXPORT_SYMBOL(drm_mode_create_aspect_ratio_property);
+
 /**
  * drm_mode_create_dirty_property - create dirty property
  * @dev: DRM device
@@ -3476,19 +3510,28 @@ EXPORT_SYMBOL(drm_property_create_enum);
 struct drm_property *drm_property_create_bitmask(struct drm_device *dev,
                                         int flags, const char *name,
                                         const struct drm_prop_enum_list *props,
-                                        int num_values)
+                                        int num_props,
+                                        uint64_t supported_bits)
 {
        struct drm_property *property;
-       int i, ret;
+       int i, ret, index = 0;
+       int num_values = hweight64(supported_bits);
 
        flags |= DRM_MODE_PROP_BITMASK;
 
        property = drm_property_create(dev, flags, name, num_values);
        if (!property)
                return NULL;
+       for (i = 0; i < num_props; i++) {
+               if (!(supported_bits & (1ULL << props[i].type)))
+                       continue;
 
-       for (i = 0; i < num_values; i++) {
-               ret = drm_property_add_enum(property, i,
+               if (WARN_ON(index >= num_values)) {
+                       drm_property_destroy(dev, property);
+                       return NULL;
+               }
+
+               ret = drm_property_add_enum(property, index++,
                                      props[i].type,
                                      props[i].name);
                if (ret) {
@@ -4936,6 +4979,36 @@ int drm_format_vert_chroma_subsampling(uint32_t format)
 }
 EXPORT_SYMBOL(drm_format_vert_chroma_subsampling);
 
+/**
+ * drm_rotation_simplify() - Try to simplify the rotation
+ * @rotation: Rotation to be simplified
+ * @supported_rotations: Supported rotations
+ *
+ * Attempt to simplify the rotation to a form that is supported.
+ * Eg. if the hardware supports everything except DRM_REFLECT_X
+ * one could call this function like this:
+ *
+ * drm_rotation_simplify(rotation, BIT(DRM_ROTATE_0) |
+ *                       BIT(DRM_ROTATE_90) | BIT(DRM_ROTATE_180) |
+ *                       BIT(DRM_ROTATE_270) | BIT(DRM_REFLECT_Y));
+ *
+ * to eliminate the DRM_ROTATE_X flag. Depending on what kind of
+ * transforms the hardware supports, this function may not
+ * be able to produce a supported transform, so the caller should
+ * check the result afterwards.
+ */
+unsigned int drm_rotation_simplify(unsigned int rotation,
+                                  unsigned int supported_rotations)
+{
+       if (rotation & ~supported_rotations) {
+               rotation ^= BIT(DRM_REFLECT_X) | BIT(DRM_REFLECT_Y);
+               rotation = (rotation & ~0xf) | BIT((ffs(rotation & 0xf) + 1) % 4);
+       }
+
+       return rotation;
+}
+EXPORT_SYMBOL(drm_rotation_simplify);
+
 /**
  * drm_mode_config_init - initialize DRM mode_configuration structure
  * @dev: DRM device
@@ -5054,3 +5127,21 @@ void drm_mode_config_cleanup(struct drm_device *dev)
        drm_modeset_lock_fini(&dev->mode_config.connection_mutex);
 }
 EXPORT_SYMBOL(drm_mode_config_cleanup);
+
+struct drm_property *drm_mode_create_rotation_property(struct drm_device *dev,
+                                                      unsigned int supported_rotations)
+{
+       static const struct drm_prop_enum_list props[] = {
+               { DRM_ROTATE_0,   "rotate-0" },
+               { DRM_ROTATE_90,  "rotate-90" },
+               { DRM_ROTATE_180, "rotate-180" },
+               { DRM_ROTATE_270, "rotate-270" },
+               { DRM_REFLECT_X,  "reflect-x" },
+               { DRM_REFLECT_Y,  "reflect-y" },
+       };
+
+       return drm_property_create_bitmask(dev, 0, "rotation",
+                                          props, ARRAY_SIZE(props),
+                                          supported_rotations);
+}
+EXPORT_SYMBOL(drm_mode_create_rotation_property);