Extend the size-checking special function to handle afbc.

Signed-off-by: Andrzej Pietrasiewicz <andrze...@collabora.com>
---
 drivers/gpu/drm/drm_gem_framebuffer_helper.c | 49 +++++++++++++++++--
 include/drm/drm_framebuffer.h                | 50 ++++++++++++++++++++
 include/drm/drm_gem_framebuffer_helper.h     |  1 +
 3 files changed, 96 insertions(+), 4 deletions(-)

diff --git a/drivers/gpu/drm/drm_gem_framebuffer_helper.c 
b/drivers/gpu/drm/drm_gem_framebuffer_helper.c
index d2fce1ec8f37..5fe9032a5ee8 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
  *
@@ -299,6 +304,34 @@ 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_framebuffer *afbc_fb)
+{
+       u32 n_blocks;
+
+       if (!drm_afbc_get_superblock_wh(mode_cmd->modifier[0], 
&afbc_fb->block_width, &afbc_fb->block_height))
+               return -EINVAL;
+
+       /* tiled header afbc */
+       if (mode_cmd->modifier[0] & AFBC_FORMAT_MOD_TILED) {
+               afbc_fb->block_width *= AFBC_TH_LAYOUT_ALIGNMENT;
+               afbc_fb->block_height *= AFBC_TH_LAYOUT_ALIGNMENT;
+       }
+
+       afbc_fb->aligned_width = ALIGN(mode_cmd->width, afbc_fb->block_width);
+       afbc_fb->aligned_height = ALIGN(mode_cmd->height, 
afbc_fb->block_height);
+       afbc_fb->offset = mode_cmd->offsets[0];
+
+       n_blocks = (afbc_fb->aligned_width * afbc_fb->aligned_height) / 
AFBC_SUPERBLOCK_PIXELS;
+       afbc_fb->offset_payload = ALIGN(n_blocks * AFBC_HEADER_SIZE, 
afbc_fb->alignment_header);
+
+       afbc_fb->afbc_size = afbc_fb->offset_payload
+                          + n_blocks * ALIGN(afbc_fb->bpp * 
AFBC_SUPERBLOCK_PIXELS / 8, AFBC_SUPERBLOCK_ALIGNMENT);
+
+       return 0;
+}
+
 /**
  * drm_gem_fb_size_check2() - Helper function for use in
  *                           &drm_mode_config_funcs.fb_create implementations
@@ -334,19 +367,27 @@ int drm_gem_fb_size_check2(struct drm_device *dev,
                            check->pitch_modulo)
                                return -EINVAL;
 
-               if (check && check->use_min_size)
+               if (check && check->use_min_size) {
                        min_size = check->min_size[i];
-               else
+               } else if (check && check->data && 
drm_is_afbc(mode_cmd->modifier[0])) {
+                       struct drm_afbc_framebuffer *afbc_fb;
+                       int ret;
+
+                       afbc_fb = check->data;
+                       ret = drm_gem_afbc_min_size(dev, mode_cmd, afbc_fb);
+                       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;
-
 }
 EXPORT_SYMBOL_GPL(drm_gem_fb_size_check2);
 
diff --git a/include/drm/drm_framebuffer.h b/include/drm/drm_framebuffer.h
index c0e0256e3e98..c8a06e37585a 100644
--- a/include/drm/drm_framebuffer.h
+++ b/include/drm/drm_framebuffer.h
@@ -297,4 +297,54 @@ int drm_framebuffer_plane_width(int width,
 int drm_framebuffer_plane_height(int height,
                                 const struct drm_framebuffer *fb, int plane);
 
+/**
+ * struct drm_afbc_framebuffer - a special afbc frame buffer object
+ *
+ * A derived class of struct drm_framebuffer, dedicated for afbc use cases.
+ */
+struct drm_afbc_framebuffer {
+       /**
+        * @base: base framebuffer structure.
+        */
+       struct drm_framebuffer base;
+       /**
+        * @block_widht: width of a single afbc block
+        */
+       u32 block_width;
+       /**
+        * @block_widht: height of a single afbc block
+        */
+       u32 block_height;
+       /**
+        * @aligned_width: aligned frame buffer width
+        */
+       u32 aligned_width;
+       /**
+        * @aligned_height: aligned frame buffer height
+        */
+       u32 aligned_height;
+       /**
+        * @offset: offset of the first afbc header
+        */
+       u32 offset;
+       /**
+        * @alignment_header: required alignment for afbc headers
+        */
+       u32 alignment_header;
+       /**
+        * @afbc_size: minimum size of afbc buffer
+        */
+       u32 afbc_size;
+       /**
+        * @offset_payload: start of afbc body buffer
+        */
+       u32 offset_payload;
+       /**
+        * @bpp: bpp value for this afbc buffer
+        */
+       u32 bpp;
+};
+
+#define fb_to_afbc_fb(x) container_of(x, struct drm_afbc_framebuffer, base)
+
 #endif
diff --git a/include/drm/drm_gem_framebuffer_helper.h 
b/include/drm/drm_gem_framebuffer_helper.h
index 4955af96d6c3..17e3f849a0fb 100644
--- a/include/drm/drm_gem_framebuffer_helper.h
+++ b/include/drm/drm_gem_framebuffer_helper.h
@@ -22,6 +22,7 @@ struct drm_size_check {
        u32 pitch_multiplier[4];
        u32 pitch_modulo;
        bool use_pitch_multiplier;
+       void *data;
 };
 
 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