ret = drm_universal_plane_init(drm, plane, 0xff, &arc_pgu_plane_funcs,
                                       formats, ARRAY_SIZE(formats),
+                                      NULL,
                                       DRM_PLANE_TYPE_PRIMARY, NULL);
        if (ret)
                return ERR_PTR(ret);
 
 
        ret = drm_universal_plane_init(drm, plane, 0xff, &hdlcd_plane_funcs,
                                       formats, ARRAY_SIZE(formats),
+                                      NULL,
                                       DRM_PLANE_TYPE_PRIMARY, NULL);
        if (ret) {
                return ERR_PTR(ret);
 
                                        DRM_PLANE_TYPE_OVERLAY;
                ret = drm_universal_plane_init(drm, &plane->base, crtcs,
                                               &malidp_de_plane_funcs, formats,
-                                              n, plane_type, NULL);
+                                              n, NULL, plane_type, NULL);
                if (ret < 0)
                        goto cleanup;
 
 
                                       &armada_primary_plane_funcs,
                                       armada_primary_formats,
                                       ARRAY_SIZE(armada_primary_formats),
+                                      NULL,
                                       DRM_PLANE_TYPE_PRIMARY, NULL);
        if (ret) {
                kfree(primary);
 
                                       &armada_ovl_plane_funcs,
                                       armada_ovl_formats,
                                       ARRAY_SIZE(armada_ovl_formats),
+                                      NULL,
                                       DRM_PLANE_TYPE_OVERLAY, NULL);
        if (ret) {
                kfree(dplane);
 
        ret = drm_universal_plane_init(dev, &plane->base, 0,
                                       &layer_plane_funcs,
                                       desc->formats->formats,
-                                      desc->formats->nformats, type, NULL);
+                                      desc->formats->nformats,
+                                      NULL, type, NULL);
        if (ret)
                return ret;
 
 
                                       &drm_primary_helper_funcs,
                                       safe_modeset_formats,
                                       ARRAY_SIZE(safe_modeset_formats),
+                                      NULL,
                                       DRM_PLANE_TYPE_PRIMARY, NULL);
        if (ret) {
                kfree(primary);
 
  * @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
  *
                             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);
                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;
 
        }
        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;
 
 
        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);
 
        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));
 
  * @funcs: callbacks for the display pipe (optional)
  * @formats: array of supported formats (DRM_FORMAT\_\*)
  * @format_count: number of elements in @formats
+ * @format_modifiers: array of formats modifiers
  * @connector: connector to attach and register (optional)
  *
  * Sets up a display pipeline which consist of a really simple
                        struct drm_simple_display_pipe *pipe,
                        const struct drm_simple_display_pipe_funcs *funcs,
                        const uint32_t *formats, unsigned int format_count,
+                       const uint64_t *format_modifiers,
                        struct drm_connector *connector)
 {
        struct drm_encoder *encoder = &pipe->encoder;
        ret = drm_universal_plane_init(dev, plane, 0,
                                       &drm_simple_kms_plane_funcs,
                                       formats, format_count,
+                                      format_modifiers,
                                       DRM_PLANE_TYPE_PRIMARY, NULL);
        if (ret)
                return ret;
 
                                       &exynos_plane_funcs,
                                       config->pixel_formats,
                                       config->num_pixel_formats,
-                                      config->type, NULL);
+                                      NULL, config->type, NULL);
        if (err) {
                DRM_ERROR("failed to initialize plane\n");
                return err;
 
                                       &fsl_dcu_drm_plane_funcs,
                                       fsl_dcu_drm_plane_formats,
                                       ARRAY_SIZE(fsl_dcu_drm_plane_formats),
-                                      DRM_PLANE_TYPE_PRIMARY, NULL);
+                                      NULL, DRM_PLANE_TYPE_PRIMARY, NULL);
        if (ret) {
                kfree(primary);
                primary = NULL;
 
        ret = drm_universal_plane_init(dev, plane, 1, &hibmc_plane_funcs,
                                       channel_formats1,
                                       ARRAY_SIZE(channel_formats1),
+                                      NULL,
                                       DRM_PLANE_TYPE_PRIMARY,
                                       NULL);
        if (ret) {
 
                return ret;
 
        ret = drm_universal_plane_init(dev, &aplane->base, 1, &ade_plane_funcs,
-                                      fmts, fmts_cnt, type, NULL);
+                                      fmts, fmts_cnt, NULL, type, NULL);
        if (ret) {
                DRM_ERROR("fail to init plane, ch=%d\n", aplane->ch);
                return ret;
 
                ret = drm_universal_plane_init(&dev_priv->drm, &primary->base,
                                               0, &intel_plane_funcs,
                                               intel_primary_formats, num_formats,
+                                              NULL,
                                               DRM_PLANE_TYPE_PRIMARY,
                                               "plane 1%c", pipe_name(pipe));
        else if (INTEL_GEN(dev_priv) >= 5 || IS_G4X(dev_priv))
                ret = drm_universal_plane_init(&dev_priv->drm, &primary->base,
                                               0, &intel_plane_funcs,
                                               intel_primary_formats, num_formats,
+                                              NULL,
                                               DRM_PLANE_TYPE_PRIMARY,
                                               "primary %c", pipe_name(pipe));
        else
                ret = drm_universal_plane_init(&dev_priv->drm, &primary->base,
                                               0, &intel_plane_funcs,
                                               intel_primary_formats, num_formats,
+                                              NULL,
                                               DRM_PLANE_TYPE_PRIMARY,
                                               "plane %c", plane_name(primary->plane));
        if (ret)
                                       0, &intel_cursor_plane_funcs,
                                       intel_cursor_formats,
                                       ARRAY_SIZE(intel_cursor_formats),
-                                      DRM_PLANE_TYPE_CURSOR,
+                                      NULL, DRM_PLANE_TYPE_CURSOR,
                                       "cursor %c", pipe_name(pipe));
        if (ret)
                goto fail;
 
                ret = drm_universal_plane_init(&dev_priv->drm, &intel_plane->base,
                                               possible_crtcs, &intel_plane_funcs,
                                               plane_formats, num_plane_formats,
-                                              DRM_PLANE_TYPE_OVERLAY,
+                                              NULL, DRM_PLANE_TYPE_OVERLAY,
                                               "plane %d%c", plane + 2, pipe_name(pipe));
        else
                ret = drm_universal_plane_init(&dev_priv->drm, &intel_plane->base,
                                               possible_crtcs, &intel_plane_funcs,
                                               plane_formats, num_plane_formats,
-                                              DRM_PLANE_TYPE_OVERLAY,
+                                              NULL, DRM_PLANE_TYPE_OVERLAY,
                                               "sprite %c", sprite_name(pipe, plane));
        if (ret)
                goto fail;
 
 
        ret = drm_universal_plane_init(dev, &ipu_plane->base, possible_crtcs,
                                       &ipu_plane_funcs, ipu_plane_formats,
-                                      ARRAY_SIZE(ipu_plane_formats), type,
-                                      NULL);
+                                      ARRAY_SIZE(ipu_plane_formats),
+                                      NULL, type, NULL);
        if (ret) {
                DRM_ERROR("failed to initialize plane\n");
                kfree(ipu_plane);
 
 
        err = drm_universal_plane_init(dev, plane, possible_crtcs,
                                       &mtk_plane_funcs, formats,
-                                      ARRAY_SIZE(formats), type, NULL);
+                                      ARRAY_SIZE(formats), NULL, type, NULL);
        if (err) {
                DRM_ERROR("failed to initialize plane\n");
                return err;
 
                                 &meson_plane_funcs,
                                 supported_drm_formats,
                                 ARRAY_SIZE(supported_drm_formats),
+                                NULL,
                                 DRM_PLANE_TYPE_PRIMARY, "meson_primary_plane");
 
        drm_plane_helper_add(plane, &meson_plane_helper_funcs);
 
        type = private_plane ? DRM_PLANE_TYPE_PRIMARY : DRM_PLANE_TYPE_OVERLAY;
        ret = drm_universal_plane_init(dev, plane, 0xff, &mdp4_plane_funcs,
                                 mdp4_plane->formats, mdp4_plane->nformats,
-                                type, NULL);
+                                NULL, type, NULL);
        if (ret)
                goto fail;
 
 
                ret = drm_universal_plane_init(dev, plane, 0xff,
                                &mdp5_cursor_plane_funcs,
                                mdp5_plane->formats, mdp5_plane->nformats,
-                               type, NULL);
+                               NULL, type, NULL);
        else
                ret = drm_universal_plane_init(dev, plane, 0xff,
                                &mdp5_plane_funcs,
                                mdp5_plane->formats, mdp5_plane->nformats,
-                               type, NULL);
+                               NULL, type, NULL);
        if (ret)
                goto fail;
 
 
        }
 
        ret = drm_simple_display_pipe_init(drm, &mxsfb->pipe, &mxsfb_funcs,
-                       mxsfb_formats, ARRAY_SIZE(mxsfb_formats),
+                       mxsfb_formats, ARRAY_SIZE(mxsfb_formats), NULL,
                        &mxsfb->connector);
        if (ret < 0) {
                dev_err(drm->dev, "Cannot setup simple display pipe\n");
 
        wndw->func = func;
        wndw->dmac = dmac;
 
-       ret = drm_universal_plane_init(dev, &wndw->plane, 0, &nv50_wndw, format,
-                                      nformat, type, "%s-%d", name, index);
+       ret = drm_universal_plane_init(dev, &wndw->plane, 0, &nv50_wndw,
+                                      format, nformat, NULL,
+                                      type, "%s-%d", name, index);
        if (ret)
                return ret;
 
 
 
        ret = drm_universal_plane_init(dev, plane, possible_crtcs,
                                       &omap_plane_funcs, formats,
-                                      nformats, type, NULL);
+                                      nformats, NULL, type, NULL);
        if (ret < 0)
                goto error;
 
 
        ret = drm_simple_display_pipe_init(drm, &priv->pipe,
                                           &pl111_display_funcs,
                                           formats, ARRAY_SIZE(formats),
-                                          &priv->connector.connector);
+                                          NULL, &priv->connector.connector);
        if (ret)
                return ret;
 
 
 
        err = drm_universal_plane_init(&qdev->ddev, plane, possible_crtcs,
                                       funcs, formats, num_formats,
-                                      type, NULL);
+                                      NULL, type, NULL);
        if (err)
                goto free_plane;
 
 
 
                ret = drm_universal_plane_init(rcdu->ddev, &plane->plane, crtcs,
                                               &rcar_du_plane_funcs, formats,
-                                              ARRAY_SIZE(formats), type,
-                                              NULL);
+                                              ARRAY_SIZE(formats),
+                                              NULL, type, NULL);
                if (ret < 0)
                        return ret;
 
 
                                               1 << vsp->index,
                                               &rcar_du_vsp_plane_funcs,
                                               formats_kms,
-                                              ARRAY_SIZE(formats_kms), type,
-                                              NULL);
+                                              ARRAY_SIZE(formats_kms),
+                                              NULL, type, NULL);
                if (ret < 0)
                        return ret;
 
 
                                               0, &vop_plane_funcs,
                                               win_data->phy->data_formats,
                                               win_data->phy->nformats,
-                                              win_data->type, NULL);
+                                              NULL, win_data->type, NULL);
                if (ret) {
                        DRM_DEV_ERROR(vop->dev, "failed to init plane %d\n",
                                      ret);
                                               &vop_plane_funcs,
                                               win_data->phy->data_formats,
                                               win_data->phy->nformats,
-                                              win_data->type, NULL);
+                                              NULL, win_data->type, NULL);
                if (ret) {
                        DRM_DEV_ERROR(vop->dev, "failed to init overlay %d\n",
                                      ret);
 
                                       &sti_cursor_plane_helpers_funcs,
                                       cursor_supported_formats,
                                       ARRAY_SIZE(cursor_supported_formats),
-                                      DRM_PLANE_TYPE_CURSOR, NULL);
+                                      NULL, DRM_PLANE_TYPE_CURSOR, NULL);
        if (res) {
                DRM_ERROR("Failed to initialize universal plane\n");
                goto err_plane;
 
                                       &sti_gdp_plane_helpers_funcs,
                                       gdp_supported_formats,
                                       ARRAY_SIZE(gdp_supported_formats),
-                                      type, NULL);
+                                      NULL, type, NULL);
        if (res) {
                DRM_ERROR("Failed to initialize universal plane\n");
                goto err;
 
                                       &sti_hqvdp_plane_helpers_funcs,
                                       hqvdp_supported_formats,
                                       ARRAY_SIZE(hqvdp_supported_formats),
-                                      DRM_PLANE_TYPE_OVERLAY, NULL);
+                                      NULL, DRM_PLANE_TYPE_OVERLAY, NULL);
        if (res) {
                DRM_ERROR("Failed to initialize universal plane\n");
                return NULL;
 
 
        ret = drm_universal_plane_init(ddev, plane, possible_crtcs,
                                       <dc_plane_funcs, formats, nb_fmt,
-                                      type, NULL);
+                                      NULL, type, NULL);
        if (ret < 0)
                return 0;
 
 
        ret = drm_universal_plane_init(drm, &layer->plane, 0,
                                       &sun4i_backend_layer_funcs,
                                       plane->formats, plane->nformats,
-                                      plane->type, NULL);
+                                      NULL, plane->type, NULL);
        if (ret) {
                dev_err(drm->dev, "Couldn't initialize layer\n");
                return ERR_PTR(ret);
 
        ret = drm_universal_plane_init(drm, &layer->plane, 0,
                                       &sun8i_mixer_layer_funcs,
                                       plane->formats, plane->nformats,
-                                      plane->type, NULL);
+                                      NULL, plane->type, NULL);
        if (ret) {
                dev_err(drm->dev, "Couldn't initialize layer\n");
                return ERR_PTR(ret);
 
 
        err = drm_universal_plane_init(drm, &plane->base, possible_crtcs,
                                       &tegra_primary_plane_funcs, formats,
-                                      num_formats, DRM_PLANE_TYPE_PRIMARY,
-                                      NULL);
+                                      num_formats, NULL,
+                                      DRM_PLANE_TYPE_PRIMARY, NULL);
        if (err < 0) {
                kfree(plane);
                return ERR_PTR(err);
 
        err = drm_universal_plane_init(drm, &plane->base, 1 << dc->pipe,
                                       &tegra_cursor_plane_funcs, formats,
-                                      num_formats, DRM_PLANE_TYPE_CURSOR,
-                                      NULL);
+                                      num_formats, NULL,
+                                      DRM_PLANE_TYPE_CURSOR, NULL);
        if (err < 0) {
                kfree(plane);
                return ERR_PTR(err);
 
        err = drm_universal_plane_init(drm, &plane->base, 1 << dc->pipe,
                                       &tegra_overlay_plane_funcs, formats,
-                                      num_formats, DRM_PLANE_TYPE_OVERLAY,
-                                      NULL);
+                                      num_formats, NULL,
+                                      DRM_PLANE_TYPE_OVERLAY, NULL);
        if (err < 0) {
                kfree(plane);
                return ERR_PTR(err);
 
                return PTR_ERR(connector);
 
        ret = drm_simple_display_pipe_init(drm, &tdev->pipe, funcs, formats,
-                                          format_count, connector);
+                                          format_count, NULL, connector);
        if (ret)
                return ret;
 
 
        ret = drm_universal_plane_init(dev, plane, 0,
                                       &vc4_plane_funcs,
                                       formats, num_formats,
-                                      type, NULL);
+                                      NULL, type, NULL);
 
        drm_plane_helper_add(plane, &vc4_plane_helper_funcs);
 
 
        ret = drm_universal_plane_init(dev, plane, 1 << index,
                                       &virtio_gpu_plane_funcs,
                                       formats, nformats,
-                                      type, NULL);
+                                      NULL, type, NULL);
        if (ret)
                goto err_plane_init;
 
 
                                       0, &vmw_ldu_plane_funcs,
                                       vmw_primary_plane_formats,
                                       ARRAY_SIZE(vmw_primary_plane_formats),
-                                      DRM_PLANE_TYPE_PRIMARY, NULL);
+                                      NULL, DRM_PLANE_TYPE_PRIMARY, NULL);
        if (ret) {
                DRM_ERROR("Failed to initialize primary plane");
                goto err_free;
                        0, &vmw_ldu_cursor_funcs,
                        vmw_cursor_plane_formats,
                        ARRAY_SIZE(vmw_cursor_plane_formats),
-                       DRM_PLANE_TYPE_CURSOR, NULL);
+                       NULL, DRM_PLANE_TYPE_CURSOR, NULL);
        if (ret) {
                DRM_ERROR("Failed to initialize cursor plane");
                drm_plane_cleanup(&ldu->base.primary);
 
                                       0, &vmw_sou_plane_funcs,
                                       vmw_primary_plane_formats,
                                       ARRAY_SIZE(vmw_primary_plane_formats),
-                                      DRM_PLANE_TYPE_PRIMARY, NULL);
+                                      NULL, DRM_PLANE_TYPE_PRIMARY, NULL);
        if (ret) {
                DRM_ERROR("Failed to initialize primary plane");
                goto err_free;
                        0, &vmw_sou_cursor_funcs,
                        vmw_cursor_plane_formats,
                        ARRAY_SIZE(vmw_cursor_plane_formats),
-                       DRM_PLANE_TYPE_CURSOR, NULL);
+                       NULL, DRM_PLANE_TYPE_CURSOR, NULL);
        if (ret) {
                DRM_ERROR("Failed to initialize cursor plane");
                drm_plane_cleanup(&sou->base.primary);
 
                                       0, &vmw_stdu_plane_funcs,
                                       vmw_primary_plane_formats,
                                       ARRAY_SIZE(vmw_primary_plane_formats),
-                                      DRM_PLANE_TYPE_PRIMARY, NULL);
+                                      NULL, DRM_PLANE_TYPE_PRIMARY, NULL);
        if (ret) {
                DRM_ERROR("Failed to initialize primary plane");
                goto err_free;
                        0, &vmw_stdu_cursor_funcs,
                        vmw_cursor_plane_formats,
                        ARRAY_SIZE(vmw_cursor_plane_formats),
-                       DRM_PLANE_TYPE_CURSOR, NULL);
+                       NULL, DRM_PLANE_TYPE_CURSOR, NULL);
        if (ret) {
                DRM_ERROR("Failed to initialize cursor plane");
                drm_plane_cleanup(&stdu->base.primary);
 
 
        ret = drm_universal_plane_init(drm, plane, VOU_CRTC_MASK,
                                       &zx_plane_funcs, formats, format_count,
-                                      type, NULL);
+                                      NULL, type, NULL);
        if (ret) {
                DRM_DEV_ERROR(dev, "failed to init universal plane: %d\n", ret);
                return ret;
 
         */
        void (*atomic_print_state)(struct drm_printer *p,
                                   const struct drm_plane_state *state);
+
+       /**
+        * @format_mod_supported:
+        *
+        * This optional hook is used for the DRM to determine if the given
+        * format/modifier combination is valid for the plane. This allows the
+        * DRM to generate the correct format bitmask (which formats apply to
+        * which modifier).
+        *
+        * Returns:
+        *
+        * True if the given modifier is valid for that format on the plane.
+        * False otherwise.
+        */
+       bool (*format_mod_supported)(struct drm_plane *plane, uint32_t format,
+                                    uint64_t modifier);
 };
 
 /**
        unsigned int format_count;
        bool format_default;
 
+       uint64_t *modifiers;
+       unsigned int modifier_count;
+
        struct drm_crtc *crtc;
        struct drm_framebuffer *fb;
 
 
 #define obj_to_plane(x) container_of(x, struct drm_plane, base)
 
-__printf(8, 9)
+__printf(9, 10)
 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, ...);
 int drm_plane_init(struct drm_device *dev,
 
                        struct drm_simple_display_pipe *pipe,
                        const struct drm_simple_display_pipe_funcs *funcs,
                        const uint32_t *formats, unsigned int format_count,
+                       const uint64_t *format_modifiers,
                        struct drm_connector *connector);
 
 #endif /* __LINUX_DRM_SIMPLE_KMS_HELPER_H */
 
 #define DRM_FORMAT_MOD_VENDOR_BROADCOM 0x07
 /* add more to the end as needed */
 
+#define DRM_FORMAT_RESERVED          ((1ULL << 56) - 1)
+
 #define fourcc_mod_code(vendor, val) \
        ((((__u64)DRM_FORMAT_MOD_VENDOR_## vendor) << 56) | (val & 0x00ffffffffffffffULL))
 
  * authoritative source for all of these.
  */
 
+/*
+ * Invalid Modifier
+ *
+ * This modifier can be used as a sentinel to terminate the format modifiers
+ * list, or to initialize a variable with an invalid modifier. It might also be
+ * used to report an error back to userspace for certain APIs.
+ */
+#define DRM_FORMAT_MOD_INVALID fourcc_mod_code(NONE, DRM_FORMAT_RESERVED)
+
 /*
  * Linear Layout
  *