]> git.proxmox.com Git - mirror_ubuntu-bionic-kernel.git/blobdiff - drivers/gpu/drm/drm_plane.c
drm: Don't update property values for atomic drivers
[mirror_ubuntu-bionic-kernel.git] / drivers / gpu / drm / drm_plane.c
index 5dc8c4350602a561fe4cfd77fce77e26770696fb..7889ef7d695498a01c900e25125b482352646bbb 100644 (file)
@@ -62,6 +62,87 @@ static unsigned int drm_num_planes(struct drm_device *dev)
        return num;
 }
 
+static inline u32 *
+formats_ptr(struct drm_format_modifier_blob *blob)
+{
+       return (u32 *)(((char *)blob) + blob->formats_offset);
+}
+
+static inline struct drm_format_modifier *
+modifiers_ptr(struct drm_format_modifier_blob *blob)
+{
+       return (struct drm_format_modifier *)(((char *)blob) + blob->modifiers_offset);
+}
+
+static int create_in_format_blob(struct drm_device *dev, struct drm_plane *plane)
+{
+       const struct drm_mode_config *config = &dev->mode_config;
+       struct drm_property_blob *blob;
+       struct drm_format_modifier *mod;
+       size_t blob_size, formats_size, modifiers_size;
+       struct drm_format_modifier_blob *blob_data;
+       unsigned int i, j;
+
+       formats_size = sizeof(__u32) * plane->format_count;
+       if (WARN_ON(!formats_size)) {
+               /* 0 formats are never expected */
+               return 0;
+       }
+
+       modifiers_size =
+               sizeof(struct drm_format_modifier) * plane->modifier_count;
+
+       blob_size = sizeof(struct drm_format_modifier_blob);
+       /* Modifiers offset is a pointer to a struct with a 64 bit field so it
+        * should be naturally aligned to 8B.
+        */
+       BUILD_BUG_ON(sizeof(struct drm_format_modifier_blob) % 8);
+       blob_size += ALIGN(formats_size, 8);
+       blob_size += modifiers_size;
+
+       blob = drm_property_create_blob(dev, blob_size, NULL);
+       if (IS_ERR(blob))
+               return -1;
+
+       blob_data = (struct drm_format_modifier_blob *)blob->data;
+       blob_data->version = FORMAT_BLOB_CURRENT;
+       blob_data->count_formats = plane->format_count;
+       blob_data->formats_offset = sizeof(struct drm_format_modifier_blob);
+       blob_data->count_modifiers = plane->modifier_count;
+
+       blob_data->modifiers_offset =
+               ALIGN(blob_data->formats_offset + formats_size, 8);
+
+       memcpy(formats_ptr(blob_data), plane->format_types, formats_size);
+
+       /* If we can't determine support, just bail */
+       if (!plane->funcs->format_mod_supported)
+               goto done;
+
+       mod = modifiers_ptr(blob_data);
+       for (i = 0; i < plane->modifier_count; i++) {
+               for (j = 0; j < plane->format_count; j++) {
+                       if (plane->funcs->format_mod_supported(plane,
+                                                              plane->format_types[j],
+                                                              plane->modifiers[i])) {
+
+                               mod->formats |= 1 << j;
+                       }
+               }
+
+               mod->modifier = plane->modifiers[i];
+               mod->offset = 0;
+               mod->pad = 0;
+               mod++;
+       }
+
+done:
+       drm_object_attach_property(&plane->base, config->modifiers_property,
+                                  blob->base.id);
+
+       return 0;
+}
+
 /**
  * drm_universal_plane_init - Initialize a new universal plane object
  * @dev: DRM device
@@ -70,6 +151,8 @@ static unsigned int drm_num_planes(struct drm_device *dev)
  * @funcs: callbacks for the new plane
  * @formats: array of supported formats (DRM_FORMAT\_\*)
  * @format_count: number of elements in @formats
+ * @format_modifiers: array of struct drm_format modifiers terminated by
+ *                    DRM_FORMAT_MOD_INVALID
  * @type: type of plane (overlay, primary, cursor)
  * @name: printf style format string for the plane name, or NULL for default name
  *
@@ -82,10 +165,12 @@ int drm_universal_plane_init(struct drm_device *dev, struct drm_plane *plane,
                             uint32_t possible_crtcs,
                             const struct drm_plane_funcs *funcs,
                             const uint32_t *formats, unsigned int format_count,
+                            const uint64_t *format_modifiers,
                             enum drm_plane_type type,
                             const char *name, ...)
 {
        struct drm_mode_config *config = &dev->mode_config;
+       unsigned int format_modifier_count = 0;
        int ret;
 
        ret = drm_mode_object_add(dev, &plane->base, DRM_MODE_OBJECT_PLANE);
@@ -105,6 +190,31 @@ int drm_universal_plane_init(struct drm_device *dev, struct drm_plane *plane,
                return -ENOMEM;
        }
 
+       /*
+        * First driver to need more than 64 formats needs to fix this. Each
+        * format is encoded as a bit and the current code only supports a u64.
+        */
+       if (WARN_ON(format_count > 64))
+               return -EINVAL;
+
+       if (format_modifiers) {
+               const uint64_t *temp_modifiers = format_modifiers;
+               while (*temp_modifiers++ != DRM_FORMAT_MOD_INVALID)
+                       format_modifier_count++;
+       }
+
+       plane->modifier_count = format_modifier_count;
+       plane->modifiers = kmalloc_array(format_modifier_count,
+                                        sizeof(format_modifiers[0]),
+                                        GFP_KERNEL);
+
+       if (format_modifier_count && !plane->modifiers) {
+               DRM_DEBUG_KMS("out of memory when allocating plane\n");
+               kfree(plane->format_types);
+               drm_mode_object_unregister(dev, &plane->base);
+               return -ENOMEM;
+       }
+
        if (name) {
                va_list ap;
 
@@ -117,12 +227,15 @@ int drm_universal_plane_init(struct drm_device *dev, struct drm_plane *plane,
        }
        if (!plane->name) {
                kfree(plane->format_types);
+               kfree(plane->modifiers);
                drm_mode_object_unregister(dev, &plane->base);
                return -ENOMEM;
        }
 
        memcpy(plane->format_types, formats, format_count * sizeof(uint32_t));
        plane->format_count = format_count;
+       memcpy(plane->modifiers, format_modifiers,
+              format_modifier_count * sizeof(format_modifiers[0]));
        plane->possible_crtcs = possible_crtcs;
        plane->type = type;
 
@@ -149,6 +262,9 @@ int drm_universal_plane_init(struct drm_device *dev, struct drm_plane *plane,
                drm_object_attach_property(&plane->base, config->prop_src_h, 0);
        }
 
+       if (config->allow_fb_modifiers)
+               create_in_format_blob(dev, plane);
+
        return 0;
 }
 EXPORT_SYMBOL(drm_universal_plane_init);
@@ -205,7 +321,8 @@ int drm_plane_init(struct drm_device *dev, struct drm_plane *plane,
 
        type = is_primary ? DRM_PLANE_TYPE_PRIMARY : DRM_PLANE_TYPE_OVERLAY;
        return drm_universal_plane_init(dev, plane, possible_crtcs, funcs,
-                                       formats, format_count, type, NULL);
+                                       formats, format_count,
+                                       NULL, type, NULL);
 }
 EXPORT_SYMBOL(drm_plane_init);
 
@@ -224,6 +341,7 @@ void drm_plane_cleanup(struct drm_plane *plane)
        drm_modeset_lock_fini(&plane->mutex);
 
        kfree(plane->format_types);
+       kfree(plane->modifiers);
        drm_mode_object_unregister(dev, &plane->base);
 
        BUG_ON(list_empty(&plane->head));
@@ -330,7 +448,7 @@ int drm_mode_plane_set_obj_prop(struct drm_plane *plane,
 
        if (plane->funcs->set_property)
                ret = plane->funcs->set_property(plane, property, value);
-       if (!ret)
+       if (!ret && !drm_drv_uses_atomic_modeset(property->dev))
                drm_object_property_set_value(obj, property, value);
 
        return ret;