Extend the size-checking special function to handle afbc.

Signed-off-by: Andrzej Pietrasiewicz <andrze...@collabora.com>
---
 drivers/gpu/drm/drm_fourcc.c                 | 10 +++-
 drivers/gpu/drm/drm_framebuffer.c            |  3 +
 drivers/gpu/drm/drm_gem_framebuffer_helper.c | 60 ++++++++++++++++++--
 include/drm/drm_gem_framebuffer_helper.h     | 16 ++++++
 4 files changed, 82 insertions(+), 7 deletions(-)

diff --git a/drivers/gpu/drm/drm_fourcc.c b/drivers/gpu/drm/drm_fourcc.c
index d14dd7c86020..9ac2175c5bee 100644
--- a/drivers/gpu/drm/drm_fourcc.c
+++ b/drivers/gpu/drm/drm_fourcc.c
@@ -323,8 +323,14 @@ drm_get_format_info(struct drm_device *dev,
 {
        const struct drm_format_info *info = NULL;
 
-       if (dev->mode_config.funcs->get_format_info)
-               info = dev->mode_config.funcs->get_format_info(mode_cmd);
+       /* bypass driver callback if afbc */
+       if (!drm_is_afbc(mode_cmd->modifier[0]))
+               if (dev->mode_config.funcs->get_format_info) {
+                       const struct drm_mode_config_funcs *funcs;
+
+                       funcs = dev->mode_config.funcs;
+                       info = funcs->get_format_info(mode_cmd);
+               }
 
        if (!info)
                info = drm_format_info(mode_cmd->pixel_format);
diff --git a/drivers/gpu/drm/drm_framebuffer.c 
b/drivers/gpu/drm/drm_framebuffer.c
index 57564318ceea..33b741cc73e8 100644
--- a/drivers/gpu/drm/drm_framebuffer.c
+++ b/drivers/gpu/drm/drm_framebuffer.c
@@ -204,6 +204,9 @@ static int framebuffer_check(struct drm_device *dev,
                unsigned int block_size = info->char_per_block[i];
                u64 min_pitch = drm_format_info_min_pitch(info, i, width);
 
+               if (drm_is_afbc(r->modifier[i]))
+                       block_size = 0;
+
                if (!block_size && (r->modifier[i] == DRM_FORMAT_MOD_LINEAR)) {
                        DRM_DEBUG_KMS("Format requires non-linear modifier for 
plane %d\n", i);
                        return -EINVAL;
diff --git a/drivers/gpu/drm/drm_gem_framebuffer_helper.c 
b/drivers/gpu/drm/drm_gem_framebuffer_helper.c
index 4201dc1f32a5..e20f4d00b0a5 100644
--- a/drivers/gpu/drm/drm_gem_framebuffer_helper.c
+++ b/drivers/gpu/drm/drm_gem_framebuffer_helper.c
@@ -21,6 +21,11 @@
 #include <drm/drm_modeset_helper.h>
 #include <drm/drm_simple_kms_helper.h>
 
+#define AFBC_HEADER_SIZE               16
+#define AFBC_TH_LAYOUT_ALIGNMENT       8
+#define AFBC_SUPERBLOCK_PIXELS         256
+#define AFBC_SUPERBLOCK_ALIGNMENT      128
+
 /**
  * DOC: overview
  *
@@ -200,6 +205,40 @@ int drm_gem_fb_lookup(struct drm_device *dev,
 }
 EXPORT_SYMBOL_GPL(drm_gem_fb_lookup);
 
+static int drm_gem_afbc_min_size(struct drm_device *dev,
+                                const struct drm_mode_fb_cmd2 *mode_cmd,
+                                struct drm_afbc *afbc)
+{
+       u32 n_blocks;
+
+       if (!drm_afbc_get_superblock_wh(mode_cmd->modifier[0],
+                                       &afbc->block_width,
+                                       &afbc->block_height)) {
+               return -EINVAL;
+       }
+
+       /* tiled header afbc */
+       if (mode_cmd->modifier[0] & AFBC_FORMAT_MOD_TILED) {
+               afbc->block_width *= AFBC_TH_LAYOUT_ALIGNMENT;
+               afbc->block_height *= AFBC_TH_LAYOUT_ALIGNMENT;
+       }
+
+       afbc->aligned_width = ALIGN(mode_cmd->width, afbc->block_width);
+       afbc->aligned_height = ALIGN(mode_cmd->height, afbc->block_height);
+       afbc->offset = mode_cmd->offsets[0];
+
+       n_blocks = (afbc->aligned_width * afbc->aligned_height)
+                / AFBC_SUPERBLOCK_PIXELS;
+       afbc->offset_payload = ALIGN(n_blocks * AFBC_HEADER_SIZE,
+                                    afbc->alignment_header);
+
+       afbc->afbc_size = afbc->offset_payload + n_blocks *
+                         ALIGN(afbc->bpp * AFBC_SUPERBLOCK_PIXELS / 8,
+                               AFBC_SUPERBLOCK_ALIGNMENT);
+
+       return 0;
+}
+
 /**
  * drm_gem_fb_size_check_special() - Helper function for use in
  *                                  &drm_mode_config_funcs.fb_create
@@ -218,6 +257,7 @@ int drm_gem_fb_size_check_special(struct drm_device *dev,
                                  const struct drm_size_check *check,
                                  struct drm_gem_object **objs)
 {
+#define CHECK_HAS(field) (check && check->field)
        const struct drm_format_info *info;
        int i;
 
@@ -231,24 +271,34 @@ int drm_gem_fb_size_check_special(struct drm_device *dev,
                unsigned int min_size;
                u32 pitch = mode_cmd->pitches[i];
 
-               if (check && check->use_pitch_multiplier)
+               if (CHECK_HAS(use_pitch_multiplier))
                        if ((pitch * check->pitch_multiplier[i]) %
                            check->pitch_modulo)
                                return -EINVAL;
 
-               if (check && check->use_min_size)
+               if (CHECK_HAS(use_min_size)) {
                        min_size = check->min_size[i];
-               else
+               } else if (CHECK_HAS(data) &&
+                               drm_is_afbc(mode_cmd->modifier[0])) {
+                       struct drm_afbc *afbc;
+                       int ret;
+
+                       afbc = check->data;
+                       ret = drm_gem_afbc_min_size(dev, mode_cmd, afbc);
+                       if (ret < 0)
+                               return ret;
+                       min_size = ret;
+               } else {
                        min_size = (height - 1) * pitch
                                 + drm_format_info_min_pitch(info, i, width)
                                 + mode_cmd->offsets[i];
-
+               }
                if (objs[i]->size < min_size)
                        return -EINVAL;
        }
 
        return 0;
-
+#undef CHECK_HAS
 }
 EXPORT_SYMBOL_GPL(drm_gem_fb_size_check_special);
 
diff --git a/include/drm/drm_gem_framebuffer_helper.h 
b/include/drm/drm_gem_framebuffer_helper.h
index 74304a268694..3d6015194b3c 100644
--- a/include/drm/drm_gem_framebuffer_helper.h
+++ b/include/drm/drm_gem_framebuffer_helper.h
@@ -22,6 +22,22 @@ struct drm_size_check {
        u32 pitch_multiplier[4];
        u32 pitch_modulo;
        bool use_pitch_multiplier;
+       void *data;
+};
+
+/**
+ * struct drm_afbc - AFBC-specific data.
+ */
+struct drm_afbc {
+       u32 block_width;
+       u32 block_height;
+       u32 aligned_width;
+       u32 aligned_height;
+       u32 offset;
+       u32 alignment_header;
+       u32 afbc_size;
+       u32 offset_payload;
+       u32 bpp;
 };
 
 struct drm_gem_object *drm_gem_fb_get_obj(struct drm_framebuffer *fb,
-- 
2.17.1

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

Reply via email to