Merge branch 'drm-etnaviv-fixes' of git://git.pengutronix.de/git/lst/linux into drm...
[cascardo/linux.git] / drivers / gpu / drm / drm_crtc.c
index 0e3cc66..b1dbb60 100644 (file)
@@ -39,6 +39,7 @@
 #include <drm/drm_fourcc.h>
 #include <drm/drm_modeset_lock.h>
 #include <drm/drm_atomic.h>
+#include <drm/drm_auth.h>
 
 #include "drm_crtc_internal.h"
 #include "drm_internal.h"
@@ -239,37 +240,6 @@ const char *drm_get_subpixel_order_name(enum subpixel_order order)
 }
 EXPORT_SYMBOL(drm_get_subpixel_order_name);
 
-static char printable_char(int c)
-{
-       return isascii(c) && isprint(c) ? c : '?';
-}
-
-/**
- * drm_get_format_name - return a string for drm fourcc format
- * @format: format to compute name of
- *
- * Note that the buffer used by this function is globally shared and owned by
- * the function itself.
- *
- * FIXME: This isn't really multithreading safe.
- */
-const char *drm_get_format_name(uint32_t format)
-{
-       static char buf[32];
-
-       snprintf(buf, sizeof(buf),
-                "%c%c%c%c %s-endian (0x%08x)",
-                printable_char(format & 0xff),
-                printable_char((format >> 8) & 0xff),
-                printable_char((format >> 16) & 0xff),
-                printable_char((format >> 24) & 0x7f),
-                format & DRM_FORMAT_BIG_ENDIAN ? "big" : "little",
-                format);
-
-       return buf;
-}
-EXPORT_SYMBOL(drm_get_format_name);
-
 /*
  * Internal function to assign a slot in the object idr and optionally
  * register the object into the idr.
@@ -426,6 +396,51 @@ void drm_mode_object_reference(struct drm_mode_object *obj)
 }
 EXPORT_SYMBOL(drm_mode_object_reference);
 
+/**
+ * drm_crtc_force_disable - Forcibly turn off a CRTC
+ * @crtc: CRTC to turn off
+ *
+ * Returns:
+ * Zero on success, error code on failure.
+ */
+int drm_crtc_force_disable(struct drm_crtc *crtc)
+{
+       struct drm_mode_set set = {
+               .crtc = crtc,
+       };
+
+       return drm_mode_set_config_internal(&set);
+}
+EXPORT_SYMBOL(drm_crtc_force_disable);
+
+/**
+ * drm_crtc_force_disable_all - Forcibly turn off all enabled CRTCs
+ * @dev: DRM device whose CRTCs to turn off
+ *
+ * Drivers may want to call this on unload to ensure that all displays are
+ * unlit and the GPU is in a consistent, low power state. Takes modeset locks.
+ *
+ * Returns:
+ * Zero on success, error code on failure.
+ */
+int drm_crtc_force_disable_all(struct drm_device *dev)
+{
+       struct drm_crtc *crtc;
+       int ret = 0;
+
+       drm_modeset_lock_all(dev);
+       drm_for_each_crtc(crtc, dev)
+               if (crtc->enabled) {
+                       ret = drm_crtc_force_disable(crtc);
+                       if (ret)
+                               goto out;
+               }
+out:
+       drm_modeset_unlock_all(dev);
+       return ret;
+}
+EXPORT_SYMBOL(drm_crtc_force_disable_all);
+
 static void drm_framebuffer_free(struct kref *kref)
 {
        struct drm_framebuffer *fb =
@@ -535,7 +550,7 @@ EXPORT_SYMBOL(drm_framebuffer_unregister_private);
  *
  * Cleanup framebuffer. This function is intended to be used from the drivers
  * ->destroy callback. It can also be used to clean up driver private
- *  framebuffers embedded into a larger structure.
+ * framebuffers embedded into a larger structure.
  *
  * Note that this function does not remove the fb from active usuage - if it is
  * still used anywhere, hilarity can ensue since userspace could call getfb on
@@ -574,8 +589,6 @@ void drm_framebuffer_remove(struct drm_framebuffer *fb)
        struct drm_device *dev;
        struct drm_crtc *crtc;
        struct drm_plane *plane;
-       struct drm_mode_set set;
-       int ret;
 
        if (!fb)
                return;
@@ -605,11 +618,7 @@ void drm_framebuffer_remove(struct drm_framebuffer *fb)
                drm_for_each_crtc(crtc, dev) {
                        if (crtc->primary->fb == fb) {
                                /* should turn off the crtc */
-                               memset(&set, 0, sizeof(struct drm_mode_set));
-                               set.crtc = crtc;
-                               set.fb = NULL;
-                               ret = drm_mode_set_config_internal(&set);
-                               if (ret)
+                               if (drm_crtc_force_disable(crtc))
                                        DRM_ERROR("failed to reset crtc %p when fb was deleted\n", crtc);
                        }
                }
@@ -639,6 +648,31 @@ static unsigned int drm_num_crtcs(struct drm_device *dev)
        return num;
 }
 
+static int drm_crtc_register_all(struct drm_device *dev)
+{
+       struct drm_crtc *crtc;
+       int ret = 0;
+
+       drm_for_each_crtc(crtc, dev) {
+               if (crtc->funcs->late_register)
+                       ret = crtc->funcs->late_register(crtc);
+               if (ret)
+                       return ret;
+       }
+
+       return 0;
+}
+
+static void drm_crtc_unregister_all(struct drm_device *dev)
+{
+       struct drm_crtc *crtc;
+
+       drm_for_each_crtc(crtc, dev) {
+               if (crtc->funcs->early_unregister)
+                       crtc->funcs->early_unregister(crtc);
+       }
+}
+
 /**
  * drm_crtc_init_with_planes - Initialise a new CRTC object with
  *    specified primary and cursor planes.
@@ -669,6 +703,9 @@ int drm_crtc_init_with_planes(struct drm_device *dev, struct drm_crtc *crtc,
        crtc->dev = dev;
        crtc->funcs = funcs;
 
+       INIT_LIST_HEAD(&crtc->commit_list);
+       spin_lock_init(&crtc->commit_lock);
+
        drm_modeset_lock_init(&crtc->mutex);
        ret = drm_mode_object_get(dev, &crtc->base, DRM_MODE_OBJECT_CRTC);
        if (ret)
@@ -692,7 +729,7 @@ int drm_crtc_init_with_planes(struct drm_device *dev, struct drm_crtc *crtc,
        crtc->base.properties = &crtc->properties;
 
        list_add_tail(&crtc->head, &config->crtc_list);
-       config->num_crtc++;
+       crtc->index = config->num_crtc++;
 
        crtc->primary = primary;
        crtc->cursor = cursor;
@@ -722,6 +759,11 @@ void drm_crtc_cleanup(struct drm_crtc *crtc)
 {
        struct drm_device *dev = crtc->dev;
 
+       /* Note that the crtc_list is considered to be static; should we
+        * remove the drm_crtc at runtime we would have to decrement all
+        * the indices on the drm_crtc after us in the crtc_list.
+        */
+
        kfree(crtc->gamma_store);
        crtc->gamma_store = NULL;
 
@@ -741,29 +783,6 @@ void drm_crtc_cleanup(struct drm_crtc *crtc)
 }
 EXPORT_SYMBOL(drm_crtc_cleanup);
 
-/**
- * drm_crtc_index - find the index of a registered CRTC
- * @crtc: CRTC to find index for
- *
- * Given a registered CRTC, return the index of that CRTC within a DRM
- * device's list of CRTCs.
- */
-unsigned int drm_crtc_index(struct drm_crtc *crtc)
-{
-       unsigned int index = 0;
-       struct drm_crtc *tmp;
-
-       drm_for_each_crtc(tmp, crtc->dev) {
-               if (tmp == crtc)
-                       return index;
-
-               index++;
-       }
-
-       BUG();
-}
-EXPORT_SYMBOL(drm_crtc_index);
-
 /*
  * drm_mode_remove - remove and free a mode
  * @connector: connector list to modify
@@ -909,11 +928,11 @@ int drm_connector_init(struct drm_device *dev,
        connector->dev = dev;
        connector->funcs = funcs;
 
-       connector->connector_id = ida_simple_get(&config->connector_ida, 0, 0, GFP_KERNEL);
-       if (connector->connector_id < 0) {
-               ret = connector->connector_id;
+       ret = ida_simple_get(&config->connector_ida, 0, 0, GFP_KERNEL);
+       if (ret < 0)
                goto out_put;
-       }
+       connector->index = ret;
+       ret = 0;
 
        connector->connector_type = connector_type;
        connector->connector_type_id =
@@ -961,7 +980,7 @@ out_put_type_id:
                ida_remove(connector_ida, connector->connector_type_id);
 out_put_id:
        if (ret)
-               ida_remove(&config->connector_ida, connector->connector_id);
+               ida_remove(&config->connector_ida, connector->index);
 out_put:
        if (ret)
                drm_mode_object_unregister(dev, &connector->base);
@@ -984,6 +1003,12 @@ void drm_connector_cleanup(struct drm_connector *connector)
        struct drm_device *dev = connector->dev;
        struct drm_display_mode *mode, *t;
 
+       /* The connector should have been removed from userspace long before
+        * it is finally destroyed.
+        */
+       if (WARN_ON(connector->registered))
+               drm_connector_unregister(connector);
+
        if (connector->tile_group) {
                drm_mode_put_tile_group(dev, connector->tile_group);
                connector->tile_group = NULL;
@@ -999,7 +1024,7 @@ void drm_connector_cleanup(struct drm_connector *connector)
                   connector->connector_type_id);
 
        ida_remove(&dev->mode_config.connector_ida,
-                  connector->connector_id);
+                  connector->index);
 
        kfree(connector->display_info.bus_formats);
        drm_mode_object_unregister(dev, &connector->base);
@@ -1030,19 +1055,34 @@ int drm_connector_register(struct drm_connector *connector)
 {
        int ret;
 
+       if (connector->registered)
+               return 0;
+
        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;
+               goto err_sysfs;
+       }
+
+       if (connector->funcs->late_register) {
+               ret = connector->funcs->late_register(connector);
+               if (ret)
+                       goto err_debugfs;
        }
 
        drm_mode_object_register(connector->dev, &connector->base);
 
+       connector->registered = true;
        return 0;
+
+err_debugfs:
+       drm_debugfs_connector_remove(connector);
+err_sysfs:
+       drm_sysfs_connector_remove(connector);
+       return ret;
 }
 EXPORT_SYMBOL(drm_connector_register);
 
@@ -1054,42 +1094,41 @@ EXPORT_SYMBOL(drm_connector_register);
  */
 void drm_connector_unregister(struct drm_connector *connector)
 {
+       if (!connector->registered)
+               return;
+
+       if (connector->funcs->early_unregister)
+               connector->funcs->early_unregister(connector);
+
        drm_sysfs_connector_remove(connector);
        drm_debugfs_connector_remove(connector);
+
+       connector->registered = false;
 }
 EXPORT_SYMBOL(drm_connector_unregister);
 
-/**
- * drm_connector_register_all - register all connectors
- * @dev: drm device
- *
- * This function registers all connectors in sysfs and other places so that
- * userspace can start to access them. Drivers can call it after calling
- * drm_dev_register() to complete the device registration, if they don't call
- * drm_connector_register() on each connector individually.
- *
- * When a device is unplugged and should be removed from userspace access,
- * call drm_connector_unregister_all(), which is the inverse of this
- * function.
- *
- * Returns:
- * Zero on success, error code on failure.
- */
-int drm_connector_register_all(struct drm_device *dev)
+static void drm_connector_unregister_all(struct drm_device *dev)
 {
        struct drm_connector *connector;
-       int ret;
 
-       mutex_lock(&dev->mode_config.mutex);
+       /* FIXME: taking the mode config mutex ends up in a clash with sysfs */
+       list_for_each_entry(connector, &dev->mode_config.connector_list, head)
+               drm_connector_unregister(connector);
+}
 
-       drm_for_each_connector(connector, dev) {
+static int drm_connector_register_all(struct drm_device *dev)
+{
+       struct drm_connector *connector;
+       int ret;
+
+       /* FIXME: taking the mode config mutex ends up in a clash with
+        * fbcon/backlight registration */
+       list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
                ret = drm_connector_register(connector);
                if (ret)
                        goto err;
        }
 
-       mutex_unlock(&dev->mode_config.mutex);
-
        return 0;
 
 err:
@@ -1097,27 +1136,31 @@ err:
        drm_connector_unregister_all(dev);
        return ret;
 }
-EXPORT_SYMBOL(drm_connector_register_all);
 
-/**
- * drm_connector_unregister_all - unregister connector userspace interfaces
- * @dev: drm device
- *
- * This functions unregisters all connectors from sysfs and other places so
- * that userspace can no longer access them. Drivers should call this as the
- * first step tearing down the device instace, or when the underlying
- * physical device disappeared (e.g. USB unplug), right before calling
- * drm_dev_unregister().
- */
-void drm_connector_unregister_all(struct drm_device *dev)
+static int drm_encoder_register_all(struct drm_device *dev)
 {
-       struct drm_connector *connector;
+       struct drm_encoder *encoder;
+       int ret = 0;
 
-       /* FIXME: taking the mode config mutex ends up in a clash with sysfs */
-       list_for_each_entry(connector, &dev->mode_config.connector_list, head)
-               drm_connector_unregister(connector);
+       drm_for_each_encoder(encoder, dev) {
+               if (encoder->funcs->late_register)
+                       ret = encoder->funcs->late_register(encoder);
+               if (ret)
+                       return ret;
+       }
+
+       return 0;
+}
+
+static void drm_encoder_unregister_all(struct drm_device *dev)
+{
+       struct drm_encoder *encoder;
+
+       drm_for_each_encoder(encoder, dev) {
+               if (encoder->funcs->early_unregister)
+                       encoder->funcs->early_unregister(encoder);
+       }
 }
-EXPORT_SYMBOL(drm_connector_unregister_all);
 
 /**
  * drm_encoder_init - Init a preallocated encoder
@@ -1166,7 +1209,7 @@ int drm_encoder_init(struct drm_device *dev,
        }
 
        list_add_tail(&encoder->head, &dev->mode_config.encoder_list);
-       dev->mode_config.num_encoder++;
+       encoder->index = dev->mode_config.num_encoder++;
 
 out_put:
        if (ret)
@@ -1179,29 +1222,6 @@ out_unlock:
 }
 EXPORT_SYMBOL(drm_encoder_init);
 
-/**
- * drm_encoder_index - find the index of a registered encoder
- * @encoder: encoder to find index for
- *
- * Given a registered encoder, return the index of that encoder within a DRM
- * device's list of encoders.
- */
-unsigned int drm_encoder_index(struct drm_encoder *encoder)
-{
-       unsigned int index = 0;
-       struct drm_encoder *tmp;
-
-       drm_for_each_encoder(tmp, encoder->dev) {
-               if (tmp == encoder)
-                       return index;
-
-               index++;
-       }
-
-       BUG();
-}
-EXPORT_SYMBOL(drm_encoder_index);
-
 /**
  * drm_encoder_cleanup - cleans up an initialised encoder
  * @encoder: encoder to cleanup
@@ -1212,6 +1232,11 @@ void drm_encoder_cleanup(struct drm_encoder *encoder)
 {
        struct drm_device *dev = encoder->dev;
 
+       /* Note that the encoder_list is considered to be static; should we
+        * remove the drm_encoder at runtime we would have to decrement all
+        * the indices on the drm_encoder after us in the encoder_list.
+        */
+
        drm_modeset_lock_all(dev);
        drm_mode_object_unregister(dev, &encoder->base);
        kfree(encoder->name);
@@ -1300,7 +1325,7 @@ int drm_universal_plane_init(struct drm_device *dev, struct drm_plane *plane,
        plane->type = type;
 
        list_add_tail(&plane->head, &config->plane_list);
-       config->num_total_plane++;
+       plane->index = config->num_total_plane++;
        if (plane->type == DRM_PLANE_TYPE_OVERLAY)
                config->num_overlay_plane++;
 
@@ -1325,6 +1350,31 @@ int drm_universal_plane_init(struct drm_device *dev, struct drm_plane *plane,
 }
 EXPORT_SYMBOL(drm_universal_plane_init);
 
+static int drm_plane_register_all(struct drm_device *dev)
+{
+       struct drm_plane *plane;
+       int ret = 0;
+
+       drm_for_each_plane(plane, dev) {
+               if (plane->funcs->late_register)
+                       ret = plane->funcs->late_register(plane);
+               if (ret)
+                       return ret;
+       }
+
+       return 0;
+}
+
+static void drm_plane_unregister_all(struct drm_device *dev)
+{
+       struct drm_plane *plane;
+
+       drm_for_each_plane(plane, dev) {
+               if (plane->funcs->early_unregister)
+                       plane->funcs->early_unregister(plane);
+       }
+}
+
 /**
  * drm_plane_init - Initialize a legacy plane
  * @dev: DRM device
@@ -1374,6 +1424,11 @@ void drm_plane_cleanup(struct drm_plane *plane)
 
        BUG_ON(list_empty(&plane->head));
 
+       /* Note that the plane_list is considered to be static; should we
+        * remove the drm_plane at runtime we would have to decrement all
+        * the indices on the drm_plane after us in the plane_list.
+        */
+
        list_del(&plane->head);
        dev->mode_config.num_total_plane--;
        if (plane->type == DRM_PLANE_TYPE_OVERLAY)
@@ -1390,29 +1445,6 @@ void drm_plane_cleanup(struct drm_plane *plane)
 }
 EXPORT_SYMBOL(drm_plane_cleanup);
 
-/**
- * drm_plane_index - find the index of a registered plane
- * @plane: plane to find index for
- *
- * Given a registered plane, return the index of that CRTC within a DRM
- * device's list of planes.
- */
-unsigned int drm_plane_index(struct drm_plane *plane)
-{
-       unsigned int index = 0;
-       struct drm_plane *tmp;
-
-       drm_for_each_plane(tmp, plane->dev) {
-               if (tmp == plane)
-                       return index;
-
-               index++;
-       }
-
-       BUG();
-}
-EXPORT_SYMBOL(drm_plane_index);
-
 /**
  * drm_plane_from_index - find the registered plane at an index
  * @dev: DRM device
@@ -1425,13 +1457,11 @@ struct drm_plane *
 drm_plane_from_index(struct drm_device *dev, int idx)
 {
        struct drm_plane *plane;
-       unsigned int i = 0;
 
-       drm_for_each_plane(plane, dev) {
-               if (i == idx)
+       drm_for_each_plane(plane, dev)
+               if (idx == plane->index)
                        return plane;
-               i++;
-       }
+
        return NULL;
 }
 EXPORT_SYMBOL(drm_plane_from_index);
@@ -1467,6 +1497,46 @@ void drm_plane_force_disable(struct drm_plane *plane)
 }
 EXPORT_SYMBOL(drm_plane_force_disable);
 
+int drm_modeset_register_all(struct drm_device *dev)
+{
+       int ret;
+
+       ret = drm_plane_register_all(dev);
+       if (ret)
+               goto err_plane;
+
+       ret = drm_crtc_register_all(dev);
+       if  (ret)
+               goto err_crtc;
+
+       ret = drm_encoder_register_all(dev);
+       if (ret)
+               goto err_encoder;
+
+       ret = drm_connector_register_all(dev);
+       if (ret)
+               goto err_connector;
+
+       return 0;
+
+err_connector:
+       drm_encoder_unregister_all(dev);
+err_encoder:
+       drm_crtc_unregister_all(dev);
+err_crtc:
+       drm_plane_unregister_all(dev);
+err_plane:
+       return ret;
+}
+
+void drm_modeset_unregister_all(struct drm_device *dev)
+{
+       drm_connector_unregister_all(dev);
+       drm_encoder_unregister_all(dev);
+       drm_crtc_unregister_all(dev);
+       drm_plane_unregister_all(dev);
+}
+
 static int drm_mode_create_standard_properties(struct drm_device *dev)
 {
        struct drm_property *prop;
@@ -2975,6 +3045,8 @@ static int drm_mode_cursor_universal(struct drm_crtc *crtc,
                                DRM_DEBUG_KMS("failed to wrap cursor buffer in drm framebuffer\n");
                                return PTR_ERR(fb);
                        }
+                       fb->hot_x = req->hot_x;
+                       fb->hot_y = req->hot_y;
                } else {
                        fb = NULL;
                }
@@ -3581,7 +3653,7 @@ int drm_mode_getfb(struct drm_device *dev,
        r->bpp = fb->bits_per_pixel;
        r->pitch = fb->pitches[0];
        if (fb->funcs->create_handle) {
-               if (file_priv->is_master || capable(CAP_SYS_ADMIN) ||
+               if (drm_is_current_master(file_priv) || capable(CAP_SYS_ADMIN) ||
                    drm_is_control_client(file_priv)) {
                        ret = fb->funcs->create_handle(fb, file_priv,
                                                       &r->handle);
@@ -3738,6 +3810,13 @@ void drm_fb_release(struct drm_file *priv)
        }
 }
 
+static bool drm_property_type_valid(struct drm_property *property)
+{
+       if (property->flags & DRM_MODE_PROP_EXTENDED_TYPE)
+               return !(property->flags & DRM_MODE_PROP_LEGACY_TYPE);
+       return !!(property->flags & DRM_MODE_PROP_LEGACY_TYPE);
+}
+
 /**
  * drm_property_create - create a new property type
  * @dev: drm device
@@ -5138,6 +5217,9 @@ EXPORT_SYMBOL(drm_mode_connector_attach_encoder);
 int drm_mode_crtc_set_gamma_size(struct drm_crtc *crtc,
                                 int gamma_size)
 {
+       uint16_t *r_base, *g_base, *b_base;
+       int i;
+
        crtc->gamma_size = gamma_size;
 
        crtc->gamma_store = kcalloc(gamma_size, sizeof(uint16_t) * 3,
@@ -5147,6 +5229,16 @@ int drm_mode_crtc_set_gamma_size(struct drm_crtc *crtc,
                return -ENOMEM;
        }
 
+       r_base = crtc->gamma_store;
+       g_base = r_base + gamma_size;
+       b_base = g_base + gamma_size;
+       for (i = 0; i < gamma_size; i++) {
+               r_base[i] = i << 8;
+               g_base[i] = i << 8;
+               b_base[i] = i << 8;
+       }
+
+
        return 0;
 }
 EXPORT_SYMBOL(drm_mode_crtc_set_gamma_size);
@@ -5214,7 +5306,7 @@ int drm_mode_gamma_set_ioctl(struct drm_device *dev,
                goto out;
        }
 
-       crtc->funcs->gamma_set(crtc, r_base, g_base, b_base, 0, crtc->gamma_size);
+       ret = crtc->funcs->gamma_set(crtc, r_base, g_base, b_base, crtc->gamma_size);
 
 out:
        drm_modeset_unlock_all(dev);
@@ -5543,264 +5635,6 @@ int drm_mode_destroy_dumb_ioctl(struct drm_device *dev,
        return dev->driver->dumb_destroy(file_priv, dev, args->handle);
 }
 
-/**
- * drm_fb_get_bpp_depth - get the bpp/depth values for format
- * @format: pixel format (DRM_FORMAT_*)
- * @depth: storage for the depth value
- * @bpp: storage for the bpp value
- *
- * This only supports RGB formats here for compat with code that doesn't use
- * pixel formats directly yet.
- */
-void drm_fb_get_bpp_depth(uint32_t format, unsigned int *depth,
-                         int *bpp)
-{
-       switch (format) {
-       case DRM_FORMAT_C8:
-       case DRM_FORMAT_RGB332:
-       case DRM_FORMAT_BGR233:
-               *depth = 8;
-               *bpp = 8;
-               break;
-       case DRM_FORMAT_XRGB1555:
-       case DRM_FORMAT_XBGR1555:
-       case DRM_FORMAT_RGBX5551:
-       case DRM_FORMAT_BGRX5551:
-       case DRM_FORMAT_ARGB1555:
-       case DRM_FORMAT_ABGR1555:
-       case DRM_FORMAT_RGBA5551:
-       case DRM_FORMAT_BGRA5551:
-               *depth = 15;
-               *bpp = 16;
-               break;
-       case DRM_FORMAT_RGB565:
-       case DRM_FORMAT_BGR565:
-               *depth = 16;
-               *bpp = 16;
-               break;
-       case DRM_FORMAT_RGB888:
-       case DRM_FORMAT_BGR888:
-               *depth = 24;
-               *bpp = 24;
-               break;
-       case DRM_FORMAT_XRGB8888:
-       case DRM_FORMAT_XBGR8888:
-       case DRM_FORMAT_RGBX8888:
-       case DRM_FORMAT_BGRX8888:
-               *depth = 24;
-               *bpp = 32;
-               break;
-       case DRM_FORMAT_XRGB2101010:
-       case DRM_FORMAT_XBGR2101010:
-       case DRM_FORMAT_RGBX1010102:
-       case DRM_FORMAT_BGRX1010102:
-       case DRM_FORMAT_ARGB2101010:
-       case DRM_FORMAT_ABGR2101010:
-       case DRM_FORMAT_RGBA1010102:
-       case DRM_FORMAT_BGRA1010102:
-               *depth = 30;
-               *bpp = 32;
-               break;
-       case DRM_FORMAT_ARGB8888:
-       case DRM_FORMAT_ABGR8888:
-       case DRM_FORMAT_RGBA8888:
-       case DRM_FORMAT_BGRA8888:
-               *depth = 32;
-               *bpp = 32;
-               break;
-       default:
-               DRM_DEBUG_KMS("unsupported pixel format %s\n",
-                             drm_get_format_name(format));
-               *depth = 0;
-               *bpp = 0;
-               break;
-       }
-}
-EXPORT_SYMBOL(drm_fb_get_bpp_depth);
-
-/**
- * drm_format_num_planes - get the number of planes for format
- * @format: pixel format (DRM_FORMAT_*)
- *
- * Returns:
- * The number of planes used by the specified pixel format.
- */
-int drm_format_num_planes(uint32_t format)
-{
-       switch (format) {
-       case DRM_FORMAT_YUV410:
-       case DRM_FORMAT_YVU410:
-       case DRM_FORMAT_YUV411:
-       case DRM_FORMAT_YVU411:
-       case DRM_FORMAT_YUV420:
-       case DRM_FORMAT_YVU420:
-       case DRM_FORMAT_YUV422:
-       case DRM_FORMAT_YVU422:
-       case DRM_FORMAT_YUV444:
-       case DRM_FORMAT_YVU444:
-               return 3;
-       case DRM_FORMAT_NV12:
-       case DRM_FORMAT_NV21:
-       case DRM_FORMAT_NV16:
-       case DRM_FORMAT_NV61:
-       case DRM_FORMAT_NV24:
-       case DRM_FORMAT_NV42:
-               return 2;
-       default:
-               return 1;
-       }
-}
-EXPORT_SYMBOL(drm_format_num_planes);
-
-/**
- * drm_format_plane_cpp - determine the bytes per pixel value
- * @format: pixel format (DRM_FORMAT_*)
- * @plane: plane index
- *
- * Returns:
- * The bytes per pixel value for the specified plane.
- */
-int drm_format_plane_cpp(uint32_t format, int plane)
-{
-       unsigned int depth;
-       int bpp;
-
-       if (plane >= drm_format_num_planes(format))
-               return 0;
-
-       switch (format) {
-       case DRM_FORMAT_YUYV:
-       case DRM_FORMAT_YVYU:
-       case DRM_FORMAT_UYVY:
-       case DRM_FORMAT_VYUY:
-               return 2;
-       case DRM_FORMAT_NV12:
-       case DRM_FORMAT_NV21:
-       case DRM_FORMAT_NV16:
-       case DRM_FORMAT_NV61:
-       case DRM_FORMAT_NV24:
-       case DRM_FORMAT_NV42:
-               return plane ? 2 : 1;
-       case DRM_FORMAT_YUV410:
-       case DRM_FORMAT_YVU410:
-       case DRM_FORMAT_YUV411:
-       case DRM_FORMAT_YVU411:
-       case DRM_FORMAT_YUV420:
-       case DRM_FORMAT_YVU420:
-       case DRM_FORMAT_YUV422:
-       case DRM_FORMAT_YVU422:
-       case DRM_FORMAT_YUV444:
-       case DRM_FORMAT_YVU444:
-               return 1;
-       default:
-               drm_fb_get_bpp_depth(format, &depth, &bpp);
-               return bpp >> 3;
-       }
-}
-EXPORT_SYMBOL(drm_format_plane_cpp);
-
-/**
- * drm_format_horz_chroma_subsampling - get the horizontal chroma subsampling factor
- * @format: pixel format (DRM_FORMAT_*)
- *
- * Returns:
- * The horizontal chroma subsampling factor for the
- * specified pixel format.
- */
-int drm_format_horz_chroma_subsampling(uint32_t format)
-{
-       switch (format) {
-       case DRM_FORMAT_YUV411:
-       case DRM_FORMAT_YVU411:
-       case DRM_FORMAT_YUV410:
-       case DRM_FORMAT_YVU410:
-               return 4;
-       case DRM_FORMAT_YUYV:
-       case DRM_FORMAT_YVYU:
-       case DRM_FORMAT_UYVY:
-       case DRM_FORMAT_VYUY:
-       case DRM_FORMAT_NV12:
-       case DRM_FORMAT_NV21:
-       case DRM_FORMAT_NV16:
-       case DRM_FORMAT_NV61:
-       case DRM_FORMAT_YUV422:
-       case DRM_FORMAT_YVU422:
-       case DRM_FORMAT_YUV420:
-       case DRM_FORMAT_YVU420:
-               return 2;
-       default:
-               return 1;
-       }
-}
-EXPORT_SYMBOL(drm_format_horz_chroma_subsampling);
-
-/**
- * drm_format_vert_chroma_subsampling - get the vertical chroma subsampling factor
- * @format: pixel format (DRM_FORMAT_*)
- *
- * Returns:
- * The vertical chroma subsampling factor for the
- * specified pixel format.
- */
-int drm_format_vert_chroma_subsampling(uint32_t format)
-{
-       switch (format) {
-       case DRM_FORMAT_YUV410:
-       case DRM_FORMAT_YVU410:
-               return 4;
-       case DRM_FORMAT_YUV420:
-       case DRM_FORMAT_YVU420:
-       case DRM_FORMAT_NV12:
-       case DRM_FORMAT_NV21:
-               return 2;
-       default:
-               return 1;
-       }
-}
-EXPORT_SYMBOL(drm_format_vert_chroma_subsampling);
-
-/**
- * drm_format_plane_width - width of the plane given the first plane
- * @width: width of the first plane
- * @format: pixel format
- * @plane: plane index
- *
- * Returns:
- * The width of @plane, given that the width of the first plane is @width.
- */
-int drm_format_plane_width(int width, uint32_t format, int plane)
-{
-       if (plane >= drm_format_num_planes(format))
-               return 0;
-
-       if (plane == 0)
-               return width;
-
-       return width / drm_format_horz_chroma_subsampling(format);
-}
-EXPORT_SYMBOL(drm_format_plane_width);
-
-/**
- * drm_format_plane_height - height of the plane given the first plane
- * @height: height of the first plane
- * @format: pixel format
- * @plane: plane index
- *
- * Returns:
- * The height of @plane, given that the height of the first plane is @height.
- */
-int drm_format_plane_height(int height, uint32_t format, int plane)
-{
-       if (plane >= drm_format_num_planes(format))
-               return 0;
-
-       if (plane == 0)
-               return height;
-
-       return height / drm_format_vert_chroma_subsampling(format);
-}
-EXPORT_SYMBOL(drm_format_plane_height);
-
 /**
  * drm_rotation_simplify() - Try to simplify the rotation
  * @rotation: Rotation to be simplified
@@ -6064,3 +5898,48 @@ struct drm_tile_group *drm_mode_create_tile_group(struct drm_device *dev,
        return tg;
 }
 EXPORT_SYMBOL(drm_mode_create_tile_group);
+
+/**
+ * drm_crtc_enable_color_mgmt - enable color management properties
+ * @crtc: DRM CRTC
+ * @degamma_lut_size: the size of the degamma lut (before CSC)
+ * @has_ctm: whether to attach ctm_property for CSC matrix
+ * @gamma_lut_size: the size of the gamma lut (after CSC)
+ *
+ * This function lets the driver enable the color correction
+ * properties on a CRTC. This includes 3 degamma, csc and gamma
+ * properties that userspace can set and 2 size properties to inform
+ * the userspace of the lut sizes. Each of the properties are
+ * optional. The gamma and degamma properties are only attached if
+ * their size is not 0 and ctm_property is only attached if has_ctm is
+ * true.
+ */
+void drm_crtc_enable_color_mgmt(struct drm_crtc *crtc,
+                               uint degamma_lut_size,
+                               bool has_ctm,
+                               uint gamma_lut_size)
+{
+       struct drm_device *dev = crtc->dev;
+       struct drm_mode_config *config = &dev->mode_config;
+
+       if (degamma_lut_size) {
+               drm_object_attach_property(&crtc->base,
+                                          config->degamma_lut_property, 0);
+               drm_object_attach_property(&crtc->base,
+                                          config->degamma_lut_size_property,
+                                          degamma_lut_size);
+       }
+
+       if (has_ctm)
+               drm_object_attach_property(&crtc->base,
+                                          config->ctm_property, 0);
+
+       if (gamma_lut_size) {
+               drm_object_attach_property(&crtc->base,
+                                          config->gamma_lut_property, 0);
+               drm_object_attach_property(&crtc->base,
+                                          config->gamma_lut_size_property,
+                                          gamma_lut_size);
+       }
+}
+EXPORT_SYMBOL(drm_crtc_enable_color_mgmt);