All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 0/2] AFBC for Rockchip
@ 2019-10-11 11:18 ` Andrzej Pietrasiewicz
  0 siblings, 0 replies; 63+ messages in thread
From: Andrzej Pietrasiewicz @ 2019-10-11 11:18 UTC (permalink / raw)
  To: dri-devel
  Cc: Sandy Huang, kernel, Andrzej Pietrasiewicz, Maarten Lankhorst,
	Maxime Ripard, Sean Paul, David Airlie, Daniel Vetter,
	Liviu Dudau, Brian Starkey, Heiko Stübner, linux-kernel,
	linux-arm-kernel, linux-rockchip

This series adds AFBC support for Rockchip.
It is inspired by:

https://chromium.googlesource.com/chromiumos/third_party/kernel/+/refs/heads/factory-gru-9017.B-chromeos-4.4/drivers/gpu/drm/rockchip/rockchip_drm_vop.c

The first patch factors out some afbc helper functions from malidp,
as they are useful in general. The second patch adds implementation proper
of AFBC support for Rockchip.

Andrzej Pietrasiewicz (2):
  drm/arm: Factor out generic afbc helpers
  drm/rockchip: Add support for afbc

 drivers/gpu/drm/Kconfig                     |   4 +
 drivers/gpu/drm/Makefile                    |   1 +
 drivers/gpu/drm/arm/Kconfig                 |   1 +
 drivers/gpu/drm/arm/malidp_drv.c            |  58 +-------
 drivers/gpu/drm/drm_afbc.c                  | 114 ++++++++++++++++
 drivers/gpu/drm/rockchip/Kconfig            |   1 +
 drivers/gpu/drm/rockchip/rockchip_drm_fb.c  |  43 ++++++
 drivers/gpu/drm/rockchip/rockchip_drm_vop.c | 140 +++++++++++++++++++-
 drivers/gpu/drm/rockchip/rockchip_drm_vop.h |  12 ++
 drivers/gpu/drm/rockchip/rockchip_vop_reg.c |  86 +++++++++++-
 include/drm/drm_afbc.h                      |  25 ++++
 11 files changed, 427 insertions(+), 58 deletions(-)
 create mode 100644 drivers/gpu/drm/drm_afbc.c
 create mode 100644 include/drm/drm_afbc.h

-- 
2.17.1


^ permalink raw reply	[flat|nested] 63+ messages in thread

* [PATCH 0/2] AFBC for Rockchip
@ 2019-10-11 11:18 ` Andrzej Pietrasiewicz
  0 siblings, 0 replies; 63+ messages in thread
From: Andrzej Pietrasiewicz @ 2019-10-11 11:18 UTC (permalink / raw)
  To: dri-devel
  Cc: Heiko Stübner, David Airlie, Liviu Dudau, Maarten Lankhorst,
	Sandy Huang, Maxime Ripard, Andrzej Pietrasiewicz,
	linux-rockchip, linux-arm-kernel, Daniel Vetter, kernel,
	Sean Paul, Brian Starkey, linux-kernel

This series adds AFBC support for Rockchip.
It is inspired by:

https://chromium.googlesource.com/chromiumos/third_party/kernel/+/refs/heads/factory-gru-9017.B-chromeos-4.4/drivers/gpu/drm/rockchip/rockchip_drm_vop.c

The first patch factors out some afbc helper functions from malidp,
as they are useful in general. The second patch adds implementation proper
of AFBC support for Rockchip.

Andrzej Pietrasiewicz (2):
  drm/arm: Factor out generic afbc helpers
  drm/rockchip: Add support for afbc

 drivers/gpu/drm/Kconfig                     |   4 +
 drivers/gpu/drm/Makefile                    |   1 +
 drivers/gpu/drm/arm/Kconfig                 |   1 +
 drivers/gpu/drm/arm/malidp_drv.c            |  58 +-------
 drivers/gpu/drm/drm_afbc.c                  | 114 ++++++++++++++++
 drivers/gpu/drm/rockchip/Kconfig            |   1 +
 drivers/gpu/drm/rockchip/rockchip_drm_fb.c  |  43 ++++++
 drivers/gpu/drm/rockchip/rockchip_drm_vop.c | 140 +++++++++++++++++++-
 drivers/gpu/drm/rockchip/rockchip_drm_vop.h |  12 ++
 drivers/gpu/drm/rockchip/rockchip_vop_reg.c |  86 +++++++++++-
 include/drm/drm_afbc.h                      |  25 ++++
 11 files changed, 427 insertions(+), 58 deletions(-)
 create mode 100644 drivers/gpu/drm/drm_afbc.c
 create mode 100644 include/drm/drm_afbc.h

-- 
2.17.1


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 63+ messages in thread

* [PATCH 1/2] drm/arm: Factor out generic afbc helpers
  2019-10-11 11:18 ` Andrzej Pietrasiewicz
@ 2019-10-11 11:18   ` Andrzej Pietrasiewicz
  -1 siblings, 0 replies; 63+ messages in thread
From: Andrzej Pietrasiewicz @ 2019-10-11 11:18 UTC (permalink / raw)
  To: dri-devel
  Cc: Sandy Huang, kernel, Andrzej Pietrasiewicz, Maarten Lankhorst,
	Maxime Ripard, Sean Paul, David Airlie, Daniel Vetter,
	Liviu Dudau, Brian Starkey, Heiko Stübner, linux-kernel,
	linux-arm-kernel, linux-rockchip

These are useful for other users of afbc, e.g. rockchip.

Signed-off-by: Andrzej Pietrasiewicz <andrzej.p@collabora.com>
---
 drivers/gpu/drm/Kconfig          |   4 ++
 drivers/gpu/drm/Makefile         |   1 +
 drivers/gpu/drm/arm/Kconfig      |   1 +
 drivers/gpu/drm/arm/malidp_drv.c |  58 ++--------------
 drivers/gpu/drm/drm_afbc.c       | 114 +++++++++++++++++++++++++++++++
 include/drm/drm_afbc.h           |  25 +++++++
 6 files changed, 149 insertions(+), 54 deletions(-)
 create mode 100644 drivers/gpu/drm/drm_afbc.c
 create mode 100644 include/drm/drm_afbc.h

diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig
index 3c88420e3497..00e3f90557f4 100644
--- a/drivers/gpu/drm/Kconfig
+++ b/drivers/gpu/drm/Kconfig
@@ -195,6 +195,10 @@ config DRM_SCHED
 	tristate
 	depends on DRM
 
+config DRM_AFBC
+	tristate
+	depends on DRM
+
 source "drivers/gpu/drm/i2c/Kconfig"
 
 source "drivers/gpu/drm/arm/Kconfig"
diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile
index 9f0d2ee35794..55368b668355 100644
--- a/drivers/gpu/drm/Makefile
+++ b/drivers/gpu/drm/Makefile
@@ -31,6 +31,7 @@ drm-$(CONFIG_OF) += drm_of.o
 drm-$(CONFIG_AGP) += drm_agpsupport.o
 drm-$(CONFIG_DEBUG_FS) += drm_debugfs.o drm_debugfs_crc.o
 drm-$(CONFIG_DRM_LOAD_EDID_FIRMWARE) += drm_edid_load.o
+drm-$(CONFIG_DRM_AFBC) += drm_afbc.o
 
 drm_vram_helper-y := drm_gem_vram_helper.o \
 		     drm_vram_helper_common.o \
diff --git a/drivers/gpu/drm/arm/Kconfig b/drivers/gpu/drm/arm/Kconfig
index a204103b3efb..25c3dc408cda 100644
--- a/drivers/gpu/drm/arm/Kconfig
+++ b/drivers/gpu/drm/arm/Kconfig
@@ -29,6 +29,7 @@ config DRM_MALI_DISPLAY
 	select DRM_KMS_HELPER
 	select DRM_KMS_CMA_HELPER
 	select DRM_GEM_CMA_HELPER
+	select DRM_AFBC
 	select VIDEOMODE_HELPERS
 	help
 	  Choose this option if you want to compile the ARM Mali Display
diff --git a/drivers/gpu/drm/arm/malidp_drv.c b/drivers/gpu/drm/arm/malidp_drv.c
index f25ec4382277..a67b69e08f63 100644
--- a/drivers/gpu/drm/arm/malidp_drv.c
+++ b/drivers/gpu/drm/arm/malidp_drv.c
@@ -16,6 +16,7 @@
 #include <linux/debugfs.h>
 
 #include <drm/drmP.h>
+#include <drm/drm_afbc.h>
 #include <drm/drm_atomic.h>
 #include <drm/drm_atomic_helper.h>
 #include <drm/drm_crtc.h>
@@ -33,8 +34,6 @@
 #include "malidp_hw.h"
 
 #define MALIDP_CONF_VALID_TIMEOUT	250
-#define AFBC_HEADER_SIZE		16
-#define AFBC_SUPERBLK_ALIGNMENT		128
 
 static void malidp_write_gamma_table(struct malidp_hw_device *hwdev,
 				     u32 data[MALIDP_COEFFTAB_NUM_COEFFS])
@@ -275,24 +274,8 @@ malidp_verify_afbc_framebuffer_caps(struct drm_device *dev,
 					mode_cmd->modifier[0]) == false)
 		return false;
 
-	if (mode_cmd->offsets[0] != 0) {
-		DRM_DEBUG_KMS("AFBC buffers' plane offset should be 0\n");
-		return false;
-	}
-
-	switch (mode_cmd->modifier[0] & AFBC_SIZE_MASK) {
-	case AFBC_SIZE_16X16:
-		if ((mode_cmd->width % 16) || (mode_cmd->height % 16)) {
-			DRM_DEBUG_KMS("AFBC buffers must be aligned to 16 pixels\n");
-			return false;
-		}
-		break;
-	default:
-		DRM_DEBUG_KMS("Unsupported AFBC block size\n");
-		return false;
-	}
-
-	return true;
+	return drm_afbc_check_offset(dev, mode_cmd) &&
+	       drm_afbc_check_size_align(dev, mode_cmd);
 }
 
 static bool
@@ -300,53 +283,20 @@ malidp_verify_afbc_framebuffer_size(struct drm_device *dev,
 				    struct drm_file *file,
 				    const struct drm_mode_fb_cmd2 *mode_cmd)
 {
-	int n_superblocks = 0;
 	const struct drm_format_info *info;
 	struct drm_gem_object *objs = NULL;
-	u32 afbc_superblock_size = 0, afbc_superblock_height = 0;
-	u32 afbc_superblock_width = 0, afbc_size = 0;
 	int bpp = 0;
 
-	switch (mode_cmd->modifier[0] & AFBC_SIZE_MASK) {
-	case AFBC_SIZE_16X16:
-		afbc_superblock_height = 16;
-		afbc_superblock_width = 16;
-		break;
-	default:
-		DRM_DEBUG_KMS("AFBC superblock size is not supported\n");
-		return false;
-	}
-
 	info = drm_get_format_info(dev, mode_cmd);
-
-	n_superblocks = (mode_cmd->width / afbc_superblock_width) *
-		(mode_cmd->height / afbc_superblock_height);
-
 	bpp = malidp_format_get_bpp(info->format);
 
-	afbc_superblock_size = (bpp * afbc_superblock_width * afbc_superblock_height)
-				/ BITS_PER_BYTE;
-
-	afbc_size = ALIGN(n_superblocks * AFBC_HEADER_SIZE, AFBC_SUPERBLK_ALIGNMENT);
-	afbc_size += n_superblocks * ALIGN(afbc_superblock_size, AFBC_SUPERBLK_ALIGNMENT);
-
-	if ((mode_cmd->width * bpp) != (mode_cmd->pitches[0] * BITS_PER_BYTE)) {
-		DRM_DEBUG_KMS("Invalid value of (pitch * BITS_PER_BYTE) (=%u) "
-			      "should be same as width (=%u) * bpp (=%u)\n",
-			      (mode_cmd->pitches[0] * BITS_PER_BYTE),
-			      mode_cmd->width, bpp);
-		return false;
-	}
-
 	objs = drm_gem_object_lookup(file, mode_cmd->handles[0]);
 	if (!objs) {
 		DRM_DEBUG_KMS("Failed to lookup GEM object\n");
 		return false;
 	}
 
-	if (objs->size < afbc_size) {
-		DRM_DEBUG_KMS("buffer size (%zu) too small for AFBC buffer size = %u\n",
-			      objs->size, afbc_size);
+	if (!drm_afbc_check_fb_size(dev, mode_cmd, objs, bpp)) {
 		drm_gem_object_put_unlocked(objs);
 		return false;
 	}
diff --git a/drivers/gpu/drm/drm_afbc.c b/drivers/gpu/drm/drm_afbc.c
new file mode 100644
index 000000000000..3e8a9225fd2e
--- /dev/null
+++ b/drivers/gpu/drm/drm_afbc.c
@@ -0,0 +1,114 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * (C) 2019 Collabora Ltd.
+ *
+ * author: Andrzej Pietrasiewicz <andrzej.p@collabora.com>
+ *
+ */
+#include <linux/module.h>
+
+#include <drm/drm_afbc.h>
+#include <drm/drm_device.h>
+#include <drm/drm_fourcc.h>
+#include <drm/drm_gem.h>
+#include <drm/drm_mode.h>
+#include <drm/drm_print.h>
+
+#define AFBC_HEADER_SIZE		16
+#define AFBC_SUPERBLK_ALIGNMENT		128
+
+bool drm_afbc_check_offset(struct drm_device *dev,
+			   const struct drm_mode_fb_cmd2 *mode_cmd)
+{
+	if (mode_cmd->offsets[0] != 0) {
+		DRM_DEBUG_KMS("AFBC buffers' plane offset should be 0\n");
+		return false;
+	}
+
+	return true;
+}
+EXPORT_SYMBOL_GPL(drm_afbc_check_offset);
+
+bool drm_afbc_check_size_align(struct drm_device *dev,
+			       const struct drm_mode_fb_cmd2 *mode_cmd)
+{
+
+	switch (mode_cmd->modifier[0] & AFBC_FORMAT_MOD_BLOCK_SIZE_MASK) {
+	case AFBC_FORMAT_MOD_BLOCK_SIZE_16x16:
+		if ((mode_cmd->width % 16) || (mode_cmd->height % 16)) {
+			DRM_DEBUG_KMS(
+				"AFBC buffer must be aligned to 16 pixels\n"
+			);
+			return false;
+		}
+		break;
+	case AFBC_FORMAT_MOD_BLOCK_SIZE_32x8:
+		/* fall through */
+	case AFBC_FORMAT_MOD_BLOCK_SIZE_64x4:
+		/* fall through */
+	case AFBC_FORMAT_MOD_BLOCK_SIZE_32x8_64x4:
+		/* fall through */
+	default:
+		DRM_DEBUG_KMS("Unsupported AFBC block size\n");
+		return false;
+	}
+
+	return true;
+}
+EXPORT_SYMBOL_GPL(drm_afbc_check_size_align);
+
+bool drm_afbc_check_fb_size(struct drm_device *dev,
+			    const struct drm_mode_fb_cmd2 *mode_cmd,
+			    struct drm_gem_object *objs, int bpp)
+{
+	int n_superblocks = 0;
+	u32 afbc_superblock_size = 0, afbc_superblock_height = 0;
+	u32 afbc_superblock_width = 0, afbc_size = 0;
+
+	switch (mode_cmd->modifier[0] & AFBC_FORMAT_MOD_BLOCK_SIZE_MASK) {
+	case AFBC_FORMAT_MOD_BLOCK_SIZE_16x16:
+		afbc_superblock_height = 16;
+		afbc_superblock_width = 16;
+		break;
+	case AFBC_FORMAT_MOD_BLOCK_SIZE_32x8:
+		/* fall through */
+	case AFBC_FORMAT_MOD_BLOCK_SIZE_64x4:
+		/* fall through */
+	case AFBC_FORMAT_MOD_BLOCK_SIZE_32x8_64x4:
+		/* fall through */
+	default:
+		DRM_DEBUG_KMS("AFBC superblock size is not supported\n");
+		return false;
+	}
+
+	n_superblocks = (mode_cmd->width / afbc_superblock_width) *
+		(mode_cmd->height / afbc_superblock_height);
+
+	afbc_superblock_size =
+		(bpp * afbc_superblock_width * afbc_superblock_height)
+			/ BITS_PER_BYTE;
+
+	afbc_size = ALIGN(n_superblocks * AFBC_HEADER_SIZE,
+			  AFBC_SUPERBLK_ALIGNMENT);
+	afbc_size += n_superblocks *
+		ALIGN(afbc_superblock_size, AFBC_SUPERBLK_ALIGNMENT);
+
+	if ((mode_cmd->width * bpp) != (mode_cmd->pitches[0] * BITS_PER_BYTE)) {
+		DRM_DEBUG_KMS("Invalid value of (pitch * BITS_PER_BYTE) (=%u) should be same as width (=%u) * bpp (=%u)\n",
+			mode_cmd->pitches[0] * BITS_PER_BYTE,
+			mode_cmd->width, bpp
+		);
+		return false;
+	}
+
+	if (objs->size < afbc_size) {
+		DRM_DEBUG_KMS("buffer size (%zu) too small for AFBC buffer size = %u\n",
+			objs->size, afbc_size
+		);
+
+		return false;
+	}
+
+	return true;
+}
+EXPORT_SYMBOL(drm_afbc_check_fb_size);
diff --git a/include/drm/drm_afbc.h b/include/drm/drm_afbc.h
new file mode 100644
index 000000000000..ce39c850217b
--- /dev/null
+++ b/include/drm/drm_afbc.h
@@ -0,0 +1,25 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * (C) 2019 Collabora Ltd.
+ *
+ * author: Andrzej Pietrasiewicz <andrzej.p@collabora.com>
+ *
+ */
+#ifndef __DRM_AFBC_H__
+#define __DRM_AFBC_H__
+
+struct drm_device;
+struct drm_mode_fb_cmd2;
+struct drm_gem_object;
+
+bool drm_afbc_check_offset(struct drm_device *dev,
+			   const struct drm_mode_fb_cmd2 *mode_cmd);
+
+bool drm_afbc_check_size_align(struct drm_device *dev,
+			       const struct drm_mode_fb_cmd2 *mode_cmd);
+
+bool drm_afbc_check_fb_size(struct drm_device *dev,
+			    const struct drm_mode_fb_cmd2 *mode_cmd,
+			    struct drm_gem_object *objs, int bpp);
+
+#endif /* __DRM_AFBC_H__ */
-- 
2.17.1


^ permalink raw reply related	[flat|nested] 63+ messages in thread

* [PATCH 1/2] drm/arm: Factor out generic afbc helpers
@ 2019-10-11 11:18   ` Andrzej Pietrasiewicz
  0 siblings, 0 replies; 63+ messages in thread
From: Andrzej Pietrasiewicz @ 2019-10-11 11:18 UTC (permalink / raw)
  To: dri-devel
  Cc: Heiko Stübner, David Airlie, Liviu Dudau, Maarten Lankhorst,
	Sandy Huang, Maxime Ripard, Andrzej Pietrasiewicz,
	linux-rockchip, linux-arm-kernel, Daniel Vetter, kernel,
	Sean Paul, Brian Starkey, linux-kernel

These are useful for other users of afbc, e.g. rockchip.

Signed-off-by: Andrzej Pietrasiewicz <andrzej.p@collabora.com>
---
 drivers/gpu/drm/Kconfig          |   4 ++
 drivers/gpu/drm/Makefile         |   1 +
 drivers/gpu/drm/arm/Kconfig      |   1 +
 drivers/gpu/drm/arm/malidp_drv.c |  58 ++--------------
 drivers/gpu/drm/drm_afbc.c       | 114 +++++++++++++++++++++++++++++++
 include/drm/drm_afbc.h           |  25 +++++++
 6 files changed, 149 insertions(+), 54 deletions(-)
 create mode 100644 drivers/gpu/drm/drm_afbc.c
 create mode 100644 include/drm/drm_afbc.h

diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig
index 3c88420e3497..00e3f90557f4 100644
--- a/drivers/gpu/drm/Kconfig
+++ b/drivers/gpu/drm/Kconfig
@@ -195,6 +195,10 @@ config DRM_SCHED
 	tristate
 	depends on DRM
 
+config DRM_AFBC
+	tristate
+	depends on DRM
+
 source "drivers/gpu/drm/i2c/Kconfig"
 
 source "drivers/gpu/drm/arm/Kconfig"
diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile
index 9f0d2ee35794..55368b668355 100644
--- a/drivers/gpu/drm/Makefile
+++ b/drivers/gpu/drm/Makefile
@@ -31,6 +31,7 @@ drm-$(CONFIG_OF) += drm_of.o
 drm-$(CONFIG_AGP) += drm_agpsupport.o
 drm-$(CONFIG_DEBUG_FS) += drm_debugfs.o drm_debugfs_crc.o
 drm-$(CONFIG_DRM_LOAD_EDID_FIRMWARE) += drm_edid_load.o
+drm-$(CONFIG_DRM_AFBC) += drm_afbc.o
 
 drm_vram_helper-y := drm_gem_vram_helper.o \
 		     drm_vram_helper_common.o \
diff --git a/drivers/gpu/drm/arm/Kconfig b/drivers/gpu/drm/arm/Kconfig
index a204103b3efb..25c3dc408cda 100644
--- a/drivers/gpu/drm/arm/Kconfig
+++ b/drivers/gpu/drm/arm/Kconfig
@@ -29,6 +29,7 @@ config DRM_MALI_DISPLAY
 	select DRM_KMS_HELPER
 	select DRM_KMS_CMA_HELPER
 	select DRM_GEM_CMA_HELPER
+	select DRM_AFBC
 	select VIDEOMODE_HELPERS
 	help
 	  Choose this option if you want to compile the ARM Mali Display
diff --git a/drivers/gpu/drm/arm/malidp_drv.c b/drivers/gpu/drm/arm/malidp_drv.c
index f25ec4382277..a67b69e08f63 100644
--- a/drivers/gpu/drm/arm/malidp_drv.c
+++ b/drivers/gpu/drm/arm/malidp_drv.c
@@ -16,6 +16,7 @@
 #include <linux/debugfs.h>
 
 #include <drm/drmP.h>
+#include <drm/drm_afbc.h>
 #include <drm/drm_atomic.h>
 #include <drm/drm_atomic_helper.h>
 #include <drm/drm_crtc.h>
@@ -33,8 +34,6 @@
 #include "malidp_hw.h"
 
 #define MALIDP_CONF_VALID_TIMEOUT	250
-#define AFBC_HEADER_SIZE		16
-#define AFBC_SUPERBLK_ALIGNMENT		128
 
 static void malidp_write_gamma_table(struct malidp_hw_device *hwdev,
 				     u32 data[MALIDP_COEFFTAB_NUM_COEFFS])
@@ -275,24 +274,8 @@ malidp_verify_afbc_framebuffer_caps(struct drm_device *dev,
 					mode_cmd->modifier[0]) == false)
 		return false;
 
-	if (mode_cmd->offsets[0] != 0) {
-		DRM_DEBUG_KMS("AFBC buffers' plane offset should be 0\n");
-		return false;
-	}
-
-	switch (mode_cmd->modifier[0] & AFBC_SIZE_MASK) {
-	case AFBC_SIZE_16X16:
-		if ((mode_cmd->width % 16) || (mode_cmd->height % 16)) {
-			DRM_DEBUG_KMS("AFBC buffers must be aligned to 16 pixels\n");
-			return false;
-		}
-		break;
-	default:
-		DRM_DEBUG_KMS("Unsupported AFBC block size\n");
-		return false;
-	}
-
-	return true;
+	return drm_afbc_check_offset(dev, mode_cmd) &&
+	       drm_afbc_check_size_align(dev, mode_cmd);
 }
 
 static bool
@@ -300,53 +283,20 @@ malidp_verify_afbc_framebuffer_size(struct drm_device *dev,
 				    struct drm_file *file,
 				    const struct drm_mode_fb_cmd2 *mode_cmd)
 {
-	int n_superblocks = 0;
 	const struct drm_format_info *info;
 	struct drm_gem_object *objs = NULL;
-	u32 afbc_superblock_size = 0, afbc_superblock_height = 0;
-	u32 afbc_superblock_width = 0, afbc_size = 0;
 	int bpp = 0;
 
-	switch (mode_cmd->modifier[0] & AFBC_SIZE_MASK) {
-	case AFBC_SIZE_16X16:
-		afbc_superblock_height = 16;
-		afbc_superblock_width = 16;
-		break;
-	default:
-		DRM_DEBUG_KMS("AFBC superblock size is not supported\n");
-		return false;
-	}
-
 	info = drm_get_format_info(dev, mode_cmd);
-
-	n_superblocks = (mode_cmd->width / afbc_superblock_width) *
-		(mode_cmd->height / afbc_superblock_height);
-
 	bpp = malidp_format_get_bpp(info->format);
 
-	afbc_superblock_size = (bpp * afbc_superblock_width * afbc_superblock_height)
-				/ BITS_PER_BYTE;
-
-	afbc_size = ALIGN(n_superblocks * AFBC_HEADER_SIZE, AFBC_SUPERBLK_ALIGNMENT);
-	afbc_size += n_superblocks * ALIGN(afbc_superblock_size, AFBC_SUPERBLK_ALIGNMENT);
-
-	if ((mode_cmd->width * bpp) != (mode_cmd->pitches[0] * BITS_PER_BYTE)) {
-		DRM_DEBUG_KMS("Invalid value of (pitch * BITS_PER_BYTE) (=%u) "
-			      "should be same as width (=%u) * bpp (=%u)\n",
-			      (mode_cmd->pitches[0] * BITS_PER_BYTE),
-			      mode_cmd->width, bpp);
-		return false;
-	}
-
 	objs = drm_gem_object_lookup(file, mode_cmd->handles[0]);
 	if (!objs) {
 		DRM_DEBUG_KMS("Failed to lookup GEM object\n");
 		return false;
 	}
 
-	if (objs->size < afbc_size) {
-		DRM_DEBUG_KMS("buffer size (%zu) too small for AFBC buffer size = %u\n",
-			      objs->size, afbc_size);
+	if (!drm_afbc_check_fb_size(dev, mode_cmd, objs, bpp)) {
 		drm_gem_object_put_unlocked(objs);
 		return false;
 	}
diff --git a/drivers/gpu/drm/drm_afbc.c b/drivers/gpu/drm/drm_afbc.c
new file mode 100644
index 000000000000..3e8a9225fd2e
--- /dev/null
+++ b/drivers/gpu/drm/drm_afbc.c
@@ -0,0 +1,114 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * (C) 2019 Collabora Ltd.
+ *
+ * author: Andrzej Pietrasiewicz <andrzej.p@collabora.com>
+ *
+ */
+#include <linux/module.h>
+
+#include <drm/drm_afbc.h>
+#include <drm/drm_device.h>
+#include <drm/drm_fourcc.h>
+#include <drm/drm_gem.h>
+#include <drm/drm_mode.h>
+#include <drm/drm_print.h>
+
+#define AFBC_HEADER_SIZE		16
+#define AFBC_SUPERBLK_ALIGNMENT		128
+
+bool drm_afbc_check_offset(struct drm_device *dev,
+			   const struct drm_mode_fb_cmd2 *mode_cmd)
+{
+	if (mode_cmd->offsets[0] != 0) {
+		DRM_DEBUG_KMS("AFBC buffers' plane offset should be 0\n");
+		return false;
+	}
+
+	return true;
+}
+EXPORT_SYMBOL_GPL(drm_afbc_check_offset);
+
+bool drm_afbc_check_size_align(struct drm_device *dev,
+			       const struct drm_mode_fb_cmd2 *mode_cmd)
+{
+
+	switch (mode_cmd->modifier[0] & AFBC_FORMAT_MOD_BLOCK_SIZE_MASK) {
+	case AFBC_FORMAT_MOD_BLOCK_SIZE_16x16:
+		if ((mode_cmd->width % 16) || (mode_cmd->height % 16)) {
+			DRM_DEBUG_KMS(
+				"AFBC buffer must be aligned to 16 pixels\n"
+			);
+			return false;
+		}
+		break;
+	case AFBC_FORMAT_MOD_BLOCK_SIZE_32x8:
+		/* fall through */
+	case AFBC_FORMAT_MOD_BLOCK_SIZE_64x4:
+		/* fall through */
+	case AFBC_FORMAT_MOD_BLOCK_SIZE_32x8_64x4:
+		/* fall through */
+	default:
+		DRM_DEBUG_KMS("Unsupported AFBC block size\n");
+		return false;
+	}
+
+	return true;
+}
+EXPORT_SYMBOL_GPL(drm_afbc_check_size_align);
+
+bool drm_afbc_check_fb_size(struct drm_device *dev,
+			    const struct drm_mode_fb_cmd2 *mode_cmd,
+			    struct drm_gem_object *objs, int bpp)
+{
+	int n_superblocks = 0;
+	u32 afbc_superblock_size = 0, afbc_superblock_height = 0;
+	u32 afbc_superblock_width = 0, afbc_size = 0;
+
+	switch (mode_cmd->modifier[0] & AFBC_FORMAT_MOD_BLOCK_SIZE_MASK) {
+	case AFBC_FORMAT_MOD_BLOCK_SIZE_16x16:
+		afbc_superblock_height = 16;
+		afbc_superblock_width = 16;
+		break;
+	case AFBC_FORMAT_MOD_BLOCK_SIZE_32x8:
+		/* fall through */
+	case AFBC_FORMAT_MOD_BLOCK_SIZE_64x4:
+		/* fall through */
+	case AFBC_FORMAT_MOD_BLOCK_SIZE_32x8_64x4:
+		/* fall through */
+	default:
+		DRM_DEBUG_KMS("AFBC superblock size is not supported\n");
+		return false;
+	}
+
+	n_superblocks = (mode_cmd->width / afbc_superblock_width) *
+		(mode_cmd->height / afbc_superblock_height);
+
+	afbc_superblock_size =
+		(bpp * afbc_superblock_width * afbc_superblock_height)
+			/ BITS_PER_BYTE;
+
+	afbc_size = ALIGN(n_superblocks * AFBC_HEADER_SIZE,
+			  AFBC_SUPERBLK_ALIGNMENT);
+	afbc_size += n_superblocks *
+		ALIGN(afbc_superblock_size, AFBC_SUPERBLK_ALIGNMENT);
+
+	if ((mode_cmd->width * bpp) != (mode_cmd->pitches[0] * BITS_PER_BYTE)) {
+		DRM_DEBUG_KMS("Invalid value of (pitch * BITS_PER_BYTE) (=%u) should be same as width (=%u) * bpp (=%u)\n",
+			mode_cmd->pitches[0] * BITS_PER_BYTE,
+			mode_cmd->width, bpp
+		);
+		return false;
+	}
+
+	if (objs->size < afbc_size) {
+		DRM_DEBUG_KMS("buffer size (%zu) too small for AFBC buffer size = %u\n",
+			objs->size, afbc_size
+		);
+
+		return false;
+	}
+
+	return true;
+}
+EXPORT_SYMBOL(drm_afbc_check_fb_size);
diff --git a/include/drm/drm_afbc.h b/include/drm/drm_afbc.h
new file mode 100644
index 000000000000..ce39c850217b
--- /dev/null
+++ b/include/drm/drm_afbc.h
@@ -0,0 +1,25 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * (C) 2019 Collabora Ltd.
+ *
+ * author: Andrzej Pietrasiewicz <andrzej.p@collabora.com>
+ *
+ */
+#ifndef __DRM_AFBC_H__
+#define __DRM_AFBC_H__
+
+struct drm_device;
+struct drm_mode_fb_cmd2;
+struct drm_gem_object;
+
+bool drm_afbc_check_offset(struct drm_device *dev,
+			   const struct drm_mode_fb_cmd2 *mode_cmd);
+
+bool drm_afbc_check_size_align(struct drm_device *dev,
+			       const struct drm_mode_fb_cmd2 *mode_cmd);
+
+bool drm_afbc_check_fb_size(struct drm_device *dev,
+			    const struct drm_mode_fb_cmd2 *mode_cmd,
+			    struct drm_gem_object *objs, int bpp);
+
+#endif /* __DRM_AFBC_H__ */
-- 
2.17.1


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply related	[flat|nested] 63+ messages in thread

* [PATCH 2/2] drm/rockchip: Add support for afbc
  2019-10-11 11:18 ` Andrzej Pietrasiewicz
@ 2019-10-11 11:18   ` Andrzej Pietrasiewicz
  -1 siblings, 0 replies; 63+ messages in thread
From: Andrzej Pietrasiewicz @ 2019-10-11 11:18 UTC (permalink / raw)
  To: dri-devel
  Cc: Sandy Huang, kernel, Andrzej Pietrasiewicz, Maarten Lankhorst,
	Maxime Ripard, Sean Paul, David Airlie, Daniel Vetter,
	Liviu Dudau, Brian Starkey, Heiko Stübner, linux-kernel,
	linux-arm-kernel, linux-rockchip

This patch adds support for afbc handling. afbc is a compressed format
which reduces the necessary memory bandwidth.

Co-developed-by: Mark Yao <mark.yao@rock-chips.com>
Signed-off-by: Mark Yao <mark.yao@rock-chips.com>
Signed-off-by: Andrzej Pietrasiewicz <andrzej.p@collabora.com>
---
 drivers/gpu/drm/rockchip/Kconfig            |   1 +
 drivers/gpu/drm/rockchip/rockchip_drm_fb.c  |  43 ++++++
 drivers/gpu/drm/rockchip/rockchip_drm_vop.c | 140 +++++++++++++++++++-
 drivers/gpu/drm/rockchip/rockchip_drm_vop.h |  12 ++
 drivers/gpu/drm/rockchip/rockchip_vop_reg.c |  86 +++++++++++-
 5 files changed, 278 insertions(+), 4 deletions(-)

diff --git a/drivers/gpu/drm/rockchip/Kconfig b/drivers/gpu/drm/rockchip/Kconfig
index 6f4222f8beeb..ff491efc52a5 100644
--- a/drivers/gpu/drm/rockchip/Kconfig
+++ b/drivers/gpu/drm/rockchip/Kconfig
@@ -5,6 +5,7 @@ config DRM_ROCKCHIP
 	select DRM_GEM_CMA_HELPER
 	select DRM_KMS_HELPER
 	select DRM_PANEL
+	select DRM_AFBC
 	select VIDEOMODE_HELPERS
 	select DRM_ANALOGIX_DP if ROCKCHIP_ANALOGIX_DP
 	select DRM_DW_HDMI if ROCKCHIP_DW_HDMI
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_fb.c b/drivers/gpu/drm/rockchip/rockchip_drm_fb.c
index 64ca87cf6d50..873185b3a721 100644
--- a/drivers/gpu/drm/rockchip/rockchip_drm_fb.c
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_fb.c
@@ -8,6 +8,7 @@
 #include <drm/drm.h>
 #include <drm/drmP.h>
 #include <drm/drm_atomic.h>
+#include <drm/drm_afbc.h>
 #include <drm/drm_damage_helper.h>
 #include <drm/drm_fb_helper.h>
 #include <drm/drm_gem_framebuffer_helper.h>
@@ -18,6 +19,8 @@
 #include "rockchip_drm_gem.h"
 #include "rockchip_drm_psr.h"
 
+#define ROCKCHIP_MAX_AFBC_WIDTH	2560
+
 static const struct drm_framebuffer_funcs rockchip_drm_fb_funcs = {
 	.destroy       = drm_gem_fb_destroy,
 	.create_handle = drm_gem_fb_create_handle,
@@ -32,6 +35,46 @@ rockchip_fb_alloc(struct drm_device *dev, const struct drm_mode_fb_cmd2 *mode_cm
 	int ret;
 	int i;
 
+	if (mode_cmd->modifier[0]) {
+		const struct drm_format_info *info;
+		int bpp;
+
+		if (mode_cmd->modifier[0] &
+			~DRM_FORMAT_MOD_ARM_AFBC(
+				AFBC_FORMAT_MOD_BLOCK_SIZE_16x16 |
+				AFBC_FORMAT_MOD_SPARSE
+			 )
+		) {
+			DRM_DEV_ERROR(dev->dev,
+				"Unsupported format modifer 0x%llx\n",
+				mode_cmd->modifier[0]
+			);
+
+			return ERR_PTR(-EINVAL);
+		}
+
+		if (!drm_afbc_check_offset(dev, mode_cmd))
+			return ERR_PTR(-EINVAL);
+
+		if (!drm_afbc_check_size_align(dev, mode_cmd))
+			return ERR_PTR(-EINVAL);
+
+		if (mode_cmd->width > ROCKCHIP_MAX_AFBC_WIDTH) {
+			DRM_DEV_ERROR(dev->dev,
+				"Unsupported width %d>%d\n",
+				mode_cmd->width,
+				ROCKCHIP_MAX_AFBC_WIDTH);
+
+			return ERR_PTR(-EINVAL);
+		}
+
+		info = drm_get_format_info(dev, mode_cmd);
+		bpp = info->cpp[0] * 8;
+
+		if (!drm_afbc_check_fb_size(dev, mode_cmd, obj[0], bpp))
+			return ERR_PTR(-EINVAL);
+	}
+
 	fb = kzalloc(sizeof(*fb), GFP_KERNEL);
 	if (!fb)
 		return ERR_PTR(-ENOMEM);
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c
index 21b68eea46cc..0ac9ab3be3f1 100644
--- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c
@@ -90,9 +90,20 @@
 #define VOP_WIN_TO_INDEX(vop_win) \
 	((vop_win) - (vop_win)->vop->win)
 
+#define VOP_AFBC_SET(vop, name, v) \
+	do { \
+		if ((vop)->data->afbc) \
+			vop_reg_set((vop), &(vop)->data->afbc->name, \
+				0, ~0, v, #name); \
+	} while (0)
+
 #define to_vop(x) container_of(x, struct vop, crtc)
 #define to_vop_win(x) container_of(x, struct vop_win, base)
 
+#define AFBC_FMT_RGB565		0x0
+#define AFBC_FMT_U8U8U8U8	0x5
+#define AFBC_FMT_U8U8U8		0x4
+
 /*
  * The coefficients of the following matrix are all fixed points.
  * The format is S2.10 for the 3x3 part of the matrix, and S9.12 for the offsets.
@@ -163,6 +174,7 @@ struct vop {
 	/* optional internal rgb encoder */
 	struct rockchip_rgb *rgb;
 
+	struct vop_win *afbc_win;
 	struct vop_win win[];
 };
 
@@ -271,6 +283,27 @@ static enum vop_data_format vop_convert_format(uint32_t format)
 	}
 }
 
+static int vop_convert_afbc_format(uint32_t format)
+{
+	switch (format) {
+	case DRM_FORMAT_XRGB8888:
+	case DRM_FORMAT_ARGB8888:
+	case DRM_FORMAT_XBGR8888:
+	case DRM_FORMAT_ABGR8888:
+		return AFBC_FMT_U8U8U8U8;
+	case DRM_FORMAT_RGB888:
+	case DRM_FORMAT_BGR888:
+		return AFBC_FMT_U8U8U8;
+	case DRM_FORMAT_RGB565:
+	case DRM_FORMAT_BGR565:
+		return AFBC_FMT_RGB565;
+	default:
+		DRM_ERROR("unsupported afbc format[%08x]\n", format);
+	}
+
+	return -EINVAL;
+}
+
 static uint16_t scl_vop_cal_scale(enum scale_mode mode, uint32_t src,
 				  uint32_t dst, bool is_horizontal,
 				  int vsu_mode, int *vskiplines)
@@ -587,6 +620,15 @@ static int vop_enable(struct drm_crtc *crtc)
 
 		vop_win_disable(vop, win);
 	}
+
+	if (vop->data->afbc) {
+		/*
+		 * Disable AFBC and forget there was a vop window with AFBC
+		 */
+		VOP_AFBC_SET(vop, enable, 0);
+		vop->afbc_win = NULL;
+	}
+
 	spin_unlock(&vop->reg_lock);
 
 	vop_cfg_done(vop);
@@ -671,6 +713,36 @@ static void vop_plane_destroy(struct drm_plane *plane)
 	drm_plane_cleanup(plane);
 }
 
+static bool rockchip_mod_supported(struct drm_plane *plane,
+				   u32 format, u64 modifier)
+{
+	const struct drm_format_info *info;
+
+	if (WARN_ON(modifier == DRM_FORMAT_MOD_INVALID))
+		return false;
+
+	if (modifier == DRM_FORMAT_MOD_LINEAR)
+		return true;
+
+	if (modifier & ~DRM_FORMAT_MOD_ARM_AFBC(
+				AFBC_FORMAT_MOD_BLOCK_SIZE_16x16 |
+				AFBC_FORMAT_MOD_SPARSE
+			)
+	) {
+		DRM_DEBUG_KMS("Unsupported format modifer 0x%llx\n", modifier);
+
+		return false;
+	}
+
+	info = drm_format_info(format);
+	if (info->num_planes != 1) {
+		DRM_DEBUG_KMS("AFBC buffers expect one plane\n");
+		return false;
+	}
+
+	return true;
+}
+
 static int vop_plane_atomic_check(struct drm_plane *plane,
 			   struct drm_plane_state *state)
 {
@@ -719,6 +791,33 @@ static int vop_plane_atomic_check(struct drm_plane *plane,
 		return -EINVAL;
 	}
 
+	if (fb->modifier == DRM_FORMAT_MOD_ARM_AFBC(
+		AFBC_FORMAT_MOD_BLOCK_SIZE_16x16 | AFBC_FORMAT_MOD_SPARSE)) {
+		struct vop *vop = to_vop(crtc);
+
+		if (!vop->data->afbc) {
+			DRM_ERROR("vop does not support AFBC\n");
+			return -EINVAL;
+		}
+
+		ret = vop_convert_afbc_format(fb->format->format);
+		if (ret < 0)
+			return ret;
+
+		if (state->src.x1 || state->src.y1) {
+			DRM_ERROR("afbc does not support offset display\n");
+			DRM_ERROR("xpos=%d, ypos=%d, offset=%d\n",
+				  state->src.x1, state->src.y1, fb->offsets[0]);
+			return -EINVAL;
+		}
+
+		if (state->rotation && state->rotation != DRM_MODE_ROTATE_0) {
+			DRM_ERROR("afbc does not support rotation\n");
+			DRM_ERROR("rotation=%d\n", state->rotation);
+			return -EINVAL;
+		}
+	}
+
 	return 0;
 }
 
@@ -735,6 +834,11 @@ static void vop_plane_atomic_disable(struct drm_plane *plane,
 	spin_lock(&vop->reg_lock);
 
 	vop_win_disable(vop, win);
+	/*
+	 * Forget about the AFBC window if it is being disabled
+	 */
+	if (vop_win == vop->afbc_win)
+		vop->afbc_win = NULL;
 
 	spin_unlock(&vop->reg_lock);
 }
@@ -774,6 +878,13 @@ static void vop_plane_atomic_update(struct drm_plane *plane,
 	if (WARN_ON(!vop->is_enabled))
 		return;
 
+	/*
+	 * If updating the AFBC window then assume that
+	 * after the update there will be no AFBC window.
+	 */
+	if (vop_win == vop->afbc_win)
+		vop->afbc_win = NULL;
+
 	if (!state->visible) {
 		vop_plane_atomic_disable(plane, old_state);
 		return;
@@ -808,6 +919,24 @@ static void vop_plane_atomic_update(struct drm_plane *plane,
 
 	spin_lock(&vop->reg_lock);
 
+	if (fb->modifier == DRM_FORMAT_MOD_ARM_AFBC(
+		AFBC_FORMAT_MOD_BLOCK_SIZE_16x16 | AFBC_FORMAT_MOD_SPARSE)) {
+		int afbc_format = vop_convert_afbc_format(fb->format->format);
+
+		VOP_AFBC_SET(vop, format, afbc_format | 1 << 4);
+		VOP_AFBC_SET(vop, hreg_block_split, 0);
+		VOP_AFBC_SET(vop, win_sel, VOP_WIN_TO_INDEX(vop_win));
+		VOP_AFBC_SET(vop, hdr_ptr, dma_addr);
+		VOP_AFBC_SET(vop, pic_size, act_info);
+
+		/*
+		 * The window being udated becomes the AFBC window
+		 */
+		vop->afbc_win = vop_win;
+
+		pr_info("AFBC on plane %s\n", plane->name);
+	}
+
 	VOP_WIN_SET(vop, win, format, format);
 	VOP_WIN_SET(vop, win, yrgb_vir, DIV_ROUND_UP(fb->pitches[0], 4));
 	VOP_WIN_SET(vop, win, yrgb_mst, dma_addr);
@@ -964,6 +1093,7 @@ static const struct drm_plane_funcs vop_plane_funcs = {
 	.reset = drm_atomic_helper_plane_reset,
 	.atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state,
 	.atomic_destroy_state = drm_atomic_helper_plane_destroy_state,
+	.format_mod_supported = rockchip_mod_supported,
 };
 
 static int vop_crtc_enable_vblank(struct drm_crtc *crtc)
@@ -1163,6 +1293,10 @@ static void vop_crtc_atomic_flush(struct drm_crtc *crtc,
 
 	spin_lock(&vop->reg_lock);
 
+	/*
+	 * Enable AFBC if there is some AFBC window, disable otherwise
+	 */
+	VOP_AFBC_SET(vop, enable, vop->afbc_win != NULL);
 	vop_cfg_done(vop);
 
 	spin_unlock(&vop->reg_lock);
@@ -1471,7 +1605,8 @@ static int vop_create_crtc(struct vop *vop)
 					       0, &vop_plane_funcs,
 					       win_data->phy->data_formats,
 					       win_data->phy->nformats,
-					       NULL, win_data->type, NULL);
+					       win_data->phy->format_modifiers,
+					       win_data->type, NULL);
 		if (ret) {
 			DRM_DEV_ERROR(vop->dev, "failed to init plane %d\n",
 				      ret);
@@ -1511,7 +1646,8 @@ static int vop_create_crtc(struct vop *vop)
 					       &vop_plane_funcs,
 					       win_data->phy->data_formats,
 					       win_data->phy->nformats,
-					       NULL, win_data->type, NULL);
+					       win_data->phy->format_modifiers,
+					       win_data->type, NULL);
 		if (ret) {
 			DRM_DEV_ERROR(vop->dev, "failed to init overlay %d\n",
 				      ret);
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.h b/drivers/gpu/drm/rockchip/rockchip_drm_vop.h
index 2149a889c29d..371b28b933a9 100644
--- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.h
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.h
@@ -34,6 +34,16 @@ struct vop_reg {
 	bool relaxed;
 };
 
+struct vop_afbc {
+	struct vop_reg enable;
+	struct vop_reg win_sel;
+	struct vop_reg format;
+	struct vop_reg hreg_block_split;
+	struct vop_reg pic_size;
+	struct vop_reg hdr_ptr;
+	struct vop_reg rstn;
+};
+
 struct vop_modeset {
 	struct vop_reg htotal_pw;
 	struct vop_reg hact_st_end;
@@ -128,6 +138,7 @@ struct vop_win_phy {
 	const struct vop_scl_regs *scl;
 	const uint32_t *data_formats;
 	uint32_t nformats;
+	const uint64_t *format_modifiers;
 
 	struct vop_reg enable;
 	struct vop_reg gate;
@@ -167,6 +178,7 @@ struct vop_data {
 	const struct vop_misc *misc;
 	const struct vop_modeset *modeset;
 	const struct vop_output *output;
+	const struct vop_afbc *afbc;
 	const struct vop_win_yuv2yuv_data *win_yuv2yuv;
 	const struct vop_win_data *win;
 	unsigned int win_size;
diff --git a/drivers/gpu/drm/rockchip/rockchip_vop_reg.c b/drivers/gpu/drm/rockchip/rockchip_vop_reg.c
index 7b9c74750f6d..a3981f037c90 100644
--- a/drivers/gpu/drm/rockchip/rockchip_vop_reg.c
+++ b/drivers/gpu/drm/rockchip/rockchip_vop_reg.c
@@ -44,6 +44,20 @@ static const uint32_t formats_win_full[] = {
 	DRM_FORMAT_NV24,
 };
 
+static const uint64_t format_modifiers_win_full[] = {
+	DRM_FORMAT_MOD_NONE,
+	DRM_FORMAT_MOD_INVALID,
+};
+
+static const uint64_t format_modifiers_win_full_afbc[] = {
+	DRM_FORMAT_MOD_ARM_AFBC(
+		AFBC_FORMAT_MOD_BLOCK_SIZE_16x16 |
+		AFBC_FORMAT_MOD_SPARSE
+	),
+	DRM_FORMAT_MOD_LINEAR,
+	DRM_FORMAT_MOD_INVALID,
+};
+
 static const uint32_t formats_win_lite[] = {
 	DRM_FORMAT_XRGB8888,
 	DRM_FORMAT_ARGB8888,
@@ -55,6 +69,11 @@ static const uint32_t formats_win_lite[] = {
 	DRM_FORMAT_BGR565,
 };
 
+static const uint64_t format_modifiers_win_lite[] = {
+	DRM_FORMAT_MOD_LINEAR,
+	DRM_FORMAT_MOD_INVALID,
+};
+
 static const struct vop_scl_regs rk3036_win_scl = {
 	.scale_yrgb_x = VOP_REG(RK3036_WIN0_SCL_FACTOR_YRGB, 0xffff, 0x0),
 	.scale_yrgb_y = VOP_REG(RK3036_WIN0_SCL_FACTOR_YRGB, 0xffff, 16),
@@ -66,6 +85,7 @@ static const struct vop_win_phy rk3036_win0_data = {
 	.scl = &rk3036_win_scl,
 	.data_formats = formats_win_full,
 	.nformats = ARRAY_SIZE(formats_win_full),
+	.format_modifiers = format_modifiers_win_full,
 	.enable = VOP_REG(RK3036_SYS_CTRL, 0x1, 0),
 	.format = VOP_REG(RK3036_SYS_CTRL, 0x7, 3),
 	.rb_swap = VOP_REG(RK3036_SYS_CTRL, 0x1, 15),
@@ -81,6 +101,7 @@ static const struct vop_win_phy rk3036_win0_data = {
 static const struct vop_win_phy rk3036_win1_data = {
 	.data_formats = formats_win_lite,
 	.nformats = ARRAY_SIZE(formats_win_lite),
+	.format_modifiers = format_modifiers_win_lite,
 	.enable = VOP_REG(RK3036_SYS_CTRL, 0x1, 1),
 	.format = VOP_REG(RK3036_SYS_CTRL, 0x7, 6),
 	.rb_swap = VOP_REG(RK3036_SYS_CTRL, 0x1, 19),
@@ -147,6 +168,7 @@ static const struct vop_data rk3036_vop = {
 static const struct vop_win_phy rk3126_win1_data = {
 	.data_formats = formats_win_lite,
 	.nformats = ARRAY_SIZE(formats_win_lite),
+	.format_modifiers = format_modifiers_win_lite,
 	.enable = VOP_REG(RK3036_SYS_CTRL, 0x1, 1),
 	.format = VOP_REG(RK3036_SYS_CTRL, 0x7, 6),
 	.rb_swap = VOP_REG(RK3036_SYS_CTRL, 0x1, 19),
@@ -226,6 +248,7 @@ static const struct vop_win_phy px30_win0_data = {
 	.scl = &px30_win_scl,
 	.data_formats = formats_win_full,
 	.nformats = ARRAY_SIZE(formats_win_full),
+	.format_modifiers = format_modifiers_win_full,
 	.enable = VOP_REG(PX30_WIN0_CTRL0, 0x1, 0),
 	.format = VOP_REG(PX30_WIN0_CTRL0, 0x7, 1),
 	.rb_swap = VOP_REG(PX30_WIN0_CTRL0, 0x1, 12),
@@ -241,6 +264,7 @@ static const struct vop_win_phy px30_win0_data = {
 static const struct vop_win_phy px30_win1_data = {
 	.data_formats = formats_win_lite,
 	.nformats = ARRAY_SIZE(formats_win_lite),
+	.format_modifiers = format_modifiers_win_lite,
 	.enable = VOP_REG(PX30_WIN1_CTRL0, 0x1, 0),
 	.format = VOP_REG(PX30_WIN1_CTRL0, 0x7, 4),
 	.rb_swap = VOP_REG(PX30_WIN1_CTRL0, 0x1, 12),
@@ -253,6 +277,7 @@ static const struct vop_win_phy px30_win1_data = {
 static const struct vop_win_phy px30_win2_data = {
 	.data_formats = formats_win_lite,
 	.nformats = ARRAY_SIZE(formats_win_lite),
+	.format_modifiers = format_modifiers_win_lite,
 	.gate = VOP_REG(PX30_WIN2_CTRL0, 0x1, 4),
 	.enable = VOP_REG(PX30_WIN2_CTRL0, 0x1, 0),
 	.format = VOP_REG(PX30_WIN2_CTRL0, 0x3, 5),
@@ -308,6 +333,7 @@ static const struct vop_win_phy rk3066_win0_data = {
 	.scl = &rk3066_win_scl,
 	.data_formats = formats_win_full,
 	.nformats = ARRAY_SIZE(formats_win_full),
+	.format_modifiers = format_modifiers_win_full,
 	.enable = VOP_REG(RK3066_SYS_CTRL1, 0x1, 0),
 	.format = VOP_REG(RK3066_SYS_CTRL0, 0x7, 4),
 	.rb_swap = VOP_REG(RK3066_SYS_CTRL0, 0x1, 19),
@@ -324,6 +350,7 @@ static const struct vop_win_phy rk3066_win1_data = {
 	.scl = &rk3066_win_scl,
 	.data_formats = formats_win_full,
 	.nformats = ARRAY_SIZE(formats_win_full),
+	.format_modifiers = format_modifiers_win_full,
 	.enable = VOP_REG(RK3066_SYS_CTRL1, 0x1, 1),
 	.format = VOP_REG(RK3066_SYS_CTRL0, 0x7, 7),
 	.rb_swap = VOP_REG(RK3066_SYS_CTRL0, 0x1, 23),
@@ -339,6 +366,7 @@ static const struct vop_win_phy rk3066_win1_data = {
 static const struct vop_win_phy rk3066_win2_data = {
 	.data_formats = formats_win_lite,
 	.nformats = ARRAY_SIZE(formats_win_lite),
+	.format_modifiers = format_modifiers_win_lite,
 	.enable = VOP_REG(RK3066_SYS_CTRL1, 0x1, 2),
 	.format = VOP_REG(RK3066_SYS_CTRL0, 0x7, 10),
 	.rb_swap = VOP_REG(RK3066_SYS_CTRL0, 0x1, 27),
@@ -418,6 +446,7 @@ static const struct vop_win_phy rk3188_win0_data = {
 	.scl = &rk3188_win_scl,
 	.data_formats = formats_win_full,
 	.nformats = ARRAY_SIZE(formats_win_full),
+	.format_modifiers = format_modifiers_win_full,
 	.enable = VOP_REG(RK3188_SYS_CTRL, 0x1, 0),
 	.format = VOP_REG(RK3188_SYS_CTRL, 0x7, 3),
 	.rb_swap = VOP_REG(RK3188_SYS_CTRL, 0x1, 15),
@@ -432,6 +461,7 @@ static const struct vop_win_phy rk3188_win0_data = {
 static const struct vop_win_phy rk3188_win1_data = {
 	.data_formats = formats_win_lite,
 	.nformats = ARRAY_SIZE(formats_win_lite),
+	.format_modifiers = format_modifiers_win_lite,
 	.enable = VOP_REG(RK3188_SYS_CTRL, 0x1, 1),
 	.format = VOP_REG(RK3188_SYS_CTRL, 0x7, 6),
 	.rb_swap = VOP_REG(RK3188_SYS_CTRL, 0x1, 19),
@@ -537,6 +567,7 @@ static const struct vop_win_phy rk3288_win01_data = {
 	.scl = &rk3288_win_full_scl,
 	.data_formats = formats_win_full,
 	.nformats = ARRAY_SIZE(formats_win_full),
+	.format_modifiers = format_modifiers_win_full,
 	.enable = VOP_REG(RK3288_WIN0_CTRL0, 0x1, 0),
 	.format = VOP_REG(RK3288_WIN0_CTRL0, 0x7, 1),
 	.rb_swap = VOP_REG(RK3288_WIN0_CTRL0, 0x1, 12),
@@ -555,6 +586,7 @@ static const struct vop_win_phy rk3288_win01_data = {
 static const struct vop_win_phy rk3288_win23_data = {
 	.data_formats = formats_win_lite,
 	.nformats = ARRAY_SIZE(formats_win_lite),
+	.format_modifiers = format_modifiers_win_lite,
 	.enable = VOP_REG(RK3288_WIN2_CTRL0, 0x1, 4),
 	.gate = VOP_REG(RK3288_WIN2_CTRL0, 0x1, 0),
 	.format = VOP_REG(RK3288_WIN2_CTRL0, 0x7, 1),
@@ -667,6 +699,7 @@ static const struct vop_win_phy rk3368_win01_data = {
 	.scl = &rk3288_win_full_scl,
 	.data_formats = formats_win_full,
 	.nformats = ARRAY_SIZE(formats_win_full),
+	.format_modifiers = format_modifiers_win_full,
 	.enable = VOP_REG(RK3368_WIN0_CTRL0, 0x1, 0),
 	.format = VOP_REG(RK3368_WIN0_CTRL0, 0x7, 1),
 	.rb_swap = VOP_REG(RK3368_WIN0_CTRL0, 0x1, 12),
@@ -687,6 +720,7 @@ static const struct vop_win_phy rk3368_win01_data = {
 static const struct vop_win_phy rk3368_win23_data = {
 	.data_formats = formats_win_lite,
 	.nformats = ARRAY_SIZE(formats_win_lite),
+	.format_modifiers = format_modifiers_win_lite,
 	.gate = VOP_REG(RK3368_WIN2_CTRL0, 0x1, 0),
 	.enable = VOP_REG(RK3368_WIN2_CTRL0, 0x1, 4),
 	.format = VOP_REG(RK3368_WIN2_CTRL0, 0x3, 5),
@@ -798,6 +832,53 @@ static const struct vop_win_yuv2yuv_data rk3399_vop_big_win_yuv2yuv_data[] = {
 	  .y2r_en = VOP_REG(RK3399_YUV2YUV_WIN, 0x1, 9) },
 	{ .base = 0xC0, .phy = &rk3399_yuv2yuv_win23_data },
 	{ .base = 0x120, .phy = &rk3399_yuv2yuv_win23_data },
+
+};
+
+static const struct vop_win_phy rk3399_win01_data = {
+	.scl = &rk3288_win_full_scl,
+	.data_formats = formats_win_full,
+	.nformats = ARRAY_SIZE(formats_win_full),
+	.format_modifiers = format_modifiers_win_full_afbc,
+	.enable = VOP_REG(RK3288_WIN0_CTRL0, 0x1, 0),
+	.format = VOP_REG(RK3288_WIN0_CTRL0, 0x7, 1),
+	.rb_swap = VOP_REG(RK3288_WIN0_CTRL0, 0x1, 12),
+	.y_mir_en = VOP_REG(RK3288_WIN0_CTRL0, 0x1, 22),
+	.act_info = VOP_REG(RK3288_WIN0_ACT_INFO, 0x1fff1fff, 0),
+	.dsp_info = VOP_REG(RK3288_WIN0_DSP_INFO, 0x0fff0fff, 0),
+	.dsp_st = VOP_REG(RK3288_WIN0_DSP_ST, 0x1fff1fff, 0),
+	.yrgb_mst = VOP_REG(RK3288_WIN0_YRGB_MST, 0xffffffff, 0),
+	.uv_mst = VOP_REG(RK3288_WIN0_CBR_MST, 0xffffffff, 0),
+	.yrgb_vir = VOP_REG(RK3288_WIN0_VIR, 0x3fff, 0),
+	.uv_vir = VOP_REG(RK3288_WIN0_VIR, 0x3fff, 16),
+	.src_alpha_ctl = VOP_REG(RK3288_WIN0_SRC_ALPHA_CTRL, 0xff, 0),
+	.dst_alpha_ctl = VOP_REG(RK3288_WIN0_DST_ALPHA_CTRL, 0xff, 0),
+};
+
+/*
+ * rk3399 vop big windows register layout is same as rk3288, but we
+ * have a separate rk3399 win data array here so that we can advertise
+ * AFBC on the primary plane.
+ */
+static const struct vop_win_data rk3399_vop_win_data[] = {
+	{ .base = 0x00, .phy = &rk3399_win01_data,
+	  .type = DRM_PLANE_TYPE_PRIMARY },
+	{ .base = 0x40, .phy = &rk3288_win01_data,
+	  .type = DRM_PLANE_TYPE_OVERLAY },
+	{ .base = 0x00, .phy = &rk3288_win23_data,
+	  .type = DRM_PLANE_TYPE_OVERLAY },
+	{ .base = 0x50, .phy = &rk3288_win23_data,
+	  .type = DRM_PLANE_TYPE_CURSOR },
+};
+
+static const struct vop_afbc rk3399_vop_afbc = {
+	.rstn = VOP_REG(RK3399_AFBCD0_CTRL, 0x1, 3),
+	.enable = VOP_REG(RK3399_AFBCD0_CTRL, 0x1, 0),
+	.win_sel = VOP_REG(RK3399_AFBCD0_CTRL, 0x3, 1),
+	.format = VOP_REG(RK3399_AFBCD0_CTRL, 0x1f, 16),
+	.hreg_block_split = VOP_REG(RK3399_AFBCD0_CTRL, 0x1, 21),
+	.hdr_ptr = VOP_REG(RK3399_AFBCD0_HDR_PTR, 0xffffffff, 0),
+	.pic_size = VOP_REG(RK3399_AFBCD0_PIC_SIZE, 0xffffffff, 0),
 };
 
 static const struct vop_data rk3399_vop_big = {
@@ -807,9 +888,10 @@ static const struct vop_data rk3399_vop_big = {
 	.common = &rk3288_common,
 	.modeset = &rk3288_modeset,
 	.output = &rk3399_output,
+	.afbc = &rk3399_vop_afbc,
 	.misc = &rk3368_misc,
-	.win = rk3368_vop_win_data,
-	.win_size = ARRAY_SIZE(rk3368_vop_win_data),
+	.win = rk3399_vop_win_data,
+	.win_size = ARRAY_SIZE(rk3399_vop_win_data),
 	.win_yuv2yuv = rk3399_vop_big_win_yuv2yuv_data,
 };
 
-- 
2.17.1


^ permalink raw reply related	[flat|nested] 63+ messages in thread

* [PATCH 2/2] drm/rockchip: Add support for afbc
@ 2019-10-11 11:18   ` Andrzej Pietrasiewicz
  0 siblings, 0 replies; 63+ messages in thread
From: Andrzej Pietrasiewicz @ 2019-10-11 11:18 UTC (permalink / raw)
  To: dri-devel
  Cc: Heiko Stübner, David Airlie, Liviu Dudau, Maarten Lankhorst,
	Sandy Huang, Maxime Ripard, Andrzej Pietrasiewicz,
	linux-rockchip, linux-arm-kernel, Daniel Vetter, kernel,
	Sean Paul, Brian Starkey, linux-kernel

This patch adds support for afbc handling. afbc is a compressed format
which reduces the necessary memory bandwidth.

Co-developed-by: Mark Yao <mark.yao@rock-chips.com>
Signed-off-by: Mark Yao <mark.yao@rock-chips.com>
Signed-off-by: Andrzej Pietrasiewicz <andrzej.p@collabora.com>
---
 drivers/gpu/drm/rockchip/Kconfig            |   1 +
 drivers/gpu/drm/rockchip/rockchip_drm_fb.c  |  43 ++++++
 drivers/gpu/drm/rockchip/rockchip_drm_vop.c | 140 +++++++++++++++++++-
 drivers/gpu/drm/rockchip/rockchip_drm_vop.h |  12 ++
 drivers/gpu/drm/rockchip/rockchip_vop_reg.c |  86 +++++++++++-
 5 files changed, 278 insertions(+), 4 deletions(-)

diff --git a/drivers/gpu/drm/rockchip/Kconfig b/drivers/gpu/drm/rockchip/Kconfig
index 6f4222f8beeb..ff491efc52a5 100644
--- a/drivers/gpu/drm/rockchip/Kconfig
+++ b/drivers/gpu/drm/rockchip/Kconfig
@@ -5,6 +5,7 @@ config DRM_ROCKCHIP
 	select DRM_GEM_CMA_HELPER
 	select DRM_KMS_HELPER
 	select DRM_PANEL
+	select DRM_AFBC
 	select VIDEOMODE_HELPERS
 	select DRM_ANALOGIX_DP if ROCKCHIP_ANALOGIX_DP
 	select DRM_DW_HDMI if ROCKCHIP_DW_HDMI
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_fb.c b/drivers/gpu/drm/rockchip/rockchip_drm_fb.c
index 64ca87cf6d50..873185b3a721 100644
--- a/drivers/gpu/drm/rockchip/rockchip_drm_fb.c
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_fb.c
@@ -8,6 +8,7 @@
 #include <drm/drm.h>
 #include <drm/drmP.h>
 #include <drm/drm_atomic.h>
+#include <drm/drm_afbc.h>
 #include <drm/drm_damage_helper.h>
 #include <drm/drm_fb_helper.h>
 #include <drm/drm_gem_framebuffer_helper.h>
@@ -18,6 +19,8 @@
 #include "rockchip_drm_gem.h"
 #include "rockchip_drm_psr.h"
 
+#define ROCKCHIP_MAX_AFBC_WIDTH	2560
+
 static const struct drm_framebuffer_funcs rockchip_drm_fb_funcs = {
 	.destroy       = drm_gem_fb_destroy,
 	.create_handle = drm_gem_fb_create_handle,
@@ -32,6 +35,46 @@ rockchip_fb_alloc(struct drm_device *dev, const struct drm_mode_fb_cmd2 *mode_cm
 	int ret;
 	int i;
 
+	if (mode_cmd->modifier[0]) {
+		const struct drm_format_info *info;
+		int bpp;
+
+		if (mode_cmd->modifier[0] &
+			~DRM_FORMAT_MOD_ARM_AFBC(
+				AFBC_FORMAT_MOD_BLOCK_SIZE_16x16 |
+				AFBC_FORMAT_MOD_SPARSE
+			 )
+		) {
+			DRM_DEV_ERROR(dev->dev,
+				"Unsupported format modifer 0x%llx\n",
+				mode_cmd->modifier[0]
+			);
+
+			return ERR_PTR(-EINVAL);
+		}
+
+		if (!drm_afbc_check_offset(dev, mode_cmd))
+			return ERR_PTR(-EINVAL);
+
+		if (!drm_afbc_check_size_align(dev, mode_cmd))
+			return ERR_PTR(-EINVAL);
+
+		if (mode_cmd->width > ROCKCHIP_MAX_AFBC_WIDTH) {
+			DRM_DEV_ERROR(dev->dev,
+				"Unsupported width %d>%d\n",
+				mode_cmd->width,
+				ROCKCHIP_MAX_AFBC_WIDTH);
+
+			return ERR_PTR(-EINVAL);
+		}
+
+		info = drm_get_format_info(dev, mode_cmd);
+		bpp = info->cpp[0] * 8;
+
+		if (!drm_afbc_check_fb_size(dev, mode_cmd, obj[0], bpp))
+			return ERR_PTR(-EINVAL);
+	}
+
 	fb = kzalloc(sizeof(*fb), GFP_KERNEL);
 	if (!fb)
 		return ERR_PTR(-ENOMEM);
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c
index 21b68eea46cc..0ac9ab3be3f1 100644
--- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c
@@ -90,9 +90,20 @@
 #define VOP_WIN_TO_INDEX(vop_win) \
 	((vop_win) - (vop_win)->vop->win)
 
+#define VOP_AFBC_SET(vop, name, v) \
+	do { \
+		if ((vop)->data->afbc) \
+			vop_reg_set((vop), &(vop)->data->afbc->name, \
+				0, ~0, v, #name); \
+	} while (0)
+
 #define to_vop(x) container_of(x, struct vop, crtc)
 #define to_vop_win(x) container_of(x, struct vop_win, base)
 
+#define AFBC_FMT_RGB565		0x0
+#define AFBC_FMT_U8U8U8U8	0x5
+#define AFBC_FMT_U8U8U8		0x4
+
 /*
  * The coefficients of the following matrix are all fixed points.
  * The format is S2.10 for the 3x3 part of the matrix, and S9.12 for the offsets.
@@ -163,6 +174,7 @@ struct vop {
 	/* optional internal rgb encoder */
 	struct rockchip_rgb *rgb;
 
+	struct vop_win *afbc_win;
 	struct vop_win win[];
 };
 
@@ -271,6 +283,27 @@ static enum vop_data_format vop_convert_format(uint32_t format)
 	}
 }
 
+static int vop_convert_afbc_format(uint32_t format)
+{
+	switch (format) {
+	case DRM_FORMAT_XRGB8888:
+	case DRM_FORMAT_ARGB8888:
+	case DRM_FORMAT_XBGR8888:
+	case DRM_FORMAT_ABGR8888:
+		return AFBC_FMT_U8U8U8U8;
+	case DRM_FORMAT_RGB888:
+	case DRM_FORMAT_BGR888:
+		return AFBC_FMT_U8U8U8;
+	case DRM_FORMAT_RGB565:
+	case DRM_FORMAT_BGR565:
+		return AFBC_FMT_RGB565;
+	default:
+		DRM_ERROR("unsupported afbc format[%08x]\n", format);
+	}
+
+	return -EINVAL;
+}
+
 static uint16_t scl_vop_cal_scale(enum scale_mode mode, uint32_t src,
 				  uint32_t dst, bool is_horizontal,
 				  int vsu_mode, int *vskiplines)
@@ -587,6 +620,15 @@ static int vop_enable(struct drm_crtc *crtc)
 
 		vop_win_disable(vop, win);
 	}
+
+	if (vop->data->afbc) {
+		/*
+		 * Disable AFBC and forget there was a vop window with AFBC
+		 */
+		VOP_AFBC_SET(vop, enable, 0);
+		vop->afbc_win = NULL;
+	}
+
 	spin_unlock(&vop->reg_lock);
 
 	vop_cfg_done(vop);
@@ -671,6 +713,36 @@ static void vop_plane_destroy(struct drm_plane *plane)
 	drm_plane_cleanup(plane);
 }
 
+static bool rockchip_mod_supported(struct drm_plane *plane,
+				   u32 format, u64 modifier)
+{
+	const struct drm_format_info *info;
+
+	if (WARN_ON(modifier == DRM_FORMAT_MOD_INVALID))
+		return false;
+
+	if (modifier == DRM_FORMAT_MOD_LINEAR)
+		return true;
+
+	if (modifier & ~DRM_FORMAT_MOD_ARM_AFBC(
+				AFBC_FORMAT_MOD_BLOCK_SIZE_16x16 |
+				AFBC_FORMAT_MOD_SPARSE
+			)
+	) {
+		DRM_DEBUG_KMS("Unsupported format modifer 0x%llx\n", modifier);
+
+		return false;
+	}
+
+	info = drm_format_info(format);
+	if (info->num_planes != 1) {
+		DRM_DEBUG_KMS("AFBC buffers expect one plane\n");
+		return false;
+	}
+
+	return true;
+}
+
 static int vop_plane_atomic_check(struct drm_plane *plane,
 			   struct drm_plane_state *state)
 {
@@ -719,6 +791,33 @@ static int vop_plane_atomic_check(struct drm_plane *plane,
 		return -EINVAL;
 	}
 
+	if (fb->modifier == DRM_FORMAT_MOD_ARM_AFBC(
+		AFBC_FORMAT_MOD_BLOCK_SIZE_16x16 | AFBC_FORMAT_MOD_SPARSE)) {
+		struct vop *vop = to_vop(crtc);
+
+		if (!vop->data->afbc) {
+			DRM_ERROR("vop does not support AFBC\n");
+			return -EINVAL;
+		}
+
+		ret = vop_convert_afbc_format(fb->format->format);
+		if (ret < 0)
+			return ret;
+
+		if (state->src.x1 || state->src.y1) {
+			DRM_ERROR("afbc does not support offset display\n");
+			DRM_ERROR("xpos=%d, ypos=%d, offset=%d\n",
+				  state->src.x1, state->src.y1, fb->offsets[0]);
+			return -EINVAL;
+		}
+
+		if (state->rotation && state->rotation != DRM_MODE_ROTATE_0) {
+			DRM_ERROR("afbc does not support rotation\n");
+			DRM_ERROR("rotation=%d\n", state->rotation);
+			return -EINVAL;
+		}
+	}
+
 	return 0;
 }
 
@@ -735,6 +834,11 @@ static void vop_plane_atomic_disable(struct drm_plane *plane,
 	spin_lock(&vop->reg_lock);
 
 	vop_win_disable(vop, win);
+	/*
+	 * Forget about the AFBC window if it is being disabled
+	 */
+	if (vop_win == vop->afbc_win)
+		vop->afbc_win = NULL;
 
 	spin_unlock(&vop->reg_lock);
 }
@@ -774,6 +878,13 @@ static void vop_plane_atomic_update(struct drm_plane *plane,
 	if (WARN_ON(!vop->is_enabled))
 		return;
 
+	/*
+	 * If updating the AFBC window then assume that
+	 * after the update there will be no AFBC window.
+	 */
+	if (vop_win == vop->afbc_win)
+		vop->afbc_win = NULL;
+
 	if (!state->visible) {
 		vop_plane_atomic_disable(plane, old_state);
 		return;
@@ -808,6 +919,24 @@ static void vop_plane_atomic_update(struct drm_plane *plane,
 
 	spin_lock(&vop->reg_lock);
 
+	if (fb->modifier == DRM_FORMAT_MOD_ARM_AFBC(
+		AFBC_FORMAT_MOD_BLOCK_SIZE_16x16 | AFBC_FORMAT_MOD_SPARSE)) {
+		int afbc_format = vop_convert_afbc_format(fb->format->format);
+
+		VOP_AFBC_SET(vop, format, afbc_format | 1 << 4);
+		VOP_AFBC_SET(vop, hreg_block_split, 0);
+		VOP_AFBC_SET(vop, win_sel, VOP_WIN_TO_INDEX(vop_win));
+		VOP_AFBC_SET(vop, hdr_ptr, dma_addr);
+		VOP_AFBC_SET(vop, pic_size, act_info);
+
+		/*
+		 * The window being udated becomes the AFBC window
+		 */
+		vop->afbc_win = vop_win;
+
+		pr_info("AFBC on plane %s\n", plane->name);
+	}
+
 	VOP_WIN_SET(vop, win, format, format);
 	VOP_WIN_SET(vop, win, yrgb_vir, DIV_ROUND_UP(fb->pitches[0], 4));
 	VOP_WIN_SET(vop, win, yrgb_mst, dma_addr);
@@ -964,6 +1093,7 @@ static const struct drm_plane_funcs vop_plane_funcs = {
 	.reset = drm_atomic_helper_plane_reset,
 	.atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state,
 	.atomic_destroy_state = drm_atomic_helper_plane_destroy_state,
+	.format_mod_supported = rockchip_mod_supported,
 };
 
 static int vop_crtc_enable_vblank(struct drm_crtc *crtc)
@@ -1163,6 +1293,10 @@ static void vop_crtc_atomic_flush(struct drm_crtc *crtc,
 
 	spin_lock(&vop->reg_lock);
 
+	/*
+	 * Enable AFBC if there is some AFBC window, disable otherwise
+	 */
+	VOP_AFBC_SET(vop, enable, vop->afbc_win != NULL);
 	vop_cfg_done(vop);
 
 	spin_unlock(&vop->reg_lock);
@@ -1471,7 +1605,8 @@ static int vop_create_crtc(struct vop *vop)
 					       0, &vop_plane_funcs,
 					       win_data->phy->data_formats,
 					       win_data->phy->nformats,
-					       NULL, win_data->type, NULL);
+					       win_data->phy->format_modifiers,
+					       win_data->type, NULL);
 		if (ret) {
 			DRM_DEV_ERROR(vop->dev, "failed to init plane %d\n",
 				      ret);
@@ -1511,7 +1646,8 @@ static int vop_create_crtc(struct vop *vop)
 					       &vop_plane_funcs,
 					       win_data->phy->data_formats,
 					       win_data->phy->nformats,
-					       NULL, win_data->type, NULL);
+					       win_data->phy->format_modifiers,
+					       win_data->type, NULL);
 		if (ret) {
 			DRM_DEV_ERROR(vop->dev, "failed to init overlay %d\n",
 				      ret);
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.h b/drivers/gpu/drm/rockchip/rockchip_drm_vop.h
index 2149a889c29d..371b28b933a9 100644
--- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.h
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.h
@@ -34,6 +34,16 @@ struct vop_reg {
 	bool relaxed;
 };
 
+struct vop_afbc {
+	struct vop_reg enable;
+	struct vop_reg win_sel;
+	struct vop_reg format;
+	struct vop_reg hreg_block_split;
+	struct vop_reg pic_size;
+	struct vop_reg hdr_ptr;
+	struct vop_reg rstn;
+};
+
 struct vop_modeset {
 	struct vop_reg htotal_pw;
 	struct vop_reg hact_st_end;
@@ -128,6 +138,7 @@ struct vop_win_phy {
 	const struct vop_scl_regs *scl;
 	const uint32_t *data_formats;
 	uint32_t nformats;
+	const uint64_t *format_modifiers;
 
 	struct vop_reg enable;
 	struct vop_reg gate;
@@ -167,6 +178,7 @@ struct vop_data {
 	const struct vop_misc *misc;
 	const struct vop_modeset *modeset;
 	const struct vop_output *output;
+	const struct vop_afbc *afbc;
 	const struct vop_win_yuv2yuv_data *win_yuv2yuv;
 	const struct vop_win_data *win;
 	unsigned int win_size;
diff --git a/drivers/gpu/drm/rockchip/rockchip_vop_reg.c b/drivers/gpu/drm/rockchip/rockchip_vop_reg.c
index 7b9c74750f6d..a3981f037c90 100644
--- a/drivers/gpu/drm/rockchip/rockchip_vop_reg.c
+++ b/drivers/gpu/drm/rockchip/rockchip_vop_reg.c
@@ -44,6 +44,20 @@ static const uint32_t formats_win_full[] = {
 	DRM_FORMAT_NV24,
 };
 
+static const uint64_t format_modifiers_win_full[] = {
+	DRM_FORMAT_MOD_NONE,
+	DRM_FORMAT_MOD_INVALID,
+};
+
+static const uint64_t format_modifiers_win_full_afbc[] = {
+	DRM_FORMAT_MOD_ARM_AFBC(
+		AFBC_FORMAT_MOD_BLOCK_SIZE_16x16 |
+		AFBC_FORMAT_MOD_SPARSE
+	),
+	DRM_FORMAT_MOD_LINEAR,
+	DRM_FORMAT_MOD_INVALID,
+};
+
 static const uint32_t formats_win_lite[] = {
 	DRM_FORMAT_XRGB8888,
 	DRM_FORMAT_ARGB8888,
@@ -55,6 +69,11 @@ static const uint32_t formats_win_lite[] = {
 	DRM_FORMAT_BGR565,
 };
 
+static const uint64_t format_modifiers_win_lite[] = {
+	DRM_FORMAT_MOD_LINEAR,
+	DRM_FORMAT_MOD_INVALID,
+};
+
 static const struct vop_scl_regs rk3036_win_scl = {
 	.scale_yrgb_x = VOP_REG(RK3036_WIN0_SCL_FACTOR_YRGB, 0xffff, 0x0),
 	.scale_yrgb_y = VOP_REG(RK3036_WIN0_SCL_FACTOR_YRGB, 0xffff, 16),
@@ -66,6 +85,7 @@ static const struct vop_win_phy rk3036_win0_data = {
 	.scl = &rk3036_win_scl,
 	.data_formats = formats_win_full,
 	.nformats = ARRAY_SIZE(formats_win_full),
+	.format_modifiers = format_modifiers_win_full,
 	.enable = VOP_REG(RK3036_SYS_CTRL, 0x1, 0),
 	.format = VOP_REG(RK3036_SYS_CTRL, 0x7, 3),
 	.rb_swap = VOP_REG(RK3036_SYS_CTRL, 0x1, 15),
@@ -81,6 +101,7 @@ static const struct vop_win_phy rk3036_win0_data = {
 static const struct vop_win_phy rk3036_win1_data = {
 	.data_formats = formats_win_lite,
 	.nformats = ARRAY_SIZE(formats_win_lite),
+	.format_modifiers = format_modifiers_win_lite,
 	.enable = VOP_REG(RK3036_SYS_CTRL, 0x1, 1),
 	.format = VOP_REG(RK3036_SYS_CTRL, 0x7, 6),
 	.rb_swap = VOP_REG(RK3036_SYS_CTRL, 0x1, 19),
@@ -147,6 +168,7 @@ static const struct vop_data rk3036_vop = {
 static const struct vop_win_phy rk3126_win1_data = {
 	.data_formats = formats_win_lite,
 	.nformats = ARRAY_SIZE(formats_win_lite),
+	.format_modifiers = format_modifiers_win_lite,
 	.enable = VOP_REG(RK3036_SYS_CTRL, 0x1, 1),
 	.format = VOP_REG(RK3036_SYS_CTRL, 0x7, 6),
 	.rb_swap = VOP_REG(RK3036_SYS_CTRL, 0x1, 19),
@@ -226,6 +248,7 @@ static const struct vop_win_phy px30_win0_data = {
 	.scl = &px30_win_scl,
 	.data_formats = formats_win_full,
 	.nformats = ARRAY_SIZE(formats_win_full),
+	.format_modifiers = format_modifiers_win_full,
 	.enable = VOP_REG(PX30_WIN0_CTRL0, 0x1, 0),
 	.format = VOP_REG(PX30_WIN0_CTRL0, 0x7, 1),
 	.rb_swap = VOP_REG(PX30_WIN0_CTRL0, 0x1, 12),
@@ -241,6 +264,7 @@ static const struct vop_win_phy px30_win0_data = {
 static const struct vop_win_phy px30_win1_data = {
 	.data_formats = formats_win_lite,
 	.nformats = ARRAY_SIZE(formats_win_lite),
+	.format_modifiers = format_modifiers_win_lite,
 	.enable = VOP_REG(PX30_WIN1_CTRL0, 0x1, 0),
 	.format = VOP_REG(PX30_WIN1_CTRL0, 0x7, 4),
 	.rb_swap = VOP_REG(PX30_WIN1_CTRL0, 0x1, 12),
@@ -253,6 +277,7 @@ static const struct vop_win_phy px30_win1_data = {
 static const struct vop_win_phy px30_win2_data = {
 	.data_formats = formats_win_lite,
 	.nformats = ARRAY_SIZE(formats_win_lite),
+	.format_modifiers = format_modifiers_win_lite,
 	.gate = VOP_REG(PX30_WIN2_CTRL0, 0x1, 4),
 	.enable = VOP_REG(PX30_WIN2_CTRL0, 0x1, 0),
 	.format = VOP_REG(PX30_WIN2_CTRL0, 0x3, 5),
@@ -308,6 +333,7 @@ static const struct vop_win_phy rk3066_win0_data = {
 	.scl = &rk3066_win_scl,
 	.data_formats = formats_win_full,
 	.nformats = ARRAY_SIZE(formats_win_full),
+	.format_modifiers = format_modifiers_win_full,
 	.enable = VOP_REG(RK3066_SYS_CTRL1, 0x1, 0),
 	.format = VOP_REG(RK3066_SYS_CTRL0, 0x7, 4),
 	.rb_swap = VOP_REG(RK3066_SYS_CTRL0, 0x1, 19),
@@ -324,6 +350,7 @@ static const struct vop_win_phy rk3066_win1_data = {
 	.scl = &rk3066_win_scl,
 	.data_formats = formats_win_full,
 	.nformats = ARRAY_SIZE(formats_win_full),
+	.format_modifiers = format_modifiers_win_full,
 	.enable = VOP_REG(RK3066_SYS_CTRL1, 0x1, 1),
 	.format = VOP_REG(RK3066_SYS_CTRL0, 0x7, 7),
 	.rb_swap = VOP_REG(RK3066_SYS_CTRL0, 0x1, 23),
@@ -339,6 +366,7 @@ static const struct vop_win_phy rk3066_win1_data = {
 static const struct vop_win_phy rk3066_win2_data = {
 	.data_formats = formats_win_lite,
 	.nformats = ARRAY_SIZE(formats_win_lite),
+	.format_modifiers = format_modifiers_win_lite,
 	.enable = VOP_REG(RK3066_SYS_CTRL1, 0x1, 2),
 	.format = VOP_REG(RK3066_SYS_CTRL0, 0x7, 10),
 	.rb_swap = VOP_REG(RK3066_SYS_CTRL0, 0x1, 27),
@@ -418,6 +446,7 @@ static const struct vop_win_phy rk3188_win0_data = {
 	.scl = &rk3188_win_scl,
 	.data_formats = formats_win_full,
 	.nformats = ARRAY_SIZE(formats_win_full),
+	.format_modifiers = format_modifiers_win_full,
 	.enable = VOP_REG(RK3188_SYS_CTRL, 0x1, 0),
 	.format = VOP_REG(RK3188_SYS_CTRL, 0x7, 3),
 	.rb_swap = VOP_REG(RK3188_SYS_CTRL, 0x1, 15),
@@ -432,6 +461,7 @@ static const struct vop_win_phy rk3188_win0_data = {
 static const struct vop_win_phy rk3188_win1_data = {
 	.data_formats = formats_win_lite,
 	.nformats = ARRAY_SIZE(formats_win_lite),
+	.format_modifiers = format_modifiers_win_lite,
 	.enable = VOP_REG(RK3188_SYS_CTRL, 0x1, 1),
 	.format = VOP_REG(RK3188_SYS_CTRL, 0x7, 6),
 	.rb_swap = VOP_REG(RK3188_SYS_CTRL, 0x1, 19),
@@ -537,6 +567,7 @@ static const struct vop_win_phy rk3288_win01_data = {
 	.scl = &rk3288_win_full_scl,
 	.data_formats = formats_win_full,
 	.nformats = ARRAY_SIZE(formats_win_full),
+	.format_modifiers = format_modifiers_win_full,
 	.enable = VOP_REG(RK3288_WIN0_CTRL0, 0x1, 0),
 	.format = VOP_REG(RK3288_WIN0_CTRL0, 0x7, 1),
 	.rb_swap = VOP_REG(RK3288_WIN0_CTRL0, 0x1, 12),
@@ -555,6 +586,7 @@ static const struct vop_win_phy rk3288_win01_data = {
 static const struct vop_win_phy rk3288_win23_data = {
 	.data_formats = formats_win_lite,
 	.nformats = ARRAY_SIZE(formats_win_lite),
+	.format_modifiers = format_modifiers_win_lite,
 	.enable = VOP_REG(RK3288_WIN2_CTRL0, 0x1, 4),
 	.gate = VOP_REG(RK3288_WIN2_CTRL0, 0x1, 0),
 	.format = VOP_REG(RK3288_WIN2_CTRL0, 0x7, 1),
@@ -667,6 +699,7 @@ static const struct vop_win_phy rk3368_win01_data = {
 	.scl = &rk3288_win_full_scl,
 	.data_formats = formats_win_full,
 	.nformats = ARRAY_SIZE(formats_win_full),
+	.format_modifiers = format_modifiers_win_full,
 	.enable = VOP_REG(RK3368_WIN0_CTRL0, 0x1, 0),
 	.format = VOP_REG(RK3368_WIN0_CTRL0, 0x7, 1),
 	.rb_swap = VOP_REG(RK3368_WIN0_CTRL0, 0x1, 12),
@@ -687,6 +720,7 @@ static const struct vop_win_phy rk3368_win01_data = {
 static const struct vop_win_phy rk3368_win23_data = {
 	.data_formats = formats_win_lite,
 	.nformats = ARRAY_SIZE(formats_win_lite),
+	.format_modifiers = format_modifiers_win_lite,
 	.gate = VOP_REG(RK3368_WIN2_CTRL0, 0x1, 0),
 	.enable = VOP_REG(RK3368_WIN2_CTRL0, 0x1, 4),
 	.format = VOP_REG(RK3368_WIN2_CTRL0, 0x3, 5),
@@ -798,6 +832,53 @@ static const struct vop_win_yuv2yuv_data rk3399_vop_big_win_yuv2yuv_data[] = {
 	  .y2r_en = VOP_REG(RK3399_YUV2YUV_WIN, 0x1, 9) },
 	{ .base = 0xC0, .phy = &rk3399_yuv2yuv_win23_data },
 	{ .base = 0x120, .phy = &rk3399_yuv2yuv_win23_data },
+
+};
+
+static const struct vop_win_phy rk3399_win01_data = {
+	.scl = &rk3288_win_full_scl,
+	.data_formats = formats_win_full,
+	.nformats = ARRAY_SIZE(formats_win_full),
+	.format_modifiers = format_modifiers_win_full_afbc,
+	.enable = VOP_REG(RK3288_WIN0_CTRL0, 0x1, 0),
+	.format = VOP_REG(RK3288_WIN0_CTRL0, 0x7, 1),
+	.rb_swap = VOP_REG(RK3288_WIN0_CTRL0, 0x1, 12),
+	.y_mir_en = VOP_REG(RK3288_WIN0_CTRL0, 0x1, 22),
+	.act_info = VOP_REG(RK3288_WIN0_ACT_INFO, 0x1fff1fff, 0),
+	.dsp_info = VOP_REG(RK3288_WIN0_DSP_INFO, 0x0fff0fff, 0),
+	.dsp_st = VOP_REG(RK3288_WIN0_DSP_ST, 0x1fff1fff, 0),
+	.yrgb_mst = VOP_REG(RK3288_WIN0_YRGB_MST, 0xffffffff, 0),
+	.uv_mst = VOP_REG(RK3288_WIN0_CBR_MST, 0xffffffff, 0),
+	.yrgb_vir = VOP_REG(RK3288_WIN0_VIR, 0x3fff, 0),
+	.uv_vir = VOP_REG(RK3288_WIN0_VIR, 0x3fff, 16),
+	.src_alpha_ctl = VOP_REG(RK3288_WIN0_SRC_ALPHA_CTRL, 0xff, 0),
+	.dst_alpha_ctl = VOP_REG(RK3288_WIN0_DST_ALPHA_CTRL, 0xff, 0),
+};
+
+/*
+ * rk3399 vop big windows register layout is same as rk3288, but we
+ * have a separate rk3399 win data array here so that we can advertise
+ * AFBC on the primary plane.
+ */
+static const struct vop_win_data rk3399_vop_win_data[] = {
+	{ .base = 0x00, .phy = &rk3399_win01_data,
+	  .type = DRM_PLANE_TYPE_PRIMARY },
+	{ .base = 0x40, .phy = &rk3288_win01_data,
+	  .type = DRM_PLANE_TYPE_OVERLAY },
+	{ .base = 0x00, .phy = &rk3288_win23_data,
+	  .type = DRM_PLANE_TYPE_OVERLAY },
+	{ .base = 0x50, .phy = &rk3288_win23_data,
+	  .type = DRM_PLANE_TYPE_CURSOR },
+};
+
+static const struct vop_afbc rk3399_vop_afbc = {
+	.rstn = VOP_REG(RK3399_AFBCD0_CTRL, 0x1, 3),
+	.enable = VOP_REG(RK3399_AFBCD0_CTRL, 0x1, 0),
+	.win_sel = VOP_REG(RK3399_AFBCD0_CTRL, 0x3, 1),
+	.format = VOP_REG(RK3399_AFBCD0_CTRL, 0x1f, 16),
+	.hreg_block_split = VOP_REG(RK3399_AFBCD0_CTRL, 0x1, 21),
+	.hdr_ptr = VOP_REG(RK3399_AFBCD0_HDR_PTR, 0xffffffff, 0),
+	.pic_size = VOP_REG(RK3399_AFBCD0_PIC_SIZE, 0xffffffff, 0),
 };
 
 static const struct vop_data rk3399_vop_big = {
@@ -807,9 +888,10 @@ static const struct vop_data rk3399_vop_big = {
 	.common = &rk3288_common,
 	.modeset = &rk3288_modeset,
 	.output = &rk3399_output,
+	.afbc = &rk3399_vop_afbc,
 	.misc = &rk3368_misc,
-	.win = rk3368_vop_win_data,
-	.win_size = ARRAY_SIZE(rk3368_vop_win_data),
+	.win = rk3399_vop_win_data,
+	.win_size = ARRAY_SIZE(rk3399_vop_win_data),
 	.win_yuv2yuv = rk3399_vop_big_win_yuv2yuv_data,
 };
 
-- 
2.17.1


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply related	[flat|nested] 63+ messages in thread

* Re: [PATCH 2/2] drm/rockchip: Add support for afbc
  2019-10-11 11:18   ` Andrzej Pietrasiewicz
  (?)
@ 2019-10-11 11:59     ` Daniel Stone
  -1 siblings, 0 replies; 63+ messages in thread
From: Daniel Stone @ 2019-10-11 11:59 UTC (permalink / raw)
  To: Andrzej Pietrasiewicz
  Cc: dri-devel, Sandy Huang, kernel, Maarten Lankhorst, Maxime Ripard,
	Sean Paul, David Airlie, Daniel Vetter, Liviu Dudau,
	Brian Starkey, Heiko Stübner, Linux Kernel Mailing List,
	linux-arm-kernel, linux-rockchip

Hi Andrzej,

On Fri, 11 Oct 2019 at 12:18, Andrzej Pietrasiewicz
<andrzej.p@collabora.com> wrote:
> @@ -32,6 +35,46 @@ rockchip_fb_alloc(struct drm_device *dev, const struct drm_mode_fb_cmd2 *mode_cm
>         int ret;
>         int i;
>
> +       if (mode_cmd->modifier[0]) {
> +               const struct drm_format_info *info;
> +               int bpp;
> +
> +               if (mode_cmd->modifier[0] &

Use != here, not &~.

> +       case DRM_FORMAT_BGR888:
> +               return AFBC_FMT_U8U8U8;
> +       case DRM_FORMAT_RGB565:
> +       case DRM_FORMAT_BGR565:
> +               return AFBC_FMT_RGB565;
> +       default:
> +               DRM_ERROR("unsupported afbc format[%08x]\n", format);

This should not be reachable, because you shouldn't be able to create
a framebuffer with an unsupported format/modifier combination.

> +static bool rockchip_mod_supported(struct drm_plane *plane,
> +                                  u32 format, u64 modifier)
> +{
> +       const struct drm_format_info *info;
> +
> +       if (WARN_ON(modifier == DRM_FORMAT_MOD_INVALID))
> +               return false;
> +
> +       if (modifier == DRM_FORMAT_MOD_LINEAR)
> +               return true;
> +
> +       if (modifier & ~DRM_FORMAT_MOD_ARM_AFBC(

Again use != here.

> +                               AFBC_FORMAT_MOD_BLOCK_SIZE_16x16 |
> +                               AFBC_FORMAT_MOD_SPARSE
> +                       )
> +       ) {
> +               DRM_DEBUG_KMS("Unsupported format modifer 0x%llx\n", modifier);
> +
> +               return false;
> +       }
> +
> +       info = drm_format_info(format);
> +       if (info->num_planes != 1) {
> +               DRM_DEBUG_KMS("AFBC buffers expect one plane\n");
> +               return false;
> +       }

This is where you should reject unsupported format + AFBC
combinations. Doing it here prevents it from ever being advertised to
userspace in the first place.

> @@ -808,6 +919,24 @@ static void vop_plane_atomic_update(struct drm_plane *plane,
>
>         spin_lock(&vop->reg_lock);
>
> +       if (fb->modifier == DRM_FORMAT_MOD_ARM_AFBC(
> +               AFBC_FORMAT_MOD_BLOCK_SIZE_16x16 | AFBC_FORMAT_MOD_SPARSE)) {
> +               int afbc_format = vop_convert_afbc_format(fb->format->format);
> +
> +               VOP_AFBC_SET(vop, format, afbc_format | 1 << 4);

I assume the (1 << 4) programs the 16x16 block size. Can we support
other block sizes?

> +               VOP_AFBC_SET(vop, hreg_block_split, 0);

Does this mean we can also support AFBC_FORMAT_MOD_SPLIT?

> +               VOP_AFBC_SET(vop, win_sel, VOP_WIN_TO_INDEX(vop_win));
> +               VOP_AFBC_SET(vop, hdr_ptr, dma_addr);
> +               VOP_AFBC_SET(vop, pic_size, act_info);
> +
> +               /*
> +                * The window being udated becomes the AFBC window
> +                */
> +               vop->afbc_win = vop_win;
> +
> +               pr_info("AFBC on plane %s\n", plane->name);

Please do not use pr_info() here. Userspace should not be able to
trigger logging, apart from DRM_DEBUG.

> +static const uint64_t format_modifiers_win_full[] = {
> +       DRM_FORMAT_MOD_NONE,

*DRM_FORMAT_MOD_LINEAR

Cheers,
Daniel

^ permalink raw reply	[flat|nested] 63+ messages in thread

* Re: [PATCH 2/2] drm/rockchip: Add support for afbc
@ 2019-10-11 11:59     ` Daniel Stone
  0 siblings, 0 replies; 63+ messages in thread
From: Daniel Stone @ 2019-10-11 11:59 UTC (permalink / raw)
  To: Andrzej Pietrasiewicz
  Cc: David Airlie, Liviu Dudau, Linux Kernel Mailing List,
	linux-rockchip, dri-devel, kernel, Sean Paul, linux-arm-kernel

Hi Andrzej,

On Fri, 11 Oct 2019 at 12:18, Andrzej Pietrasiewicz
<andrzej.p@collabora.com> wrote:
> @@ -32,6 +35,46 @@ rockchip_fb_alloc(struct drm_device *dev, const struct drm_mode_fb_cmd2 *mode_cm
>         int ret;
>         int i;
>
> +       if (mode_cmd->modifier[0]) {
> +               const struct drm_format_info *info;
> +               int bpp;
> +
> +               if (mode_cmd->modifier[0] &

Use != here, not &~.

> +       case DRM_FORMAT_BGR888:
> +               return AFBC_FMT_U8U8U8;
> +       case DRM_FORMAT_RGB565:
> +       case DRM_FORMAT_BGR565:
> +               return AFBC_FMT_RGB565;
> +       default:
> +               DRM_ERROR("unsupported afbc format[%08x]\n", format);

This should not be reachable, because you shouldn't be able to create
a framebuffer with an unsupported format/modifier combination.

> +static bool rockchip_mod_supported(struct drm_plane *plane,
> +                                  u32 format, u64 modifier)
> +{
> +       const struct drm_format_info *info;
> +
> +       if (WARN_ON(modifier == DRM_FORMAT_MOD_INVALID))
> +               return false;
> +
> +       if (modifier == DRM_FORMAT_MOD_LINEAR)
> +               return true;
> +
> +       if (modifier & ~DRM_FORMAT_MOD_ARM_AFBC(

Again use != here.

> +                               AFBC_FORMAT_MOD_BLOCK_SIZE_16x16 |
> +                               AFBC_FORMAT_MOD_SPARSE
> +                       )
> +       ) {
> +               DRM_DEBUG_KMS("Unsupported format modifer 0x%llx\n", modifier);
> +
> +               return false;
> +       }
> +
> +       info = drm_format_info(format);
> +       if (info->num_planes != 1) {
> +               DRM_DEBUG_KMS("AFBC buffers expect one plane\n");
> +               return false;
> +       }

This is where you should reject unsupported format + AFBC
combinations. Doing it here prevents it from ever being advertised to
userspace in the first place.

> @@ -808,6 +919,24 @@ static void vop_plane_atomic_update(struct drm_plane *plane,
>
>         spin_lock(&vop->reg_lock);
>
> +       if (fb->modifier == DRM_FORMAT_MOD_ARM_AFBC(
> +               AFBC_FORMAT_MOD_BLOCK_SIZE_16x16 | AFBC_FORMAT_MOD_SPARSE)) {
> +               int afbc_format = vop_convert_afbc_format(fb->format->format);
> +
> +               VOP_AFBC_SET(vop, format, afbc_format | 1 << 4);

I assume the (1 << 4) programs the 16x16 block size. Can we support
other block sizes?

> +               VOP_AFBC_SET(vop, hreg_block_split, 0);

Does this mean we can also support AFBC_FORMAT_MOD_SPLIT?

> +               VOP_AFBC_SET(vop, win_sel, VOP_WIN_TO_INDEX(vop_win));
> +               VOP_AFBC_SET(vop, hdr_ptr, dma_addr);
> +               VOP_AFBC_SET(vop, pic_size, act_info);
> +
> +               /*
> +                * The window being udated becomes the AFBC window
> +                */
> +               vop->afbc_win = vop_win;
> +
> +               pr_info("AFBC on plane %s\n", plane->name);

Please do not use pr_info() here. Userspace should not be able to
trigger logging, apart from DRM_DEBUG.

> +static const uint64_t format_modifiers_win_full[] = {
> +       DRM_FORMAT_MOD_NONE,

*DRM_FORMAT_MOD_LINEAR

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

^ permalink raw reply	[flat|nested] 63+ messages in thread

* Re: [PATCH 2/2] drm/rockchip: Add support for afbc
@ 2019-10-11 11:59     ` Daniel Stone
  0 siblings, 0 replies; 63+ messages in thread
From: Daniel Stone @ 2019-10-11 11:59 UTC (permalink / raw)
  To: Andrzej Pietrasiewicz
  Cc: Heiko Stübner, David Airlie, Liviu Dudau, Maarten Lankhorst,
	Sandy Huang, Maxime Ripard, Linux Kernel Mailing List,
	linux-rockchip, dri-devel, Daniel Vetter, kernel, Sean Paul,
	Brian Starkey, linux-arm-kernel

Hi Andrzej,

On Fri, 11 Oct 2019 at 12:18, Andrzej Pietrasiewicz
<andrzej.p@collabora.com> wrote:
> @@ -32,6 +35,46 @@ rockchip_fb_alloc(struct drm_device *dev, const struct drm_mode_fb_cmd2 *mode_cm
>         int ret;
>         int i;
>
> +       if (mode_cmd->modifier[0]) {
> +               const struct drm_format_info *info;
> +               int bpp;
> +
> +               if (mode_cmd->modifier[0] &

Use != here, not &~.

> +       case DRM_FORMAT_BGR888:
> +               return AFBC_FMT_U8U8U8;
> +       case DRM_FORMAT_RGB565:
> +       case DRM_FORMAT_BGR565:
> +               return AFBC_FMT_RGB565;
> +       default:
> +               DRM_ERROR("unsupported afbc format[%08x]\n", format);

This should not be reachable, because you shouldn't be able to create
a framebuffer with an unsupported format/modifier combination.

> +static bool rockchip_mod_supported(struct drm_plane *plane,
> +                                  u32 format, u64 modifier)
> +{
> +       const struct drm_format_info *info;
> +
> +       if (WARN_ON(modifier == DRM_FORMAT_MOD_INVALID))
> +               return false;
> +
> +       if (modifier == DRM_FORMAT_MOD_LINEAR)
> +               return true;
> +
> +       if (modifier & ~DRM_FORMAT_MOD_ARM_AFBC(

Again use != here.

> +                               AFBC_FORMAT_MOD_BLOCK_SIZE_16x16 |
> +                               AFBC_FORMAT_MOD_SPARSE
> +                       )
> +       ) {
> +               DRM_DEBUG_KMS("Unsupported format modifer 0x%llx\n", modifier);
> +
> +               return false;
> +       }
> +
> +       info = drm_format_info(format);
> +       if (info->num_planes != 1) {
> +               DRM_DEBUG_KMS("AFBC buffers expect one plane\n");
> +               return false;
> +       }

This is where you should reject unsupported format + AFBC
combinations. Doing it here prevents it from ever being advertised to
userspace in the first place.

> @@ -808,6 +919,24 @@ static void vop_plane_atomic_update(struct drm_plane *plane,
>
>         spin_lock(&vop->reg_lock);
>
> +       if (fb->modifier == DRM_FORMAT_MOD_ARM_AFBC(
> +               AFBC_FORMAT_MOD_BLOCK_SIZE_16x16 | AFBC_FORMAT_MOD_SPARSE)) {
> +               int afbc_format = vop_convert_afbc_format(fb->format->format);
> +
> +               VOP_AFBC_SET(vop, format, afbc_format | 1 << 4);

I assume the (1 << 4) programs the 16x16 block size. Can we support
other block sizes?

> +               VOP_AFBC_SET(vop, hreg_block_split, 0);

Does this mean we can also support AFBC_FORMAT_MOD_SPLIT?

> +               VOP_AFBC_SET(vop, win_sel, VOP_WIN_TO_INDEX(vop_win));
> +               VOP_AFBC_SET(vop, hdr_ptr, dma_addr);
> +               VOP_AFBC_SET(vop, pic_size, act_info);
> +
> +               /*
> +                * The window being udated becomes the AFBC window
> +                */
> +               vop->afbc_win = vop_win;
> +
> +               pr_info("AFBC on plane %s\n", plane->name);

Please do not use pr_info() here. Userspace should not be able to
trigger logging, apart from DRM_DEBUG.

> +static const uint64_t format_modifiers_win_full[] = {
> +       DRM_FORMAT_MOD_NONE,

*DRM_FORMAT_MOD_LINEAR

Cheers,
Daniel

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 63+ messages in thread

* Re: [PATCH 1/2] drm/arm: Factor out generic afbc helpers
  2019-10-11 11:18   ` Andrzej Pietrasiewicz
  (?)
@ 2019-10-21 13:50     ` Ayan Halder
  -1 siblings, 0 replies; 63+ messages in thread
From: Ayan Halder @ 2019-10-21 13:50 UTC (permalink / raw)
  To: Andrzej Pietrasiewicz
  Cc: dri-devel, David Airlie, Liviu Dudau,
	james qian wang (Arm Technology China),
	Mihail Atanassov, linux-rockchip, linux-arm-kernel, kernel,
	Sean Paul, linux-kernel, nd

On Fri, Oct 11, 2019 at 01:18:10PM +0200, Andrzej Pietrasiewicz wrote:
> These are useful for other users of afbc, e.g. rockchip.
> 
> Signed-off-by: Andrzej Pietrasiewicz <andrzej.p@collabora.com>

Hi Andrzej,

Thanks a lot for doing this. Much appreciated. :)
It was on our TODO list for a long time.

I have cc-ed james.qian.wang@arm.com, Mihail.Atanassov@arm.com for
their comments as well.

> ---
>  drivers/gpu/drm/Kconfig          |   4 ++
>  drivers/gpu/drm/Makefile         |   1 +
>  drivers/gpu/drm/arm/Kconfig      |   1 +
>  drivers/gpu/drm/arm/malidp_drv.c |  58 ++--------------
>  drivers/gpu/drm/drm_afbc.c       | 114 +++++++++++++++++++++++++++++++
>  include/drm/drm_afbc.h           |  25 +++++++
>  6 files changed, 149 insertions(+), 54 deletions(-)
>  create mode 100644 drivers/gpu/drm/drm_afbc.c
>  create mode 100644 include/drm/drm_afbc.h
> 
> diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig
> index 3c88420e3497..00e3f90557f4 100644
> --- a/drivers/gpu/drm/Kconfig
> +++ b/drivers/gpu/drm/Kconfig
> @@ -195,6 +195,10 @@ config DRM_SCHED
>  	tristate
>  	depends on DRM
>  
> +config DRM_AFBC
> +	tristate
> +	depends on DRM
Adding a 'help' would be great here. Stealing the first line from
https://www.kernel.org/doc/html/latest/gpu/afbc.html

"AFBC is a proprietary lossless image compression protocol and format.
It provides fine-grained random access and minimizes the amount of
data transferred between IP blocks."

> +
>  source "drivers/gpu/drm/i2c/Kconfig"
>  
>  source "drivers/gpu/drm/arm/Kconfig"
> diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile
> index 9f0d2ee35794..55368b668355 100644
> --- a/drivers/gpu/drm/Makefile
> +++ b/drivers/gpu/drm/Makefile
> @@ -31,6 +31,7 @@ drm-$(CONFIG_OF) += drm_of.o
>  drm-$(CONFIG_AGP) += drm_agpsupport.o
>  drm-$(CONFIG_DEBUG_FS) += drm_debugfs.o drm_debugfs_crc.o
>  drm-$(CONFIG_DRM_LOAD_EDID_FIRMWARE) += drm_edid_load.o
> +drm-$(CONFIG_DRM_AFBC) += drm_afbc.o
>  
>  drm_vram_helper-y := drm_gem_vram_helper.o \
>  		     drm_vram_helper_common.o \
> diff --git a/drivers/gpu/drm/arm/Kconfig b/drivers/gpu/drm/arm/Kconfig
> index a204103b3efb..25c3dc408cda 100644
> --- a/drivers/gpu/drm/arm/Kconfig
> +++ b/drivers/gpu/drm/arm/Kconfig
> @@ -29,6 +29,7 @@ config DRM_MALI_DISPLAY
>  	select DRM_KMS_HELPER
>  	select DRM_KMS_CMA_HELPER
>  	select DRM_GEM_CMA_HELPER
> +	select DRM_AFBC
>  	select VIDEOMODE_HELPERS
>  	help
>  	  Choose this option if you want to compile the ARM Mali Display
> diff --git a/drivers/gpu/drm/arm/malidp_drv.c b/drivers/gpu/drm/arm/malidp_drv.c
> index f25ec4382277..a67b69e08f63 100644
> --- a/drivers/gpu/drm/arm/malidp_drv.c
> +++ b/drivers/gpu/drm/arm/malidp_drv.c
> @@ -16,6 +16,7 @@
>  #include <linux/debugfs.h>
>  
>  #include <drm/drmP.h>
> +#include <drm/drm_afbc.h>
>  #include <drm/drm_atomic.h>
>  #include <drm/drm_atomic_helper.h>
>  #include <drm/drm_crtc.h>
> @@ -33,8 +34,6 @@
>  #include "malidp_hw.h"
>  
>  #define MALIDP_CONF_VALID_TIMEOUT	250
> -#define AFBC_HEADER_SIZE		16
> -#define AFBC_SUPERBLK_ALIGNMENT		128
>  
>  static void malidp_write_gamma_table(struct malidp_hw_device *hwdev,
>  				     u32 data[MALIDP_COEFFTAB_NUM_COEFFS])
> @@ -275,24 +274,8 @@ malidp_verify_afbc_framebuffer_caps(struct drm_device *dev,
>  					mode_cmd->modifier[0]) == false)
>  		return false;
>  
> -	if (mode_cmd->offsets[0] != 0) {
> -		DRM_DEBUG_KMS("AFBC buffers' plane offset should be 0\n");
> -		return false;
> -	}
> -
> -	switch (mode_cmd->modifier[0] & AFBC_SIZE_MASK) {
> -	case AFBC_SIZE_16X16:
> -		if ((mode_cmd->width % 16) || (mode_cmd->height % 16)) {
> -			DRM_DEBUG_KMS("AFBC buffers must be aligned to 16 pixels\n");
> -			return false;
> -		}
> -		break;
> -	default:
> -		DRM_DEBUG_KMS("Unsupported AFBC block size\n");
> -		return false;
> -	}
> -
> -	return true;
> +	return drm_afbc_check_offset(dev, mode_cmd) &&
> +	       drm_afbc_check_size_align(dev, mode_cmd);
>  }
>  
>  static bool
> @@ -300,53 +283,20 @@ malidp_verify_afbc_framebuffer_size(struct drm_device *dev,
>  				    struct drm_file *file,
>  				    const struct drm_mode_fb_cmd2 *mode_cmd)
>  {
> -	int n_superblocks = 0;
>  	const struct drm_format_info *info;
>  	struct drm_gem_object *objs = NULL;
> -	u32 afbc_superblock_size = 0, afbc_superblock_height = 0;
> -	u32 afbc_superblock_width = 0, afbc_size = 0;
>  	int bpp = 0;
>  
> -	switch (mode_cmd->modifier[0] & AFBC_SIZE_MASK) {
> -	case AFBC_SIZE_16X16:
> -		afbc_superblock_height = 16;
> -		afbc_superblock_width = 16;
> -		break;
> -	default:
> -		DRM_DEBUG_KMS("AFBC superblock size is not supported\n");
> -		return false;
> -	}
> -
>  	info = drm_get_format_info(dev, mode_cmd);
> -
> -	n_superblocks = (mode_cmd->width / afbc_superblock_width) *
> -		(mode_cmd->height / afbc_superblock_height);
> -
>  	bpp = malidp_format_get_bpp(info->format);
>  
> -	afbc_superblock_size = (bpp * afbc_superblock_width * afbc_superblock_height)
> -				/ BITS_PER_BYTE;
> -
> -	afbc_size = ALIGN(n_superblocks * AFBC_HEADER_SIZE, AFBC_SUPERBLK_ALIGNMENT);
> -	afbc_size += n_superblocks * ALIGN(afbc_superblock_size, AFBC_SUPERBLK_ALIGNMENT);
> -
> -	if ((mode_cmd->width * bpp) != (mode_cmd->pitches[0] * BITS_PER_BYTE)) {
> -		DRM_DEBUG_KMS("Invalid value of (pitch * BITS_PER_BYTE) (=%u) "
> -			      "should be same as width (=%u) * bpp (=%u)\n",
> -			      (mode_cmd->pitches[0] * BITS_PER_BYTE),
> -			      mode_cmd->width, bpp);
> -		return false;
> -	}
> -
>  	objs = drm_gem_object_lookup(file, mode_cmd->handles[0]);
>  	if (!objs) {
>  		DRM_DEBUG_KMS("Failed to lookup GEM object\n");
>  		return false;
>  	}
>  
> -	if (objs->size < afbc_size) {
> -		DRM_DEBUG_KMS("buffer size (%zu) too small for AFBC buffer size = %u\n",
> -			      objs->size, afbc_size);
> +	if (!drm_afbc_check_fb_size(dev, mode_cmd, objs, bpp)) {
>  		drm_gem_object_put_unlocked(objs);
>  		return false;
>  	}
Also can you do the code refactoring for komeda driver as well.
specifically komeda_fb_afbc_size_check(). I will let
james.qian.wang@arm.com and Mihail.Atanassov@arm.com have their
opinion on this.

> diff --git a/drivers/gpu/drm/drm_afbc.c b/drivers/gpu/drm/drm_afbc.c
> new file mode 100644
> index 000000000000..3e8a9225fd2e
> --- /dev/null
> +++ b/drivers/gpu/drm/drm_afbc.c
> @@ -0,0 +1,114 @@
> +// SPDX-License-Identifier: GPL-2.0+
> +/*
> + * (C) 2019 Collabora Ltd.
> + *
> + * author: Andrzej Pietrasiewicz <andrzej.p@collabora.com>
> + *
> + */
> +#include <linux/module.h>
> +
> +#include <drm/drm_afbc.h>
> +#include <drm/drm_device.h>
> +#include <drm/drm_fourcc.h>
> +#include <drm/drm_gem.h>
> +#include <drm/drm_mode.h>
> +#include <drm/drm_print.h>
> +
> +#define AFBC_HEADER_SIZE		16
> +#define AFBC_SUPERBLK_ALIGNMENT		128
> +
> +bool drm_afbc_check_offset(struct drm_device *dev,
> +			   const struct drm_mode_fb_cmd2 *mode_cmd)
> +{
> +	if (mode_cmd->offsets[0] != 0) {
> +		DRM_DEBUG_KMS("AFBC buffers' plane offset should be 0\n");
> +		return false;
> +	}
> +
> +	return true;
> +}
> +EXPORT_SYMBOL_GPL(drm_afbc_check_offset);
> +
> +bool drm_afbc_check_size_align(struct drm_device *dev,
> +			       const struct drm_mode_fb_cmd2 *mode_cmd)
> +{
> +
> +	switch (mode_cmd->modifier[0] & AFBC_FORMAT_MOD_BLOCK_SIZE_MASK) {
> +	case AFBC_FORMAT_MOD_BLOCK_SIZE_16x16:
> +		if ((mode_cmd->width % 16) || (mode_cmd->height % 16)) {
> +			DRM_DEBUG_KMS(
> +				"AFBC buffer must be aligned to 16 pixels\n"
> +			);
> +			return false;
> +		}
> +		break;
> +	case AFBC_FORMAT_MOD_BLOCK_SIZE_32x8:
> +		/* fall through */
> +	case AFBC_FORMAT_MOD_BLOCK_SIZE_64x4:
> +		/* fall through */
> +	case AFBC_FORMAT_MOD_BLOCK_SIZE_32x8_64x4:
> +		/* fall through */
> +	default:
> +		DRM_DEBUG_KMS("Unsupported AFBC block size\n");
> +		return false;
> +	}
> +
> +	return true;
> +}
> +EXPORT_SYMBOL_GPL(drm_afbc_check_size_align);
> +
> +bool drm_afbc_check_fb_size(struct drm_device *dev,
> +			    const struct drm_mode_fb_cmd2 *mode_cmd,
> +			    struct drm_gem_object *objs, int bpp)
> +{
> +	int n_superblocks = 0;
> +	u32 afbc_superblock_size = 0, afbc_superblock_height = 0;
> +	u32 afbc_superblock_width = 0, afbc_size = 0;
> +
> +	switch (mode_cmd->modifier[0] & AFBC_FORMAT_MOD_BLOCK_SIZE_MASK) {
> +	case AFBC_FORMAT_MOD_BLOCK_SIZE_16x16:
> +		afbc_superblock_height = 16;
> +		afbc_superblock_width = 16;
> +		break;
> +	case AFBC_FORMAT_MOD_BLOCK_SIZE_32x8:
Copying from
https://cgit.freedesktop.org/drm/drm-tip/tree/drivers/gpu/drm/arm/display/komeda/komeda_framebuffer.c#n60
                afbc_superblock_width = 32;
                afbc_superblock_height = 8;
> +		/* fall through */
> +	case AFBC_FORMAT_MOD_BLOCK_SIZE_64x4:
> +		/* fall through */
> +	case AFBC_FORMAT_MOD_BLOCK_SIZE_32x8_64x4:
> +		/* fall through */
> +	default:
> +		DRM_DEBUG_KMS("AFBC superblock size is not supported\n");
> +		return false;
> +	}
Can you combine the two switch - case confitions (from this function
and the one in drm_afbc_check_size_align()) and put it in a separate
function (say drm_afbc_get_superblock_dimensions()) of its own ?
This will help to avoid code repetition.

> +
> +	n_superblocks = (mode_cmd->width / afbc_superblock_width) *
> +		(mode_cmd->height / afbc_superblock_height);
> +
> +	afbc_superblock_size =
> +		(bpp * afbc_superblock_width * afbc_superblock_height)
> +			/ BITS_PER_BYTE;
> +
> +	afbc_size = ALIGN(n_superblocks * AFBC_HEADER_SIZE,
> +			  AFBC_SUPERBLK_ALIGNMENT);
> +	afbc_size += n_superblocks *
> +		ALIGN(afbc_superblock_size, AFBC_SUPERBLK_ALIGNMENT);
> +
> +	if ((mode_cmd->width * bpp) != (mode_cmd->pitches[0] * BITS_PER_BYTE)) {
> +		DRM_DEBUG_KMS("Invalid value of (pitch * BITS_PER_BYTE) (=%u) should be same as width (=%u) * bpp (=%u)\n",
> +			mode_cmd->pitches[0] * BITS_PER_BYTE,
> +			mode_cmd->width, bpp
> +		);
> +		return false;
> +	}
> +
> +	if (objs->size < afbc_size) {
> +		DRM_DEBUG_KMS("buffer size (%zu) too small for AFBC buffer size = %u\n",
> +			objs->size, afbc_size
> +		);
> +
> +		return false;
> +	}
> +
> +	return true;
> +}
> +EXPORT_SYMBOL(drm_afbc_check_fb_size);
> diff --git a/include/drm/drm_afbc.h b/include/drm/drm_afbc.h
> new file mode 100644
> index 000000000000..ce39c850217b
> --- /dev/null
> +++ b/include/drm/drm_afbc.h
> @@ -0,0 +1,25 @@
> +/* SPDX-License-Identifier: GPL-2.0+ */
> +/*
> + * (C) 2019 Collabora Ltd.
> + *
> + * author: Andrzej Pietrasiewicz <andrzej.p@collabora.com>
> + *
> + */
> +#ifndef __DRM_AFBC_H__
> +#define __DRM_AFBC_H__
> +
> +struct drm_device;
> +struct drm_mode_fb_cmd2;
> +struct drm_gem_object;
> +
> +bool drm_afbc_check_offset(struct drm_device *dev,
> +			   const struct drm_mode_fb_cmd2 *mode_cmd);
> +
> +bool drm_afbc_check_size_align(struct drm_device *dev,
> +			       const struct drm_mode_fb_cmd2 *mode_cmd);
> +
> +bool drm_afbc_check_fb_size(struct drm_device *dev,
> +			    const struct drm_mode_fb_cmd2 *mode_cmd,
> +			    struct drm_gem_object *objs, int bpp);
> +
> +#endif /* __DRM_AFBC_H__ */
> --
> 2.17.1
> 
> _______________________________________________
> dri-devel mailing list
> dri-devel@lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 63+ messages in thread

* Re: [PATCH 1/2] drm/arm: Factor out generic afbc helpers
@ 2019-10-21 13:50     ` Ayan Halder
  0 siblings, 0 replies; 63+ messages in thread
From: Ayan Halder @ 2019-10-21 13:50 UTC (permalink / raw)
  To: Andrzej Pietrasiewicz
  Cc: nd, kernel, David Airlie, Liviu Dudau, linux-kernel, dri-devel,
	linux-rockchip, james qian wang (Arm Technology China),
	Mihail Atanassov, Sean Paul, linux-arm-kernel

On Fri, Oct 11, 2019 at 01:18:10PM +0200, Andrzej Pietrasiewicz wrote:
> These are useful for other users of afbc, e.g. rockchip.
> 
> Signed-off-by: Andrzej Pietrasiewicz <andrzej.p@collabora.com>

Hi Andrzej,

Thanks a lot for doing this. Much appreciated. :)
It was on our TODO list for a long time.

I have cc-ed james.qian.wang@arm.com, Mihail.Atanassov@arm.com for
their comments as well.

> ---
>  drivers/gpu/drm/Kconfig          |   4 ++
>  drivers/gpu/drm/Makefile         |   1 +
>  drivers/gpu/drm/arm/Kconfig      |   1 +
>  drivers/gpu/drm/arm/malidp_drv.c |  58 ++--------------
>  drivers/gpu/drm/drm_afbc.c       | 114 +++++++++++++++++++++++++++++++
>  include/drm/drm_afbc.h           |  25 +++++++
>  6 files changed, 149 insertions(+), 54 deletions(-)
>  create mode 100644 drivers/gpu/drm/drm_afbc.c
>  create mode 100644 include/drm/drm_afbc.h
> 
> diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig
> index 3c88420e3497..00e3f90557f4 100644
> --- a/drivers/gpu/drm/Kconfig
> +++ b/drivers/gpu/drm/Kconfig
> @@ -195,6 +195,10 @@ config DRM_SCHED
>  	tristate
>  	depends on DRM
>  
> +config DRM_AFBC
> +	tristate
> +	depends on DRM
Adding a 'help' would be great here. Stealing the first line from
https://www.kernel.org/doc/html/latest/gpu/afbc.html

"AFBC is a proprietary lossless image compression protocol and format.
It provides fine-grained random access and minimizes the amount of
data transferred between IP blocks."

> +
>  source "drivers/gpu/drm/i2c/Kconfig"
>  
>  source "drivers/gpu/drm/arm/Kconfig"
> diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile
> index 9f0d2ee35794..55368b668355 100644
> --- a/drivers/gpu/drm/Makefile
> +++ b/drivers/gpu/drm/Makefile
> @@ -31,6 +31,7 @@ drm-$(CONFIG_OF) += drm_of.o
>  drm-$(CONFIG_AGP) += drm_agpsupport.o
>  drm-$(CONFIG_DEBUG_FS) += drm_debugfs.o drm_debugfs_crc.o
>  drm-$(CONFIG_DRM_LOAD_EDID_FIRMWARE) += drm_edid_load.o
> +drm-$(CONFIG_DRM_AFBC) += drm_afbc.o
>  
>  drm_vram_helper-y := drm_gem_vram_helper.o \
>  		     drm_vram_helper_common.o \
> diff --git a/drivers/gpu/drm/arm/Kconfig b/drivers/gpu/drm/arm/Kconfig
> index a204103b3efb..25c3dc408cda 100644
> --- a/drivers/gpu/drm/arm/Kconfig
> +++ b/drivers/gpu/drm/arm/Kconfig
> @@ -29,6 +29,7 @@ config DRM_MALI_DISPLAY
>  	select DRM_KMS_HELPER
>  	select DRM_KMS_CMA_HELPER
>  	select DRM_GEM_CMA_HELPER
> +	select DRM_AFBC
>  	select VIDEOMODE_HELPERS
>  	help
>  	  Choose this option if you want to compile the ARM Mali Display
> diff --git a/drivers/gpu/drm/arm/malidp_drv.c b/drivers/gpu/drm/arm/malidp_drv.c
> index f25ec4382277..a67b69e08f63 100644
> --- a/drivers/gpu/drm/arm/malidp_drv.c
> +++ b/drivers/gpu/drm/arm/malidp_drv.c
> @@ -16,6 +16,7 @@
>  #include <linux/debugfs.h>
>  
>  #include <drm/drmP.h>
> +#include <drm/drm_afbc.h>
>  #include <drm/drm_atomic.h>
>  #include <drm/drm_atomic_helper.h>
>  #include <drm/drm_crtc.h>
> @@ -33,8 +34,6 @@
>  #include "malidp_hw.h"
>  
>  #define MALIDP_CONF_VALID_TIMEOUT	250
> -#define AFBC_HEADER_SIZE		16
> -#define AFBC_SUPERBLK_ALIGNMENT		128
>  
>  static void malidp_write_gamma_table(struct malidp_hw_device *hwdev,
>  				     u32 data[MALIDP_COEFFTAB_NUM_COEFFS])
> @@ -275,24 +274,8 @@ malidp_verify_afbc_framebuffer_caps(struct drm_device *dev,
>  					mode_cmd->modifier[0]) == false)
>  		return false;
>  
> -	if (mode_cmd->offsets[0] != 0) {
> -		DRM_DEBUG_KMS("AFBC buffers' plane offset should be 0\n");
> -		return false;
> -	}
> -
> -	switch (mode_cmd->modifier[0] & AFBC_SIZE_MASK) {
> -	case AFBC_SIZE_16X16:
> -		if ((mode_cmd->width % 16) || (mode_cmd->height % 16)) {
> -			DRM_DEBUG_KMS("AFBC buffers must be aligned to 16 pixels\n");
> -			return false;
> -		}
> -		break;
> -	default:
> -		DRM_DEBUG_KMS("Unsupported AFBC block size\n");
> -		return false;
> -	}
> -
> -	return true;
> +	return drm_afbc_check_offset(dev, mode_cmd) &&
> +	       drm_afbc_check_size_align(dev, mode_cmd);
>  }
>  
>  static bool
> @@ -300,53 +283,20 @@ malidp_verify_afbc_framebuffer_size(struct drm_device *dev,
>  				    struct drm_file *file,
>  				    const struct drm_mode_fb_cmd2 *mode_cmd)
>  {
> -	int n_superblocks = 0;
>  	const struct drm_format_info *info;
>  	struct drm_gem_object *objs = NULL;
> -	u32 afbc_superblock_size = 0, afbc_superblock_height = 0;
> -	u32 afbc_superblock_width = 0, afbc_size = 0;
>  	int bpp = 0;
>  
> -	switch (mode_cmd->modifier[0] & AFBC_SIZE_MASK) {
> -	case AFBC_SIZE_16X16:
> -		afbc_superblock_height = 16;
> -		afbc_superblock_width = 16;
> -		break;
> -	default:
> -		DRM_DEBUG_KMS("AFBC superblock size is not supported\n");
> -		return false;
> -	}
> -
>  	info = drm_get_format_info(dev, mode_cmd);
> -
> -	n_superblocks = (mode_cmd->width / afbc_superblock_width) *
> -		(mode_cmd->height / afbc_superblock_height);
> -
>  	bpp = malidp_format_get_bpp(info->format);
>  
> -	afbc_superblock_size = (bpp * afbc_superblock_width * afbc_superblock_height)
> -				/ BITS_PER_BYTE;
> -
> -	afbc_size = ALIGN(n_superblocks * AFBC_HEADER_SIZE, AFBC_SUPERBLK_ALIGNMENT);
> -	afbc_size += n_superblocks * ALIGN(afbc_superblock_size, AFBC_SUPERBLK_ALIGNMENT);
> -
> -	if ((mode_cmd->width * bpp) != (mode_cmd->pitches[0] * BITS_PER_BYTE)) {
> -		DRM_DEBUG_KMS("Invalid value of (pitch * BITS_PER_BYTE) (=%u) "
> -			      "should be same as width (=%u) * bpp (=%u)\n",
> -			      (mode_cmd->pitches[0] * BITS_PER_BYTE),
> -			      mode_cmd->width, bpp);
> -		return false;
> -	}
> -
>  	objs = drm_gem_object_lookup(file, mode_cmd->handles[0]);
>  	if (!objs) {
>  		DRM_DEBUG_KMS("Failed to lookup GEM object\n");
>  		return false;
>  	}
>  
> -	if (objs->size < afbc_size) {
> -		DRM_DEBUG_KMS("buffer size (%zu) too small for AFBC buffer size = %u\n",
> -			      objs->size, afbc_size);
> +	if (!drm_afbc_check_fb_size(dev, mode_cmd, objs, bpp)) {
>  		drm_gem_object_put_unlocked(objs);
>  		return false;
>  	}
Also can you do the code refactoring for komeda driver as well.
specifically komeda_fb_afbc_size_check(). I will let
james.qian.wang@arm.com and Mihail.Atanassov@arm.com have their
opinion on this.

> diff --git a/drivers/gpu/drm/drm_afbc.c b/drivers/gpu/drm/drm_afbc.c
> new file mode 100644
> index 000000000000..3e8a9225fd2e
> --- /dev/null
> +++ b/drivers/gpu/drm/drm_afbc.c
> @@ -0,0 +1,114 @@
> +// SPDX-License-Identifier: GPL-2.0+
> +/*
> + * (C) 2019 Collabora Ltd.
> + *
> + * author: Andrzej Pietrasiewicz <andrzej.p@collabora.com>
> + *
> + */
> +#include <linux/module.h>
> +
> +#include <drm/drm_afbc.h>
> +#include <drm/drm_device.h>
> +#include <drm/drm_fourcc.h>
> +#include <drm/drm_gem.h>
> +#include <drm/drm_mode.h>
> +#include <drm/drm_print.h>
> +
> +#define AFBC_HEADER_SIZE		16
> +#define AFBC_SUPERBLK_ALIGNMENT		128
> +
> +bool drm_afbc_check_offset(struct drm_device *dev,
> +			   const struct drm_mode_fb_cmd2 *mode_cmd)
> +{
> +	if (mode_cmd->offsets[0] != 0) {
> +		DRM_DEBUG_KMS("AFBC buffers' plane offset should be 0\n");
> +		return false;
> +	}
> +
> +	return true;
> +}
> +EXPORT_SYMBOL_GPL(drm_afbc_check_offset);
> +
> +bool drm_afbc_check_size_align(struct drm_device *dev,
> +			       const struct drm_mode_fb_cmd2 *mode_cmd)
> +{
> +
> +	switch (mode_cmd->modifier[0] & AFBC_FORMAT_MOD_BLOCK_SIZE_MASK) {
> +	case AFBC_FORMAT_MOD_BLOCK_SIZE_16x16:
> +		if ((mode_cmd->width % 16) || (mode_cmd->height % 16)) {
> +			DRM_DEBUG_KMS(
> +				"AFBC buffer must be aligned to 16 pixels\n"
> +			);
> +			return false;
> +		}
> +		break;
> +	case AFBC_FORMAT_MOD_BLOCK_SIZE_32x8:
> +		/* fall through */
> +	case AFBC_FORMAT_MOD_BLOCK_SIZE_64x4:
> +		/* fall through */
> +	case AFBC_FORMAT_MOD_BLOCK_SIZE_32x8_64x4:
> +		/* fall through */
> +	default:
> +		DRM_DEBUG_KMS("Unsupported AFBC block size\n");
> +		return false;
> +	}
> +
> +	return true;
> +}
> +EXPORT_SYMBOL_GPL(drm_afbc_check_size_align);
> +
> +bool drm_afbc_check_fb_size(struct drm_device *dev,
> +			    const struct drm_mode_fb_cmd2 *mode_cmd,
> +			    struct drm_gem_object *objs, int bpp)
> +{
> +	int n_superblocks = 0;
> +	u32 afbc_superblock_size = 0, afbc_superblock_height = 0;
> +	u32 afbc_superblock_width = 0, afbc_size = 0;
> +
> +	switch (mode_cmd->modifier[0] & AFBC_FORMAT_MOD_BLOCK_SIZE_MASK) {
> +	case AFBC_FORMAT_MOD_BLOCK_SIZE_16x16:
> +		afbc_superblock_height = 16;
> +		afbc_superblock_width = 16;
> +		break;
> +	case AFBC_FORMAT_MOD_BLOCK_SIZE_32x8:
Copying from
https://cgit.freedesktop.org/drm/drm-tip/tree/drivers/gpu/drm/arm/display/komeda/komeda_framebuffer.c#n60
                afbc_superblock_width = 32;
                afbc_superblock_height = 8;
> +		/* fall through */
> +	case AFBC_FORMAT_MOD_BLOCK_SIZE_64x4:
> +		/* fall through */
> +	case AFBC_FORMAT_MOD_BLOCK_SIZE_32x8_64x4:
> +		/* fall through */
> +	default:
> +		DRM_DEBUG_KMS("AFBC superblock size is not supported\n");
> +		return false;
> +	}
Can you combine the two switch - case confitions (from this function
and the one in drm_afbc_check_size_align()) and put it in a separate
function (say drm_afbc_get_superblock_dimensions()) of its own ?
This will help to avoid code repetition.

> +
> +	n_superblocks = (mode_cmd->width / afbc_superblock_width) *
> +		(mode_cmd->height / afbc_superblock_height);
> +
> +	afbc_superblock_size =
> +		(bpp * afbc_superblock_width * afbc_superblock_height)
> +			/ BITS_PER_BYTE;
> +
> +	afbc_size = ALIGN(n_superblocks * AFBC_HEADER_SIZE,
> +			  AFBC_SUPERBLK_ALIGNMENT);
> +	afbc_size += n_superblocks *
> +		ALIGN(afbc_superblock_size, AFBC_SUPERBLK_ALIGNMENT);
> +
> +	if ((mode_cmd->width * bpp) != (mode_cmd->pitches[0] * BITS_PER_BYTE)) {
> +		DRM_DEBUG_KMS("Invalid value of (pitch * BITS_PER_BYTE) (=%u) should be same as width (=%u) * bpp (=%u)\n",
> +			mode_cmd->pitches[0] * BITS_PER_BYTE,
> +			mode_cmd->width, bpp
> +		);
> +		return false;
> +	}
> +
> +	if (objs->size < afbc_size) {
> +		DRM_DEBUG_KMS("buffer size (%zu) too small for AFBC buffer size = %u\n",
> +			objs->size, afbc_size
> +		);
> +
> +		return false;
> +	}
> +
> +	return true;
> +}
> +EXPORT_SYMBOL(drm_afbc_check_fb_size);
> diff --git a/include/drm/drm_afbc.h b/include/drm/drm_afbc.h
> new file mode 100644
> index 000000000000..ce39c850217b
> --- /dev/null
> +++ b/include/drm/drm_afbc.h
> @@ -0,0 +1,25 @@
> +/* SPDX-License-Identifier: GPL-2.0+ */
> +/*
> + * (C) 2019 Collabora Ltd.
> + *
> + * author: Andrzej Pietrasiewicz <andrzej.p@collabora.com>
> + *
> + */
> +#ifndef __DRM_AFBC_H__
> +#define __DRM_AFBC_H__
> +
> +struct drm_device;
> +struct drm_mode_fb_cmd2;
> +struct drm_gem_object;
> +
> +bool drm_afbc_check_offset(struct drm_device *dev,
> +			   const struct drm_mode_fb_cmd2 *mode_cmd);
> +
> +bool drm_afbc_check_size_align(struct drm_device *dev,
> +			       const struct drm_mode_fb_cmd2 *mode_cmd);
> +
> +bool drm_afbc_check_fb_size(struct drm_device *dev,
> +			    const struct drm_mode_fb_cmd2 *mode_cmd,
> +			    struct drm_gem_object *objs, int bpp);
> +
> +#endif /* __DRM_AFBC_H__ */
> --
> 2.17.1
> 
> _______________________________________________
> dri-devel mailing list
> dri-devel@lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/dri-devel
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 63+ messages in thread

* Re: [PATCH 1/2] drm/arm: Factor out generic afbc helpers
@ 2019-10-21 13:50     ` Ayan Halder
  0 siblings, 0 replies; 63+ messages in thread
From: Ayan Halder @ 2019-10-21 13:50 UTC (permalink / raw)
  To: Andrzej Pietrasiewicz
  Cc: nd, kernel, David Airlie, Liviu Dudau, linux-kernel, dri-devel,
	linux-rockchip, james qian wang (Arm Technology China),
	Mihail Atanassov, Sean Paul, linux-arm-kernel

On Fri, Oct 11, 2019 at 01:18:10PM +0200, Andrzej Pietrasiewicz wrote:
> These are useful for other users of afbc, e.g. rockchip.
> 
> Signed-off-by: Andrzej Pietrasiewicz <andrzej.p@collabora.com>

Hi Andrzej,

Thanks a lot for doing this. Much appreciated. :)
It was on our TODO list for a long time.

I have cc-ed james.qian.wang@arm.com, Mihail.Atanassov@arm.com for
their comments as well.

> ---
>  drivers/gpu/drm/Kconfig          |   4 ++
>  drivers/gpu/drm/Makefile         |   1 +
>  drivers/gpu/drm/arm/Kconfig      |   1 +
>  drivers/gpu/drm/arm/malidp_drv.c |  58 ++--------------
>  drivers/gpu/drm/drm_afbc.c       | 114 +++++++++++++++++++++++++++++++
>  include/drm/drm_afbc.h           |  25 +++++++
>  6 files changed, 149 insertions(+), 54 deletions(-)
>  create mode 100644 drivers/gpu/drm/drm_afbc.c
>  create mode 100644 include/drm/drm_afbc.h
> 
> diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig
> index 3c88420e3497..00e3f90557f4 100644
> --- a/drivers/gpu/drm/Kconfig
> +++ b/drivers/gpu/drm/Kconfig
> @@ -195,6 +195,10 @@ config DRM_SCHED
>  	tristate
>  	depends on DRM
>  
> +config DRM_AFBC
> +	tristate
> +	depends on DRM
Adding a 'help' would be great here. Stealing the first line from
https://www.kernel.org/doc/html/latest/gpu/afbc.html

"AFBC is a proprietary lossless image compression protocol and format.
It provides fine-grained random access and minimizes the amount of
data transferred between IP blocks."

> +
>  source "drivers/gpu/drm/i2c/Kconfig"
>  
>  source "drivers/gpu/drm/arm/Kconfig"
> diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile
> index 9f0d2ee35794..55368b668355 100644
> --- a/drivers/gpu/drm/Makefile
> +++ b/drivers/gpu/drm/Makefile
> @@ -31,6 +31,7 @@ drm-$(CONFIG_OF) += drm_of.o
>  drm-$(CONFIG_AGP) += drm_agpsupport.o
>  drm-$(CONFIG_DEBUG_FS) += drm_debugfs.o drm_debugfs_crc.o
>  drm-$(CONFIG_DRM_LOAD_EDID_FIRMWARE) += drm_edid_load.o
> +drm-$(CONFIG_DRM_AFBC) += drm_afbc.o
>  
>  drm_vram_helper-y := drm_gem_vram_helper.o \
>  		     drm_vram_helper_common.o \
> diff --git a/drivers/gpu/drm/arm/Kconfig b/drivers/gpu/drm/arm/Kconfig
> index a204103b3efb..25c3dc408cda 100644
> --- a/drivers/gpu/drm/arm/Kconfig
> +++ b/drivers/gpu/drm/arm/Kconfig
> @@ -29,6 +29,7 @@ config DRM_MALI_DISPLAY
>  	select DRM_KMS_HELPER
>  	select DRM_KMS_CMA_HELPER
>  	select DRM_GEM_CMA_HELPER
> +	select DRM_AFBC
>  	select VIDEOMODE_HELPERS
>  	help
>  	  Choose this option if you want to compile the ARM Mali Display
> diff --git a/drivers/gpu/drm/arm/malidp_drv.c b/drivers/gpu/drm/arm/malidp_drv.c
> index f25ec4382277..a67b69e08f63 100644
> --- a/drivers/gpu/drm/arm/malidp_drv.c
> +++ b/drivers/gpu/drm/arm/malidp_drv.c
> @@ -16,6 +16,7 @@
>  #include <linux/debugfs.h>
>  
>  #include <drm/drmP.h>
> +#include <drm/drm_afbc.h>
>  #include <drm/drm_atomic.h>
>  #include <drm/drm_atomic_helper.h>
>  #include <drm/drm_crtc.h>
> @@ -33,8 +34,6 @@
>  #include "malidp_hw.h"
>  
>  #define MALIDP_CONF_VALID_TIMEOUT	250
> -#define AFBC_HEADER_SIZE		16
> -#define AFBC_SUPERBLK_ALIGNMENT		128
>  
>  static void malidp_write_gamma_table(struct malidp_hw_device *hwdev,
>  				     u32 data[MALIDP_COEFFTAB_NUM_COEFFS])
> @@ -275,24 +274,8 @@ malidp_verify_afbc_framebuffer_caps(struct drm_device *dev,
>  					mode_cmd->modifier[0]) == false)
>  		return false;
>  
> -	if (mode_cmd->offsets[0] != 0) {
> -		DRM_DEBUG_KMS("AFBC buffers' plane offset should be 0\n");
> -		return false;
> -	}
> -
> -	switch (mode_cmd->modifier[0] & AFBC_SIZE_MASK) {
> -	case AFBC_SIZE_16X16:
> -		if ((mode_cmd->width % 16) || (mode_cmd->height % 16)) {
> -			DRM_DEBUG_KMS("AFBC buffers must be aligned to 16 pixels\n");
> -			return false;
> -		}
> -		break;
> -	default:
> -		DRM_DEBUG_KMS("Unsupported AFBC block size\n");
> -		return false;
> -	}
> -
> -	return true;
> +	return drm_afbc_check_offset(dev, mode_cmd) &&
> +	       drm_afbc_check_size_align(dev, mode_cmd);
>  }
>  
>  static bool
> @@ -300,53 +283,20 @@ malidp_verify_afbc_framebuffer_size(struct drm_device *dev,
>  				    struct drm_file *file,
>  				    const struct drm_mode_fb_cmd2 *mode_cmd)
>  {
> -	int n_superblocks = 0;
>  	const struct drm_format_info *info;
>  	struct drm_gem_object *objs = NULL;
> -	u32 afbc_superblock_size = 0, afbc_superblock_height = 0;
> -	u32 afbc_superblock_width = 0, afbc_size = 0;
>  	int bpp = 0;
>  
> -	switch (mode_cmd->modifier[0] & AFBC_SIZE_MASK) {
> -	case AFBC_SIZE_16X16:
> -		afbc_superblock_height = 16;
> -		afbc_superblock_width = 16;
> -		break;
> -	default:
> -		DRM_DEBUG_KMS("AFBC superblock size is not supported\n");
> -		return false;
> -	}
> -
>  	info = drm_get_format_info(dev, mode_cmd);
> -
> -	n_superblocks = (mode_cmd->width / afbc_superblock_width) *
> -		(mode_cmd->height / afbc_superblock_height);
> -
>  	bpp = malidp_format_get_bpp(info->format);
>  
> -	afbc_superblock_size = (bpp * afbc_superblock_width * afbc_superblock_height)
> -				/ BITS_PER_BYTE;
> -
> -	afbc_size = ALIGN(n_superblocks * AFBC_HEADER_SIZE, AFBC_SUPERBLK_ALIGNMENT);
> -	afbc_size += n_superblocks * ALIGN(afbc_superblock_size, AFBC_SUPERBLK_ALIGNMENT);
> -
> -	if ((mode_cmd->width * bpp) != (mode_cmd->pitches[0] * BITS_PER_BYTE)) {
> -		DRM_DEBUG_KMS("Invalid value of (pitch * BITS_PER_BYTE) (=%u) "
> -			      "should be same as width (=%u) * bpp (=%u)\n",
> -			      (mode_cmd->pitches[0] * BITS_PER_BYTE),
> -			      mode_cmd->width, bpp);
> -		return false;
> -	}
> -
>  	objs = drm_gem_object_lookup(file, mode_cmd->handles[0]);
>  	if (!objs) {
>  		DRM_DEBUG_KMS("Failed to lookup GEM object\n");
>  		return false;
>  	}
>  
> -	if (objs->size < afbc_size) {
> -		DRM_DEBUG_KMS("buffer size (%zu) too small for AFBC buffer size = %u\n",
> -			      objs->size, afbc_size);
> +	if (!drm_afbc_check_fb_size(dev, mode_cmd, objs, bpp)) {
>  		drm_gem_object_put_unlocked(objs);
>  		return false;
>  	}
Also can you do the code refactoring for komeda driver as well.
specifically komeda_fb_afbc_size_check(). I will let
james.qian.wang@arm.com and Mihail.Atanassov@arm.com have their
opinion on this.

> diff --git a/drivers/gpu/drm/drm_afbc.c b/drivers/gpu/drm/drm_afbc.c
> new file mode 100644
> index 000000000000..3e8a9225fd2e
> --- /dev/null
> +++ b/drivers/gpu/drm/drm_afbc.c
> @@ -0,0 +1,114 @@
> +// SPDX-License-Identifier: GPL-2.0+
> +/*
> + * (C) 2019 Collabora Ltd.
> + *
> + * author: Andrzej Pietrasiewicz <andrzej.p@collabora.com>
> + *
> + */
> +#include <linux/module.h>
> +
> +#include <drm/drm_afbc.h>
> +#include <drm/drm_device.h>
> +#include <drm/drm_fourcc.h>
> +#include <drm/drm_gem.h>
> +#include <drm/drm_mode.h>
> +#include <drm/drm_print.h>
> +
> +#define AFBC_HEADER_SIZE		16
> +#define AFBC_SUPERBLK_ALIGNMENT		128
> +
> +bool drm_afbc_check_offset(struct drm_device *dev,
> +			   const struct drm_mode_fb_cmd2 *mode_cmd)
> +{
> +	if (mode_cmd->offsets[0] != 0) {
> +		DRM_DEBUG_KMS("AFBC buffers' plane offset should be 0\n");
> +		return false;
> +	}
> +
> +	return true;
> +}
> +EXPORT_SYMBOL_GPL(drm_afbc_check_offset);
> +
> +bool drm_afbc_check_size_align(struct drm_device *dev,
> +			       const struct drm_mode_fb_cmd2 *mode_cmd)
> +{
> +
> +	switch (mode_cmd->modifier[0] & AFBC_FORMAT_MOD_BLOCK_SIZE_MASK) {
> +	case AFBC_FORMAT_MOD_BLOCK_SIZE_16x16:
> +		if ((mode_cmd->width % 16) || (mode_cmd->height % 16)) {
> +			DRM_DEBUG_KMS(
> +				"AFBC buffer must be aligned to 16 pixels\n"
> +			);
> +			return false;
> +		}
> +		break;
> +	case AFBC_FORMAT_MOD_BLOCK_SIZE_32x8:
> +		/* fall through */
> +	case AFBC_FORMAT_MOD_BLOCK_SIZE_64x4:
> +		/* fall through */
> +	case AFBC_FORMAT_MOD_BLOCK_SIZE_32x8_64x4:
> +		/* fall through */
> +	default:
> +		DRM_DEBUG_KMS("Unsupported AFBC block size\n");
> +		return false;
> +	}
> +
> +	return true;
> +}
> +EXPORT_SYMBOL_GPL(drm_afbc_check_size_align);
> +
> +bool drm_afbc_check_fb_size(struct drm_device *dev,
> +			    const struct drm_mode_fb_cmd2 *mode_cmd,
> +			    struct drm_gem_object *objs, int bpp)
> +{
> +	int n_superblocks = 0;
> +	u32 afbc_superblock_size = 0, afbc_superblock_height = 0;
> +	u32 afbc_superblock_width = 0, afbc_size = 0;
> +
> +	switch (mode_cmd->modifier[0] & AFBC_FORMAT_MOD_BLOCK_SIZE_MASK) {
> +	case AFBC_FORMAT_MOD_BLOCK_SIZE_16x16:
> +		afbc_superblock_height = 16;
> +		afbc_superblock_width = 16;
> +		break;
> +	case AFBC_FORMAT_MOD_BLOCK_SIZE_32x8:
Copying from
https://cgit.freedesktop.org/drm/drm-tip/tree/drivers/gpu/drm/arm/display/komeda/komeda_framebuffer.c#n60
                afbc_superblock_width = 32;
                afbc_superblock_height = 8;
> +		/* fall through */
> +	case AFBC_FORMAT_MOD_BLOCK_SIZE_64x4:
> +		/* fall through */
> +	case AFBC_FORMAT_MOD_BLOCK_SIZE_32x8_64x4:
> +		/* fall through */
> +	default:
> +		DRM_DEBUG_KMS("AFBC superblock size is not supported\n");
> +		return false;
> +	}
Can you combine the two switch - case confitions (from this function
and the one in drm_afbc_check_size_align()) and put it in a separate
function (say drm_afbc_get_superblock_dimensions()) of its own ?
This will help to avoid code repetition.

> +
> +	n_superblocks = (mode_cmd->width / afbc_superblock_width) *
> +		(mode_cmd->height / afbc_superblock_height);
> +
> +	afbc_superblock_size =
> +		(bpp * afbc_superblock_width * afbc_superblock_height)
> +			/ BITS_PER_BYTE;
> +
> +	afbc_size = ALIGN(n_superblocks * AFBC_HEADER_SIZE,
> +			  AFBC_SUPERBLK_ALIGNMENT);
> +	afbc_size += n_superblocks *
> +		ALIGN(afbc_superblock_size, AFBC_SUPERBLK_ALIGNMENT);
> +
> +	if ((mode_cmd->width * bpp) != (mode_cmd->pitches[0] * BITS_PER_BYTE)) {
> +		DRM_DEBUG_KMS("Invalid value of (pitch * BITS_PER_BYTE) (=%u) should be same as width (=%u) * bpp (=%u)\n",
> +			mode_cmd->pitches[0] * BITS_PER_BYTE,
> +			mode_cmd->width, bpp
> +		);
> +		return false;
> +	}
> +
> +	if (objs->size < afbc_size) {
> +		DRM_DEBUG_KMS("buffer size (%zu) too small for AFBC buffer size = %u\n",
> +			objs->size, afbc_size
> +		);
> +
> +		return false;
> +	}
> +
> +	return true;
> +}
> +EXPORT_SYMBOL(drm_afbc_check_fb_size);
> diff --git a/include/drm/drm_afbc.h b/include/drm/drm_afbc.h
> new file mode 100644
> index 000000000000..ce39c850217b
> --- /dev/null
> +++ b/include/drm/drm_afbc.h
> @@ -0,0 +1,25 @@
> +/* SPDX-License-Identifier: GPL-2.0+ */
> +/*
> + * (C) 2019 Collabora Ltd.
> + *
> + * author: Andrzej Pietrasiewicz <andrzej.p@collabora.com>
> + *
> + */
> +#ifndef __DRM_AFBC_H__
> +#define __DRM_AFBC_H__
> +
> +struct drm_device;
> +struct drm_mode_fb_cmd2;
> +struct drm_gem_object;
> +
> +bool drm_afbc_check_offset(struct drm_device *dev,
> +			   const struct drm_mode_fb_cmd2 *mode_cmd);
> +
> +bool drm_afbc_check_size_align(struct drm_device *dev,
> +			       const struct drm_mode_fb_cmd2 *mode_cmd);
> +
> +bool drm_afbc_check_fb_size(struct drm_device *dev,
> +			    const struct drm_mode_fb_cmd2 *mode_cmd,
> +			    struct drm_gem_object *objs, int bpp);
> +
> +#endif /* __DRM_AFBC_H__ */
> --
> 2.17.1
> 
> _______________________________________________
> dri-devel mailing list
> dri-devel@lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/dri-devel

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 63+ messages in thread

* Re: [PATCH 1/2] drm/arm: Factor out generic afbc helpers
  2019-10-21 13:50     ` Ayan Halder
  (?)
@ 2019-10-21 14:41       ` Mihail Atanassov
  -1 siblings, 0 replies; 63+ messages in thread
From: Mihail Atanassov @ 2019-10-21 14:41 UTC (permalink / raw)
  To: Ayan Halder
  Cc: Andrzej Pietrasiewicz, dri-devel, David Airlie, Liviu Dudau,
	james qian wang (Arm Technology China),
	linux-rockchip, linux-arm-kernel, kernel, Sean Paul,
	linux-kernel, nd

Hi Andrzej,

On Monday, 21 October 2019 14:50:14 BST Ayan Halder wrote:
> On Fri, Oct 11, 2019 at 01:18:10PM +0200, Andrzej Pietrasiewicz wrote:
> > These are useful for other users of afbc, e.g. rockchip.
> > 
> > Signed-off-by: Andrzej Pietrasiewicz <andrzej.p@collabora.com>
> 
> Hi Andrzej,
> 
> Thanks a lot for doing this. Much appreciated. :)
> It was on our TODO list for a long time.

Seconded, thanks for the patch!

> 
> I have cc-ed james.qian.wang@arm.com, Mihail.Atanassov@arm.com for
> their comments as well.
> 
> > ---
> >  drivers/gpu/drm/Kconfig          |   4 ++
> >  drivers/gpu/drm/Makefile         |   1 +
> >  drivers/gpu/drm/arm/Kconfig      |   1 +
> >  drivers/gpu/drm/arm/malidp_drv.c |  58 ++--------------
> >  drivers/gpu/drm/drm_afbc.c       | 114 +++++++++++++++++++++++++++++++
> >  include/drm/drm_afbc.h           |  25 +++++++
> >  6 files changed, 149 insertions(+), 54 deletions(-)
> >  create mode 100644 drivers/gpu/drm/drm_afbc.c
> >  create mode 100644 include/drm/drm_afbc.h
> > 
> > diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig
> > index 3c88420e3497..00e3f90557f4 100644
> > --- a/drivers/gpu/drm/Kconfig
> > +++ b/drivers/gpu/drm/Kconfig
> > @@ -195,6 +195,10 @@ config DRM_SCHED
> >  	tristate
> >  	depends on DRM
> >  
> > +config DRM_AFBC
> > +	tristate
> > +	depends on DRM
> Adding a 'help' would be great here. Stealing the first line from
> https://www.kernel.org/doc/html/latest/gpu/afbc.html
> 
> "AFBC is a proprietary lossless image compression protocol and format.
> It provides fine-grained random access and minimizes the amount of
> data transferred between IP blocks."
> 
> > +
> >  source "drivers/gpu/drm/i2c/Kconfig"
> >  
> >  source "drivers/gpu/drm/arm/Kconfig"
> > diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile
> > index 9f0d2ee35794..55368b668355 100644
> > --- a/drivers/gpu/drm/Makefile
> > +++ b/drivers/gpu/drm/Makefile
> > @@ -31,6 +31,7 @@ drm-$(CONFIG_OF) += drm_of.o
> >  drm-$(CONFIG_AGP) += drm_agpsupport.o
> >  drm-$(CONFIG_DEBUG_FS) += drm_debugfs.o drm_debugfs_crc.o
> >  drm-$(CONFIG_DRM_LOAD_EDID_FIRMWARE) += drm_edid_load.o
> > +drm-$(CONFIG_DRM_AFBC) += drm_afbc.o
> >  
> >  drm_vram_helper-y := drm_gem_vram_helper.o \
> >  		     drm_vram_helper_common.o \
> > diff --git a/drivers/gpu/drm/arm/Kconfig b/drivers/gpu/drm/arm/Kconfig
> > index a204103b3efb..25c3dc408cda 100644
> > --- a/drivers/gpu/drm/arm/Kconfig
> > +++ b/drivers/gpu/drm/arm/Kconfig
> > @@ -29,6 +29,7 @@ config DRM_MALI_DISPLAY
> >  	select DRM_KMS_HELPER
> >  	select DRM_KMS_CMA_HELPER
> >  	select DRM_GEM_CMA_HELPER
> > +	select DRM_AFBC
> >  	select VIDEOMODE_HELPERS
> >  	help
> >  	  Choose this option if you want to compile the ARM Mali Display
> > diff --git a/drivers/gpu/drm/arm/malidp_drv.c b/drivers/gpu/drm/arm/malidp_drv.c
> > index f25ec4382277..a67b69e08f63 100644
> > --- a/drivers/gpu/drm/arm/malidp_drv.c
> > +++ b/drivers/gpu/drm/arm/malidp_drv.c

This file is GPL-2.0-only. Shouldn't this be preserved when the
substantive bit of the code in drm_afbc.c comes from here?

> > @@ -16,6 +16,7 @@
> >  #include <linux/debugfs.h>
> >  
> >  #include <drm/drmP.h>
> > +#include <drm/drm_afbc.h>
> >  #include <drm/drm_atomic.h>
> >  #include <drm/drm_atomic_helper.h>
> >  #include <drm/drm_crtc.h>
> > @@ -33,8 +34,6 @@
> >  #include "malidp_hw.h"
> >  
> >  #define MALIDP_CONF_VALID_TIMEOUT	250
> > -#define AFBC_HEADER_SIZE		16
> > -#define AFBC_SUPERBLK_ALIGNMENT		128
> >  
> >  static void malidp_write_gamma_table(struct malidp_hw_device *hwdev,
> >  				     u32 data[MALIDP_COEFFTAB_NUM_COEFFS])
> > @@ -275,24 +274,8 @@ malidp_verify_afbc_framebuffer_caps(struct drm_device *dev,
> >  					mode_cmd->modifier[0]) == false)
> >  		return false;
> >  
> > -	if (mode_cmd->offsets[0] != 0) {
> > -		DRM_DEBUG_KMS("AFBC buffers' plane offset should be 0\n");
> > -		return false;
> > -	}
> > -
> > -	switch (mode_cmd->modifier[0] & AFBC_SIZE_MASK) {
> > -	case AFBC_SIZE_16X16:
> > -		if ((mode_cmd->width % 16) || (mode_cmd->height % 16)) {
> > -			DRM_DEBUG_KMS("AFBC buffers must be aligned to 16 pixels\n");
> > -			return false;
> > -		}
> > -		break;
> > -	default:
> > -		DRM_DEBUG_KMS("Unsupported AFBC block size\n");
> > -		return false;
> > -	}
> > -
> > -	return true;
> > +	return drm_afbc_check_offset(dev, mode_cmd) &&
> > +	       drm_afbc_check_size_align(dev, mode_cmd);
> >  }
> >  
> >  static bool
> > @@ -300,53 +283,20 @@ malidp_verify_afbc_framebuffer_size(struct drm_device *dev,
> >  				    struct drm_file *file,
> >  				    const struct drm_mode_fb_cmd2 *mode_cmd)
> >  {
> > -	int n_superblocks = 0;
> >  	const struct drm_format_info *info;
> >  	struct drm_gem_object *objs = NULL;
> > -	u32 afbc_superblock_size = 0, afbc_superblock_height = 0;
> > -	u32 afbc_superblock_width = 0, afbc_size = 0;
> >  	int bpp = 0;
> >  
> > -	switch (mode_cmd->modifier[0] & AFBC_SIZE_MASK) {
> > -	case AFBC_SIZE_16X16:
> > -		afbc_superblock_height = 16;
> > -		afbc_superblock_width = 16;
> > -		break;
> > -	default:
> > -		DRM_DEBUG_KMS("AFBC superblock size is not supported\n");
> > -		return false;
> > -	}
> > -
> >  	info = drm_get_format_info(dev, mode_cmd);
> > -
> > -	n_superblocks = (mode_cmd->width / afbc_superblock_width) *
> > -		(mode_cmd->height / afbc_superblock_height);
> > -
> >  	bpp = malidp_format_get_bpp(info->format);
> >  
> > -	afbc_superblock_size = (bpp * afbc_superblock_width * afbc_superblock_height)
> > -				/ BITS_PER_BYTE;
> > -
> > -	afbc_size = ALIGN(n_superblocks * AFBC_HEADER_SIZE, AFBC_SUPERBLK_ALIGNMENT);
> > -	afbc_size += n_superblocks * ALIGN(afbc_superblock_size, AFBC_SUPERBLK_ALIGNMENT);
> > -
> > -	if ((mode_cmd->width * bpp) != (mode_cmd->pitches[0] * BITS_PER_BYTE)) {
> > -		DRM_DEBUG_KMS("Invalid value of (pitch * BITS_PER_BYTE) (=%u) "
> > -			      "should be same as width (=%u) * bpp (=%u)\n",
> > -			      (mode_cmd->pitches[0] * BITS_PER_BYTE),
> > -			      mode_cmd->width, bpp);
> > -		return false;
> > -	}
> > -
> >  	objs = drm_gem_object_lookup(file, mode_cmd->handles[0]);
> >  	if (!objs) {
> >  		DRM_DEBUG_KMS("Failed to lookup GEM object\n");
> >  		return false;
> >  	}
> >  
> > -	if (objs->size < afbc_size) {
> > -		DRM_DEBUG_KMS("buffer size (%zu) too small for AFBC buffer size = %u\n",
> > -			      objs->size, afbc_size);
> > +	if (!drm_afbc_check_fb_size(dev, mode_cmd, objs, bpp)) {
> >  		drm_gem_object_put_unlocked(objs);
> >  		return false;
> >  	}
> Also can you do the code refactoring for komeda driver as well.
> specifically komeda_fb_afbc_size_check(). I will let
> james.qian.wang@arm.com and Mihail.Atanassov@arm.com have their
> opinion on this.

I'd say that it'd be really nice to get this work done for us ;)
but it doesn't have to be in this patch but rather in a follow-up.

> 
> > diff --git a/drivers/gpu/drm/drm_afbc.c b/drivers/gpu/drm/drm_afbc.c
> > new file mode 100644
> > index 000000000000..3e8a9225fd2e
> > --- /dev/null
> > +++ b/drivers/gpu/drm/drm_afbc.c
> > @@ -0,0 +1,114 @@
> > +// SPDX-License-Identifier: GPL-2.0+
> > +/*
> > + * (C) 2019 Collabora Ltd.
> > + *
> > + * author: Andrzej Pietrasiewicz <andrzej.p@collabora.com>
> > + *
> > + */
> > +#include <linux/module.h>
> > +
> > +#include <drm/drm_afbc.h>
> > +#include <drm/drm_device.h>
> > +#include <drm/drm_fourcc.h>
> > +#include <drm/drm_gem.h>
> > +#include <drm/drm_mode.h>
> > +#include <drm/drm_print.h>
> > +
> > +#define AFBC_HEADER_SIZE		16
> > +#define AFBC_SUPERBLK_ALIGNMENT		128
> > +
> > +bool drm_afbc_check_offset(struct drm_device *dev,
> > +			   const struct drm_mode_fb_cmd2 *mode_cmd)
> > +{
> > +	if (mode_cmd->offsets[0] != 0) {
> > +		DRM_DEBUG_KMS("AFBC buffers' plane offset should be 0\n");
> > +		return false;
> > +	}
> > +
> > +	return true;
> > +}
> > +EXPORT_SYMBOL_GPL(drm_afbc_check_offset);
> > +
> > +bool drm_afbc_check_size_align(struct drm_device *dev,
> > +			       const struct drm_mode_fb_cmd2 *mode_cmd)
> > +{
> > +
> > +	switch (mode_cmd->modifier[0] & AFBC_FORMAT_MOD_BLOCK_SIZE_MASK) {
> > +	case AFBC_FORMAT_MOD_BLOCK_SIZE_16x16:
> > +		if ((mode_cmd->width % 16) || (mode_cmd->height % 16)) {
> > +			DRM_DEBUG_KMS(
> > +				"AFBC buffer must be aligned to 16 pixels\n"
> > +			);
> > +			return false;
> > +		}
> > +		break;
> > +	case AFBC_FORMAT_MOD_BLOCK_SIZE_32x8:
> > +		/* fall through */
> > +	case AFBC_FORMAT_MOD_BLOCK_SIZE_64x4:
> > +		/* fall through */
> > +	case AFBC_FORMAT_MOD_BLOCK_SIZE_32x8_64x4:
> > +		/* fall through */
> > +	default:
> > +		DRM_DEBUG_KMS("Unsupported AFBC block size\n");
> > +		return false;
> > +	}
> > +
> > +	return true;
> > +}
> > +EXPORT_SYMBOL_GPL(drm_afbc_check_size_align);
> > +
> > +bool drm_afbc_check_fb_size(struct drm_device *dev,
> > +			    const struct drm_mode_fb_cmd2 *mode_cmd,
> > +			    struct drm_gem_object *objs, int bpp)
> > +{
> > +	int n_superblocks = 0;
> > +	u32 afbc_superblock_size = 0, afbc_superblock_height = 0;
> > +	u32 afbc_superblock_width = 0, afbc_size = 0;
> > +
> > +	switch (mode_cmd->modifier[0] & AFBC_FORMAT_MOD_BLOCK_SIZE_MASK) {
> > +	case AFBC_FORMAT_MOD_BLOCK_SIZE_16x16:
> > +		afbc_superblock_height = 16;
> > +		afbc_superblock_width = 16;
> > +		break;
> > +	case AFBC_FORMAT_MOD_BLOCK_SIZE_32x8:
> Copying from
> https://cgit.freedesktop.org/drm/drm-tip/tree/drivers/gpu/drm/arm/display/komeda/komeda_framebuffer.c#n60
>                 afbc_superblock_width = 32;
>                 afbc_superblock_height = 8;
> > +		/* fall through */
> > +	case AFBC_FORMAT_MOD_BLOCK_SIZE_64x4:
> > +		/* fall through */
> > +	case AFBC_FORMAT_MOD_BLOCK_SIZE_32x8_64x4:
> > +		/* fall through */
> > +	default:
> > +		DRM_DEBUG_KMS("AFBC superblock size is not supported\n");
> > +		return false;
> > +	}
> Can you combine the two switch - case confitions (from this function
> and the one in drm_afbc_check_size_align()) and put it in a separate
> function (say drm_afbc_get_superblock_dimensions()) of its own ?
> This will help to avoid code repetition.
> 

I'm personally a bit on the fence about this - functions should ideally
do one thing. That shared helper would be both getting the dimensions
_and_ checking the mode_cmd is valid, so one place cares about one half
of the function's results, and the other - the second half. ¯\_O_/¯,
opinions, everybody has them :).

> > +
> > +	n_superblocks = (mode_cmd->width / afbc_superblock_width) *
> > +		(mode_cmd->height / afbc_superblock_height);
> > +
> > +	afbc_superblock_size =
> > +		(bpp * afbc_superblock_width * afbc_superblock_height)
> > +			/ BITS_PER_BYTE;
> > +
> > +	afbc_size = ALIGN(n_superblocks * AFBC_HEADER_SIZE,
> > +			  AFBC_SUPERBLK_ALIGNMENT);
> > +	afbc_size += n_superblocks *
> > +		ALIGN(afbc_superblock_size, AFBC_SUPERBLK_ALIGNMENT);
> > +
> > +	if ((mode_cmd->width * bpp) != (mode_cmd->pitches[0] * BITS_PER_BYTE)) {
> > +		DRM_DEBUG_KMS("Invalid value of (pitch * BITS_PER_BYTE) (=%u) should be same as width (=%u) * bpp (=%u)\n",
> > +			mode_cmd->pitches[0] * BITS_PER_BYTE,
> > +			mode_cmd->width, bpp
> > +		);
> > +		return false;
> > +	}
> > +
> > +	if (objs->size < afbc_size) {
> > +		DRM_DEBUG_KMS("buffer size (%zu) too small for AFBC buffer size = %u\n",
> > +			objs->size, afbc_size
> > +		);
> > +
> > +		return false;
> > +	}
> > +
> > +	return true;
> > +}
> > +EXPORT_SYMBOL(drm_afbc_check_fb_size);
> > diff --git a/include/drm/drm_afbc.h b/include/drm/drm_afbc.h
> > new file mode 100644
> > index 000000000000..ce39c850217b
> > --- /dev/null
> > +++ b/include/drm/drm_afbc.h
> > @@ -0,0 +1,25 @@
> > +/* SPDX-License-Identifier: GPL-2.0+ */
> > +/*
> > + * (C) 2019 Collabora Ltd.
> > + *
> > + * author: Andrzej Pietrasiewicz <andrzej.p@collabora.com>
> > + *
> > + */
> > +#ifndef __DRM_AFBC_H__
> > +#define __DRM_AFBC_H__
> > +
> > +struct drm_device;
> > +struct drm_mode_fb_cmd2;
> > +struct drm_gem_object;
> > +
> > +bool drm_afbc_check_offset(struct drm_device *dev,
> > +			   const struct drm_mode_fb_cmd2 *mode_cmd);
> > +
> > +bool drm_afbc_check_size_align(struct drm_device *dev,
> > +			       const struct drm_mode_fb_cmd2 *mode_cmd);
> > +
> > +bool drm_afbc_check_fb_size(struct drm_device *dev,
> > +			    const struct drm_mode_fb_cmd2 *mode_cmd,
> > +			    struct drm_gem_object *objs, int bpp);
> > +
> > +#endif /* __DRM_AFBC_H__ */
> > --
> > 2.17.1
> > 
> > _______________________________________________
> > dri-devel mailing list
> > dri-devel@lists.freedesktop.org
> > https://lists.freedesktop.org/mailman/listinfo/dri-devel
> 

Overall the patch LGTM as-is, nice and straightforward
mostly-cut-n-paste, just let's sort out the SPDX identifier question
I have, then I'll be happy.

-- 
Mihail




^ permalink raw reply	[flat|nested] 63+ messages in thread

* Re: [PATCH 1/2] drm/arm: Factor out generic afbc helpers
@ 2019-10-21 14:41       ` Mihail Atanassov
  0 siblings, 0 replies; 63+ messages in thread
From: Mihail Atanassov @ 2019-10-21 14:41 UTC (permalink / raw)
  To: Ayan Halder
  Cc: nd, David Airlie, Liviu Dudau, linux-kernel, dri-devel,
	Andrzej Pietrasiewicz, linux-rockchip,
	james qian wang (Arm Technology China),
	kernel, Sean Paul, linux-arm-kernel

Hi Andrzej,

On Monday, 21 October 2019 14:50:14 BST Ayan Halder wrote:
> On Fri, Oct 11, 2019 at 01:18:10PM +0200, Andrzej Pietrasiewicz wrote:
> > These are useful for other users of afbc, e.g. rockchip.
> > 
> > Signed-off-by: Andrzej Pietrasiewicz <andrzej.p@collabora.com>
> 
> Hi Andrzej,
> 
> Thanks a lot for doing this. Much appreciated. :)
> It was on our TODO list for a long time.

Seconded, thanks for the patch!

> 
> I have cc-ed james.qian.wang@arm.com, Mihail.Atanassov@arm.com for
> their comments as well.
> 
> > ---
> >  drivers/gpu/drm/Kconfig          |   4 ++
> >  drivers/gpu/drm/Makefile         |   1 +
> >  drivers/gpu/drm/arm/Kconfig      |   1 +
> >  drivers/gpu/drm/arm/malidp_drv.c |  58 ++--------------
> >  drivers/gpu/drm/drm_afbc.c       | 114 +++++++++++++++++++++++++++++++
> >  include/drm/drm_afbc.h           |  25 +++++++
> >  6 files changed, 149 insertions(+), 54 deletions(-)
> >  create mode 100644 drivers/gpu/drm/drm_afbc.c
> >  create mode 100644 include/drm/drm_afbc.h
> > 
> > diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig
> > index 3c88420e3497..00e3f90557f4 100644
> > --- a/drivers/gpu/drm/Kconfig
> > +++ b/drivers/gpu/drm/Kconfig
> > @@ -195,6 +195,10 @@ config DRM_SCHED
> >  	tristate
> >  	depends on DRM
> >  
> > +config DRM_AFBC
> > +	tristate
> > +	depends on DRM
> Adding a 'help' would be great here. Stealing the first line from
> https://www.kernel.org/doc/html/latest/gpu/afbc.html
> 
> "AFBC is a proprietary lossless image compression protocol and format.
> It provides fine-grained random access and minimizes the amount of
> data transferred between IP blocks."
> 
> > +
> >  source "drivers/gpu/drm/i2c/Kconfig"
> >  
> >  source "drivers/gpu/drm/arm/Kconfig"
> > diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile
> > index 9f0d2ee35794..55368b668355 100644
> > --- a/drivers/gpu/drm/Makefile
> > +++ b/drivers/gpu/drm/Makefile
> > @@ -31,6 +31,7 @@ drm-$(CONFIG_OF) += drm_of.o
> >  drm-$(CONFIG_AGP) += drm_agpsupport.o
> >  drm-$(CONFIG_DEBUG_FS) += drm_debugfs.o drm_debugfs_crc.o
> >  drm-$(CONFIG_DRM_LOAD_EDID_FIRMWARE) += drm_edid_load.o
> > +drm-$(CONFIG_DRM_AFBC) += drm_afbc.o
> >  
> >  drm_vram_helper-y := drm_gem_vram_helper.o \
> >  		     drm_vram_helper_common.o \
> > diff --git a/drivers/gpu/drm/arm/Kconfig b/drivers/gpu/drm/arm/Kconfig
> > index a204103b3efb..25c3dc408cda 100644
> > --- a/drivers/gpu/drm/arm/Kconfig
> > +++ b/drivers/gpu/drm/arm/Kconfig
> > @@ -29,6 +29,7 @@ config DRM_MALI_DISPLAY
> >  	select DRM_KMS_HELPER
> >  	select DRM_KMS_CMA_HELPER
> >  	select DRM_GEM_CMA_HELPER
> > +	select DRM_AFBC
> >  	select VIDEOMODE_HELPERS
> >  	help
> >  	  Choose this option if you want to compile the ARM Mali Display
> > diff --git a/drivers/gpu/drm/arm/malidp_drv.c b/drivers/gpu/drm/arm/malidp_drv.c
> > index f25ec4382277..a67b69e08f63 100644
> > --- a/drivers/gpu/drm/arm/malidp_drv.c
> > +++ b/drivers/gpu/drm/arm/malidp_drv.c

This file is GPL-2.0-only. Shouldn't this be preserved when the
substantive bit of the code in drm_afbc.c comes from here?

> > @@ -16,6 +16,7 @@
> >  #include <linux/debugfs.h>
> >  
> >  #include <drm/drmP.h>
> > +#include <drm/drm_afbc.h>
> >  #include <drm/drm_atomic.h>
> >  #include <drm/drm_atomic_helper.h>
> >  #include <drm/drm_crtc.h>
> > @@ -33,8 +34,6 @@
> >  #include "malidp_hw.h"
> >  
> >  #define MALIDP_CONF_VALID_TIMEOUT	250
> > -#define AFBC_HEADER_SIZE		16
> > -#define AFBC_SUPERBLK_ALIGNMENT		128
> >  
> >  static void malidp_write_gamma_table(struct malidp_hw_device *hwdev,
> >  				     u32 data[MALIDP_COEFFTAB_NUM_COEFFS])
> > @@ -275,24 +274,8 @@ malidp_verify_afbc_framebuffer_caps(struct drm_device *dev,
> >  					mode_cmd->modifier[0]) == false)
> >  		return false;
> >  
> > -	if (mode_cmd->offsets[0] != 0) {
> > -		DRM_DEBUG_KMS("AFBC buffers' plane offset should be 0\n");
> > -		return false;
> > -	}
> > -
> > -	switch (mode_cmd->modifier[0] & AFBC_SIZE_MASK) {
> > -	case AFBC_SIZE_16X16:
> > -		if ((mode_cmd->width % 16) || (mode_cmd->height % 16)) {
> > -			DRM_DEBUG_KMS("AFBC buffers must be aligned to 16 pixels\n");
> > -			return false;
> > -		}
> > -		break;
> > -	default:
> > -		DRM_DEBUG_KMS("Unsupported AFBC block size\n");
> > -		return false;
> > -	}
> > -
> > -	return true;
> > +	return drm_afbc_check_offset(dev, mode_cmd) &&
> > +	       drm_afbc_check_size_align(dev, mode_cmd);
> >  }
> >  
> >  static bool
> > @@ -300,53 +283,20 @@ malidp_verify_afbc_framebuffer_size(struct drm_device *dev,
> >  				    struct drm_file *file,
> >  				    const struct drm_mode_fb_cmd2 *mode_cmd)
> >  {
> > -	int n_superblocks = 0;
> >  	const struct drm_format_info *info;
> >  	struct drm_gem_object *objs = NULL;
> > -	u32 afbc_superblock_size = 0, afbc_superblock_height = 0;
> > -	u32 afbc_superblock_width = 0, afbc_size = 0;
> >  	int bpp = 0;
> >  
> > -	switch (mode_cmd->modifier[0] & AFBC_SIZE_MASK) {
> > -	case AFBC_SIZE_16X16:
> > -		afbc_superblock_height = 16;
> > -		afbc_superblock_width = 16;
> > -		break;
> > -	default:
> > -		DRM_DEBUG_KMS("AFBC superblock size is not supported\n");
> > -		return false;
> > -	}
> > -
> >  	info = drm_get_format_info(dev, mode_cmd);
> > -
> > -	n_superblocks = (mode_cmd->width / afbc_superblock_width) *
> > -		(mode_cmd->height / afbc_superblock_height);
> > -
> >  	bpp = malidp_format_get_bpp(info->format);
> >  
> > -	afbc_superblock_size = (bpp * afbc_superblock_width * afbc_superblock_height)
> > -				/ BITS_PER_BYTE;
> > -
> > -	afbc_size = ALIGN(n_superblocks * AFBC_HEADER_SIZE, AFBC_SUPERBLK_ALIGNMENT);
> > -	afbc_size += n_superblocks * ALIGN(afbc_superblock_size, AFBC_SUPERBLK_ALIGNMENT);
> > -
> > -	if ((mode_cmd->width * bpp) != (mode_cmd->pitches[0] * BITS_PER_BYTE)) {
> > -		DRM_DEBUG_KMS("Invalid value of (pitch * BITS_PER_BYTE) (=%u) "
> > -			      "should be same as width (=%u) * bpp (=%u)\n",
> > -			      (mode_cmd->pitches[0] * BITS_PER_BYTE),
> > -			      mode_cmd->width, bpp);
> > -		return false;
> > -	}
> > -
> >  	objs = drm_gem_object_lookup(file, mode_cmd->handles[0]);
> >  	if (!objs) {
> >  		DRM_DEBUG_KMS("Failed to lookup GEM object\n");
> >  		return false;
> >  	}
> >  
> > -	if (objs->size < afbc_size) {
> > -		DRM_DEBUG_KMS("buffer size (%zu) too small for AFBC buffer size = %u\n",
> > -			      objs->size, afbc_size);
> > +	if (!drm_afbc_check_fb_size(dev, mode_cmd, objs, bpp)) {
> >  		drm_gem_object_put_unlocked(objs);
> >  		return false;
> >  	}
> Also can you do the code refactoring for komeda driver as well.
> specifically komeda_fb_afbc_size_check(). I will let
> james.qian.wang@arm.com and Mihail.Atanassov@arm.com have their
> opinion on this.

I'd say that it'd be really nice to get this work done for us ;)
but it doesn't have to be in this patch but rather in a follow-up.

> 
> > diff --git a/drivers/gpu/drm/drm_afbc.c b/drivers/gpu/drm/drm_afbc.c
> > new file mode 100644
> > index 000000000000..3e8a9225fd2e
> > --- /dev/null
> > +++ b/drivers/gpu/drm/drm_afbc.c
> > @@ -0,0 +1,114 @@
> > +// SPDX-License-Identifier: GPL-2.0+
> > +/*
> > + * (C) 2019 Collabora Ltd.
> > + *
> > + * author: Andrzej Pietrasiewicz <andrzej.p@collabora.com>
> > + *
> > + */
> > +#include <linux/module.h>
> > +
> > +#include <drm/drm_afbc.h>
> > +#include <drm/drm_device.h>
> > +#include <drm/drm_fourcc.h>
> > +#include <drm/drm_gem.h>
> > +#include <drm/drm_mode.h>
> > +#include <drm/drm_print.h>
> > +
> > +#define AFBC_HEADER_SIZE		16
> > +#define AFBC_SUPERBLK_ALIGNMENT		128
> > +
> > +bool drm_afbc_check_offset(struct drm_device *dev,
> > +			   const struct drm_mode_fb_cmd2 *mode_cmd)
> > +{
> > +	if (mode_cmd->offsets[0] != 0) {
> > +		DRM_DEBUG_KMS("AFBC buffers' plane offset should be 0\n");
> > +		return false;
> > +	}
> > +
> > +	return true;
> > +}
> > +EXPORT_SYMBOL_GPL(drm_afbc_check_offset);
> > +
> > +bool drm_afbc_check_size_align(struct drm_device *dev,
> > +			       const struct drm_mode_fb_cmd2 *mode_cmd)
> > +{
> > +
> > +	switch (mode_cmd->modifier[0] & AFBC_FORMAT_MOD_BLOCK_SIZE_MASK) {
> > +	case AFBC_FORMAT_MOD_BLOCK_SIZE_16x16:
> > +		if ((mode_cmd->width % 16) || (mode_cmd->height % 16)) {
> > +			DRM_DEBUG_KMS(
> > +				"AFBC buffer must be aligned to 16 pixels\n"
> > +			);
> > +			return false;
> > +		}
> > +		break;
> > +	case AFBC_FORMAT_MOD_BLOCK_SIZE_32x8:
> > +		/* fall through */
> > +	case AFBC_FORMAT_MOD_BLOCK_SIZE_64x4:
> > +		/* fall through */
> > +	case AFBC_FORMAT_MOD_BLOCK_SIZE_32x8_64x4:
> > +		/* fall through */
> > +	default:
> > +		DRM_DEBUG_KMS("Unsupported AFBC block size\n");
> > +		return false;
> > +	}
> > +
> > +	return true;
> > +}
> > +EXPORT_SYMBOL_GPL(drm_afbc_check_size_align);
> > +
> > +bool drm_afbc_check_fb_size(struct drm_device *dev,
> > +			    const struct drm_mode_fb_cmd2 *mode_cmd,
> > +			    struct drm_gem_object *objs, int bpp)
> > +{
> > +	int n_superblocks = 0;
> > +	u32 afbc_superblock_size = 0, afbc_superblock_height = 0;
> > +	u32 afbc_superblock_width = 0, afbc_size = 0;
> > +
> > +	switch (mode_cmd->modifier[0] & AFBC_FORMAT_MOD_BLOCK_SIZE_MASK) {
> > +	case AFBC_FORMAT_MOD_BLOCK_SIZE_16x16:
> > +		afbc_superblock_height = 16;
> > +		afbc_superblock_width = 16;
> > +		break;
> > +	case AFBC_FORMAT_MOD_BLOCK_SIZE_32x8:
> Copying from
> https://cgit.freedesktop.org/drm/drm-tip/tree/drivers/gpu/drm/arm/display/komeda/komeda_framebuffer.c#n60
>                 afbc_superblock_width = 32;
>                 afbc_superblock_height = 8;
> > +		/* fall through */
> > +	case AFBC_FORMAT_MOD_BLOCK_SIZE_64x4:
> > +		/* fall through */
> > +	case AFBC_FORMAT_MOD_BLOCK_SIZE_32x8_64x4:
> > +		/* fall through */
> > +	default:
> > +		DRM_DEBUG_KMS("AFBC superblock size is not supported\n");
> > +		return false;
> > +	}
> Can you combine the two switch - case confitions (from this function
> and the one in drm_afbc_check_size_align()) and put it in a separate
> function (say drm_afbc_get_superblock_dimensions()) of its own ?
> This will help to avoid code repetition.
> 

I'm personally a bit on the fence about this - functions should ideally
do one thing. That shared helper would be both getting the dimensions
_and_ checking the mode_cmd is valid, so one place cares about one half
of the function's results, and the other - the second half. ¯\_O_/¯,
opinions, everybody has them :).

> > +
> > +	n_superblocks = (mode_cmd->width / afbc_superblock_width) *
> > +		(mode_cmd->height / afbc_superblock_height);
> > +
> > +	afbc_superblock_size =
> > +		(bpp * afbc_superblock_width * afbc_superblock_height)
> > +			/ BITS_PER_BYTE;
> > +
> > +	afbc_size = ALIGN(n_superblocks * AFBC_HEADER_SIZE,
> > +			  AFBC_SUPERBLK_ALIGNMENT);
> > +	afbc_size += n_superblocks *
> > +		ALIGN(afbc_superblock_size, AFBC_SUPERBLK_ALIGNMENT);
> > +
> > +	if ((mode_cmd->width * bpp) != (mode_cmd->pitches[0] * BITS_PER_BYTE)) {
> > +		DRM_DEBUG_KMS("Invalid value of (pitch * BITS_PER_BYTE) (=%u) should be same as width (=%u) * bpp (=%u)\n",
> > +			mode_cmd->pitches[0] * BITS_PER_BYTE,
> > +			mode_cmd->width, bpp
> > +		);
> > +		return false;
> > +	}
> > +
> > +	if (objs->size < afbc_size) {
> > +		DRM_DEBUG_KMS("buffer size (%zu) too small for AFBC buffer size = %u\n",
> > +			objs->size, afbc_size
> > +		);
> > +
> > +		return false;
> > +	}
> > +
> > +	return true;
> > +}
> > +EXPORT_SYMBOL(drm_afbc_check_fb_size);
> > diff --git a/include/drm/drm_afbc.h b/include/drm/drm_afbc.h
> > new file mode 100644
> > index 000000000000..ce39c850217b
> > --- /dev/null
> > +++ b/include/drm/drm_afbc.h
> > @@ -0,0 +1,25 @@
> > +/* SPDX-License-Identifier: GPL-2.0+ */
> > +/*
> > + * (C) 2019 Collabora Ltd.
> > + *
> > + * author: Andrzej Pietrasiewicz <andrzej.p@collabora.com>
> > + *
> > + */
> > +#ifndef __DRM_AFBC_H__
> > +#define __DRM_AFBC_H__
> > +
> > +struct drm_device;
> > +struct drm_mode_fb_cmd2;
> > +struct drm_gem_object;
> > +
> > +bool drm_afbc_check_offset(struct drm_device *dev,
> > +			   const struct drm_mode_fb_cmd2 *mode_cmd);
> > +
> > +bool drm_afbc_check_size_align(struct drm_device *dev,
> > +			       const struct drm_mode_fb_cmd2 *mode_cmd);
> > +
> > +bool drm_afbc_check_fb_size(struct drm_device *dev,
> > +			    const struct drm_mode_fb_cmd2 *mode_cmd,
> > +			    struct drm_gem_object *objs, int bpp);
> > +
> > +#endif /* __DRM_AFBC_H__ */
> > --
> > 2.17.1
> > 
> > _______________________________________________
> > dri-devel mailing list
> > dri-devel@lists.freedesktop.org
> > https://lists.freedesktop.org/mailman/listinfo/dri-devel
> 

Overall the patch LGTM as-is, nice and straightforward
mostly-cut-n-paste, just let's sort out the SPDX identifier question
I have, then I'll be happy.

-- 
Mihail



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

^ permalink raw reply	[flat|nested] 63+ messages in thread

* Re: [PATCH 1/2] drm/arm: Factor out generic afbc helpers
@ 2019-10-21 14:41       ` Mihail Atanassov
  0 siblings, 0 replies; 63+ messages in thread
From: Mihail Atanassov @ 2019-10-21 14:41 UTC (permalink / raw)
  To: Ayan Halder
  Cc: nd, David Airlie, Liviu Dudau, linux-kernel, dri-devel,
	Andrzej Pietrasiewicz, linux-rockchip,
	james qian wang (Arm Technology China),
	kernel, Sean Paul, linux-arm-kernel

Hi Andrzej,

On Monday, 21 October 2019 14:50:14 BST Ayan Halder wrote:
> On Fri, Oct 11, 2019 at 01:18:10PM +0200, Andrzej Pietrasiewicz wrote:
> > These are useful for other users of afbc, e.g. rockchip.
> > 
> > Signed-off-by: Andrzej Pietrasiewicz <andrzej.p@collabora.com>
> 
> Hi Andrzej,
> 
> Thanks a lot for doing this. Much appreciated. :)
> It was on our TODO list for a long time.

Seconded, thanks for the patch!

> 
> I have cc-ed james.qian.wang@arm.com, Mihail.Atanassov@arm.com for
> their comments as well.
> 
> > ---
> >  drivers/gpu/drm/Kconfig          |   4 ++
> >  drivers/gpu/drm/Makefile         |   1 +
> >  drivers/gpu/drm/arm/Kconfig      |   1 +
> >  drivers/gpu/drm/arm/malidp_drv.c |  58 ++--------------
> >  drivers/gpu/drm/drm_afbc.c       | 114 +++++++++++++++++++++++++++++++
> >  include/drm/drm_afbc.h           |  25 +++++++
> >  6 files changed, 149 insertions(+), 54 deletions(-)
> >  create mode 100644 drivers/gpu/drm/drm_afbc.c
> >  create mode 100644 include/drm/drm_afbc.h
> > 
> > diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig
> > index 3c88420e3497..00e3f90557f4 100644
> > --- a/drivers/gpu/drm/Kconfig
> > +++ b/drivers/gpu/drm/Kconfig
> > @@ -195,6 +195,10 @@ config DRM_SCHED
> >  	tristate
> >  	depends on DRM
> >  
> > +config DRM_AFBC
> > +	tristate
> > +	depends on DRM
> Adding a 'help' would be great here. Stealing the first line from
> https://www.kernel.org/doc/html/latest/gpu/afbc.html
> 
> "AFBC is a proprietary lossless image compression protocol and format.
> It provides fine-grained random access and minimizes the amount of
> data transferred between IP blocks."
> 
> > +
> >  source "drivers/gpu/drm/i2c/Kconfig"
> >  
> >  source "drivers/gpu/drm/arm/Kconfig"
> > diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile
> > index 9f0d2ee35794..55368b668355 100644
> > --- a/drivers/gpu/drm/Makefile
> > +++ b/drivers/gpu/drm/Makefile
> > @@ -31,6 +31,7 @@ drm-$(CONFIG_OF) += drm_of.o
> >  drm-$(CONFIG_AGP) += drm_agpsupport.o
> >  drm-$(CONFIG_DEBUG_FS) += drm_debugfs.o drm_debugfs_crc.o
> >  drm-$(CONFIG_DRM_LOAD_EDID_FIRMWARE) += drm_edid_load.o
> > +drm-$(CONFIG_DRM_AFBC) += drm_afbc.o
> >  
> >  drm_vram_helper-y := drm_gem_vram_helper.o \
> >  		     drm_vram_helper_common.o \
> > diff --git a/drivers/gpu/drm/arm/Kconfig b/drivers/gpu/drm/arm/Kconfig
> > index a204103b3efb..25c3dc408cda 100644
> > --- a/drivers/gpu/drm/arm/Kconfig
> > +++ b/drivers/gpu/drm/arm/Kconfig
> > @@ -29,6 +29,7 @@ config DRM_MALI_DISPLAY
> >  	select DRM_KMS_HELPER
> >  	select DRM_KMS_CMA_HELPER
> >  	select DRM_GEM_CMA_HELPER
> > +	select DRM_AFBC
> >  	select VIDEOMODE_HELPERS
> >  	help
> >  	  Choose this option if you want to compile the ARM Mali Display
> > diff --git a/drivers/gpu/drm/arm/malidp_drv.c b/drivers/gpu/drm/arm/malidp_drv.c
> > index f25ec4382277..a67b69e08f63 100644
> > --- a/drivers/gpu/drm/arm/malidp_drv.c
> > +++ b/drivers/gpu/drm/arm/malidp_drv.c

This file is GPL-2.0-only. Shouldn't this be preserved when the
substantive bit of the code in drm_afbc.c comes from here?

> > @@ -16,6 +16,7 @@
> >  #include <linux/debugfs.h>
> >  
> >  #include <drm/drmP.h>
> > +#include <drm/drm_afbc.h>
> >  #include <drm/drm_atomic.h>
> >  #include <drm/drm_atomic_helper.h>
> >  #include <drm/drm_crtc.h>
> > @@ -33,8 +34,6 @@
> >  #include "malidp_hw.h"
> >  
> >  #define MALIDP_CONF_VALID_TIMEOUT	250
> > -#define AFBC_HEADER_SIZE		16
> > -#define AFBC_SUPERBLK_ALIGNMENT		128
> >  
> >  static void malidp_write_gamma_table(struct malidp_hw_device *hwdev,
> >  				     u32 data[MALIDP_COEFFTAB_NUM_COEFFS])
> > @@ -275,24 +274,8 @@ malidp_verify_afbc_framebuffer_caps(struct drm_device *dev,
> >  					mode_cmd->modifier[0]) == false)
> >  		return false;
> >  
> > -	if (mode_cmd->offsets[0] != 0) {
> > -		DRM_DEBUG_KMS("AFBC buffers' plane offset should be 0\n");
> > -		return false;
> > -	}
> > -
> > -	switch (mode_cmd->modifier[0] & AFBC_SIZE_MASK) {
> > -	case AFBC_SIZE_16X16:
> > -		if ((mode_cmd->width % 16) || (mode_cmd->height % 16)) {
> > -			DRM_DEBUG_KMS("AFBC buffers must be aligned to 16 pixels\n");
> > -			return false;
> > -		}
> > -		break;
> > -	default:
> > -		DRM_DEBUG_KMS("Unsupported AFBC block size\n");
> > -		return false;
> > -	}
> > -
> > -	return true;
> > +	return drm_afbc_check_offset(dev, mode_cmd) &&
> > +	       drm_afbc_check_size_align(dev, mode_cmd);
> >  }
> >  
> >  static bool
> > @@ -300,53 +283,20 @@ malidp_verify_afbc_framebuffer_size(struct drm_device *dev,
> >  				    struct drm_file *file,
> >  				    const struct drm_mode_fb_cmd2 *mode_cmd)
> >  {
> > -	int n_superblocks = 0;
> >  	const struct drm_format_info *info;
> >  	struct drm_gem_object *objs = NULL;
> > -	u32 afbc_superblock_size = 0, afbc_superblock_height = 0;
> > -	u32 afbc_superblock_width = 0, afbc_size = 0;
> >  	int bpp = 0;
> >  
> > -	switch (mode_cmd->modifier[0] & AFBC_SIZE_MASK) {
> > -	case AFBC_SIZE_16X16:
> > -		afbc_superblock_height = 16;
> > -		afbc_superblock_width = 16;
> > -		break;
> > -	default:
> > -		DRM_DEBUG_KMS("AFBC superblock size is not supported\n");
> > -		return false;
> > -	}
> > -
> >  	info = drm_get_format_info(dev, mode_cmd);
> > -
> > -	n_superblocks = (mode_cmd->width / afbc_superblock_width) *
> > -		(mode_cmd->height / afbc_superblock_height);
> > -
> >  	bpp = malidp_format_get_bpp(info->format);
> >  
> > -	afbc_superblock_size = (bpp * afbc_superblock_width * afbc_superblock_height)
> > -				/ BITS_PER_BYTE;
> > -
> > -	afbc_size = ALIGN(n_superblocks * AFBC_HEADER_SIZE, AFBC_SUPERBLK_ALIGNMENT);
> > -	afbc_size += n_superblocks * ALIGN(afbc_superblock_size, AFBC_SUPERBLK_ALIGNMENT);
> > -
> > -	if ((mode_cmd->width * bpp) != (mode_cmd->pitches[0] * BITS_PER_BYTE)) {
> > -		DRM_DEBUG_KMS("Invalid value of (pitch * BITS_PER_BYTE) (=%u) "
> > -			      "should be same as width (=%u) * bpp (=%u)\n",
> > -			      (mode_cmd->pitches[0] * BITS_PER_BYTE),
> > -			      mode_cmd->width, bpp);
> > -		return false;
> > -	}
> > -
> >  	objs = drm_gem_object_lookup(file, mode_cmd->handles[0]);
> >  	if (!objs) {
> >  		DRM_DEBUG_KMS("Failed to lookup GEM object\n");
> >  		return false;
> >  	}
> >  
> > -	if (objs->size < afbc_size) {
> > -		DRM_DEBUG_KMS("buffer size (%zu) too small for AFBC buffer size = %u\n",
> > -			      objs->size, afbc_size);
> > +	if (!drm_afbc_check_fb_size(dev, mode_cmd, objs, bpp)) {
> >  		drm_gem_object_put_unlocked(objs);
> >  		return false;
> >  	}
> Also can you do the code refactoring for komeda driver as well.
> specifically komeda_fb_afbc_size_check(). I will let
> james.qian.wang@arm.com and Mihail.Atanassov@arm.com have their
> opinion on this.

I'd say that it'd be really nice to get this work done for us ;)
but it doesn't have to be in this patch but rather in a follow-up.

> 
> > diff --git a/drivers/gpu/drm/drm_afbc.c b/drivers/gpu/drm/drm_afbc.c
> > new file mode 100644
> > index 000000000000..3e8a9225fd2e
> > --- /dev/null
> > +++ b/drivers/gpu/drm/drm_afbc.c
> > @@ -0,0 +1,114 @@
> > +// SPDX-License-Identifier: GPL-2.0+
> > +/*
> > + * (C) 2019 Collabora Ltd.
> > + *
> > + * author: Andrzej Pietrasiewicz <andrzej.p@collabora.com>
> > + *
> > + */
> > +#include <linux/module.h>
> > +
> > +#include <drm/drm_afbc.h>
> > +#include <drm/drm_device.h>
> > +#include <drm/drm_fourcc.h>
> > +#include <drm/drm_gem.h>
> > +#include <drm/drm_mode.h>
> > +#include <drm/drm_print.h>
> > +
> > +#define AFBC_HEADER_SIZE		16
> > +#define AFBC_SUPERBLK_ALIGNMENT		128
> > +
> > +bool drm_afbc_check_offset(struct drm_device *dev,
> > +			   const struct drm_mode_fb_cmd2 *mode_cmd)
> > +{
> > +	if (mode_cmd->offsets[0] != 0) {
> > +		DRM_DEBUG_KMS("AFBC buffers' plane offset should be 0\n");
> > +		return false;
> > +	}
> > +
> > +	return true;
> > +}
> > +EXPORT_SYMBOL_GPL(drm_afbc_check_offset);
> > +
> > +bool drm_afbc_check_size_align(struct drm_device *dev,
> > +			       const struct drm_mode_fb_cmd2 *mode_cmd)
> > +{
> > +
> > +	switch (mode_cmd->modifier[0] & AFBC_FORMAT_MOD_BLOCK_SIZE_MASK) {
> > +	case AFBC_FORMAT_MOD_BLOCK_SIZE_16x16:
> > +		if ((mode_cmd->width % 16) || (mode_cmd->height % 16)) {
> > +			DRM_DEBUG_KMS(
> > +				"AFBC buffer must be aligned to 16 pixels\n"
> > +			);
> > +			return false;
> > +		}
> > +		break;
> > +	case AFBC_FORMAT_MOD_BLOCK_SIZE_32x8:
> > +		/* fall through */
> > +	case AFBC_FORMAT_MOD_BLOCK_SIZE_64x4:
> > +		/* fall through */
> > +	case AFBC_FORMAT_MOD_BLOCK_SIZE_32x8_64x4:
> > +		/* fall through */
> > +	default:
> > +		DRM_DEBUG_KMS("Unsupported AFBC block size\n");
> > +		return false;
> > +	}
> > +
> > +	return true;
> > +}
> > +EXPORT_SYMBOL_GPL(drm_afbc_check_size_align);
> > +
> > +bool drm_afbc_check_fb_size(struct drm_device *dev,
> > +			    const struct drm_mode_fb_cmd2 *mode_cmd,
> > +			    struct drm_gem_object *objs, int bpp)
> > +{
> > +	int n_superblocks = 0;
> > +	u32 afbc_superblock_size = 0, afbc_superblock_height = 0;
> > +	u32 afbc_superblock_width = 0, afbc_size = 0;
> > +
> > +	switch (mode_cmd->modifier[0] & AFBC_FORMAT_MOD_BLOCK_SIZE_MASK) {
> > +	case AFBC_FORMAT_MOD_BLOCK_SIZE_16x16:
> > +		afbc_superblock_height = 16;
> > +		afbc_superblock_width = 16;
> > +		break;
> > +	case AFBC_FORMAT_MOD_BLOCK_SIZE_32x8:
> Copying from
> https://cgit.freedesktop.org/drm/drm-tip/tree/drivers/gpu/drm/arm/display/komeda/komeda_framebuffer.c#n60
>                 afbc_superblock_width = 32;
>                 afbc_superblock_height = 8;
> > +		/* fall through */
> > +	case AFBC_FORMAT_MOD_BLOCK_SIZE_64x4:
> > +		/* fall through */
> > +	case AFBC_FORMAT_MOD_BLOCK_SIZE_32x8_64x4:
> > +		/* fall through */
> > +	default:
> > +		DRM_DEBUG_KMS("AFBC superblock size is not supported\n");
> > +		return false;
> > +	}
> Can you combine the two switch - case confitions (from this function
> and the one in drm_afbc_check_size_align()) and put it in a separate
> function (say drm_afbc_get_superblock_dimensions()) of its own ?
> This will help to avoid code repetition.
> 

I'm personally a bit on the fence about this - functions should ideally
do one thing. That shared helper would be both getting the dimensions
_and_ checking the mode_cmd is valid, so one place cares about one half
of the function's results, and the other - the second half. ¯\_O_/¯,
opinions, everybody has them :).

> > +
> > +	n_superblocks = (mode_cmd->width / afbc_superblock_width) *
> > +		(mode_cmd->height / afbc_superblock_height);
> > +
> > +	afbc_superblock_size =
> > +		(bpp * afbc_superblock_width * afbc_superblock_height)
> > +			/ BITS_PER_BYTE;
> > +
> > +	afbc_size = ALIGN(n_superblocks * AFBC_HEADER_SIZE,
> > +			  AFBC_SUPERBLK_ALIGNMENT);
> > +	afbc_size += n_superblocks *
> > +		ALIGN(afbc_superblock_size, AFBC_SUPERBLK_ALIGNMENT);
> > +
> > +	if ((mode_cmd->width * bpp) != (mode_cmd->pitches[0] * BITS_PER_BYTE)) {
> > +		DRM_DEBUG_KMS("Invalid value of (pitch * BITS_PER_BYTE) (=%u) should be same as width (=%u) * bpp (=%u)\n",
> > +			mode_cmd->pitches[0] * BITS_PER_BYTE,
> > +			mode_cmd->width, bpp
> > +		);
> > +		return false;
> > +	}
> > +
> > +	if (objs->size < afbc_size) {
> > +		DRM_DEBUG_KMS("buffer size (%zu) too small for AFBC buffer size = %u\n",
> > +			objs->size, afbc_size
> > +		);
> > +
> > +		return false;
> > +	}
> > +
> > +	return true;
> > +}
> > +EXPORT_SYMBOL(drm_afbc_check_fb_size);
> > diff --git a/include/drm/drm_afbc.h b/include/drm/drm_afbc.h
> > new file mode 100644
> > index 000000000000..ce39c850217b
> > --- /dev/null
> > +++ b/include/drm/drm_afbc.h
> > @@ -0,0 +1,25 @@
> > +/* SPDX-License-Identifier: GPL-2.0+ */
> > +/*
> > + * (C) 2019 Collabora Ltd.
> > + *
> > + * author: Andrzej Pietrasiewicz <andrzej.p@collabora.com>
> > + *
> > + */
> > +#ifndef __DRM_AFBC_H__
> > +#define __DRM_AFBC_H__
> > +
> > +struct drm_device;
> > +struct drm_mode_fb_cmd2;
> > +struct drm_gem_object;
> > +
> > +bool drm_afbc_check_offset(struct drm_device *dev,
> > +			   const struct drm_mode_fb_cmd2 *mode_cmd);
> > +
> > +bool drm_afbc_check_size_align(struct drm_device *dev,
> > +			       const struct drm_mode_fb_cmd2 *mode_cmd);
> > +
> > +bool drm_afbc_check_fb_size(struct drm_device *dev,
> > +			    const struct drm_mode_fb_cmd2 *mode_cmd,
> > +			    struct drm_gem_object *objs, int bpp);
> > +
> > +#endif /* __DRM_AFBC_H__ */
> > --
> > 2.17.1
> > 
> > _______________________________________________
> > dri-devel mailing list
> > dri-devel@lists.freedesktop.org
> > https://lists.freedesktop.org/mailman/listinfo/dri-devel
> 

Overall the patch LGTM as-is, nice and straightforward
mostly-cut-n-paste, just let's sort out the SPDX identifier question
I have, then I'll be happy.

-- 
Mihail




_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 63+ messages in thread

* [PATCHv2 0/4] AFBC support for Rockchip
  2019-10-21 14:41       ` Mihail Atanassov
  (?)
  (?)
@ 2019-11-04 22:12       ` Andrzej Pietrasiewicz
  2019-11-04 22:12         ` [PATCHv2 1/4] drm/arm: Factor out generic afbc helpers Andrzej Pietrasiewicz
                           ` (3 more replies)
  -1 siblings, 4 replies; 63+ messages in thread
From: Andrzej Pietrasiewicz @ 2019-11-04 22:12 UTC (permalink / raw)
  To: dri-devel
  Cc: Ayan Halder, kernel, David Airlie, Liviu Dudau, linux-rockchip,
	James Wang, Mihail Atanassov, Sean Paul

This series adds AFBC support for Rockchip. It is inspired by:

https://chromium.googlesource.com/chromiumos/third_party/kernel/+/refs/heads/factory-gru-9017.B-chromeos-4.4/drivers/gpu/drm/rockchip/rockchip_drm_vop.c

The first patch factors out some afbc helper functions, as they are useful
in general. The second and third patches use the helpers and the fourth patch
adds implementation proper of AFBC support for Rockchip.

v1..v2:

- addressed comments from Daniel Stone, Ayan Halder, Mihail Atanassov
- coding style fixes

Andrzej Pietrasiewicz (4):
  drm/arm: Factor out generic afbc helpers
  drm/malidp: use afbc helpers
  drm/komeda: use afbc helpers
  drm/rockchip: Add support for afbc

 drivers/gpu/drm/Kconfig                       |   8 +
 drivers/gpu/drm/Makefile                      |   1 +
 drivers/gpu/drm/arm/Kconfig                   |   1 +
 .../arm/display/komeda/komeda_format_caps.h   |   1 -
 .../arm/display/komeda/komeda_framebuffer.c   |  44 +++---
 drivers/gpu/drm/arm/malidp_drv.c              |  66 ++------
 drivers/gpu/drm/drm_afbc.c                    | 129 ++++++++++++++++
 drivers/gpu/drm/rockchip/Kconfig              |   1 +
 drivers/gpu/drm/rockchip/rockchip_drm_fb.c    |  42 ++++++
 drivers/gpu/drm/rockchip/rockchip_drm_vop.c   | 141 +++++++++++++++++-
 drivers/gpu/drm/rockchip/rockchip_drm_vop.h   |  12 ++
 drivers/gpu/drm/rockchip/rockchip_vop_reg.c   |  84 ++++++++++-
 include/drm/drm_afbc.h                        |  36 +++++
 13 files changed, 480 insertions(+), 86 deletions(-)
 create mode 100644 drivers/gpu/drm/drm_afbc.c
 create mode 100644 include/drm/drm_afbc.h

-- 
2.17.1

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

^ permalink raw reply	[flat|nested] 63+ messages in thread

* [PATCHv2 1/4] drm/arm: Factor out generic afbc helpers
  2019-11-04 22:12       ` [PATCHv2 0/4] AFBC support for Rockchip Andrzej Pietrasiewicz
@ 2019-11-04 22:12         ` Andrzej Pietrasiewicz
  2019-11-05  9:22           ` Daniel Vetter
  2019-11-05 23:26             ` Daniel Stone
  2019-11-04 22:12         ` [PATCHv2 2/4] drm/malidp: use " Andrzej Pietrasiewicz
                           ` (2 subsequent siblings)
  3 siblings, 2 replies; 63+ messages in thread
From: Andrzej Pietrasiewicz @ 2019-11-04 22:12 UTC (permalink / raw)
  To: dri-devel
  Cc: Ayan Halder, kernel, David Airlie, Liviu Dudau, linux-rockchip,
	James Wang, Mihail Atanassov, Sean Paul

These are useful for other users of afbc, e.g. rockchip.

Signed-off-by: Andrzej Pietrasiewicz <andrzej.p@collabora.com>
---
 drivers/gpu/drm/Kconfig     |   8 +++
 drivers/gpu/drm/Makefile    |   1 +
 drivers/gpu/drm/arm/Kconfig |   1 +
 drivers/gpu/drm/drm_afbc.c  | 129 ++++++++++++++++++++++++++++++++++++
 include/drm/drm_afbc.h      |  36 ++++++++++
 5 files changed, 175 insertions(+)
 create mode 100644 drivers/gpu/drm/drm_afbc.c
 create mode 100644 include/drm/drm_afbc.h

diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig
index 36357a36a281..ae1ca5e02bfe 100644
--- a/drivers/gpu/drm/Kconfig
+++ b/drivers/gpu/drm/Kconfig
@@ -205,6 +205,14 @@ config DRM_SCHED
 	tristate
 	depends on DRM
 
+config DRM_AFBC
+	tristate
+	depends on DRM
+	help
+	  AFBC is a proprietary lossless image compression protocol and format.
+	  It provides fine-grained random access and minimizes the amount of
+	  data transferred between IP blocks.
+
 source "drivers/gpu/drm/i2c/Kconfig"
 
 source "drivers/gpu/drm/arm/Kconfig"
diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile
index 9f1c7c486f88..3a5d092ea514 100644
--- a/drivers/gpu/drm/Makefile
+++ b/drivers/gpu/drm/Makefile
@@ -31,6 +31,7 @@ drm-$(CONFIG_OF) += drm_of.o
 drm-$(CONFIG_AGP) += drm_agpsupport.o
 drm-$(CONFIG_DEBUG_FS) += drm_debugfs.o drm_debugfs_crc.o
 drm-$(CONFIG_DRM_LOAD_EDID_FIRMWARE) += drm_edid_load.o
+drm-$(CONFIG_DRM_AFBC) += drm_afbc.o
 
 drm_vram_helper-y := drm_gem_vram_helper.o \
 		     drm_vram_helper_common.o
diff --git a/drivers/gpu/drm/arm/Kconfig b/drivers/gpu/drm/arm/Kconfig
index a204103b3efb..25c3dc408cda 100644
--- a/drivers/gpu/drm/arm/Kconfig
+++ b/drivers/gpu/drm/arm/Kconfig
@@ -29,6 +29,7 @@ config DRM_MALI_DISPLAY
 	select DRM_KMS_HELPER
 	select DRM_KMS_CMA_HELPER
 	select DRM_GEM_CMA_HELPER
+	select DRM_AFBC
 	select VIDEOMODE_HELPERS
 	help
 	  Choose this option if you want to compile the ARM Mali Display
diff --git a/drivers/gpu/drm/drm_afbc.c b/drivers/gpu/drm/drm_afbc.c
new file mode 100644
index 000000000000..010ca9eb0480
--- /dev/null
+++ b/drivers/gpu/drm/drm_afbc.c
@@ -0,0 +1,129 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * (C) 2019 Collabora Ltd.
+ *
+ * author: Andrzej Pietrasiewicz <andrzej.p@collabora.com>
+ *
+ */
+#include <linux/module.h>
+
+#include <drm/drm_afbc.h>
+#include <drm/drm_device.h>
+#include <drm/drm_fourcc.h>
+#include <drm/drm_gem.h>
+#include <drm/drm_mode.h>
+#include <drm/drm_print.h>
+
+#define AFBC_HEADER_SIZE		16
+
+bool drm_afbc_check_offset(struct drm_device *dev,
+			   const struct drm_mode_fb_cmd2 *mode_cmd)
+{
+	if (mode_cmd->offsets[0] != 0) {
+		DRM_DEBUG_KMS("AFBC buffers' plane offset should be 0\n");
+		return false;
+	}
+
+	return true;
+}
+EXPORT_SYMBOL_GPL(drm_afbc_check_offset);
+
+bool drm_afbc_check_size_align(struct drm_device *dev,
+			       const struct drm_mode_fb_cmd2 *mode_cmd)
+{
+	switch (mode_cmd->modifier[0] & AFBC_FORMAT_MOD_BLOCK_SIZE_MASK) {
+	case AFBC_FORMAT_MOD_BLOCK_SIZE_16x16:
+		if ((mode_cmd->width % 16) || (mode_cmd->height % 16)) {
+			DRM_DEBUG_KMS(
+				"AFBC buffer must be aligned to 16 pixels\n"
+			);
+			return false;
+		}
+		break;
+	case AFBC_FORMAT_MOD_BLOCK_SIZE_32x8:
+		/* fall through */
+	case AFBC_FORMAT_MOD_BLOCK_SIZE_64x4:
+		/* fall through */
+	case AFBC_FORMAT_MOD_BLOCK_SIZE_32x8_64x4:
+		/* fall through */
+	default:
+		DRM_DEBUG_KMS("Unsupported AFBC block size\n");
+		return false;
+	}
+
+	return true;
+}
+EXPORT_SYMBOL_GPL(drm_afbc_check_size_align);
+
+bool drm_afbc_get_superblk_wh(u64 modifier, u32 *w, u32 *h)
+{
+	switch (modifier & AFBC_FORMAT_MOD_BLOCK_SIZE_MASK) {
+	case AFBC_FORMAT_MOD_BLOCK_SIZE_16x16:
+		*w = 16;
+		*h = 16;
+		break;
+	case AFBC_FORMAT_MOD_BLOCK_SIZE_32x8:
+		*w = 32;
+		*h = 8;
+		break;
+	case AFBC_FORMAT_MOD_BLOCK_SIZE_64x4:
+		/* fall through */
+	case AFBC_FORMAT_MOD_BLOCK_SIZE_32x8_64x4:
+		/* fall through */
+	default:
+		DRM_DEBUG_KMS("Invalid AFBC_FORMAT_MOD_BLOCK_SIZE: %lld.\n",
+			      modifier & AFBC_FORMAT_MOD_BLOCK_SIZE_MASK);
+		return false;
+	}
+	return true;
+}
+EXPORT_SYMBOL_GPL(drm_afbc_get_superblk_wh);
+
+bool drm_afbc_check_fb_size_ret(u32 pitch, int bpp,
+				u32 w, u32 h, u32 superblk_w, u32 superblk_h,
+				size_t size, u32 offset, u32 hdr_align,
+				u32 *payload_off, u32 *total_size)
+{
+	int n_superblks = 0;
+	u32 superblk_sz = 0;
+	u32 afbc_size = 0;
+
+	n_superblks = (w / superblk_w) * (h / superblk_h);
+	superblk_sz = (bpp * superblk_w * superblk_h) / BITS_PER_BYTE;
+	afbc_size = ALIGN(n_superblks * AFBC_HEADER_SIZE, hdr_align);
+	*payload_off = afbc_size;
+
+	afbc_size += n_superblks * ALIGN(superblk_sz, AFBC_SUPERBLK_ALIGNMENT);
+	*total_size = afbc_size + offset;
+
+	if ((w * bpp) != (pitch * BITS_PER_BYTE)) {
+		DRM_DEBUG_KMS("Invalid value of (pitch * BITS_PER_BYTE) (=%u) should be same as width (=%u) * bpp (=%u)\n",
+			      pitch * BITS_PER_BYTE, w, bpp
+		);
+		return false;
+	}
+
+	if (size < afbc_size) {
+		DRM_DEBUG_KMS("buffer size (%zu) too small for AFBC buffer size = %u\n",
+			      size, afbc_size
+		);
+
+		return false;
+	}
+
+	return true;
+}
+EXPORT_SYMBOL(drm_afbc_check_fb_size_ret);
+
+bool drm_afbc_check_fb_size(u32 pitch, int bpp,
+			    u32 w, u32 h, u32 superblk_w, u32 superblk_h,
+			    size_t size, u32 offset, u32 hdr_align)
+{
+	u32 payload_offset, total_size;
+
+	return drm_afbc_check_fb_size_ret(pitch, bpp, w, h,
+					  superblk_w, superblk_h,
+					  size, offset, hdr_align,
+					  &payload_offset, &total_size);
+}
+EXPORT_SYMBOL(drm_afbc_check_fb_size);
diff --git a/include/drm/drm_afbc.h b/include/drm/drm_afbc.h
new file mode 100644
index 000000000000..b28ae2849f96
--- /dev/null
+++ b/include/drm/drm_afbc.h
@@ -0,0 +1,36 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * (C) 2019 Collabora Ltd.
+ *
+ * author: Andrzej Pietrasiewicz <andrzej.p@collabora.com>
+ *
+ */
+#ifndef __DRM_AFBC_H__
+#define __DRM_AFBC_H__
+
+#include <linux/types.h>
+
+struct drm_device;
+struct drm_mode_fb_cmd2;
+struct drm_gem_object;
+
+#define AFBC_SUPERBLK_ALIGNMENT		128
+
+bool drm_afbc_check_offset(struct drm_device *dev,
+			   const struct drm_mode_fb_cmd2 *mode_cmd);
+
+bool drm_afbc_check_size_align(struct drm_device *dev,
+			       const struct drm_mode_fb_cmd2 *mode_cmd);
+
+bool drm_afbc_check_fb_size_ret(u32 pitch, int bpp,
+				u32 w, u32 h, u32 superblk_w, u32 superblk_h,
+				size_t size, u32 offset, u32 hdr_align,
+				u32 *payload_off, u32 *total_size);
+
+bool drm_afbc_check_fb_size(u32 pitch, int bpp,
+			    u32 w, u32 h, u32 superblk_w, u32 superblk_h,
+			    size_t size, u32 offset, u32 hdr_align);
+
+bool drm_afbc_get_superblk_wh(u64 modifier, u32 *w, u32 *h);
+
+#endif /* __DRM_AFBC_H__ */
-- 
2.17.1

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

^ permalink raw reply related	[flat|nested] 63+ messages in thread

* [PATCHv2 2/4] drm/malidp: use afbc helpers
  2019-11-04 22:12       ` [PATCHv2 0/4] AFBC support for Rockchip Andrzej Pietrasiewicz
  2019-11-04 22:12         ` [PATCHv2 1/4] drm/arm: Factor out generic afbc helpers Andrzej Pietrasiewicz
@ 2019-11-04 22:12         ` Andrzej Pietrasiewicz
  2019-11-06 11:09           ` Liviu Dudau
  2019-11-04 22:12         ` [PATCHv2 3/4] drm/komeda: " Andrzej Pietrasiewicz
  2019-11-04 22:12         ` [PATCHv2 " Andrzej Pietrasiewicz
  3 siblings, 1 reply; 63+ messages in thread
From: Andrzej Pietrasiewicz @ 2019-11-04 22:12 UTC (permalink / raw)
  To: dri-devel
  Cc: Ayan Halder, kernel, David Airlie, Liviu Dudau, linux-rockchip,
	James Wang, Mihail Atanassov, Sean Paul

There are afbc helpers available.

Signed-off-by: Andrzej Pietrasiewicz <andrzej.p@collabora.com>
---
 drivers/gpu/drm/arm/malidp_drv.c | 66 ++++++--------------------------
 1 file changed, 12 insertions(+), 54 deletions(-)

diff --git a/drivers/gpu/drm/arm/malidp_drv.c b/drivers/gpu/drm/arm/malidp_drv.c
index 37d92a06318e..ab93588cc8eb 100644
--- a/drivers/gpu/drm/arm/malidp_drv.c
+++ b/drivers/gpu/drm/arm/malidp_drv.c
@@ -15,6 +15,7 @@
 #include <linux/pm_runtime.h>
 #include <linux/debugfs.h>
 
+#include <drm/drm_afbc.h>
 #include <drm/drm_atomic.h>
 #include <drm/drm_atomic_helper.h>
 #include <drm/drm_crtc.h>
@@ -35,8 +36,6 @@
 #include "malidp_hw.h"
 
 #define MALIDP_CONF_VALID_TIMEOUT	250
-#define AFBC_HEADER_SIZE		16
-#define AFBC_SUPERBLK_ALIGNMENT		128
 
 static void malidp_write_gamma_table(struct malidp_hw_device *hwdev,
 				     u32 data[MALIDP_COEFFTAB_NUM_COEFFS])
@@ -277,24 +276,8 @@ malidp_verify_afbc_framebuffer_caps(struct drm_device *dev,
 					mode_cmd->modifier[0]) == false)
 		return false;
 
-	if (mode_cmd->offsets[0] != 0) {
-		DRM_DEBUG_KMS("AFBC buffers' plane offset should be 0\n");
-		return false;
-	}
-
-	switch (mode_cmd->modifier[0] & AFBC_SIZE_MASK) {
-	case AFBC_SIZE_16X16:
-		if ((mode_cmd->width % 16) || (mode_cmd->height % 16)) {
-			DRM_DEBUG_KMS("AFBC buffers must be aligned to 16 pixels\n");
-			return false;
-		}
-		break;
-	default:
-		DRM_DEBUG_KMS("Unsupported AFBC block size\n");
-		return false;
-	}
-
-	return true;
+	return drm_afbc_check_offset(dev, mode_cmd) &&
+	       drm_afbc_check_size_align(dev, mode_cmd);
 }
 
 static bool
@@ -302,54 +285,29 @@ malidp_verify_afbc_framebuffer_size(struct drm_device *dev,
 				    struct drm_file *file,
 				    const struct drm_mode_fb_cmd2 *mode_cmd)
 {
-	int n_superblocks = 0;
 	const struct drm_format_info *info;
 	struct drm_gem_object *objs = NULL;
-	u32 afbc_superblock_size = 0, afbc_superblock_height = 0;
-	u32 afbc_superblock_width = 0, afbc_size = 0;
 	int bpp = 0;
-
-	switch (mode_cmd->modifier[0] & AFBC_SIZE_MASK) {
-	case AFBC_SIZE_16X16:
-		afbc_superblock_height = 16;
-		afbc_superblock_width = 16;
-		break;
-	default:
-		DRM_DEBUG_KMS("AFBC superblock size is not supported\n");
-		return false;
-	}
+	u32 w, h;
 
 	info = drm_get_format_info(dev, mode_cmd);
-
-	n_superblocks = (mode_cmd->width / afbc_superblock_width) *
-		(mode_cmd->height / afbc_superblock_height);
-
 	bpp = malidp_format_get_bpp(info->format);
 
-	afbc_superblock_size = (bpp * afbc_superblock_width * afbc_superblock_height)
-				/ BITS_PER_BYTE;
-
-	afbc_size = ALIGN(n_superblocks * AFBC_HEADER_SIZE, AFBC_SUPERBLK_ALIGNMENT);
-	afbc_size += n_superblocks * ALIGN(afbc_superblock_size, AFBC_SUPERBLK_ALIGNMENT);
-
-	if ((mode_cmd->width * bpp) != (mode_cmd->pitches[0] * BITS_PER_BYTE)) {
-		DRM_DEBUG_KMS("Invalid value of (pitch * BITS_PER_BYTE) (=%u) "
-			      "should be same as width (=%u) * bpp (=%u)\n",
-			      (mode_cmd->pitches[0] * BITS_PER_BYTE),
-			      mode_cmd->width, bpp);
-		return false;
-	}
-
 	objs = drm_gem_object_lookup(file, mode_cmd->handles[0]);
 	if (!objs) {
 		DRM_DEBUG_KMS("Failed to lookup GEM object\n");
 		return false;
 	}
 
-	if (objs->size < afbc_size) {
-		DRM_DEBUG_KMS("buffer size (%zu) too small for AFBC buffer size = %u\n",
-			      objs->size, afbc_size);
+	if (!drm_afbc_get_superblk_wh(mode_cmd->modifier[0], &w, &h))
+		return false;
+
+	if (!drm_afbc_check_fb_size(mode_cmd->pitches[0], bpp,
+				    mode_cmd->width, mode_cmd->height, w, h,
+				    objs->size, mode_cmd->offsets[0],
+				    AFBC_SUPERBLK_ALIGNMENT)) {
 		drm_gem_object_put_unlocked(objs);
+
 		return false;
 	}
 
-- 
2.17.1

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

^ permalink raw reply related	[flat|nested] 63+ messages in thread

* [PATCHv2 3/4] drm/komeda: use afbc helpers
  2019-11-04 22:12       ` [PATCHv2 0/4] AFBC support for Rockchip Andrzej Pietrasiewicz
  2019-11-04 22:12         ` [PATCHv2 1/4] drm/arm: Factor out generic afbc helpers Andrzej Pietrasiewicz
  2019-11-04 22:12         ` [PATCHv2 2/4] drm/malidp: use " Andrzej Pietrasiewicz
@ 2019-11-04 22:12         ` Andrzej Pietrasiewicz
  2019-11-08 16:09             ` Ayan Halder
  2019-11-04 22:12         ` [PATCHv2 " Andrzej Pietrasiewicz
  3 siblings, 1 reply; 63+ messages in thread
From: Andrzej Pietrasiewicz @ 2019-11-04 22:12 UTC (permalink / raw)
  To: dri-devel
  Cc: Ayan Halder, kernel, David Airlie, Liviu Dudau, linux-rockchip,
	James Wang, Mihail Atanassov, Sean Paul

There are afbc helpers available.

Signed-off-by: Andrzej Pietrasiewicz <andrzej.p@collabora.com>
---
 .../arm/display/komeda/komeda_format_caps.h   |  1 -
 .../arm/display/komeda/komeda_framebuffer.c   | 44 +++++++------------
 2 files changed, 17 insertions(+), 28 deletions(-)

diff --git a/drivers/gpu/drm/arm/display/komeda/komeda_format_caps.h b/drivers/gpu/drm/arm/display/komeda/komeda_format_caps.h
index 32273cf18f7c..607eea80e60c 100644
--- a/drivers/gpu/drm/arm/display/komeda/komeda_format_caps.h
+++ b/drivers/gpu/drm/arm/display/komeda/komeda_format_caps.h
@@ -33,7 +33,6 @@
 
 #define AFBC_TH_LAYOUT_ALIGNMENT	8
 #define AFBC_HEADER_SIZE		16
-#define AFBC_SUPERBLK_ALIGNMENT		128
 #define AFBC_SUPERBLK_PIXELS		256
 #define AFBC_BODY_START_ALIGNMENT	1024
 #define AFBC_TH_BODY_START_ALIGNMENT	4096
diff --git a/drivers/gpu/drm/arm/display/komeda/komeda_framebuffer.c b/drivers/gpu/drm/arm/display/komeda/komeda_framebuffer.c
index 1b01a625f40e..e9c87551a5b8 100644
--- a/drivers/gpu/drm/arm/display/komeda/komeda_framebuffer.c
+++ b/drivers/gpu/drm/arm/display/komeda/komeda_framebuffer.c
@@ -4,6 +4,7 @@
  * Author: James.Qian.Wang <james.qian.wang@arm.com>
  *
  */
+#include <drm/drm_afbc.h>
 #include <drm/drm_device.h>
 #include <drm/drm_fb_cma_helper.h>
 #include <drm/drm_gem.h>
@@ -43,8 +44,7 @@ komeda_fb_afbc_size_check(struct komeda_fb *kfb, struct drm_file *file,
 	struct drm_framebuffer *fb = &kfb->base;
 	const struct drm_format_info *info = fb->format;
 	struct drm_gem_object *obj;
-	u32 alignment_w = 0, alignment_h = 0, alignment_header, n_blocks, bpp;
-	u64 min_size;
+	u32 alignment_w = 0, alignment_h = 0, alignment_header, bpp;
 
 	obj = drm_gem_object_lookup(file, mode_cmd->handles[0]);
 	if (!obj) {
@@ -52,19 +52,15 @@ komeda_fb_afbc_size_check(struct komeda_fb *kfb, struct drm_file *file,
 		return -ENOENT;
 	}
 
-	switch (fb->modifier & AFBC_FORMAT_MOD_BLOCK_SIZE_MASK) {
-	case AFBC_FORMAT_MOD_BLOCK_SIZE_32x8:
-		alignment_w = 32;
-		alignment_h = 8;
-		break;
-	case AFBC_FORMAT_MOD_BLOCK_SIZE_16x16:
-		alignment_w = 16;
-		alignment_h = 16;
-		break;
-	default:
-		WARN(1, "Invalid AFBC_FORMAT_MOD_BLOCK_SIZE: %lld.\n",
-		     fb->modifier & AFBC_FORMAT_MOD_BLOCK_SIZE_MASK);
-		break;
+	if (!drm_afbc_get_superblk_wh(fb->modifier, &alignment_w, &alignment_h))
+		return -EINVAL;
+
+	if ((alignment_w != 16 || alignment_h != 16) &&
+	    (alignment_w != 32 || alignment_h != 8)) {
+		DRM_DEBUG_KMS("Unsupported afbc tile w/h [%d/%d]\n",
+			      alignment_w, alignment_h);
+
+		return -EINVAL;
 	}
 
 	/* tiled header afbc */
@@ -84,20 +80,14 @@ komeda_fb_afbc_size_check(struct komeda_fb *kfb, struct drm_file *file,
 		goto check_failed;
 	}
 
-	n_blocks = (kfb->aligned_w * kfb->aligned_h) / AFBC_SUPERBLK_PIXELS;
-	kfb->offset_payload = ALIGN(n_blocks * AFBC_HEADER_SIZE,
-				    alignment_header);
-
 	bpp = komeda_get_afbc_format_bpp(info, fb->modifier);
-	kfb->afbc_size = kfb->offset_payload + n_blocks *
-			 ALIGN(bpp * AFBC_SUPERBLK_PIXELS / 8,
-			       AFBC_SUPERBLK_ALIGNMENT);
-	min_size = kfb->afbc_size + fb->offsets[0];
-	if (min_size > obj->size) {
-		DRM_DEBUG_KMS("afbc size check failed, obj_size: 0x%zx. min_size 0x%llx.\n",
-			      obj->size, min_size);
+
+	if (!drm_afbc_check_fb_size(mode_cmd->pitches[0], bpp,
+				    mode_cmd->width, mode_cmd->height,
+				    alignment_w, alignment_h,
+				    obj->size, mode_cmd->offsets[0],
+				    AFBC_SUPERBLK_ALIGNMENT))
 		goto check_failed;
-	}
 
 	fb->obj[0] = obj;
 	return 0;
-- 
2.17.1

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

^ permalink raw reply related	[flat|nested] 63+ messages in thread

* [PATCHv2 4/4] drm/rockchip: Add support for afbc
  2019-11-04 22:12       ` [PATCHv2 0/4] AFBC support for Rockchip Andrzej Pietrasiewicz
                           ` (2 preceding siblings ...)
  2019-11-04 22:12         ` [PATCHv2 3/4] drm/komeda: " Andrzej Pietrasiewicz
@ 2019-11-04 22:12         ` Andrzej Pietrasiewicz
  2019-11-05 23:34             ` Daniel Stone
  3 siblings, 1 reply; 63+ messages in thread
From: Andrzej Pietrasiewicz @ 2019-11-04 22:12 UTC (permalink / raw)
  To: dri-devel
  Cc: Ayan Halder, kernel, David Airlie, Liviu Dudau, linux-rockchip,
	James Wang, Mihail Atanassov, Sean Paul, Mark Yao

This patch adds support for afbc handling. afbc is a compressed format
which reduces the necessary memory bandwidth.

Co-developed-by: Mark Yao <mark.yao@rock-chips.com>
Signed-off-by: Mark Yao <mark.yao@rock-chips.com>
Signed-off-by: Andrzej Pietrasiewicz <andrzej.p@collabora.com>
---
 drivers/gpu/drm/rockchip/Kconfig            |   1 +
 drivers/gpu/drm/rockchip/rockchip_drm_fb.c  |  42 ++++++
 drivers/gpu/drm/rockchip/rockchip_drm_vop.c | 141 +++++++++++++++++++-
 drivers/gpu/drm/rockchip/rockchip_drm_vop.h |  12 ++
 drivers/gpu/drm/rockchip/rockchip_vop_reg.c |  84 +++++++++++-
 5 files changed, 276 insertions(+), 4 deletions(-)

diff --git a/drivers/gpu/drm/rockchip/Kconfig b/drivers/gpu/drm/rockchip/Kconfig
index 6f4222f8beeb..ff491efc52a5 100644
--- a/drivers/gpu/drm/rockchip/Kconfig
+++ b/drivers/gpu/drm/rockchip/Kconfig
@@ -5,6 +5,7 @@ config DRM_ROCKCHIP
 	select DRM_GEM_CMA_HELPER
 	select DRM_KMS_HELPER
 	select DRM_PANEL
+	select DRM_AFBC
 	select VIDEOMODE_HELPERS
 	select DRM_ANALOGIX_DP if ROCKCHIP_ANALOGIX_DP
 	select DRM_DW_HDMI if ROCKCHIP_DW_HDMI
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_fb.c b/drivers/gpu/drm/rockchip/rockchip_drm_fb.c
index ca01234c037c..0aac3e596df1 100644
--- a/drivers/gpu/drm/rockchip/rockchip_drm_fb.c
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_fb.c
@@ -8,6 +8,7 @@
 
 #include <drm/drm.h>
 #include <drm/drm_atomic.h>
+#include <drm/drm_afbc.h>
 #include <drm/drm_damage_helper.h>
 #include <drm/drm_fb_helper.h>
 #include <drm/drm_fourcc.h>
@@ -18,6 +19,8 @@
 #include "rockchip_drm_fb.h"
 #include "rockchip_drm_gem.h"
 
+#define ROCKCHIP_MAX_AFBC_WIDTH	2560
+
 static const struct drm_framebuffer_funcs rockchip_drm_fb_funcs = {
 	.destroy       = drm_gem_fb_destroy,
 	.create_handle = drm_gem_fb_create_handle,
@@ -29,9 +32,48 @@ rockchip_fb_alloc(struct drm_device *dev, const struct drm_mode_fb_cmd2 *mode_cm
 		  struct drm_gem_object **obj, unsigned int num_planes)
 {
 	struct drm_framebuffer *fb;
+	u32 w, h;
 	int ret;
 	int i;
 
+	if (mode_cmd->modifier[0]) {
+		const struct drm_format_info *info;
+		int bpp;
+
+		if (!drm_afbc_check_offset(dev, mode_cmd))
+			return ERR_PTR(-EINVAL);
+
+		if (!drm_afbc_get_superblk_wh(mode_cmd->modifier[0], &w, &h))
+			return ERR_PTR(-EINVAL);
+
+		if (w != 16 || h != 16) {
+			DRM_DEV_ERROR(dev->dev,
+				"Unsupported afbc tile w/h [%d/%d]\n", w, h);
+			return ERR_PTR(-EINVAL);
+		}
+
+		if (!drm_afbc_check_size_align(dev, mode_cmd))
+			return ERR_PTR(-EINVAL);
+
+		if (mode_cmd->width > ROCKCHIP_MAX_AFBC_WIDTH) {
+			DRM_DEV_ERROR(dev->dev,
+				      "Unsupported width %d>%d\n",
+				      mode_cmd->width,
+				      ROCKCHIP_MAX_AFBC_WIDTH
+			);
+
+			return ERR_PTR(-EINVAL);
+		}
+
+		info = drm_get_format_info(dev, mode_cmd);
+		bpp = info->cpp[0] * 8;
+
+		if (!drm_afbc_check_fb_size(mode_cmd->pitches[0], bpp,
+		    mode_cmd->width, mode_cmd->height, w, h, obj[0]->size,
+			mode_cmd->offsets[0], AFBC_SUPERBLK_ALIGNMENT))
+			return ERR_PTR(-EINVAL);
+	}
+
 	fb = kzalloc(sizeof(*fb), GFP_KERNEL);
 	if (!fb)
 		return ERR_PTR(-ENOMEM);
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c
index d04b3492bdac..e9ba72a4c4c6 100644
--- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c
@@ -91,9 +91,22 @@
 #define VOP_WIN_TO_INDEX(vop_win) \
 	((vop_win) - (vop_win)->vop->win)
 
+#define VOP_AFBC_SET(vop, name, v) \
+	do { \
+		if ((vop)->data->afbc) \
+			vop_reg_set((vop), &(vop)->data->afbc->name, \
+				0, ~0, v, #name); \
+	} while (0)
+
 #define to_vop(x) container_of(x, struct vop, crtc)
 #define to_vop_win(x) container_of(x, struct vop_win, base)
 
+#define AFBC_FMT_RGB565		0x0
+#define AFBC_FMT_U8U8U8U8	0x5
+#define AFBC_FMT_U8U8U8		0x4
+
+#define AFBC_TILE_16x16		BIT(4)
+
 /*
  * The coefficients of the following matrix are all fixed points.
  * The format is S2.10 for the 3x3 part of the matrix, and S9.12 for the offsets.
@@ -166,6 +179,7 @@ struct vop {
 	/* optional internal rgb encoder */
 	struct rockchip_rgb *rgb;
 
+	struct vop_win *afbc_win;
 	struct vop_win win[];
 };
 
@@ -274,6 +288,28 @@ static enum vop_data_format vop_convert_format(uint32_t format)
 	}
 }
 
+static int vop_convert_afbc_format(uint32_t format)
+{
+	switch (format) {
+	case DRM_FORMAT_XRGB8888:
+	case DRM_FORMAT_ARGB8888:
+	case DRM_FORMAT_XBGR8888:
+	case DRM_FORMAT_ABGR8888:
+		return AFBC_FMT_U8U8U8U8;
+	case DRM_FORMAT_RGB888:
+	case DRM_FORMAT_BGR888:
+		return AFBC_FMT_U8U8U8;
+	case DRM_FORMAT_RGB565:
+	case DRM_FORMAT_BGR565:
+		return AFBC_FMT_RGB565;
+	/* either of the below should not be reachable */
+	default:
+		return -EINVAL;
+	}
+
+	return -EINVAL;
+}
+
 static uint16_t scl_vop_cal_scale(enum scale_mode mode, uint32_t src,
 				  uint32_t dst, bool is_horizontal,
 				  int vsu_mode, int *vskiplines)
@@ -598,6 +634,15 @@ static int vop_enable(struct drm_crtc *crtc, struct drm_crtc_state *old_state)
 			vop_win_disable(vop, vop_win);
 		}
 	}
+
+	if (vop->data->afbc) {
+		/*
+		 * Disable AFBC and forget there was a vop window with AFBC
+		 */
+		VOP_AFBC_SET(vop, enable, 0);
+		vop->afbc_win = NULL;
+	}
+
 	spin_unlock(&vop->reg_lock);
 
 	vop_cfg_done(vop);
@@ -710,6 +755,34 @@ static void vop_plane_destroy(struct drm_plane *plane)
 	drm_plane_cleanup(plane);
 }
 
+static bool rockchip_mod_supported(struct drm_plane *plane,
+				   u32 format, u64 modifier)
+{
+	const struct drm_format_info *info;
+
+	if (WARN_ON(modifier == DRM_FORMAT_MOD_INVALID))
+		return false;
+
+	if (modifier == DRM_FORMAT_MOD_LINEAR)
+		return true;
+
+	if (modifier !=
+		DRM_FORMAT_MOD_ARM_AFBC(AFBC_FORMAT_MOD_BLOCK_SIZE_16x16 |
+		AFBC_FORMAT_MOD_SPARSE)) {
+		DRM_DEBUG_KMS("Unsupported format modifer 0x%llx\n", modifier);
+
+		return false;
+	}
+
+	info = drm_format_info(format);
+	if (info->num_planes != 1) {
+		DRM_DEBUG_KMS("AFBC buffers expect one plane\n");
+		return false;
+	}
+
+	return true;
+}
+
 static int vop_plane_atomic_check(struct drm_plane *plane,
 			   struct drm_plane_state *state)
 {
@@ -758,6 +831,34 @@ static int vop_plane_atomic_check(struct drm_plane *plane,
 		return -EINVAL;
 	}
 
+	if (fb->modifier ==
+		DRM_FORMAT_MOD_ARM_AFBC(AFBC_FORMAT_MOD_BLOCK_SIZE_16x16 |
+		AFBC_FORMAT_MOD_SPARSE)) {
+		struct vop *vop = to_vop(crtc);
+
+		if (!vop->data->afbc) {
+			DRM_ERROR("vop does not support AFBC\n");
+			return -EINVAL;
+		}
+
+		ret = vop_convert_afbc_format(fb->format->format);
+		if (ret < 0)
+			return ret;
+
+		if (state->src.x1 || state->src.y1) {
+			DRM_ERROR("afbc does not support offset display\n");
+			DRM_ERROR("xpos=%d, ypos=%d, offset=%d\n",
+				  state->src.x1, state->src.y1, fb->offsets[0]);
+			return -EINVAL;
+		}
+
+		if (state->rotation && state->rotation != DRM_MODE_ROTATE_0) {
+			DRM_ERROR("afbc does not support rotation\n");
+			DRM_ERROR("rotation=%d\n", state->rotation);
+			return -EINVAL;
+		}
+	}
+
 	return 0;
 }
 
@@ -773,6 +874,11 @@ static void vop_plane_atomic_disable(struct drm_plane *plane,
 	spin_lock(&vop->reg_lock);
 
 	vop_win_disable(vop, vop_win);
+	/*
+	 * Forget about the AFBC window if it is being disabled
+	 */
+	if (vop_win == vop->afbc_win)
+		vop->afbc_win = NULL;
 
 	spin_unlock(&vop->reg_lock);
 }
@@ -812,6 +918,13 @@ static void vop_plane_atomic_update(struct drm_plane *plane,
 	if (WARN_ON(!vop->is_enabled))
 		return;
 
+	/*
+	 * If updating the AFBC window then assume that
+	 * after the update there will be no AFBC window.
+	 */
+	if (vop_win == vop->afbc_win)
+		vop->afbc_win = NULL;
+
 	if (!state->visible) {
 		vop_plane_atomic_disable(plane, old_state);
 		return;
@@ -846,6 +959,23 @@ static void vop_plane_atomic_update(struct drm_plane *plane,
 
 	spin_lock(&vop->reg_lock);
 
+	if (fb->modifier ==
+		DRM_FORMAT_MOD_ARM_AFBC(AFBC_FORMAT_MOD_BLOCK_SIZE_16x16 |
+		AFBC_FORMAT_MOD_SPARSE)) {
+		int afbc_format = vop_convert_afbc_format(fb->format->format);
+
+		VOP_AFBC_SET(vop, format, afbc_format | AFBC_TILE_16x16);
+		VOP_AFBC_SET(vop, hreg_block_split, 0);
+		VOP_AFBC_SET(vop, win_sel, VOP_WIN_TO_INDEX(vop_win));
+		VOP_AFBC_SET(vop, hdr_ptr, dma_addr);
+		VOP_AFBC_SET(vop, pic_size, act_info);
+
+		/*
+		 * The window being udated becomes the AFBC window
+		 */
+		vop->afbc_win = vop_win;
+	}
+
 	VOP_WIN_SET(vop, win, format, format);
 	VOP_WIN_SET(vop, win, yrgb_vir, DIV_ROUND_UP(fb->pitches[0], 4));
 	VOP_WIN_SET(vop, win, yrgb_mst, dma_addr);
@@ -1001,6 +1131,7 @@ static const struct drm_plane_funcs vop_plane_funcs = {
 	.reset = drm_atomic_helper_plane_reset,
 	.atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state,
 	.atomic_destroy_state = drm_atomic_helper_plane_destroy_state,
+	.format_mod_supported = rockchip_mod_supported,
 };
 
 static int vop_crtc_enable_vblank(struct drm_crtc *crtc)
@@ -1340,6 +1471,10 @@ static void vop_crtc_atomic_flush(struct drm_crtc *crtc,
 
 	spin_lock(&vop->reg_lock);
 
+	/*
+	 * Enable AFBC if there is some AFBC window, disable otherwise
+	 */
+	VOP_AFBC_SET(vop, enable, vop->afbc_win != NULL);
 	vop_cfg_done(vop);
 
 	spin_unlock(&vop->reg_lock);
@@ -1634,7 +1769,8 @@ static int vop_create_crtc(struct vop *vop)
 					       0, &vop_plane_funcs,
 					       win_data->phy->data_formats,
 					       win_data->phy->nformats,
-					       NULL, win_data->type, NULL);
+					       win_data->phy->format_modifiers,
+					       win_data->type, NULL);
 		if (ret) {
 			DRM_DEV_ERROR(vop->dev, "failed to init plane %d\n",
 				      ret);
@@ -1678,7 +1814,8 @@ static int vop_create_crtc(struct vop *vop)
 					       &vop_plane_funcs,
 					       win_data->phy->data_formats,
 					       win_data->phy->nformats,
-					       NULL, win_data->type, NULL);
+					       win_data->phy->format_modifiers,
+					       win_data->type, NULL);
 		if (ret) {
 			DRM_DEV_ERROR(vop->dev, "failed to init overlay %d\n",
 				      ret);
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.h b/drivers/gpu/drm/rockchip/rockchip_drm_vop.h
index 0b3d18c457b2..3f4e88a783d2 100644
--- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.h
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.h
@@ -34,6 +34,16 @@ struct vop_reg {
 	bool relaxed;
 };
 
+struct vop_afbc {
+	struct vop_reg enable;
+	struct vop_reg win_sel;
+	struct vop_reg format;
+	struct vop_reg hreg_block_split;
+	struct vop_reg pic_size;
+	struct vop_reg hdr_ptr;
+	struct vop_reg rstn;
+};
+
 struct vop_modeset {
 	struct vop_reg htotal_pw;
 	struct vop_reg hact_st_end;
@@ -134,6 +144,7 @@ struct vop_win_phy {
 	const struct vop_scl_regs *scl;
 	const uint32_t *data_formats;
 	uint32_t nformats;
+	const uint64_t *format_modifiers;
 
 	struct vop_reg enable;
 	struct vop_reg gate;
@@ -173,6 +184,7 @@ struct vop_data {
 	const struct vop_misc *misc;
 	const struct vop_modeset *modeset;
 	const struct vop_output *output;
+	const struct vop_afbc *afbc;
 	const struct vop_win_yuv2yuv_data *win_yuv2yuv;
 	const struct vop_win_data *win;
 	unsigned int win_size;
diff --git a/drivers/gpu/drm/rockchip/rockchip_vop_reg.c b/drivers/gpu/drm/rockchip/rockchip_vop_reg.c
index 7a9d979c8d5d..f0cf1b04591d 100644
--- a/drivers/gpu/drm/rockchip/rockchip_vop_reg.c
+++ b/drivers/gpu/drm/rockchip/rockchip_vop_reg.c
@@ -50,6 +50,18 @@ static const uint32_t formats_win_full[] = {
 	DRM_FORMAT_NV24,
 };
 
+static const uint64_t format_modifiers_win_full[] = {
+	DRM_FORMAT_MOD_LINEAR,
+	DRM_FORMAT_MOD_INVALID,
+};
+
+static const uint64_t format_modifiers_win_full_afbc[] = {
+	DRM_FORMAT_MOD_ARM_AFBC(AFBC_FORMAT_MOD_BLOCK_SIZE_16x16 |
+				AFBC_FORMAT_MOD_SPARSE),
+	DRM_FORMAT_MOD_LINEAR,
+	DRM_FORMAT_MOD_INVALID,
+};
+
 static const uint32_t formats_win_lite[] = {
 	DRM_FORMAT_XRGB8888,
 	DRM_FORMAT_ARGB8888,
@@ -61,6 +73,11 @@ static const uint32_t formats_win_lite[] = {
 	DRM_FORMAT_BGR565,
 };
 
+static const uint64_t format_modifiers_win_lite[] = {
+	DRM_FORMAT_MOD_LINEAR,
+	DRM_FORMAT_MOD_INVALID,
+};
+
 static const struct vop_scl_regs rk3036_win_scl = {
 	.scale_yrgb_x = VOP_REG(RK3036_WIN0_SCL_FACTOR_YRGB, 0xffff, 0x0),
 	.scale_yrgb_y = VOP_REG(RK3036_WIN0_SCL_FACTOR_YRGB, 0xffff, 16),
@@ -72,6 +89,7 @@ static const struct vop_win_phy rk3036_win0_data = {
 	.scl = &rk3036_win_scl,
 	.data_formats = formats_win_full,
 	.nformats = ARRAY_SIZE(formats_win_full),
+	.format_modifiers = format_modifiers_win_full,
 	.enable = VOP_REG(RK3036_SYS_CTRL, 0x1, 0),
 	.format = VOP_REG(RK3036_SYS_CTRL, 0x7, 3),
 	.rb_swap = VOP_REG(RK3036_SYS_CTRL, 0x1, 15),
@@ -87,6 +105,7 @@ static const struct vop_win_phy rk3036_win0_data = {
 static const struct vop_win_phy rk3036_win1_data = {
 	.data_formats = formats_win_lite,
 	.nformats = ARRAY_SIZE(formats_win_lite),
+	.format_modifiers = format_modifiers_win_lite,
 	.enable = VOP_REG(RK3036_SYS_CTRL, 0x1, 1),
 	.format = VOP_REG(RK3036_SYS_CTRL, 0x7, 6),
 	.rb_swap = VOP_REG(RK3036_SYS_CTRL, 0x1, 19),
@@ -153,6 +172,7 @@ static const struct vop_data rk3036_vop = {
 static const struct vop_win_phy rk3126_win1_data = {
 	.data_formats = formats_win_lite,
 	.nformats = ARRAY_SIZE(formats_win_lite),
+	.format_modifiers = format_modifiers_win_lite,
 	.enable = VOP_REG(RK3036_SYS_CTRL, 0x1, 1),
 	.format = VOP_REG(RK3036_SYS_CTRL, 0x7, 6),
 	.rb_swap = VOP_REG(RK3036_SYS_CTRL, 0x1, 19),
@@ -234,6 +254,7 @@ static const struct vop_win_phy px30_win0_data = {
 	.scl = &px30_win_scl,
 	.data_formats = formats_win_full,
 	.nformats = ARRAY_SIZE(formats_win_full),
+	.format_modifiers = format_modifiers_win_full,
 	.enable = VOP_REG(PX30_WIN0_CTRL0, 0x1, 0),
 	.format = VOP_REG(PX30_WIN0_CTRL0, 0x7, 1),
 	.rb_swap = VOP_REG(PX30_WIN0_CTRL0, 0x1, 12),
@@ -249,6 +270,7 @@ static const struct vop_win_phy px30_win0_data = {
 static const struct vop_win_phy px30_win1_data = {
 	.data_formats = formats_win_lite,
 	.nformats = ARRAY_SIZE(formats_win_lite),
+	.format_modifiers = format_modifiers_win_lite,
 	.enable = VOP_REG(PX30_WIN1_CTRL0, 0x1, 0),
 	.format = VOP_REG(PX30_WIN1_CTRL0, 0x7, 4),
 	.rb_swap = VOP_REG(PX30_WIN1_CTRL0, 0x1, 12),
@@ -261,6 +283,7 @@ static const struct vop_win_phy px30_win1_data = {
 static const struct vop_win_phy px30_win2_data = {
 	.data_formats = formats_win_lite,
 	.nformats = ARRAY_SIZE(formats_win_lite),
+	.format_modifiers = format_modifiers_win_lite,
 	.gate = VOP_REG(PX30_WIN2_CTRL0, 0x1, 4),
 	.enable = VOP_REG(PX30_WIN2_CTRL0, 0x1, 0),
 	.format = VOP_REG(PX30_WIN2_CTRL0, 0x3, 5),
@@ -316,6 +339,7 @@ static const struct vop_win_phy rk3066_win0_data = {
 	.scl = &rk3066_win_scl,
 	.data_formats = formats_win_full,
 	.nformats = ARRAY_SIZE(formats_win_full),
+	.format_modifiers = format_modifiers_win_full,
 	.enable = VOP_REG(RK3066_SYS_CTRL1, 0x1, 0),
 	.format = VOP_REG(RK3066_SYS_CTRL0, 0x7, 4),
 	.rb_swap = VOP_REG(RK3066_SYS_CTRL0, 0x1, 19),
@@ -332,6 +356,7 @@ static const struct vop_win_phy rk3066_win1_data = {
 	.scl = &rk3066_win_scl,
 	.data_formats = formats_win_full,
 	.nformats = ARRAY_SIZE(formats_win_full),
+	.format_modifiers = format_modifiers_win_full,
 	.enable = VOP_REG(RK3066_SYS_CTRL1, 0x1, 1),
 	.format = VOP_REG(RK3066_SYS_CTRL0, 0x7, 7),
 	.rb_swap = VOP_REG(RK3066_SYS_CTRL0, 0x1, 23),
@@ -347,6 +372,7 @@ static const struct vop_win_phy rk3066_win1_data = {
 static const struct vop_win_phy rk3066_win2_data = {
 	.data_formats = formats_win_lite,
 	.nformats = ARRAY_SIZE(formats_win_lite),
+	.format_modifiers = format_modifiers_win_lite,
 	.enable = VOP_REG(RK3066_SYS_CTRL1, 0x1, 2),
 	.format = VOP_REG(RK3066_SYS_CTRL0, 0x7, 10),
 	.rb_swap = VOP_REG(RK3066_SYS_CTRL0, 0x1, 27),
@@ -426,6 +452,7 @@ static const struct vop_win_phy rk3188_win0_data = {
 	.scl = &rk3188_win_scl,
 	.data_formats = formats_win_full,
 	.nformats = ARRAY_SIZE(formats_win_full),
+	.format_modifiers = format_modifiers_win_full,
 	.enable = VOP_REG(RK3188_SYS_CTRL, 0x1, 0),
 	.format = VOP_REG(RK3188_SYS_CTRL, 0x7, 3),
 	.rb_swap = VOP_REG(RK3188_SYS_CTRL, 0x1, 15),
@@ -440,6 +467,7 @@ static const struct vop_win_phy rk3188_win0_data = {
 static const struct vop_win_phy rk3188_win1_data = {
 	.data_formats = formats_win_lite,
 	.nformats = ARRAY_SIZE(formats_win_lite),
+	.format_modifiers = format_modifiers_win_lite,
 	.enable = VOP_REG(RK3188_SYS_CTRL, 0x1, 1),
 	.format = VOP_REG(RK3188_SYS_CTRL, 0x7, 6),
 	.rb_swap = VOP_REG(RK3188_SYS_CTRL, 0x1, 19),
@@ -545,6 +573,7 @@ static const struct vop_win_phy rk3288_win01_data = {
 	.scl = &rk3288_win_full_scl,
 	.data_formats = formats_win_full,
 	.nformats = ARRAY_SIZE(formats_win_full),
+	.format_modifiers = format_modifiers_win_full,
 	.enable = VOP_REG(RK3288_WIN0_CTRL0, 0x1, 0),
 	.format = VOP_REG(RK3288_WIN0_CTRL0, 0x7, 1),
 	.rb_swap = VOP_REG(RK3288_WIN0_CTRL0, 0x1, 12),
@@ -563,6 +592,7 @@ static const struct vop_win_phy rk3288_win01_data = {
 static const struct vop_win_phy rk3288_win23_data = {
 	.data_formats = formats_win_lite,
 	.nformats = ARRAY_SIZE(formats_win_lite),
+	.format_modifiers = format_modifiers_win_lite,
 	.enable = VOP_REG(RK3288_WIN2_CTRL0, 0x1, 4),
 	.gate = VOP_REG(RK3288_WIN2_CTRL0, 0x1, 0),
 	.format = VOP_REG(RK3288_WIN2_CTRL0, 0x7, 1),
@@ -677,6 +707,7 @@ static const struct vop_win_phy rk3368_win01_data = {
 	.scl = &rk3288_win_full_scl,
 	.data_formats = formats_win_full,
 	.nformats = ARRAY_SIZE(formats_win_full),
+	.format_modifiers = format_modifiers_win_full,
 	.enable = VOP_REG(RK3368_WIN0_CTRL0, 0x1, 0),
 	.format = VOP_REG(RK3368_WIN0_CTRL0, 0x7, 1),
 	.rb_swap = VOP_REG(RK3368_WIN0_CTRL0, 0x1, 12),
@@ -697,6 +728,7 @@ static const struct vop_win_phy rk3368_win01_data = {
 static const struct vop_win_phy rk3368_win23_data = {
 	.data_formats = formats_win_lite,
 	.nformats = ARRAY_SIZE(formats_win_lite),
+	.format_modifiers = format_modifiers_win_lite,
 	.gate = VOP_REG(RK3368_WIN2_CTRL0, 0x1, 0),
 	.enable = VOP_REG(RK3368_WIN2_CTRL0, 0x1, 4),
 	.format = VOP_REG(RK3368_WIN2_CTRL0, 0x3, 5),
@@ -817,6 +849,53 @@ static const struct vop_win_yuv2yuv_data rk3399_vop_big_win_yuv2yuv_data[] = {
 	  .y2r_en = VOP_REG(RK3399_YUV2YUV_WIN, 0x1, 9) },
 	{ .base = 0xC0, .phy = &rk3399_yuv2yuv_win23_data },
 	{ .base = 0x120, .phy = &rk3399_yuv2yuv_win23_data },
+
+};
+
+static const struct vop_win_phy rk3399_win01_data = {
+	.scl = &rk3288_win_full_scl,
+	.data_formats = formats_win_full,
+	.nformats = ARRAY_SIZE(formats_win_full),
+	.format_modifiers = format_modifiers_win_full_afbc,
+	.enable = VOP_REG(RK3288_WIN0_CTRL0, 0x1, 0),
+	.format = VOP_REG(RK3288_WIN0_CTRL0, 0x7, 1),
+	.rb_swap = VOP_REG(RK3288_WIN0_CTRL0, 0x1, 12),
+	.y_mir_en = VOP_REG(RK3288_WIN0_CTRL0, 0x1, 22),
+	.act_info = VOP_REG(RK3288_WIN0_ACT_INFO, 0x1fff1fff, 0),
+	.dsp_info = VOP_REG(RK3288_WIN0_DSP_INFO, 0x0fff0fff, 0),
+	.dsp_st = VOP_REG(RK3288_WIN0_DSP_ST, 0x1fff1fff, 0),
+	.yrgb_mst = VOP_REG(RK3288_WIN0_YRGB_MST, 0xffffffff, 0),
+	.uv_mst = VOP_REG(RK3288_WIN0_CBR_MST, 0xffffffff, 0),
+	.yrgb_vir = VOP_REG(RK3288_WIN0_VIR, 0x3fff, 0),
+	.uv_vir = VOP_REG(RK3288_WIN0_VIR, 0x3fff, 16),
+	.src_alpha_ctl = VOP_REG(RK3288_WIN0_SRC_ALPHA_CTRL, 0xff, 0),
+	.dst_alpha_ctl = VOP_REG(RK3288_WIN0_DST_ALPHA_CTRL, 0xff, 0),
+};
+
+/*
+ * rk3399 vop big windows register layout is same as rk3288, but we
+ * have a separate rk3399 win data array here so that we can advertise
+ * AFBC on the primary plane.
+ */
+static const struct vop_win_data rk3399_vop_win_data[] = {
+	{ .base = 0x00, .phy = &rk3399_win01_data,
+	  .type = DRM_PLANE_TYPE_PRIMARY },
+	{ .base = 0x40, .phy = &rk3288_win01_data,
+	  .type = DRM_PLANE_TYPE_OVERLAY },
+	{ .base = 0x00, .phy = &rk3288_win23_data,
+	  .type = DRM_PLANE_TYPE_OVERLAY },
+	{ .base = 0x50, .phy = &rk3288_win23_data,
+	  .type = DRM_PLANE_TYPE_CURSOR },
+};
+
+static const struct vop_afbc rk3399_vop_afbc = {
+	.rstn = VOP_REG(RK3399_AFBCD0_CTRL, 0x1, 3),
+	.enable = VOP_REG(RK3399_AFBCD0_CTRL, 0x1, 0),
+	.win_sel = VOP_REG(RK3399_AFBCD0_CTRL, 0x3, 1),
+	.format = VOP_REG(RK3399_AFBCD0_CTRL, 0x1f, 16),
+	.hreg_block_split = VOP_REG(RK3399_AFBCD0_CTRL, 0x1, 21),
+	.hdr_ptr = VOP_REG(RK3399_AFBCD0_HDR_PTR, 0xffffffff, 0),
+	.pic_size = VOP_REG(RK3399_AFBCD0_PIC_SIZE, 0xffffffff, 0),
 };
 
 static const struct vop_data rk3399_vop_big = {
@@ -826,9 +905,10 @@ static const struct vop_data rk3399_vop_big = {
 	.common = &rk3288_common,
 	.modeset = &rk3288_modeset,
 	.output = &rk3399_output,
+	.afbc = &rk3399_vop_afbc,
 	.misc = &rk3368_misc,
-	.win = rk3368_vop_win_data,
-	.win_size = ARRAY_SIZE(rk3368_vop_win_data),
+	.win = rk3399_vop_win_data,
+	.win_size = ARRAY_SIZE(rk3399_vop_win_data),
 	.win_yuv2yuv = rk3399_vop_big_win_yuv2yuv_data,
 };
 
-- 
2.17.1

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

^ permalink raw reply related	[flat|nested] 63+ messages in thread

* Re: [PATCHv2 1/4] drm/arm: Factor out generic afbc helpers
  2019-11-04 22:12         ` [PATCHv2 1/4] drm/arm: Factor out generic afbc helpers Andrzej Pietrasiewicz
@ 2019-11-05  9:22           ` Daniel Vetter
  2019-11-06 12:45             ` Andrzej Pietrasiewicz
  2019-11-05 23:26             ` Daniel Stone
  1 sibling, 1 reply; 63+ messages in thread
From: Daniel Vetter @ 2019-11-05  9:22 UTC (permalink / raw)
  To: Andrzej Pietrasiewicz
  Cc: Ayan Halder, kernel, David Airlie, Liviu Dudau, linux-rockchip,
	James Wang, dri-devel, Mihail Atanassov, Sean Paul

On Mon, Nov 04, 2019 at 11:12:25PM +0100, Andrzej Pietrasiewicz wrote:
> These are useful for other users of afbc, e.g. rockchip.
> 
> Signed-off-by: Andrzej Pietrasiewicz <andrzej.p@collabora.com>
> ---
>  drivers/gpu/drm/Kconfig     |   8 +++
>  drivers/gpu/drm/Makefile    |   1 +
>  drivers/gpu/drm/arm/Kconfig |   1 +
>  drivers/gpu/drm/drm_afbc.c  | 129 ++++++++++++++++++++++++++++++++++++
>  include/drm/drm_afbc.h      |  36 ++++++++++
>  5 files changed, 175 insertions(+)
>  create mode 100644 drivers/gpu/drm/drm_afbc.c
>  create mode 100644 include/drm/drm_afbc.h
> 
> diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig
> index 36357a36a281..ae1ca5e02bfe 100644
> --- a/drivers/gpu/drm/Kconfig
> +++ b/drivers/gpu/drm/Kconfig
> @@ -205,6 +205,14 @@ config DRM_SCHED
>  	tristate
>  	depends on DRM
>  
> +config DRM_AFBC
> +	tristate
> +	depends on DRM
> +	help
> +	  AFBC is a proprietary lossless image compression protocol and format.
> +	  It provides fine-grained random access and minimizes the amount of
> +	  data transferred between IP blocks.

Uh a module option for 2 functions ... seems like massive overkill. Please
just put that into existing format helpers instead.

What's missing otoh is kernel doc for these.

> +
>  source "drivers/gpu/drm/i2c/Kconfig"
>  
>  source "drivers/gpu/drm/arm/Kconfig"
> diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile
> index 9f1c7c486f88..3a5d092ea514 100644
> --- a/drivers/gpu/drm/Makefile
> +++ b/drivers/gpu/drm/Makefile
> @@ -31,6 +31,7 @@ drm-$(CONFIG_OF) += drm_of.o
>  drm-$(CONFIG_AGP) += drm_agpsupport.o
>  drm-$(CONFIG_DEBUG_FS) += drm_debugfs.o drm_debugfs_crc.o
>  drm-$(CONFIG_DRM_LOAD_EDID_FIRMWARE) += drm_edid_load.o
> +drm-$(CONFIG_DRM_AFBC) += drm_afbc.o
>  
>  drm_vram_helper-y := drm_gem_vram_helper.o \
>  		     drm_vram_helper_common.o
> diff --git a/drivers/gpu/drm/arm/Kconfig b/drivers/gpu/drm/arm/Kconfig
> index a204103b3efb..25c3dc408cda 100644
> --- a/drivers/gpu/drm/arm/Kconfig
> +++ b/drivers/gpu/drm/arm/Kconfig
> @@ -29,6 +29,7 @@ config DRM_MALI_DISPLAY
>  	select DRM_KMS_HELPER
>  	select DRM_KMS_CMA_HELPER
>  	select DRM_GEM_CMA_HELPER
> +	select DRM_AFBC
>  	select VIDEOMODE_HELPERS
>  	help
>  	  Choose this option if you want to compile the ARM Mali Display
> diff --git a/drivers/gpu/drm/drm_afbc.c b/drivers/gpu/drm/drm_afbc.c
> new file mode 100644
> index 000000000000..010ca9eb0480
> --- /dev/null
> +++ b/drivers/gpu/drm/drm_afbc.c
> @@ -0,0 +1,129 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * (C) 2019 Collabora Ltd.
> + *
> + * author: Andrzej Pietrasiewicz <andrzej.p@collabora.com>
> + *
> + */
> +#include <linux/module.h>
> +
> +#include <drm/drm_afbc.h>
> +#include <drm/drm_device.h>
> +#include <drm/drm_fourcc.h>
> +#include <drm/drm_gem.h>
> +#include <drm/drm_mode.h>
> +#include <drm/drm_print.h>
> +
> +#define AFBC_HEADER_SIZE		16
> +
> +bool drm_afbc_check_offset(struct drm_device *dev,
> +			   const struct drm_mode_fb_cmd2 *mode_cmd)
> +{
> +	if (mode_cmd->offsets[0] != 0) {
> +		DRM_DEBUG_KMS("AFBC buffers' plane offset should be 0\n");
> +		return false;
> +	}
> +
> +	return true;
> +}
> +EXPORT_SYMBOL_GPL(drm_afbc_check_offset);
> +
> +bool drm_afbc_check_size_align(struct drm_device *dev,
> +			       const struct drm_mode_fb_cmd2 *mode_cmd)
> +{
> +	switch (mode_cmd->modifier[0] & AFBC_FORMAT_MOD_BLOCK_SIZE_MASK) {
> +	case AFBC_FORMAT_MOD_BLOCK_SIZE_16x16:
> +		if ((mode_cmd->width % 16) || (mode_cmd->height % 16)) {
> +			DRM_DEBUG_KMS(
> +				"AFBC buffer must be aligned to 16 pixels\n"
> +			);
> +			return false;
> +		}
> +		break;
> +	case AFBC_FORMAT_MOD_BLOCK_SIZE_32x8:
> +		/* fall through */
> +	case AFBC_FORMAT_MOD_BLOCK_SIZE_64x4:
> +		/* fall through */
> +	case AFBC_FORMAT_MOD_BLOCK_SIZE_32x8_64x4:
> +		/* fall through */
> +	default:
> +		DRM_DEBUG_KMS("Unsupported AFBC block size\n");
> +		return false;
> +	}
> +
> +	return true;
> +}
> +EXPORT_SYMBOL_GPL(drm_afbc_check_size_align);
> +
> +bool drm_afbc_get_superblk_wh(u64 modifier, u32 *w, u32 *h)
> +{
> +	switch (modifier & AFBC_FORMAT_MOD_BLOCK_SIZE_MASK) {
> +	case AFBC_FORMAT_MOD_BLOCK_SIZE_16x16:
> +		*w = 16;
> +		*h = 16;
> +		break;
> +	case AFBC_FORMAT_MOD_BLOCK_SIZE_32x8:
> +		*w = 32;
> +		*h = 8;
> +		break;
> +	case AFBC_FORMAT_MOD_BLOCK_SIZE_64x4:
> +		/* fall through */
> +	case AFBC_FORMAT_MOD_BLOCK_SIZE_32x8_64x4:
> +		/* fall through */
> +	default:
> +		DRM_DEBUG_KMS("Invalid AFBC_FORMAT_MOD_BLOCK_SIZE: %lld.\n",
> +			      modifier & AFBC_FORMAT_MOD_BLOCK_SIZE_MASK);
> +		return false;
> +	}
> +	return true;
> +}
> +EXPORT_SYMBOL_GPL(drm_afbc_get_superblk_wh);
> +
> +bool drm_afbc_check_fb_size_ret(u32 pitch, int bpp,
> +				u32 w, u32 h, u32 superblk_w, u32 superblk_h,
> +				size_t size, u32 offset, u32 hdr_align,
> +				u32 *payload_off, u32 *total_size)
> +{
> +	int n_superblks = 0;
> +	u32 superblk_sz = 0;
> +	u32 afbc_size = 0;
> +
> +	n_superblks = (w / superblk_w) * (h / superblk_h);
> +	superblk_sz = (bpp * superblk_w * superblk_h) / BITS_PER_BYTE;
> +	afbc_size = ALIGN(n_superblks * AFBC_HEADER_SIZE, hdr_align);
> +	*payload_off = afbc_size;
> +
> +	afbc_size += n_superblks * ALIGN(superblk_sz, AFBC_SUPERBLK_ALIGNMENT);
> +	*total_size = afbc_size + offset;
> +
> +	if ((w * bpp) != (pitch * BITS_PER_BYTE)) {
> +		DRM_DEBUG_KMS("Invalid value of (pitch * BITS_PER_BYTE) (=%u) should be same as width (=%u) * bpp (=%u)\n",
> +			      pitch * BITS_PER_BYTE, w, bpp
> +		);
> +		return false;
> +	}
> +
> +	if (size < afbc_size) {
> +		DRM_DEBUG_KMS("buffer size (%zu) too small for AFBC buffer size = %u\n",
> +			      size, afbc_size
> +		);
> +
> +		return false;
> +	}
> +
> +	return true;
> +}
> +EXPORT_SYMBOL(drm_afbc_check_fb_size_ret);
> +
> +bool drm_afbc_check_fb_size(u32 pitch, int bpp,
> +			    u32 w, u32 h, u32 superblk_w, u32 superblk_h,
> +			    size_t size, u32 offset, u32 hdr_align)
> +{
> +	u32 payload_offset, total_size;
> +
> +	return drm_afbc_check_fb_size_ret(pitch, bpp, w, h,
> +					  superblk_w, superblk_h,
> +					  size, offset, hdr_align,
> +					  &payload_offset, &total_size);
> +}
> +EXPORT_SYMBOL(drm_afbc_check_fb_size);

Why don't we have one overall "check afbc parameters against buffer"
function?

Also would be kinda neat if we could wire up that check code directly into
core addfb2 code, since afbc is a cross driver standard, everyone will
have to use the same code. Doing it that way would also solve your
kerneldoc need (since core code checks it directly). We already have an
example for the tiled nv12 format, which is also checked in core.

Cheers, Daniel

> diff --git a/include/drm/drm_afbc.h b/include/drm/drm_afbc.h
> new file mode 100644
> index 000000000000..b28ae2849f96
> --- /dev/null
> +++ b/include/drm/drm_afbc.h
> @@ -0,0 +1,36 @@
> +/* SPDX-License-Identifier: GPL-2.0+ */
> +/*
> + * (C) 2019 Collabora Ltd.
> + *
> + * author: Andrzej Pietrasiewicz <andrzej.p@collabora.com>
> + *
> + */
> +#ifndef __DRM_AFBC_H__
> +#define __DRM_AFBC_H__
> +
> +#include <linux/types.h>
> +
> +struct drm_device;
> +struct drm_mode_fb_cmd2;
> +struct drm_gem_object;
> +
> +#define AFBC_SUPERBLK_ALIGNMENT		128
> +
> +bool drm_afbc_check_offset(struct drm_device *dev,
> +			   const struct drm_mode_fb_cmd2 *mode_cmd);
> +
> +bool drm_afbc_check_size_align(struct drm_device *dev,
> +			       const struct drm_mode_fb_cmd2 *mode_cmd);
> +
> +bool drm_afbc_check_fb_size_ret(u32 pitch, int bpp,
> +				u32 w, u32 h, u32 superblk_w, u32 superblk_h,
> +				size_t size, u32 offset, u32 hdr_align,
> +				u32 *payload_off, u32 *total_size);
> +
> +bool drm_afbc_check_fb_size(u32 pitch, int bpp,
> +			    u32 w, u32 h, u32 superblk_w, u32 superblk_h,
> +			    size_t size, u32 offset, u32 hdr_align);
> +
> +bool drm_afbc_get_superblk_wh(u64 modifier, u32 *w, u32 *h);
> +
> +#endif /* __DRM_AFBC_H__ */
> -- 
> 2.17.1
> 

-- 
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 63+ messages in thread

* Re: [PATCHv2 1/4] drm/arm: Factor out generic afbc helpers
@ 2019-11-05 23:26             ` Daniel Stone
  0 siblings, 0 replies; 63+ messages in thread
From: Daniel Stone @ 2019-11-05 23:26 UTC (permalink / raw)
  To: Andrzej Pietrasiewicz, dri-devel
  Cc: Ayan Halder, kernel, David Airlie, Liviu Dudau, linux-rockchip,
	James Wang, Mihail Atanassov, Sean Paul

Hi Andrzej,
Thanks for taking this on! It's looking better than v1 for sure. A few
things below:

On Mon, 2019-11-04 at 23:12 +0100, Andrzej Pietrasiewicz wrote:
> +bool drm_afbc_check_offset(struct drm_device *dev,
> +			   const struct drm_mode_fb_cmd2 *mode_cmd)
> +{
> +	if (mode_cmd->offsets[0] != 0) {
> +		DRM_DEBUG_KMS("AFBC buffers' plane offset should be
> 0\n");
> +		return false;
> +	}
> +
> +	return true;
> +}
> +EXPORT_SYMBOL_GPL(drm_afbc_check_offset);

Is this actually universally true? If the offset is sufficiently
aligned for (e.g.) DMA transfers to succeed, is there any reason why it
must be zero?

> +bool drm_afbc_check_size_align(struct drm_device *dev,
> +			       const struct drm_mode_fb_cmd2 *mode_cmd)
> +{
> +	switch (mode_cmd->modifier[0] &
> AFBC_FORMAT_MOD_BLOCK_SIZE_MASK) {
> +	case AFBC_FORMAT_MOD_BLOCK_SIZE_16x16:
> +		if ((mode_cmd->width % 16) || (mode_cmd->height % 16))
> {

This is a dealbreaker for many resolutions: for example, 1366x768 isn't
cleanly divisible by 16 in width. So this means that we would have to
either use a larger buffer and crop, or scale, or something.

No userspace is prepared to align fb width/height to tile dimensions
like this, so this check will basically fail everywhere.

However, overallocation relative to the declared width/height isn't a
problem at all. In order to deal with horizontal alignment, you simply
need to ensure that the stride is a multiple of the tile width; for
vertical arrangement, that the buffer is large enough to contain
sufficient 'lines' to the next tile boundary.

i.e. rather than checking width/height, you should check:
  * fb_stride >= (ALIGN(fb_width, tile_width), bpp)
  * buf_size >= fb_stride * ALIGN(fb_height, tile_height)

This may force us to do some silly cropping games inside the Rockchip
KMS driver, but I feel it beats the alternative of breaking userspace.

> +			DRM_DEBUG_KMS(
> +				"AFBC buffer must be aligned to 16
> pixels\n"
> +			);
> +			return false;
> +		}
> +		break;
> +	case AFBC_FORMAT_MOD_BLOCK_SIZE_32x8:
> +		/* fall through */

It's also incongruous that 32x8 is unsupported here, but has a section
in get_superblk_wh; please harmonise them so this section either does
the checks as above, or that get_superblk_wh doesn't support 32x8
either.

> +bool drm_afbc_check_fb_size_ret(u32 pitch, int bpp,
> +				u32 w, u32 h, u32 superblk_w, u32
> superblk_h,
> +				size_t size, u32 offset, u32 hdr_align,
> +				u32 *payload_off, u32 *total_size)
> +{
> +	int n_superblks = 0;
> +	u32 superblk_sz = 0;
> +	u32 afbc_size = 0;

Please don't initialise the above three variables, given that you go on
to immediately change their values. In this case, initialising to zero
can only hide legitimate uninitialised-variable-use warnings.

> +	n_superblks = (w / superblk_w) * (h / superblk_h);
> +	superblk_sz = (bpp * superblk_w * superblk_h) / BITS_PER_BYTE;
> +	afbc_size = ALIGN(n_superblks * AFBC_HEADER_SIZE, hdr_align);
> +	*payload_off = afbc_size;
> +
> +	afbc_size += n_superblks * ALIGN(superblk_sz,
> AFBC_SUPERBLK_ALIGNMENT);
> +	*total_size = afbc_size + offset;

Generally these are referred to as 'tiles' rather than 'superblocks',
given that I would only expect one superblock per buffer, but if that's
the terminology AFBC uses then it might be better to stick with it.

> +	if ((w * bpp) != (pitch * BITS_PER_BYTE)) {
> +		DRM_DEBUG_KMS("Invalid value of (pitch * BITS_PER_BYTE)
> (=%u) should be same as width (=%u) * bpp (=%u)\n",
> +			      pitch * BITS_PER_BYTE, w, bpp
> +		);
> +		return false;
> +	}

Having a too-small pitch is obviously a problem and we should reject
it. But is having a too-large pitch really a problem; does it need to
be an exact match, or can we support the case where the pitch is too
large but also tile-aligned? If we can, it would be very good to
support that.

Cheers,
Daniel

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

^ permalink raw reply	[flat|nested] 63+ messages in thread

* Re: [PATCHv2 1/4] drm/arm: Factor out generic afbc helpers
@ 2019-11-05 23:26             ` Daniel Stone
  0 siblings, 0 replies; 63+ messages in thread
From: Daniel Stone @ 2019-11-05 23:26 UTC (permalink / raw)
  To: Andrzej Pietrasiewicz, dri-devel
  Cc: Ayan Halder, kernel, David Airlie, Liviu Dudau, linux-rockchip,
	James Wang, Mihail Atanassov, Sean Paul

Hi Andrzej,
Thanks for taking this on! It's looking better than v1 for sure. A few
things below:

On Mon, 2019-11-04 at 23:12 +0100, Andrzej Pietrasiewicz wrote:
> +bool drm_afbc_check_offset(struct drm_device *dev,
> +			   const struct drm_mode_fb_cmd2 *mode_cmd)
> +{
> +	if (mode_cmd->offsets[0] != 0) {
> +		DRM_DEBUG_KMS("AFBC buffers' plane offset should be
> 0\n");
> +		return false;
> +	}
> +
> +	return true;
> +}
> +EXPORT_SYMBOL_GPL(drm_afbc_check_offset);

Is this actually universally true? If the offset is sufficiently
aligned for (e.g.) DMA transfers to succeed, is there any reason why it
must be zero?

> +bool drm_afbc_check_size_align(struct drm_device *dev,
> +			       const struct drm_mode_fb_cmd2 *mode_cmd)
> +{
> +	switch (mode_cmd->modifier[0] &
> AFBC_FORMAT_MOD_BLOCK_SIZE_MASK) {
> +	case AFBC_FORMAT_MOD_BLOCK_SIZE_16x16:
> +		if ((mode_cmd->width % 16) || (mode_cmd->height % 16))
> {

This is a dealbreaker for many resolutions: for example, 1366x768 isn't
cleanly divisible by 16 in width. So this means that we would have to
either use a larger buffer and crop, or scale, or something.

No userspace is prepared to align fb width/height to tile dimensions
like this, so this check will basically fail everywhere.

However, overallocation relative to the declared width/height isn't a
problem at all. In order to deal with horizontal alignment, you simply
need to ensure that the stride is a multiple of the tile width; for
vertical arrangement, that the buffer is large enough to contain
sufficient 'lines' to the next tile boundary.

i.e. rather than checking width/height, you should check:
  * fb_stride >= (ALIGN(fb_width, tile_width), bpp)
  * buf_size >= fb_stride * ALIGN(fb_height, tile_height)

This may force us to do some silly cropping games inside the Rockchip
KMS driver, but I feel it beats the alternative of breaking userspace.

> +			DRM_DEBUG_KMS(
> +				"AFBC buffer must be aligned to 16
> pixels\n"
> +			);
> +			return false;
> +		}
> +		break;
> +	case AFBC_FORMAT_MOD_BLOCK_SIZE_32x8:
> +		/* fall through */

It's also incongruous that 32x8 is unsupported here, but has a section
in get_superblk_wh; please harmonise them so this section either does
the checks as above, or that get_superblk_wh doesn't support 32x8
either.

> +bool drm_afbc_check_fb_size_ret(u32 pitch, int bpp,
> +				u32 w, u32 h, u32 superblk_w, u32
> superblk_h,
> +				size_t size, u32 offset, u32 hdr_align,
> +				u32 *payload_off, u32 *total_size)
> +{
> +	int n_superblks = 0;
> +	u32 superblk_sz = 0;
> +	u32 afbc_size = 0;

Please don't initialise the above three variables, given that you go on
to immediately change their values. In this case, initialising to zero
can only hide legitimate uninitialised-variable-use warnings.

> +	n_superblks = (w / superblk_w) * (h / superblk_h);
> +	superblk_sz = (bpp * superblk_w * superblk_h) / BITS_PER_BYTE;
> +	afbc_size = ALIGN(n_superblks * AFBC_HEADER_SIZE, hdr_align);
> +	*payload_off = afbc_size;
> +
> +	afbc_size += n_superblks * ALIGN(superblk_sz,
> AFBC_SUPERBLK_ALIGNMENT);
> +	*total_size = afbc_size + offset;

Generally these are referred to as 'tiles' rather than 'superblocks',
given that I would only expect one superblock per buffer, but if that's
the terminology AFBC uses then it might be better to stick with it.

> +	if ((w * bpp) != (pitch * BITS_PER_BYTE)) {
> +		DRM_DEBUG_KMS("Invalid value of (pitch * BITS_PER_BYTE)
> (=%u) should be same as width (=%u) * bpp (=%u)\n",
> +			      pitch * BITS_PER_BYTE, w, bpp
> +		);
> +		return false;
> +	}

Having a too-small pitch is obviously a problem and we should reject
it. But is having a too-large pitch really a problem; does it need to
be an exact match, or can we support the case where the pitch is too
large but also tile-aligned? If we can, it would be very good to
support that.

Cheers,
Daniel

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

^ permalink raw reply	[flat|nested] 63+ messages in thread

* Re: [PATCHv2 4/4] drm/rockchip: Add support for afbc
@ 2019-11-05 23:34             ` Daniel Stone
  0 siblings, 0 replies; 63+ messages in thread
From: Daniel Stone @ 2019-11-05 23:34 UTC (permalink / raw)
  To: Andrzej Pietrasiewicz, dri-devel
  Cc: Ayan Halder, kernel, David Airlie, Liviu Dudau, linux-rockchip,
	James Wang, Mihail Atanassov, Sean Paul, Mark Yao

Hi Andrzej,

On Mon, 2019-11-04 at 23:12 +0100, Andrzej Pietrasiewicz wrote:
> +	if (mode_cmd->modifier[0]) {

I believe this can still be DRM_FORMAT_MOD_INVALID, which != 0. You
probably want to explicitly check if it's an AFBC modifier.

> +		const struct drm_format_info *info;
> +		int bpp;
> +
> +		if (!drm_afbc_check_offset(dev, mode_cmd))
> +			return ERR_PTR(-EINVAL);
> +
> +		if (!drm_afbc_get_superblk_wh(mode_cmd->modifier[0],
> &w, &h))
> +			return ERR_PTR(-EINVAL);
> +
> +		if (w != 16 || h != 16) {
> +			DRM_DEV_ERROR(dev->dev,
> +				"Unsupported afbc tile w/h [%d/%d]\n",
> w, h);

This can just be a WARN_ONCE() or something, since it indicates an
impossible condition - the DRM core should've already rejected this
modifier as unsupported.

> +		if (mode_cmd->width > ROCKCHIP_MAX_AFBC_WIDTH) {
> +			DRM_DEV_ERROR(dev->dev,
> +				      "Unsupported width %d>%d\n",
> +				      mode_cmd->width,
> +				      ROCKCHIP_MAX_AFBC_WIDTH
> +			);

Userspace shouldn't be allowed to spam the log by triggering error
messages; please make this debug instead. Whilst you're there, adding
logs to the other error returns here might be useful.

> @@ -166,6 +179,7 @@ struct vop {
>  	/* optional internal rgb encoder */
>  	struct rockchip_rgb *rgb;
>  
> +	struct vop_win *afbc_win;

It seems like everywhere afbc_win is used, it's not actually used for
the window value, but rather just used as an is_afbc_enabled bool. In
that case, it would be better as a real bool, and living in either the
output or plane state.

This would eliminate the need to unset the variable as well.

Relatedly, can one VOP support multiple simultaneous windows using
AFBC? If not, the check that only one window is using AFBC is missing
from this patch.

> +static int vop_convert_afbc_format(uint32_t format)
> +{
> +	switch (format) {
> +	case DRM_FORMAT_XRGB8888:
> +	case DRM_FORMAT_ARGB8888:
> +	case DRM_FORMAT_XBGR8888:
> +	case DRM_FORMAT_ABGR8888:
> +		return AFBC_FMT_U8U8U8U8;
> +	case DRM_FORMAT_RGB888:
> +	case DRM_FORMAT_BGR888:
> +		return AFBC_FMT_U8U8U8;
> +	case DRM_FORMAT_RGB565:
> +	case DRM_FORMAT_BGR565:
> +		return AFBC_FMT_RGB565;
> +	/* either of the below should not be reachable */

Unreachable can be WARN_ONCE() rather than a silent return.

Other than that, this is looking a _lot_ nicer than v1 though!

Cheers,
Daniel

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

^ permalink raw reply	[flat|nested] 63+ messages in thread

* Re: [PATCHv2 4/4] drm/rockchip: Add support for afbc
@ 2019-11-05 23:34             ` Daniel Stone
  0 siblings, 0 replies; 63+ messages in thread
From: Daniel Stone @ 2019-11-05 23:34 UTC (permalink / raw)
  To: Andrzej Pietrasiewicz, dri-devel
  Cc: Ayan Halder, kernel, David Airlie, Liviu Dudau, linux-rockchip,
	James Wang, Mihail Atanassov, Sean Paul, Mark Yao

Hi Andrzej,

On Mon, 2019-11-04 at 23:12 +0100, Andrzej Pietrasiewicz wrote:
> +	if (mode_cmd->modifier[0]) {

I believe this can still be DRM_FORMAT_MOD_INVALID, which != 0. You
probably want to explicitly check if it's an AFBC modifier.

> +		const struct drm_format_info *info;
> +		int bpp;
> +
> +		if (!drm_afbc_check_offset(dev, mode_cmd))
> +			return ERR_PTR(-EINVAL);
> +
> +		if (!drm_afbc_get_superblk_wh(mode_cmd->modifier[0],
> &w, &h))
> +			return ERR_PTR(-EINVAL);
> +
> +		if (w != 16 || h != 16) {
> +			DRM_DEV_ERROR(dev->dev,
> +				"Unsupported afbc tile w/h [%d/%d]\n",
> w, h);

This can just be a WARN_ONCE() or something, since it indicates an
impossible condition - the DRM core should've already rejected this
modifier as unsupported.

> +		if (mode_cmd->width > ROCKCHIP_MAX_AFBC_WIDTH) {
> +			DRM_DEV_ERROR(dev->dev,
> +				      "Unsupported width %d>%d\n",
> +				      mode_cmd->width,
> +				      ROCKCHIP_MAX_AFBC_WIDTH
> +			);

Userspace shouldn't be allowed to spam the log by triggering error
messages; please make this debug instead. Whilst you're there, adding
logs to the other error returns here might be useful.

> @@ -166,6 +179,7 @@ struct vop {
>  	/* optional internal rgb encoder */
>  	struct rockchip_rgb *rgb;
>  
> +	struct vop_win *afbc_win;

It seems like everywhere afbc_win is used, it's not actually used for
the window value, but rather just used as an is_afbc_enabled bool. In
that case, it would be better as a real bool, and living in either the
output or plane state.

This would eliminate the need to unset the variable as well.

Relatedly, can one VOP support multiple simultaneous windows using
AFBC? If not, the check that only one window is using AFBC is missing
from this patch.

> +static int vop_convert_afbc_format(uint32_t format)
> +{
> +	switch (format) {
> +	case DRM_FORMAT_XRGB8888:
> +	case DRM_FORMAT_ARGB8888:
> +	case DRM_FORMAT_XBGR8888:
> +	case DRM_FORMAT_ABGR8888:
> +		return AFBC_FMT_U8U8U8U8;
> +	case DRM_FORMAT_RGB888:
> +	case DRM_FORMAT_BGR888:
> +		return AFBC_FMT_U8U8U8;
> +	case DRM_FORMAT_RGB565:
> +	case DRM_FORMAT_BGR565:
> +		return AFBC_FMT_RGB565;
> +	/* either of the below should not be reachable */

Unreachable can be WARN_ONCE() rather than a silent return.

Other than that, this is looking a _lot_ nicer than v1 though!

Cheers,
Daniel

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

^ permalink raw reply	[flat|nested] 63+ messages in thread

* Re: [PATCHv2 1/4] drm/arm: Factor out generic afbc helpers
  2019-11-05 23:26             ` Daniel Stone
  (?)
@ 2019-11-06 10:28             ` Liviu Dudau
  -1 siblings, 0 replies; 63+ messages in thread
From: Liviu Dudau @ 2019-11-06 10:28 UTC (permalink / raw)
  To: Daniel Stone
  Cc: Ayan Halder, kernel, David Airlie, Andrzej Pietrasiewicz,
	linux-rockchip, James Wang, dri-devel, Mihail Atanassov,
	Sean Paul

Hi Andrzej,

On Tue, Nov 05, 2019 at 11:26:36PM +0000, Daniel Stone wrote:
> Hi Andrzej,
> Thanks for taking this on! It's looking better than v1 for sure. A few
> things below:
> 
> On Mon, 2019-11-04 at 23:12 +0100, Andrzej Pietrasiewicz wrote:
> > +bool drm_afbc_check_offset(struct drm_device *dev,
> > +			   const struct drm_mode_fb_cmd2 *mode_cmd)
> > +{
> > +	if (mode_cmd->offsets[0] != 0) {
> > +		DRM_DEBUG_KMS("AFBC buffers' plane offset should be
> > 0\n");
> > +		return false;
> > +	}
> > +
> > +	return true;
> > +}
> > +EXPORT_SYMBOL_GPL(drm_afbc_check_offset);
> 
> Is this actually universally true? If the offset is sufficiently
> aligned for (e.g.) DMA transfers to succeed, is there any reason why it
> must be zero?
> 
> > +bool drm_afbc_check_size_align(struct drm_device *dev,
> > +			       const struct drm_mode_fb_cmd2 *mode_cmd)
> > +{
> > +	switch (mode_cmd->modifier[0] &
> > AFBC_FORMAT_MOD_BLOCK_SIZE_MASK) {
> > +	case AFBC_FORMAT_MOD_BLOCK_SIZE_16x16:
> > +		if ((mode_cmd->width % 16) || (mode_cmd->height % 16))
> > {
> 
> This is a dealbreaker for many resolutions: for example, 1366x768 isn't
> cleanly divisible by 16 in width. So this means that we would have to
> either use a larger buffer and crop, or scale, or something.
> 
> No userspace is prepared to align fb width/height to tile dimensions
> like this, so this check will basically fail everywhere.

I agree with Daniel, for AFBC_FORMAT_MOD_BLOCK_SIZE_xxxx you need to check that the
allocated framebuffer's width and height are divisible by block size, not what the
resolution of the mode is.

Best regards,
Liviu

> 
> However, overallocation relative to the declared width/height isn't a
> problem at all. In order to deal with horizontal alignment, you simply
> need to ensure that the stride is a multiple of the tile width; for
> vertical arrangement, that the buffer is large enough to contain
> sufficient 'lines' to the next tile boundary.
> 
> i.e. rather than checking width/height, you should check:
>   * fb_stride >= (ALIGN(fb_width, tile_width), bpp)
>   * buf_size >= fb_stride * ALIGN(fb_height, tile_height)
> 
> This may force us to do some silly cropping games inside the Rockchip
> KMS driver, but I feel it beats the alternative of breaking userspace.
> 
> > +			DRM_DEBUG_KMS(
> > +				"AFBC buffer must be aligned to 16
> > pixels\n"
> > +			);
> > +			return false;
> > +		}
> > +		break;
> > +	case AFBC_FORMAT_MOD_BLOCK_SIZE_32x8:
> > +		/* fall through */
> 
> It's also incongruous that 32x8 is unsupported here, but has a section
> in get_superblk_wh; please harmonise them so this section either does
> the checks as above, or that get_superblk_wh doesn't support 32x8
> either.
> 
> > +bool drm_afbc_check_fb_size_ret(u32 pitch, int bpp,
> > +				u32 w, u32 h, u32 superblk_w, u32
> > superblk_h,
> > +				size_t size, u32 offset, u32 hdr_align,
> > +				u32 *payload_off, u32 *total_size)
> > +{
> > +	int n_superblks = 0;
> > +	u32 superblk_sz = 0;
> > +	u32 afbc_size = 0;
> 
> Please don't initialise the above three variables, given that you go on
> to immediately change their values. In this case, initialising to zero
> can only hide legitimate uninitialised-variable-use warnings.
> 
> > +	n_superblks = (w / superblk_w) * (h / superblk_h);
> > +	superblk_sz = (bpp * superblk_w * superblk_h) / BITS_PER_BYTE;
> > +	afbc_size = ALIGN(n_superblks * AFBC_HEADER_SIZE, hdr_align);
> > +	*payload_off = afbc_size;
> > +
> > +	afbc_size += n_superblks * ALIGN(superblk_sz,
> > AFBC_SUPERBLK_ALIGNMENT);
> > +	*total_size = afbc_size + offset;
> 
> Generally these are referred to as 'tiles' rather than 'superblocks',
> given that I would only expect one superblock per buffer, but if that's
> the terminology AFBC uses then it might be better to stick with it.
> 
> > +	if ((w * bpp) != (pitch * BITS_PER_BYTE)) {
> > +		DRM_DEBUG_KMS("Invalid value of (pitch * BITS_PER_BYTE)
> > (=%u) should be same as width (=%u) * bpp (=%u)\n",
> > +			      pitch * BITS_PER_BYTE, w, bpp
> > +		);
> > +		return false;
> > +	}
> 
> Having a too-small pitch is obviously a problem and we should reject
> it. But is having a too-large pitch really a problem; does it need to
> be an exact match, or can we support the case where the pitch is too
> large but also tile-aligned? If we can, it would be very good to
> support that.
> 
> Cheers,
> Daniel
> 

-- 
====================
| I would like to |
| fix the world,  |
| but they're not |
| giving me the   |
 \ source code!  /
  ---------------
    ¯\_(ツ)_/¯
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 63+ messages in thread

* Re: [PATCHv2 2/4] drm/malidp: use afbc helpers
  2019-11-04 22:12         ` [PATCHv2 2/4] drm/malidp: use " Andrzej Pietrasiewicz
@ 2019-11-06 11:09           ` Liviu Dudau
  0 siblings, 0 replies; 63+ messages in thread
From: Liviu Dudau @ 2019-11-06 11:09 UTC (permalink / raw)
  To: Andrzej Pietrasiewicz
  Cc: Ayan Halder, kernel, David Airlie, linux-rockchip, James Wang,
	dri-devel, Mihail Atanassov, Sean Paul

Hi Andrzej,

On Mon, Nov 04, 2019 at 11:12:26PM +0100, Andrzej Pietrasiewicz wrote:
> There are afbc helpers available.
> 
> Signed-off-by: Andrzej Pietrasiewicz <andrzej.p@collabora.com>
> ---
>  drivers/gpu/drm/arm/malidp_drv.c | 66 ++++++--------------------------
>  1 file changed, 12 insertions(+), 54 deletions(-)
> 
> diff --git a/drivers/gpu/drm/arm/malidp_drv.c b/drivers/gpu/drm/arm/malidp_drv.c
> index 37d92a06318e..ab93588cc8eb 100644
> --- a/drivers/gpu/drm/arm/malidp_drv.c
> +++ b/drivers/gpu/drm/arm/malidp_drv.c
> @@ -15,6 +15,7 @@
>  #include <linux/pm_runtime.h>
>  #include <linux/debugfs.h>
>  
> +#include <drm/drm_afbc.h>
>  #include <drm/drm_atomic.h>
>  #include <drm/drm_atomic_helper.h>
>  #include <drm/drm_crtc.h>
> @@ -35,8 +36,6 @@
>  #include "malidp_hw.h"
>  
>  #define MALIDP_CONF_VALID_TIMEOUT	250
> -#define AFBC_HEADER_SIZE		16
> -#define AFBC_SUPERBLK_ALIGNMENT		128
>  
>  static void malidp_write_gamma_table(struct malidp_hw_device *hwdev,
>  				     u32 data[MALIDP_COEFFTAB_NUM_COEFFS])
> @@ -277,24 +276,8 @@ malidp_verify_afbc_framebuffer_caps(struct drm_device *dev,
>  					mode_cmd->modifier[0]) == false)
>  		return false;
>  
> -	if (mode_cmd->offsets[0] != 0) {
> -		DRM_DEBUG_KMS("AFBC buffers' plane offset should be 0\n");
> -		return false;
> -	}
> -
> -	switch (mode_cmd->modifier[0] & AFBC_SIZE_MASK) {
> -	case AFBC_SIZE_16X16:
> -		if ((mode_cmd->width % 16) || (mode_cmd->height % 16)) {
> -			DRM_DEBUG_KMS("AFBC buffers must be aligned to 16 pixels\n");
> -			return false;
> -		}
> -		break;
> -	default:
> -		DRM_DEBUG_KMS("Unsupported AFBC block size\n");
> -		return false;
> -	}
> -
> -	return true;
> +	return drm_afbc_check_offset(dev, mode_cmd) &&
> +	       drm_afbc_check_size_align(dev, mode_cmd);
>  }

Given that the content of this function gets copied pretty much verbatim into the new
drm_afbc.c file, I suggest you make the change in the 1/4 patch and also update the
copyright statement in that file to show that the code originated from here.

Best regards,
Liviu

>  
>  static bool
> @@ -302,54 +285,29 @@ malidp_verify_afbc_framebuffer_size(struct drm_device *dev,
>  				    struct drm_file *file,
>  				    const struct drm_mode_fb_cmd2 *mode_cmd)
>  {
> -	int n_superblocks = 0;
>  	const struct drm_format_info *info;
>  	struct drm_gem_object *objs = NULL;
> -	u32 afbc_superblock_size = 0, afbc_superblock_height = 0;
> -	u32 afbc_superblock_width = 0, afbc_size = 0;
>  	int bpp = 0;
> -
> -	switch (mode_cmd->modifier[0] & AFBC_SIZE_MASK) {
> -	case AFBC_SIZE_16X16:
> -		afbc_superblock_height = 16;
> -		afbc_superblock_width = 16;
> -		break;
> -	default:
> -		DRM_DEBUG_KMS("AFBC superblock size is not supported\n");
> -		return false;
> -	}
> +	u32 w, h;
>  
>  	info = drm_get_format_info(dev, mode_cmd);
> -
> -	n_superblocks = (mode_cmd->width / afbc_superblock_width) *
> -		(mode_cmd->height / afbc_superblock_height);
> -
>  	bpp = malidp_format_get_bpp(info->format);
>  
> -	afbc_superblock_size = (bpp * afbc_superblock_width * afbc_superblock_height)
> -				/ BITS_PER_BYTE;
> -
> -	afbc_size = ALIGN(n_superblocks * AFBC_HEADER_SIZE, AFBC_SUPERBLK_ALIGNMENT);
> -	afbc_size += n_superblocks * ALIGN(afbc_superblock_size, AFBC_SUPERBLK_ALIGNMENT);
> -
> -	if ((mode_cmd->width * bpp) != (mode_cmd->pitches[0] * BITS_PER_BYTE)) {
> -		DRM_DEBUG_KMS("Invalid value of (pitch * BITS_PER_BYTE) (=%u) "
> -			      "should be same as width (=%u) * bpp (=%u)\n",
> -			      (mode_cmd->pitches[0] * BITS_PER_BYTE),
> -			      mode_cmd->width, bpp);
> -		return false;
> -	}
> -
>  	objs = drm_gem_object_lookup(file, mode_cmd->handles[0]);
>  	if (!objs) {
>  		DRM_DEBUG_KMS("Failed to lookup GEM object\n");
>  		return false;
>  	}
>  
> -	if (objs->size < afbc_size) {
> -		DRM_DEBUG_KMS("buffer size (%zu) too small for AFBC buffer size = %u\n",
> -			      objs->size, afbc_size);
> +	if (!drm_afbc_get_superblk_wh(mode_cmd->modifier[0], &w, &h))
> +		return false;
> +
> +	if (!drm_afbc_check_fb_size(mode_cmd->pitches[0], bpp,
> +				    mode_cmd->width, mode_cmd->height, w, h,
> +				    objs->size, mode_cmd->offsets[0],
> +				    AFBC_SUPERBLK_ALIGNMENT)) {
>  		drm_gem_object_put_unlocked(objs);
> +
>  		return false;
>  	}
>  
> -- 
> 2.17.1
> 

-- 
====================
| I would like to |
| fix the world,  |
| but they're not |
| giving me the   |
 \ source code!  /
  ---------------
    ¯\_(ツ)_/¯
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 63+ messages in thread

* Re: [PATCHv2 1/4] drm/arm: Factor out generic afbc helpers
  2019-11-05  9:22           ` Daniel Vetter
@ 2019-11-06 12:45             ` Andrzej Pietrasiewicz
  2019-11-07  8:27               ` Daniel Vetter
  0 siblings, 1 reply; 63+ messages in thread
From: Andrzej Pietrasiewicz @ 2019-11-06 12:45 UTC (permalink / raw)
  To: Daniel Vetter
  Cc: kernel, Mihail Atanassov, David Airlie, Liviu Dudau, dri-devel,
	linux-rockchip, James Wang, Ayan Halder, Sean Paul

Hi Daniel,

Thank you for review,

W dniu 05.11.2019 o 10:22, Daniel Vetter pisze:
> On Mon, Nov 04, 2019 at 11:12:25PM +0100, Andrzej Pietrasiewicz wrote:
>> These are useful for other users of afbc, e.g. rockchip.
>>

<snip>

>> +
>> +bool drm_afbc_check_fb_size_ret(u32 pitch, int bpp,
>> +				u32 w, u32 h, u32 superblk_w, u32 superblk_h,
>> +				size_t size, u32 offset, u32 hdr_align,
>> +				u32 *payload_off, u32 *total_size)
>> +{
>> +	int n_superblks = 0;
>> +	u32 superblk_sz = 0;
>> +	u32 afbc_size = 0;
>> +
>> +	n_superblks = (w / superblk_w) * (h / superblk_h);
>> +	superblk_sz = (bpp * superblk_w * superblk_h) / BITS_PER_BYTE;
>> +	afbc_size = ALIGN(n_superblks * AFBC_HEADER_SIZE, hdr_align);
>> +	*payload_off = afbc_size;
>> +
>> +	afbc_size += n_superblks * ALIGN(superblk_sz, AFBC_SUPERBLK_ALIGNMENT);
>> +	*total_size = afbc_size + offset;
>> +
>> +	if ((w * bpp) != (pitch * BITS_PER_BYTE)) {
>> +		DRM_DEBUG_KMS("Invalid value of (pitch * BITS_PER_BYTE) (=%u) should be same as width (=%u) * bpp (=%u)\n",
>> +			      pitch * BITS_PER_BYTE, w, bpp
>> +		);
>> +		return false;
>> +	}
>> +
>> +	if (size < afbc_size) {
>> +		DRM_DEBUG_KMS("buffer size (%zu) too small for AFBC buffer size = %u\n",
>> +			      size, afbc_size
>> +		);
>> +
>> +		return false;
>> +	}
>> +
>> +	return true;
>> +}
>> +EXPORT_SYMBOL(drm_afbc_check_fb_size_ret);
>> +
>> +bool drm_afbc_check_fb_size(u32 pitch, int bpp,
>> +			    u32 w, u32 h, u32 superblk_w, u32 superblk_h,
>> +			    size_t size, u32 offset, u32 hdr_align)
>> +{
>> +	u32 payload_offset, total_size;
>> +
>> +	return drm_afbc_check_fb_size_ret(pitch, bpp, w, h,
>> +					  superblk_w, superblk_h,
>> +					  size, offset, hdr_align,
>> +					  &payload_offset, &total_size);
>> +}
>> +EXPORT_SYMBOL(drm_afbc_check_fb_size);
> 
> Why don't we have one overall "check afbc parameters against buffer"
> function?
> 

I noticed that different drivers have different needs (malidp
and rockchip are kind of similar, but komeda is a bit different).
That is why the helpers are only building blocks out of which
each driver builds its own checking logic. In particular komeda
wants some by-products of the check stored in its internal data
structures, hence drm_afbc_check_fb_size_ret() and its wrapper
drm_afbc_check_fb_size() which ignores the "out" parameters.

If I wanted to create one overall "check afbc parameters" I'd have
to come up with a way to pass driver-specific requirements to it
and then inside the function have some logic to decide what to
check against what. Do you think it is worth it?

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

^ permalink raw reply	[flat|nested] 63+ messages in thread

* Re: [PATCHv2 1/4] drm/arm: Factor out generic afbc helpers
  2019-11-06 12:45             ` Andrzej Pietrasiewicz
@ 2019-11-07  8:27               ` Daniel Vetter
  0 siblings, 0 replies; 63+ messages in thread
From: Daniel Vetter @ 2019-11-07  8:27 UTC (permalink / raw)
  To: Andrzej Pietrasiewicz
  Cc: kernel, Mihail Atanassov, David Airlie, Liviu Dudau, dri-devel,
	linux-rockchip, James Wang, Ayan Halder, Sean Paul

On Wed, Nov 06, 2019 at 01:45:05PM +0100, Andrzej Pietrasiewicz wrote:
> Hi Daniel,
> 
> Thank you for review,
> 
> W dniu 05.11.2019 o 10:22, Daniel Vetter pisze:
> > On Mon, Nov 04, 2019 at 11:12:25PM +0100, Andrzej Pietrasiewicz wrote:
> > > These are useful for other users of afbc, e.g. rockchip.
> > > 
> 
> <snip>
> 
> > > +
> > > +bool drm_afbc_check_fb_size_ret(u32 pitch, int bpp,
> > > +				u32 w, u32 h, u32 superblk_w, u32 superblk_h,
> > > +				size_t size, u32 offset, u32 hdr_align,
> > > +				u32 *payload_off, u32 *total_size)
> > > +{
> > > +	int n_superblks = 0;
> > > +	u32 superblk_sz = 0;
> > > +	u32 afbc_size = 0;
> > > +
> > > +	n_superblks = (w / superblk_w) * (h / superblk_h);
> > > +	superblk_sz = (bpp * superblk_w * superblk_h) / BITS_PER_BYTE;
> > > +	afbc_size = ALIGN(n_superblks * AFBC_HEADER_SIZE, hdr_align);
> > > +	*payload_off = afbc_size;
> > > +
> > > +	afbc_size += n_superblks * ALIGN(superblk_sz, AFBC_SUPERBLK_ALIGNMENT);
> > > +	*total_size = afbc_size + offset;
> > > +
> > > +	if ((w * bpp) != (pitch * BITS_PER_BYTE)) {
> > > +		DRM_DEBUG_KMS("Invalid value of (pitch * BITS_PER_BYTE) (=%u) should be same as width (=%u) * bpp (=%u)\n",
> > > +			      pitch * BITS_PER_BYTE, w, bpp
> > > +		);
> > > +		return false;
> > > +	}
> > > +
> > > +	if (size < afbc_size) {
> > > +		DRM_DEBUG_KMS("buffer size (%zu) too small for AFBC buffer size = %u\n",
> > > +			      size, afbc_size
> > > +		);
> > > +
> > > +		return false;
> > > +	}
> > > +
> > > +	return true;
> > > +}
> > > +EXPORT_SYMBOL(drm_afbc_check_fb_size_ret);
> > > +
> > > +bool drm_afbc_check_fb_size(u32 pitch, int bpp,
> > > +			    u32 w, u32 h, u32 superblk_w, u32 superblk_h,
> > > +			    size_t size, u32 offset, u32 hdr_align)
> > > +{
> > > +	u32 payload_offset, total_size;
> > > +
> > > +	return drm_afbc_check_fb_size_ret(pitch, bpp, w, h,
> > > +					  superblk_w, superblk_h,
> > > +					  size, offset, hdr_align,
> > > +					  &payload_offset, &total_size);
> > > +}
> > > +EXPORT_SYMBOL(drm_afbc_check_fb_size);
> > 
> > Why don't we have one overall "check afbc parameters against buffer"
> > function?
> > 
> 
> I noticed that different drivers have different needs (malidp
> and rockchip are kind of similar, but komeda is a bit different).
> That is why the helpers are only building blocks out of which
> each driver builds its own checking logic. In particular komeda
> wants some by-products of the check stored in its internal data
> structures, hence drm_afbc_check_fb_size_ret() and its wrapper
> drm_afbc_check_fb_size() which ignores the "out" parameters.
> 
> If I wanted to create one overall "check afbc parameters" I'd have
> to come up with a way to pass driver-specific requirements to it
> and then inside the function have some logic to decide what to
> check against what. Do you think it is worth it?

Hm I figured there's at least two parts of this:
- Generic checking of afbc against the fb parameters, i.e. is it big
  enough, correctly aligned, all that.
- Additional driver checks, which might need some of the same parameters
  again.

The idea behind asking for the first part is that maybe we should put that
into the core as part of the addfb checks (like we do for the tiled NV12
thing already). Then drivers only need to do additional checks on top for
their specific constraints. For that you could expose some helpers ofc (to
get the payload_offset and anything else computed you might need).

But the basic drm_afbc_check_fb_size() should imo be done unconditionally
for any afbc modifier. To make sure we don't have lots of drivers with
different bugs in that thing.
-Daniel
-- 
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 63+ messages in thread

* Re: [PATCHv2 1/4] drm/arm: Factor out generic afbc helpers
@ 2019-11-07 17:20               ` Brian Starkey
  0 siblings, 0 replies; 63+ messages in thread
From: Brian Starkey @ 2019-11-07 17:20 UTC (permalink / raw)
  To: Daniel Stone
  Cc: Ayan Halder, kernel, David Airlie, Liviu Dudau,
	Andrzej Pietrasiewicz, linux-rockchip,
	james qian wang (Arm Technology China),
	dri-devel, Mihail Atanassov, Sean Paul

Hi Daniel,

On Tue, Nov 05, 2019 at 11:26:36PM +0000, Daniel Stone wrote:
> Hi Andrzej,
> Thanks for taking this on! It's looking better than v1 for sure. A few
> things below:
>
> On Mon, 2019-11-04 at 23:12 +0100, Andrzej Pietrasiewicz wrote:
> > +bool drm_afbc_check_offset(struct drm_device *dev,
> > +                      const struct drm_mode_fb_cmd2 *mode_cmd)
> > +{
> > +   if (mode_cmd->offsets[0] != 0) {
> > +           DRM_DEBUG_KMS("AFBC buffers' plane offset should be
> > 0\n");
> > +           return false;
> > +   }
> > +
> > +   return true;
> > +}
> > +EXPORT_SYMBOL_GPL(drm_afbc_check_offset);
>
> Is this actually universally true? If the offset is sufficiently
> aligned for (e.g.) DMA transfers to succeed, is there any reason why it
> must be zero?
>
> > +bool drm_afbc_check_size_align(struct drm_device *dev,
> > +                          const struct drm_mode_fb_cmd2 *mode_cmd)
> > +{
> > +   switch (mode_cmd->modifier[0] &
> > AFBC_FORMAT_MOD_BLOCK_SIZE_MASK) {
> > +   case AFBC_FORMAT_MOD_BLOCK_SIZE_16x16:
> > +           if ((mode_cmd->width % 16) || (mode_cmd->height % 16))
> > {
>
> This is a dealbreaker for many resolutions: for example, 1366x768 isn't
> cleanly divisible by 16 in width. So this means that we would have to
> either use a larger buffer and crop, or scale, or something.
>
> No userspace is prepared to align fb width/height to tile dimensions
> like this, so this check will basically fail everywhere.
>
> However, overallocation relative to the declared width/height isn't a
> problem at all. In order to deal with horizontal alignment, you simply
> need to ensure that the stride is a multiple of the tile width; for
> vertical arrangement, that the buffer is large enough to contain
> sufficient 'lines' to the next tile boundary.
>
> i.e. rather than checking width/height, you should check:
>   * fb_stride >= (ALIGN(fb_width, tile_width), bpp)
>   * buf_size >= fb_stride * ALIGN(fb_height, tile_height)

Well, sort of.

I agree with you that for horizontal padding, we can indeed use pitch.

However, the AFBC decoder(s) need to know exactly what the total
_allocated_ size in pixels of the buffer is - as this influences the
header size, and we need to know the header size to know where it ends
and the body begins.

I see a couple of possible ways forwards:

 - Keep it as-is. The restrictive checks ensure that there's no
   ambiguity and we use the fb width/height to determine the real
   allocated width/height. Userspace needs to be AFBC-aware and set up
   plane cropping to handle the alignment differences.

 - Use pitch to determine the "real" width, and internally in the
   kernel align height up to the next alignment boundary. This works
   OK, so long as there's no additional padding at the bottom of the
   buffer. This would work, but I can't figure a way to check/enforce
   that there's no additional padding at the bottom.

 - Something else...

The checks as-implemented were deliberately conservative, and don't
preclude doing some relaxation in the future.

On Android, gralloc is used to store the "real" allocated width/height
and this is used to set up the DRM API appropriately.

>
> This may force us to do some silly cropping games inside the Rockchip
> KMS driver, but I feel it beats the alternative of breaking userspace.

Well, nothing's going to get broken - it's just perhaps not ready to
turn on AFBC yet.

>
> > +                   DRM_DEBUG_KMS(
> > +                           "AFBC buffer must be aligned to 16
> > pixels\n"
> > +                   );
> > +                   return false;
> > +           }
> > +           break;
> > +   case AFBC_FORMAT_MOD_BLOCK_SIZE_32x8:
> > +           /* fall through */
>
> It's also incongruous that 32x8 is unsupported here, but has a section
> in get_superblk_wh; please harmonise them so this section either does
> the checks as above, or that get_superblk_wh doesn't support 32x8
> either.
>
> > +bool drm_afbc_check_fb_size_ret(u32 pitch, int bpp,
> > +                           u32 w, u32 h, u32 superblk_w, u32
> > superblk_h,
> > +                           size_t size, u32 offset, u32 hdr_align,
> > +                           u32 *payload_off, u32 *total_size)
> > +{
> > +   int n_superblks = 0;
> > +   u32 superblk_sz = 0;
> > +   u32 afbc_size = 0;
>
> Please don't initialise the above three variables, given that you go on
> to immediately change their values. In this case, initialising to zero
> can only hide legitimate uninitialised-variable-use warnings.
>
> > +   n_superblks = (w / superblk_w) * (h / superblk_h);
> > +   superblk_sz = (bpp * superblk_w * superblk_h) / BITS_PER_BYTE;
> > +   afbc_size = ALIGN(n_superblks * AFBC_HEADER_SIZE, hdr_align);
> > +   *payload_off = afbc_size;
> > +
> > +   afbc_size += n_superblks * ALIGN(superblk_sz,
> > AFBC_SUPERBLK_ALIGNMENT);
> > +   *total_size = afbc_size + offset;
>
> Generally these are referred to as 'tiles' rather than 'superblocks',
> given that I would only expect one superblock per buffer, but if that's
> the terminology AFBC uses then it might be better to stick with it.
>
> > +   if ((w * bpp) != (pitch * BITS_PER_BYTE)) {
> > +           DRM_DEBUG_KMS("Invalid value of (pitch * BITS_PER_BYTE)
> > (=%u) should be same as width (=%u) * bpp (=%u)\n",
> > +                         pitch * BITS_PER_BYTE, w, bpp
> > +           );
> > +           return false;
> > +   }
>
> Having a too-small pitch is obviously a problem and we should reject
> it. But is having a too-large pitch really a problem; does it need to
> be an exact match, or can we support the case where the pitch is too
> large but also tile-aligned? If we can, it would be very good to
> support that.

The reason for forcing it to be exact is as I said above - we _must_
know what the "real" width and height is. Implementing this check to
force (pitch == width * bpp) ensures that, and also leaves the option
for us to relax to allow a larger pitch (as above) if that was the
preferred approach for alignment.

In general the current checks are deliberately designed to leave the
door open for future improvements without breaking anything.

Cheers,
-Brian

>
> Cheers,
> Daniel
>
IMPORTANT NOTICE: The contents of this email and any attachments are confidential and may also be privileged. If you are not the intended recipient, please notify the sender immediately and do not disclose the contents to any other person, use it for any purpose, or store or copy the information in any medium. Thank you.
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 63+ messages in thread

* Re: [PATCHv2 1/4] drm/arm: Factor out generic afbc helpers
@ 2019-11-07 17:20               ` Brian Starkey
  0 siblings, 0 replies; 63+ messages in thread
From: Brian Starkey @ 2019-11-07 17:20 UTC (permalink / raw)
  To: Daniel Stone
  Cc: Ayan Halder, kernel, David Airlie, Liviu Dudau,
	Andrzej Pietrasiewicz, linux-rockchip,
	james qian wang (Arm Technology China),
	dri-devel, Mihail Atanassov, Sean Paul

Hi Daniel,

On Tue, Nov 05, 2019 at 11:26:36PM +0000, Daniel Stone wrote:
> Hi Andrzej,
> Thanks for taking this on! It's looking better than v1 for sure. A few
> things below:
>
> On Mon, 2019-11-04 at 23:12 +0100, Andrzej Pietrasiewicz wrote:
> > +bool drm_afbc_check_offset(struct drm_device *dev,
> > +                      const struct drm_mode_fb_cmd2 *mode_cmd)
> > +{
> > +   if (mode_cmd->offsets[0] != 0) {
> > +           DRM_DEBUG_KMS("AFBC buffers' plane offset should be
> > 0\n");
> > +           return false;
> > +   }
> > +
> > +   return true;
> > +}
> > +EXPORT_SYMBOL_GPL(drm_afbc_check_offset);
>
> Is this actually universally true? If the offset is sufficiently
> aligned for (e.g.) DMA transfers to succeed, is there any reason why it
> must be zero?
>
> > +bool drm_afbc_check_size_align(struct drm_device *dev,
> > +                          const struct drm_mode_fb_cmd2 *mode_cmd)
> > +{
> > +   switch (mode_cmd->modifier[0] &
> > AFBC_FORMAT_MOD_BLOCK_SIZE_MASK) {
> > +   case AFBC_FORMAT_MOD_BLOCK_SIZE_16x16:
> > +           if ((mode_cmd->width % 16) || (mode_cmd->height % 16))
> > {
>
> This is a dealbreaker for many resolutions: for example, 1366x768 isn't
> cleanly divisible by 16 in width. So this means that we would have to
> either use a larger buffer and crop, or scale, or something.
>
> No userspace is prepared to align fb width/height to tile dimensions
> like this, so this check will basically fail everywhere.
>
> However, overallocation relative to the declared width/height isn't a
> problem at all. In order to deal with horizontal alignment, you simply
> need to ensure that the stride is a multiple of the tile width; for
> vertical arrangement, that the buffer is large enough to contain
> sufficient 'lines' to the next tile boundary.
>
> i.e. rather than checking width/height, you should check:
>   * fb_stride >= (ALIGN(fb_width, tile_width), bpp)
>   * buf_size >= fb_stride * ALIGN(fb_height, tile_height)

Well, sort of.

I agree with you that for horizontal padding, we can indeed use pitch.

However, the AFBC decoder(s) need to know exactly what the total
_allocated_ size in pixels of the buffer is - as this influences the
header size, and we need to know the header size to know where it ends
and the body begins.

I see a couple of possible ways forwards:

 - Keep it as-is. The restrictive checks ensure that there's no
   ambiguity and we use the fb width/height to determine the real
   allocated width/height. Userspace needs to be AFBC-aware and set up
   plane cropping to handle the alignment differences.

 - Use pitch to determine the "real" width, and internally in the
   kernel align height up to the next alignment boundary. This works
   OK, so long as there's no additional padding at the bottom of the
   buffer. This would work, but I can't figure a way to check/enforce
   that there's no additional padding at the bottom.

 - Something else...

The checks as-implemented were deliberately conservative, and don't
preclude doing some relaxation in the future.

On Android, gralloc is used to store the "real" allocated width/height
and this is used to set up the DRM API appropriately.

>
> This may force us to do some silly cropping games inside the Rockchip
> KMS driver, but I feel it beats the alternative of breaking userspace.

Well, nothing's going to get broken - it's just perhaps not ready to
turn on AFBC yet.

>
> > +                   DRM_DEBUG_KMS(
> > +                           "AFBC buffer must be aligned to 16
> > pixels\n"
> > +                   );
> > +                   return false;
> > +           }
> > +           break;
> > +   case AFBC_FORMAT_MOD_BLOCK_SIZE_32x8:
> > +           /* fall through */
>
> It's also incongruous that 32x8 is unsupported here, but has a section
> in get_superblk_wh; please harmonise them so this section either does
> the checks as above, or that get_superblk_wh doesn't support 32x8
> either.
>
> > +bool drm_afbc_check_fb_size_ret(u32 pitch, int bpp,
> > +                           u32 w, u32 h, u32 superblk_w, u32
> > superblk_h,
> > +                           size_t size, u32 offset, u32 hdr_align,
> > +                           u32 *payload_off, u32 *total_size)
> > +{
> > +   int n_superblks = 0;
> > +   u32 superblk_sz = 0;
> > +   u32 afbc_size = 0;
>
> Please don't initialise the above three variables, given that you go on
> to immediately change their values. In this case, initialising to zero
> can only hide legitimate uninitialised-variable-use warnings.
>
> > +   n_superblks = (w / superblk_w) * (h / superblk_h);
> > +   superblk_sz = (bpp * superblk_w * superblk_h) / BITS_PER_BYTE;
> > +   afbc_size = ALIGN(n_superblks * AFBC_HEADER_SIZE, hdr_align);
> > +   *payload_off = afbc_size;
> > +
> > +   afbc_size += n_superblks * ALIGN(superblk_sz,
> > AFBC_SUPERBLK_ALIGNMENT);
> > +   *total_size = afbc_size + offset;
>
> Generally these are referred to as 'tiles' rather than 'superblocks',
> given that I would only expect one superblock per buffer, but if that's
> the terminology AFBC uses then it might be better to stick with it.
>
> > +   if ((w * bpp) != (pitch * BITS_PER_BYTE)) {
> > +           DRM_DEBUG_KMS("Invalid value of (pitch * BITS_PER_BYTE)
> > (=%u) should be same as width (=%u) * bpp (=%u)\n",
> > +                         pitch * BITS_PER_BYTE, w, bpp
> > +           );
> > +           return false;
> > +   }
>
> Having a too-small pitch is obviously a problem and we should reject
> it. But is having a too-large pitch really a problem; does it need to
> be an exact match, or can we support the case where the pitch is too
> large but also tile-aligned? If we can, it would be very good to
> support that.

The reason for forcing it to be exact is as I said above - we _must_
know what the "real" width and height is. Implementing this check to
force (pitch == width * bpp) ensures that, and also leaves the option
for us to relax to allow a larger pitch (as above) if that was the
preferred approach for alignment.

In general the current checks are deliberately designed to leave the
door open for future improvements without breaking anything.

Cheers,
-Brian

>
> Cheers,
> Daniel
>
IMPORTANT NOTICE: The contents of this email and any attachments are confidential and may also be privileged. If you are not the intended recipient, please notify the sender immediately and do not disclose the contents to any other person, use it for any purpose, or store or copy the information in any medium. Thank you.
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 63+ messages in thread

* Re: [PATCHv2 1/4] drm/arm: Factor out generic afbc helpers
@ 2019-11-07 17:32                 ` Daniel Vetter
  0 siblings, 0 replies; 63+ messages in thread
From: Daniel Vetter @ 2019-11-07 17:32 UTC (permalink / raw)
  To: Brian Starkey
  Cc: Ayan Halder, kernel, Daniel Stone, David Airlie, Liviu Dudau,
	Andrzej Pietrasiewicz, linux-rockchip,
	james qian wang (Arm Technology China),
	dri-devel, Mihail Atanassov, Sean Paul

On Thu, Nov 7, 2019 at 6:20 PM Brian Starkey <Brian.Starkey@arm.com> wrote:
>
> Hi Daniel,
>
> On Tue, Nov 05, 2019 at 11:26:36PM +0000, Daniel Stone wrote:
> > Hi Andrzej,
> > Thanks for taking this on! It's looking better than v1 for sure. A few
> > things below:
> >
> > On Mon, 2019-11-04 at 23:12 +0100, Andrzej Pietrasiewicz wrote:
> > > +bool drm_afbc_check_offset(struct drm_device *dev,
> > > +                      const struct drm_mode_fb_cmd2 *mode_cmd)
> > > +{
> > > +   if (mode_cmd->offsets[0] != 0) {
> > > +           DRM_DEBUG_KMS("AFBC buffers' plane offset should be
> > > 0\n");
> > > +           return false;
> > > +   }
> > > +
> > > +   return true;
> > > +}
> > > +EXPORT_SYMBOL_GPL(drm_afbc_check_offset);
> >
> > Is this actually universally true? If the offset is sufficiently
> > aligned for (e.g.) DMA transfers to succeed, is there any reason why it
> > must be zero?
> >
> > > +bool drm_afbc_check_size_align(struct drm_device *dev,
> > > +                          const struct drm_mode_fb_cmd2 *mode_cmd)
> > > +{
> > > +   switch (mode_cmd->modifier[0] &
> > > AFBC_FORMAT_MOD_BLOCK_SIZE_MASK) {
> > > +   case AFBC_FORMAT_MOD_BLOCK_SIZE_16x16:
> > > +           if ((mode_cmd->width % 16) || (mode_cmd->height % 16))
> > > {
> >
> > This is a dealbreaker for many resolutions: for example, 1366x768 isn't
> > cleanly divisible by 16 in width. So this means that we would have to
> > either use a larger buffer and crop, or scale, or something.
> >
> > No userspace is prepared to align fb width/height to tile dimensions
> > like this, so this check will basically fail everywhere.
> >
> > However, overallocation relative to the declared width/height isn't a
> > problem at all. In order to deal with horizontal alignment, you simply
> > need to ensure that the stride is a multiple of the tile width; for
> > vertical arrangement, that the buffer is large enough to contain
> > sufficient 'lines' to the next tile boundary.
> >
> > i.e. rather than checking width/height, you should check:
> >   * fb_stride >= (ALIGN(fb_width, tile_width), bpp)
> >   * buf_size >= fb_stride * ALIGN(fb_height, tile_height)
>
> Well, sort of.
>
> I agree with you that for horizontal padding, we can indeed use pitch.
>
> However, the AFBC decoder(s) need to know exactly what the total
> _allocated_ size in pixels of the buffer is - as this influences the
> header size, and we need to know the header size to know where it ends
> and the body begins.
>
> I see a couple of possible ways forwards:
>
>  - Keep it as-is. The restrictive checks ensure that there's no
>    ambiguity and we use the fb width/height to determine the real
>    allocated width/height. Userspace needs to be AFBC-aware and set up
>    plane cropping to handle the alignment differences.
>
>  - Use pitch to determine the "real" width, and internally in the
>    kernel align height up to the next alignment boundary. This works
>    OK, so long as there's no additional padding at the bottom of the
>    buffer. This would work, but I can't figure a way to check/enforce
>    that there's no additional padding at the bottom.
>
>  - Something else...
>
> The checks as-implemented were deliberately conservative, and don't
> preclude doing some relaxation in the future.
>
> On Android, gralloc is used to store the "real" allocated width/height
> and this is used to set up the DRM API appropriately.

Fake stride + real visible h/w in the drmfb. Because that's how it
works with all the tiled formats already, and expecting userspace to
fudge this all correctly seems very backwards to me. In a way we had
that entire fake stride discussion already for the block size format
stuff already, but now in a different flavour.

Also I think that's more reasons why this should be no-opt-outable
code that's done for all drivers when we check framebuffers in addfb.
Plus then some helpers to get at computed values for any framebuffer
we know to be valid.
-Daniel

> > This may force us to do some silly cropping games inside the Rockchip
> > KMS driver, but I feel it beats the alternative of breaking userspace.
>
> Well, nothing's going to get broken - it's just perhaps not ready to
> turn on AFBC yet.
>
> >
> > > +                   DRM_DEBUG_KMS(
> > > +                           "AFBC buffer must be aligned to 16
> > > pixels\n"
> > > +                   );
> > > +                   return false;
> > > +           }
> > > +           break;
> > > +   case AFBC_FORMAT_MOD_BLOCK_SIZE_32x8:
> > > +           /* fall through */
> >
> > It's also incongruous that 32x8 is unsupported here, but has a section
> > in get_superblk_wh; please harmonise them so this section either does
> > the checks as above, or that get_superblk_wh doesn't support 32x8
> > either.
> >
> > > +bool drm_afbc_check_fb_size_ret(u32 pitch, int bpp,
> > > +                           u32 w, u32 h, u32 superblk_w, u32
> > > superblk_h,
> > > +                           size_t size, u32 offset, u32 hdr_align,
> > > +                           u32 *payload_off, u32 *total_size)
> > > +{
> > > +   int n_superblks = 0;
> > > +   u32 superblk_sz = 0;
> > > +   u32 afbc_size = 0;
> >
> > Please don't initialise the above three variables, given that you go on
> > to immediately change their values. In this case, initialising to zero
> > can only hide legitimate uninitialised-variable-use warnings.
> >
> > > +   n_superblks = (w / superblk_w) * (h / superblk_h);
> > > +   superblk_sz = (bpp * superblk_w * superblk_h) / BITS_PER_BYTE;
> > > +   afbc_size = ALIGN(n_superblks * AFBC_HEADER_SIZE, hdr_align);
> > > +   *payload_off = afbc_size;
> > > +
> > > +   afbc_size += n_superblks * ALIGN(superblk_sz,
> > > AFBC_SUPERBLK_ALIGNMENT);
> > > +   *total_size = afbc_size + offset;
> >
> > Generally these are referred to as 'tiles' rather than 'superblocks',
> > given that I would only expect one superblock per buffer, but if that's
> > the terminology AFBC uses then it might be better to stick with it.
> >
> > > +   if ((w * bpp) != (pitch * BITS_PER_BYTE)) {
> > > +           DRM_DEBUG_KMS("Invalid value of (pitch * BITS_PER_BYTE)
> > > (=%u) should be same as width (=%u) * bpp (=%u)\n",
> > > +                         pitch * BITS_PER_BYTE, w, bpp
> > > +           );
> > > +           return false;
> > > +   }
> >
> > Having a too-small pitch is obviously a problem and we should reject
> > it. But is having a too-large pitch really a problem; does it need to
> > be an exact match, or can we support the case where the pitch is too
> > large but also tile-aligned? If we can, it would be very good to
> > support that.
>
> The reason for forcing it to be exact is as I said above - we _must_
> know what the "real" width and height is. Implementing this check to
> force (pitch == width * bpp) ensures that, and also leaves the option
> for us to relax to allow a larger pitch (as above) if that was the
> preferred approach for alignment.
>
> In general the current checks are deliberately designed to leave the
> door open for future improvements without breaking anything.
>
> Cheers,
> -Brian
>
> >
> > Cheers,
> > Daniel
> >
> IMPORTANT NOTICE: The contents of this email and any attachments are confidential and may also be privileged. If you are not the intended recipient, please notify the sender immediately and do not disclose the contents to any other person, use it for any purpose, or store or copy the information in any medium. Thank you.



-- 
Daniel Vetter
Software Engineer, Intel Corporation
+41 (0) 79 365 57 48 - http://blog.ffwll.ch
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 63+ messages in thread

* Re: [PATCHv2 1/4] drm/arm: Factor out generic afbc helpers
@ 2019-11-07 17:32                 ` Daniel Vetter
  0 siblings, 0 replies; 63+ messages in thread
From: Daniel Vetter @ 2019-11-07 17:32 UTC (permalink / raw)
  To: Brian Starkey
  Cc: Ayan Halder, kernel, Daniel Stone, David Airlie, Liviu Dudau,
	Andrzej Pietrasiewicz, linux-rockchip,
	james qian wang (Arm Technology China),
	dri-devel, Mihail Atanassov, Sean Paul

On Thu, Nov 7, 2019 at 6:20 PM Brian Starkey <Brian.Starkey@arm.com> wrote:
>
> Hi Daniel,
>
> On Tue, Nov 05, 2019 at 11:26:36PM +0000, Daniel Stone wrote:
> > Hi Andrzej,
> > Thanks for taking this on! It's looking better than v1 for sure. A few
> > things below:
> >
> > On Mon, 2019-11-04 at 23:12 +0100, Andrzej Pietrasiewicz wrote:
> > > +bool drm_afbc_check_offset(struct drm_device *dev,
> > > +                      const struct drm_mode_fb_cmd2 *mode_cmd)
> > > +{
> > > +   if (mode_cmd->offsets[0] != 0) {
> > > +           DRM_DEBUG_KMS("AFBC buffers' plane offset should be
> > > 0\n");
> > > +           return false;
> > > +   }
> > > +
> > > +   return true;
> > > +}
> > > +EXPORT_SYMBOL_GPL(drm_afbc_check_offset);
> >
> > Is this actually universally true? If the offset is sufficiently
> > aligned for (e.g.) DMA transfers to succeed, is there any reason why it
> > must be zero?
> >
> > > +bool drm_afbc_check_size_align(struct drm_device *dev,
> > > +                          const struct drm_mode_fb_cmd2 *mode_cmd)
> > > +{
> > > +   switch (mode_cmd->modifier[0] &
> > > AFBC_FORMAT_MOD_BLOCK_SIZE_MASK) {
> > > +   case AFBC_FORMAT_MOD_BLOCK_SIZE_16x16:
> > > +           if ((mode_cmd->width % 16) || (mode_cmd->height % 16))
> > > {
> >
> > This is a dealbreaker for many resolutions: for example, 1366x768 isn't
> > cleanly divisible by 16 in width. So this means that we would have to
> > either use a larger buffer and crop, or scale, or something.
> >
> > No userspace is prepared to align fb width/height to tile dimensions
> > like this, so this check will basically fail everywhere.
> >
> > However, overallocation relative to the declared width/height isn't a
> > problem at all. In order to deal with horizontal alignment, you simply
> > need to ensure that the stride is a multiple of the tile width; for
> > vertical arrangement, that the buffer is large enough to contain
> > sufficient 'lines' to the next tile boundary.
> >
> > i.e. rather than checking width/height, you should check:
> >   * fb_stride >= (ALIGN(fb_width, tile_width), bpp)
> >   * buf_size >= fb_stride * ALIGN(fb_height, tile_height)
>
> Well, sort of.
>
> I agree with you that for horizontal padding, we can indeed use pitch.
>
> However, the AFBC decoder(s) need to know exactly what the total
> _allocated_ size in pixels of the buffer is - as this influences the
> header size, and we need to know the header size to know where it ends
> and the body begins.
>
> I see a couple of possible ways forwards:
>
>  - Keep it as-is. The restrictive checks ensure that there's no
>    ambiguity and we use the fb width/height to determine the real
>    allocated width/height. Userspace needs to be AFBC-aware and set up
>    plane cropping to handle the alignment differences.
>
>  - Use pitch to determine the "real" width, and internally in the
>    kernel align height up to the next alignment boundary. This works
>    OK, so long as there's no additional padding at the bottom of the
>    buffer. This would work, but I can't figure a way to check/enforce
>    that there's no additional padding at the bottom.
>
>  - Something else...
>
> The checks as-implemented were deliberately conservative, and don't
> preclude doing some relaxation in the future.
>
> On Android, gralloc is used to store the "real" allocated width/height
> and this is used to set up the DRM API appropriately.

Fake stride + real visible h/w in the drmfb. Because that's how it
works with all the tiled formats already, and expecting userspace to
fudge this all correctly seems very backwards to me. In a way we had
that entire fake stride discussion already for the block size format
stuff already, but now in a different flavour.

Also I think that's more reasons why this should be no-opt-outable
code that's done for all drivers when we check framebuffers in addfb.
Plus then some helpers to get at computed values for any framebuffer
we know to be valid.
-Daniel

> > This may force us to do some silly cropping games inside the Rockchip
> > KMS driver, but I feel it beats the alternative of breaking userspace.
>
> Well, nothing's going to get broken - it's just perhaps not ready to
> turn on AFBC yet.
>
> >
> > > +                   DRM_DEBUG_KMS(
> > > +                           "AFBC buffer must be aligned to 16
> > > pixels\n"
> > > +                   );
> > > +                   return false;
> > > +           }
> > > +           break;
> > > +   case AFBC_FORMAT_MOD_BLOCK_SIZE_32x8:
> > > +           /* fall through */
> >
> > It's also incongruous that 32x8 is unsupported here, but has a section
> > in get_superblk_wh; please harmonise them so this section either does
> > the checks as above, or that get_superblk_wh doesn't support 32x8
> > either.
> >
> > > +bool drm_afbc_check_fb_size_ret(u32 pitch, int bpp,
> > > +                           u32 w, u32 h, u32 superblk_w, u32
> > > superblk_h,
> > > +                           size_t size, u32 offset, u32 hdr_align,
> > > +                           u32 *payload_off, u32 *total_size)
> > > +{
> > > +   int n_superblks = 0;
> > > +   u32 superblk_sz = 0;
> > > +   u32 afbc_size = 0;
> >
> > Please don't initialise the above three variables, given that you go on
> > to immediately change their values. In this case, initialising to zero
> > can only hide legitimate uninitialised-variable-use warnings.
> >
> > > +   n_superblks = (w / superblk_w) * (h / superblk_h);
> > > +   superblk_sz = (bpp * superblk_w * superblk_h) / BITS_PER_BYTE;
> > > +   afbc_size = ALIGN(n_superblks * AFBC_HEADER_SIZE, hdr_align);
> > > +   *payload_off = afbc_size;
> > > +
> > > +   afbc_size += n_superblks * ALIGN(superblk_sz,
> > > AFBC_SUPERBLK_ALIGNMENT);
> > > +   *total_size = afbc_size + offset;
> >
> > Generally these are referred to as 'tiles' rather than 'superblocks',
> > given that I would only expect one superblock per buffer, but if that's
> > the terminology AFBC uses then it might be better to stick with it.
> >
> > > +   if ((w * bpp) != (pitch * BITS_PER_BYTE)) {
> > > +           DRM_DEBUG_KMS("Invalid value of (pitch * BITS_PER_BYTE)
> > > (=%u) should be same as width (=%u) * bpp (=%u)\n",
> > > +                         pitch * BITS_PER_BYTE, w, bpp
> > > +           );
> > > +           return false;
> > > +   }
> >
> > Having a too-small pitch is obviously a problem and we should reject
> > it. But is having a too-large pitch really a problem; does it need to
> > be an exact match, or can we support the case where the pitch is too
> > large but also tile-aligned? If we can, it would be very good to
> > support that.
>
> The reason for forcing it to be exact is as I said above - we _must_
> know what the "real" width and height is. Implementing this check to
> force (pitch == width * bpp) ensures that, and also leaves the option
> for us to relax to allow a larger pitch (as above) if that was the
> preferred approach for alignment.
>
> In general the current checks are deliberately designed to leave the
> door open for future improvements without breaking anything.
>
> Cheers,
> -Brian
>
> >
> > Cheers,
> > Daniel
> >
> IMPORTANT NOTICE: The contents of this email and any attachments are confidential and may also be privileged. If you are not the intended recipient, please notify the sender immediately and do not disclose the contents to any other person, use it for any purpose, or store or copy the information in any medium. Thank you.



-- 
Daniel Vetter
Software Engineer, Intel Corporation
+41 (0) 79 365 57 48 - http://blog.ffwll.ch
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 63+ messages in thread

* Re: [PATCHv2 1/4] drm/arm: Factor out generic afbc helpers
@ 2019-11-07 17:49                   ` Brian Starkey
  0 siblings, 0 replies; 63+ messages in thread
From: Brian Starkey @ 2019-11-07 17:49 UTC (permalink / raw)
  To: Daniel Vetter
  Cc: nd, Ayan Halder, kernel, Daniel Stone, David Airlie, Liviu Dudau,
	Andrzej Pietrasiewicz, linux-rockchip,
	james qian wang (Arm Technology China),
	dri-devel, Mihail Atanassov, Sean Paul

Hi Daniel,

On Thu, Nov 07, 2019 at 06:32:01PM +0100, Daniel Vetter wrote:
> On Thu, Nov 7, 2019 at 6:20 PM Brian Starkey <Brian.Starkey@arm.com> wrote:
> >
> > Hi Daniel,
> >
> > On Tue, Nov 05, 2019 at 11:26:36PM +0000, Daniel Stone wrote:
> > > Hi Andrzej,
> > > Thanks for taking this on! It's looking better than v1 for sure. A few
> > > things below:
> > >
> > > On Mon, 2019-11-04 at 23:12 +0100, Andrzej Pietrasiewicz wrote:
> > > > +bool drm_afbc_check_offset(struct drm_device *dev,
> > > > +                      const struct drm_mode_fb_cmd2 *mode_cmd)
> > > > +{
> > > > +   if (mode_cmd->offsets[0] != 0) {
> > > > +           DRM_DEBUG_KMS("AFBC buffers' plane offset should be
> > > > 0\n");
> > > > +           return false;
> > > > +   }
> > > > +
> > > > +   return true;
> > > > +}
> > > > +EXPORT_SYMBOL_GPL(drm_afbc_check_offset);
> > >
> > > Is this actually universally true? If the offset is sufficiently
> > > aligned for (e.g.) DMA transfers to succeed, is there any reason why it
> > > must be zero?
> > >
> > > > +bool drm_afbc_check_size_align(struct drm_device *dev,
> > > > +                          const struct drm_mode_fb_cmd2 *mode_cmd)
> > > > +{
> > > > +   switch (mode_cmd->modifier[0] &
> > > > AFBC_FORMAT_MOD_BLOCK_SIZE_MASK) {
> > > > +   case AFBC_FORMAT_MOD_BLOCK_SIZE_16x16:
> > > > +           if ((mode_cmd->width % 16) || (mode_cmd->height % 16))
> > > > {
> > >
> > > This is a dealbreaker for many resolutions: for example, 1366x768 isn't
> > > cleanly divisible by 16 in width. So this means that we would have to
> > > either use a larger buffer and crop, or scale, or something.
> > >
> > > No userspace is prepared to align fb width/height to tile dimensions
> > > like this, so this check will basically fail everywhere.
> > >
> > > However, overallocation relative to the declared width/height isn't a
> > > problem at all. In order to deal with horizontal alignment, you simply
> > > need to ensure that the stride is a multiple of the tile width; for
> > > vertical arrangement, that the buffer is large enough to contain
> > > sufficient 'lines' to the next tile boundary.
> > >
> > > i.e. rather than checking width/height, you should check:
> > >   * fb_stride >= (ALIGN(fb_width, tile_width), bpp)
> > >   * buf_size >= fb_stride * ALIGN(fb_height, tile_height)
> >
> > Well, sort of.
> >
> > I agree with you that for horizontal padding, we can indeed use pitch.
> >
> > However, the AFBC decoder(s) need to know exactly what the total
> > _allocated_ size in pixels of the buffer is - as this influences the
> > header size, and we need to know the header size to know where it ends
> > and the body begins.
> >
> > I see a couple of possible ways forwards:
> >
> >  - Keep it as-is. The restrictive checks ensure that there's no
> >    ambiguity and we use the fb width/height to determine the real
> >    allocated width/height. Userspace needs to be AFBC-aware and set up
> >    plane cropping to handle the alignment differences.
> >
> >  - Use pitch to determine the "real" width, and internally in the
> >    kernel align height up to the next alignment boundary. This works
> >    OK, so long as there's no additional padding at the bottom of the
> >    buffer. This would work, but I can't figure a way to check/enforce
> >    that there's no additional padding at the bottom.
> >
> >  - Something else...
> >
> > The checks as-implemented were deliberately conservative, and don't
> > preclude doing some relaxation in the future.
> >
> > On Android, gralloc is used to store the "real" allocated width/height
> > and this is used to set up the DRM API appropriately.
> 
> Fake stride + real visible h/w in the drmfb. Because that's how it
> works with all the tiled formats already, and expecting userspace to
> fudge this all correctly seems very backwards to me. In a way we had
> that entire fake stride discussion already for the block size format
> stuff already, but now in a different flavour.

Fake stride - like I said, no problem; sounds good. That solves one
dimension.

So do you have a proposal for how we determine what the allocated
height is in that case? I don't really see a way.

Thanks,
-Brian

> 
> Also I think that's more reasons why this should be no-opt-outable
> code that's done for all drivers when we check framebuffers in addfb.
> Plus then some helpers to get at computed values for any framebuffer
> we know to be valid.
> -Daniel
> 
> > > This may force us to do some silly cropping games inside the Rockchip
> > > KMS driver, but I feel it beats the alternative of breaking userspace.
> >
> > Well, nothing's going to get broken - it's just perhaps not ready to
> > turn on AFBC yet.
> >
> > >
> > > > +                   DRM_DEBUG_KMS(
> > > > +                           "AFBC buffer must be aligned to 16
> > > > pixels\n"
> > > > +                   );
> > > > +                   return false;
> > > > +           }
> > > > +           break;
> > > > +   case AFBC_FORMAT_MOD_BLOCK_SIZE_32x8:
> > > > +           /* fall through */
> > >
> > > It's also incongruous that 32x8 is unsupported here, but has a section
> > > in get_superblk_wh; please harmonise them so this section either does
> > > the checks as above, or that get_superblk_wh doesn't support 32x8
> > > either.
> > >
> > > > +bool drm_afbc_check_fb_size_ret(u32 pitch, int bpp,
> > > > +                           u32 w, u32 h, u32 superblk_w, u32
> > > > superblk_h,
> > > > +                           size_t size, u32 offset, u32 hdr_align,
> > > > +                           u32 *payload_off, u32 *total_size)
> > > > +{
> > > > +   int n_superblks = 0;
> > > > +   u32 superblk_sz = 0;
> > > > +   u32 afbc_size = 0;
> > >
> > > Please don't initialise the above three variables, given that you go on
> > > to immediately change their values. In this case, initialising to zero
> > > can only hide legitimate uninitialised-variable-use warnings.
> > >
> > > > +   n_superblks = (w / superblk_w) * (h / superblk_h);
> > > > +   superblk_sz = (bpp * superblk_w * superblk_h) / BITS_PER_BYTE;
> > > > +   afbc_size = ALIGN(n_superblks * AFBC_HEADER_SIZE, hdr_align);
> > > > +   *payload_off = afbc_size;
> > > > +
> > > > +   afbc_size += n_superblks * ALIGN(superblk_sz,
> > > > AFBC_SUPERBLK_ALIGNMENT);
> > > > +   *total_size = afbc_size + offset;
> > >
> > > Generally these are referred to as 'tiles' rather than 'superblocks',
> > > given that I would only expect one superblock per buffer, but if that's
> > > the terminology AFBC uses then it might be better to stick with it.
> > >
> > > > +   if ((w * bpp) != (pitch * BITS_PER_BYTE)) {
> > > > +           DRM_DEBUG_KMS("Invalid value of (pitch * BITS_PER_BYTE)
> > > > (=%u) should be same as width (=%u) * bpp (=%u)\n",
> > > > +                         pitch * BITS_PER_BYTE, w, bpp
> > > > +           );
> > > > +           return false;
> > > > +   }
> > >
> > > Having a too-small pitch is obviously a problem and we should reject
> > > it. But is having a too-large pitch really a problem; does it need to
> > > be an exact match, or can we support the case where the pitch is too
> > > large but also tile-aligned? If we can, it would be very good to
> > > support that.
> >
> > The reason for forcing it to be exact is as I said above - we _must_
> > know what the "real" width and height is. Implementing this check to
> > force (pitch == width * bpp) ensures that, and also leaves the option
> > for us to relax to allow a larger pitch (as above) if that was the
> > preferred approach for alignment.
> >
> > In general the current checks are deliberately designed to leave the
> > door open for future improvements without breaking anything.
> >
> > Cheers,
> > -Brian
> >
> > >
> > > Cheers,
> > > Daniel
> > >
> > IMPORTANT NOTICE: The contents of this email and any attachments are confidential and may also be privileged. If you are not the intended recipient, please notify the sender immediately and do not disclose the contents to any other person, use it for any purpose, or store or copy the information in any medium. Thank you.

Not sure how that snuck in.

> 
> 
> 
> -- 
> Daniel Vetter
> Software Engineer, Intel Corporation
> +41 (0) 79 365 57 48 - http://blog.ffwll.ch
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 63+ messages in thread

* Re: [PATCHv2 1/4] drm/arm: Factor out generic afbc helpers
@ 2019-11-07 17:49                   ` Brian Starkey
  0 siblings, 0 replies; 63+ messages in thread
From: Brian Starkey @ 2019-11-07 17:49 UTC (permalink / raw)
  To: Daniel Vetter
  Cc: nd, Ayan Halder, kernel, Daniel Stone, David Airlie, Liviu Dudau,
	Andrzej Pietrasiewicz, linux-rockchip,
	james qian wang (Arm Technology China),
	dri-devel, Mihail Atanassov, Sean Paul

Hi Daniel,

On Thu, Nov 07, 2019 at 06:32:01PM +0100, Daniel Vetter wrote:
> On Thu, Nov 7, 2019 at 6:20 PM Brian Starkey <Brian.Starkey@arm.com> wrote:
> >
> > Hi Daniel,
> >
> > On Tue, Nov 05, 2019 at 11:26:36PM +0000, Daniel Stone wrote:
> > > Hi Andrzej,
> > > Thanks for taking this on! It's looking better than v1 for sure. A few
> > > things below:
> > >
> > > On Mon, 2019-11-04 at 23:12 +0100, Andrzej Pietrasiewicz wrote:
> > > > +bool drm_afbc_check_offset(struct drm_device *dev,
> > > > +                      const struct drm_mode_fb_cmd2 *mode_cmd)
> > > > +{
> > > > +   if (mode_cmd->offsets[0] != 0) {
> > > > +           DRM_DEBUG_KMS("AFBC buffers' plane offset should be
> > > > 0\n");
> > > > +           return false;
> > > > +   }
> > > > +
> > > > +   return true;
> > > > +}
> > > > +EXPORT_SYMBOL_GPL(drm_afbc_check_offset);
> > >
> > > Is this actually universally true? If the offset is sufficiently
> > > aligned for (e.g.) DMA transfers to succeed, is there any reason why it
> > > must be zero?
> > >
> > > > +bool drm_afbc_check_size_align(struct drm_device *dev,
> > > > +                          const struct drm_mode_fb_cmd2 *mode_cmd)
> > > > +{
> > > > +   switch (mode_cmd->modifier[0] &
> > > > AFBC_FORMAT_MOD_BLOCK_SIZE_MASK) {
> > > > +   case AFBC_FORMAT_MOD_BLOCK_SIZE_16x16:
> > > > +           if ((mode_cmd->width % 16) || (mode_cmd->height % 16))
> > > > {
> > >
> > > This is a dealbreaker for many resolutions: for example, 1366x768 isn't
> > > cleanly divisible by 16 in width. So this means that we would have to
> > > either use a larger buffer and crop, or scale, or something.
> > >
> > > No userspace is prepared to align fb width/height to tile dimensions
> > > like this, so this check will basically fail everywhere.
> > >
> > > However, overallocation relative to the declared width/height isn't a
> > > problem at all. In order to deal with horizontal alignment, you simply
> > > need to ensure that the stride is a multiple of the tile width; for
> > > vertical arrangement, that the buffer is large enough to contain
> > > sufficient 'lines' to the next tile boundary.
> > >
> > > i.e. rather than checking width/height, you should check:
> > >   * fb_stride >= (ALIGN(fb_width, tile_width), bpp)
> > >   * buf_size >= fb_stride * ALIGN(fb_height, tile_height)
> >
> > Well, sort of.
> >
> > I agree with you that for horizontal padding, we can indeed use pitch.
> >
> > However, the AFBC decoder(s) need to know exactly what the total
> > _allocated_ size in pixels of the buffer is - as this influences the
> > header size, and we need to know the header size to know where it ends
> > and the body begins.
> >
> > I see a couple of possible ways forwards:
> >
> >  - Keep it as-is. The restrictive checks ensure that there's no
> >    ambiguity and we use the fb width/height to determine the real
> >    allocated width/height. Userspace needs to be AFBC-aware and set up
> >    plane cropping to handle the alignment differences.
> >
> >  - Use pitch to determine the "real" width, and internally in the
> >    kernel align height up to the next alignment boundary. This works
> >    OK, so long as there's no additional padding at the bottom of the
> >    buffer. This would work, but I can't figure a way to check/enforce
> >    that there's no additional padding at the bottom.
> >
> >  - Something else...
> >
> > The checks as-implemented were deliberately conservative, and don't
> > preclude doing some relaxation in the future.
> >
> > On Android, gralloc is used to store the "real" allocated width/height
> > and this is used to set up the DRM API appropriately.
> 
> Fake stride + real visible h/w in the drmfb. Because that's how it
> works with all the tiled formats already, and expecting userspace to
> fudge this all correctly seems very backwards to me. In a way we had
> that entire fake stride discussion already for the block size format
> stuff already, but now in a different flavour.

Fake stride - like I said, no problem; sounds good. That solves one
dimension.

So do you have a proposal for how we determine what the allocated
height is in that case? I don't really see a way.

Thanks,
-Brian

> 
> Also I think that's more reasons why this should be no-opt-outable
> code that's done for all drivers when we check framebuffers in addfb.
> Plus then some helpers to get at computed values for any framebuffer
> we know to be valid.
> -Daniel
> 
> > > This may force us to do some silly cropping games inside the Rockchip
> > > KMS driver, but I feel it beats the alternative of breaking userspace.
> >
> > Well, nothing's going to get broken - it's just perhaps not ready to
> > turn on AFBC yet.
> >
> > >
> > > > +                   DRM_DEBUG_KMS(
> > > > +                           "AFBC buffer must be aligned to 16
> > > > pixels\n"
> > > > +                   );
> > > > +                   return false;
> > > > +           }
> > > > +           break;
> > > > +   case AFBC_FORMAT_MOD_BLOCK_SIZE_32x8:
> > > > +           /* fall through */
> > >
> > > It's also incongruous that 32x8 is unsupported here, but has a section
> > > in get_superblk_wh; please harmonise them so this section either does
> > > the checks as above, or that get_superblk_wh doesn't support 32x8
> > > either.
> > >
> > > > +bool drm_afbc_check_fb_size_ret(u32 pitch, int bpp,
> > > > +                           u32 w, u32 h, u32 superblk_w, u32
> > > > superblk_h,
> > > > +                           size_t size, u32 offset, u32 hdr_align,
> > > > +                           u32 *payload_off, u32 *total_size)
> > > > +{
> > > > +   int n_superblks = 0;
> > > > +   u32 superblk_sz = 0;
> > > > +   u32 afbc_size = 0;
> > >
> > > Please don't initialise the above three variables, given that you go on
> > > to immediately change their values. In this case, initialising to zero
> > > can only hide legitimate uninitialised-variable-use warnings.
> > >
> > > > +   n_superblks = (w / superblk_w) * (h / superblk_h);
> > > > +   superblk_sz = (bpp * superblk_w * superblk_h) / BITS_PER_BYTE;
> > > > +   afbc_size = ALIGN(n_superblks * AFBC_HEADER_SIZE, hdr_align);
> > > > +   *payload_off = afbc_size;
> > > > +
> > > > +   afbc_size += n_superblks * ALIGN(superblk_sz,
> > > > AFBC_SUPERBLK_ALIGNMENT);
> > > > +   *total_size = afbc_size + offset;
> > >
> > > Generally these are referred to as 'tiles' rather than 'superblocks',
> > > given that I would only expect one superblock per buffer, but if that's
> > > the terminology AFBC uses then it might be better to stick with it.
> > >
> > > > +   if ((w * bpp) != (pitch * BITS_PER_BYTE)) {
> > > > +           DRM_DEBUG_KMS("Invalid value of (pitch * BITS_PER_BYTE)
> > > > (=%u) should be same as width (=%u) * bpp (=%u)\n",
> > > > +                         pitch * BITS_PER_BYTE, w, bpp
> > > > +           );
> > > > +           return false;
> > > > +   }
> > >
> > > Having a too-small pitch is obviously a problem and we should reject
> > > it. But is having a too-large pitch really a problem; does it need to
> > > be an exact match, or can we support the case where the pitch is too
> > > large but also tile-aligned? If we can, it would be very good to
> > > support that.
> >
> > The reason for forcing it to be exact is as I said above - we _must_
> > know what the "real" width and height is. Implementing this check to
> > force (pitch == width * bpp) ensures that, and also leaves the option
> > for us to relax to allow a larger pitch (as above) if that was the
> > preferred approach for alignment.
> >
> > In general the current checks are deliberately designed to leave the
> > door open for future improvements without breaking anything.
> >
> > Cheers,
> > -Brian
> >
> > >
> > > Cheers,
> > > Daniel
> > >
> > IMPORTANT NOTICE: The contents of this email and any attachments are confidential and may also be privileged. If you are not the intended recipient, please notify the sender immediately and do not disclose the contents to any other person, use it for any purpose, or store or copy the information in any medium. Thank you.

Not sure how that snuck in.

> 
> 
> 
> -- 
> Daniel Vetter
> Software Engineer, Intel Corporation
> +41 (0) 79 365 57 48 - http://blog.ffwll.ch
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 63+ messages in thread

* Re: [PATCHv2 1/4] drm/arm: Factor out generic afbc helpers
@ 2019-11-07 19:28                     ` Daniel Vetter
  0 siblings, 0 replies; 63+ messages in thread
From: Daniel Vetter @ 2019-11-07 19:28 UTC (permalink / raw)
  To: Brian Starkey
  Cc: nd, Ayan Halder, kernel, Daniel Stone, David Airlie, Liviu Dudau,
	Andrzej Pietrasiewicz, linux-rockchip,
	james qian wang (Arm Technology China),
	dri-devel, Mihail Atanassov, Sean Paul

On Thu, Nov 07, 2019 at 05:49:14PM +0000, Brian Starkey wrote:
> Hi Daniel,
> 
> On Thu, Nov 07, 2019 at 06:32:01PM +0100, Daniel Vetter wrote:
> > On Thu, Nov 7, 2019 at 6:20 PM Brian Starkey <Brian.Starkey@arm.com> wrote:
> > >
> > > Hi Daniel,
> > >
> > > On Tue, Nov 05, 2019 at 11:26:36PM +0000, Daniel Stone wrote:
> > > > Hi Andrzej,
> > > > Thanks for taking this on! It's looking better than v1 for sure. A few
> > > > things below:
> > > >
> > > > On Mon, 2019-11-04 at 23:12 +0100, Andrzej Pietrasiewicz wrote:
> > > > > +bool drm_afbc_check_offset(struct drm_device *dev,
> > > > > +                      const struct drm_mode_fb_cmd2 *mode_cmd)
> > > > > +{
> > > > > +   if (mode_cmd->offsets[0] != 0) {
> > > > > +           DRM_DEBUG_KMS("AFBC buffers' plane offset should be
> > > > > 0\n");
> > > > > +           return false;
> > > > > +   }
> > > > > +
> > > > > +   return true;
> > > > > +}
> > > > > +EXPORT_SYMBOL_GPL(drm_afbc_check_offset);
> > > >
> > > > Is this actually universally true? If the offset is sufficiently
> > > > aligned for (e.g.) DMA transfers to succeed, is there any reason why it
> > > > must be zero?
> > > >
> > > > > +bool drm_afbc_check_size_align(struct drm_device *dev,
> > > > > +                          const struct drm_mode_fb_cmd2 *mode_cmd)
> > > > > +{
> > > > > +   switch (mode_cmd->modifier[0] &
> > > > > AFBC_FORMAT_MOD_BLOCK_SIZE_MASK) {
> > > > > +   case AFBC_FORMAT_MOD_BLOCK_SIZE_16x16:
> > > > > +           if ((mode_cmd->width % 16) || (mode_cmd->height % 16))
> > > > > {
> > > >
> > > > This is a dealbreaker for many resolutions: for example, 1366x768 isn't
> > > > cleanly divisible by 16 in width. So this means that we would have to
> > > > either use a larger buffer and crop, or scale, or something.
> > > >
> > > > No userspace is prepared to align fb width/height to tile dimensions
> > > > like this, so this check will basically fail everywhere.
> > > >
> > > > However, overallocation relative to the declared width/height isn't a
> > > > problem at all. In order to deal with horizontal alignment, you simply
> > > > need to ensure that the stride is a multiple of the tile width; for
> > > > vertical arrangement, that the buffer is large enough to contain
> > > > sufficient 'lines' to the next tile boundary.
> > > >
> > > > i.e. rather than checking width/height, you should check:
> > > >   * fb_stride >= (ALIGN(fb_width, tile_width), bpp)
> > > >   * buf_size >= fb_stride * ALIGN(fb_height, tile_height)
> > >
> > > Well, sort of.
> > >
> > > I agree with you that for horizontal padding, we can indeed use pitch.
> > >
> > > However, the AFBC decoder(s) need to know exactly what the total
> > > _allocated_ size in pixels of the buffer is - as this influences the
> > > header size, and we need to know the header size to know where it ends
> > > and the body begins.
> > >
> > > I see a couple of possible ways forwards:
> > >
> > >  - Keep it as-is. The restrictive checks ensure that there's no
> > >    ambiguity and we use the fb width/height to determine the real
> > >    allocated width/height. Userspace needs to be AFBC-aware and set up
> > >    plane cropping to handle the alignment differences.
> > >
> > >  - Use pitch to determine the "real" width, and internally in the
> > >    kernel align height up to the next alignment boundary. This works
> > >    OK, so long as there's no additional padding at the bottom of the
> > >    buffer. This would work, but I can't figure a way to check/enforce
> > >    that there's no additional padding at the bottom.
> > >
> > >  - Something else...
> > >
> > > The checks as-implemented were deliberately conservative, and don't
> > > preclude doing some relaxation in the future.
> > >
> > > On Android, gralloc is used to store the "real" allocated width/height
> > > and this is used to set up the DRM API appropriately.
> > 
> > Fake stride + real visible h/w in the drmfb. Because that's how it
> > works with all the tiled formats already, and expecting userspace to
> > fudge this all correctly seems very backwards to me. In a way we had
> > that entire fake stride discussion already for the block size format
> > stuff already, but now in a different flavour.
> 
> Fake stride - like I said, no problem; sounds good. That solves one
> dimension.
> 
> So do you have a proposal for how we determine what the allocated
> height is in that case? I don't really see a way.

Could you compute the height by looking at the buffer size? Or does that
not help since the header stuff is generally rather small?

Otherwise I guess just round up height and hope it works. If we run into a
use-case where that doesn't work anymore somehow, then we get to rev all
the afbc modifiers and make them 2 planes. With that there's no such issue
anymore (which is why the intel compressed stuff has 2 planes).
-Daniel


> Thanks,
> -Brian
> 
> > 
> > Also I think that's more reasons why this should be no-opt-outable
> > code that's done for all drivers when we check framebuffers in addfb.
> > Plus then some helpers to get at computed values for any framebuffer
> > we know to be valid.
> > -Daniel
> > 
> > > > This may force us to do some silly cropping games inside the Rockchip
> > > > KMS driver, but I feel it beats the alternative of breaking userspace.
> > >
> > > Well, nothing's going to get broken - it's just perhaps not ready to
> > > turn on AFBC yet.
> > >
> > > >
> > > > > +                   DRM_DEBUG_KMS(
> > > > > +                           "AFBC buffer must be aligned to 16
> > > > > pixels\n"
> > > > > +                   );
> > > > > +                   return false;
> > > > > +           }
> > > > > +           break;
> > > > > +   case AFBC_FORMAT_MOD_BLOCK_SIZE_32x8:
> > > > > +           /* fall through */
> > > >
> > > > It's also incongruous that 32x8 is unsupported here, but has a section
> > > > in get_superblk_wh; please harmonise them so this section either does
> > > > the checks as above, or that get_superblk_wh doesn't support 32x8
> > > > either.
> > > >
> > > > > +bool drm_afbc_check_fb_size_ret(u32 pitch, int bpp,
> > > > > +                           u32 w, u32 h, u32 superblk_w, u32
> > > > > superblk_h,
> > > > > +                           size_t size, u32 offset, u32 hdr_align,
> > > > > +                           u32 *payload_off, u32 *total_size)
> > > > > +{
> > > > > +   int n_superblks = 0;
> > > > > +   u32 superblk_sz = 0;
> > > > > +   u32 afbc_size = 0;
> > > >
> > > > Please don't initialise the above three variables, given that you go on
> > > > to immediately change their values. In this case, initialising to zero
> > > > can only hide legitimate uninitialised-variable-use warnings.
> > > >
> > > > > +   n_superblks = (w / superblk_w) * (h / superblk_h);
> > > > > +   superblk_sz = (bpp * superblk_w * superblk_h) / BITS_PER_BYTE;
> > > > > +   afbc_size = ALIGN(n_superblks * AFBC_HEADER_SIZE, hdr_align);
> > > > > +   *payload_off = afbc_size;
> > > > > +
> > > > > +   afbc_size += n_superblks * ALIGN(superblk_sz,
> > > > > AFBC_SUPERBLK_ALIGNMENT);
> > > > > +   *total_size = afbc_size + offset;
> > > >
> > > > Generally these are referred to as 'tiles' rather than 'superblocks',
> > > > given that I would only expect one superblock per buffer, but if that's
> > > > the terminology AFBC uses then it might be better to stick with it.
> > > >
> > > > > +   if ((w * bpp) != (pitch * BITS_PER_BYTE)) {
> > > > > +           DRM_DEBUG_KMS("Invalid value of (pitch * BITS_PER_BYTE)
> > > > > (=%u) should be same as width (=%u) * bpp (=%u)\n",
> > > > > +                         pitch * BITS_PER_BYTE, w, bpp
> > > > > +           );
> > > > > +           return false;
> > > > > +   }
> > > >
> > > > Having a too-small pitch is obviously a problem and we should reject
> > > > it. But is having a too-large pitch really a problem; does it need to
> > > > be an exact match, or can we support the case where the pitch is too
> > > > large but also tile-aligned? If we can, it would be very good to
> > > > support that.
> > >
> > > The reason for forcing it to be exact is as I said above - we _must_
> > > know what the "real" width and height is. Implementing this check to
> > > force (pitch == width * bpp) ensures that, and also leaves the option
> > > for us to relax to allow a larger pitch (as above) if that was the
> > > preferred approach for alignment.
> > >
> > > In general the current checks are deliberately designed to leave the
> > > door open for future improvements without breaking anything.
> > >
> > > Cheers,
> > > -Brian
> > >
> > > >
> > > > Cheers,
> > > > Daniel
> > > >
> > > IMPORTANT NOTICE: The contents of this email and any attachments are confidential and may also be privileged. If you are not the intended recipient, please notify the sender immediately and do not disclose the contents to any other person, use it for any purpose, or store or copy the information in any medium. Thank you.
> 
> Not sure how that snuck in.
> 
> > 
> > 
> > 
> > -- 
> > Daniel Vetter
> > Software Engineer, Intel Corporation
> > +41 (0) 79 365 57 48 - http://blog.ffwll.ch

-- 
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 63+ messages in thread

* Re: [PATCHv2 1/4] drm/arm: Factor out generic afbc helpers
@ 2019-11-07 19:28                     ` Daniel Vetter
  0 siblings, 0 replies; 63+ messages in thread
From: Daniel Vetter @ 2019-11-07 19:28 UTC (permalink / raw)
  To: Brian Starkey
  Cc: nd, Ayan Halder, kernel, Daniel Stone, David Airlie, Liviu Dudau,
	Andrzej Pietrasiewicz, linux-rockchip,
	james qian wang (Arm Technology China),
	dri-devel, Mihail Atanassov, Sean Paul

On Thu, Nov 07, 2019 at 05:49:14PM +0000, Brian Starkey wrote:
> Hi Daniel,
> 
> On Thu, Nov 07, 2019 at 06:32:01PM +0100, Daniel Vetter wrote:
> > On Thu, Nov 7, 2019 at 6:20 PM Brian Starkey <Brian.Starkey@arm.com> wrote:
> > >
> > > Hi Daniel,
> > >
> > > On Tue, Nov 05, 2019 at 11:26:36PM +0000, Daniel Stone wrote:
> > > > Hi Andrzej,
> > > > Thanks for taking this on! It's looking better than v1 for sure. A few
> > > > things below:
> > > >
> > > > On Mon, 2019-11-04 at 23:12 +0100, Andrzej Pietrasiewicz wrote:
> > > > > +bool drm_afbc_check_offset(struct drm_device *dev,
> > > > > +                      const struct drm_mode_fb_cmd2 *mode_cmd)
> > > > > +{
> > > > > +   if (mode_cmd->offsets[0] != 0) {
> > > > > +           DRM_DEBUG_KMS("AFBC buffers' plane offset should be
> > > > > 0\n");
> > > > > +           return false;
> > > > > +   }
> > > > > +
> > > > > +   return true;
> > > > > +}
> > > > > +EXPORT_SYMBOL_GPL(drm_afbc_check_offset);
> > > >
> > > > Is this actually universally true? If the offset is sufficiently
> > > > aligned for (e.g.) DMA transfers to succeed, is there any reason why it
> > > > must be zero?
> > > >
> > > > > +bool drm_afbc_check_size_align(struct drm_device *dev,
> > > > > +                          const struct drm_mode_fb_cmd2 *mode_cmd)
> > > > > +{
> > > > > +   switch (mode_cmd->modifier[0] &
> > > > > AFBC_FORMAT_MOD_BLOCK_SIZE_MASK) {
> > > > > +   case AFBC_FORMAT_MOD_BLOCK_SIZE_16x16:
> > > > > +           if ((mode_cmd->width % 16) || (mode_cmd->height % 16))
> > > > > {
> > > >
> > > > This is a dealbreaker for many resolutions: for example, 1366x768 isn't
> > > > cleanly divisible by 16 in width. So this means that we would have to
> > > > either use a larger buffer and crop, or scale, or something.
> > > >
> > > > No userspace is prepared to align fb width/height to tile dimensions
> > > > like this, so this check will basically fail everywhere.
> > > >
> > > > However, overallocation relative to the declared width/height isn't a
> > > > problem at all. In order to deal with horizontal alignment, you simply
> > > > need to ensure that the stride is a multiple of the tile width; for
> > > > vertical arrangement, that the buffer is large enough to contain
> > > > sufficient 'lines' to the next tile boundary.
> > > >
> > > > i.e. rather than checking width/height, you should check:
> > > >   * fb_stride >= (ALIGN(fb_width, tile_width), bpp)
> > > >   * buf_size >= fb_stride * ALIGN(fb_height, tile_height)
> > >
> > > Well, sort of.
> > >
> > > I agree with you that for horizontal padding, we can indeed use pitch.
> > >
> > > However, the AFBC decoder(s) need to know exactly what the total
> > > _allocated_ size in pixels of the buffer is - as this influences the
> > > header size, and we need to know the header size to know where it ends
> > > and the body begins.
> > >
> > > I see a couple of possible ways forwards:
> > >
> > >  - Keep it as-is. The restrictive checks ensure that there's no
> > >    ambiguity and we use the fb width/height to determine the real
> > >    allocated width/height. Userspace needs to be AFBC-aware and set up
> > >    plane cropping to handle the alignment differences.
> > >
> > >  - Use pitch to determine the "real" width, and internally in the
> > >    kernel align height up to the next alignment boundary. This works
> > >    OK, so long as there's no additional padding at the bottom of the
> > >    buffer. This would work, but I can't figure a way to check/enforce
> > >    that there's no additional padding at the bottom.
> > >
> > >  - Something else...
> > >
> > > The checks as-implemented were deliberately conservative, and don't
> > > preclude doing some relaxation in the future.
> > >
> > > On Android, gralloc is used to store the "real" allocated width/height
> > > and this is used to set up the DRM API appropriately.
> > 
> > Fake stride + real visible h/w in the drmfb. Because that's how it
> > works with all the tiled formats already, and expecting userspace to
> > fudge this all correctly seems very backwards to me. In a way we had
> > that entire fake stride discussion already for the block size format
> > stuff already, but now in a different flavour.
> 
> Fake stride - like I said, no problem; sounds good. That solves one
> dimension.
> 
> So do you have a proposal for how we determine what the allocated
> height is in that case? I don't really see a way.

Could you compute the height by looking at the buffer size? Or does that
not help since the header stuff is generally rather small?

Otherwise I guess just round up height and hope it works. If we run into a
use-case where that doesn't work anymore somehow, then we get to rev all
the afbc modifiers and make them 2 planes. With that there's no such issue
anymore (which is why the intel compressed stuff has 2 planes).
-Daniel


> Thanks,
> -Brian
> 
> > 
> > Also I think that's more reasons why this should be no-opt-outable
> > code that's done for all drivers when we check framebuffers in addfb.
> > Plus then some helpers to get at computed values for any framebuffer
> > we know to be valid.
> > -Daniel
> > 
> > > > This may force us to do some silly cropping games inside the Rockchip
> > > > KMS driver, but I feel it beats the alternative of breaking userspace.
> > >
> > > Well, nothing's going to get broken - it's just perhaps not ready to
> > > turn on AFBC yet.
> > >
> > > >
> > > > > +                   DRM_DEBUG_KMS(
> > > > > +                           "AFBC buffer must be aligned to 16
> > > > > pixels\n"
> > > > > +                   );
> > > > > +                   return false;
> > > > > +           }
> > > > > +           break;
> > > > > +   case AFBC_FORMAT_MOD_BLOCK_SIZE_32x8:
> > > > > +           /* fall through */
> > > >
> > > > It's also incongruous that 32x8 is unsupported here, but has a section
> > > > in get_superblk_wh; please harmonise them so this section either does
> > > > the checks as above, or that get_superblk_wh doesn't support 32x8
> > > > either.
> > > >
> > > > > +bool drm_afbc_check_fb_size_ret(u32 pitch, int bpp,
> > > > > +                           u32 w, u32 h, u32 superblk_w, u32
> > > > > superblk_h,
> > > > > +                           size_t size, u32 offset, u32 hdr_align,
> > > > > +                           u32 *payload_off, u32 *total_size)
> > > > > +{
> > > > > +   int n_superblks = 0;
> > > > > +   u32 superblk_sz = 0;
> > > > > +   u32 afbc_size = 0;
> > > >
> > > > Please don't initialise the above three variables, given that you go on
> > > > to immediately change their values. In this case, initialising to zero
> > > > can only hide legitimate uninitialised-variable-use warnings.
> > > >
> > > > > +   n_superblks = (w / superblk_w) * (h / superblk_h);
> > > > > +   superblk_sz = (bpp * superblk_w * superblk_h) / BITS_PER_BYTE;
> > > > > +   afbc_size = ALIGN(n_superblks * AFBC_HEADER_SIZE, hdr_align);
> > > > > +   *payload_off = afbc_size;
> > > > > +
> > > > > +   afbc_size += n_superblks * ALIGN(superblk_sz,
> > > > > AFBC_SUPERBLK_ALIGNMENT);
> > > > > +   *total_size = afbc_size + offset;
> > > >
> > > > Generally these are referred to as 'tiles' rather than 'superblocks',
> > > > given that I would only expect one superblock per buffer, but if that's
> > > > the terminology AFBC uses then it might be better to stick with it.
> > > >
> > > > > +   if ((w * bpp) != (pitch * BITS_PER_BYTE)) {
> > > > > +           DRM_DEBUG_KMS("Invalid value of (pitch * BITS_PER_BYTE)
> > > > > (=%u) should be same as width (=%u) * bpp (=%u)\n",
> > > > > +                         pitch * BITS_PER_BYTE, w, bpp
> > > > > +           );
> > > > > +           return false;
> > > > > +   }
> > > >
> > > > Having a too-small pitch is obviously a problem and we should reject
> > > > it. But is having a too-large pitch really a problem; does it need to
> > > > be an exact match, or can we support the case where the pitch is too
> > > > large but also tile-aligned? If we can, it would be very good to
> > > > support that.
> > >
> > > The reason for forcing it to be exact is as I said above - we _must_
> > > know what the "real" width and height is. Implementing this check to
> > > force (pitch == width * bpp) ensures that, and also leaves the option
> > > for us to relax to allow a larger pitch (as above) if that was the
> > > preferred approach for alignment.
> > >
> > > In general the current checks are deliberately designed to leave the
> > > door open for future improvements without breaking anything.
> > >
> > > Cheers,
> > > -Brian
> > >
> > > >
> > > > Cheers,
> > > > Daniel
> > > >
> > > IMPORTANT NOTICE: The contents of this email and any attachments are confidential and may also be privileged. If you are not the intended recipient, please notify the sender immediately and do not disclose the contents to any other person, use it for any purpose, or store or copy the information in any medium. Thank you.
> 
> Not sure how that snuck in.
> 
> > 
> > 
> > 
> > -- 
> > Daniel Vetter
> > Software Engineer, Intel Corporation
> > +41 (0) 79 365 57 48 - http://blog.ffwll.ch

-- 
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 63+ messages in thread

* Re: [PATCHv2 1/4] drm/arm: Factor out generic afbc helpers
@ 2019-11-08  9:46                       ` Brian Starkey
  0 siblings, 0 replies; 63+ messages in thread
From: Brian Starkey @ 2019-11-08  9:46 UTC (permalink / raw)
  To: Daniel Vetter
  Cc: nd, Ayan Halder, kernel, Daniel Stone, David Airlie, Liviu Dudau,
	Andrzej Pietrasiewicz, linux-rockchip,
	james qian wang (Arm Technology China),
	dri-devel, Mihail Atanassov, Sean Paul

Hi Daniel,

On Thu, Nov 07, 2019 at 08:28:08PM +0100, Daniel Vetter wrote:
> On Thu, Nov 07, 2019 at 05:49:14PM +0000, Brian Starkey wrote:
> > Hi Daniel,
> > 
> > On Thu, Nov 07, 2019 at 06:32:01PM +0100, Daniel Vetter wrote:
> > > On Thu, Nov 7, 2019 at 6:20 PM Brian Starkey <Brian.Starkey@arm.com> wrote:
> > > >
> > > > Hi Daniel,
> > > >
> > > > On Tue, Nov 05, 2019 at 11:26:36PM +0000, Daniel Stone wrote:
> > > > > Hi Andrzej,
> > > > > Thanks for taking this on! It's looking better than v1 for sure. A few
> > > > > things below:
> > > > >
> > > > > On Mon, 2019-11-04 at 23:12 +0100, Andrzej Pietrasiewicz wrote:
> > > > > > +bool drm_afbc_check_offset(struct drm_device *dev,
> > > > > > +                      const struct drm_mode_fb_cmd2 *mode_cmd)
> > > > > > +{
> > > > > > +   if (mode_cmd->offsets[0] != 0) {
> > > > > > +           DRM_DEBUG_KMS("AFBC buffers' plane offset should be
> > > > > > 0\n");
> > > > > > +           return false;
> > > > > > +   }
> > > > > > +
> > > > > > +   return true;
> > > > > > +}
> > > > > > +EXPORT_SYMBOL_GPL(drm_afbc_check_offset);
> > > > >
> > > > > Is this actually universally true? If the offset is sufficiently
> > > > > aligned for (e.g.) DMA transfers to succeed, is there any reason why it
> > > > > must be zero?
> > > > >
> > > > > > +bool drm_afbc_check_size_align(struct drm_device *dev,
> > > > > > +                          const struct drm_mode_fb_cmd2 *mode_cmd)
> > > > > > +{
> > > > > > +   switch (mode_cmd->modifier[0] &
> > > > > > AFBC_FORMAT_MOD_BLOCK_SIZE_MASK) {
> > > > > > +   case AFBC_FORMAT_MOD_BLOCK_SIZE_16x16:
> > > > > > +           if ((mode_cmd->width % 16) || (mode_cmd->height % 16))
> > > > > > {
> > > > >
> > > > > This is a dealbreaker for many resolutions: for example, 1366x768 isn't
> > > > > cleanly divisible by 16 in width. So this means that we would have to
> > > > > either use a larger buffer and crop, or scale, or something.
> > > > >
> > > > > No userspace is prepared to align fb width/height to tile dimensions
> > > > > like this, so this check will basically fail everywhere.
> > > > >
> > > > > However, overallocation relative to the declared width/height isn't a
> > > > > problem at all. In order to deal with horizontal alignment, you simply
> > > > > need to ensure that the stride is a multiple of the tile width; for
> > > > > vertical arrangement, that the buffer is large enough to contain
> > > > > sufficient 'lines' to the next tile boundary.
> > > > >
> > > > > i.e. rather than checking width/height, you should check:
> > > > >   * fb_stride >= (ALIGN(fb_width, tile_width), bpp)
> > > > >   * buf_size >= fb_stride * ALIGN(fb_height, tile_height)
> > > >
> > > > Well, sort of.
> > > >
> > > > I agree with you that for horizontal padding, we can indeed use pitch.
> > > >
> > > > However, the AFBC decoder(s) need to know exactly what the total
> > > > _allocated_ size in pixels of the buffer is - as this influences the
> > > > header size, and we need to know the header size to know where it ends
> > > > and the body begins.
> > > >
> > > > I see a couple of possible ways forwards:
> > > >
> > > >  - Keep it as-is. The restrictive checks ensure that there's no
> > > >    ambiguity and we use the fb width/height to determine the real
> > > >    allocated width/height. Userspace needs to be AFBC-aware and set up
> > > >    plane cropping to handle the alignment differences.
> > > >
> > > >  - Use pitch to determine the "real" width, and internally in the
> > > >    kernel align height up to the next alignment boundary. This works
> > > >    OK, so long as there's no additional padding at the bottom of the
> > > >    buffer. This would work, but I can't figure a way to check/enforce
> > > >    that there's no additional padding at the bottom.
> > > >
> > > >  - Something else...
> > > >
> > > > The checks as-implemented were deliberately conservative, and don't
> > > > preclude doing some relaxation in the future.
> > > >
> > > > On Android, gralloc is used to store the "real" allocated width/height
> > > > and this is used to set up the DRM API appropriately.
> > > 
> > > Fake stride + real visible h/w in the drmfb. Because that's how it
> > > works with all the tiled formats already, and expecting userspace to
> > > fudge this all correctly seems very backwards to me. In a way we had
> > > that entire fake stride discussion already for the block size format
> > > stuff already, but now in a different flavour.
> > 
> > Fake stride - like I said, no problem; sounds good. That solves one
> > dimension.
> > 
> > So do you have a proposal for how we determine what the allocated
> > height is in that case? I don't really see a way.
> 
> Could you compute the height by looking at the buffer size? Or does that
> not help since the header stuff is generally rather small?

I've wondered about that. We might be able to use it heuristically,
but it does place certain assumptions on the allocator - for instance
rounding up to a page order might cause problems.

> 
> Otherwise I guess just round up height and hope it works. If we run into a
> use-case where that doesn't work anymore somehow, then we get to rev all
> the afbc modifiers and make them 2 planes. With that there's no such issue
> anymore (which is why the intel compressed stuff has 2 planes).
> -Daniel
> 

We considered exposing the header explicitly as a plane before
originally submitting the modifiers; however the header and body are
linked in such a way that they aren't separable, so they aren't really
separate planes. Also we have multi-plane AFBC buffers, where each
plane has its own header and thus we'd need at least 6 planes to
describe it fully if we separate out the header.

I'm not entirely sure how a separate header plane would help with this
issue anyway.


We could round up the height, which should cover the common case. It
seem(ed) safest to start with the conservative restrictions.

My proposal for handling the case of additional vertical padding on
top of that would be to add a field in the modifier which indicates
how much additional vertical padding there is. I know the Broadcom
SAND modifiers do a similar thing. It does make the modifiers a bit
"non-opaque" though, as the modifier value can't be simply queried
from the modifier list.


... all of that said, the kernel interface is already rich enough to
support everything, if userspace understands that sometimes it needs
to crop.

Thanks,
-Brian

> 
> > Thanks,
> > -Brian
> > 
> > > 
> > > Also I think that's more reasons why this should be no-opt-outable
> > > code that's done for all drivers when we check framebuffers in addfb.
> > > Plus then some helpers to get at computed values for any framebuffer
> > > we know to be valid.
> > > -Daniel
> > > 
> > > > > This may force us to do some silly cropping games inside the Rockchip
> > > > > KMS driver, but I feel it beats the alternative of breaking userspace.
> > > >
> > > > Well, nothing's going to get broken - it's just perhaps not ready to
> > > > turn on AFBC yet.
> > > >
> > > > >
> > > > > > +                   DRM_DEBUG_KMS(
> > > > > > +                           "AFBC buffer must be aligned to 16
> > > > > > pixels\n"
> > > > > > +                   );
> > > > > > +                   return false;
> > > > > > +           }
> > > > > > +           break;
> > > > > > +   case AFBC_FORMAT_MOD_BLOCK_SIZE_32x8:
> > > > > > +           /* fall through */
> > > > >
> > > > > It's also incongruous that 32x8 is unsupported here, but has a section
> > > > > in get_superblk_wh; please harmonise them so this section either does
> > > > > the checks as above, or that get_superblk_wh doesn't support 32x8
> > > > > either.
> > > > >
> > > > > > +bool drm_afbc_check_fb_size_ret(u32 pitch, int bpp,
> > > > > > +                           u32 w, u32 h, u32 superblk_w, u32
> > > > > > superblk_h,
> > > > > > +                           size_t size, u32 offset, u32 hdr_align,
> > > > > > +                           u32 *payload_off, u32 *total_size)
> > > > > > +{
> > > > > > +   int n_superblks = 0;
> > > > > > +   u32 superblk_sz = 0;
> > > > > > +   u32 afbc_size = 0;
> > > > >
> > > > > Please don't initialise the above three variables, given that you go on
> > > > > to immediately change their values. In this case, initialising to zero
> > > > > can only hide legitimate uninitialised-variable-use warnings.
> > > > >
> > > > > > +   n_superblks = (w / superblk_w) * (h / superblk_h);
> > > > > > +   superblk_sz = (bpp * superblk_w * superblk_h) / BITS_PER_BYTE;
> > > > > > +   afbc_size = ALIGN(n_superblks * AFBC_HEADER_SIZE, hdr_align);
> > > > > > +   *payload_off = afbc_size;
> > > > > > +
> > > > > > +   afbc_size += n_superblks * ALIGN(superblk_sz,
> > > > > > AFBC_SUPERBLK_ALIGNMENT);
> > > > > > +   *total_size = afbc_size + offset;
> > > > >
> > > > > Generally these are referred to as 'tiles' rather than 'superblocks',
> > > > > given that I would only expect one superblock per buffer, but if that's
> > > > > the terminology AFBC uses then it might be better to stick with it.
> > > > >
> > > > > > +   if ((w * bpp) != (pitch * BITS_PER_BYTE)) {
> > > > > > +           DRM_DEBUG_KMS("Invalid value of (pitch * BITS_PER_BYTE)
> > > > > > (=%u) should be same as width (=%u) * bpp (=%u)\n",
> > > > > > +                         pitch * BITS_PER_BYTE, w, bpp
> > > > > > +           );
> > > > > > +           return false;
> > > > > > +   }
> > > > >
> > > > > Having a too-small pitch is obviously a problem and we should reject
> > > > > it. But is having a too-large pitch really a problem; does it need to
> > > > > be an exact match, or can we support the case where the pitch is too
> > > > > large but also tile-aligned? If we can, it would be very good to
> > > > > support that.
> > > >
> > > > The reason for forcing it to be exact is as I said above - we _must_
> > > > know what the "real" width and height is. Implementing this check to
> > > > force (pitch == width * bpp) ensures that, and also leaves the option
> > > > for us to relax to allow a larger pitch (as above) if that was the
> > > > preferred approach for alignment.
> > > >
> > > > In general the current checks are deliberately designed to leave the
> > > > door open for future improvements without breaking anything.
> > > >
> > > > Cheers,
> > > > -Brian
> > > >
> > > > >
> > > > > Cheers,
> > > > > Daniel
> > > > >
> > > > IMPORTANT NOTICE: The contents of this email and any attachments are confidential and may also be privileged. If you are not the intended recipient, please notify the sender immediately and do not disclose the contents to any other person, use it for any purpose, or store or copy the information in any medium. Thank you.
> > 
> > Not sure how that snuck in.
> > 
> > > 
> > > 
> > > 
> > > -- 
> > > Daniel Vetter
> > > Software Engineer, Intel Corporation
> > > +41 (0) 79 365 57 48 - http://blog.ffwll.ch
> 
> -- 
> Daniel Vetter
> Software Engineer, Intel Corporation
> http://blog.ffwll.ch
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 63+ messages in thread

* Re: [PATCHv2 1/4] drm/arm: Factor out generic afbc helpers
@ 2019-11-08  9:46                       ` Brian Starkey
  0 siblings, 0 replies; 63+ messages in thread
From: Brian Starkey @ 2019-11-08  9:46 UTC (permalink / raw)
  To: Daniel Vetter
  Cc: nd, Ayan Halder, kernel, Daniel Stone, David Airlie, Liviu Dudau,
	Andrzej Pietrasiewicz, linux-rockchip,
	james qian wang (Arm Technology China),
	dri-devel, Mihail Atanassov, Sean Paul

Hi Daniel,

On Thu, Nov 07, 2019 at 08:28:08PM +0100, Daniel Vetter wrote:
> On Thu, Nov 07, 2019 at 05:49:14PM +0000, Brian Starkey wrote:
> > Hi Daniel,
> > 
> > On Thu, Nov 07, 2019 at 06:32:01PM +0100, Daniel Vetter wrote:
> > > On Thu, Nov 7, 2019 at 6:20 PM Brian Starkey <Brian.Starkey@arm.com> wrote:
> > > >
> > > > Hi Daniel,
> > > >
> > > > On Tue, Nov 05, 2019 at 11:26:36PM +0000, Daniel Stone wrote:
> > > > > Hi Andrzej,
> > > > > Thanks for taking this on! It's looking better than v1 for sure. A few
> > > > > things below:
> > > > >
> > > > > On Mon, 2019-11-04 at 23:12 +0100, Andrzej Pietrasiewicz wrote:
> > > > > > +bool drm_afbc_check_offset(struct drm_device *dev,
> > > > > > +                      const struct drm_mode_fb_cmd2 *mode_cmd)
> > > > > > +{
> > > > > > +   if (mode_cmd->offsets[0] != 0) {
> > > > > > +           DRM_DEBUG_KMS("AFBC buffers' plane offset should be
> > > > > > 0\n");
> > > > > > +           return false;
> > > > > > +   }
> > > > > > +
> > > > > > +   return true;
> > > > > > +}
> > > > > > +EXPORT_SYMBOL_GPL(drm_afbc_check_offset);
> > > > >
> > > > > Is this actually universally true? If the offset is sufficiently
> > > > > aligned for (e.g.) DMA transfers to succeed, is there any reason why it
> > > > > must be zero?
> > > > >
> > > > > > +bool drm_afbc_check_size_align(struct drm_device *dev,
> > > > > > +                          const struct drm_mode_fb_cmd2 *mode_cmd)
> > > > > > +{
> > > > > > +   switch (mode_cmd->modifier[0] &
> > > > > > AFBC_FORMAT_MOD_BLOCK_SIZE_MASK) {
> > > > > > +   case AFBC_FORMAT_MOD_BLOCK_SIZE_16x16:
> > > > > > +           if ((mode_cmd->width % 16) || (mode_cmd->height % 16))
> > > > > > {
> > > > >
> > > > > This is a dealbreaker for many resolutions: for example, 1366x768 isn't
> > > > > cleanly divisible by 16 in width. So this means that we would have to
> > > > > either use a larger buffer and crop, or scale, or something.
> > > > >
> > > > > No userspace is prepared to align fb width/height to tile dimensions
> > > > > like this, so this check will basically fail everywhere.
> > > > >
> > > > > However, overallocation relative to the declared width/height isn't a
> > > > > problem at all. In order to deal with horizontal alignment, you simply
> > > > > need to ensure that the stride is a multiple of the tile width; for
> > > > > vertical arrangement, that the buffer is large enough to contain
> > > > > sufficient 'lines' to the next tile boundary.
> > > > >
> > > > > i.e. rather than checking width/height, you should check:
> > > > >   * fb_stride >= (ALIGN(fb_width, tile_width), bpp)
> > > > >   * buf_size >= fb_stride * ALIGN(fb_height, tile_height)
> > > >
> > > > Well, sort of.
> > > >
> > > > I agree with you that for horizontal padding, we can indeed use pitch.
> > > >
> > > > However, the AFBC decoder(s) need to know exactly what the total
> > > > _allocated_ size in pixels of the buffer is - as this influences the
> > > > header size, and we need to know the header size to know where it ends
> > > > and the body begins.
> > > >
> > > > I see a couple of possible ways forwards:
> > > >
> > > >  - Keep it as-is. The restrictive checks ensure that there's no
> > > >    ambiguity and we use the fb width/height to determine the real
> > > >    allocated width/height. Userspace needs to be AFBC-aware and set up
> > > >    plane cropping to handle the alignment differences.
> > > >
> > > >  - Use pitch to determine the "real" width, and internally in the
> > > >    kernel align height up to the next alignment boundary. This works
> > > >    OK, so long as there's no additional padding at the bottom of the
> > > >    buffer. This would work, but I can't figure a way to check/enforce
> > > >    that there's no additional padding at the bottom.
> > > >
> > > >  - Something else...
> > > >
> > > > The checks as-implemented were deliberately conservative, and don't
> > > > preclude doing some relaxation in the future.
> > > >
> > > > On Android, gralloc is used to store the "real" allocated width/height
> > > > and this is used to set up the DRM API appropriately.
> > > 
> > > Fake stride + real visible h/w in the drmfb. Because that's how it
> > > works with all the tiled formats already, and expecting userspace to
> > > fudge this all correctly seems very backwards to me. In a way we had
> > > that entire fake stride discussion already for the block size format
> > > stuff already, but now in a different flavour.
> > 
> > Fake stride - like I said, no problem; sounds good. That solves one
> > dimension.
> > 
> > So do you have a proposal for how we determine what the allocated
> > height is in that case? I don't really see a way.
> 
> Could you compute the height by looking at the buffer size? Or does that
> not help since the header stuff is generally rather small?

I've wondered about that. We might be able to use it heuristically,
but it does place certain assumptions on the allocator - for instance
rounding up to a page order might cause problems.

> 
> Otherwise I guess just round up height and hope it works. If we run into a
> use-case where that doesn't work anymore somehow, then we get to rev all
> the afbc modifiers and make them 2 planes. With that there's no such issue
> anymore (which is why the intel compressed stuff has 2 planes).
> -Daniel
> 

We considered exposing the header explicitly as a plane before
originally submitting the modifiers; however the header and body are
linked in such a way that they aren't separable, so they aren't really
separate planes. Also we have multi-plane AFBC buffers, where each
plane has its own header and thus we'd need at least 6 planes to
describe it fully if we separate out the header.

I'm not entirely sure how a separate header plane would help with this
issue anyway.


We could round up the height, which should cover the common case. It
seem(ed) safest to start with the conservative restrictions.

My proposal for handling the case of additional vertical padding on
top of that would be to add a field in the modifier which indicates
how much additional vertical padding there is. I know the Broadcom
SAND modifiers do a similar thing. It does make the modifiers a bit
"non-opaque" though, as the modifier value can't be simply queried
from the modifier list.


... all of that said, the kernel interface is already rich enough to
support everything, if userspace understands that sometimes it needs
to crop.

Thanks,
-Brian

> 
> > Thanks,
> > -Brian
> > 
> > > 
> > > Also I think that's more reasons why this should be no-opt-outable
> > > code that's done for all drivers when we check framebuffers in addfb.
> > > Plus then some helpers to get at computed values for any framebuffer
> > > we know to be valid.
> > > -Daniel
> > > 
> > > > > This may force us to do some silly cropping games inside the Rockchip
> > > > > KMS driver, but I feel it beats the alternative of breaking userspace.
> > > >
> > > > Well, nothing's going to get broken - it's just perhaps not ready to
> > > > turn on AFBC yet.
> > > >
> > > > >
> > > > > > +                   DRM_DEBUG_KMS(
> > > > > > +                           "AFBC buffer must be aligned to 16
> > > > > > pixels\n"
> > > > > > +                   );
> > > > > > +                   return false;
> > > > > > +           }
> > > > > > +           break;
> > > > > > +   case AFBC_FORMAT_MOD_BLOCK_SIZE_32x8:
> > > > > > +           /* fall through */
> > > > >
> > > > > It's also incongruous that 32x8 is unsupported here, but has a section
> > > > > in get_superblk_wh; please harmonise them so this section either does
> > > > > the checks as above, or that get_superblk_wh doesn't support 32x8
> > > > > either.
> > > > >
> > > > > > +bool drm_afbc_check_fb_size_ret(u32 pitch, int bpp,
> > > > > > +                           u32 w, u32 h, u32 superblk_w, u32
> > > > > > superblk_h,
> > > > > > +                           size_t size, u32 offset, u32 hdr_align,
> > > > > > +                           u32 *payload_off, u32 *total_size)
> > > > > > +{
> > > > > > +   int n_superblks = 0;
> > > > > > +   u32 superblk_sz = 0;
> > > > > > +   u32 afbc_size = 0;
> > > > >
> > > > > Please don't initialise the above three variables, given that you go on
> > > > > to immediately change their values. In this case, initialising to zero
> > > > > can only hide legitimate uninitialised-variable-use warnings.
> > > > >
> > > > > > +   n_superblks = (w / superblk_w) * (h / superblk_h);
> > > > > > +   superblk_sz = (bpp * superblk_w * superblk_h) / BITS_PER_BYTE;
> > > > > > +   afbc_size = ALIGN(n_superblks * AFBC_HEADER_SIZE, hdr_align);
> > > > > > +   *payload_off = afbc_size;
> > > > > > +
> > > > > > +   afbc_size += n_superblks * ALIGN(superblk_sz,
> > > > > > AFBC_SUPERBLK_ALIGNMENT);
> > > > > > +   *total_size = afbc_size + offset;
> > > > >
> > > > > Generally these are referred to as 'tiles' rather than 'superblocks',
> > > > > given that I would only expect one superblock per buffer, but if that's
> > > > > the terminology AFBC uses then it might be better to stick with it.
> > > > >
> > > > > > +   if ((w * bpp) != (pitch * BITS_PER_BYTE)) {
> > > > > > +           DRM_DEBUG_KMS("Invalid value of (pitch * BITS_PER_BYTE)
> > > > > > (=%u) should be same as width (=%u) * bpp (=%u)\n",
> > > > > > +                         pitch * BITS_PER_BYTE, w, bpp
> > > > > > +           );
> > > > > > +           return false;
> > > > > > +   }
> > > > >
> > > > > Having a too-small pitch is obviously a problem and we should reject
> > > > > it. But is having a too-large pitch really a problem; does it need to
> > > > > be an exact match, or can we support the case where the pitch is too
> > > > > large but also tile-aligned? If we can, it would be very good to
> > > > > support that.
> > > >
> > > > The reason for forcing it to be exact is as I said above - we _must_
> > > > know what the "real" width and height is. Implementing this check to
> > > > force (pitch == width * bpp) ensures that, and also leaves the option
> > > > for us to relax to allow a larger pitch (as above) if that was the
> > > > preferred approach for alignment.
> > > >
> > > > In general the current checks are deliberately designed to leave the
> > > > door open for future improvements without breaking anything.
> > > >
> > > > Cheers,
> > > > -Brian
> > > >
> > > > >
> > > > > Cheers,
> > > > > Daniel
> > > > >
> > > > IMPORTANT NOTICE: The contents of this email and any attachments are confidential and may also be privileged. If you are not the intended recipient, please notify the sender immediately and do not disclose the contents to any other person, use it for any purpose, or store or copy the information in any medium. Thank you.
> > 
> > Not sure how that snuck in.
> > 
> > > 
> > > 
> > > 
> > > -- 
> > > Daniel Vetter
> > > Software Engineer, Intel Corporation
> > > +41 (0) 79 365 57 48 - http://blog.ffwll.ch
> 
> -- 
> Daniel Vetter
> Software Engineer, Intel Corporation
> http://blog.ffwll.ch
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 63+ messages in thread

* Re: [PATCHv2 3/4] drm/komeda: use afbc helpers
@ 2019-11-08 16:09             ` Ayan Halder
  0 siblings, 0 replies; 63+ messages in thread
From: Ayan Halder @ 2019-11-08 16:09 UTC (permalink / raw)
  To: Andrzej Pietrasiewicz
  Cc: nd, kernel, David Airlie, Liviu Dudau, linux-rockchip,
	james qian wang (Arm Technology China),
	dri-devel, Mihail Atanassov, Sean Paul

On Mon, Nov 04, 2019 at 11:12:27PM +0100, Andrzej Pietrasiewicz wrote:
> There are afbc helpers available.
> 
> Signed-off-by: Andrzej Pietrasiewicz <andrzej.p@collabora.com>
> ---
>  .../arm/display/komeda/komeda_format_caps.h   |  1 -
>  .../arm/display/komeda/komeda_framebuffer.c   | 44 +++++++------------
>  2 files changed, 17 insertions(+), 28 deletions(-)
> 
> diff --git a/drivers/gpu/drm/arm/display/komeda/komeda_format_caps.h b/drivers/gpu/drm/arm/display/komeda/komeda_format_caps.h
> index 32273cf18f7c..607eea80e60c 100644
> --- a/drivers/gpu/drm/arm/display/komeda/komeda_format_caps.h
> +++ b/drivers/gpu/drm/arm/display/komeda/komeda_format_caps.h
> @@ -33,7 +33,6 @@
>  
>  #define AFBC_TH_LAYOUT_ALIGNMENT	8
>  #define AFBC_HEADER_SIZE		16
> -#define AFBC_SUPERBLK_ALIGNMENT		128
>  #define AFBC_SUPERBLK_PIXELS		256
>  #define AFBC_BODY_START_ALIGNMENT	1024
>  #define AFBC_TH_BODY_START_ALIGNMENT	4096
> diff --git a/drivers/gpu/drm/arm/display/komeda/komeda_framebuffer.c b/drivers/gpu/drm/arm/display/komeda/komeda_framebuffer.c
> index 1b01a625f40e..e9c87551a5b8 100644
> --- a/drivers/gpu/drm/arm/display/komeda/komeda_framebuffer.c
> +++ b/drivers/gpu/drm/arm/display/komeda/komeda_framebuffer.c
> @@ -4,6 +4,7 @@
>   * Author: James.Qian.Wang <james.qian.wang@arm.com>
>   *
>   */
> +#include <drm/drm_afbc.h>
>  #include <drm/drm_device.h>
>  #include <drm/drm_fb_cma_helper.h>
>  #include <drm/drm_gem.h>
> @@ -43,8 +44,7 @@ komeda_fb_afbc_size_check(struct komeda_fb *kfb, struct drm_file *file,
>  	struct drm_framebuffer *fb = &kfb->base;
>  	const struct drm_format_info *info = fb->format;
>  	struct drm_gem_object *obj;
> -	u32 alignment_w = 0, alignment_h = 0, alignment_header, n_blocks, bpp;
> -	u64 min_size;
> +	u32 alignment_w = 0, alignment_h = 0, alignment_header, bpp;
>  
>  	obj = drm_gem_object_lookup(file, mode_cmd->handles[0]);
>  	if (!obj) {
> @@ -52,19 +52,15 @@ komeda_fb_afbc_size_check(struct komeda_fb *kfb, struct drm_file *file,
>  		return -ENOENT;
>  	}
>  
> -	switch (fb->modifier & AFBC_FORMAT_MOD_BLOCK_SIZE_MASK) {
> -	case AFBC_FORMAT_MOD_BLOCK_SIZE_32x8:
> -		alignment_w = 32;
> -		alignment_h = 8;
> -		break;
> -	case AFBC_FORMAT_MOD_BLOCK_SIZE_16x16:
> -		alignment_w = 16;
> -		alignment_h = 16;
> -		break;
> -	default:
> -		WARN(1, "Invalid AFBC_FORMAT_MOD_BLOCK_SIZE: %lld.\n",
> -		     fb->modifier & AFBC_FORMAT_MOD_BLOCK_SIZE_MASK);
> -		break;
> +	if (!drm_afbc_get_superblk_wh(fb->modifier, &alignment_w, &alignment_h))
> +		return -EINVAL;
> +
> +	if ((alignment_w != 16 || alignment_h != 16) &&
> +	    (alignment_w != 32 || alignment_h != 8)) {
> +		DRM_DEBUG_KMS("Unsupported afbc tile w/h [%d/%d]\n",
> +			      alignment_w, alignment_h);
> +
> +		return -EINVAL;
To be honest, the previous code looks much more readable
>  	}
>  
>  	/* tiled header afbc */
> @@ -84,20 +80,14 @@ komeda_fb_afbc_size_check(struct komeda_fb *kfb, struct drm_file *file,
>  		goto check_failed;
>  	}
>  
> -	n_blocks = (kfb->aligned_w * kfb->aligned_h) / AFBC_SUPERBLK_PIXELS;
> -	kfb->offset_payload = ALIGN(n_blocks * AFBC_HEADER_SIZE,
> -				    alignment_header);
> -
>  	bpp = komeda_get_afbc_format_bpp(info, fb->modifier);
> -	kfb->afbc_size = kfb->offset_payload + n_blocks *
> -			 ALIGN(bpp * AFBC_SUPERBLK_PIXELS / 8,
> -			       AFBC_SUPERBLK_ALIGNMENT);
> -	min_size = kfb->afbc_size + fb->offsets[0];
> -	if (min_size > obj->size) {
> -		DRM_DEBUG_KMS("afbc size check failed, obj_size: 0x%zx. min_size 0x%llx.\n",
> -			      obj->size, min_size);
We need kfb->offset_payload and kfb->afbc_size to set some registers
in d71_layer_update(). At this moment I feel like punching myself for
making the suggestion to consider abstracting some of the komeda's afbc
checks. To me it does not look like komeda(in the current shape) can take
much advantage of the generic _afbc_fb_check() function (as was suggested
previously by Danvet).

However, I will let james.qian.wang@arm.com,
Mihail.Atanassov@arm.com, Ben.Davis@arm.com comment here to see if
there could be a way of abstracting the afbc bits from komeda.

Thanks anyways for taking a stab at this.
-Ayan
> +
> +	if (!drm_afbc_check_fb_size(mode_cmd->pitches[0], bpp,
> +				    mode_cmd->width, mode_cmd->height,
> +				    alignment_w, alignment_h,
> +				    obj->size, mode_cmd->offsets[0],
> +				    AFBC_SUPERBLK_ALIGNMENT))
>  		goto check_failed;
> -	}
>  
>  	fb->obj[0] = obj;
>  	return 0;
> -- 
> 2.17.1
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 63+ messages in thread

* Re: [PATCHv2 3/4] drm/komeda: use afbc helpers
@ 2019-11-08 16:09             ` Ayan Halder
  0 siblings, 0 replies; 63+ messages in thread
From: Ayan Halder @ 2019-11-08 16:09 UTC (permalink / raw)
  To: Andrzej Pietrasiewicz
  Cc: nd, kernel, David Airlie, Liviu Dudau, linux-rockchip,
	james qian wang (Arm Technology China),
	dri-devel, Mihail Atanassov, Sean Paul

On Mon, Nov 04, 2019 at 11:12:27PM +0100, Andrzej Pietrasiewicz wrote:
> There are afbc helpers available.
> 
> Signed-off-by: Andrzej Pietrasiewicz <andrzej.p@collabora.com>
> ---
>  .../arm/display/komeda/komeda_format_caps.h   |  1 -
>  .../arm/display/komeda/komeda_framebuffer.c   | 44 +++++++------------
>  2 files changed, 17 insertions(+), 28 deletions(-)
> 
> diff --git a/drivers/gpu/drm/arm/display/komeda/komeda_format_caps.h b/drivers/gpu/drm/arm/display/komeda/komeda_format_caps.h
> index 32273cf18f7c..607eea80e60c 100644
> --- a/drivers/gpu/drm/arm/display/komeda/komeda_format_caps.h
> +++ b/drivers/gpu/drm/arm/display/komeda/komeda_format_caps.h
> @@ -33,7 +33,6 @@
>  
>  #define AFBC_TH_LAYOUT_ALIGNMENT	8
>  #define AFBC_HEADER_SIZE		16
> -#define AFBC_SUPERBLK_ALIGNMENT		128
>  #define AFBC_SUPERBLK_PIXELS		256
>  #define AFBC_BODY_START_ALIGNMENT	1024
>  #define AFBC_TH_BODY_START_ALIGNMENT	4096
> diff --git a/drivers/gpu/drm/arm/display/komeda/komeda_framebuffer.c b/drivers/gpu/drm/arm/display/komeda/komeda_framebuffer.c
> index 1b01a625f40e..e9c87551a5b8 100644
> --- a/drivers/gpu/drm/arm/display/komeda/komeda_framebuffer.c
> +++ b/drivers/gpu/drm/arm/display/komeda/komeda_framebuffer.c
> @@ -4,6 +4,7 @@
>   * Author: James.Qian.Wang <james.qian.wang@arm.com>
>   *
>   */
> +#include <drm/drm_afbc.h>
>  #include <drm/drm_device.h>
>  #include <drm/drm_fb_cma_helper.h>
>  #include <drm/drm_gem.h>
> @@ -43,8 +44,7 @@ komeda_fb_afbc_size_check(struct komeda_fb *kfb, struct drm_file *file,
>  	struct drm_framebuffer *fb = &kfb->base;
>  	const struct drm_format_info *info = fb->format;
>  	struct drm_gem_object *obj;
> -	u32 alignment_w = 0, alignment_h = 0, alignment_header, n_blocks, bpp;
> -	u64 min_size;
> +	u32 alignment_w = 0, alignment_h = 0, alignment_header, bpp;
>  
>  	obj = drm_gem_object_lookup(file, mode_cmd->handles[0]);
>  	if (!obj) {
> @@ -52,19 +52,15 @@ komeda_fb_afbc_size_check(struct komeda_fb *kfb, struct drm_file *file,
>  		return -ENOENT;
>  	}
>  
> -	switch (fb->modifier & AFBC_FORMAT_MOD_BLOCK_SIZE_MASK) {
> -	case AFBC_FORMAT_MOD_BLOCK_SIZE_32x8:
> -		alignment_w = 32;
> -		alignment_h = 8;
> -		break;
> -	case AFBC_FORMAT_MOD_BLOCK_SIZE_16x16:
> -		alignment_w = 16;
> -		alignment_h = 16;
> -		break;
> -	default:
> -		WARN(1, "Invalid AFBC_FORMAT_MOD_BLOCK_SIZE: %lld.\n",
> -		     fb->modifier & AFBC_FORMAT_MOD_BLOCK_SIZE_MASK);
> -		break;
> +	if (!drm_afbc_get_superblk_wh(fb->modifier, &alignment_w, &alignment_h))
> +		return -EINVAL;
> +
> +	if ((alignment_w != 16 || alignment_h != 16) &&
> +	    (alignment_w != 32 || alignment_h != 8)) {
> +		DRM_DEBUG_KMS("Unsupported afbc tile w/h [%d/%d]\n",
> +			      alignment_w, alignment_h);
> +
> +		return -EINVAL;
To be honest, the previous code looks much more readable
>  	}
>  
>  	/* tiled header afbc */
> @@ -84,20 +80,14 @@ komeda_fb_afbc_size_check(struct komeda_fb *kfb, struct drm_file *file,
>  		goto check_failed;
>  	}
>  
> -	n_blocks = (kfb->aligned_w * kfb->aligned_h) / AFBC_SUPERBLK_PIXELS;
> -	kfb->offset_payload = ALIGN(n_blocks * AFBC_HEADER_SIZE,
> -				    alignment_header);
> -
>  	bpp = komeda_get_afbc_format_bpp(info, fb->modifier);
> -	kfb->afbc_size = kfb->offset_payload + n_blocks *
> -			 ALIGN(bpp * AFBC_SUPERBLK_PIXELS / 8,
> -			       AFBC_SUPERBLK_ALIGNMENT);
> -	min_size = kfb->afbc_size + fb->offsets[0];
> -	if (min_size > obj->size) {
> -		DRM_DEBUG_KMS("afbc size check failed, obj_size: 0x%zx. min_size 0x%llx.\n",
> -			      obj->size, min_size);
We need kfb->offset_payload and kfb->afbc_size to set some registers
in d71_layer_update(). At this moment I feel like punching myself for
making the suggestion to consider abstracting some of the komeda's afbc
checks. To me it does not look like komeda(in the current shape) can take
much advantage of the generic _afbc_fb_check() function (as was suggested
previously by Danvet).

However, I will let james.qian.wang@arm.com,
Mihail.Atanassov@arm.com, Ben.Davis@arm.com comment here to see if
there could be a way of abstracting the afbc bits from komeda.

Thanks anyways for taking a stab at this.
-Ayan
> +
> +	if (!drm_afbc_check_fb_size(mode_cmd->pitches[0], bpp,
> +				    mode_cmd->width, mode_cmd->height,
> +				    alignment_w, alignment_h,
> +				    obj->size, mode_cmd->offsets[0],
> +				    AFBC_SUPERBLK_ALIGNMENT))
>  		goto check_failed;
> -	}
>  
>  	fb->obj[0] = obj;
>  	return 0;
> -- 
> 2.17.1
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 63+ messages in thread

* Re: [PATCHv2 3/4] drm/komeda: use afbc helpers
  2019-11-08 16:09             ` Ayan Halder
  (?)
@ 2019-11-13  2:01             ` james qian wang (Arm Technology China)
  2019-11-13 11:39               ` Daniel Vetter
  -1 siblings, 1 reply; 63+ messages in thread
From: james qian wang (Arm Technology China) @ 2019-11-13  2:01 UTC (permalink / raw)
  To: Ayan Halder
  Cc: nd, kernel, David Airlie, Liviu Dudau, Andrzej Pietrasiewicz,
	linux-rockchip, dri-devel, Mihail Atanassov, Sean Paul

On Fri, Nov 08, 2019 at 04:09:54PM +0000, Ayan Halder wrote:
> On Mon, Nov 04, 2019 at 11:12:27PM +0100, Andrzej Pietrasiewicz wrote:
> > There are afbc helpers available.
> > 
> > Signed-off-by: Andrzej Pietrasiewicz <andrzej.p@collabora.com>
> > ---
> >  .../arm/display/komeda/komeda_format_caps.h   |  1 -
> >  .../arm/display/komeda/komeda_framebuffer.c   | 44 +++++++------------
> >  2 files changed, 17 insertions(+), 28 deletions(-)
> > 
> > diff --git a/drivers/gpu/drm/arm/display/komeda/komeda_format_caps.h b/drivers/gpu/drm/arm/display/komeda/komeda_format_caps.h
> > index 32273cf18f7c..607eea80e60c 100644
> > --- a/drivers/gpu/drm/arm/display/komeda/komeda_format_caps.h
> > +++ b/drivers/gpu/drm/arm/display/komeda/komeda_format_caps.h
> > @@ -33,7 +33,6 @@
> >  
> >  #define AFBC_TH_LAYOUT_ALIGNMENT	8
> >  #define AFBC_HEADER_SIZE		16
> > -#define AFBC_SUPERBLK_ALIGNMENT		128
> >  #define AFBC_SUPERBLK_PIXELS		256
> >  #define AFBC_BODY_START_ALIGNMENT	1024
> >  #define AFBC_TH_BODY_START_ALIGNMENT	4096
> > diff --git a/drivers/gpu/drm/arm/display/komeda/komeda_framebuffer.c b/drivers/gpu/drm/arm/display/komeda/komeda_framebuffer.c
> > index 1b01a625f40e..e9c87551a5b8 100644
> > --- a/drivers/gpu/drm/arm/display/komeda/komeda_framebuffer.c
> > +++ b/drivers/gpu/drm/arm/display/komeda/komeda_framebuffer.c
> > @@ -4,6 +4,7 @@
> >   * Author: James.Qian.Wang <james.qian.wang@arm.com>
> >   *
> >   */
> > +#include <drm/drm_afbc.h>
> >  #include <drm/drm_device.h>
> >  #include <drm/drm_fb_cma_helper.h>
> >  #include <drm/drm_gem.h>
> > @@ -43,8 +44,7 @@ komeda_fb_afbc_size_check(struct komeda_fb *kfb, struct drm_file *file,
> >  	struct drm_framebuffer *fb = &kfb->base;
> >  	const struct drm_format_info *info = fb->format;
> >  	struct drm_gem_object *obj;
> > -	u32 alignment_w = 0, alignment_h = 0, alignment_header, n_blocks, bpp;
> > -	u64 min_size;
> > +	u32 alignment_w = 0, alignment_h = 0, alignment_header, bpp;
> >  
> >  	obj = drm_gem_object_lookup(file, mode_cmd->handles[0]);
> >  	if (!obj) {
> > @@ -52,19 +52,15 @@ komeda_fb_afbc_size_check(struct komeda_fb *kfb, struct drm_file *file,
> >  		return -ENOENT;
> >  	}
> >  
> > -	switch (fb->modifier & AFBC_FORMAT_MOD_BLOCK_SIZE_MASK) {
> > -	case AFBC_FORMAT_MOD_BLOCK_SIZE_32x8:
> > -		alignment_w = 32;
> > -		alignment_h = 8;
> > -		break;
> > -	case AFBC_FORMAT_MOD_BLOCK_SIZE_16x16:
> > -		alignment_w = 16;
> > -		alignment_h = 16;
> > -		break;
> > -	default:
> > -		WARN(1, "Invalid AFBC_FORMAT_MOD_BLOCK_SIZE: %lld.\n",
> > -		     fb->modifier & AFBC_FORMAT_MOD_BLOCK_SIZE_MASK);
> > -		break;
> > +	if (!drm_afbc_get_superblk_wh(fb->modifier, &alignment_w, &alignment_h))
> > +		return -EINVAL;
> > +
> > +	if ((alignment_w != 16 || alignment_h != 16) &&
> > +	    (alignment_w != 32 || alignment_h != 8)) {
> > +		DRM_DEBUG_KMS("Unsupported afbc tile w/h [%d/%d]\n",
> > +			      alignment_w, alignment_h);
> > +
> > +		return -EINVAL;
> To be honest, the previous code looks much more readable
> >  	}
> >  
> >  	/* tiled header afbc */
> > @@ -84,20 +80,14 @@ komeda_fb_afbc_size_check(struct komeda_fb *kfb, struct drm_file *file,
> >  		goto check_failed;
> >  	}
> >  
> > -	n_blocks = (kfb->aligned_w * kfb->aligned_h) / AFBC_SUPERBLK_PIXELS;
> > -	kfb->offset_payload = ALIGN(n_blocks * AFBC_HEADER_SIZE,
> > -				    alignment_header);
> > -
> >  	bpp = komeda_get_afbc_format_bpp(info, fb->modifier);
> > -	kfb->afbc_size = kfb->offset_payload + n_blocks *
> > -			 ALIGN(bpp * AFBC_SUPERBLK_PIXELS / 8,
> > -			       AFBC_SUPERBLK_ALIGNMENT);
> > -	min_size = kfb->afbc_size + fb->offsets[0];
> > -	if (min_size > obj->size) {
> > -		DRM_DEBUG_KMS("afbc size check failed, obj_size: 0x%zx. min_size 0x%llx.\n",
> > -			      obj->size, min_size);
> We need kfb->offset_payload and kfb->afbc_size to set some registers
> in d71_layer_update(). At this moment I feel like punching myself for
> making the suggestion to consider abstracting some of the komeda's afbc
> checks. To me it does not look like komeda(in the current shape) can take
> much advantage of the generic _afbc_fb_check() function (as was suggested
> previously by Danvet).
> 
> However, I will let james.qian.wang@arm.com,
> Mihail.Atanassov@arm.com, Ben.Davis@arm.com comment here to see if
> there could be a way of abstracting the afbc bits from komeda.
>

Hi all:

Since the current generic drm_afbc helpers only support afbc_1.1, but
komeda needs support both afbc1.1/1.2, so I think we can:
- Add afbc1.2 support to drm afbc helpers.
- for the afbc_payload_offset, can we add this member to
  drm_framebuffer ?
- The aligned_w/h are important for afbc, so can we have them in
  drm_framebuffer ?  

Thanks
James

> Thanks anyways for taking a stab at this.
> -Ayan
> > +
> > +	if (!drm_afbc_check_fb_size(mode_cmd->pitches[0], bpp,
> > +				    mode_cmd->width, mode_cmd->height,
> > +				    alignment_w, alignment_h,
> > +				    obj->size, mode_cmd->offsets[0],
> > +				    AFBC_SUPERBLK_ALIGNMENT))
> >  		goto check_failed;
> > -	}
> >  
> >  	fb->obj[0] = obj;
> >  	return 0;
> > -- 
> > 2.17.1
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 63+ messages in thread

* Re: [PATCHv2 3/4] drm/komeda: use afbc helpers
  2019-11-13  2:01             ` james qian wang (Arm Technology China)
@ 2019-11-13 11:39               ` Daniel Vetter
  2019-11-14  1:52                 ` james qian wang (Arm Technology China)
  0 siblings, 1 reply; 63+ messages in thread
From: Daniel Vetter @ 2019-11-13 11:39 UTC (permalink / raw)
  To: james qian wang (Arm Technology China)
  Cc: nd, Mihail Atanassov, kernel, David Airlie, Liviu Dudau,
	Andrzej Pietrasiewicz, linux-rockchip, dri-devel, Ayan Halder,
	Sean Paul

On Wed, Nov 13, 2019 at 02:01:53AM +0000, james qian wang (Arm Technology China) wrote:
> On Fri, Nov 08, 2019 at 04:09:54PM +0000, Ayan Halder wrote:
> > On Mon, Nov 04, 2019 at 11:12:27PM +0100, Andrzej Pietrasiewicz wrote:
> > > There are afbc helpers available.
> > > 
> > > Signed-off-by: Andrzej Pietrasiewicz <andrzej.p@collabora.com>
> > > ---
> > >  .../arm/display/komeda/komeda_format_caps.h   |  1 -
> > >  .../arm/display/komeda/komeda_framebuffer.c   | 44 +++++++------------
> > >  2 files changed, 17 insertions(+), 28 deletions(-)
> > > 
> > > diff --git a/drivers/gpu/drm/arm/display/komeda/komeda_format_caps.h b/drivers/gpu/drm/arm/display/komeda/komeda_format_caps.h
> > > index 32273cf18f7c..607eea80e60c 100644
> > > --- a/drivers/gpu/drm/arm/display/komeda/komeda_format_caps.h
> > > +++ b/drivers/gpu/drm/arm/display/komeda/komeda_format_caps.h
> > > @@ -33,7 +33,6 @@
> > >  
> > >  #define AFBC_TH_LAYOUT_ALIGNMENT	8
> > >  #define AFBC_HEADER_SIZE		16
> > > -#define AFBC_SUPERBLK_ALIGNMENT		128
> > >  #define AFBC_SUPERBLK_PIXELS		256
> > >  #define AFBC_BODY_START_ALIGNMENT	1024
> > >  #define AFBC_TH_BODY_START_ALIGNMENT	4096
> > > diff --git a/drivers/gpu/drm/arm/display/komeda/komeda_framebuffer.c b/drivers/gpu/drm/arm/display/komeda/komeda_framebuffer.c
> > > index 1b01a625f40e..e9c87551a5b8 100644
> > > --- a/drivers/gpu/drm/arm/display/komeda/komeda_framebuffer.c
> > > +++ b/drivers/gpu/drm/arm/display/komeda/komeda_framebuffer.c
> > > @@ -4,6 +4,7 @@
> > >   * Author: James.Qian.Wang <james.qian.wang@arm.com>
> > >   *
> > >   */
> > > +#include <drm/drm_afbc.h>
> > >  #include <drm/drm_device.h>
> > >  #include <drm/drm_fb_cma_helper.h>
> > >  #include <drm/drm_gem.h>
> > > @@ -43,8 +44,7 @@ komeda_fb_afbc_size_check(struct komeda_fb *kfb, struct drm_file *file,
> > >  	struct drm_framebuffer *fb = &kfb->base;
> > >  	const struct drm_format_info *info = fb->format;
> > >  	struct drm_gem_object *obj;
> > > -	u32 alignment_w = 0, alignment_h = 0, alignment_header, n_blocks, bpp;
> > > -	u64 min_size;
> > > +	u32 alignment_w = 0, alignment_h = 0, alignment_header, bpp;
> > >  
> > >  	obj = drm_gem_object_lookup(file, mode_cmd->handles[0]);
> > >  	if (!obj) {
> > > @@ -52,19 +52,15 @@ komeda_fb_afbc_size_check(struct komeda_fb *kfb, struct drm_file *file,
> > >  		return -ENOENT;
> > >  	}
> > >  
> > > -	switch (fb->modifier & AFBC_FORMAT_MOD_BLOCK_SIZE_MASK) {
> > > -	case AFBC_FORMAT_MOD_BLOCK_SIZE_32x8:
> > > -		alignment_w = 32;
> > > -		alignment_h = 8;
> > > -		break;
> > > -	case AFBC_FORMAT_MOD_BLOCK_SIZE_16x16:
> > > -		alignment_w = 16;
> > > -		alignment_h = 16;
> > > -		break;
> > > -	default:
> > > -		WARN(1, "Invalid AFBC_FORMAT_MOD_BLOCK_SIZE: %lld.\n",
> > > -		     fb->modifier & AFBC_FORMAT_MOD_BLOCK_SIZE_MASK);
> > > -		break;
> > > +	if (!drm_afbc_get_superblk_wh(fb->modifier, &alignment_w, &alignment_h))
> > > +		return -EINVAL;
> > > +
> > > +	if ((alignment_w != 16 || alignment_h != 16) &&
> > > +	    (alignment_w != 32 || alignment_h != 8)) {
> > > +		DRM_DEBUG_KMS("Unsupported afbc tile w/h [%d/%d]\n",
> > > +			      alignment_w, alignment_h);
> > > +
> > > +		return -EINVAL;
> > To be honest, the previous code looks much more readable
> > >  	}
> > >  
> > >  	/* tiled header afbc */
> > > @@ -84,20 +80,14 @@ komeda_fb_afbc_size_check(struct komeda_fb *kfb, struct drm_file *file,
> > >  		goto check_failed;
> > >  	}
> > >  
> > > -	n_blocks = (kfb->aligned_w * kfb->aligned_h) / AFBC_SUPERBLK_PIXELS;
> > > -	kfb->offset_payload = ALIGN(n_blocks * AFBC_HEADER_SIZE,
> > > -				    alignment_header);
> > > -
> > >  	bpp = komeda_get_afbc_format_bpp(info, fb->modifier);
> > > -	kfb->afbc_size = kfb->offset_payload + n_blocks *
> > > -			 ALIGN(bpp * AFBC_SUPERBLK_PIXELS / 8,
> > > -			       AFBC_SUPERBLK_ALIGNMENT);
> > > -	min_size = kfb->afbc_size + fb->offsets[0];
> > > -	if (min_size > obj->size) {
> > > -		DRM_DEBUG_KMS("afbc size check failed, obj_size: 0x%zx. min_size 0x%llx.\n",
> > > -			      obj->size, min_size);
> > We need kfb->offset_payload and kfb->afbc_size to set some registers
> > in d71_layer_update(). At this moment I feel like punching myself for
> > making the suggestion to consider abstracting some of the komeda's afbc
> > checks. To me it does not look like komeda(in the current shape) can take
> > much advantage of the generic _afbc_fb_check() function (as was suggested
> > previously by Danvet).
> > 
> > However, I will let james.qian.wang@arm.com,
> > Mihail.Atanassov@arm.com, Ben.Davis@arm.com comment here to see if
> > there could be a way of abstracting the afbc bits from komeda.
> >
> 
> Hi all:
> 
> Since the current generic drm_afbc helpers only support afbc_1.1, but
> komeda needs support both afbc1.1/1.2, so I think we can:
> - Add afbc1.2 support to drm afbc helpers.
> - for the afbc_payload_offset, can we add this member to
>   drm_framebuffer ?
> - The aligned_w/h are important for afbc, so can we have them in
>   drm_framebuffer ?  

How expensive is it to recompute these from a struct drm_framebuffer?

I'd just go with one function which computes all these derived values, and
stuffs them into a struct drm_afbc. Then drivers call that once or so.

For reworking drm_framebuffer itself I think it's probably a bit too
earlier. And if we do it, we should maybe go a bit more bold, aiming to
property-fy all the framebuffer settings, maybe even making it extensible,
and have drivers handle a corresponding drm_framebuffer_state.

A third option would be to create a drm_afbc_framebuffer which embeds
drm_framebuffer and which drivers would need to use. But also feels a bit
like too much churn. Recomputing should be quick enough and much easier.
-Daniel

> 
> Thanks
> James
> 
> > Thanks anyways for taking a stab at this.
> > -Ayan
> > > +
> > > +	if (!drm_afbc_check_fb_size(mode_cmd->pitches[0], bpp,
> > > +				    mode_cmd->width, mode_cmd->height,
> > > +				    alignment_w, alignment_h,
> > > +				    obj->size, mode_cmd->offsets[0],
> > > +				    AFBC_SUPERBLK_ALIGNMENT))
> > >  		goto check_failed;
> > > -	}
> > >  
> > >  	fb->obj[0] = obj;
> > >  	return 0;
> > > -- 
> > > 2.17.1

-- 
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 63+ messages in thread

* Re: [PATCHv2 3/4] drm/komeda: use afbc helpers
  2019-11-13 11:39               ` Daniel Vetter
@ 2019-11-14  1:52                 ` james qian wang (Arm Technology China)
  2019-11-14 10:12                   ` Daniel Vetter
  0 siblings, 1 reply; 63+ messages in thread
From: james qian wang (Arm Technology China) @ 2019-11-14  1:52 UTC (permalink / raw)
  To: Daniel Vetter
  Cc: nd, Mihail Atanassov, kernel, David Airlie, Liviu Dudau,
	Andrzej Pietrasiewicz, linux-rockchip, dri-devel, Ayan Halder,
	Sean Paul

On Wed, Nov 13, 2019 at 12:39:54PM +0100, Daniel Vetter wrote:
> On Wed, Nov 13, 2019 at 02:01:53AM +0000, james qian wang (Arm Technology China) wrote:
> > On Fri, Nov 08, 2019 at 04:09:54PM +0000, Ayan Halder wrote:
> > > On Mon, Nov 04, 2019 at 11:12:27PM +0100, Andrzej Pietrasiewicz wrote:
> > > > There are afbc helpers available.
> > > > 
> > > > Signed-off-by: Andrzej Pietrasiewicz <andrzej.p@collabora.com>
> > > > ---
> > > >  .../arm/display/komeda/komeda_format_caps.h   |  1 -
> > > >  .../arm/display/komeda/komeda_framebuffer.c   | 44 +++++++------------
> > > >  2 files changed, 17 insertions(+), 28 deletions(-)
> > > > 
> > > > diff --git a/drivers/gpu/drm/arm/display/komeda/komeda_format_caps.h b/drivers/gpu/drm/arm/display/komeda/komeda_format_caps.h
> > > > index 32273cf18f7c..607eea80e60c 100644
> > > > --- a/drivers/gpu/drm/arm/display/komeda/komeda_format_caps.h
> > > > +++ b/drivers/gpu/drm/arm/display/komeda/komeda_format_caps.h
> > > > @@ -33,7 +33,6 @@
> > > >  
> > > >  #define AFBC_TH_LAYOUT_ALIGNMENT	8
> > > >  #define AFBC_HEADER_SIZE		16
> > > > -#define AFBC_SUPERBLK_ALIGNMENT		128
> > > >  #define AFBC_SUPERBLK_PIXELS		256
> > > >  #define AFBC_BODY_START_ALIGNMENT	1024
> > > >  #define AFBC_TH_BODY_START_ALIGNMENT	4096
> > > > diff --git a/drivers/gpu/drm/arm/display/komeda/komeda_framebuffer.c b/drivers/gpu/drm/arm/display/komeda/komeda_framebuffer.c
> > > > index 1b01a625f40e..e9c87551a5b8 100644
> > > > --- a/drivers/gpu/drm/arm/display/komeda/komeda_framebuffer.c
> > > > +++ b/drivers/gpu/drm/arm/display/komeda/komeda_framebuffer.c
> > > > @@ -4,6 +4,7 @@
> > > >   * Author: James.Qian.Wang <james.qian.wang@arm.com>
> > > >   *
> > > >   */
> > > > +#include <drm/drm_afbc.h>
> > > >  #include <drm/drm_device.h>
> > > >  #include <drm/drm_fb_cma_helper.h>
> > > >  #include <drm/drm_gem.h>
> > > > @@ -43,8 +44,7 @@ komeda_fb_afbc_size_check(struct komeda_fb *kfb, struct drm_file *file,
> > > >  	struct drm_framebuffer *fb = &kfb->base;
> > > >  	const struct drm_format_info *info = fb->format;
> > > >  	struct drm_gem_object *obj;
> > > > -	u32 alignment_w = 0, alignment_h = 0, alignment_header, n_blocks, bpp;
> > > > -	u64 min_size;
> > > > +	u32 alignment_w = 0, alignment_h = 0, alignment_header, bpp;
> > > >  
> > > >  	obj = drm_gem_object_lookup(file, mode_cmd->handles[0]);
> > > >  	if (!obj) {
> > > > @@ -52,19 +52,15 @@ komeda_fb_afbc_size_check(struct komeda_fb *kfb, struct drm_file *file,
> > > >  		return -ENOENT;
> > > >  	}
> > > >  
> > > > -	switch (fb->modifier & AFBC_FORMAT_MOD_BLOCK_SIZE_MASK) {
> > > > -	case AFBC_FORMAT_MOD_BLOCK_SIZE_32x8:
> > > > -		alignment_w = 32;
> > > > -		alignment_h = 8;
> > > > -		break;
> > > > -	case AFBC_FORMAT_MOD_BLOCK_SIZE_16x16:
> > > > -		alignment_w = 16;
> > > > -		alignment_h = 16;
> > > > -		break;
> > > > -	default:
> > > > -		WARN(1, "Invalid AFBC_FORMAT_MOD_BLOCK_SIZE: %lld.\n",
> > > > -		     fb->modifier & AFBC_FORMAT_MOD_BLOCK_SIZE_MASK);
> > > > -		break;
> > > > +	if (!drm_afbc_get_superblk_wh(fb->modifier, &alignment_w, &alignment_h))
> > > > +		return -EINVAL;
> > > > +
> > > > +	if ((alignment_w != 16 || alignment_h != 16) &&
> > > > +	    (alignment_w != 32 || alignment_h != 8)) {
> > > > +		DRM_DEBUG_KMS("Unsupported afbc tile w/h [%d/%d]\n",
> > > > +			      alignment_w, alignment_h);
> > > > +
> > > > +		return -EINVAL;
> > > To be honest, the previous code looks much more readable
> > > >  	}
> > > >  
> > > >  	/* tiled header afbc */
> > > > @@ -84,20 +80,14 @@ komeda_fb_afbc_size_check(struct komeda_fb *kfb, struct drm_file *file,
> > > >  		goto check_failed;
> > > >  	}
> > > >  
> > > > -	n_blocks = (kfb->aligned_w * kfb->aligned_h) / AFBC_SUPERBLK_PIXELS;
> > > > -	kfb->offset_payload = ALIGN(n_blocks * AFBC_HEADER_SIZE,
> > > > -				    alignment_header);
> > > > -
> > > >  	bpp = komeda_get_afbc_format_bpp(info, fb->modifier);
> > > > -	kfb->afbc_size = kfb->offset_payload + n_blocks *
> > > > -			 ALIGN(bpp * AFBC_SUPERBLK_PIXELS / 8,
> > > > -			       AFBC_SUPERBLK_ALIGNMENT);
> > > > -	min_size = kfb->afbc_size + fb->offsets[0];
> > > > -	if (min_size > obj->size) {
> > > > -		DRM_DEBUG_KMS("afbc size check failed, obj_size: 0x%zx. min_size 0x%llx.\n",
> > > > -			      obj->size, min_size);
> > > We need kfb->offset_payload and kfb->afbc_size to set some registers
> > > in d71_layer_update(). At this moment I feel like punching myself for
> > > making the suggestion to consider abstracting some of the komeda's afbc
> > > checks. To me it does not look like komeda(in the current shape) can take
> > > much advantage of the generic _afbc_fb_check() function (as was suggested
> > > previously by Danvet).
> > > 
> > > However, I will let james.qian.wang@arm.com,
> > > Mihail.Atanassov@arm.com, Ben.Davis@arm.com comment here to see if
> > > there could be a way of abstracting the afbc bits from komeda.
> > >
> > 
> > Hi all:
> > 
> > Since the current generic drm_afbc helpers only support afbc_1.1, but
> > komeda needs support both afbc1.1/1.2, so I think we can:
> > - Add afbc1.2 support to drm afbc helpers.
> > - for the afbc_payload_offset, can we add this member to
> >   drm_framebuffer ?
> > - The aligned_w/h are important for afbc, so can we have them in
> >   drm_framebuffer ?  
> 
> How expensive is it to recompute these from a struct drm_framebuffer?
> 
> I'd just go with one function which computes all these derived values, and
> stuffs them into a struct drm_afbc. Then drivers call that once or so.
>

A struct drm_afbc, good idea, I like it. :-)

and we can compute it when do the afbc size check like 

  drm_afbc_check_fb_size(..., &komeda_fb->drm_afbc);

Thanks.
James

> For reworking drm_framebuffer itself I think it's probably a bit too
> earlier. And if we do it, we should maybe go a bit more bold, aiming to
> property-fy all the framebuffer settings, maybe even making it extensible,
> and have drivers handle a corresponding drm_framebuffer_state.
> 
> A third option would be to create a drm_afbc_framebuffer which embeds
> drm_framebuffer and which drivers would need to use. But also feels a bit
> like too much churn. Recomputing should be quick enough and much easier.
> -Daniel
> 
> > 
> > Thanks
> > James
> > 
> > > Thanks anyways for taking a stab at this.
> > > -Ayan
> > > > +
> > > > +	if (!drm_afbc_check_fb_size(mode_cmd->pitches[0], bpp,
> > > > +				    mode_cmd->width, mode_cmd->height,
> > > > +				    alignment_w, alignment_h,
> > > > +				    obj->size, mode_cmd->offsets[0],
> > > > +				    AFBC_SUPERBLK_ALIGNMENT))
> > > >  		goto check_failed;
> > > > -	}
> > > >  
> > > >  	fb->obj[0] = obj;
> > > >  	return 0;
> > > > -- 
> > > > 2.17.1
> 
> -- 
> Daniel Vetter
> Software Engineer, Intel Corporation
> http://blog.ffwll.ch
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 63+ messages in thread

* Re: [PATCHv2 3/4] drm/komeda: use afbc helpers
  2019-11-14  1:52                 ` james qian wang (Arm Technology China)
@ 2019-11-14 10:12                   ` Daniel Vetter
  2019-11-18  7:09                     ` james qian wang (Arm Technology China)
  0 siblings, 1 reply; 63+ messages in thread
From: Daniel Vetter @ 2019-11-14 10:12 UTC (permalink / raw)
  To: james qian wang (Arm Technology China)
  Cc: nd, Mihail Atanassov, kernel, David Airlie, Liviu Dudau,
	Andrzej Pietrasiewicz, linux-rockchip, dri-devel, Ayan Halder,
	Sean Paul

On Thu, Nov 14, 2019 at 2:52 AM james qian wang (Arm Technology China)
<james.qian.wang@arm.com> wrote:
> On Wed, Nov 13, 2019 at 12:39:54PM +0100, Daniel Vetter wrote:
> > On Wed, Nov 13, 2019 at 02:01:53AM +0000, james qian wang (Arm Technology China) wrote:
> > > On Fri, Nov 08, 2019 at 04:09:54PM +0000, Ayan Halder wrote:
> > > > On Mon, Nov 04, 2019 at 11:12:27PM +0100, Andrzej Pietrasiewicz wrote:
> > > > > There are afbc helpers available.
> > > > >
> > > > > Signed-off-by: Andrzej Pietrasiewicz <andrzej.p@collabora.com>
> > > > > ---
> > > > >  .../arm/display/komeda/komeda_format_caps.h   |  1 -
> > > > >  .../arm/display/komeda/komeda_framebuffer.c   | 44 +++++++------------
> > > > >  2 files changed, 17 insertions(+), 28 deletions(-)
> > > > >
> > > > > diff --git a/drivers/gpu/drm/arm/display/komeda/komeda_format_caps.h b/drivers/gpu/drm/arm/display/komeda/komeda_format_caps.h
> > > > > index 32273cf18f7c..607eea80e60c 100644
> > > > > --- a/drivers/gpu/drm/arm/display/komeda/komeda_format_caps.h
> > > > > +++ b/drivers/gpu/drm/arm/display/komeda/komeda_format_caps.h
> > > > > @@ -33,7 +33,6 @@
> > > > >
> > > > >  #define AFBC_TH_LAYOUT_ALIGNMENT       8
> > > > >  #define AFBC_HEADER_SIZE               16
> > > > > -#define AFBC_SUPERBLK_ALIGNMENT                128
> > > > >  #define AFBC_SUPERBLK_PIXELS           256
> > > > >  #define AFBC_BODY_START_ALIGNMENT      1024
> > > > >  #define AFBC_TH_BODY_START_ALIGNMENT   4096
> > > > > diff --git a/drivers/gpu/drm/arm/display/komeda/komeda_framebuffer.c b/drivers/gpu/drm/arm/display/komeda/komeda_framebuffer.c
> > > > > index 1b01a625f40e..e9c87551a5b8 100644
> > > > > --- a/drivers/gpu/drm/arm/display/komeda/komeda_framebuffer.c
> > > > > +++ b/drivers/gpu/drm/arm/display/komeda/komeda_framebuffer.c
> > > > > @@ -4,6 +4,7 @@
> > > > >   * Author: James.Qian.Wang <james.qian.wang@arm.com>
> > > > >   *
> > > > >   */
> > > > > +#include <drm/drm_afbc.h>
> > > > >  #include <drm/drm_device.h>
> > > > >  #include <drm/drm_fb_cma_helper.h>
> > > > >  #include <drm/drm_gem.h>
> > > > > @@ -43,8 +44,7 @@ komeda_fb_afbc_size_check(struct komeda_fb *kfb, struct drm_file *file,
> > > > >         struct drm_framebuffer *fb = &kfb->base;
> > > > >         const struct drm_format_info *info = fb->format;
> > > > >         struct drm_gem_object *obj;
> > > > > -       u32 alignment_w = 0, alignment_h = 0, alignment_header, n_blocks, bpp;
> > > > > -       u64 min_size;
> > > > > +       u32 alignment_w = 0, alignment_h = 0, alignment_header, bpp;
> > > > >
> > > > >         obj = drm_gem_object_lookup(file, mode_cmd->handles[0]);
> > > > >         if (!obj) {
> > > > > @@ -52,19 +52,15 @@ komeda_fb_afbc_size_check(struct komeda_fb *kfb, struct drm_file *file,
> > > > >                 return -ENOENT;
> > > > >         }
> > > > >
> > > > > -       switch (fb->modifier & AFBC_FORMAT_MOD_BLOCK_SIZE_MASK) {
> > > > > -       case AFBC_FORMAT_MOD_BLOCK_SIZE_32x8:
> > > > > -               alignment_w = 32;
> > > > > -               alignment_h = 8;
> > > > > -               break;
> > > > > -       case AFBC_FORMAT_MOD_BLOCK_SIZE_16x16:
> > > > > -               alignment_w = 16;
> > > > > -               alignment_h = 16;
> > > > > -               break;
> > > > > -       default:
> > > > > -               WARN(1, "Invalid AFBC_FORMAT_MOD_BLOCK_SIZE: %lld.\n",
> > > > > -                    fb->modifier & AFBC_FORMAT_MOD_BLOCK_SIZE_MASK);
> > > > > -               break;
> > > > > +       if (!drm_afbc_get_superblk_wh(fb->modifier, &alignment_w, &alignment_h))
> > > > > +               return -EINVAL;
> > > > > +
> > > > > +       if ((alignment_w != 16 || alignment_h != 16) &&
> > > > > +           (alignment_w != 32 || alignment_h != 8)) {
> > > > > +               DRM_DEBUG_KMS("Unsupported afbc tile w/h [%d/%d]\n",
> > > > > +                             alignment_w, alignment_h);
> > > > > +
> > > > > +               return -EINVAL;
> > > > To be honest, the previous code looks much more readable
> > > > >         }
> > > > >
> > > > >         /* tiled header afbc */
> > > > > @@ -84,20 +80,14 @@ komeda_fb_afbc_size_check(struct komeda_fb *kfb, struct drm_file *file,
> > > > >                 goto check_failed;
> > > > >         }
> > > > >
> > > > > -       n_blocks = (kfb->aligned_w * kfb->aligned_h) / AFBC_SUPERBLK_PIXELS;
> > > > > -       kfb->offset_payload = ALIGN(n_blocks * AFBC_HEADER_SIZE,
> > > > > -                                   alignment_header);
> > > > > -
> > > > >         bpp = komeda_get_afbc_format_bpp(info, fb->modifier);
> > > > > -       kfb->afbc_size = kfb->offset_payload + n_blocks *
> > > > > -                        ALIGN(bpp * AFBC_SUPERBLK_PIXELS / 8,
> > > > > -                              AFBC_SUPERBLK_ALIGNMENT);
> > > > > -       min_size = kfb->afbc_size + fb->offsets[0];
> > > > > -       if (min_size > obj->size) {
> > > > > -               DRM_DEBUG_KMS("afbc size check failed, obj_size: 0x%zx. min_size 0x%llx.\n",
> > > > > -                             obj->size, min_size);
> > > > We need kfb->offset_payload and kfb->afbc_size to set some registers
> > > > in d71_layer_update(). At this moment I feel like punching myself for
> > > > making the suggestion to consider abstracting some of the komeda's afbc
> > > > checks. To me it does not look like komeda(in the current shape) can take
> > > > much advantage of the generic _afbc_fb_check() function (as was suggested
> > > > previously by Danvet).
> > > >
> > > > However, I will let james.qian.wang@arm.com,
> > > > Mihail.Atanassov@arm.com, Ben.Davis@arm.com comment here to see if
> > > > there could be a way of abstracting the afbc bits from komeda.
> > > >
> > >
> > > Hi all:
> > >
> > > Since the current generic drm_afbc helpers only support afbc_1.1, but
> > > komeda needs support both afbc1.1/1.2, so I think we can:
> > > - Add afbc1.2 support to drm afbc helpers.
> > > - for the afbc_payload_offset, can we add this member to
> > >   drm_framebuffer ?
> > > - The aligned_w/h are important for afbc, so can we have them in
> > >   drm_framebuffer ?
> >
> > How expensive is it to recompute these from a struct drm_framebuffer?
> >
> > I'd just go with one function which computes all these derived values, and
> > stuffs them into a struct drm_afbc. Then drivers call that once or so.
> >
>
> A struct drm_afbc, good idea, I like it. :-)
>
> and we can compute it when do the afbc size check like
>
>   drm_afbc_check_fb_size(..., &komeda_fb->drm_afbc);

Discussed this also with Andrzej on irc on where exactly to place
stuff. I think ideally we'd be able to get rid of the custom
malidp_fb_create completely, and komeda should also be able to get rid
of most of the open-coded checks (it's largely reinveting
drm_gem_fb_create_with_funcs, imo better to just call that first, then
then do a few more calls of the specific things you need to have
computed in addition).
-Daniel

>
> Thanks.
> James
>
> > For reworking drm_framebuffer itself I think it's probably a bit too
> > earlier. And if we do it, we should maybe go a bit more bold, aiming to
> > property-fy all the framebuffer settings, maybe even making it extensible,
> > and have drivers handle a corresponding drm_framebuffer_state.
> >
> > A third option would be to create a drm_afbc_framebuffer which embeds
> > drm_framebuffer and which drivers would need to use. But also feels a bit
> > like too much churn. Recomputing should be quick enough and much easier.
> > -Daniel
> >
> > >
> > > Thanks
> > > James
> > >
> > > > Thanks anyways for taking a stab at this.
> > > > -Ayan
> > > > > +
> > > > > +       if (!drm_afbc_check_fb_size(mode_cmd->pitches[0], bpp,
> > > > > +                                   mode_cmd->width, mode_cmd->height,
> > > > > +                                   alignment_w, alignment_h,
> > > > > +                                   obj->size, mode_cmd->offsets[0],
> > > > > +                                   AFBC_SUPERBLK_ALIGNMENT))
> > > > >                 goto check_failed;
> > > > > -       }
> > > > >
> > > > >         fb->obj[0] = obj;
> > > > >         return 0;
> > > > > --
> > > > > 2.17.1
> >
> > --
> > Daniel Vetter
> > Software Engineer, Intel Corporation
> > http://blog.ffwll.ch



-- 
Daniel Vetter
Software Engineer, Intel Corporation
+41 (0) 79 365 57 48 - http://blog.ffwll.ch
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 63+ messages in thread

* Re: [PATCHv2 3/4] drm/komeda: use afbc helpers
  2019-11-14 10:12                   ` Daniel Vetter
@ 2019-11-18  7:09                     ` james qian wang (Arm Technology China)
  2019-11-18  9:51                       ` Daniel Vetter
  0 siblings, 1 reply; 63+ messages in thread
From: james qian wang (Arm Technology China) @ 2019-11-18  7:09 UTC (permalink / raw)
  To: Daniel Vetter
  Cc: nd, Mihail Atanassov, kernel, David Airlie, Liviu Dudau,
	Andrzej Pietrasiewicz, linux-rockchip, dri-devel, Ayan Halder,
	Sean Paul

On Thu, Nov 14, 2019 at 11:12:13AM +0100, Daniel Vetter wrote:
> On Thu, Nov 14, 2019 at 2:52 AM james qian wang (Arm Technology China)
> <james.qian.wang@arm.com> wrote:
> > On Wed, Nov 13, 2019 at 12:39:54PM +0100, Daniel Vetter wrote:
> > > On Wed, Nov 13, 2019 at 02:01:53AM +0000, james qian wang (Arm Technology China) wrote:
> > > > On Fri, Nov 08, 2019 at 04:09:54PM +0000, Ayan Halder wrote:
> > > > > On Mon, Nov 04, 2019 at 11:12:27PM +0100, Andrzej Pietrasiewicz wrote:
> > > > > > There are afbc helpers available.
> > > > > >
> > > > > > Signed-off-by: Andrzej Pietrasiewicz <andrzej.p@collabora.com>
> > > > > > ---
> > > > > >  .../arm/display/komeda/komeda_format_caps.h   |  1 -
> > > > > >  .../arm/display/komeda/komeda_framebuffer.c   | 44 +++++++------------
> > > > > >  2 files changed, 17 insertions(+), 28 deletions(-)
> > > > > >
> > > > > > diff --git a/drivers/gpu/drm/arm/display/komeda/komeda_format_caps.h b/drivers/gpu/drm/arm/display/komeda/komeda_format_caps.h
> > > > > > index 32273cf18f7c..607eea80e60c 100644
> > > > > > --- a/drivers/gpu/drm/arm/display/komeda/komeda_format_caps.h
> > > > > > +++ b/drivers/gpu/drm/arm/display/komeda/komeda_format_caps.h
> > > > > > @@ -33,7 +33,6 @@
> > > > > >
> > > > > >  #define AFBC_TH_LAYOUT_ALIGNMENT       8
> > > > > >  #define AFBC_HEADER_SIZE               16
> > > > > > -#define AFBC_SUPERBLK_ALIGNMENT                128
> > > > > >  #define AFBC_SUPERBLK_PIXELS           256
> > > > > >  #define AFBC_BODY_START_ALIGNMENT      1024
> > > > > >  #define AFBC_TH_BODY_START_ALIGNMENT   4096
> > > > > > diff --git a/drivers/gpu/drm/arm/display/komeda/komeda_framebuffer.c b/drivers/gpu/drm/arm/display/komeda/komeda_framebuffer.c
> > > > > > index 1b01a625f40e..e9c87551a5b8 100644
> > > > > > --- a/drivers/gpu/drm/arm/display/komeda/komeda_framebuffer.c
> > > > > > +++ b/drivers/gpu/drm/arm/display/komeda/komeda_framebuffer.c
> > > > > > @@ -4,6 +4,7 @@
> > > > > >   * Author: James.Qian.Wang <james.qian.wang@arm.com>
> > > > > >   *
> > > > > >   */
> > > > > > +#include <drm/drm_afbc.h>
> > > > > >  #include <drm/drm_device.h>
> > > > > >  #include <drm/drm_fb_cma_helper.h>
> > > > > >  #include <drm/drm_gem.h>
> > > > > > @@ -43,8 +44,7 @@ komeda_fb_afbc_size_check(struct komeda_fb *kfb, struct drm_file *file,
> > > > > >         struct drm_framebuffer *fb = &kfb->base;
> > > > > >         const struct drm_format_info *info = fb->format;
> > > > > >         struct drm_gem_object *obj;
> > > > > > -       u32 alignment_w = 0, alignment_h = 0, alignment_header, n_blocks, bpp;
> > > > > > -       u64 min_size;
> > > > > > +       u32 alignment_w = 0, alignment_h = 0, alignment_header, bpp;
> > > > > >
> > > > > >         obj = drm_gem_object_lookup(file, mode_cmd->handles[0]);
> > > > > >         if (!obj) {
> > > > > > @@ -52,19 +52,15 @@ komeda_fb_afbc_size_check(struct komeda_fb *kfb, struct drm_file *file,
> > > > > >                 return -ENOENT;
> > > > > >         }
> > > > > >
> > > > > > -       switch (fb->modifier & AFBC_FORMAT_MOD_BLOCK_SIZE_MASK) {
> > > > > > -       case AFBC_FORMAT_MOD_BLOCK_SIZE_32x8:
> > > > > > -               alignment_w = 32;
> > > > > > -               alignment_h = 8;
> > > > > > -               break;
> > > > > > -       case AFBC_FORMAT_MOD_BLOCK_SIZE_16x16:
> > > > > > -               alignment_w = 16;
> > > > > > -               alignment_h = 16;
> > > > > > -               break;
> > > > > > -       default:
> > > > > > -               WARN(1, "Invalid AFBC_FORMAT_MOD_BLOCK_SIZE: %lld.\n",
> > > > > > -                    fb->modifier & AFBC_FORMAT_MOD_BLOCK_SIZE_MASK);
> > > > > > -               break;
> > > > > > +       if (!drm_afbc_get_superblk_wh(fb->modifier, &alignment_w, &alignment_h))
> > > > > > +               return -EINVAL;
> > > > > > +
> > > > > > +       if ((alignment_w != 16 || alignment_h != 16) &&
> > > > > > +           (alignment_w != 32 || alignment_h != 8)) {
> > > > > > +               DRM_DEBUG_KMS("Unsupported afbc tile w/h [%d/%d]\n",
> > > > > > +                             alignment_w, alignment_h);
> > > > > > +
> > > > > > +               return -EINVAL;
> > > > > To be honest, the previous code looks much more readable
> > > > > >         }
> > > > > >
> > > > > >         /* tiled header afbc */
> > > > > > @@ -84,20 +80,14 @@ komeda_fb_afbc_size_check(struct komeda_fb *kfb, struct drm_file *file,
> > > > > >                 goto check_failed;
> > > > > >         }
> > > > > >
> > > > > > -       n_blocks = (kfb->aligned_w * kfb->aligned_h) / AFBC_SUPERBLK_PIXELS;
> > > > > > -       kfb->offset_payload = ALIGN(n_blocks * AFBC_HEADER_SIZE,
> > > > > > -                                   alignment_header);
> > > > > > -
> > > > > >         bpp = komeda_get_afbc_format_bpp(info, fb->modifier);
> > > > > > -       kfb->afbc_size = kfb->offset_payload + n_blocks *
> > > > > > -                        ALIGN(bpp * AFBC_SUPERBLK_PIXELS / 8,
> > > > > > -                              AFBC_SUPERBLK_ALIGNMENT);
> > > > > > -       min_size = kfb->afbc_size + fb->offsets[0];
> > > > > > -       if (min_size > obj->size) {
> > > > > > -               DRM_DEBUG_KMS("afbc size check failed, obj_size: 0x%zx. min_size 0x%llx.\n",
> > > > > > -                             obj->size, min_size);
> > > > > We need kfb->offset_payload and kfb->afbc_size to set some registers
> > > > > in d71_layer_update(). At this moment I feel like punching myself for
> > > > > making the suggestion to consider abstracting some of the komeda's afbc
> > > > > checks. To me it does not look like komeda(in the current shape) can take
> > > > > much advantage of the generic _afbc_fb_check() function (as was suggested
> > > > > previously by Danvet).
> > > > >
> > > > > However, I will let james.qian.wang@arm.com,
> > > > > Mihail.Atanassov@arm.com, Ben.Davis@arm.com comment here to see if
> > > > > there could be a way of abstracting the afbc bits from komeda.
> > > > >
> > > >
> > > > Hi all:
> > > >
> > > > Since the current generic drm_afbc helpers only support afbc_1.1, but
> > > > komeda needs support both afbc1.1/1.2, so I think we can:
> > > > - Add afbc1.2 support to drm afbc helpers.
> > > > - for the afbc_payload_offset, can we add this member to
> > > >   drm_framebuffer ?
> > > > - The aligned_w/h are important for afbc, so can we have them in
> > > >   drm_framebuffer ?
> > >
> > > How expensive is it to recompute these from a struct drm_framebuffer?
> > >
> > > I'd just go with one function which computes all these derived values, and
> > > stuffs them into a struct drm_afbc. Then drivers call that once or so.
> > >
> >
> > A struct drm_afbc, good idea, I like it. :-)
> >
> > and we can compute it when do the afbc size check like
> >
> >   drm_afbc_check_fb_size(..., &komeda_fb->drm_afbc);
> 
> Discussed this also with Andrzej on irc on where exactly to place
> stuff. I think ideally we'd be able to get rid of the custom
> malidp_fb_create completely, and komeda should also be able to get rid
> of most of the open-coded checks (it's largely reinveting
> drm_gem_fb_create_with_funcs, imo better to just call that first, then
> then do a few more calls of the specific things you need to have
> computed in addition).
> -Daniel

The afbc support is the only reason why malidp/komeda define our own
fb_create(), it is good for komeda and malidp if we put afbc support
directly into the standard drm_gem_fb_create_with_funcs.

BTW:

can we add one more argument: fb_struct_size to

  drm_gem_fb_create_with_funcs(..., size_t fb_struct_size);

then driver can use it to extend its own fb struct and add some private
infos.

Thanks
James
> >
> > Thanks.
> > James
> >
> > > For reworking drm_framebuffer itself I think it's probably a bit too
> > > earlier. And if we do it, we should maybe go a bit more bold, aiming to
> > > property-fy all the framebuffer settings, maybe even making it extensible,
> > > and have drivers handle a corresponding drm_framebuffer_state.
> > >
> > > A third option would be to create a drm_afbc_framebuffer which embeds
> > > drm_framebuffer and which drivers would need to use. But also feels a bit
> > > like too much churn. Recomputing should be quick enough and much easier.
> > > -Daniel
> > >
> > > >
> > > > Thanks
> > > > James
> > > >
> > > > > Thanks anyways for taking a stab at this.
> > > > > -Ayan
> > > > > > +
> > > > > > +       if (!drm_afbc_check_fb_size(mode_cmd->pitches[0], bpp,
> > > > > > +                                   mode_cmd->width, mode_cmd->height,
> > > > > > +                                   alignment_w, alignment_h,
> > > > > > +                                   obj->size, mode_cmd->offsets[0],
> > > > > > +                                   AFBC_SUPERBLK_ALIGNMENT))
> > > > > >                 goto check_failed;
> > > > > > -       }
> > > > > >
> > > > > >         fb->obj[0] = obj;
> > > > > >         return 0;
> > > > > > --
> > > > > > 2.17.1
> > >
> > > --
> > > Daniel Vetter
> > > Software Engineer, Intel Corporation
> > > http://blog.ffwll.ch
> 
> 
> 
> -- 
> Daniel Vetter
> Software Engineer, Intel Corporation
> +41 (0) 79 365 57 48 - http://blog.ffwll.ch
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 63+ messages in thread

* Re: [PATCHv2 3/4] drm/komeda: use afbc helpers
  2019-11-18  7:09                     ` james qian wang (Arm Technology China)
@ 2019-11-18  9:51                       ` Daniel Vetter
       [not found]                         ` <20191118095136.GC23790-dv86pmgwkMBes7Z6vYuT8azUEOm+Xw19@public.gmane.org>
  0 siblings, 1 reply; 63+ messages in thread
From: Daniel Vetter @ 2019-11-18  9:51 UTC (permalink / raw)
  To: james qian wang (Arm Technology China)
  Cc: nd, Mihail Atanassov, kernel, David Airlie, Liviu Dudau,
	Andrzej Pietrasiewicz, linux-rockchip, dri-devel, Ayan Halder,
	Sean Paul

On Mon, Nov 18, 2019 at 07:09:56AM +0000, james qian wang (Arm Technology China) wrote:
> On Thu, Nov 14, 2019 at 11:12:13AM +0100, Daniel Vetter wrote:
> > On Thu, Nov 14, 2019 at 2:52 AM james qian wang (Arm Technology China)
> > <james.qian.wang@arm.com> wrote:
> > > On Wed, Nov 13, 2019 at 12:39:54PM +0100, Daniel Vetter wrote:
> > > > On Wed, Nov 13, 2019 at 02:01:53AM +0000, james qian wang (Arm Technology China) wrote:
> > > > > On Fri, Nov 08, 2019 at 04:09:54PM +0000, Ayan Halder wrote:
> > > > > > On Mon, Nov 04, 2019 at 11:12:27PM +0100, Andrzej Pietrasiewicz wrote:
> > > > > > > There are afbc helpers available.
> > > > > > >
> > > > > > > Signed-off-by: Andrzej Pietrasiewicz <andrzej.p@collabora.com>
> > > > > > > ---
> > > > > > >  .../arm/display/komeda/komeda_format_caps.h   |  1 -
> > > > > > >  .../arm/display/komeda/komeda_framebuffer.c   | 44 +++++++------------
> > > > > > >  2 files changed, 17 insertions(+), 28 deletions(-)
> > > > > > >
> > > > > > > diff --git a/drivers/gpu/drm/arm/display/komeda/komeda_format_caps.h b/drivers/gpu/drm/arm/display/komeda/komeda_format_caps.h
> > > > > > > index 32273cf18f7c..607eea80e60c 100644
> > > > > > > --- a/drivers/gpu/drm/arm/display/komeda/komeda_format_caps.h
> > > > > > > +++ b/drivers/gpu/drm/arm/display/komeda/komeda_format_caps.h
> > > > > > > @@ -33,7 +33,6 @@
> > > > > > >
> > > > > > >  #define AFBC_TH_LAYOUT_ALIGNMENT       8
> > > > > > >  #define AFBC_HEADER_SIZE               16
> > > > > > > -#define AFBC_SUPERBLK_ALIGNMENT                128
> > > > > > >  #define AFBC_SUPERBLK_PIXELS           256
> > > > > > >  #define AFBC_BODY_START_ALIGNMENT      1024
> > > > > > >  #define AFBC_TH_BODY_START_ALIGNMENT   4096
> > > > > > > diff --git a/drivers/gpu/drm/arm/display/komeda/komeda_framebuffer.c b/drivers/gpu/drm/arm/display/komeda/komeda_framebuffer.c
> > > > > > > index 1b01a625f40e..e9c87551a5b8 100644
> > > > > > > --- a/drivers/gpu/drm/arm/display/komeda/komeda_framebuffer.c
> > > > > > > +++ b/drivers/gpu/drm/arm/display/komeda/komeda_framebuffer.c
> > > > > > > @@ -4,6 +4,7 @@
> > > > > > >   * Author: James.Qian.Wang <james.qian.wang@arm.com>
> > > > > > >   *
> > > > > > >   */
> > > > > > > +#include <drm/drm_afbc.h>
> > > > > > >  #include <drm/drm_device.h>
> > > > > > >  #include <drm/drm_fb_cma_helper.h>
> > > > > > >  #include <drm/drm_gem.h>
> > > > > > > @@ -43,8 +44,7 @@ komeda_fb_afbc_size_check(struct komeda_fb *kfb, struct drm_file *file,
> > > > > > >         struct drm_framebuffer *fb = &kfb->base;
> > > > > > >         const struct drm_format_info *info = fb->format;
> > > > > > >         struct drm_gem_object *obj;
> > > > > > > -       u32 alignment_w = 0, alignment_h = 0, alignment_header, n_blocks, bpp;
> > > > > > > -       u64 min_size;
> > > > > > > +       u32 alignment_w = 0, alignment_h = 0, alignment_header, bpp;
> > > > > > >
> > > > > > >         obj = drm_gem_object_lookup(file, mode_cmd->handles[0]);
> > > > > > >         if (!obj) {
> > > > > > > @@ -52,19 +52,15 @@ komeda_fb_afbc_size_check(struct komeda_fb *kfb, struct drm_file *file,
> > > > > > >                 return -ENOENT;
> > > > > > >         }
> > > > > > >
> > > > > > > -       switch (fb->modifier & AFBC_FORMAT_MOD_BLOCK_SIZE_MASK) {
> > > > > > > -       case AFBC_FORMAT_MOD_BLOCK_SIZE_32x8:
> > > > > > > -               alignment_w = 32;
> > > > > > > -               alignment_h = 8;
> > > > > > > -               break;
> > > > > > > -       case AFBC_FORMAT_MOD_BLOCK_SIZE_16x16:
> > > > > > > -               alignment_w = 16;
> > > > > > > -               alignment_h = 16;
> > > > > > > -               break;
> > > > > > > -       default:
> > > > > > > -               WARN(1, "Invalid AFBC_FORMAT_MOD_BLOCK_SIZE: %lld.\n",
> > > > > > > -                    fb->modifier & AFBC_FORMAT_MOD_BLOCK_SIZE_MASK);
> > > > > > > -               break;
> > > > > > > +       if (!drm_afbc_get_superblk_wh(fb->modifier, &alignment_w, &alignment_h))
> > > > > > > +               return -EINVAL;
> > > > > > > +
> > > > > > > +       if ((alignment_w != 16 || alignment_h != 16) &&
> > > > > > > +           (alignment_w != 32 || alignment_h != 8)) {
> > > > > > > +               DRM_DEBUG_KMS("Unsupported afbc tile w/h [%d/%d]\n",
> > > > > > > +                             alignment_w, alignment_h);
> > > > > > > +
> > > > > > > +               return -EINVAL;
> > > > > > To be honest, the previous code looks much more readable
> > > > > > >         }
> > > > > > >
> > > > > > >         /* tiled header afbc */
> > > > > > > @@ -84,20 +80,14 @@ komeda_fb_afbc_size_check(struct komeda_fb *kfb, struct drm_file *file,
> > > > > > >                 goto check_failed;
> > > > > > >         }
> > > > > > >
> > > > > > > -       n_blocks = (kfb->aligned_w * kfb->aligned_h) / AFBC_SUPERBLK_PIXELS;
> > > > > > > -       kfb->offset_payload = ALIGN(n_blocks * AFBC_HEADER_SIZE,
> > > > > > > -                                   alignment_header);
> > > > > > > -
> > > > > > >         bpp = komeda_get_afbc_format_bpp(info, fb->modifier);
> > > > > > > -       kfb->afbc_size = kfb->offset_payload + n_blocks *
> > > > > > > -                        ALIGN(bpp * AFBC_SUPERBLK_PIXELS / 8,
> > > > > > > -                              AFBC_SUPERBLK_ALIGNMENT);
> > > > > > > -       min_size = kfb->afbc_size + fb->offsets[0];
> > > > > > > -       if (min_size > obj->size) {
> > > > > > > -               DRM_DEBUG_KMS("afbc size check failed, obj_size: 0x%zx. min_size 0x%llx.\n",
> > > > > > > -                             obj->size, min_size);
> > > > > > We need kfb->offset_payload and kfb->afbc_size to set some registers
> > > > > > in d71_layer_update(). At this moment I feel like punching myself for
> > > > > > making the suggestion to consider abstracting some of the komeda's afbc
> > > > > > checks. To me it does not look like komeda(in the current shape) can take
> > > > > > much advantage of the generic _afbc_fb_check() function (as was suggested
> > > > > > previously by Danvet).
> > > > > >
> > > > > > However, I will let james.qian.wang@arm.com,
> > > > > > Mihail.Atanassov@arm.com, Ben.Davis@arm.com comment here to see if
> > > > > > there could be a way of abstracting the afbc bits from komeda.
> > > > > >
> > > > >
> > > > > Hi all:
> > > > >
> > > > > Since the current generic drm_afbc helpers only support afbc_1.1, but
> > > > > komeda needs support both afbc1.1/1.2, so I think we can:
> > > > > - Add afbc1.2 support to drm afbc helpers.
> > > > > - for the afbc_payload_offset, can we add this member to
> > > > >   drm_framebuffer ?
> > > > > - The aligned_w/h are important for afbc, so can we have them in
> > > > >   drm_framebuffer ?
> > > >
> > > > How expensive is it to recompute these from a struct drm_framebuffer?
> > > >
> > > > I'd just go with one function which computes all these derived values, and
> > > > stuffs them into a struct drm_afbc. Then drivers call that once or so.
> > > >
> > >
> > > A struct drm_afbc, good idea, I like it. :-)
> > >
> > > and we can compute it when do the afbc size check like
> > >
> > >   drm_afbc_check_fb_size(..., &komeda_fb->drm_afbc);
> > 
> > Discussed this also with Andrzej on irc on where exactly to place
> > stuff. I think ideally we'd be able to get rid of the custom
> > malidp_fb_create completely, and komeda should also be able to get rid
> > of most of the open-coded checks (it's largely reinveting
> > drm_gem_fb_create_with_funcs, imo better to just call that first, then
> > then do a few more calls of the specific things you need to have
> > computed in addition).
> > -Daniel
> 
> The afbc support is the only reason why malidp/komeda define our own
> fb_create(), it is good for komeda and malidp if we put afbc support
> directly into the standard drm_gem_fb_create_with_funcs.
> 
> BTW:
> 
> can we add one more argument: fb_struct_size to
> 
>   drm_gem_fb_create_with_funcs(..., size_t fb_struct_size);
> 
> then driver can use it to extend its own fb struct and add some private
> infos.

Hm, this isn't how we usually do it for subclassing - the trouble with
this is that the size of the allocation is very far away from where we
actually allocate, automated checkers have a harder time with this
pattern.

Usually what we do is split the kzalloc out from the _create function,
leaving just _init behind. Then you have roughly (pseudo-code):

	drm_gem_fb_create_with_funcs(args) {
		struct drm_gem_fb *fb;

		fb = kzalloc(sizeof(*fb));
		if (!fb)
			return -ENOMEM;

		return drm_gem_fb_init_with_functions(fb, args);
	}

If you then need a bigger function, you just allocate that bigger
function, and pass &fb->base to the _init function. Costs 3 additional
lines (for the kzalloc and error checking), but easier to read&verify for
both humans and compilers.

I guess what we could then do is create a drm_gem_afbc_create function
which sets this all up for a

struct drm_gem_afbc_framebuffer {
	struct drm_gem_framebuffer base;
	/* afbc stuff */
};

and then also fills out all derived afbc values, so more than just
calling drm_gem_fb_init_with_functions. And drivers could still have their
own version with even more checks on top.

And all afbc supporting drivers could then use that. Feels a bit like
overengineering to me, but if you feel like that's justified to do it's a
good solution.

Cheers, Daniel
> 
> Thanks
> James
> > >
> > > Thanks.
> > > James
> > >
> > > > For reworking drm_framebuffer itself I think it's probably a bit too
> > > > earlier. And if we do it, we should maybe go a bit more bold, aiming to
> > > > property-fy all the framebuffer settings, maybe even making it extensible,
> > > > and have drivers handle a corresponding drm_framebuffer_state.
> > > >
> > > > A third option would be to create a drm_afbc_framebuffer which embeds
> > > > drm_framebuffer and which drivers would need to use. But also feels a bit
> > > > like too much churn. Recomputing should be quick enough and much easier.
> > > > -Daniel
> > > >
> > > > >
> > > > > Thanks
> > > > > James
> > > > >
> > > > > > Thanks anyways for taking a stab at this.
> > > > > > -Ayan
> > > > > > > +
> > > > > > > +       if (!drm_afbc_check_fb_size(mode_cmd->pitches[0], bpp,
> > > > > > > +                                   mode_cmd->width, mode_cmd->height,
> > > > > > > +                                   alignment_w, alignment_h,
> > > > > > > +                                   obj->size, mode_cmd->offsets[0],
> > > > > > > +                                   AFBC_SUPERBLK_ALIGNMENT))
> > > > > > >                 goto check_failed;
> > > > > > > -       }
> > > > > > >
> > > > > > >         fb->obj[0] = obj;
> > > > > > >         return 0;
> > > > > > > --
> > > > > > > 2.17.1
> > > >
> > > > --
> > > > Daniel Vetter
> > > > Software Engineer, Intel Corporation
> > > > http://blog.ffwll.ch
> > 
> > 
> > 
> > -- 
> > Daniel Vetter
> > Software Engineer, Intel Corporation
> > +41 (0) 79 365 57 48 - http://blog.ffwll.ch

-- 
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 63+ messages in thread

* Re: [PATCHv2 3/4] drm/komeda: use afbc helpers
@ 2019-11-19  8:34                             ` james qian wang (Arm Technology China)
  0 siblings, 0 replies; 63+ messages in thread
From: james qian wang (Arm Technology China) @ 2019-11-19  8:34 UTC (permalink / raw)
  To: Daniel Vetter
  Cc: nd, Mihail Atanassov, kernel-ZGY8ohtN/8qB+jHODAdFcQ,
	Heiko Stübner, David Airlie, Liviu Dudau, Maarten Lankhorst,
	Sandy Huang, Maxime Ripard, Andrzej Pietrasiewicz,
	linux-rockchip-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	dri-devel-PD4FTy7X32lNgt0PjOBp9y5qC8QIuHrW, Ayan Halder,
	Sean Paul, Brian Starkey

On Mon, Nov 18, 2019 at 10:51:36AM +0100, Daniel Vetter wrote:
> On Mon, Nov 18, 2019 at 07:09:56AM +0000, james qian wang (Arm Technology China) wrote:
> > On Thu, Nov 14, 2019 at 11:12:13AM +0100, Daniel Vetter wrote:
> > > On Thu, Nov 14, 2019 at 2:52 AM james qian wang (Arm Technology China)
> > > <james.qian.wang-5wv7dgnIgG8@public.gmane.org> wrote:
> > > > On Wed, Nov 13, 2019 at 12:39:54PM +0100, Daniel Vetter wrote:
> > > > > On Wed, Nov 13, 2019 at 02:01:53AM +0000, james qian wang (Arm Technology China) wrote:
> > > > > > On Fri, Nov 08, 2019 at 04:09:54PM +0000, Ayan Halder wrote:
> > > > > > > On Mon, Nov 04, 2019 at 11:12:27PM +0100, Andrzej Pietrasiewicz wrote:
> > > > > > > > There are afbc helpers available.
> > > > > > > >
> > > > > > > > Signed-off-by: Andrzej Pietrasiewicz <andrzej.p-ZGY8ohtN/8qB+jHODAdFcQ@public.gmane.org>
> > > > > > > > ---
> > > > > > > >  .../arm/display/komeda/komeda_format_caps.h   |  1 -
> > > > > > > >  .../arm/display/komeda/komeda_framebuffer.c   | 44 +++++++------------
> > > > > > > >  2 files changed, 17 insertions(+), 28 deletions(-)
> > > > > > > >
> > > > > > > > diff --git a/drivers/gpu/drm/arm/display/komeda/komeda_format_caps.h b/drivers/gpu/drm/arm/display/komeda/komeda_format_caps.h
> > > > > > > > index 32273cf18f7c..607eea80e60c 100644
> > > > > > > > --- a/drivers/gpu/drm/arm/display/komeda/komeda_format_caps.h
> > > > > > > > +++ b/drivers/gpu/drm/arm/display/komeda/komeda_format_caps.h
> > > > > > > > @@ -33,7 +33,6 @@
> > > > > > > >
> > > > > > > >  #define AFBC_TH_LAYOUT_ALIGNMENT       8
> > > > > > > >  #define AFBC_HEADER_SIZE               16
> > > > > > > > -#define AFBC_SUPERBLK_ALIGNMENT                128
> > > > > > > >  #define AFBC_SUPERBLK_PIXELS           256
> > > > > > > >  #define AFBC_BODY_START_ALIGNMENT      1024
> > > > > > > >  #define AFBC_TH_BODY_START_ALIGNMENT   4096
> > > > > > > > diff --git a/drivers/gpu/drm/arm/display/komeda/komeda_framebuffer.c b/drivers/gpu/drm/arm/display/komeda/komeda_framebuffer.c
> > > > > > > > index 1b01a625f40e..e9c87551a5b8 100644
> > > > > > > > --- a/drivers/gpu/drm/arm/display/komeda/komeda_framebuffer.c
> > > > > > > > +++ b/drivers/gpu/drm/arm/display/komeda/komeda_framebuffer.c
> > > > > > > > @@ -4,6 +4,7 @@
> > > > > > > >   * Author: James.Qian.Wang <james.qian.wang-5wv7dgnIgG8@public.gmane.org>
> > > > > > > >   *
> > > > > > > >   */
> > > > > > > > +#include <drm/drm_afbc.h>
> > > > > > > >  #include <drm/drm_device.h>
> > > > > > > >  #include <drm/drm_fb_cma_helper.h>
> > > > > > > >  #include <drm/drm_gem.h>
> > > > > > > > @@ -43,8 +44,7 @@ komeda_fb_afbc_size_check(struct komeda_fb *kfb, struct drm_file *file,
> > > > > > > >         struct drm_framebuffer *fb = &kfb->base;
> > > > > > > >         const struct drm_format_info *info = fb->format;
> > > > > > > >         struct drm_gem_object *obj;
> > > > > > > > -       u32 alignment_w = 0, alignment_h = 0, alignment_header, n_blocks, bpp;
> > > > > > > > -       u64 min_size;
> > > > > > > > +       u32 alignment_w = 0, alignment_h = 0, alignment_header, bpp;
> > > > > > > >
> > > > > > > >         obj = drm_gem_object_lookup(file, mode_cmd->handles[0]);
> > > > > > > >         if (!obj) {
> > > > > > > > @@ -52,19 +52,15 @@ komeda_fb_afbc_size_check(struct komeda_fb *kfb, struct drm_file *file,
> > > > > > > >                 return -ENOENT;
> > > > > > > >         }
> > > > > > > >
> > > > > > > > -       switch (fb->modifier & AFBC_FORMAT_MOD_BLOCK_SIZE_MASK) {
> > > > > > > > -       case AFBC_FORMAT_MOD_BLOCK_SIZE_32x8:
> > > > > > > > -               alignment_w = 32;
> > > > > > > > -               alignment_h = 8;
> > > > > > > > -               break;
> > > > > > > > -       case AFBC_FORMAT_MOD_BLOCK_SIZE_16x16:
> > > > > > > > -               alignment_w = 16;
> > > > > > > > -               alignment_h = 16;
> > > > > > > > -               break;
> > > > > > > > -       default:
> > > > > > > > -               WARN(1, "Invalid AFBC_FORMAT_MOD_BLOCK_SIZE: %lld.\n",
> > > > > > > > -                    fb->modifier & AFBC_FORMAT_MOD_BLOCK_SIZE_MASK);
> > > > > > > > -               break;
> > > > > > > > +       if (!drm_afbc_get_superblk_wh(fb->modifier, &alignment_w, &alignment_h))
> > > > > > > > +               return -EINVAL;
> > > > > > > > +
> > > > > > > > +       if ((alignment_w != 16 || alignment_h != 16) &&
> > > > > > > > +           (alignment_w != 32 || alignment_h != 8)) {
> > > > > > > > +               DRM_DEBUG_KMS("Unsupported afbc tile w/h [%d/%d]\n",
> > > > > > > > +                             alignment_w, alignment_h);
> > > > > > > > +
> > > > > > > > +               return -EINVAL;
> > > > > > > To be honest, the previous code looks much more readable
> > > > > > > >         }
> > > > > > > >
> > > > > > > >         /* tiled header afbc */
> > > > > > > > @@ -84,20 +80,14 @@ komeda_fb_afbc_size_check(struct komeda_fb *kfb, struct drm_file *file,
> > > > > > > >                 goto check_failed;
> > > > > > > >         }
> > > > > > > >
> > > > > > > > -       n_blocks = (kfb->aligned_w * kfb->aligned_h) / AFBC_SUPERBLK_PIXELS;
> > > > > > > > -       kfb->offset_payload = ALIGN(n_blocks * AFBC_HEADER_SIZE,
> > > > > > > > -                                   alignment_header);
> > > > > > > > -
> > > > > > > >         bpp = komeda_get_afbc_format_bpp(info, fb->modifier);
> > > > > > > > -       kfb->afbc_size = kfb->offset_payload + n_blocks *
> > > > > > > > -                        ALIGN(bpp * AFBC_SUPERBLK_PIXELS / 8,
> > > > > > > > -                              AFBC_SUPERBLK_ALIGNMENT);
> > > > > > > > -       min_size = kfb->afbc_size + fb->offsets[0];
> > > > > > > > -       if (min_size > obj->size) {
> > > > > > > > -               DRM_DEBUG_KMS("afbc size check failed, obj_size: 0x%zx. min_size 0x%llx.\n",
> > > > > > > > -                             obj->size, min_size);
> > > > > > > We need kfb->offset_payload and kfb->afbc_size to set some registers
> > > > > > > in d71_layer_update(). At this moment I feel like punching myself for
> > > > > > > making the suggestion to consider abstracting some of the komeda's afbc
> > > > > > > checks. To me it does not look like komeda(in the current shape) can take
> > > > > > > much advantage of the generic _afbc_fb_check() function (as was suggested
> > > > > > > previously by Danvet).
> > > > > > >
> > > > > > > However, I will let james.qian.wang-5wv7dgnIgG8@public.gmane.org,
> > > > > > > Mihail.Atanassov-5wv7dgnIgG8@public.gmane.org, Ben.Davis-5wv7dgnIgG8@public.gmane.org comment here to see if
> > > > > > > there could be a way of abstracting the afbc bits from komeda.
> > > > > > >
> > > > > >
> > > > > > Hi all:
> > > > > >
> > > > > > Since the current generic drm_afbc helpers only support afbc_1.1, but
> > > > > > komeda needs support both afbc1.1/1.2, so I think we can:
> > > > > > - Add afbc1.2 support to drm afbc helpers.
> > > > > > - for the afbc_payload_offset, can we add this member to
> > > > > >   drm_framebuffer ?
> > > > > > - The aligned_w/h are important for afbc, so can we have them in
> > > > > >   drm_framebuffer ?
> > > > >
> > > > > How expensive is it to recompute these from a struct drm_framebuffer?
> > > > >
> > > > > I'd just go with one function which computes all these derived values, and
> > > > > stuffs them into a struct drm_afbc. Then drivers call that once or so.
> > > > >
> > > >
> > > > A struct drm_afbc, good idea, I like it. :-)
> > > >
> > > > and we can compute it when do the afbc size check like
> > > >
> > > >   drm_afbc_check_fb_size(..., &komeda_fb->drm_afbc);
> > > 
> > > Discussed this also with Andrzej on irc on where exactly to place
> > > stuff. I think ideally we'd be able to get rid of the custom
> > > malidp_fb_create completely, and komeda should also be able to get rid
> > > of most of the open-coded checks (it's largely reinveting
> > > drm_gem_fb_create_with_funcs, imo better to just call that first, then
> > > then do a few more calls of the specific things you need to have
> > > computed in addition).
> > > -Daniel
> > 
> > The afbc support is the only reason why malidp/komeda define our own
> > fb_create(), it is good for komeda and malidp if we put afbc support
> > directly into the standard drm_gem_fb_create_with_funcs.
> > 
> > BTW:
> > 
> > can we add one more argument: fb_struct_size to
> > 
> >   drm_gem_fb_create_with_funcs(..., size_t fb_struct_size);
> > 
> > then driver can use it to extend its own fb struct and add some private
> > infos.
> 
> Hm, this isn't how we usually do it for subclassing - the trouble with
> this is that the size of the allocation is very far away from where we
> actually allocate, automated checkers have a harder time with this
> pattern.
> 
> Usually what we do is split the kzalloc out from the _create function,
> leaving just _init behind. Then you have roughly (pseudo-code):
> 
> 	drm_gem_fb_create_with_funcs(args) {
> 		struct drm_gem_fb *fb;
> 
> 		fb = kzalloc(sizeof(*fb));
> 		if (!fb)
> 			return -ENOMEM;
> 
> 		return drm_gem_fb_init_with_functions(fb, args);
> 	}
> 
> If you then need a bigger function, you just allocate that bigger
> function, and pass &fb->base to the _init function. Costs 3 additional
> lines (for the kzalloc and error checking), but easier to read&verify for
> both humans and compilers.
> 
> I guess what we could then do is create a drm_gem_afbc_create function
> which sets this all up for a
> 
> struct drm_gem_afbc_framebuffer {
> 	struct drm_gem_framebuffer base;
> 	/* afbc stuff */
> };
> 
> and then also fills out all derived afbc values, so more than just
> calling drm_gem_fb_init_with_functions. And drivers could still have their
> own version with even more checks on top.
> 
> And all afbc supporting drivers could then use that. Feels a bit like
> overengineering to me, but if you feel like that's justified to do it's a
> good solution.

Hi Daniel:

This solution looks good, it can fit all our requirement.

Thanks
James.

> Cheers, Daniel
> > 
> > Thanks
> > James
> > > >
> > > > Thanks.
> > > > James
> > > >
> > > > > For reworking drm_framebuffer itself I think it's probably a bit too
> > > > > earlier. And if we do it, we should maybe go a bit more bold, aiming to
> > > > > property-fy all the framebuffer settings, maybe even making it extensible,
> > > > > and have drivers handle a corresponding drm_framebuffer_state.
> > > > >
> > > > > A third option would be to create a drm_afbc_framebuffer which embeds
> > > > > drm_framebuffer and which drivers would need to use. But also feels a bit
> > > > > like too much churn. Recomputing should be quick enough and much easier.
> > > > > -Daniel
> > > > >
> > > > > >
> > > > > > Thanks
> > > > > > James
> > > > > >
> > > > > > > Thanks anyways for taking a stab at this.
> > > > > > > -Ayan
> > > > > > > > +
> > > > > > > > +       if (!drm_afbc_check_fb_size(mode_cmd->pitches[0], bpp,
> > > > > > > > +                                   mode_cmd->width, mode_cmd->height,
> > > > > > > > +                                   alignment_w, alignment_h,
> > > > > > > > +                                   obj->size, mode_cmd->offsets[0],
> > > > > > > > +                                   AFBC_SUPERBLK_ALIGNMENT))
> > > > > > > >                 goto check_failed;
> > > > > > > > -       }
> > > > > > > >
> > > > > > > >         fb->obj[0] = obj;
> > > > > > > >         return 0;
> > > > > > > > --
> > > > > > > > 2.17.1
> > > > >
> > > > > --
> > > > > Daniel Vetter
> > > > > Software Engineer, Intel Corporation
> > > > > http://blog.ffwll.ch
> > > 
> > > 
> > > 
> > > -- 
> > > Daniel Vetter
> > > Software Engineer, Intel Corporation
> > > +41 (0) 79 365 57 48 - http://blog.ffwll.ch
> 
> -- 
> Daniel Vetter
> Software Engineer, Intel Corporation
> http://blog.ffwll.ch

^ permalink raw reply	[flat|nested] 63+ messages in thread

* Re: [PATCHv2 3/4] drm/komeda: use afbc helpers
@ 2019-11-19  8:34                             ` james qian wang (Arm Technology China)
  0 siblings, 0 replies; 63+ messages in thread
From: james qian wang (Arm Technology China) @ 2019-11-19  8:34 UTC (permalink / raw)
  To: Daniel Vetter
  Cc: nd, Mihail Atanassov, kernel, David Airlie, Liviu Dudau,
	Andrzej Pietrasiewicz, linux-rockchip, dri-devel, Ayan Halder,
	Sean Paul

On Mon, Nov 18, 2019 at 10:51:36AM +0100, Daniel Vetter wrote:
> On Mon, Nov 18, 2019 at 07:09:56AM +0000, james qian wang (Arm Technology China) wrote:
> > On Thu, Nov 14, 2019 at 11:12:13AM +0100, Daniel Vetter wrote:
> > > On Thu, Nov 14, 2019 at 2:52 AM james qian wang (Arm Technology China)
> > > <james.qian.wang@arm.com> wrote:
> > > > On Wed, Nov 13, 2019 at 12:39:54PM +0100, Daniel Vetter wrote:
> > > > > On Wed, Nov 13, 2019 at 02:01:53AM +0000, james qian wang (Arm Technology China) wrote:
> > > > > > On Fri, Nov 08, 2019 at 04:09:54PM +0000, Ayan Halder wrote:
> > > > > > > On Mon, Nov 04, 2019 at 11:12:27PM +0100, Andrzej Pietrasiewicz wrote:
> > > > > > > > There are afbc helpers available.
> > > > > > > >
> > > > > > > > Signed-off-by: Andrzej Pietrasiewicz <andrzej.p@collabora.com>
> > > > > > > > ---
> > > > > > > >  .../arm/display/komeda/komeda_format_caps.h   |  1 -
> > > > > > > >  .../arm/display/komeda/komeda_framebuffer.c   | 44 +++++++------------
> > > > > > > >  2 files changed, 17 insertions(+), 28 deletions(-)
> > > > > > > >
> > > > > > > > diff --git a/drivers/gpu/drm/arm/display/komeda/komeda_format_caps.h b/drivers/gpu/drm/arm/display/komeda/komeda_format_caps.h
> > > > > > > > index 32273cf18f7c..607eea80e60c 100644
> > > > > > > > --- a/drivers/gpu/drm/arm/display/komeda/komeda_format_caps.h
> > > > > > > > +++ b/drivers/gpu/drm/arm/display/komeda/komeda_format_caps.h
> > > > > > > > @@ -33,7 +33,6 @@
> > > > > > > >
> > > > > > > >  #define AFBC_TH_LAYOUT_ALIGNMENT       8
> > > > > > > >  #define AFBC_HEADER_SIZE               16
> > > > > > > > -#define AFBC_SUPERBLK_ALIGNMENT                128
> > > > > > > >  #define AFBC_SUPERBLK_PIXELS           256
> > > > > > > >  #define AFBC_BODY_START_ALIGNMENT      1024
> > > > > > > >  #define AFBC_TH_BODY_START_ALIGNMENT   4096
> > > > > > > > diff --git a/drivers/gpu/drm/arm/display/komeda/komeda_framebuffer.c b/drivers/gpu/drm/arm/display/komeda/komeda_framebuffer.c
> > > > > > > > index 1b01a625f40e..e9c87551a5b8 100644
> > > > > > > > --- a/drivers/gpu/drm/arm/display/komeda/komeda_framebuffer.c
> > > > > > > > +++ b/drivers/gpu/drm/arm/display/komeda/komeda_framebuffer.c
> > > > > > > > @@ -4,6 +4,7 @@
> > > > > > > >   * Author: James.Qian.Wang <james.qian.wang@arm.com>
> > > > > > > >   *
> > > > > > > >   */
> > > > > > > > +#include <drm/drm_afbc.h>
> > > > > > > >  #include <drm/drm_device.h>
> > > > > > > >  #include <drm/drm_fb_cma_helper.h>
> > > > > > > >  #include <drm/drm_gem.h>
> > > > > > > > @@ -43,8 +44,7 @@ komeda_fb_afbc_size_check(struct komeda_fb *kfb, struct drm_file *file,
> > > > > > > >         struct drm_framebuffer *fb = &kfb->base;
> > > > > > > >         const struct drm_format_info *info = fb->format;
> > > > > > > >         struct drm_gem_object *obj;
> > > > > > > > -       u32 alignment_w = 0, alignment_h = 0, alignment_header, n_blocks, bpp;
> > > > > > > > -       u64 min_size;
> > > > > > > > +       u32 alignment_w = 0, alignment_h = 0, alignment_header, bpp;
> > > > > > > >
> > > > > > > >         obj = drm_gem_object_lookup(file, mode_cmd->handles[0]);
> > > > > > > >         if (!obj) {
> > > > > > > > @@ -52,19 +52,15 @@ komeda_fb_afbc_size_check(struct komeda_fb *kfb, struct drm_file *file,
> > > > > > > >                 return -ENOENT;
> > > > > > > >         }
> > > > > > > >
> > > > > > > > -       switch (fb->modifier & AFBC_FORMAT_MOD_BLOCK_SIZE_MASK) {
> > > > > > > > -       case AFBC_FORMAT_MOD_BLOCK_SIZE_32x8:
> > > > > > > > -               alignment_w = 32;
> > > > > > > > -               alignment_h = 8;
> > > > > > > > -               break;
> > > > > > > > -       case AFBC_FORMAT_MOD_BLOCK_SIZE_16x16:
> > > > > > > > -               alignment_w = 16;
> > > > > > > > -               alignment_h = 16;
> > > > > > > > -               break;
> > > > > > > > -       default:
> > > > > > > > -               WARN(1, "Invalid AFBC_FORMAT_MOD_BLOCK_SIZE: %lld.\n",
> > > > > > > > -                    fb->modifier & AFBC_FORMAT_MOD_BLOCK_SIZE_MASK);
> > > > > > > > -               break;
> > > > > > > > +       if (!drm_afbc_get_superblk_wh(fb->modifier, &alignment_w, &alignment_h))
> > > > > > > > +               return -EINVAL;
> > > > > > > > +
> > > > > > > > +       if ((alignment_w != 16 || alignment_h != 16) &&
> > > > > > > > +           (alignment_w != 32 || alignment_h != 8)) {
> > > > > > > > +               DRM_DEBUG_KMS("Unsupported afbc tile w/h [%d/%d]\n",
> > > > > > > > +                             alignment_w, alignment_h);
> > > > > > > > +
> > > > > > > > +               return -EINVAL;
> > > > > > > To be honest, the previous code looks much more readable
> > > > > > > >         }
> > > > > > > >
> > > > > > > >         /* tiled header afbc */
> > > > > > > > @@ -84,20 +80,14 @@ komeda_fb_afbc_size_check(struct komeda_fb *kfb, struct drm_file *file,
> > > > > > > >                 goto check_failed;
> > > > > > > >         }
> > > > > > > >
> > > > > > > > -       n_blocks = (kfb->aligned_w * kfb->aligned_h) / AFBC_SUPERBLK_PIXELS;
> > > > > > > > -       kfb->offset_payload = ALIGN(n_blocks * AFBC_HEADER_SIZE,
> > > > > > > > -                                   alignment_header);
> > > > > > > > -
> > > > > > > >         bpp = komeda_get_afbc_format_bpp(info, fb->modifier);
> > > > > > > > -       kfb->afbc_size = kfb->offset_payload + n_blocks *
> > > > > > > > -                        ALIGN(bpp * AFBC_SUPERBLK_PIXELS / 8,
> > > > > > > > -                              AFBC_SUPERBLK_ALIGNMENT);
> > > > > > > > -       min_size = kfb->afbc_size + fb->offsets[0];
> > > > > > > > -       if (min_size > obj->size) {
> > > > > > > > -               DRM_DEBUG_KMS("afbc size check failed, obj_size: 0x%zx. min_size 0x%llx.\n",
> > > > > > > > -                             obj->size, min_size);
> > > > > > > We need kfb->offset_payload and kfb->afbc_size to set some registers
> > > > > > > in d71_layer_update(). At this moment I feel like punching myself for
> > > > > > > making the suggestion to consider abstracting some of the komeda's afbc
> > > > > > > checks. To me it does not look like komeda(in the current shape) can take
> > > > > > > much advantage of the generic _afbc_fb_check() function (as was suggested
> > > > > > > previously by Danvet).
> > > > > > >
> > > > > > > However, I will let james.qian.wang@arm.com,
> > > > > > > Mihail.Atanassov@arm.com, Ben.Davis@arm.com comment here to see if
> > > > > > > there could be a way of abstracting the afbc bits from komeda.
> > > > > > >
> > > > > >
> > > > > > Hi all:
> > > > > >
> > > > > > Since the current generic drm_afbc helpers only support afbc_1.1, but
> > > > > > komeda needs support both afbc1.1/1.2, so I think we can:
> > > > > > - Add afbc1.2 support to drm afbc helpers.
> > > > > > - for the afbc_payload_offset, can we add this member to
> > > > > >   drm_framebuffer ?
> > > > > > - The aligned_w/h are important for afbc, so can we have them in
> > > > > >   drm_framebuffer ?
> > > > >
> > > > > How expensive is it to recompute these from a struct drm_framebuffer?
> > > > >
> > > > > I'd just go with one function which computes all these derived values, and
> > > > > stuffs them into a struct drm_afbc. Then drivers call that once or so.
> > > > >
> > > >
> > > > A struct drm_afbc, good idea, I like it. :-)
> > > >
> > > > and we can compute it when do the afbc size check like
> > > >
> > > >   drm_afbc_check_fb_size(..., &komeda_fb->drm_afbc);
> > > 
> > > Discussed this also with Andrzej on irc on where exactly to place
> > > stuff. I think ideally we'd be able to get rid of the custom
> > > malidp_fb_create completely, and komeda should also be able to get rid
> > > of most of the open-coded checks (it's largely reinveting
> > > drm_gem_fb_create_with_funcs, imo better to just call that first, then
> > > then do a few more calls of the specific things you need to have
> > > computed in addition).
> > > -Daniel
> > 
> > The afbc support is the only reason why malidp/komeda define our own
> > fb_create(), it is good for komeda and malidp if we put afbc support
> > directly into the standard drm_gem_fb_create_with_funcs.
> > 
> > BTW:
> > 
> > can we add one more argument: fb_struct_size to
> > 
> >   drm_gem_fb_create_with_funcs(..., size_t fb_struct_size);
> > 
> > then driver can use it to extend its own fb struct and add some private
> > infos.
> 
> Hm, this isn't how we usually do it for subclassing - the trouble with
> this is that the size of the allocation is very far away from where we
> actually allocate, automated checkers have a harder time with this
> pattern.
> 
> Usually what we do is split the kzalloc out from the _create function,
> leaving just _init behind. Then you have roughly (pseudo-code):
> 
> 	drm_gem_fb_create_with_funcs(args) {
> 		struct drm_gem_fb *fb;
> 
> 		fb = kzalloc(sizeof(*fb));
> 		if (!fb)
> 			return -ENOMEM;
> 
> 		return drm_gem_fb_init_with_functions(fb, args);
> 	}
> 
> If you then need a bigger function, you just allocate that bigger
> function, and pass &fb->base to the _init function. Costs 3 additional
> lines (for the kzalloc and error checking), but easier to read&verify for
> both humans and compilers.
> 
> I guess what we could then do is create a drm_gem_afbc_create function
> which sets this all up for a
> 
> struct drm_gem_afbc_framebuffer {
> 	struct drm_gem_framebuffer base;
> 	/* afbc stuff */
> };
> 
> and then also fills out all derived afbc values, so more than just
> calling drm_gem_fb_init_with_functions. And drivers could still have their
> own version with even more checks on top.
> 
> And all afbc supporting drivers could then use that. Feels a bit like
> overengineering to me, but if you feel like that's justified to do it's a
> good solution.

Hi Daniel:

This solution looks good, it can fit all our requirement.

Thanks
James.

> Cheers, Daniel
> > 
> > Thanks
> > James
> > > >
> > > > Thanks.
> > > > James
> > > >
> > > > > For reworking drm_framebuffer itself I think it's probably a bit too
> > > > > earlier. And if we do it, we should maybe go a bit more bold, aiming to
> > > > > property-fy all the framebuffer settings, maybe even making it extensible,
> > > > > and have drivers handle a corresponding drm_framebuffer_state.
> > > > >
> > > > > A third option would be to create a drm_afbc_framebuffer which embeds
> > > > > drm_framebuffer and which drivers would need to use. But also feels a bit
> > > > > like too much churn. Recomputing should be quick enough and much easier.
> > > > > -Daniel
> > > > >
> > > > > >
> > > > > > Thanks
> > > > > > James
> > > > > >
> > > > > > > Thanks anyways for taking a stab at this.
> > > > > > > -Ayan
> > > > > > > > +
> > > > > > > > +       if (!drm_afbc_check_fb_size(mode_cmd->pitches[0], bpp,
> > > > > > > > +                                   mode_cmd->width, mode_cmd->height,
> > > > > > > > +                                   alignment_w, alignment_h,
> > > > > > > > +                                   obj->size, mode_cmd->offsets[0],
> > > > > > > > +                                   AFBC_SUPERBLK_ALIGNMENT))
> > > > > > > >                 goto check_failed;
> > > > > > > > -       }
> > > > > > > >
> > > > > > > >         fb->obj[0] = obj;
> > > > > > > >         return 0;
> > > > > > > > --
> > > > > > > > 2.17.1
> > > > >
> > > > > --
> > > > > Daniel Vetter
> > > > > Software Engineer, Intel Corporation
> > > > > http://blog.ffwll.ch
> > > 
> > > 
> > > 
> > > -- 
> > > Daniel Vetter
> > > Software Engineer, Intel Corporation
> > > +41 (0) 79 365 57 48 - http://blog.ffwll.ch
> 
> -- 
> Daniel Vetter
> Software Engineer, Intel Corporation
> http://blog.ffwll.ch
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 63+ messages in thread

* [PATCHv3/RFC 0/4] AFBC rework and support for Rockchip
  2019-11-19  8:34                             ` james qian wang (Arm Technology China)
  (?)
@ 2019-11-21 17:22                             ` Andrzej Pietrasiewicz
  2019-11-21 17:22                               ` [PATCHv3/RFC 1/4] drm/arm: Factor out generic afbc helpers Andrzej Pietrasiewicz
                                                 ` (3 more replies)
  -1 siblings, 4 replies; 63+ messages in thread
From: Andrzej Pietrasiewicz @ 2019-11-21 17:22 UTC (permalink / raw)
  To: dri-devel
  Cc: Ayan Halder, kernel, David Airlie, Liviu Dudau, James Wang,
	Mihail Atanassov, Sean Paul

v2..v3:

- addressed (some) comments from Daniel Stone, Liviu Dudau, Daniel Vetter
and Brian Starkey - thank you all

In this iteration some rework has been done. The checking logic is now moved
to framebuffer_check() so it is common to all drivers. But the common part
is not good for komeda, so this series is not good for merging yet.
I kindly ask for feedback whether the changes are in the right direction.
I also kindly ask for input on how to accommodate komeda.

The CONFIG_DRM_AFBC option has been eliminated in favour of adding
drm_afbc.c to drm_kms_helper.

v1..v2:

This series adds AFBC support for Rockchip. It is inspired by:

https://chromium.googlesource.com/chromiumos/third_party/kernel/+/refs/heads/factory-gru-9017.B-chromeos-4.4/drivers/gpu/drm/rockchip/rockchip_drm_vop.c

- addressed comments from Daniel Stone, Ayan Halder, Mihail Atanassov
- coding style fixes

Andrzej Pietrasiewicz (4):
  drm/arm: Factor out generic afbc helpers
  drm/malidp: use afbc helpers
  drm/komeda: Use afbc helper
  drm/rockchip: Add support for afbc

 drivers/gpu/drm/Makefile                      |   2 +-
 .../arm/display/komeda/komeda_framebuffer.c   |  17 +--
 drivers/gpu/drm/arm/malidp_drv.c              | 121 +++------------
 drivers/gpu/drm/drm_afbc.c                    |  84 +++++++++++
 drivers/gpu/drm/drm_fourcc.c                  |  11 +-
 drivers/gpu/drm/drm_framebuffer.c             |  71 ++++++++-
 drivers/gpu/drm/rockchip/rockchip_drm_fb.c    |  29 ++++
 drivers/gpu/drm/rockchip/rockchip_drm_vop.c   | 142 +++++++++++++++++-
 drivers/gpu/drm/rockchip/rockchip_drm_vop.h   |  12 ++
 drivers/gpu/drm/rockchip/rockchip_vop_reg.c   |  84 ++++++++++-
 include/drm/drm_afbc.h                        |  35 +++++
 11 files changed, 485 insertions(+), 123 deletions(-)
 create mode 100644 drivers/gpu/drm/drm_afbc.c
 create mode 100644 include/drm/drm_afbc.h

-- 
2.17.1

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

^ permalink raw reply	[flat|nested] 63+ messages in thread

* [PATCHv3/RFC 1/4] drm/arm: Factor out generic afbc helpers
  2019-11-21 17:22                             ` [PATCHv3/RFC 0/4] AFBC rework and support for Rockchip Andrzej Pietrasiewicz
@ 2019-11-21 17:22                               ` Andrzej Pietrasiewicz
  2019-11-23  7:13                                   ` Ezequiel Garcia
                                                   ` (2 more replies)
  2019-11-21 17:22                               ` [PATCHv3/RFC 2/4] drm/malidp: use " Andrzej Pietrasiewicz
                                                 ` (2 subsequent siblings)
  3 siblings, 3 replies; 63+ messages in thread
From: Andrzej Pietrasiewicz @ 2019-11-21 17:22 UTC (permalink / raw)
  To: dri-devel
  Cc: Ayan Halder, kernel, David Airlie, Liviu Dudau, James Wang,
	Mihail Atanassov, Sean Paul

These are useful for other users of afbc, e.g. rockchip.

Signed-off-by: Andrzej Pietrasiewicz <andrzej.p@collabora.com>
---
 drivers/gpu/drm/Makefile          |  2 +-
 drivers/gpu/drm/drm_afbc.c        | 84 +++++++++++++++++++++++++++++++
 drivers/gpu/drm/drm_fourcc.c      | 11 +++-
 drivers/gpu/drm/drm_framebuffer.c | 71 +++++++++++++++++++++++++-
 include/drm/drm_afbc.h            | 35 +++++++++++++
 5 files changed, 199 insertions(+), 4 deletions(-)
 create mode 100644 drivers/gpu/drm/drm_afbc.c
 create mode 100644 include/drm/drm_afbc.h

diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile
index d9bcc9f2a0a4..3a58f30b83a6 100644
--- a/drivers/gpu/drm/Makefile
+++ b/drivers/gpu/drm/Makefile
@@ -44,7 +44,7 @@ drm_kms_helper-y := drm_crtc_helper.o drm_dp_helper.o drm_dsc.o drm_probe_helper
 		drm_simple_kms_helper.o drm_modeset_helper.o \
 		drm_scdc_helper.o drm_gem_framebuffer_helper.o \
 		drm_atomic_state_helper.o drm_damage_helper.o \
-		drm_format_helper.o drm_self_refresh_helper.o
+		drm_format_helper.o drm_self_refresh_helper.o drm_afbc.o
 
 drm_kms_helper-$(CONFIG_DRM_PANEL_BRIDGE) += bridge/panel.o
 drm_kms_helper-$(CONFIG_DRM_FBDEV_EMULATION) += drm_fb_helper.o
diff --git a/drivers/gpu/drm/drm_afbc.c b/drivers/gpu/drm/drm_afbc.c
new file mode 100644
index 000000000000..f308c4719546
--- /dev/null
+++ b/drivers/gpu/drm/drm_afbc.c
@@ -0,0 +1,84 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * (C) 2019 Collabora Ltd.
+ *
+ * author: Andrzej Pietrasiewicz <andrzej.p@collabora.com>
+ *
+ */
+#include <linux/module.h>
+
+#include <drm/drm_afbc.h>
+#include <drm/drm_device.h>
+#include <drm/drm_fourcc.h>
+#include <drm/drm_gem.h>
+#include <drm/drm_mode.h>
+#include <drm/drm_print.h>
+
+/**
+ * drm_afbc_get_superblk_wh - extract afbc block width/height from modifier
+ * @modifier: the modifier to be looked at
+ * @w: address of a place to store the block width
+ * @h: address of a place to store the block height
+ *
+ * Returns: true if the modifier describes a supported block size
+ */
+bool drm_afbc_get_superblk_wh(u64 modifier, u32 *w, u32 *h)
+{
+	switch (modifier & AFBC_FORMAT_MOD_BLOCK_SIZE_MASK) {
+	case AFBC_FORMAT_MOD_BLOCK_SIZE_16x16:
+		*w = 16;
+		*h = 16;
+		break;
+	case AFBC_FORMAT_MOD_BLOCK_SIZE_32x8:
+		*w = 32;
+		*h = 8;
+		break;
+	case AFBC_FORMAT_MOD_BLOCK_SIZE_64x4:
+		/* fall through */
+	case AFBC_FORMAT_MOD_BLOCK_SIZE_32x8_64x4:
+		/* fall through */
+	default:
+		DRM_DEBUG_KMS("Invalid AFBC_FORMAT_MOD_BLOCK_SIZE: %lld.\n",
+			      modifier & AFBC_FORMAT_MOD_BLOCK_SIZE_MASK);
+		return false;
+	}
+	return true;
+}
+EXPORT_SYMBOL_GPL(drm_afbc_get_superblk_wh);
+
+/**
+ * drm_afbc_get_parameters - extract afbc parameters from mode command
+ * @mode_cmd: mode command to be looked at
+ * @afbc: address of a struct to be filled in
+ */
+void drm_afbc_get_parameters(const struct drm_mode_fb_cmd2 *mode_cmd,
+			     struct drm_afbc *afbc)
+{
+	drm_afbc_get_superblk_wh(mode_cmd->modifier[0],
+				 &afbc->tile_w, &afbc->tile_h);
+	afbc->width = mode_cmd->pitches[0];
+	afbc->height =
+		DIV_ROUND_UP(mode_cmd->height, afbc->tile_h) * afbc->tile_h;
+	afbc->offset = mode_cmd->offsets[0];
+}
+EXPORT_SYMBOL(drm_afbc_get_parameters);
+
+/**
+ * drm_is_afbc - test if the modifier describes an afbc buffer
+ * @modifier - modifier to be tested
+ *
+ * Returns: true if the modifier describes an afbc buffer
+ */
+bool drm_is_afbc(u64 modifier)
+{
+	/* is it ARM AFBC? */
+	if ((modifier & DRM_FORMAT_MOD_ARM_AFBC(0)) == 0)
+		return false;
+
+	/* Block size must be known */
+	if ((modifier & AFBC_FORMAT_MOD_BLOCK_SIZE_MASK) == 0)
+		return false;
+
+	return true;
+}
+EXPORT_SYMBOL_GPL(drm_is_afbc);
diff --git a/drivers/gpu/drm/drm_fourcc.c b/drivers/gpu/drm/drm_fourcc.c
index c630064ccf41..8d9f197cc0ab 100644
--- a/drivers/gpu/drm/drm_fourcc.c
+++ b/drivers/gpu/drm/drm_fourcc.c
@@ -27,6 +27,7 @@
 #include <linux/export.h>
 #include <linux/kernel.h>
 
+#include <drm/drm_afbc.h>
 #include <drm/drm_device.h>
 #include <drm/drm_fourcc.h>
 
@@ -322,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..303eea624a02 100644
--- a/drivers/gpu/drm/drm_framebuffer.c
+++ b/drivers/gpu/drm/drm_framebuffer.c
@@ -23,6 +23,7 @@
 #include <linux/export.h>
 #include <linux/uaccess.h>
 
+#include <drm/drm_afbc.h>
 #include <drm/drm_atomic.h>
 #include <drm/drm_atomic_uapi.h>
 #include <drm/drm_auth.h>
@@ -31,6 +32,7 @@
 #include <drm/drm_file.h>
 #include <drm/drm_fourcc.h>
 #include <drm/drm_framebuffer.h>
+#include <drm/drm_gem.h>
 #include <drm/drm_print.h>
 #include <drm/drm_util.h>
 
@@ -168,7 +170,69 @@ static int fb_plane_height(int height,
 	return DIV_ROUND_UP(height, format->vsub);
 }
 
+static int afbc_check(struct drm_file *file_priv,
+		      const struct drm_mode_fb_cmd2 *r, int i,
+		      const struct drm_format_info *info)
+{
+	struct drm_gem_object *obj;
+	int bpp = info->cpp[0] * 8;
+	int tiles;
+	u32 w, h, height, tile_sz, afbc_size;
+	int result = 0;
+
+	if (i) {
+		DRM_DEBUG_KMS("AFBC supported only for plane 0\n");
+
+		return 1;
+	}
+
+	/* get tile w/h */
+	if (!drm_afbc_get_superblk_wh(r->modifier[0], &w, &h))
+		return 1;
+
+	/* pitch must be divisible by tile width */
+	if (r->pitches[0] % w) {
+		DRM_DEBUG_KMS("Invalid pitch for plane %d\n", i);
+
+		return 1;
+	}
+
+	obj = drm_gem_object_lookup(file_priv, r->handles[0]);
+	if (!obj) {
+		DRM_DEBUG_KMS("Failed to lookup GEM object\n");
+
+		return 1;
+	}
+
+	/* estimate height based on tile size and height from userspace */
+	height = DIV_ROUND_UP(r->height, h) * h;
+
+	tiles = (r->pitches[0] / w) * (height / h);
+	afbc_size = ALIGN(tiles * AFBC_HEADER_SIZE, AFBC_SUPERBLK_ALIGNMENT);
+
+	tile_sz = (bpp * w * h) / BITS_PER_BYTE;
+	afbc_size += tiles * ALIGN(tile_sz, AFBC_SUPERBLK_ALIGNMENT);
+
+	result = obj->size < afbc_size;
+
+	drm_gem_object_put_unlocked(obj);
+
+	return result;
+}
+
+static int modifier_check(struct drm_file *file_priv,
+			  const struct drm_mode_fb_cmd2 *r, int i,
+			  const struct drm_format_info *info)
+{
+	/* non-afbc format */
+	if (!drm_is_afbc(r->modifier[i]))
+		return 0;
+
+	return afbc_check(file_priv, r, i, info);
+}
+
 static int framebuffer_check(struct drm_device *dev,
+			     struct drm_file *file_priv,
 			     const struct drm_mode_fb_cmd2 *r)
 {
 	const struct drm_format_info *info;
@@ -204,6 +268,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;
@@ -253,6 +320,8 @@ static int framebuffer_check(struct drm_device *dev,
 			break;
 
 		default:
+			if (modifier_check(file_priv, r, i, info))
+				return -EINVAL;
 			break;
 		}
 	}
@@ -317,7 +386,7 @@ drm_internal_framebuffer_create(struct drm_device *dev,
 		return ERR_PTR(-EINVAL);
 	}
 
-	ret = framebuffer_check(dev, r);
+	ret = framebuffer_check(dev, file_priv, r);
 	if (ret)
 		return ERR_PTR(ret);
 
diff --git a/include/drm/drm_afbc.h b/include/drm/drm_afbc.h
new file mode 100644
index 000000000000..fb4d4549f77e
--- /dev/null
+++ b/include/drm/drm_afbc.h
@@ -0,0 +1,35 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * (C) 2019 Collabora Ltd.
+ *
+ * author: Andrzej Pietrasiewicz <andrzej.p@collabora.com>
+ *
+ */
+#ifndef __DRM_AFBC_H__
+#define __DRM_AFBC_H__
+
+#include <linux/types.h>
+
+struct drm_device;
+struct drm_mode_fb_cmd2;
+struct drm_gem_object;
+
+struct drm_afbc {
+	u32 tile_w;
+	u32 tile_h;
+	u32 width;
+	u32 height;
+	u32 offset;
+};
+
+#define AFBC_HEADER_SIZE		16
+#define AFBC_SUPERBLK_ALIGNMENT		128
+
+bool drm_afbc_get_superblk_wh(u64 modifier, u32 *w, u32 *h);
+
+void drm_afbc_get_parameters(const struct drm_mode_fb_cmd2 *mode_cmd,
+			     struct drm_afbc *afbc);
+
+bool drm_is_afbc(u64 modifier);
+
+#endif /* __DRM_AFBC_H__ */
-- 
2.17.1

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

^ permalink raw reply related	[flat|nested] 63+ messages in thread

* [PATCHv3/RFC 2/4] drm/malidp: use afbc helpers
  2019-11-21 17:22                             ` [PATCHv3/RFC 0/4] AFBC rework and support for Rockchip Andrzej Pietrasiewicz
  2019-11-21 17:22                               ` [PATCHv3/RFC 1/4] drm/arm: Factor out generic afbc helpers Andrzej Pietrasiewicz
@ 2019-11-21 17:22                               ` Andrzej Pietrasiewicz
  2019-11-21 17:22                               ` [PATCHv3/RFC 3/4] drm/komeda: Use afbc helper Andrzej Pietrasiewicz
  2019-11-21 17:22                               ` [PATCHv3/RFC 4/4] drm/rockchip: Add support for afbc Andrzej Pietrasiewicz
  3 siblings, 0 replies; 63+ messages in thread
From: Andrzej Pietrasiewicz @ 2019-11-21 17:22 UTC (permalink / raw)
  To: dri-devel
  Cc: Ayan Halder, kernel, David Airlie, Liviu Dudau, James Wang,
	Mihail Atanassov, Sean Paul

There are afbc helpers available.

Signed-off-by: Andrzej Pietrasiewicz <andrzej.p@collabora.com>
---
 drivers/gpu/drm/arm/malidp_drv.c | 121 +++++--------------------------
 1 file changed, 20 insertions(+), 101 deletions(-)

diff --git a/drivers/gpu/drm/arm/malidp_drv.c b/drivers/gpu/drm/arm/malidp_drv.c
index 37d92a06318e..ff8364680676 100644
--- a/drivers/gpu/drm/arm/malidp_drv.c
+++ b/drivers/gpu/drm/arm/malidp_drv.c
@@ -15,6 +15,7 @@
 #include <linux/pm_runtime.h>
 #include <linux/debugfs.h>
 
+#include <drm/drm_afbc.h>
 #include <drm/drm_atomic.h>
 #include <drm/drm_atomic_helper.h>
 #include <drm/drm_crtc.h>
@@ -35,8 +36,6 @@
 #include "malidp_hw.h"
 
 #define MALIDP_CONF_VALID_TIMEOUT	250
-#define AFBC_HEADER_SIZE		16
-#define AFBC_SUPERBLK_ALIGNMENT		128
 
 static void malidp_write_gamma_table(struct malidp_hw_device *hwdev,
 				     u32 data[MALIDP_COEFFTAB_NUM_COEFFS])
@@ -269,112 +268,32 @@ static const struct drm_mode_config_helper_funcs malidp_mode_config_helpers = {
 	.atomic_commit_tail = malidp_atomic_commit_tail,
 };
 
-static bool
-malidp_verify_afbc_framebuffer_caps(struct drm_device *dev,
-				    const struct drm_mode_fb_cmd2 *mode_cmd)
-{
-	if (malidp_format_mod_supported(dev, mode_cmd->pixel_format,
-					mode_cmd->modifier[0]) == false)
-		return false;
-
-	if (mode_cmd->offsets[0] != 0) {
-		DRM_DEBUG_KMS("AFBC buffers' plane offset should be 0\n");
-		return false;
-	}
-
-	switch (mode_cmd->modifier[0] & AFBC_SIZE_MASK) {
-	case AFBC_SIZE_16X16:
-		if ((mode_cmd->width % 16) || (mode_cmd->height % 16)) {
-			DRM_DEBUG_KMS("AFBC buffers must be aligned to 16 pixels\n");
-			return false;
-		}
-		break;
-	default:
-		DRM_DEBUG_KMS("Unsupported AFBC block size\n");
-		return false;
-	}
-
-	return true;
-}
-
-static bool
-malidp_verify_afbc_framebuffer_size(struct drm_device *dev,
-				    struct drm_file *file,
-				    const struct drm_mode_fb_cmd2 *mode_cmd)
+static struct drm_framebuffer *
+malidp_fb_create(struct drm_device *dev, struct drm_file *file,
+		 const struct drm_mode_fb_cmd2 *mode_cmd)
 {
-	int n_superblocks = 0;
-	const struct drm_format_info *info;
-	struct drm_gem_object *objs = NULL;
-	u32 afbc_superblock_size = 0, afbc_superblock_height = 0;
-	u32 afbc_superblock_width = 0, afbc_size = 0;
-	int bpp = 0;
-
-	switch (mode_cmd->modifier[0] & AFBC_SIZE_MASK) {
-	case AFBC_SIZE_16X16:
-		afbc_superblock_height = 16;
-		afbc_superblock_width = 16;
-		break;
-	default:
-		DRM_DEBUG_KMS("AFBC superblock size is not supported\n");
-		return false;
-	}
-
-	info = drm_get_format_info(dev, mode_cmd);
-
-	n_superblocks = (mode_cmd->width / afbc_superblock_width) *
-		(mode_cmd->height / afbc_superblock_height);
-
-	bpp = malidp_format_get_bpp(info->format);
-
-	afbc_superblock_size = (bpp * afbc_superblock_width * afbc_superblock_height)
-				/ BITS_PER_BYTE;
-
-	afbc_size = ALIGN(n_superblocks * AFBC_HEADER_SIZE, AFBC_SUPERBLK_ALIGNMENT);
-	afbc_size += n_superblocks * ALIGN(afbc_superblock_size, AFBC_SUPERBLK_ALIGNMENT);
-
-	if ((mode_cmd->width * bpp) != (mode_cmd->pitches[0] * BITS_PER_BYTE)) {
-		DRM_DEBUG_KMS("Invalid value of (pitch * BITS_PER_BYTE) (=%u) "
-			      "should be same as width (=%u) * bpp (=%u)\n",
-			      (mode_cmd->pitches[0] * BITS_PER_BYTE),
-			      mode_cmd->width, bpp);
-		return false;
-	}
-
-	objs = drm_gem_object_lookup(file, mode_cmd->handles[0]);
-	if (!objs) {
-		DRM_DEBUG_KMS("Failed to lookup GEM object\n");
-		return false;
-	}
+	if (mode_cmd->modifier[0]) {
+		struct drm_afbc afbc;
 
-	if (objs->size < afbc_size) {
-		DRM_DEBUG_KMS("buffer size (%zu) too small for AFBC buffer size = %u\n",
-			      objs->size, afbc_size);
-		drm_gem_object_put_unlocked(objs);
-		return false;
-	}
+		if (malidp_format_mod_supported(dev, mode_cmd->pixel_format,
+						mode_cmd->modifier[0]) == false)
+			return ERR_PTR(-EINVAL);
 
-	drm_gem_object_put_unlocked(objs);
+		drm_afbc_get_parameters(mode_cmd, &afbc);
 
-	return true;
-}
+		if (afbc.tile_w != 16 || afbc.tile_h != 16) {
+			DRM_DEV_DEBUG(dev->dev,
+				      "Unsupported AFBC block size %dx%d\n",
+				      afbc.tile_w, afbc.tile_h);
 
-static bool
-malidp_verify_afbc_framebuffer(struct drm_device *dev, struct drm_file *file,
-			       const struct drm_mode_fb_cmd2 *mode_cmd)
-{
-	if (malidp_verify_afbc_framebuffer_caps(dev, mode_cmd))
-		return malidp_verify_afbc_framebuffer_size(dev, file, mode_cmd);
-
-	return false;
-}
+			return ERR_PTR(-EINVAL);
+		}
 
-static struct drm_framebuffer *
-malidp_fb_create(struct drm_device *dev, struct drm_file *file,
-		 const struct drm_mode_fb_cmd2 *mode_cmd)
-{
-	if (mode_cmd->modifier[0]) {
-		if (!malidp_verify_afbc_framebuffer(dev, file, mode_cmd))
+		if (afbc.offset) {
+			DRM_DEV_ERROR(dev->dev,
+				"AFBC plane offset must be zero!\n");
 			return ERR_PTR(-EINVAL);
+		}
 	}
 
 	return drm_gem_fb_create(dev, file, mode_cmd);
-- 
2.17.1

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

^ permalink raw reply related	[flat|nested] 63+ messages in thread

* [PATCHv3/RFC 3/4] drm/komeda: Use afbc helper
  2019-11-21 17:22                             ` [PATCHv3/RFC 0/4] AFBC rework and support for Rockchip Andrzej Pietrasiewicz
  2019-11-21 17:22                               ` [PATCHv3/RFC 1/4] drm/arm: Factor out generic afbc helpers Andrzej Pietrasiewicz
  2019-11-21 17:22                               ` [PATCHv3/RFC 2/4] drm/malidp: use " Andrzej Pietrasiewicz
@ 2019-11-21 17:22                               ` Andrzej Pietrasiewicz
  2019-11-21 17:22                               ` [PATCHv3/RFC 4/4] drm/rockchip: Add support for afbc Andrzej Pietrasiewicz
  3 siblings, 0 replies; 63+ messages in thread
From: Andrzej Pietrasiewicz @ 2019-11-21 17:22 UTC (permalink / raw)
  To: dri-devel
  Cc: Ayan Halder, kernel, David Airlie, Liviu Dudau, James Wang,
	Mihail Atanassov, Sean Paul

AFBC helpers are available. Use those which increase code readability.

Signed-off-by: Andrzej Pietrasiewicz <andrzej.p@collabora.com>
---
 .../drm/arm/display/komeda/komeda_framebuffer.c | 17 +++--------------
 1 file changed, 3 insertions(+), 14 deletions(-)

diff --git a/drivers/gpu/drm/arm/display/komeda/komeda_framebuffer.c b/drivers/gpu/drm/arm/display/komeda/komeda_framebuffer.c
index 1b01a625f40e..f7edde3ac319 100644
--- a/drivers/gpu/drm/arm/display/komeda/komeda_framebuffer.c
+++ b/drivers/gpu/drm/arm/display/komeda/komeda_framebuffer.c
@@ -4,6 +4,7 @@
  * Author: James.Qian.Wang <james.qian.wang@arm.com>
  *
  */
+#include <drm/drm_afbc.h>
 #include <drm/drm_device.h>
 #include <drm/drm_fb_cma_helper.h>
 #include <drm/drm_gem.h>
@@ -52,20 +53,8 @@ komeda_fb_afbc_size_check(struct komeda_fb *kfb, struct drm_file *file,
 		return -ENOENT;
 	}
 
-	switch (fb->modifier & AFBC_FORMAT_MOD_BLOCK_SIZE_MASK) {
-	case AFBC_FORMAT_MOD_BLOCK_SIZE_32x8:
-		alignment_w = 32;
-		alignment_h = 8;
-		break;
-	case AFBC_FORMAT_MOD_BLOCK_SIZE_16x16:
-		alignment_w = 16;
-		alignment_h = 16;
-		break;
-	default:
-		WARN(1, "Invalid AFBC_FORMAT_MOD_BLOCK_SIZE: %lld.\n",
-		     fb->modifier & AFBC_FORMAT_MOD_BLOCK_SIZE_MASK);
-		break;
-	}
+	if (!drm_afbc_get_superblk_wh(fb->modifier, &alignment_w, &alignment_h))
+		return -EINVAL;
 
 	/* tiled header afbc */
 	if (fb->modifier & AFBC_FORMAT_MOD_TILED) {
-- 
2.17.1

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

^ permalink raw reply related	[flat|nested] 63+ messages in thread

* [PATCHv3/RFC 4/4] drm/rockchip: Add support for afbc
  2019-11-21 17:22                             ` [PATCHv3/RFC 0/4] AFBC rework and support for Rockchip Andrzej Pietrasiewicz
                                                 ` (2 preceding siblings ...)
  2019-11-21 17:22                               ` [PATCHv3/RFC 3/4] drm/komeda: Use afbc helper Andrzej Pietrasiewicz
@ 2019-11-21 17:22                               ` Andrzej Pietrasiewicz
  2019-11-23  7:21                                   ` Ezequiel Garcia
  3 siblings, 1 reply; 63+ messages in thread
From: Andrzej Pietrasiewicz @ 2019-11-21 17:22 UTC (permalink / raw)
  To: dri-devel
  Cc: Ayan Halder, kernel, David Airlie, Liviu Dudau, James Wang,
	Mihail Atanassov, Sean Paul, Mark Yao

This patch adds support for afbc handling. afbc is a compressed format
which reduces the necessary memory bandwidth.

Co-developed-by: Mark Yao <mark.yao@rock-chips.com>
Signed-off-by: Mark Yao <mark.yao@rock-chips.com>
Signed-off-by: Andrzej Pietrasiewicz <andrzej.p@collabora.com>
---
 drivers/gpu/drm/rockchip/rockchip_drm_fb.c  |  29 ++++
 drivers/gpu/drm/rockchip/rockchip_drm_vop.c | 142 +++++++++++++++++++-
 drivers/gpu/drm/rockchip/rockchip_drm_vop.h |  12 ++
 drivers/gpu/drm/rockchip/rockchip_vop_reg.c |  84 +++++++++++-
 4 files changed, 263 insertions(+), 4 deletions(-)

diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_fb.c b/drivers/gpu/drm/rockchip/rockchip_drm_fb.c
index ca01234c037c..7eaa3fdc03b2 100644
--- a/drivers/gpu/drm/rockchip/rockchip_drm_fb.c
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_fb.c
@@ -8,6 +8,7 @@
 
 #include <drm/drm.h>
 #include <drm/drm_atomic.h>
+#include <drm/drm_afbc.h>
 #include <drm/drm_damage_helper.h>
 #include <drm/drm_fb_helper.h>
 #include <drm/drm_fourcc.h>
@@ -18,6 +19,8 @@
 #include "rockchip_drm_fb.h"
 #include "rockchip_drm_gem.h"
 
+#define ROCKCHIP_MAX_AFBC_WIDTH	2560
+
 static const struct drm_framebuffer_funcs rockchip_drm_fb_funcs = {
 	.destroy       = drm_gem_fb_destroy,
 	.create_handle = drm_gem_fb_create_handle,
@@ -32,6 +35,32 @@ rockchip_fb_alloc(struct drm_device *dev, const struct drm_mode_fb_cmd2 *mode_cm
 	int ret;
 	int i;
 
+	if (drm_is_afbc(mode_cmd->modifier[0])) {
+		struct drm_afbc afbc;
+
+		drm_afbc_get_parameters(mode_cmd, &afbc);
+
+		if (afbc.offset) {
+			DRM_WARN("AFBC plane offset must be zero!\n");
+
+			return ERR_PTR(-EINVAL);
+		}
+
+		if (afbc.tile_w != 16 || afbc.tile_h != 16) {
+			DRM_WARN("Unsupported afbc tile w/h [%d/%d]\n",
+				 afbc.tile_w, afbc.tile_h);
+
+			return ERR_PTR(-EINVAL);
+		}
+
+		if (afbc.width > ROCKCHIP_MAX_AFBC_WIDTH) {
+			DRM_WARN("Unsupported width %d>%d\n",
+				 afbc.width, ROCKCHIP_MAX_AFBC_WIDTH);
+
+			return ERR_PTR(-EINVAL);
+		}
+	}
+
 	fb = kzalloc(sizeof(*fb), GFP_KERNEL);
 	if (!fb)
 		return ERR_PTR(-ENOMEM);
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c
index d04b3492bdac..31f72ba61361 100644
--- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c
@@ -91,9 +91,22 @@
 #define VOP_WIN_TO_INDEX(vop_win) \
 	((vop_win) - (vop_win)->vop->win)
 
+#define VOP_AFBC_SET(vop, name, v) \
+	do { \
+		if ((vop)->data->afbc) \
+			vop_reg_set((vop), &(vop)->data->afbc->name, \
+				0, ~0, v, #name); \
+	} while (0)
+
 #define to_vop(x) container_of(x, struct vop, crtc)
 #define to_vop_win(x) container_of(x, struct vop_win, base)
 
+#define AFBC_FMT_RGB565		0x0
+#define AFBC_FMT_U8U8U8U8	0x5
+#define AFBC_FMT_U8U8U8		0x4
+
+#define AFBC_TILE_16x16		BIT(4)
+
 /*
  * The coefficients of the following matrix are all fixed points.
  * The format is S2.10 for the 3x3 part of the matrix, and S9.12 for the offsets.
@@ -166,6 +179,7 @@ struct vop {
 	/* optional internal rgb encoder */
 	struct rockchip_rgb *rgb;
 
+	struct vop_win *afbc_win;
 	struct vop_win win[];
 };
 
@@ -274,6 +288,29 @@ static enum vop_data_format vop_convert_format(uint32_t format)
 	}
 }
 
+static int vop_convert_afbc_format(uint32_t format)
+{
+	switch (format) {
+	case DRM_FORMAT_XRGB8888:
+	case DRM_FORMAT_ARGB8888:
+	case DRM_FORMAT_XBGR8888:
+	case DRM_FORMAT_ABGR8888:
+		return AFBC_FMT_U8U8U8U8;
+	case DRM_FORMAT_RGB888:
+	case DRM_FORMAT_BGR888:
+		return AFBC_FMT_U8U8U8;
+	case DRM_FORMAT_RGB565:
+	case DRM_FORMAT_BGR565:
+		return AFBC_FMT_RGB565;
+	/* either of the below should not be reachable */
+	default:
+		DRM_WARN_ONCE("unsupported AFBC format[%08x]\n", format);
+		return -EINVAL;
+	}
+
+	return -EINVAL;
+}
+
 static uint16_t scl_vop_cal_scale(enum scale_mode mode, uint32_t src,
 				  uint32_t dst, bool is_horizontal,
 				  int vsu_mode, int *vskiplines)
@@ -598,6 +635,15 @@ static int vop_enable(struct drm_crtc *crtc, struct drm_crtc_state *old_state)
 			vop_win_disable(vop, vop_win);
 		}
 	}
+
+	if (vop->data->afbc) {
+		/*
+		 * Disable AFBC and forget there was a vop window with AFBC
+		 */
+		VOP_AFBC_SET(vop, enable, 0);
+		vop->afbc_win = NULL;
+	}
+
 	spin_unlock(&vop->reg_lock);
 
 	vop_cfg_done(vop);
@@ -710,6 +756,34 @@ static void vop_plane_destroy(struct drm_plane *plane)
 	drm_plane_cleanup(plane);
 }
 
+static bool rockchip_mod_supported(struct drm_plane *plane,
+				   u32 format, u64 modifier)
+{
+	const struct drm_format_info *info;
+
+	if (WARN_ON(modifier == DRM_FORMAT_MOD_INVALID))
+		return false;
+
+	if (modifier == DRM_FORMAT_MOD_LINEAR)
+		return true;
+
+	if (modifier !=
+		DRM_FORMAT_MOD_ARM_AFBC(AFBC_FORMAT_MOD_BLOCK_SIZE_16x16 |
+		AFBC_FORMAT_MOD_SPARSE)) {
+		DRM_DEBUG_KMS("Unsupported format modifer 0x%llx\n", modifier);
+
+		return false;
+	}
+
+	info = drm_format_info(format);
+	if (info->num_planes != 1) {
+		DRM_DEBUG_KMS("AFBC buffers expect one plane\n");
+		return false;
+	}
+
+	return true;
+}
+
 static int vop_plane_atomic_check(struct drm_plane *plane,
 			   struct drm_plane_state *state)
 {
@@ -758,6 +832,34 @@ static int vop_plane_atomic_check(struct drm_plane *plane,
 		return -EINVAL;
 	}
 
+	if (fb->modifier ==
+		DRM_FORMAT_MOD_ARM_AFBC(AFBC_FORMAT_MOD_BLOCK_SIZE_16x16 |
+		AFBC_FORMAT_MOD_SPARSE)) {
+		struct vop *vop = to_vop(crtc);
+
+		if (!vop->data->afbc) {
+			DRM_ERROR("vop does not support AFBC\n");
+			return -EINVAL;
+		}
+
+		ret = vop_convert_afbc_format(fb->format->format);
+		if (ret < 0)
+			return ret;
+
+		if (state->src.x1 || state->src.y1) {
+			DRM_ERROR("afbc does not support offset display\n");
+			DRM_ERROR("xpos=%d, ypos=%d, offset=%d\n",
+				  state->src.x1, state->src.y1, fb->offsets[0]);
+			return -EINVAL;
+		}
+
+		if (state->rotation && state->rotation != DRM_MODE_ROTATE_0) {
+			DRM_ERROR("afbc does not support rotation\n");
+			DRM_ERROR("rotation=%d\n", state->rotation);
+			return -EINVAL;
+		}
+	}
+
 	return 0;
 }
 
@@ -773,6 +875,11 @@ static void vop_plane_atomic_disable(struct drm_plane *plane,
 	spin_lock(&vop->reg_lock);
 
 	vop_win_disable(vop, vop_win);
+	/*
+	 * Forget about the AFBC window if it is being disabled
+	 */
+	if (vop_win == vop->afbc_win)
+		vop->afbc_win = NULL;
 
 	spin_unlock(&vop->reg_lock);
 }
@@ -812,6 +919,13 @@ static void vop_plane_atomic_update(struct drm_plane *plane,
 	if (WARN_ON(!vop->is_enabled))
 		return;
 
+	/*
+	 * If updating the AFBC window then assume that
+	 * after the update there will be no AFBC window.
+	 */
+	if (vop_win == vop->afbc_win)
+		vop->afbc_win = NULL;
+
 	if (!state->visible) {
 		vop_plane_atomic_disable(plane, old_state);
 		return;
@@ -846,6 +960,23 @@ static void vop_plane_atomic_update(struct drm_plane *plane,
 
 	spin_lock(&vop->reg_lock);
 
+	if (fb->modifier ==
+		DRM_FORMAT_MOD_ARM_AFBC(AFBC_FORMAT_MOD_BLOCK_SIZE_16x16 |
+		AFBC_FORMAT_MOD_SPARSE)) {
+		int afbc_format = vop_convert_afbc_format(fb->format->format);
+
+		VOP_AFBC_SET(vop, format, afbc_format | AFBC_TILE_16x16);
+		VOP_AFBC_SET(vop, hreg_block_split, 0);
+		VOP_AFBC_SET(vop, win_sel, VOP_WIN_TO_INDEX(vop_win));
+		VOP_AFBC_SET(vop, hdr_ptr, dma_addr);
+		VOP_AFBC_SET(vop, pic_size, act_info);
+
+		/*
+		 * The window being udated becomes the AFBC window
+		 */
+		vop->afbc_win = vop_win;
+	}
+
 	VOP_WIN_SET(vop, win, format, format);
 	VOP_WIN_SET(vop, win, yrgb_vir, DIV_ROUND_UP(fb->pitches[0], 4));
 	VOP_WIN_SET(vop, win, yrgb_mst, dma_addr);
@@ -1001,6 +1132,7 @@ static const struct drm_plane_funcs vop_plane_funcs = {
 	.reset = drm_atomic_helper_plane_reset,
 	.atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state,
 	.atomic_destroy_state = drm_atomic_helper_plane_destroy_state,
+	.format_mod_supported = rockchip_mod_supported,
 };
 
 static int vop_crtc_enable_vblank(struct drm_crtc *crtc)
@@ -1340,6 +1472,10 @@ static void vop_crtc_atomic_flush(struct drm_crtc *crtc,
 
 	spin_lock(&vop->reg_lock);
 
+	/*
+	 * Enable AFBC if there is some AFBC window, disable otherwise
+	 */
+	VOP_AFBC_SET(vop, enable, vop->afbc_win != NULL);
 	vop_cfg_done(vop);
 
 	spin_unlock(&vop->reg_lock);
@@ -1634,7 +1770,8 @@ static int vop_create_crtc(struct vop *vop)
 					       0, &vop_plane_funcs,
 					       win_data->phy->data_formats,
 					       win_data->phy->nformats,
-					       NULL, win_data->type, NULL);
+					       win_data->phy->format_modifiers,
+					       win_data->type, NULL);
 		if (ret) {
 			DRM_DEV_ERROR(vop->dev, "failed to init plane %d\n",
 				      ret);
@@ -1678,7 +1815,8 @@ static int vop_create_crtc(struct vop *vop)
 					       &vop_plane_funcs,
 					       win_data->phy->data_formats,
 					       win_data->phy->nformats,
-					       NULL, win_data->type, NULL);
+					       win_data->phy->format_modifiers,
+					       win_data->type, NULL);
 		if (ret) {
 			DRM_DEV_ERROR(vop->dev, "failed to init overlay %d\n",
 				      ret);
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.h b/drivers/gpu/drm/rockchip/rockchip_drm_vop.h
index 0b3d18c457b2..3f4e88a783d2 100644
--- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.h
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.h
@@ -34,6 +34,16 @@ struct vop_reg {
 	bool relaxed;
 };
 
+struct vop_afbc {
+	struct vop_reg enable;
+	struct vop_reg win_sel;
+	struct vop_reg format;
+	struct vop_reg hreg_block_split;
+	struct vop_reg pic_size;
+	struct vop_reg hdr_ptr;
+	struct vop_reg rstn;
+};
+
 struct vop_modeset {
 	struct vop_reg htotal_pw;
 	struct vop_reg hact_st_end;
@@ -134,6 +144,7 @@ struct vop_win_phy {
 	const struct vop_scl_regs *scl;
 	const uint32_t *data_formats;
 	uint32_t nformats;
+	const uint64_t *format_modifiers;
 
 	struct vop_reg enable;
 	struct vop_reg gate;
@@ -173,6 +184,7 @@ struct vop_data {
 	const struct vop_misc *misc;
 	const struct vop_modeset *modeset;
 	const struct vop_output *output;
+	const struct vop_afbc *afbc;
 	const struct vop_win_yuv2yuv_data *win_yuv2yuv;
 	const struct vop_win_data *win;
 	unsigned int win_size;
diff --git a/drivers/gpu/drm/rockchip/rockchip_vop_reg.c b/drivers/gpu/drm/rockchip/rockchip_vop_reg.c
index 7a9d979c8d5d..f0cf1b04591d 100644
--- a/drivers/gpu/drm/rockchip/rockchip_vop_reg.c
+++ b/drivers/gpu/drm/rockchip/rockchip_vop_reg.c
@@ -50,6 +50,18 @@ static const uint32_t formats_win_full[] = {
 	DRM_FORMAT_NV24,
 };
 
+static const uint64_t format_modifiers_win_full[] = {
+	DRM_FORMAT_MOD_LINEAR,
+	DRM_FORMAT_MOD_INVALID,
+};
+
+static const uint64_t format_modifiers_win_full_afbc[] = {
+	DRM_FORMAT_MOD_ARM_AFBC(AFBC_FORMAT_MOD_BLOCK_SIZE_16x16 |
+				AFBC_FORMAT_MOD_SPARSE),
+	DRM_FORMAT_MOD_LINEAR,
+	DRM_FORMAT_MOD_INVALID,
+};
+
 static const uint32_t formats_win_lite[] = {
 	DRM_FORMAT_XRGB8888,
 	DRM_FORMAT_ARGB8888,
@@ -61,6 +73,11 @@ static const uint32_t formats_win_lite[] = {
 	DRM_FORMAT_BGR565,
 };
 
+static const uint64_t format_modifiers_win_lite[] = {
+	DRM_FORMAT_MOD_LINEAR,
+	DRM_FORMAT_MOD_INVALID,
+};
+
 static const struct vop_scl_regs rk3036_win_scl = {
 	.scale_yrgb_x = VOP_REG(RK3036_WIN0_SCL_FACTOR_YRGB, 0xffff, 0x0),
 	.scale_yrgb_y = VOP_REG(RK3036_WIN0_SCL_FACTOR_YRGB, 0xffff, 16),
@@ -72,6 +89,7 @@ static const struct vop_win_phy rk3036_win0_data = {
 	.scl = &rk3036_win_scl,
 	.data_formats = formats_win_full,
 	.nformats = ARRAY_SIZE(formats_win_full),
+	.format_modifiers = format_modifiers_win_full,
 	.enable = VOP_REG(RK3036_SYS_CTRL, 0x1, 0),
 	.format = VOP_REG(RK3036_SYS_CTRL, 0x7, 3),
 	.rb_swap = VOP_REG(RK3036_SYS_CTRL, 0x1, 15),
@@ -87,6 +105,7 @@ static const struct vop_win_phy rk3036_win0_data = {
 static const struct vop_win_phy rk3036_win1_data = {
 	.data_formats = formats_win_lite,
 	.nformats = ARRAY_SIZE(formats_win_lite),
+	.format_modifiers = format_modifiers_win_lite,
 	.enable = VOP_REG(RK3036_SYS_CTRL, 0x1, 1),
 	.format = VOP_REG(RK3036_SYS_CTRL, 0x7, 6),
 	.rb_swap = VOP_REG(RK3036_SYS_CTRL, 0x1, 19),
@@ -153,6 +172,7 @@ static const struct vop_data rk3036_vop = {
 static const struct vop_win_phy rk3126_win1_data = {
 	.data_formats = formats_win_lite,
 	.nformats = ARRAY_SIZE(formats_win_lite),
+	.format_modifiers = format_modifiers_win_lite,
 	.enable = VOP_REG(RK3036_SYS_CTRL, 0x1, 1),
 	.format = VOP_REG(RK3036_SYS_CTRL, 0x7, 6),
 	.rb_swap = VOP_REG(RK3036_SYS_CTRL, 0x1, 19),
@@ -234,6 +254,7 @@ static const struct vop_win_phy px30_win0_data = {
 	.scl = &px30_win_scl,
 	.data_formats = formats_win_full,
 	.nformats = ARRAY_SIZE(formats_win_full),
+	.format_modifiers = format_modifiers_win_full,
 	.enable = VOP_REG(PX30_WIN0_CTRL0, 0x1, 0),
 	.format = VOP_REG(PX30_WIN0_CTRL0, 0x7, 1),
 	.rb_swap = VOP_REG(PX30_WIN0_CTRL0, 0x1, 12),
@@ -249,6 +270,7 @@ static const struct vop_win_phy px30_win0_data = {
 static const struct vop_win_phy px30_win1_data = {
 	.data_formats = formats_win_lite,
 	.nformats = ARRAY_SIZE(formats_win_lite),
+	.format_modifiers = format_modifiers_win_lite,
 	.enable = VOP_REG(PX30_WIN1_CTRL0, 0x1, 0),
 	.format = VOP_REG(PX30_WIN1_CTRL0, 0x7, 4),
 	.rb_swap = VOP_REG(PX30_WIN1_CTRL0, 0x1, 12),
@@ -261,6 +283,7 @@ static const struct vop_win_phy px30_win1_data = {
 static const struct vop_win_phy px30_win2_data = {
 	.data_formats = formats_win_lite,
 	.nformats = ARRAY_SIZE(formats_win_lite),
+	.format_modifiers = format_modifiers_win_lite,
 	.gate = VOP_REG(PX30_WIN2_CTRL0, 0x1, 4),
 	.enable = VOP_REG(PX30_WIN2_CTRL0, 0x1, 0),
 	.format = VOP_REG(PX30_WIN2_CTRL0, 0x3, 5),
@@ -316,6 +339,7 @@ static const struct vop_win_phy rk3066_win0_data = {
 	.scl = &rk3066_win_scl,
 	.data_formats = formats_win_full,
 	.nformats = ARRAY_SIZE(formats_win_full),
+	.format_modifiers = format_modifiers_win_full,
 	.enable = VOP_REG(RK3066_SYS_CTRL1, 0x1, 0),
 	.format = VOP_REG(RK3066_SYS_CTRL0, 0x7, 4),
 	.rb_swap = VOP_REG(RK3066_SYS_CTRL0, 0x1, 19),
@@ -332,6 +356,7 @@ static const struct vop_win_phy rk3066_win1_data = {
 	.scl = &rk3066_win_scl,
 	.data_formats = formats_win_full,
 	.nformats = ARRAY_SIZE(formats_win_full),
+	.format_modifiers = format_modifiers_win_full,
 	.enable = VOP_REG(RK3066_SYS_CTRL1, 0x1, 1),
 	.format = VOP_REG(RK3066_SYS_CTRL0, 0x7, 7),
 	.rb_swap = VOP_REG(RK3066_SYS_CTRL0, 0x1, 23),
@@ -347,6 +372,7 @@ static const struct vop_win_phy rk3066_win1_data = {
 static const struct vop_win_phy rk3066_win2_data = {
 	.data_formats = formats_win_lite,
 	.nformats = ARRAY_SIZE(formats_win_lite),
+	.format_modifiers = format_modifiers_win_lite,
 	.enable = VOP_REG(RK3066_SYS_CTRL1, 0x1, 2),
 	.format = VOP_REG(RK3066_SYS_CTRL0, 0x7, 10),
 	.rb_swap = VOP_REG(RK3066_SYS_CTRL0, 0x1, 27),
@@ -426,6 +452,7 @@ static const struct vop_win_phy rk3188_win0_data = {
 	.scl = &rk3188_win_scl,
 	.data_formats = formats_win_full,
 	.nformats = ARRAY_SIZE(formats_win_full),
+	.format_modifiers = format_modifiers_win_full,
 	.enable = VOP_REG(RK3188_SYS_CTRL, 0x1, 0),
 	.format = VOP_REG(RK3188_SYS_CTRL, 0x7, 3),
 	.rb_swap = VOP_REG(RK3188_SYS_CTRL, 0x1, 15),
@@ -440,6 +467,7 @@ static const struct vop_win_phy rk3188_win0_data = {
 static const struct vop_win_phy rk3188_win1_data = {
 	.data_formats = formats_win_lite,
 	.nformats = ARRAY_SIZE(formats_win_lite),
+	.format_modifiers = format_modifiers_win_lite,
 	.enable = VOP_REG(RK3188_SYS_CTRL, 0x1, 1),
 	.format = VOP_REG(RK3188_SYS_CTRL, 0x7, 6),
 	.rb_swap = VOP_REG(RK3188_SYS_CTRL, 0x1, 19),
@@ -545,6 +573,7 @@ static const struct vop_win_phy rk3288_win01_data = {
 	.scl = &rk3288_win_full_scl,
 	.data_formats = formats_win_full,
 	.nformats = ARRAY_SIZE(formats_win_full),
+	.format_modifiers = format_modifiers_win_full,
 	.enable = VOP_REG(RK3288_WIN0_CTRL0, 0x1, 0),
 	.format = VOP_REG(RK3288_WIN0_CTRL0, 0x7, 1),
 	.rb_swap = VOP_REG(RK3288_WIN0_CTRL0, 0x1, 12),
@@ -563,6 +592,7 @@ static const struct vop_win_phy rk3288_win01_data = {
 static const struct vop_win_phy rk3288_win23_data = {
 	.data_formats = formats_win_lite,
 	.nformats = ARRAY_SIZE(formats_win_lite),
+	.format_modifiers = format_modifiers_win_lite,
 	.enable = VOP_REG(RK3288_WIN2_CTRL0, 0x1, 4),
 	.gate = VOP_REG(RK3288_WIN2_CTRL0, 0x1, 0),
 	.format = VOP_REG(RK3288_WIN2_CTRL0, 0x7, 1),
@@ -677,6 +707,7 @@ static const struct vop_win_phy rk3368_win01_data = {
 	.scl = &rk3288_win_full_scl,
 	.data_formats = formats_win_full,
 	.nformats = ARRAY_SIZE(formats_win_full),
+	.format_modifiers = format_modifiers_win_full,
 	.enable = VOP_REG(RK3368_WIN0_CTRL0, 0x1, 0),
 	.format = VOP_REG(RK3368_WIN0_CTRL0, 0x7, 1),
 	.rb_swap = VOP_REG(RK3368_WIN0_CTRL0, 0x1, 12),
@@ -697,6 +728,7 @@ static const struct vop_win_phy rk3368_win01_data = {
 static const struct vop_win_phy rk3368_win23_data = {
 	.data_formats = formats_win_lite,
 	.nformats = ARRAY_SIZE(formats_win_lite),
+	.format_modifiers = format_modifiers_win_lite,
 	.gate = VOP_REG(RK3368_WIN2_CTRL0, 0x1, 0),
 	.enable = VOP_REG(RK3368_WIN2_CTRL0, 0x1, 4),
 	.format = VOP_REG(RK3368_WIN2_CTRL0, 0x3, 5),
@@ -817,6 +849,53 @@ static const struct vop_win_yuv2yuv_data rk3399_vop_big_win_yuv2yuv_data[] = {
 	  .y2r_en = VOP_REG(RK3399_YUV2YUV_WIN, 0x1, 9) },
 	{ .base = 0xC0, .phy = &rk3399_yuv2yuv_win23_data },
 	{ .base = 0x120, .phy = &rk3399_yuv2yuv_win23_data },
+
+};
+
+static const struct vop_win_phy rk3399_win01_data = {
+	.scl = &rk3288_win_full_scl,
+	.data_formats = formats_win_full,
+	.nformats = ARRAY_SIZE(formats_win_full),
+	.format_modifiers = format_modifiers_win_full_afbc,
+	.enable = VOP_REG(RK3288_WIN0_CTRL0, 0x1, 0),
+	.format = VOP_REG(RK3288_WIN0_CTRL0, 0x7, 1),
+	.rb_swap = VOP_REG(RK3288_WIN0_CTRL0, 0x1, 12),
+	.y_mir_en = VOP_REG(RK3288_WIN0_CTRL0, 0x1, 22),
+	.act_info = VOP_REG(RK3288_WIN0_ACT_INFO, 0x1fff1fff, 0),
+	.dsp_info = VOP_REG(RK3288_WIN0_DSP_INFO, 0x0fff0fff, 0),
+	.dsp_st = VOP_REG(RK3288_WIN0_DSP_ST, 0x1fff1fff, 0),
+	.yrgb_mst = VOP_REG(RK3288_WIN0_YRGB_MST, 0xffffffff, 0),
+	.uv_mst = VOP_REG(RK3288_WIN0_CBR_MST, 0xffffffff, 0),
+	.yrgb_vir = VOP_REG(RK3288_WIN0_VIR, 0x3fff, 0),
+	.uv_vir = VOP_REG(RK3288_WIN0_VIR, 0x3fff, 16),
+	.src_alpha_ctl = VOP_REG(RK3288_WIN0_SRC_ALPHA_CTRL, 0xff, 0),
+	.dst_alpha_ctl = VOP_REG(RK3288_WIN0_DST_ALPHA_CTRL, 0xff, 0),
+};
+
+/*
+ * rk3399 vop big windows register layout is same as rk3288, but we
+ * have a separate rk3399 win data array here so that we can advertise
+ * AFBC on the primary plane.
+ */
+static const struct vop_win_data rk3399_vop_win_data[] = {
+	{ .base = 0x00, .phy = &rk3399_win01_data,
+	  .type = DRM_PLANE_TYPE_PRIMARY },
+	{ .base = 0x40, .phy = &rk3288_win01_data,
+	  .type = DRM_PLANE_TYPE_OVERLAY },
+	{ .base = 0x00, .phy = &rk3288_win23_data,
+	  .type = DRM_PLANE_TYPE_OVERLAY },
+	{ .base = 0x50, .phy = &rk3288_win23_data,
+	  .type = DRM_PLANE_TYPE_CURSOR },
+};
+
+static const struct vop_afbc rk3399_vop_afbc = {
+	.rstn = VOP_REG(RK3399_AFBCD0_CTRL, 0x1, 3),
+	.enable = VOP_REG(RK3399_AFBCD0_CTRL, 0x1, 0),
+	.win_sel = VOP_REG(RK3399_AFBCD0_CTRL, 0x3, 1),
+	.format = VOP_REG(RK3399_AFBCD0_CTRL, 0x1f, 16),
+	.hreg_block_split = VOP_REG(RK3399_AFBCD0_CTRL, 0x1, 21),
+	.hdr_ptr = VOP_REG(RK3399_AFBCD0_HDR_PTR, 0xffffffff, 0),
+	.pic_size = VOP_REG(RK3399_AFBCD0_PIC_SIZE, 0xffffffff, 0),
 };
 
 static const struct vop_data rk3399_vop_big = {
@@ -826,9 +905,10 @@ static const struct vop_data rk3399_vop_big = {
 	.common = &rk3288_common,
 	.modeset = &rk3288_modeset,
 	.output = &rk3399_output,
+	.afbc = &rk3399_vop_afbc,
 	.misc = &rk3368_misc,
-	.win = rk3368_vop_win_data,
-	.win_size = ARRAY_SIZE(rk3368_vop_win_data),
+	.win = rk3399_vop_win_data,
+	.win_size = ARRAY_SIZE(rk3399_vop_win_data),
 	.win_yuv2yuv = rk3399_vop_big_win_yuv2yuv_data,
 };
 
-- 
2.17.1

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

^ permalink raw reply related	[flat|nested] 63+ messages in thread

* Re: [PATCHv3/RFC 1/4] drm/arm: Factor out generic afbc helpers
@ 2019-11-23  7:13                                   ` Ezequiel Garcia
  0 siblings, 0 replies; 63+ messages in thread
From: Ezequiel Garcia @ 2019-11-23  7:13 UTC (permalink / raw)
  To: Andrzej Pietrasiewicz, dri-devel
  Cc: Ayan Halder, kernel, David Airlie, Liviu Dudau, James Wang,
	Mihail Atanassov, Sean Paul

Hi Andrzej,

Thanks for the series. It's certainly going well.

Please see some minor comments below.

On Thu, 2019-11-21 at 18:22 +0100, Andrzej Pietrasiewicz wrote:
> These are useful for other users of afbc, e.g. rockchip.
> 
> Signed-off-by: Andrzej Pietrasiewicz <andrzej.p@collabora.com>
> ---
>  drivers/gpu/drm/Makefile          |  2 +-
>  drivers/gpu/drm/drm_afbc.c        | 84 +++++++++++++++++++++++++++++++
>  drivers/gpu/drm/drm_fourcc.c      | 11 +++-
>  drivers/gpu/drm/drm_framebuffer.c | 71 +++++++++++++++++++++++++-
>  include/drm/drm_afbc.h            | 35 +++++++++++++
>  5 files changed, 199 insertions(+), 4 deletions(-)
>  create mode 100644 drivers/gpu/drm/drm_afbc.c
>  create mode 100644 include/drm/drm_afbc.h
> 
> diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile
> index d9bcc9f2a0a4..3a58f30b83a6 100644
> --- a/drivers/gpu/drm/Makefile
> +++ b/drivers/gpu/drm/Makefile
> @@ -44,7 +44,7 @@ drm_kms_helper-y := drm_crtc_helper.o drm_dp_helper.o drm_dsc.o drm_probe_helper
>  		drm_simple_kms_helper.o drm_modeset_helper.o \
>  		drm_scdc_helper.o drm_gem_framebuffer_helper.o \
>  		drm_atomic_state_helper.o drm_damage_helper.o \
> -		drm_format_helper.o drm_self_refresh_helper.o
> +		drm_format_helper.o drm_self_refresh_helper.o drm_afbc.o
>  
>  drm_kms_helper-$(CONFIG_DRM_PANEL_BRIDGE) += bridge/panel.o
>  drm_kms_helper-$(CONFIG_DRM_FBDEV_EMULATION) += drm_fb_helper.o
> diff --git a/drivers/gpu/drm/drm_afbc.c b/drivers/gpu/drm/drm_afbc.c
> new file mode 100644
> index 000000000000..f308c4719546
> --- /dev/null
> +++ b/drivers/gpu/drm/drm_afbc.c
> @@ -0,0 +1,84 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * (C) 2019 Collabora Ltd.
> + *
> + * author: Andrzej Pietrasiewicz <andrzej.p@collabora.com>
> + *
> + */
> +#include <linux/module.h>
> +
> +#include <drm/drm_afbc.h>
> +#include <drm/drm_device.h>
> +#include <drm/drm_fourcc.h>
> +#include <drm/drm_gem.h>
> +#include <drm/drm_mode.h>
> +#include <drm/drm_print.h>
> +
> +/**
> + * drm_afbc_get_superblk_wh - extract afbc block width/height from modifier
> + * @modifier: the modifier to be looked at
> + * @w: address of a place to store the block width
> + * @h: address of a place to store the block height
> + *
> + * Returns: true if the modifier describes a supported block size
> + */
> +bool drm_afbc_get_superblk_wh(u64 modifier, u32 *w, u32 *h)
> +{

Name nitpicking: drm_afbc_get_superblock_size. The coding-style
guide has a chapter on naming and suggests avoiding stuff like
"superblk".

> +	switch (modifier & AFBC_FORMAT_MOD_BLOCK_SIZE_MASK) {
> +	case AFBC_FORMAT_MOD_BLOCK_SIZE_16x16:
> +		*w = 16;
> +		*h = 16;
> +		break;
> +	case AFBC_FORMAT_MOD_BLOCK_SIZE_32x8:
> +		*w = 32;
> +		*h = 8;
> +		break;
> +	case AFBC_FORMAT_MOD_BLOCK_SIZE_64x4:
> +		/* fall through */
> +	case AFBC_FORMAT_MOD_BLOCK_SIZE_32x8_64x4:
> +		/* fall through */
> +	default:
> +		DRM_DEBUG_KMS("Invalid AFBC_FORMAT_MOD_BLOCK_SIZE: %lld.\n",
> +			      modifier & AFBC_FORMAT_MOD_BLOCK_SIZE_MASK);
> +		return false;
> +	}
> +	return true;
> +}
> +EXPORT_SYMBOL_GPL(drm_afbc_get_superblk_wh);
> +
> +/**
> + * drm_afbc_get_parameters - extract afbc parameters from mode command
> + * @mode_cmd: mode command to be looked at
> + * @afbc: address of a struct to be filled in
> + */
> +void drm_afbc_get_parameters(const struct drm_mode_fb_cmd2 *mode_cmd,
> +			     struct drm_afbc *afbc)
> +{
> +	drm_afbc_get_superblk_wh(mode_cmd->modifier[0],
> +				 &afbc->tile_w, &afbc->tile_h);
> +	afbc->width = mode_cmd->pitches[0];
> +	afbc->height =
> +		DIV_ROUND_UP(mode_cmd->height, afbc->tile_h) * afbc->tile_h;
> +	afbc->offset = mode_cmd->offsets[0];
> +}
> +EXPORT_SYMBOL(drm_afbc_get_parameters);
> +

Not sure if this was discussed before, but why some
are EXPORT_SYMBOL and others are exported as _GPL?

> +/**
> + * drm_is_afbc - test if the modifier describes an afbc buffer
> + * @modifier - modifier to be tested
> + *
> + * Returns: true if the modifier describes an afbc buffer
> + */
> +bool drm_is_afbc(u64 modifier)
> +{
> +	/* is it ARM AFBC? */
> +	if ((modifier & DRM_FORMAT_MOD_ARM_AFBC(0)) == 0)
> +		return false;
> +
> +	/* Block size must be known */
> +	if ((modifier & AFBC_FORMAT_MOD_BLOCK_SIZE_MASK) == 0)
> +		return false;
> +
> +	return true;
> +}
> +EXPORT_SYMBOL_GPL(drm_is_afbc);
> diff --git a/drivers/gpu/drm/drm_fourcc.c b/drivers/gpu/drm/drm_fourcc.c
> index c630064ccf41..8d9f197cc0ab 100644
> --- a/drivers/gpu/drm/drm_fourcc.c
> +++ b/drivers/gpu/drm/drm_fourcc.c
> @@ -27,6 +27,7 @@
>  #include <linux/export.h>
>  #include <linux/kernel.h>
>  
> +#include <drm/drm_afbc.h>
>  #include <drm/drm_device.h>
>  #include <drm/drm_fourcc.h>
>  
> @@ -322,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..303eea624a02 100644
> --- a/drivers/gpu/drm/drm_framebuffer.c
> +++ b/drivers/gpu/drm/drm_framebuffer.c
> @@ -23,6 +23,7 @@
>  #include <linux/export.h>
>  #include <linux/uaccess.h>
>  
> +#include <drm/drm_afbc.h>
>  #include <drm/drm_atomic.h>
>  #include <drm/drm_atomic_uapi.h>
>  #include <drm/drm_auth.h>
> @@ -31,6 +32,7 @@
>  #include <drm/drm_file.h>
>  #include <drm/drm_fourcc.h>
>  #include <drm/drm_framebuffer.h>
> +#include <drm/drm_gem.h>
>  #include <drm/drm_print.h>
>  #include <drm/drm_util.h>
>  
> @@ -168,7 +170,69 @@ static int fb_plane_height(int height,
>  	return DIV_ROUND_UP(height, format->vsub);
>  }
>  
> +static int afbc_check(struct drm_file *file_priv,
> +		      const struct drm_mode_fb_cmd2 *r, int i,
> +		      const struct drm_format_info *info)
> +{
> +	struct drm_gem_object *obj;
> +	int bpp = info->cpp[0] * 8;
> +	int tiles;
> +	u32 w, h, height, tile_sz, afbc_size;
> +	int result = 0;
> +
> +	if (i) {
> +		DRM_DEBUG_KMS("AFBC supported only for plane 0\n");
> +
> +		return 1;

Any reason to return 1, instead of an errno, or a boolean?

> +	}
> +
> +	/* get tile w/h */
> +	if (!drm_afbc_get_superblk_wh(r->modifier[0], &w, &h))
> +		return 1;
> +
> +	/* pitch must be divisible by tile width */
> +	if (r->pitches[0] % w) {
> +		DRM_DEBUG_KMS("Invalid pitch for plane %d\n", i);
> +
> +		return 1;
> +	}
> +
> +	obj = drm_gem_object_lookup(file_priv, r->handles[0]);
> +	if (!obj) {
> +		DRM_DEBUG_KMS("Failed to lookup GEM object\n");
> +
> +		return 1;
> +	}
> +
> +	/* estimate height based on tile size and height from userspace */
> +	height = DIV_ROUND_UP(r->height, h) * h;
> +
> +	tiles = (r->pitches[0] / w) * (height / h);
> +	afbc_size = ALIGN(tiles * AFBC_HEADER_SIZE, AFBC_SUPERBLK_ALIGNMENT);
> +
> +	tile_sz = (bpp * w * h) / BITS_PER_BYTE;
> +	afbc_size += tiles * ALIGN(tile_sz, AFBC_SUPERBLK_ALIGNMENT);
> +
> +	result = obj->size < afbc_size;
> +
> +	drm_gem_object_put_unlocked(obj);
> +
> +	return result;
> +}
> +
> +static int modifier_check(struct drm_file *file_priv,
> +			  const struct drm_mode_fb_cmd2 *r, int i,
> +			  const struct drm_format_info *info)
> +{
> +	/* non-afbc format */
> +	if (!drm_is_afbc(r->modifier[i]))
> +		return 0;
> +
> +	return afbc_check(file_priv, r, i, info);
> +}
> +
>  static int framebuffer_check(struct drm_device *dev,
> +			     struct drm_file *file_priv,
>  			     const struct drm_mode_fb_cmd2 *r)
>  {
>  	const struct drm_format_info *info;
> @@ -204,6 +268,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;
> @@ -253,6 +320,8 @@ static int framebuffer_check(struct drm_device *dev,
>  			break;
>  
>  		default:
> +			if (modifier_check(file_priv, r, i, info))
> +				return -EINVAL;
>  			break;
>  		}
>  	}
> @@ -317,7 +386,7 @@ drm_internal_framebuffer_create(struct drm_device *dev,
>  		return ERR_PTR(-EINVAL);
>  	}
>  
> -	ret = framebuffer_check(dev, r);
> +	ret = framebuffer_check(dev, file_priv, r);
>  	if (ret)
>  		return ERR_PTR(ret);
>  
> diff --git a/include/drm/drm_afbc.h b/include/drm/drm_afbc.h
> new file mode 100644
> index 000000000000..fb4d4549f77e
> --- /dev/null
> +++ b/include/drm/drm_afbc.h
> @@ -0,0 +1,35 @@
> +/* SPDX-License-Identifier: GPL-2.0+ */
> +/*
> + * (C) 2019 Collabora Ltd.
> + *
> + * author: Andrzej Pietrasiewicz <andrzej.p@collabora.com>
> + *
> + */
> +#ifndef __DRM_AFBC_H__
> +#define __DRM_AFBC_H__
> +
> +#include <linux/types.h>
> +
> +struct drm_device;
> +struct drm_mode_fb_cmd2;
> +struct drm_gem_object;
> +
> +struct drm_afbc {
> +	u32 tile_w;
> +	u32 tile_h;

I'd go with tile_width and tile_height.

> +	u32 width;
> +	u32 height;
> +	u32 offset;
> +};
> +
> +#define AFBC_HEADER_SIZE		16
> +#define AFBC_SUPERBLK_ALIGNMENT		128
> +

Ditto, s/SUPERBLK/SUPERBLOCK.

> +bool drm_afbc_get_superblk_wh(u64 modifier, u32 *w, u32 *h);
> +
> +void drm_afbc_get_parameters(const struct drm_mode_fb_cmd2 *mode_cmd,
> +			     struct drm_afbc *afbc);
> +
> +bool drm_is_afbc(u64 modifier);
> +
> +#endif /* __DRM_AFBC_H__ */
> -- 
> 2.17.1
> 
> 

Thanks!
Eze

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

^ permalink raw reply	[flat|nested] 63+ messages in thread

* Re: [PATCHv3/RFC 1/4] drm/arm: Factor out generic afbc helpers
@ 2019-11-23  7:13                                   ` Ezequiel Garcia
  0 siblings, 0 replies; 63+ messages in thread
From: Ezequiel Garcia @ 2019-11-23  7:13 UTC (permalink / raw)
  To: Andrzej Pietrasiewicz, dri-devel
  Cc: Ayan Halder, kernel, David Airlie, Liviu Dudau, James Wang,
	Mihail Atanassov, Sean Paul

Hi Andrzej,

Thanks for the series. It's certainly going well.

Please see some minor comments below.

On Thu, 2019-11-21 at 18:22 +0100, Andrzej Pietrasiewicz wrote:
> These are useful for other users of afbc, e.g. rockchip.
> 
> Signed-off-by: Andrzej Pietrasiewicz <andrzej.p@collabora.com>
> ---
>  drivers/gpu/drm/Makefile          |  2 +-
>  drivers/gpu/drm/drm_afbc.c        | 84 +++++++++++++++++++++++++++++++
>  drivers/gpu/drm/drm_fourcc.c      | 11 +++-
>  drivers/gpu/drm/drm_framebuffer.c | 71 +++++++++++++++++++++++++-
>  include/drm/drm_afbc.h            | 35 +++++++++++++
>  5 files changed, 199 insertions(+), 4 deletions(-)
>  create mode 100644 drivers/gpu/drm/drm_afbc.c
>  create mode 100644 include/drm/drm_afbc.h
> 
> diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile
> index d9bcc9f2a0a4..3a58f30b83a6 100644
> --- a/drivers/gpu/drm/Makefile
> +++ b/drivers/gpu/drm/Makefile
> @@ -44,7 +44,7 @@ drm_kms_helper-y := drm_crtc_helper.o drm_dp_helper.o drm_dsc.o drm_probe_helper
>  		drm_simple_kms_helper.o drm_modeset_helper.o \
>  		drm_scdc_helper.o drm_gem_framebuffer_helper.o \
>  		drm_atomic_state_helper.o drm_damage_helper.o \
> -		drm_format_helper.o drm_self_refresh_helper.o
> +		drm_format_helper.o drm_self_refresh_helper.o drm_afbc.o
>  
>  drm_kms_helper-$(CONFIG_DRM_PANEL_BRIDGE) += bridge/panel.o
>  drm_kms_helper-$(CONFIG_DRM_FBDEV_EMULATION) += drm_fb_helper.o
> diff --git a/drivers/gpu/drm/drm_afbc.c b/drivers/gpu/drm/drm_afbc.c
> new file mode 100644
> index 000000000000..f308c4719546
> --- /dev/null
> +++ b/drivers/gpu/drm/drm_afbc.c
> @@ -0,0 +1,84 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * (C) 2019 Collabora Ltd.
> + *
> + * author: Andrzej Pietrasiewicz <andrzej.p@collabora.com>
> + *
> + */
> +#include <linux/module.h>
> +
> +#include <drm/drm_afbc.h>
> +#include <drm/drm_device.h>
> +#include <drm/drm_fourcc.h>
> +#include <drm/drm_gem.h>
> +#include <drm/drm_mode.h>
> +#include <drm/drm_print.h>
> +
> +/**
> + * drm_afbc_get_superblk_wh - extract afbc block width/height from modifier
> + * @modifier: the modifier to be looked at
> + * @w: address of a place to store the block width
> + * @h: address of a place to store the block height
> + *
> + * Returns: true if the modifier describes a supported block size
> + */
> +bool drm_afbc_get_superblk_wh(u64 modifier, u32 *w, u32 *h)
> +{

Name nitpicking: drm_afbc_get_superblock_size. The coding-style
guide has a chapter on naming and suggests avoiding stuff like
"superblk".

> +	switch (modifier & AFBC_FORMAT_MOD_BLOCK_SIZE_MASK) {
> +	case AFBC_FORMAT_MOD_BLOCK_SIZE_16x16:
> +		*w = 16;
> +		*h = 16;
> +		break;
> +	case AFBC_FORMAT_MOD_BLOCK_SIZE_32x8:
> +		*w = 32;
> +		*h = 8;
> +		break;
> +	case AFBC_FORMAT_MOD_BLOCK_SIZE_64x4:
> +		/* fall through */
> +	case AFBC_FORMAT_MOD_BLOCK_SIZE_32x8_64x4:
> +		/* fall through */
> +	default:
> +		DRM_DEBUG_KMS("Invalid AFBC_FORMAT_MOD_BLOCK_SIZE: %lld.\n",
> +			      modifier & AFBC_FORMAT_MOD_BLOCK_SIZE_MASK);
> +		return false;
> +	}
> +	return true;
> +}
> +EXPORT_SYMBOL_GPL(drm_afbc_get_superblk_wh);
> +
> +/**
> + * drm_afbc_get_parameters - extract afbc parameters from mode command
> + * @mode_cmd: mode command to be looked at
> + * @afbc: address of a struct to be filled in
> + */
> +void drm_afbc_get_parameters(const struct drm_mode_fb_cmd2 *mode_cmd,
> +			     struct drm_afbc *afbc)
> +{
> +	drm_afbc_get_superblk_wh(mode_cmd->modifier[0],
> +				 &afbc->tile_w, &afbc->tile_h);
> +	afbc->width = mode_cmd->pitches[0];
> +	afbc->height =
> +		DIV_ROUND_UP(mode_cmd->height, afbc->tile_h) * afbc->tile_h;
> +	afbc->offset = mode_cmd->offsets[0];
> +}
> +EXPORT_SYMBOL(drm_afbc_get_parameters);
> +

Not sure if this was discussed before, but why some
are EXPORT_SYMBOL and others are exported as _GPL?

> +/**
> + * drm_is_afbc - test if the modifier describes an afbc buffer
> + * @modifier - modifier to be tested
> + *
> + * Returns: true if the modifier describes an afbc buffer
> + */
> +bool drm_is_afbc(u64 modifier)
> +{
> +	/* is it ARM AFBC? */
> +	if ((modifier & DRM_FORMAT_MOD_ARM_AFBC(0)) == 0)
> +		return false;
> +
> +	/* Block size must be known */
> +	if ((modifier & AFBC_FORMAT_MOD_BLOCK_SIZE_MASK) == 0)
> +		return false;
> +
> +	return true;
> +}
> +EXPORT_SYMBOL_GPL(drm_is_afbc);
> diff --git a/drivers/gpu/drm/drm_fourcc.c b/drivers/gpu/drm/drm_fourcc.c
> index c630064ccf41..8d9f197cc0ab 100644
> --- a/drivers/gpu/drm/drm_fourcc.c
> +++ b/drivers/gpu/drm/drm_fourcc.c
> @@ -27,6 +27,7 @@
>  #include <linux/export.h>
>  #include <linux/kernel.h>
>  
> +#include <drm/drm_afbc.h>
>  #include <drm/drm_device.h>
>  #include <drm/drm_fourcc.h>
>  
> @@ -322,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..303eea624a02 100644
> --- a/drivers/gpu/drm/drm_framebuffer.c
> +++ b/drivers/gpu/drm/drm_framebuffer.c
> @@ -23,6 +23,7 @@
>  #include <linux/export.h>
>  #include <linux/uaccess.h>
>  
> +#include <drm/drm_afbc.h>
>  #include <drm/drm_atomic.h>
>  #include <drm/drm_atomic_uapi.h>
>  #include <drm/drm_auth.h>
> @@ -31,6 +32,7 @@
>  #include <drm/drm_file.h>
>  #include <drm/drm_fourcc.h>
>  #include <drm/drm_framebuffer.h>
> +#include <drm/drm_gem.h>
>  #include <drm/drm_print.h>
>  #include <drm/drm_util.h>
>  
> @@ -168,7 +170,69 @@ static int fb_plane_height(int height,
>  	return DIV_ROUND_UP(height, format->vsub);
>  }
>  
> +static int afbc_check(struct drm_file *file_priv,
> +		      const struct drm_mode_fb_cmd2 *r, int i,
> +		      const struct drm_format_info *info)
> +{
> +	struct drm_gem_object *obj;
> +	int bpp = info->cpp[0] * 8;
> +	int tiles;
> +	u32 w, h, height, tile_sz, afbc_size;
> +	int result = 0;
> +
> +	if (i) {
> +		DRM_DEBUG_KMS("AFBC supported only for plane 0\n");
> +
> +		return 1;

Any reason to return 1, instead of an errno, or a boolean?

> +	}
> +
> +	/* get tile w/h */
> +	if (!drm_afbc_get_superblk_wh(r->modifier[0], &w, &h))
> +		return 1;
> +
> +	/* pitch must be divisible by tile width */
> +	if (r->pitches[0] % w) {
> +		DRM_DEBUG_KMS("Invalid pitch for plane %d\n", i);
> +
> +		return 1;
> +	}
> +
> +	obj = drm_gem_object_lookup(file_priv, r->handles[0]);
> +	if (!obj) {
> +		DRM_DEBUG_KMS("Failed to lookup GEM object\n");
> +
> +		return 1;
> +	}
> +
> +	/* estimate height based on tile size and height from userspace */
> +	height = DIV_ROUND_UP(r->height, h) * h;
> +
> +	tiles = (r->pitches[0] / w) * (height / h);
> +	afbc_size = ALIGN(tiles * AFBC_HEADER_SIZE, AFBC_SUPERBLK_ALIGNMENT);
> +
> +	tile_sz = (bpp * w * h) / BITS_PER_BYTE;
> +	afbc_size += tiles * ALIGN(tile_sz, AFBC_SUPERBLK_ALIGNMENT);
> +
> +	result = obj->size < afbc_size;
> +
> +	drm_gem_object_put_unlocked(obj);
> +
> +	return result;
> +}
> +
> +static int modifier_check(struct drm_file *file_priv,
> +			  const struct drm_mode_fb_cmd2 *r, int i,
> +			  const struct drm_format_info *info)
> +{
> +	/* non-afbc format */
> +	if (!drm_is_afbc(r->modifier[i]))
> +		return 0;
> +
> +	return afbc_check(file_priv, r, i, info);
> +}
> +
>  static int framebuffer_check(struct drm_device *dev,
> +			     struct drm_file *file_priv,
>  			     const struct drm_mode_fb_cmd2 *r)
>  {
>  	const struct drm_format_info *info;
> @@ -204,6 +268,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;
> @@ -253,6 +320,8 @@ static int framebuffer_check(struct drm_device *dev,
>  			break;
>  
>  		default:
> +			if (modifier_check(file_priv, r, i, info))
> +				return -EINVAL;
>  			break;
>  		}
>  	}
> @@ -317,7 +386,7 @@ drm_internal_framebuffer_create(struct drm_device *dev,
>  		return ERR_PTR(-EINVAL);
>  	}
>  
> -	ret = framebuffer_check(dev, r);
> +	ret = framebuffer_check(dev, file_priv, r);
>  	if (ret)
>  		return ERR_PTR(ret);
>  
> diff --git a/include/drm/drm_afbc.h b/include/drm/drm_afbc.h
> new file mode 100644
> index 000000000000..fb4d4549f77e
> --- /dev/null
> +++ b/include/drm/drm_afbc.h
> @@ -0,0 +1,35 @@
> +/* SPDX-License-Identifier: GPL-2.0+ */
> +/*
> + * (C) 2019 Collabora Ltd.
> + *
> + * author: Andrzej Pietrasiewicz <andrzej.p@collabora.com>
> + *
> + */
> +#ifndef __DRM_AFBC_H__
> +#define __DRM_AFBC_H__
> +
> +#include <linux/types.h>
> +
> +struct drm_device;
> +struct drm_mode_fb_cmd2;
> +struct drm_gem_object;
> +
> +struct drm_afbc {
> +	u32 tile_w;
> +	u32 tile_h;

I'd go with tile_width and tile_height.

> +	u32 width;
> +	u32 height;
> +	u32 offset;
> +};
> +
> +#define AFBC_HEADER_SIZE		16
> +#define AFBC_SUPERBLK_ALIGNMENT		128
> +

Ditto, s/SUPERBLK/SUPERBLOCK.

> +bool drm_afbc_get_superblk_wh(u64 modifier, u32 *w, u32 *h);
> +
> +void drm_afbc_get_parameters(const struct drm_mode_fb_cmd2 *mode_cmd,
> +			     struct drm_afbc *afbc);
> +
> +bool drm_is_afbc(u64 modifier);
> +
> +#endif /* __DRM_AFBC_H__ */
> -- 
> 2.17.1
> 
> 

Thanks!
Eze

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

^ permalink raw reply	[flat|nested] 63+ messages in thread

* Re: [PATCHv3/RFC 4/4] drm/rockchip: Add support for afbc
@ 2019-11-23  7:21                                   ` Ezequiel Garcia
  0 siblings, 0 replies; 63+ messages in thread
From: Ezequiel Garcia @ 2019-11-23  7:21 UTC (permalink / raw)
  To: Andrzej Pietrasiewicz, dri-devel
  Cc: Ayan Halder, kernel, David Airlie, Liviu Dudau, James Wang,
	Mihail Atanassov, Sean Paul, Mark Yao

Hello Andrzej,

Thanks a lot for the patch.

Reviewed-by: Ezequiel Garcia <ezequiel@collabora.com>

On Thu, 2019-11-21 at 18:22 +0100, Andrzej Pietrasiewicz wrote:
> This patch adds support for afbc handling. afbc is a compressed format
> which reduces the necessary memory bandwidth.
> 
> Co-developed-by: Mark Yao <mark.yao@rock-chips.com>
> Signed-off-by: Mark Yao <mark.yao@rock-chips.com>
> Signed-off-by: Andrzej Pietrasiewicz <andrzej.p@collabora.com>
> ---
>  drivers/gpu/drm/rockchip/rockchip_drm_fb.c  |  29 ++++
>  drivers/gpu/drm/rockchip/rockchip_drm_vop.c | 142 +++++++++++++++++++-
>  drivers/gpu/drm/rockchip/rockchip_drm_vop.h |  12 ++
>  drivers/gpu/drm/rockchip/rockchip_vop_reg.c |  84 +++++++++++-
>  4 files changed, 263 insertions(+), 4 deletions(-)
> 
> diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_fb.c b/drivers/gpu/drm/rockchip/rockchip_drm_fb.c
> index ca01234c037c..7eaa3fdc03b2 100644
> --- a/drivers/gpu/drm/rockchip/rockchip_drm_fb.c
> +++ b/drivers/gpu/drm/rockchip/rockchip_drm_fb.c
> @@ -8,6 +8,7 @@
>  
>  #include <drm/drm.h>
>  #include <drm/drm_atomic.h>
> +#include <drm/drm_afbc.h>
>  #include <drm/drm_damage_helper.h>
>  #include <drm/drm_fb_helper.h>
>  #include <drm/drm_fourcc.h>
> @@ -18,6 +19,8 @@
>  #include "rockchip_drm_fb.h"
>  #include "rockchip_drm_gem.h"
>  
> +#define ROCKCHIP_MAX_AFBC_WIDTH	2560
> +
>  static const struct drm_framebuffer_funcs rockchip_drm_fb_funcs = {
>  	.destroy       = drm_gem_fb_destroy,
>  	.create_handle = drm_gem_fb_create_handle,
> @@ -32,6 +35,32 @@ rockchip_fb_alloc(struct drm_device *dev, const struct drm_mode_fb_cmd2 *mode_cm
>  	int ret;
>  	int i;
>  
> +	if (drm_is_afbc(mode_cmd->modifier[0])) {
> +		struct drm_afbc afbc;
> +
> +		drm_afbc_get_parameters(mode_cmd, &afbc);
> +
> +		if (afbc.offset) {
> +			DRM_WARN("AFBC plane offset must be zero!\n");
> +
> +			return ERR_PTR(-EINVAL);
> +		}
> +
> +		if (afbc.tile_w != 16 || afbc.tile_h != 16) {
> +			DRM_WARN("Unsupported afbc tile w/h [%d/%d]\n",
> +				 afbc.tile_w, afbc.tile_h);
> +

I think it's important to stick to using always "AFBC" or
always ", i.e. to be consisten in user messages.
Makes grepping easier.

[..]
> @@ -846,6 +960,23 @@ static void vop_plane_atomic_update(struct drm_plane *plane,
>  
>  	spin_lock(&vop->reg_lock);
>  
> +	if (fb->modifier ==
> +		DRM_FORMAT_MOD_ARM_AFBC(AFBC_FORMAT_MOD_BLOCK_SIZE_16x16 |
> +		AFBC_FORMAT_MOD_SPARSE)) {

You check this modifier condition a few times, how about
having a helper for it?

> +		int afbc_format = vop_convert_afbc_format(fb->format->format);
> +
> +		VOP_AFBC_SET(vop, format, afbc_format | AFBC_TILE_16x16);
> +		VOP_AFBC_SET(vop, hreg_block_split, 0);
> +		VOP_AFBC_SET(vop, win_sel, VOP_WIN_TO_INDEX(vop_win));
> +		VOP_AFBC_SET(vop, hdr_ptr, dma_addr);
> +		VOP_AFBC_SET(vop, pic_size, act_info);
> +
> +		/*
> +		 * The window being udated becomes the AFBC window
> +		 */
> +		vop->afbc_win = vop_win;
> +	}
> +
>  	VOP_WIN_SET(vop, win, format, format);
>  	VOP_WIN_SET(vop, win, yrgb_vir, DIV_ROUND_UP(fb->pitches[0], 4));
>  	VOP_WIN_SET(vop, win, yrgb_mst, dma_addr);
> @@ -1001,6 +1132,7 @@ static const struct drm_plane_funcs vop_plane_funcs = {
>  	.reset = drm_atomic_helper_plane_reset,
>  	.atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state,
>  	.atomic_destroy_state = drm_atomic_helper_plane_destroy_state,
> +	.format_mod_supported = rockchip_mod_supported,
>  };
>  
>  static int vop_crtc_enable_vblank(struct drm_crtc *crtc)
> @@ -1340,6 +1472,10 @@ static void vop_crtc_atomic_flush(struct drm_crtc *crtc,
>  
>  	spin_lock(&vop->reg_lock);
>  
> +	/*
> +	 * Enable AFBC if there is some AFBC window, disable otherwise
> +	 */

Nitpick: no need for multi-line style comments, if the comment
is a single line. Also, you might want to end the comment with a stop.

Thanks!
Eze

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

^ permalink raw reply	[flat|nested] 63+ messages in thread

* Re: [PATCHv3/RFC 4/4] drm/rockchip: Add support for afbc
@ 2019-11-23  7:21                                   ` Ezequiel Garcia
  0 siblings, 0 replies; 63+ messages in thread
From: Ezequiel Garcia @ 2019-11-23  7:21 UTC (permalink / raw)
  To: Andrzej Pietrasiewicz, dri-devel
  Cc: Ayan Halder, kernel, David Airlie, Liviu Dudau, James Wang,
	Mihail Atanassov, Sean Paul, Mark Yao

Hello Andrzej,

Thanks a lot for the patch.

Reviewed-by: Ezequiel Garcia <ezequiel@collabora.com>

On Thu, 2019-11-21 at 18:22 +0100, Andrzej Pietrasiewicz wrote:
> This patch adds support for afbc handling. afbc is a compressed format
> which reduces the necessary memory bandwidth.
> 
> Co-developed-by: Mark Yao <mark.yao@rock-chips.com>
> Signed-off-by: Mark Yao <mark.yao@rock-chips.com>
> Signed-off-by: Andrzej Pietrasiewicz <andrzej.p@collabora.com>
> ---
>  drivers/gpu/drm/rockchip/rockchip_drm_fb.c  |  29 ++++
>  drivers/gpu/drm/rockchip/rockchip_drm_vop.c | 142 +++++++++++++++++++-
>  drivers/gpu/drm/rockchip/rockchip_drm_vop.h |  12 ++
>  drivers/gpu/drm/rockchip/rockchip_vop_reg.c |  84 +++++++++++-
>  4 files changed, 263 insertions(+), 4 deletions(-)
> 
> diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_fb.c b/drivers/gpu/drm/rockchip/rockchip_drm_fb.c
> index ca01234c037c..7eaa3fdc03b2 100644
> --- a/drivers/gpu/drm/rockchip/rockchip_drm_fb.c
> +++ b/drivers/gpu/drm/rockchip/rockchip_drm_fb.c
> @@ -8,6 +8,7 @@
>  
>  #include <drm/drm.h>
>  #include <drm/drm_atomic.h>
> +#include <drm/drm_afbc.h>
>  #include <drm/drm_damage_helper.h>
>  #include <drm/drm_fb_helper.h>
>  #include <drm/drm_fourcc.h>
> @@ -18,6 +19,8 @@
>  #include "rockchip_drm_fb.h"
>  #include "rockchip_drm_gem.h"
>  
> +#define ROCKCHIP_MAX_AFBC_WIDTH	2560
> +
>  static const struct drm_framebuffer_funcs rockchip_drm_fb_funcs = {
>  	.destroy       = drm_gem_fb_destroy,
>  	.create_handle = drm_gem_fb_create_handle,
> @@ -32,6 +35,32 @@ rockchip_fb_alloc(struct drm_device *dev, const struct drm_mode_fb_cmd2 *mode_cm
>  	int ret;
>  	int i;
>  
> +	if (drm_is_afbc(mode_cmd->modifier[0])) {
> +		struct drm_afbc afbc;
> +
> +		drm_afbc_get_parameters(mode_cmd, &afbc);
> +
> +		if (afbc.offset) {
> +			DRM_WARN("AFBC plane offset must be zero!\n");
> +
> +			return ERR_PTR(-EINVAL);
> +		}
> +
> +		if (afbc.tile_w != 16 || afbc.tile_h != 16) {
> +			DRM_WARN("Unsupported afbc tile w/h [%d/%d]\n",
> +				 afbc.tile_w, afbc.tile_h);
> +

I think it's important to stick to using always "AFBC" or
always ", i.e. to be consisten in user messages.
Makes grepping easier.

[..]
> @@ -846,6 +960,23 @@ static void vop_plane_atomic_update(struct drm_plane *plane,
>  
>  	spin_lock(&vop->reg_lock);
>  
> +	if (fb->modifier ==
> +		DRM_FORMAT_MOD_ARM_AFBC(AFBC_FORMAT_MOD_BLOCK_SIZE_16x16 |
> +		AFBC_FORMAT_MOD_SPARSE)) {

You check this modifier condition a few times, how about
having a helper for it?

> +		int afbc_format = vop_convert_afbc_format(fb->format->format);
> +
> +		VOP_AFBC_SET(vop, format, afbc_format | AFBC_TILE_16x16);
> +		VOP_AFBC_SET(vop, hreg_block_split, 0);
> +		VOP_AFBC_SET(vop, win_sel, VOP_WIN_TO_INDEX(vop_win));
> +		VOP_AFBC_SET(vop, hdr_ptr, dma_addr);
> +		VOP_AFBC_SET(vop, pic_size, act_info);
> +
> +		/*
> +		 * The window being udated becomes the AFBC window
> +		 */
> +		vop->afbc_win = vop_win;
> +	}
> +
>  	VOP_WIN_SET(vop, win, format, format);
>  	VOP_WIN_SET(vop, win, yrgb_vir, DIV_ROUND_UP(fb->pitches[0], 4));
>  	VOP_WIN_SET(vop, win, yrgb_mst, dma_addr);
> @@ -1001,6 +1132,7 @@ static const struct drm_plane_funcs vop_plane_funcs = {
>  	.reset = drm_atomic_helper_plane_reset,
>  	.atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state,
>  	.atomic_destroy_state = drm_atomic_helper_plane_destroy_state,
> +	.format_mod_supported = rockchip_mod_supported,
>  };
>  
>  static int vop_crtc_enable_vblank(struct drm_crtc *crtc)
> @@ -1340,6 +1472,10 @@ static void vop_crtc_atomic_flush(struct drm_crtc *crtc,
>  
>  	spin_lock(&vop->reg_lock);
>  
> +	/*
> +	 * Enable AFBC if there is some AFBC window, disable otherwise
> +	 */

Nitpick: no need for multi-line style comments, if the comment
is a single line. Also, you might want to end the comment with a stop.

Thanks!
Eze

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

^ permalink raw reply	[flat|nested] 63+ messages in thread

* Re: [PATCHv3/RFC 1/4] drm/arm: Factor out generic afbc helpers
  2019-11-21 17:22                               ` [PATCHv3/RFC 1/4] drm/arm: Factor out generic afbc helpers Andrzej Pietrasiewicz
  2019-11-23  7:13                                   ` Ezequiel Garcia
@ 2019-11-24 10:11                                 ` kbuild test robot
  2019-11-25  8:55                                 ` Daniel Vetter
  2 siblings, 0 replies; 63+ messages in thread
From: kbuild test robot @ 2019-11-24 10:11 UTC (permalink / raw)
  To: kbuild-all

[-- Attachment #1: Type: text/plain, Size: 2948 bytes --]

Hi Andrzej,

[FYI, it's a private test report for your RFC patch.]
[auto build test ERROR on next-20191122]
[also build test ERROR on v5.4-rc8]
[cannot apply to rockchip/for-next drm-exynos/exynos-drm-next linus/master v5.4-rc8 v5.4-rc7 v5.4-rc6]
[if your patch is applied to the wrong git tree, please drop us a note to help
improve the system. BTW, we also suggest to use '--base' option to specify the
base tree in git format-patch, please see https://stackoverflow.com/a/37406982]

url:    https://github.com/0day-ci/linux/commits/Andrzej-Pietrasiewicz/AFBC-rework-and-support-for-Rockchip/20191124-080522
base:    b9d3d01405061bb42358fe53f824e894a1922ced
config: x86_64-randconfig-a001-20191124 (attached as .config)
compiler: gcc-7 (Debian 7.4.0-14) 7.4.0
reproduce:
        # save the attached .config to linux build tree
        make ARCH=x86_64 

If you fix the issue, kindly add following tag
Reported-by: kbuild test robot <lkp@intel.com>

All errors (new ones prefixed by >>):

   ld: drivers/gpu/drm/drm_fourcc.o: in function `drm_get_format_info':
>> drivers/gpu/drm/drm_fourcc.c:327: undefined reference to `drm_is_afbc'
   ld: drivers/gpu/drm/drm_framebuffer.o: in function `framebuffer_check':
>> drivers/gpu/drm/drm_framebuffer.c:271: undefined reference to `drm_is_afbc'
   ld: drivers/gpu/drm/drm_framebuffer.o: in function `modifier_check':
   drivers/gpu/drm/drm_framebuffer.c:228: undefined reference to `drm_is_afbc'
   ld: drivers/gpu/drm/drm_framebuffer.o: in function `afbc_check':
>> drivers/gpu/drm/drm_framebuffer.c:190: undefined reference to `drm_afbc_get_superblk_wh'

vim +327 drivers/gpu/drm/drm_fourcc.c

   310	
   311	/**
   312	 * drm_get_format_info - query information for a given framebuffer configuration
   313	 * @dev: DRM device
   314	 * @mode_cmd: metadata from the userspace fb creation request
   315	 *
   316	 * Returns:
   317	 * The instance of struct drm_format_info that describes the pixel format, or
   318	 * NULL if the format is unsupported.
   319	 */
   320	const struct drm_format_info *
   321	drm_get_format_info(struct drm_device *dev,
   322			    const struct drm_mode_fb_cmd2 *mode_cmd)
   323	{
   324		const struct drm_format_info *info = NULL;
   325	
   326		/* bypass driver callback if afbc */
 > 327		if (!drm_is_afbc(mode_cmd->modifier[0]))
   328			if (dev->mode_config.funcs->get_format_info) {
   329				const struct drm_mode_config_funcs *funcs;
   330	
   331				funcs = dev->mode_config.funcs;
   332				info = funcs->get_format_info(mode_cmd);
   333			}
   334	
   335		if (!info)
   336			info = drm_format_info(mode_cmd->pixel_format);
   337	
   338		return info;
   339	}
   340	EXPORT_SYMBOL(drm_get_format_info);
   341	

---
0-DAY kernel test infrastructure                 Open Source Technology Center
https://lists.01.org/hyperkitty/list/kbuild-all(a)lists.01.org Intel Corporation

[-- Attachment #2: config.gz --]
[-- Type: application/gzip, Size: 27903 bytes --]

^ permalink raw reply	[flat|nested] 63+ messages in thread

* Re: [PATCHv3/RFC 1/4] drm/arm: Factor out generic afbc helpers
  2019-11-21 17:22                               ` [PATCHv3/RFC 1/4] drm/arm: Factor out generic afbc helpers Andrzej Pietrasiewicz
  2019-11-23  7:13                                   ` Ezequiel Garcia
  2019-11-24 10:11                                 ` kbuild test robot
@ 2019-11-25  8:55                                 ` Daniel Vetter
  2019-11-26 20:27                                   ` Andrzej Pietrasiewicz
  2019-11-28 10:47                                   ` james qian wang (Arm Technology China)
  2 siblings, 2 replies; 63+ messages in thread
From: Daniel Vetter @ 2019-11-25  8:55 UTC (permalink / raw)
  To: Andrzej Pietrasiewicz
  Cc: Ayan Halder, kernel, David Airlie, Liviu Dudau, James Wang,
	dri-devel, Mihail Atanassov, Sean Paul

On Thu, Nov 21, 2019 at 06:22:44PM +0100, Andrzej Pietrasiewicz wrote:
> These are useful for other users of afbc, e.g. rockchip.
> 
> Signed-off-by: Andrzej Pietrasiewicz <andrzej.p@collabora.com>
> ---
>  drivers/gpu/drm/Makefile          |  2 +-
>  drivers/gpu/drm/drm_afbc.c        | 84 +++++++++++++++++++++++++++++++
>  drivers/gpu/drm/drm_fourcc.c      | 11 +++-
>  drivers/gpu/drm/drm_framebuffer.c | 71 +++++++++++++++++++++++++-
>  include/drm/drm_afbc.h            | 35 +++++++++++++
>  5 files changed, 199 insertions(+), 4 deletions(-)
>  create mode 100644 drivers/gpu/drm/drm_afbc.c
>  create mode 100644 include/drm/drm_afbc.h
> 
> diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile
> index d9bcc9f2a0a4..3a58f30b83a6 100644
> --- a/drivers/gpu/drm/Makefile
> +++ b/drivers/gpu/drm/Makefile
> @@ -44,7 +44,7 @@ drm_kms_helper-y := drm_crtc_helper.o drm_dp_helper.o drm_dsc.o drm_probe_helper
>  		drm_simple_kms_helper.o drm_modeset_helper.o \
>  		drm_scdc_helper.o drm_gem_framebuffer_helper.o \
>  		drm_atomic_state_helper.o drm_damage_helper.o \
> -		drm_format_helper.o drm_self_refresh_helper.o
> +		drm_format_helper.o drm_self_refresh_helper.o drm_afbc.o

Just a quick drive-by:
- you can't put this into helpers and call from core code. This should be
  core code. Also, I'd have just stuffed it into drm_format.c.

- If you want to keep your separate file, please include it in the doc
  template, next to the format handling functions.
>  
>  drm_kms_helper-$(CONFIG_DRM_PANEL_BRIDGE) += bridge/panel.o
>  drm_kms_helper-$(CONFIG_DRM_FBDEV_EMULATION) += drm_fb_helper.o
> diff --git a/drivers/gpu/drm/drm_afbc.c b/drivers/gpu/drm/drm_afbc.c
> new file mode 100644
> index 000000000000..f308c4719546
> --- /dev/null
> +++ b/drivers/gpu/drm/drm_afbc.c
> @@ -0,0 +1,84 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * (C) 2019 Collabora Ltd.
> + *
> + * author: Andrzej Pietrasiewicz <andrzej.p@collabora.com>
> + *
> + */
> +#include <linux/module.h>
> +
> +#include <drm/drm_afbc.h>
> +#include <drm/drm_device.h>
> +#include <drm/drm_fourcc.h>
> +#include <drm/drm_gem.h>
> +#include <drm/drm_mode.h>
> +#include <drm/drm_print.h>
> +
> +/**
> + * drm_afbc_get_superblk_wh - extract afbc block width/height from modifier
> + * @modifier: the modifier to be looked at
> + * @w: address of a place to store the block width
> + * @h: address of a place to store the block height
> + *
> + * Returns: true if the modifier describes a supported block size
> + */
> +bool drm_afbc_get_superblk_wh(u64 modifier, u32 *w, u32 *h)
> +{
> +	switch (modifier & AFBC_FORMAT_MOD_BLOCK_SIZE_MASK) {
> +	case AFBC_FORMAT_MOD_BLOCK_SIZE_16x16:
> +		*w = 16;
> +		*h = 16;
> +		break;
> +	case AFBC_FORMAT_MOD_BLOCK_SIZE_32x8:
> +		*w = 32;
> +		*h = 8;
> +		break;
> +	case AFBC_FORMAT_MOD_BLOCK_SIZE_64x4:
> +		/* fall through */
> +	case AFBC_FORMAT_MOD_BLOCK_SIZE_32x8_64x4:
> +		/* fall through */
> +	default:
> +		DRM_DEBUG_KMS("Invalid AFBC_FORMAT_MOD_BLOCK_SIZE: %lld.\n",
> +			      modifier & AFBC_FORMAT_MOD_BLOCK_SIZE_MASK);
> +		return false;
> +	}
> +	return true;
> +}
> +EXPORT_SYMBOL_GPL(drm_afbc_get_superblk_wh);
> +
> +/**
> + * drm_afbc_get_parameters - extract afbc parameters from mode command
> + * @mode_cmd: mode command to be looked at
> + * @afbc: address of a struct to be filled in
> + */
> +void drm_afbc_get_parameters(const struct drm_mode_fb_cmd2 *mode_cmd,
> +			     struct drm_afbc *afbc)
> +{
> +	drm_afbc_get_superblk_wh(mode_cmd->modifier[0],
> +				 &afbc->tile_w, &afbc->tile_h);
> +	afbc->width = mode_cmd->pitches[0];
> +	afbc->height =
> +		DIV_ROUND_UP(mode_cmd->height, afbc->tile_h) * afbc->tile_h;
> +	afbc->offset = mode_cmd->offsets[0];
> +}
> +EXPORT_SYMBOL(drm_afbc_get_parameters);
> +
> +/**
> + * drm_is_afbc - test if the modifier describes an afbc buffer
> + * @modifier - modifier to be tested
> + *
> + * Returns: true if the modifier describes an afbc buffer
> + */
> +bool drm_is_afbc(u64 modifier)
> +{
> +	/* is it ARM AFBC? */
> +	if ((modifier & DRM_FORMAT_MOD_ARM_AFBC(0)) == 0)
> +		return false;
> +
> +	/* Block size must be known */
> +	if ((modifier & AFBC_FORMAT_MOD_BLOCK_SIZE_MASK) == 0)
> +		return false;
> +
> +	return true;
> +}
> +EXPORT_SYMBOL_GPL(drm_is_afbc);
> diff --git a/drivers/gpu/drm/drm_fourcc.c b/drivers/gpu/drm/drm_fourcc.c
> index c630064ccf41..8d9f197cc0ab 100644
> --- a/drivers/gpu/drm/drm_fourcc.c
> +++ b/drivers/gpu/drm/drm_fourcc.c
> @@ -27,6 +27,7 @@
>  #include <linux/export.h>
>  #include <linux/kernel.h>
>  
> +#include <drm/drm_afbc.h>
>  #include <drm/drm_device.h>
>  #include <drm/drm_fourcc.h>
>  
> @@ -322,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..303eea624a02 100644
> --- a/drivers/gpu/drm/drm_framebuffer.c
> +++ b/drivers/gpu/drm/drm_framebuffer.c
> @@ -23,6 +23,7 @@
>  #include <linux/export.h>
>  #include <linux/uaccess.h>
>  
> +#include <drm/drm_afbc.h>
>  #include <drm/drm_atomic.h>
>  #include <drm/drm_atomic_uapi.h>
>  #include <drm/drm_auth.h>
> @@ -31,6 +32,7 @@
>  #include <drm/drm_file.h>
>  #include <drm/drm_fourcc.h>
>  #include <drm/drm_framebuffer.h>
> +#include <drm/drm_gem.h>
>  #include <drm/drm_print.h>
>  #include <drm/drm_util.h>
>  
> @@ -168,7 +170,69 @@ static int fb_plane_height(int height,
>  	return DIV_ROUND_UP(height, format->vsub);
>  }
>  
> +static int afbc_check(struct drm_file *file_priv,
> +		      const struct drm_mode_fb_cmd2 *r, int i,
> +		      const struct drm_format_info *info)
> +{
> +	struct drm_gem_object *obj;
> +	int bpp = info->cpp[0] * 8;
> +	int tiles;
> +	u32 w, h, height, tile_sz, afbc_size;
> +	int result = 0;
> +
> +	if (i) {
> +		DRM_DEBUG_KMS("AFBC supported only for plane 0\n");
> +
> +		return 1;
> +	}
> +
> +	/* get tile w/h */
> +	if (!drm_afbc_get_superblk_wh(r->modifier[0], &w, &h))
> +		return 1;
> +
> +	/* pitch must be divisible by tile width */
> +	if (r->pitches[0] % w) {
> +		DRM_DEBUG_KMS("Invalid pitch for plane %d\n", i);
> +
> +		return 1;
> +	}
> +
> +	obj = drm_gem_object_lookup(file_priv, r->handles[0]);

I think this is a bit ugly ... I'd split this into a new
framebuffer_check_post() function which is called after fb_create, at that
point you do have the objects already looked up.

Also I suggested that this could be done as a helper implementation for
fb_create, wrapping it around the default gem implementation. That way you
could keep all the afbc stuff in helpers entirely (but drivers could screw
things up, so there's a tradeoff).

What's definitely not ok is calling drm_gem_object_lookup unconditionally
from core code here. For consistency I think the helper approach would be
good, since currently the size related checks are done in
drm_gem_fb_create() - i.e. in the helpers, not in core. Otoh having checks
split like this is also ugly, so maybe we should have a
framebuffer_check_post for everyone, and move all the size checks into
core (not just for afbc).
-Daniel

> +	if (!obj) {
> +		DRM_DEBUG_KMS("Failed to lookup GEM object\n");
> +
> +		return 1;
> +	}
> +
> +	/* estimate height based on tile size and height from userspace */
> +	height = DIV_ROUND_UP(r->height, h) * h;
> +
> +	tiles = (r->pitches[0] / w) * (height / h);
> +	afbc_size = ALIGN(tiles * AFBC_HEADER_SIZE, AFBC_SUPERBLK_ALIGNMENT);
> +
> +	tile_sz = (bpp * w * h) / BITS_PER_BYTE;
> +	afbc_size += tiles * ALIGN(tile_sz, AFBC_SUPERBLK_ALIGNMENT);
> +
> +	result = obj->size < afbc_size;
> +
> +	drm_gem_object_put_unlocked(obj);
> +
> +	return result;
> +}
> +
> +static int modifier_check(struct drm_file *file_priv,
> +			  const struct drm_mode_fb_cmd2 *r, int i,
> +			  const struct drm_format_info *info)
> +{
> +	/* non-afbc format */
> +	if (!drm_is_afbc(r->modifier[i]))
> +		return 0;
> +
> +	return afbc_check(file_priv, r, i, info);
> +}
> +
>  static int framebuffer_check(struct drm_device *dev,
> +			     struct drm_file *file_priv,
>  			     const struct drm_mode_fb_cmd2 *r)
>  {
>  	const struct drm_format_info *info;
> @@ -204,6 +268,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;
> @@ -253,6 +320,8 @@ static int framebuffer_check(struct drm_device *dev,
>  			break;
>  
>  		default:
> +			if (modifier_check(file_priv, r, i, info))
> +				return -EINVAL;
>  			break;
>  		}
>  	}
> @@ -317,7 +386,7 @@ drm_internal_framebuffer_create(struct drm_device *dev,
>  		return ERR_PTR(-EINVAL);
>  	}
>  
> -	ret = framebuffer_check(dev, r);
> +	ret = framebuffer_check(dev, file_priv, r);
>  	if (ret)
>  		return ERR_PTR(ret);
>  
> diff --git a/include/drm/drm_afbc.h b/include/drm/drm_afbc.h
> new file mode 100644
> index 000000000000..fb4d4549f77e
> --- /dev/null
> +++ b/include/drm/drm_afbc.h
> @@ -0,0 +1,35 @@
> +/* SPDX-License-Identifier: GPL-2.0+ */
> +/*
> + * (C) 2019 Collabora Ltd.
> + *
> + * author: Andrzej Pietrasiewicz <andrzej.p@collabora.com>
> + *
> + */
> +#ifndef __DRM_AFBC_H__
> +#define __DRM_AFBC_H__
> +
> +#include <linux/types.h>
> +
> +struct drm_device;
> +struct drm_mode_fb_cmd2;
> +struct drm_gem_object;
> +
> +struct drm_afbc {
> +	u32 tile_w;
> +	u32 tile_h;
> +	u32 width;
> +	u32 height;
> +	u32 offset;
> +};
> +
> +#define AFBC_HEADER_SIZE		16
> +#define AFBC_SUPERBLK_ALIGNMENT		128
> +
> +bool drm_afbc_get_superblk_wh(u64 modifier, u32 *w, u32 *h);
> +
> +void drm_afbc_get_parameters(const struct drm_mode_fb_cmd2 *mode_cmd,
> +			     struct drm_afbc *afbc);
> +
> +bool drm_is_afbc(u64 modifier);
> +
> +#endif /* __DRM_AFBC_H__ */
> -- 
> 2.17.1
> 

-- 
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 63+ messages in thread

* Re: [PATCHv3/RFC 1/4] drm/arm: Factor out generic afbc helpers
  2019-11-25  8:55                                 ` Daniel Vetter
@ 2019-11-26 20:27                                   ` Andrzej Pietrasiewicz
  2019-11-27  9:51                                     ` Daniel Vetter
  2019-11-28 10:47                                   ` james qian wang (Arm Technology China)
  1 sibling, 1 reply; 63+ messages in thread
From: Andrzej Pietrasiewicz @ 2019-11-26 20:27 UTC (permalink / raw)
  To: Daniel Vetter
  Cc: kernel, Mihail Atanassov, David Airlie, Liviu Dudau, dri-devel,
	James Wang, Ayan Halder, Sean Paul

Hi Daniel,

Thanks for the comments, please see inline

W dniu 25.11.2019 o 09:55, Daniel Vetter pisze:
> On Thu, Nov 21, 2019 at 06:22:44PM +0100, Andrzej Pietrasiewicz wrote:
>> These are useful for other users of afbc, e.g. rockchip.
>>
>> Signed-off-by: Andrzej Pietrasiewicz <andrzej.p@collabora.com>
>> ---
>>   drivers/gpu/drm/Makefile          |  2 +-
>>   drivers/gpu/drm/drm_afbc.c        | 84 +++++++++++++++++++++++++++++++
>>   drivers/gpu/drm/drm_fourcc.c      | 11 +++-
>>   drivers/gpu/drm/drm_framebuffer.c | 71 +++++++++++++++++++++++++-
>>   include/drm/drm_afbc.h            | 35 +++++++++++++
>>   5 files changed, 199 insertions(+), 4 deletions(-)
>>   create mode 100644 drivers/gpu/drm/drm_afbc.c
>>   create mode 100644 include/drm/drm_afbc.h
>>
>> diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile
>> index d9bcc9f2a0a4..3a58f30b83a6 100644
>> --- a/drivers/gpu/drm/Makefile
>> +++ b/drivers/gpu/drm/Makefile
>> @@ -44,7 +44,7 @@ drm_kms_helper-y := drm_crtc_helper.o drm_dp_helper.o drm_dsc.o drm_probe_helper
>>   		drm_simple_kms_helper.o drm_modeset_helper.o \
>>   		drm_scdc_helper.o drm_gem_framebuffer_helper.o \
>>   		drm_atomic_state_helper.o drm_damage_helper.o \
>> -		drm_format_helper.o drm_self_refresh_helper.o
>> +		drm_format_helper.o drm_self_refresh_helper.o drm_afbc.o
> 
> Just a quick drive-by:
> - you can't put this into helpers and call from core code. This should be
>    core code. Also, I'd have just stuffed it into drm_format.c.
> 

drm_format.c does not exist. Did you mean drm_format_helper.c?

<snip>

>> diff --git a/drivers/gpu/drm/drm_framebuffer.c b/drivers/gpu/drm/drm_framebuffer.c
>> index 57564318ceea..303eea624a02 100644
>> --- a/drivers/gpu/drm/drm_framebuffer.c
>> +++ b/drivers/gpu/drm/drm_framebuffer.c
>> @@ -23,6 +23,7 @@
>>   #include <linux/export.h>
>>   #include <linux/uaccess.h>
>>   
>> +#include <drm/drm_afbc.h>
>>   #include <drm/drm_atomic.h>
>>   #include <drm/drm_atomic_uapi.h>
>>   #include <drm/drm_auth.h>
>> @@ -31,6 +32,7 @@
>>   #include <drm/drm_file.h>
>>   #include <drm/drm_fourcc.h>
>>   #include <drm/drm_framebuffer.h>
>> +#include <drm/drm_gem.h>
>>   #include <drm/drm_print.h>
>>   #include <drm/drm_util.h>
>>   
>> @@ -168,7 +170,69 @@ static int fb_plane_height(int height,
>>   	return DIV_ROUND_UP(height, format->vsub);
>>   }
>>   
>> +static int afbc_check(struct drm_file *file_priv,
>> +		      const struct drm_mode_fb_cmd2 *r, int i,
>> +		      const struct drm_format_info *info)
>> +{
>> +	struct drm_gem_object *obj;
>> +	int bpp = info->cpp[0] * 8;
>> +	int tiles;
>> +	u32 w, h, height, tile_sz, afbc_size;
>> +	int result = 0;
>> +
>> +	if (i) {
>> +		DRM_DEBUG_KMS("AFBC supported only for plane 0\n");
>> +
>> +		return 1;
>> +	}
>> +
>> +	/* get tile w/h */
>> +	if (!drm_afbc_get_superblk_wh(r->modifier[0], &w, &h))
>> +		return 1;
>> +
>> +	/* pitch must be divisible by tile width */
>> +	if (r->pitches[0] % w) {
>> +		DRM_DEBUG_KMS("Invalid pitch for plane %d\n", i);
>> +
>> +		return 1;
>> +	}
>> +
>> +	obj = drm_gem_object_lookup(file_priv, r->handles[0]);
> 
> I think this is a bit ugly ... I'd split this into a new
> framebuffer_check_post() function which is called after fb_create, at that
> point you do have the objects already looked up.
> 
> Also I suggested that this could be done as a helper implementation for
> fb_create, wrapping it around the default gem implementation. That way you
> could keep all the afbc stuff in helpers entirely (but drivers could screw
> things up, so there's a tradeoff).
> 
> What's definitely not ok is calling drm_gem_object_lookup unconditionally
> from core code here. For consistency I think the helper approach would be
> good, since currently the size related checks are done in
> drm_gem_fb_create() - i.e. in the helpers, not in core. Otoh having checks
> split like this is also ugly, so maybe we should have a
> framebuffer_check_post for everyone, and move all the size checks into
> core (not just for afbc).
> -Daniel

As far as I understand you see more than one way forward.
Can you please comment on the below? And in particular, can you say
if I understood you correctly? So, my understanding of what you
said above is to either:

1) move the part of the code which requires objects to be looked up
to a new framebuffer_check_post() called after fb_create, that is
from drm_internal_framebuffer_create() after

fb = dev->mode_config.funcs->fb_create(dev, file_priv, r);

because at that point the objects have already been looked up.
How driver-specific checks can be done in this scheme?

or

2) Move the body of afbc_check() to a helper implementation to be used by
driver-specific fb_create implementations. Sorry for my ignorance, it seems
that "helpers" and "core" have precise meaning here but I don't quite
understand what is what of what, so I also don't quite understand where
to move the code to and why this would mean keeping all the afbc stuff
entirely in helpers :O Can you explain?

Did you mean that all the checking code is called by specific drivers
on an opt-in basis? I thought you were not in favor of drivers opting-in,
as some of them might opt-in while some others opt-out, or use different
subsets of available checks.

or

3) e.g. rockchip does not use drm_gem_fb_create(). It uses
drm_gem_fb_create_handle(), though. Anyway, the third way forward
is to have framebuffer_check_post() as in 1) and move the size checks
to "core" - which I don't quite understand where exactly it is.
What is the difference to 1)?

> 
>> +	if (!obj) {
>> +		DRM_DEBUG_KMS("Failed to lookup GEM object\n");
>> +
>> +		return 1;
>> +	}
>> +
>> +	/* estimate height based on tile size and height from userspace */
>> +	height = DIV_ROUND_UP(r->height, h) * h;
>> +
>> +	tiles = (r->pitches[0] / w) * (height / h);
>> +	afbc_size = ALIGN(tiles * AFBC_HEADER_SIZE, AFBC_SUPERBLK_ALIGNMENT);

This computation is for malidp/rockchip, but for komeda the alignment
is different. So it seems it is driver-specific. If so, we need
some way for specific drivers to provide their specific checks
and/or specific data for generic checking code to use.

Thanks

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

^ permalink raw reply	[flat|nested] 63+ messages in thread

* Re: [PATCHv3/RFC 1/4] drm/arm: Factor out generic afbc helpers
  2019-11-26 20:27                                   ` Andrzej Pietrasiewicz
@ 2019-11-27  9:51                                     ` Daniel Vetter
  0 siblings, 0 replies; 63+ messages in thread
From: Daniel Vetter @ 2019-11-27  9:51 UTC (permalink / raw)
  To: Andrzej Pietrasiewicz
  Cc: kernel, Mihail Atanassov, David Airlie, Liviu Dudau, dri-devel,
	James Wang, Ayan Halder, Sean Paul

On Tue, Nov 26, 2019 at 09:27:59PM +0100, Andrzej Pietrasiewicz wrote:
> Hi Daniel,
> 
> Thanks for the comments, please see inline
> 
> W dniu 25.11.2019 o 09:55, Daniel Vetter pisze:
> > On Thu, Nov 21, 2019 at 06:22:44PM +0100, Andrzej Pietrasiewicz wrote:
> > > These are useful for other users of afbc, e.g. rockchip.
> > > 
> > > Signed-off-by: Andrzej Pietrasiewicz <andrzej.p@collabora.com>
> > > ---
> > >   drivers/gpu/drm/Makefile          |  2 +-
> > >   drivers/gpu/drm/drm_afbc.c        | 84 +++++++++++++++++++++++++++++++
> > >   drivers/gpu/drm/drm_fourcc.c      | 11 +++-
> > >   drivers/gpu/drm/drm_framebuffer.c | 71 +++++++++++++++++++++++++-
> > >   include/drm/drm_afbc.h            | 35 +++++++++++++
> > >   5 files changed, 199 insertions(+), 4 deletions(-)
> > >   create mode 100644 drivers/gpu/drm/drm_afbc.c
> > >   create mode 100644 include/drm/drm_afbc.h
> > > 
> > > diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile
> > > index d9bcc9f2a0a4..3a58f30b83a6 100644
> > > --- a/drivers/gpu/drm/Makefile
> > > +++ b/drivers/gpu/drm/Makefile
> > > @@ -44,7 +44,7 @@ drm_kms_helper-y := drm_crtc_helper.o drm_dp_helper.o drm_dsc.o drm_probe_helper
> > >   		drm_simple_kms_helper.o drm_modeset_helper.o \
> > >   		drm_scdc_helper.o drm_gem_framebuffer_helper.o \
> > >   		drm_atomic_state_helper.o drm_damage_helper.o \
> > > -		drm_format_helper.o drm_self_refresh_helper.o
> > > +		drm_format_helper.o drm_self_refresh_helper.o drm_afbc.o
> > 
> > Just a quick drive-by:
> > - you can't put this into helpers and call from core code. This should be
> >    core code. Also, I'd have just stuffed it into drm_format.c.
> > 
> 
> drm_format.c does not exist. Did you mean drm_format_helper.c?

drm_fourcc.c. You can't put this into a helper and call it from core code,
it wont link for modular builds.

> <snip>
> 
> > > diff --git a/drivers/gpu/drm/drm_framebuffer.c b/drivers/gpu/drm/drm_framebuffer.c
> > > index 57564318ceea..303eea624a02 100644
> > > --- a/drivers/gpu/drm/drm_framebuffer.c
> > > +++ b/drivers/gpu/drm/drm_framebuffer.c
> > > @@ -23,6 +23,7 @@
> > >   #include <linux/export.h>
> > >   #include <linux/uaccess.h>
> > > +#include <drm/drm_afbc.h>
> > >   #include <drm/drm_atomic.h>
> > >   #include <drm/drm_atomic_uapi.h>
> > >   #include <drm/drm_auth.h>
> > > @@ -31,6 +32,7 @@
> > >   #include <drm/drm_file.h>
> > >   #include <drm/drm_fourcc.h>
> > >   #include <drm/drm_framebuffer.h>
> > > +#include <drm/drm_gem.h>
> > >   #include <drm/drm_print.h>
> > >   #include <drm/drm_util.h>
> > > @@ -168,7 +170,69 @@ static int fb_plane_height(int height,
> > >   	return DIV_ROUND_UP(height, format->vsub);
> > >   }
> > > +static int afbc_check(struct drm_file *file_priv,
> > > +		      const struct drm_mode_fb_cmd2 *r, int i,
> > > +		      const struct drm_format_info *info)
> > > +{
> > > +	struct drm_gem_object *obj;
> > > +	int bpp = info->cpp[0] * 8;
> > > +	int tiles;
> > > +	u32 w, h, height, tile_sz, afbc_size;
> > > +	int result = 0;
> > > +
> > > +	if (i) {
> > > +		DRM_DEBUG_KMS("AFBC supported only for plane 0\n");
> > > +
> > > +		return 1;
> > > +	}
> > > +
> > > +	/* get tile w/h */
> > > +	if (!drm_afbc_get_superblk_wh(r->modifier[0], &w, &h))
> > > +		return 1;
> > > +
> > > +	/* pitch must be divisible by tile width */
> > > +	if (r->pitches[0] % w) {
> > > +		DRM_DEBUG_KMS("Invalid pitch for plane %d\n", i);
> > > +
> > > +		return 1;
> > > +	}
> > > +
> > > +	obj = drm_gem_object_lookup(file_priv, r->handles[0]);
> > 
> > I think this is a bit ugly ... I'd split this into a new
> > framebuffer_check_post() function which is called after fb_create, at that
> > point you do have the objects already looked up.
> > 
> > Also I suggested that this could be done as a helper implementation for
> > fb_create, wrapping it around the default gem implementation. That way you
> > could keep all the afbc stuff in helpers entirely (but drivers could screw
> > things up, so there's a tradeoff).
> > 
> > What's definitely not ok is calling drm_gem_object_lookup unconditionally
> > from core code here. For consistency I think the helper approach would be
> > good, since currently the size related checks are done in
> > drm_gem_fb_create() - i.e. in the helpers, not in core. Otoh having checks
> > split like this is also ugly, so maybe we should have a
> > framebuffer_check_post for everyone, and move all the size checks into
> > core (not just for afbc).
> > -Daniel
> 
> As far as I understand you see more than one way forward.
> Can you please comment on the below? And in particular, can you say
> if I understood you correctly? So, my understanding of what you
> said above is to either:
> 
> 1) move the part of the code which requires objects to be looked up
> to a new framebuffer_check_post() called after fb_create, that is
> from drm_internal_framebuffer_create() after
> 
> fb = dev->mode_config.funcs->fb_create(dev, file_priv, r);
> 
> because at that point the objects have already been looked up.
> How driver-specific checks can be done in this scheme?

Yup that's one way of doing it. Still feels a bit icky.

> or
> 
> 2) Move the body of afbc_check() to a helper implementation to be used by
> driver-specific fb_create implementations. Sorry for my ignorance, it seems
> that "helpers" and "core" have precise meaning here but I don't quite
> understand what is what of what, so I also don't quite understand where
> to move the code to and why this would mean keeping all the afbc stuff
> entirely in helpers :O Can you explain?

That's the 2nd option, where 2a would be putting the checks into
drm_gem_fb_create_with_funcs(). That would at least be consistent with the
existing placement of size related checks we have.

For more context on core vs midlayer:

https://blog.ffwll.ch/2016/12/midlayers-once-more-with-feeling.html

The first few paragraphs have a pile of links with what this means for
kernel hackers.

In this case specifically the choice of using gem as backing storage for
drm_framebuffer is up to drivers, and hence anything gem related should be
in opt-in helpers. Although we only have 1 driver not using gem, so we
standardized this a lot and somewhat muddied the core/helper separation
here. Still, we should at least try to be consistent across the different
formats and checks.

> Did you mean that all the checking code is called by specific drivers
> on an opt-in basis? I thought you were not in favor of drivers opting-in,
> as some of them might opt-in while some others opt-out, or use different
> subsets of available checks.
> 
> or
> 
> 3) e.g. rockchip does not use drm_gem_fb_create(). It uses
> drm_gem_fb_create_handle(), though. Anyway, the third way forward
> is to have framebuffer_check_post() as in 1) and move the size checks
> to "core" - which I don't quite understand where exactly it is.
> What is the difference to 1)?

create_handle is a different ioctl, it's called from the GETFB ioctl. We'd
need to move the fb_create hook over to helpers for rockchip, and you're
lucky, I have a patch for you:

"drm/rockchip: Use drm_gem_fb_create_with_dirty"

Can you pls review/test that one?

Thanks, Daniel

> 
> > 
> > > +	if (!obj) {
> > > +		DRM_DEBUG_KMS("Failed to lookup GEM object\n");
> > > +
> > > +		return 1;
> > > +	}
> > > +
> > > +	/* estimate height based on tile size and height from userspace */
> > > +	height = DIV_ROUND_UP(r->height, h) * h;
> > > +
> > > +	tiles = (r->pitches[0] / w) * (height / h);
> > > +	afbc_size = ALIGN(tiles * AFBC_HEADER_SIZE, AFBC_SUPERBLK_ALIGNMENT);
> 
> This computation is for malidp/rockchip, but for komeda the alignment
> is different. So it seems it is driver-specific. If so, we need
> some way for specific drivers to provide their specific checks
> and/or specific data for generic checking code to use.
> 
> Thanks
> 
> Andrzej

-- 
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 63+ messages in thread

* Re: [PATCHv3/RFC 1/4] drm/arm: Factor out generic afbc helpers
  2019-11-25  8:55                                 ` Daniel Vetter
  2019-11-26 20:27                                   ` Andrzej Pietrasiewicz
@ 2019-11-28 10:47                                   ` james qian wang (Arm Technology China)
  1 sibling, 0 replies; 63+ messages in thread
From: james qian wang (Arm Technology China) @ 2019-11-28 10:47 UTC (permalink / raw)
  To: Daniel Vetter
  Cc: nd, Ayan Halder, kernel, David Airlie, Liviu Dudau,
	Andrzej Pietrasiewicz, dri-devel, Mihail Atanassov, Sean Paul

On Mon, Nov 25, 2019 at 09:55:06AM +0100, Daniel Vetter wrote:
> On Thu, Nov 21, 2019 at 06:22:44PM +0100, Andrzej Pietrasiewicz wrote:
> > These are useful for other users of afbc, e.g. rockchip.
> > 
> > Signed-off-by: Andrzej Pietrasiewicz <andrzej.p@collabora.com>
> > ---
> >  drivers/gpu/drm/Makefile          |  2 +-
> >  drivers/gpu/drm/drm_afbc.c        | 84 +++++++++++++++++++++++++++++++
> >  drivers/gpu/drm/drm_fourcc.c      | 11 +++-
> >  drivers/gpu/drm/drm_framebuffer.c | 71 +++++++++++++++++++++++++-
> >  include/drm/drm_afbc.h            | 35 +++++++++++++
> >  5 files changed, 199 insertions(+), 4 deletions(-)
> >  create mode 100644 drivers/gpu/drm/drm_afbc.c
> >  create mode 100644 include/drm/drm_afbc.h
> > 
> > diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile
> > index d9bcc9f2a0a4..3a58f30b83a6 100644
> > --- a/drivers/gpu/drm/Makefile
> > +++ b/drivers/gpu/drm/Makefile
> > @@ -44,7 +44,7 @@ drm_kms_helper-y := drm_crtc_helper.o drm_dp_helper.o drm_dsc.o drm_probe_helper
> >  		drm_simple_kms_helper.o drm_modeset_helper.o \
> >  		drm_scdc_helper.o drm_gem_framebuffer_helper.o \
> >  		drm_atomic_state_helper.o drm_damage_helper.o \
> > -		drm_format_helper.o drm_self_refresh_helper.o
> > +		drm_format_helper.o drm_self_refresh_helper.o drm_afbc.o
> 
> Just a quick drive-by:
> - you can't put this into helpers and call from core code. This should be
>   core code. Also, I'd have just stuffed it into drm_format.c.
> 
> - If you want to keep your separate file, please include it in the doc
>   template, next to the format handling functions.
> >  
> >  drm_kms_helper-$(CONFIG_DRM_PANEL_BRIDGE) += bridge/panel.o
> >  drm_kms_helper-$(CONFIG_DRM_FBDEV_EMULATION) += drm_fb_helper.o
> > diff --git a/drivers/gpu/drm/drm_afbc.c b/drivers/gpu/drm/drm_afbc.c
> > new file mode 100644
> > index 000000000000..f308c4719546
> > --- /dev/null
> > +++ b/drivers/gpu/drm/drm_afbc.c
> > @@ -0,0 +1,84 @@
> > +// SPDX-License-Identifier: GPL-2.0
> > +/*
> > + * (C) 2019 Collabora Ltd.
> > + *
> > + * author: Andrzej Pietrasiewicz <andrzej.p@collabora.com>
> > + *
> > + */
> > +#include <linux/module.h>
> > +
> > +#include <drm/drm_afbc.h>
> > +#include <drm/drm_device.h>
> > +#include <drm/drm_fourcc.h>
> > +#include <drm/drm_gem.h>
> > +#include <drm/drm_mode.h>
> > +#include <drm/drm_print.h>
> > +
> > +/**
> > + * drm_afbc_get_superblk_wh - extract afbc block width/height from modifier
> > + * @modifier: the modifier to be looked at
> > + * @w: address of a place to store the block width
> > + * @h: address of a place to store the block height
> > + *
> > + * Returns: true if the modifier describes a supported block size
> > + */
> > +bool drm_afbc_get_superblk_wh(u64 modifier, u32 *w, u32 *h)
> > +{
> > +	switch (modifier & AFBC_FORMAT_MOD_BLOCK_SIZE_MASK) {
> > +	case AFBC_FORMAT_MOD_BLOCK_SIZE_16x16:
> > +		*w = 16;
> > +		*h = 16;
> > +		break;
> > +	case AFBC_FORMAT_MOD_BLOCK_SIZE_32x8:
> > +		*w = 32;
> > +		*h = 8;
> > +		break;
> > +	case AFBC_FORMAT_MOD_BLOCK_SIZE_64x4:
> > +		/* fall through */
> > +	case AFBC_FORMAT_MOD_BLOCK_SIZE_32x8_64x4:
> > +		/* fall through */
> > +	default:
> > +		DRM_DEBUG_KMS("Invalid AFBC_FORMAT_MOD_BLOCK_SIZE: %lld.\n",
> > +			      modifier & AFBC_FORMAT_MOD_BLOCK_SIZE_MASK);
> > +		return false;
> > +	}
> > +	return true;
> > +}
> > +EXPORT_SYMBOL_GPL(drm_afbc_get_superblk_wh);
> > +
> > +/**
> > + * drm_afbc_get_parameters - extract afbc parameters from mode command
> > + * @mode_cmd: mode command to be looked at
> > + * @afbc: address of a struct to be filled in
> > + */
> > +void drm_afbc_get_parameters(const struct drm_mode_fb_cmd2 *mode_cmd,
> > +			     struct drm_afbc *afbc)
> > +{
> > +	drm_afbc_get_superblk_wh(mode_cmd->modifier[0],
> > +				 &afbc->tile_w, &afbc->tile_h);
> > +	afbc->width = mode_cmd->pitches[0];
> > +	afbc->height =
> > +		DIV_ROUND_UP(mode_cmd->height, afbc->tile_h) * afbc->tile_h;
> > +	afbc->offset = mode_cmd->offsets[0];
> > +}
> > +EXPORT_SYMBOL(drm_afbc_get_parameters);
> > +
> > +/**
> > + * drm_is_afbc - test if the modifier describes an afbc buffer
> > + * @modifier - modifier to be tested
> > + *
> > + * Returns: true if the modifier describes an afbc buffer
> > + */
> > +bool drm_is_afbc(u64 modifier)
> > +{
> > +	/* is it ARM AFBC? */
> > +	if ((modifier & DRM_FORMAT_MOD_ARM_AFBC(0)) == 0)
> > +		return false;
> > +
> > +	/* Block size must be known */
> > +	if ((modifier & AFBC_FORMAT_MOD_BLOCK_SIZE_MASK) == 0)
> > +		return false;
> > +
> > +	return true;
> > +}
> > +EXPORT_SYMBOL_GPL(drm_is_afbc);
> > diff --git a/drivers/gpu/drm/drm_fourcc.c b/drivers/gpu/drm/drm_fourcc.c
> > index c630064ccf41..8d9f197cc0ab 100644
> > --- a/drivers/gpu/drm/drm_fourcc.c
> > +++ b/drivers/gpu/drm/drm_fourcc.c
> > @@ -27,6 +27,7 @@
> >  #include <linux/export.h>
> >  #include <linux/kernel.h>
> >  
> > +#include <drm/drm_afbc.h>
> >  #include <drm/drm_device.h>
> >  #include <drm/drm_fourcc.h>
> >  
> > @@ -322,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..303eea624a02 100644
> > --- a/drivers/gpu/drm/drm_framebuffer.c
> > +++ b/drivers/gpu/drm/drm_framebuffer.c
> > @@ -23,6 +23,7 @@
> >  #include <linux/export.h>
> >  #include <linux/uaccess.h>
> >  
> > +#include <drm/drm_afbc.h>
> >  #include <drm/drm_atomic.h>
> >  #include <drm/drm_atomic_uapi.h>
> >  #include <drm/drm_auth.h>
> > @@ -31,6 +32,7 @@
> >  #include <drm/drm_file.h>
> >  #include <drm/drm_fourcc.h>
> >  #include <drm/drm_framebuffer.h>
> > +#include <drm/drm_gem.h>
> >  #include <drm/drm_print.h>
> >  #include <drm/drm_util.h>
> >  
> > @@ -168,7 +170,69 @@ static int fb_plane_height(int height,
> >  	return DIV_ROUND_UP(height, format->vsub);
> >  }
> >  
> > +static int afbc_check(struct drm_file *file_priv,
> > +		      const struct drm_mode_fb_cmd2 *r, int i,
> > +		      const struct drm_format_info *info)
> > +{
> > +	struct drm_gem_object *obj;
> > +	int bpp = info->cpp[0] * 8;
> > +	int tiles;
> > +	u32 w, h, height, tile_sz, afbc_size;
> > +	int result = 0;
> > +
> > +	if (i) {
> > +		DRM_DEBUG_KMS("AFBC supported only for plane 0\n");
> > +
> > +		return 1;
> > +	}
> > +
> > +	/* get tile w/h */
> > +	if (!drm_afbc_get_superblk_wh(r->modifier[0], &w, &h))
> > +		return 1;
> > +
> > +	/* pitch must be divisible by tile width */
> > +	if (r->pitches[0] % w) {
> > +		DRM_DEBUG_KMS("Invalid pitch for plane %d\n", i);
> > +
> > +		return 1;
> > +	}
> > +
> > +	obj = drm_gem_object_lookup(file_priv, r->handles[0]);
> 
> I think this is a bit ugly ... I'd split this into a new
> framebuffer_check_post() function which is called after fb_create, at that
> point you do have the objects already looked up.
> 
> Also I suggested that this could be done as a helper implementation for
> fb_create, wrapping it around the default gem implementation. That way you
> could keep all the afbc stuff in helpers entirely (but drivers could screw
> things up, so there's a tradeoff).
> 
> What's definitely not ok is calling drm_gem_object_lookup unconditionally
> from core code here. For consistency I think the helper approach would be
> good, since currently the size related checks are done in
> drm_gem_fb_create() - i.e. in the helpers, not in core. Otoh having checks
> split like this is also ugly, so maybe we should have a
> framebuffer_check_post for everyone, and move all the size checks into
> core (not just for afbc).
> -Daniel
> 
> > +	if (!obj) {
> > +		DRM_DEBUG_KMS("Failed to lookup GEM object\n");
> > +
> > +		return 1;
> > +	}
> > +
> > +	/* estimate height based on tile size and height from userspace */
> > +	height = DIV_ROUND_UP(r->height, h) * h;
> > +
> > +	tiles = (r->pitches[0] / w) * (height / h);
> > +	afbc_size = ALIGN(tiles * AFBC_HEADER_SIZE, AFBC_SUPERBLK_ALIGNMENT);
> > +
> > +	tile_sz = (bpp * w * h) / BITS_PER_BYTE;
> > +	afbc_size += tiles * ALIGN(tile_sz, AFBC_SUPERBLK_ALIGNMENT);
> > +
> > +	result = obj->size < afbc_size;
> > +
> > +	drm_gem_object_put_unlocked(obj);
> > +
> > +	return result;
> > +}
> > +
> > +static int modifier_check(struct drm_file *file_priv,
> > +			  const struct drm_mode_fb_cmd2 *r, int i,
> > +			  const struct drm_format_info *info)
> > +{
> > +	/* non-afbc format */
> > +	if (!drm_is_afbc(r->modifier[i]))
> > +		return 0;
> > +
> > +	return afbc_check(file_priv, r, i, info);
> > +}
> > +
> >  static int framebuffer_check(struct drm_device *dev,
> > +			     struct drm_file *file_priv,
> >  			     const struct drm_mode_fb_cmd2 *r)
> >  {
> >  	const struct drm_format_info *info;
> > @@ -204,6 +268,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;
> > @@ -253,6 +320,8 @@ static int framebuffer_check(struct drm_device *dev,
> >  			break;
> >  
> >  		default:
> > +			if (modifier_check(file_priv, r, i, info))
> > +				return -EINVAL;
> >  			break;
> >  		}
> >  	}
> > @@ -317,7 +386,7 @@ drm_internal_framebuffer_create(struct drm_device *dev,
> >  		return ERR_PTR(-EINVAL);
> >  	}
> >  
> > -	ret = framebuffer_check(dev, r);
> > +	ret = framebuffer_check(dev, file_priv, r);
> >  	if (ret)
> >  		return ERR_PTR(ret);
> >  
> > diff --git a/include/drm/drm_afbc.h b/include/drm/drm_afbc.h
> > new file mode 100644
> > index 000000000000..fb4d4549f77e
> > --- /dev/null
> > +++ b/include/drm/drm_afbc.h
> > @@ -0,0 +1,35 @@
> > +/* SPDX-License-Identifier: GPL-2.0+ */
> > +/*
> > + * (C) 2019 Collabora Ltd.
> > + *
> > + * author: Andrzej Pietrasiewicz <andrzej.p@collabora.com>
> > + *
> > + */
> > +#ifndef __DRM_AFBC_H__
> > +#define __DRM_AFBC_H__
> > +
> > +#include <linux/types.h>
> > +
> > +struct drm_device;
> > +struct drm_mode_fb_cmd2;
> > +struct drm_gem_object;
> > +
> > +struct drm_afbc {
> > +	u32 tile_w;
> > +	u32 tile_h;
> > +	u32 width;
> > +	u32 height;
> > +	u32 offset;
> > +};
> > +

Can we put a afbc ptr into drm_framebuffer, as the afbc extension if
the fb is afbc.
Since mostly this drm_afbc is enough for afbc support, but no need to
expose check func to driver, since per design the afbc modifier bits represent
all the requrement, the check is like a sanity check between the modifier and
fb info.

And we can also extend such afbc_info to all modifier which need an
extra check or extra info. like.

struct drm_framebuffer {
    ...
    union {    
        struct drm_afbc *afbc_info;
        void *mod_info; //extra modifier extension.  
    }
    ...
}

and such modifier info can be returned modifier_check()

drm_gem_fb_create_with_funcs()
{
    void *mod_info;

    if (!modifier)
        none_modifier_size_check();
    else if (afbc)
        mod_info = drm_afbc_size_check();
    else if (mode_config->fb_modifier_check())
        // for vendor specific modifier check
        mod_info = mode_config->fb_modifier_check();

    fb = drm_gem_fb_alloc();

    fb->mod_info = mod_info;
}

And in specific driver, you can directly convert the fb->mod_info to
your own modifier info. like current modifier is afbc, then

   struct drm_afbc *afbc_info = fb->mod_info;

Thanks
James
> > +#define AFBC_HEADER_SIZE		16
> > +#define AFBC_SUPERBLK_ALIGNMENT		128
> > +
> > +bool drm_afbc_get_superblk_wh(u64 modifier, u32 *w, u32 *h);
> > +
> > +void drm_afbc_get_parameters(const struct drm_mode_fb_cmd2 *mode_cmd,
> > +			     struct drm_afbc *afbc);
> > +
> > +bool drm_is_afbc(u64 modifier);
> > +
> > +#endif /* __DRM_AFBC_H__ */
> > -- 
> > 2.17.1
> > 
> 
> -- 
> Daniel Vetter
> Software Engineer, Intel Corporation
> http://blog.ffwll.ch
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 63+ messages in thread

end of thread, other threads:[~2019-11-28 10:48 UTC | newest]

Thread overview: 63+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-10-11 11:18 [PATCH 0/2] AFBC for Rockchip Andrzej Pietrasiewicz
2019-10-11 11:18 ` Andrzej Pietrasiewicz
2019-10-11 11:18 ` [PATCH 1/2] drm/arm: Factor out generic afbc helpers Andrzej Pietrasiewicz
2019-10-11 11:18   ` Andrzej Pietrasiewicz
2019-10-21 13:50   ` Ayan Halder
2019-10-21 13:50     ` Ayan Halder
2019-10-21 13:50     ` Ayan Halder
2019-10-21 14:41     ` Mihail Atanassov
2019-10-21 14:41       ` Mihail Atanassov
2019-10-21 14:41       ` Mihail Atanassov
2019-11-04 22:12       ` [PATCHv2 0/4] AFBC support for Rockchip Andrzej Pietrasiewicz
2019-11-04 22:12         ` [PATCHv2 1/4] drm/arm: Factor out generic afbc helpers Andrzej Pietrasiewicz
2019-11-05  9:22           ` Daniel Vetter
2019-11-06 12:45             ` Andrzej Pietrasiewicz
2019-11-07  8:27               ` Daniel Vetter
2019-11-05 23:26           ` Daniel Stone
2019-11-05 23:26             ` Daniel Stone
2019-11-06 10:28             ` Liviu Dudau
2019-11-07 17:20             ` Brian Starkey
2019-11-07 17:20               ` Brian Starkey
2019-11-07 17:32               ` Daniel Vetter
2019-11-07 17:32                 ` Daniel Vetter
2019-11-07 17:49                 ` Brian Starkey
2019-11-07 17:49                   ` Brian Starkey
2019-11-07 19:28                   ` Daniel Vetter
2019-11-07 19:28                     ` Daniel Vetter
2019-11-08  9:46                     ` Brian Starkey
2019-11-08  9:46                       ` Brian Starkey
2019-11-04 22:12         ` [PATCHv2 2/4] drm/malidp: use " Andrzej Pietrasiewicz
2019-11-06 11:09           ` Liviu Dudau
2019-11-04 22:12         ` [PATCHv2 3/4] drm/komeda: " Andrzej Pietrasiewicz
2019-11-08 16:09           ` Ayan Halder
2019-11-08 16:09             ` Ayan Halder
2019-11-13  2:01             ` james qian wang (Arm Technology China)
2019-11-13 11:39               ` Daniel Vetter
2019-11-14  1:52                 ` james qian wang (Arm Technology China)
2019-11-14 10:12                   ` Daniel Vetter
2019-11-18  7:09                     ` james qian wang (Arm Technology China)
2019-11-18  9:51                       ` Daniel Vetter
     [not found]                         ` <20191118095136.GC23790-dv86pmgwkMBes7Z6vYuT8azUEOm+Xw19@public.gmane.org>
2019-11-19  8:34                           ` james qian wang (Arm Technology China)
2019-11-19  8:34                             ` james qian wang (Arm Technology China)
2019-11-21 17:22                             ` [PATCHv3/RFC 0/4] AFBC rework and support for Rockchip Andrzej Pietrasiewicz
2019-11-21 17:22                               ` [PATCHv3/RFC 1/4] drm/arm: Factor out generic afbc helpers Andrzej Pietrasiewicz
2019-11-23  7:13                                 ` Ezequiel Garcia
2019-11-23  7:13                                   ` Ezequiel Garcia
2019-11-24 10:11                                 ` kbuild test robot
2019-11-25  8:55                                 ` Daniel Vetter
2019-11-26 20:27                                   ` Andrzej Pietrasiewicz
2019-11-27  9:51                                     ` Daniel Vetter
2019-11-28 10:47                                   ` james qian wang (Arm Technology China)
2019-11-21 17:22                               ` [PATCHv3/RFC 2/4] drm/malidp: use " Andrzej Pietrasiewicz
2019-11-21 17:22                               ` [PATCHv3/RFC 3/4] drm/komeda: Use afbc helper Andrzej Pietrasiewicz
2019-11-21 17:22                               ` [PATCHv3/RFC 4/4] drm/rockchip: Add support for afbc Andrzej Pietrasiewicz
2019-11-23  7:21                                 ` Ezequiel Garcia
2019-11-23  7:21                                   ` Ezequiel Garcia
2019-11-04 22:12         ` [PATCHv2 " Andrzej Pietrasiewicz
2019-11-05 23:34           ` Daniel Stone
2019-11-05 23:34             ` Daniel Stone
2019-10-11 11:18 ` [PATCH 2/2] " Andrzej Pietrasiewicz
2019-10-11 11:18   ` Andrzej Pietrasiewicz
2019-10-11 11:59   ` Daniel Stone
2019-10-11 11:59     ` Daniel Stone
2019-10-11 11:59     ` Daniel Stone

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.