All of lore.kernel.org
 help / color / mirror / Atom feed
From: Maxime Ripard <maxime.ripard@bootlin.com>
To: Daniel Vetter <daniel.vetter@intel.com>,
	David Airlie <airlied@linux.ie>,
	Maarten Lankhorst <maarten.lankhorst@linux.intel.com>,
	Sean Paul <seanpaul@chromium.org>,
	Maxime Ripard <maxime.ripard@bootlin.com>,
	Mauro Carvalho Chehab <mchehab@kernel.org>
Cc: Sakari Ailus <sakari.ailus@linux.intel.com>,
	Hans Verkuil <hans.verkuil@cisco.com>,
	Laurent Pinchart <laurent.pinchart@ideasonboard.com>,
	Thomas Petazzoni <thomas.petazzoni@bootlin.com>,
	Paul Kocialkowski <paul.kocialkowski@bootlin.com>,
	dri-devel@lists.freedesktop.org, linux-kernel@vger.kernel.org,
	linux-media@vger.kernel.org
Subject: [RFC PATCH 06/20] lib: Add video format information library
Date: Tue, 19 Mar 2019 22:57:11 +0100	[thread overview]
Message-ID: <a2ecd9e599e0b536c2a005e5feb140463566788e.1553032382.git-series.maxime.ripard@bootlin.com> (raw)
In-Reply-To: <cover.92acdec88ee4c280cb74e08ea22f0075e5fa055c.1553032382.git-series.maxime.ripard@bootlin.com>

Move the DRM formats API to turn this into a more generic image formats API
to be able to leverage it into some other places of the kernel, such as
v4l2 drivers.

Signed-off-by: Maxime Ripard <maxime.ripard@bootlin.com>
---
 include/linux/image-formats.h | 240 +++++++++++-
 lib/Kconfig                   |   7 +-
 lib/Makefile                  |   3 +-
 lib/image-formats-selftests.c | 326 +++++++++++++++-
 lib/image-formats.c           | 760 +++++++++++++++++++++++++++++++++++-
 5 files changed, 1336 insertions(+)
 create mode 100644 include/linux/image-formats.h
 create mode 100644 lib/image-formats-selftests.c
 create mode 100644 lib/image-formats.c

diff --git a/include/linux/image-formats.h b/include/linux/image-formats.h
new file mode 100644
index 000000000000..53fd73a71b3d
--- /dev/null
+++ b/include/linux/image-formats.h
@@ -0,0 +1,240 @@
+#ifndef _IMAGE_FORMATS_H_
+#define _IMAGE_FORMATS_H_
+
+#include <linux/types.h>
+
+/**
+ * struct image_format_info - information about a image format
+ */
+struct image_format_info {
+	union {
+		/**
+		 * @drm_fmt:
+		 *
+		 * DRM 4CC format identifier (DRM_FORMAT_*)
+		 */
+		u32 drm_fmt;
+
+		/**
+		 * @format:
+		 *
+		 * DRM 4CC format identifier (DRM_FORMAT_*). Kept
+		 * around for compatibility reasons with the current
+		 * DRM drivers.
+		 */
+		u32 format;
+	};
+
+	/**
+	 * @depth:
+	 *
+	 * Color depth (number of bits per pixel excluding padding bits),
+	 * valid for a subset of RGB formats only. This is a legacy field, do
+	 * not use in new code and set to 0 for new formats.
+	 */
+	u8 depth;
+
+	/** @num_planes: Number of color planes (1 to 3) */
+	u8 num_planes;
+
+	union {
+		/**
+		 * @cpp:
+		 *
+		 * Number of bytes per pixel (per plane), this is aliased with
+		 * @char_per_block. It is deprecated in favour of using the
+		 * triplet @char_per_block, @block_w, @block_h for better
+		 * describing the pixel format.
+		 */
+		u8 cpp[3];
+
+		/**
+		 * @char_per_block:
+		 *
+		 * Number of bytes per block (per plane), where blocks are
+		 * defined as a rectangle of pixels which are stored next to
+		 * each other in a byte aligned memory region. Together with
+		 * @block_w and @block_h this is used to properly describe tiles
+		 * in tiled formats or to describe groups of pixels in packed
+		 * formats for which the memory needed for a single pixel is not
+		 * byte aligned.
+		 *
+		 * @cpp has been kept for historical reasons because there are
+		 * a lot of places in drivers where it's used. In drm core for
+		 * generic code paths the preferred way is to use
+		 * @char_per_block, image_format_block_width() and
+		 * image_format_block_height() which allows handling both
+		 * block and non-block formats in the same way.
+		 *
+		 * For formats that are intended to be used only with non-linear
+		 * modifiers both @cpp and @char_per_block must be 0 in the
+		 * generic format table. Drivers could supply accurate
+		 * information from their drm_mode_config.get_format_info hook
+		 * if they want the core to be validating the pitch.
+		 */
+		u8 char_per_block[3];
+	};
+
+	/**
+	 * @block_w:
+	 *
+	 * Block width in pixels, this is intended to be accessed through
+	 * image_format_block_width()
+	 */
+	u8 block_w[3];
+
+	/**
+	 * @block_h:
+	 *
+	 * Block height in pixels, this is intended to be accessed through
+	 * image_format_block_height()
+	 */
+	u8 block_h[3];
+
+	/** @hsub: Horizontal chroma subsampling factor */
+	u8 hsub;
+	/** @vsub: Vertical chroma subsampling factor */
+	u8 vsub;
+
+	/** @has_alpha: Does the format embeds an alpha component? */
+	bool has_alpha;
+
+	/** @is_yuv: Is it a YUV format? */
+	bool is_yuv;
+};
+
+/**
+ * image_format_info_is_yuv_packed - check that the format info matches a YUV
+ * format with data laid in a single plane
+ * @info: format info
+ *
+ * Returns:
+ * A boolean indicating whether the format info matches a packed YUV format.
+ */
+static inline bool
+image_format_info_is_yuv_packed(const struct image_format_info *info)
+{
+	return info->is_yuv && info->num_planes == 1;
+}
+
+/**
+ * image_format_info_is_yuv_semiplanar - check that the format info matches a YUV
+ * format with data laid in two planes (luminance and chrominance)
+ * @info: format info
+ *
+ * Returns:
+ * A boolean indicating whether the format info matches a semiplanar YUV format.
+ */
+static inline bool
+image_format_info_is_yuv_semiplanar(const struct image_format_info *info)
+{
+	return info->is_yuv && info->num_planes == 2;
+}
+
+/**
+ * image_format_info_is_yuv_planar - check that the format info matches a YUV
+ * format with data laid in three planes (one for each YUV component)
+ * @info: format info
+ *
+ * Returns:
+ * A boolean indicating whether the format info matches a planar YUV format.
+ */
+static inline bool
+image_format_info_is_yuv_planar(const struct image_format_info *info)
+{
+	return info->is_yuv && info->num_planes == 3;
+}
+
+/**
+ * image_format_info_is_yuv_sampling_410 - check that the format info matches a
+ * YUV format with 4:1:0 sub-sampling
+ * @info: format info
+ *
+ * Returns:
+ * A boolean indicating whether the format info matches a YUV format with 4:1:0
+ * sub-sampling.
+ */
+static inline bool
+image_format_info_is_yuv_sampling_410(const struct image_format_info *info)
+{
+	return info->is_yuv && info->hsub == 4 && info->vsub == 4;
+}
+
+/**
+ * image_format_info_is_yuv_sampling_411 - check that the format info matches a
+ * YUV format with 4:1:1 sub-sampling
+ * @info: format info
+ *
+ * Returns:
+ * A boolean indicating whether the format info matches a YUV format with 4:1:1
+ * sub-sampling.
+ */
+static inline bool
+image_format_info_is_yuv_sampling_411(const struct image_format_info *info)
+{
+	return info->is_yuv && info->hsub == 4 && info->vsub == 1;
+}
+
+/**
+ * image_format_info_is_yuv_sampling_420 - check that the format info matches a
+ * YUV format with 4:2:0 sub-sampling
+ * @info: format info
+ *
+ * Returns:
+ * A boolean indicating whether the format info matches a YUV format with 4:2:0
+ * sub-sampling.
+ */
+static inline bool
+image_format_info_is_yuv_sampling_420(const struct image_format_info *info)
+{
+	return info->is_yuv && info->hsub == 2 && info->vsub == 2;
+}
+
+/**
+ * image_format_info_is_yuv_sampling_422 - check that the format info matches a
+ * YUV format with 4:2:2 sub-sampling
+ * @info: format info
+ *
+ * Returns:
+ * A boolean indicating whether the format info matches a YUV format with 4:2:2
+ * sub-sampling.
+ */
+static inline bool
+image_format_info_is_yuv_sampling_422(const struct image_format_info *info)
+{
+	return info->is_yuv && info->hsub == 2 && info->vsub == 1;
+}
+
+/**
+ * image_format_info_is_yuv_sampling_444 - check that the format info matches a
+ * YUV format with 4:4:4 sub-sampling
+ * @info: format info
+ *
+ * Returns:
+ * A boolean indicating whether the format info matches a YUV format with 4:4:4
+ * sub-sampling.
+ */
+static inline bool
+image_format_info_is_yuv_sampling_444(const struct image_format_info *info)
+{
+	return info->is_yuv && info->hsub == 1 && info->vsub == 1;
+}
+
+const struct image_format_info *__image_format_drm_lookup(u32 drm);
+const struct image_format_info *image_format_drm_lookup(u32 drm);
+unsigned int image_format_plane_cpp(const struct image_format_info *format,
+				    int plane);
+unsigned int image_format_plane_width(int width,
+				      const struct image_format_info *format,
+				      int plane);
+unsigned int image_format_plane_height(int height,
+				       const struct image_format_info *format,
+				       int plane);
+unsigned int image_format_block_width(const struct image_format_info *format,
+				      int plane);
+unsigned int image_format_block_height(const struct image_format_info *format,
+				       int plane);
+uint64_t image_format_min_pitch(const struct image_format_info *info,
+				int plane, unsigned int buffer_width);
+
+#endif /* _IMAGE_FORMATS_H_ */
diff --git a/lib/Kconfig b/lib/Kconfig
index a9e56539bd11..421acac83b13 100644
--- a/lib/Kconfig
+++ b/lib/Kconfig
@@ -635,3 +635,10 @@ config GENERIC_LIB_UCMPDI2
 
 config OBJAGG
 	tristate "objagg" if COMPILE_TEST
+
+config IMAGE_FORMATS
+	bool
+
+config IMAGE_FORMATS_SELFTESTS
+	tristate "Test image format functions"
+	depends on IMAGE_FORMATS
diff --git a/lib/Makefile b/lib/Makefile
index e1b59da71418..b1916e6d30da 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -276,3 +276,6 @@ obj-$(CONFIG_GENERIC_LIB_MULDI3) += muldi3.o
 obj-$(CONFIG_GENERIC_LIB_CMPDI2) += cmpdi2.o
 obj-$(CONFIG_GENERIC_LIB_UCMPDI2) += ucmpdi2.o
 obj-$(CONFIG_OBJAGG) += objagg.o
+
+obj-$(CONFIG_IMAGE_FORMATS) += image-formats.o
+obj-$(CONFIG_IMAGE_FORMATS_SELFTESTS) += image-formats-selftests.o
diff --git a/lib/image-formats-selftests.c b/lib/image-formats-selftests.c
new file mode 100644
index 000000000000..8fdc50b15dcc
--- /dev/null
+++ b/lib/image-formats-selftests.c
@@ -0,0 +1,326 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Test cases for the image_format functions
+ */
+
+#define pr_fmt(fmt) "image_format: " fmt
+
+#include <linux/errno.h>
+#include <linux/image-formats.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+
+#include <drm/drm_fourcc.h>
+
+#define FAIL(test, msg, ...) \
+	do { \
+		if (test) { \
+			pr_err("%s/%u: " msg, __FUNCTION__, __LINE__, ##__VA_ARGS__); \
+			return -EINVAL; \
+		} \
+	} while (0)
+
+#define FAIL_ON(x) FAIL((x), "%s", "FAIL_ON(" __stringify(x) ")\n")
+
+static int test_image_format_block_width(void)
+{
+	const struct image_format_info *info = NULL;
+
+	/* Test invalid arguments */
+	FAIL_ON(image_format_block_width(info, 0) != 0);
+	FAIL_ON(image_format_block_width(info, -1) != 0);
+	FAIL_ON(image_format_block_width(info, 1) != 0);
+
+	/* Test 1 plane format */
+	info = image_format_drm_lookup(DRM_FORMAT_XRGB4444);
+	FAIL_ON(!info);
+	FAIL_ON(image_format_block_width(info, 0) != 1);
+	FAIL_ON(image_format_block_width(info, 1) != 0);
+	FAIL_ON(image_format_block_width(info, -1) != 0);
+
+	/* Test 2 planes format */
+	info = image_format_drm_lookup(DRM_FORMAT_NV12);
+	FAIL_ON(!info);
+	FAIL_ON(image_format_block_width(info, 0) != 1);
+	FAIL_ON(image_format_block_width(info, 1) != 1);
+	FAIL_ON(image_format_block_width(info, 2) != 0);
+	FAIL_ON(image_format_block_width(info, -1) != 0);
+
+	/* Test 3 planes format */
+	info = image_format_drm_lookup(DRM_FORMAT_YUV422);
+	FAIL_ON(!info);
+	FAIL_ON(image_format_block_width(info, 0) != 1);
+	FAIL_ON(image_format_block_width(info, 1) != 1);
+	FAIL_ON(image_format_block_width(info, 2) != 1);
+	FAIL_ON(image_format_block_width(info, 3) != 0);
+	FAIL_ON(image_format_block_width(info, -1) != 0);
+
+	/* Test a tiled format */
+	info = image_format_drm_lookup(DRM_FORMAT_X0L0);
+	FAIL_ON(!info);
+	FAIL_ON(image_format_block_width(info, 0) != 2);
+	FAIL_ON(image_format_block_width(info, 1) != 0);
+	FAIL_ON(image_format_block_width(info, -1) != 0);
+
+	return 0;
+}
+
+static int test_image_format_block_height(void)
+{
+	const struct image_format_info *info = NULL;
+
+	/* Test invalid arguments */
+	FAIL_ON(image_format_block_height(info, 0) != 0);
+	FAIL_ON(image_format_block_height(info, -1) != 0);
+	FAIL_ON(image_format_block_height(info, 1) != 0);
+
+	/* Test 1 plane format */
+	info = image_format_drm_lookup(DRM_FORMAT_XRGB4444);
+	FAIL_ON(!info);
+	FAIL_ON(image_format_block_height(info, 0) != 1);
+	FAIL_ON(image_format_block_height(info, 1) != 0);
+	FAIL_ON(image_format_block_height(info, -1) != 0);
+
+	/* Test 2 planes format */
+	info = image_format_drm_lookup(DRM_FORMAT_NV12);
+	FAIL_ON(!info);
+	FAIL_ON(image_format_block_height(info, 0) != 1);
+	FAIL_ON(image_format_block_height(info, 1) != 1);
+	FAIL_ON(image_format_block_height(info, 2) != 0);
+	FAIL_ON(image_format_block_height(info, -1) != 0);
+
+	/* Test 3 planes format */
+	info = image_format_drm_lookup(DRM_FORMAT_YUV422);
+	FAIL_ON(!info);
+	FAIL_ON(image_format_block_height(info, 0) != 1);
+	FAIL_ON(image_format_block_height(info, 1) != 1);
+	FAIL_ON(image_format_block_height(info, 2) != 1);
+	FAIL_ON(image_format_block_height(info, 3) != 0);
+	FAIL_ON(image_format_block_height(info, -1) != 0);
+
+	/* Test a tiled format */
+	info = image_format_drm_lookup(DRM_FORMAT_X0L0);
+	FAIL_ON(!info);
+	FAIL_ON(image_format_block_height(info, 0) != 2);
+	FAIL_ON(image_format_block_height(info, 1) != 0);
+	FAIL_ON(image_format_block_height(info, -1) != 0);
+
+	return 0;
+}
+
+static int test_image_format_min_pitch(void)
+{
+	const struct image_format_info *info = NULL;
+
+	/* Test invalid arguments */
+	FAIL_ON(image_format_min_pitch(info, 0, 0) != 0);
+	FAIL_ON(image_format_min_pitch(info, -1, 0) != 0);
+	FAIL_ON(image_format_min_pitch(info, 1, 0) != 0);
+
+	/* Test 1 plane 8 bits per pixel format */
+	info = image_format_drm_lookup(DRM_FORMAT_RGB332);
+	FAIL_ON(!info);
+	FAIL_ON(image_format_min_pitch(info, 0, 0) != 0);
+	FAIL_ON(image_format_min_pitch(info, -1, 0) != 0);
+	FAIL_ON(image_format_min_pitch(info, 1, 0) != 0);
+
+	FAIL_ON(image_format_min_pitch(info, 0, 1) != 1);
+	FAIL_ON(image_format_min_pitch(info, 0, 2) != 2);
+	FAIL_ON(image_format_min_pitch(info, 0, 640) != 640);
+	FAIL_ON(image_format_min_pitch(info, 0, 1024) != 1024);
+	FAIL_ON(image_format_min_pitch(info, 0, 1920) != 1920);
+	FAIL_ON(image_format_min_pitch(info, 0, 4096) != 4096);
+	FAIL_ON(image_format_min_pitch(info, 0, 671) != 671);
+	FAIL_ON(image_format_min_pitch(info, 0, UINT_MAX) !=
+			(uint64_t)UINT_MAX);
+	FAIL_ON(image_format_min_pitch(info, 0, (UINT_MAX - 1)) !=
+			(uint64_t)(UINT_MAX - 1));
+
+	/* Test 1 plane 16 bits per pixel format */
+	info = image_format_drm_lookup(DRM_FORMAT_XRGB4444);
+	FAIL_ON(!info);
+	FAIL_ON(image_format_min_pitch(info, 0, 0) != 0);
+	FAIL_ON(image_format_min_pitch(info, -1, 0) != 0);
+	FAIL_ON(image_format_min_pitch(info, 1, 0) != 0);
+
+	FAIL_ON(image_format_min_pitch(info, 0, 1) != 2);
+	FAIL_ON(image_format_min_pitch(info, 0, 2) != 4);
+	FAIL_ON(image_format_min_pitch(info, 0, 640) != 1280);
+	FAIL_ON(image_format_min_pitch(info, 0, 1024) != 2048);
+	FAIL_ON(image_format_min_pitch(info, 0, 1920) != 3840);
+	FAIL_ON(image_format_min_pitch(info, 0, 4096) != 8192);
+	FAIL_ON(image_format_min_pitch(info, 0, 671) != 1342);
+	FAIL_ON(image_format_min_pitch(info, 0, UINT_MAX) !=
+			(uint64_t)UINT_MAX * 2);
+	FAIL_ON(image_format_min_pitch(info, 0, (UINT_MAX - 1)) !=
+			(uint64_t)(UINT_MAX - 1) * 2);
+
+	/* Test 1 plane 24 bits per pixel format */
+	info = image_format_drm_lookup(DRM_FORMAT_RGB888);
+	FAIL_ON(!info);
+	FAIL_ON(image_format_min_pitch(info, 0, 0) != 0);
+	FAIL_ON(image_format_min_pitch(info, -1, 0) != 0);
+	FAIL_ON(image_format_min_pitch(info, 1, 0) != 0);
+
+	FAIL_ON(image_format_min_pitch(info, 0, 1) != 3);
+	FAIL_ON(image_format_min_pitch(info, 0, 2) != 6);
+	FAIL_ON(image_format_min_pitch(info, 0, 640) != 1920);
+	FAIL_ON(image_format_min_pitch(info, 0, 1024) != 3072);
+	FAIL_ON(image_format_min_pitch(info, 0, 1920) != 5760);
+	FAIL_ON(image_format_min_pitch(info, 0, 4096) != 12288);
+	FAIL_ON(image_format_min_pitch(info, 0, 671) != 2013);
+	FAIL_ON(image_format_min_pitch(info, 0, UINT_MAX) !=
+			(uint64_t)UINT_MAX * 3);
+	FAIL_ON(image_format_min_pitch(info, 0, UINT_MAX - 1) !=
+			(uint64_t)(UINT_MAX - 1) * 3);
+
+	/* Test 1 plane 32 bits per pixel format */
+	info = image_format_drm_lookup(DRM_FORMAT_ABGR8888);
+	FAIL_ON(!info);
+	FAIL_ON(image_format_min_pitch(info, 0, 0) != 0);
+	FAIL_ON(image_format_min_pitch(info, -1, 0) != 0);
+	FAIL_ON(image_format_min_pitch(info, 1, 0) != 0);
+
+	FAIL_ON(image_format_min_pitch(info, 0, 1) != 4);
+	FAIL_ON(image_format_min_pitch(info, 0, 2) != 8);
+	FAIL_ON(image_format_min_pitch(info, 0, 640) != 2560);
+	FAIL_ON(image_format_min_pitch(info, 0, 1024) != 4096);
+	FAIL_ON(image_format_min_pitch(info, 0, 1920) != 7680);
+	FAIL_ON(image_format_min_pitch(info, 0, 4096) != 16384);
+	FAIL_ON(image_format_min_pitch(info, 0, 671) != 2684);
+	FAIL_ON(image_format_min_pitch(info, 0, UINT_MAX) !=
+			(uint64_t)UINT_MAX * 4);
+	FAIL_ON(image_format_min_pitch(info, 0, UINT_MAX - 1) !=
+			(uint64_t)(UINT_MAX - 1) * 4);
+
+	/* Test 2 planes format */
+	info = image_format_drm_lookup(DRM_FORMAT_NV12);
+	FAIL_ON(!info);
+	FAIL_ON(image_format_min_pitch(info, 0, 0) != 0);
+	FAIL_ON(image_format_min_pitch(info, 1, 0) != 0);
+	FAIL_ON(image_format_min_pitch(info, -1, 0) != 0);
+	FAIL_ON(image_format_min_pitch(info, 2, 0) != 0);
+
+	FAIL_ON(image_format_min_pitch(info, 0, 1) != 1);
+	FAIL_ON(image_format_min_pitch(info, 1, 1) != 2);
+	FAIL_ON(image_format_min_pitch(info, 0, 2) != 2);
+	FAIL_ON(image_format_min_pitch(info, 1, 1) != 2);
+	FAIL_ON(image_format_min_pitch(info, 0, 640) != 640);
+	FAIL_ON(image_format_min_pitch(info, 1, 320) != 640);
+	FAIL_ON(image_format_min_pitch(info, 0, 1024) != 1024);
+	FAIL_ON(image_format_min_pitch(info, 1, 512) != 1024);
+	FAIL_ON(image_format_min_pitch(info, 0, 1920) != 1920);
+	FAIL_ON(image_format_min_pitch(info, 1, 960) != 1920);
+	FAIL_ON(image_format_min_pitch(info, 0, 4096) != 4096);
+	FAIL_ON(image_format_min_pitch(info, 1, 2048) != 4096);
+	FAIL_ON(image_format_min_pitch(info, 0, 671) != 671);
+	FAIL_ON(image_format_min_pitch(info, 1, 336) != 672);
+	FAIL_ON(image_format_min_pitch(info, 0, UINT_MAX) !=
+			(uint64_t)UINT_MAX);
+	FAIL_ON(image_format_min_pitch(info, 1, UINT_MAX / 2 + 1) !=
+			(uint64_t)UINT_MAX + 1);
+	FAIL_ON(image_format_min_pitch(info, 0, (UINT_MAX - 1)) !=
+			(uint64_t)(UINT_MAX - 1));
+	FAIL_ON(image_format_min_pitch(info, 1, (UINT_MAX - 1) /  2) !=
+			(uint64_t)(UINT_MAX - 1));
+
+	/* Test 3 planes 8 bits per pixel format */
+	info = image_format_drm_lookup(DRM_FORMAT_YUV422);
+	FAIL_ON(!info);
+	FAIL_ON(image_format_min_pitch(info, 0, 0) != 0);
+	FAIL_ON(image_format_min_pitch(info, 1, 0) != 0);
+	FAIL_ON(image_format_min_pitch(info, 2, 0) != 0);
+	FAIL_ON(image_format_min_pitch(info, -1, 0) != 0);
+	FAIL_ON(image_format_min_pitch(info, 3, 0) != 0);
+
+	FAIL_ON(image_format_min_pitch(info, 0, 1) != 1);
+	FAIL_ON(image_format_min_pitch(info, 1, 1) != 1);
+	FAIL_ON(image_format_min_pitch(info, 2, 1) != 1);
+	FAIL_ON(image_format_min_pitch(info, 0, 2) != 2);
+	FAIL_ON(image_format_min_pitch(info, 1, 2) != 2);
+	FAIL_ON(image_format_min_pitch(info, 2, 2) != 2);
+	FAIL_ON(image_format_min_pitch(info, 0, 640) != 640);
+	FAIL_ON(image_format_min_pitch(info, 1, 320) != 320);
+	FAIL_ON(image_format_min_pitch(info, 2, 320) != 320);
+	FAIL_ON(image_format_min_pitch(info, 0, 1024) != 1024);
+	FAIL_ON(image_format_min_pitch(info, 1, 512) != 512);
+	FAIL_ON(image_format_min_pitch(info, 2, 512) != 512);
+	FAIL_ON(image_format_min_pitch(info, 0, 1920) != 1920);
+	FAIL_ON(image_format_min_pitch(info, 1, 960) != 960);
+	FAIL_ON(image_format_min_pitch(info, 2, 960) != 960);
+	FAIL_ON(image_format_min_pitch(info, 0, 4096) != 4096);
+	FAIL_ON(image_format_min_pitch(info, 1, 2048) != 2048);
+	FAIL_ON(image_format_min_pitch(info, 2, 2048) != 2048);
+	FAIL_ON(image_format_min_pitch(info, 0, 671) != 671);
+	FAIL_ON(image_format_min_pitch(info, 1, 336) != 336);
+	FAIL_ON(image_format_min_pitch(info, 2, 336) != 336);
+	FAIL_ON(image_format_min_pitch(info, 0, UINT_MAX) !=
+			(uint64_t)UINT_MAX);
+	FAIL_ON(image_format_min_pitch(info, 1, UINT_MAX / 2 + 1) !=
+			(uint64_t)UINT_MAX / 2 + 1);
+	FAIL_ON(image_format_min_pitch(info, 2, UINT_MAX / 2 + 1) !=
+			(uint64_t)UINT_MAX / 2 + 1);
+	FAIL_ON(image_format_min_pitch(info, 0, (UINT_MAX - 1) / 2) !=
+			(uint64_t)(UINT_MAX - 1) / 2);
+	FAIL_ON(image_format_min_pitch(info, 1, (UINT_MAX - 1) / 2) !=
+			(uint64_t)(UINT_MAX - 1) / 2);
+	FAIL_ON(image_format_min_pitch(info, 2, (UINT_MAX - 1) / 2) !=
+			(uint64_t)(UINT_MAX - 1) / 2);
+
+	/* Test tiled format */
+	info = image_format_drm_lookup(DRM_FORMAT_X0L2);
+	FAIL_ON(!info);
+	FAIL_ON(image_format_min_pitch(info, 0, 0) != 0);
+	FAIL_ON(image_format_min_pitch(info, -1, 0) != 0);
+	FAIL_ON(image_format_min_pitch(info, 1, 0) != 0);
+
+	FAIL_ON(image_format_min_pitch(info, 0, 1) != 2);
+	FAIL_ON(image_format_min_pitch(info, 0, 2) != 4);
+	FAIL_ON(image_format_min_pitch(info, 0, 640) != 1280);
+	FAIL_ON(image_format_min_pitch(info, 0, 1024) != 2048);
+	FAIL_ON(image_format_min_pitch(info, 0, 1920) != 3840);
+	FAIL_ON(image_format_min_pitch(info, 0, 4096) != 8192);
+	FAIL_ON(image_format_min_pitch(info, 0, 671) != 1342);
+	FAIL_ON(image_format_min_pitch(info, 0, UINT_MAX) !=
+			(uint64_t)UINT_MAX * 2);
+	FAIL_ON(image_format_min_pitch(info, 0, UINT_MAX - 1) !=
+			(uint64_t)(UINT_MAX - 1) * 2);
+
+	return 0;
+}
+
+#define selftest(test)	{ .name = #test, .func = test, }
+
+static struct image_format_test {
+	char	*name;
+	int	(*func)(void);
+} tests[] = {
+	selftest(test_image_format_block_height),
+	selftest(test_image_format_block_width),
+	selftest(test_image_format_min_pitch),
+};
+
+static int __init image_format_test_init(void)
+{
+	unsigned int i;
+
+	for (i = 0; i < ARRAY_SIZE(tests); i++) {
+		struct image_format_test *test = &tests[i];
+		int ret;
+
+		ret = test->func();
+		if (ret) {
+			pr_err("Failed test %s\n", test->name);
+			return ret;
+		}
+	}
+
+	pr_info("All tests executed properly.\n");
+	return 0;
+}
+
+static void __exit image_format_test_exit(void)
+{
+}
+module_init(image_format_test_init);
+module_exit(image_format_test_exit);
diff --git a/lib/image-formats.c b/lib/image-formats.c
new file mode 100644
index 000000000000..9b9a73220c5d
--- /dev/null
+++ b/lib/image-formats.c
@@ -0,0 +1,760 @@
+#include <linux/bug.h>
+#include <linux/image-formats.h>
+#include <linux/kernel.h>
+#include <linux/math64.h>
+
+#include <uapi/drm/drm_fourcc.h>
+
+static const struct image_format_info formats[] = {
+	{
+		.drm_fmt = DRM_FORMAT_C8,
+		.depth = 8,
+		.num_planes = 1,
+		.cpp = { 1, 0, 0 },
+		.hsub = 1,
+		.vsub = 1,
+	}, {
+		.drm_fmt = DRM_FORMAT_RGB332,
+		.depth = 8,
+		.num_planes = 1,
+		.cpp = { 1, 0, 0 },
+		.hsub = 1,
+		.vsub = 1,
+	}, {
+		.drm_fmt = DRM_FORMAT_BGR233,
+		.depth = 8,
+		.num_planes = 1,
+		.cpp = { 1, 0, 0 },
+		.hsub = 1,
+		.vsub = 1,
+	}, {
+		.drm_fmt = DRM_FORMAT_XRGB4444,
+		.depth = 0,
+		.num_planes = 1,
+		.cpp = { 2, 0, 0 },
+		.hsub = 1,
+		.vsub = 1,
+	}, {
+		.drm_fmt = DRM_FORMAT_XBGR4444,
+		.depth = 0,
+		.num_planes = 1,
+		.cpp = { 2, 0, 0 },
+		.hsub = 1,
+		.vsub = 1,
+	}, {
+		.drm_fmt = DRM_FORMAT_RGBX4444,
+		.depth = 0,
+		.num_planes = 1,
+		.cpp = { 2, 0, 0 },
+		.hsub = 1,
+		.vsub = 1,
+	}, {
+		.drm_fmt = DRM_FORMAT_BGRX4444,
+		.depth = 0,
+		.num_planes = 1,
+		.cpp = { 2, 0, 0 },
+		.hsub = 1,
+		.vsub = 1,
+	}, {
+		.drm_fmt = DRM_FORMAT_ARGB4444,
+		.depth = 0,
+		.num_planes = 1,
+		.cpp = { 2, 0, 0 },
+		.hsub = 1,
+		.vsub = 1,
+		.has_alpha = true,
+	}, {
+		.drm_fmt = DRM_FORMAT_ABGR4444,
+		.depth = 0,
+		.num_planes = 1,
+		.cpp = { 2, 0, 0 },
+		.hsub = 1,
+		.vsub = 1,
+		.has_alpha = true,
+	}, {
+		.drm_fmt = DRM_FORMAT_RGBA4444,
+		.depth = 0,
+		.num_planes = 1,
+		.cpp = { 2, 0, 0 },
+		.hsub = 1,
+		.vsub = 1,
+		.has_alpha = true,
+	}, {
+		.drm_fmt = DRM_FORMAT_BGRA4444,
+		.depth = 0,
+		.num_planes = 1,
+		.cpp = { 2, 0, 0 },
+		.hsub = 1,
+		.vsub = 1,
+		.has_alpha = true,
+	}, {
+		.drm_fmt = DRM_FORMAT_XRGB1555,
+		.depth = 15,
+		.num_planes = 1,
+		.cpp = { 2, 0, 0 },
+		.hsub = 1,
+		.vsub = 1,
+	}, {
+		.drm_fmt = DRM_FORMAT_XBGR1555,
+		.depth = 15,
+		.num_planes = 1,
+		.cpp = { 2, 0, 0 },
+		.hsub = 1,
+		.vsub = 1,
+	}, {
+		.drm_fmt = DRM_FORMAT_RGBX5551,
+		.depth = 15,
+		.num_planes = 1,
+		.cpp = { 2, 0, 0 },
+		.hsub = 1,
+		.vsub = 1,
+	}, {
+		.drm_fmt = DRM_FORMAT_BGRX5551,
+		.depth = 15,
+		.num_planes = 1,
+		.cpp = { 2, 0, 0 },
+		.hsub = 1,
+		.vsub = 1,
+	}, {
+		.drm_fmt = DRM_FORMAT_ARGB1555,
+		.depth = 15,
+		.num_planes = 1,
+		.cpp = { 2, 0, 0 },
+		.hsub = 1,
+		.vsub = 1,
+		.has_alpha = true,
+	}, {
+		.drm_fmt = DRM_FORMAT_ABGR1555,
+		.depth = 15,
+		.num_planes = 1,
+		.cpp = { 2, 0, 0 },
+		.hsub = 1,
+		.vsub = 1,
+		.has_alpha = true,
+	}, {
+		.drm_fmt = DRM_FORMAT_RGBA5551,
+		.depth = 15,
+		.num_planes = 1,
+		.cpp = { 2, 0, 0 },
+		.hsub = 1,
+		.vsub = 1,
+		.has_alpha = true,
+	}, {
+		.drm_fmt = DRM_FORMAT_BGRA5551,
+		.depth = 15,
+		.num_planes = 1,
+		.cpp = { 2, 0, 0 },
+		.hsub = 1,
+		.vsub = 1,
+		.has_alpha = true,
+	}, {
+		.drm_fmt = DRM_FORMAT_RGB565,
+		.depth = 16,
+		.num_planes = 1,
+		.cpp = { 2, 0, 0 },
+		.hsub = 1,
+		.vsub = 1,
+	}, {
+		.drm_fmt = DRM_FORMAT_BGR565,
+		.depth = 16,
+		.num_planes = 1,
+		.cpp = { 2, 0, 0 },
+		.hsub = 1,
+		.vsub = 1,
+	}, {
+		.drm_fmt = DRM_FORMAT_RGB888,
+		.depth = 24,
+		.num_planes = 1,
+		.cpp = { 3, 0, 0 },
+		.hsub = 1,
+		.vsub = 1,
+	}, {
+		.drm_fmt = DRM_FORMAT_BGR888,
+		.depth = 24,
+		.num_planes = 1,
+		.cpp = { 3, 0, 0 },
+		.hsub = 1,
+		.vsub = 1,
+	}, {
+		.drm_fmt = DRM_FORMAT_XRGB8888,
+		.depth = 24,
+		.num_planes = 1,
+		.cpp = { 4, 0, 0 },
+		.hsub = 1,
+		.vsub = 1,
+	}, {
+		.drm_fmt = DRM_FORMAT_XBGR8888,
+		.depth = 24,
+		.num_planes = 1,
+		.cpp = { 4, 0, 0 },
+		.hsub = 1,
+		.vsub = 1,
+	}, {
+		.drm_fmt = DRM_FORMAT_RGBX8888,
+		.depth = 24,
+		.num_planes = 1,
+		.cpp = { 4, 0, 0 },
+		.hsub = 1,
+		.vsub = 1,
+	}, {
+		.drm_fmt = DRM_FORMAT_BGRX8888,
+		.depth = 24,
+		.num_planes = 1,
+		.cpp = { 4, 0, 0 },
+		.hsub = 1,
+		.vsub = 1,
+	}, {
+		.drm_fmt = DRM_FORMAT_RGB565_A8,
+		.depth = 24,
+		.num_planes = 2,
+		.cpp = { 2, 1, 0 },
+		.hsub = 1,
+		.vsub = 1,
+		.has_alpha = true,
+	}, {
+		.drm_fmt = DRM_FORMAT_BGR565_A8,
+		.depth = 24,
+		.num_planes = 2,
+		.cpp = { 2, 1, 0 },
+		.hsub = 1,
+		.vsub = 1,
+		.has_alpha = true,
+	}, {
+		.drm_fmt = DRM_FORMAT_XRGB2101010,
+		.depth = 30,
+		.num_planes = 1,
+		.cpp = { 4, 0, 0 },
+		.hsub = 1,
+		.vsub = 1,
+	}, {
+		.drm_fmt = DRM_FORMAT_XBGR2101010,
+		.depth = 30,
+		.num_planes = 1,
+		.cpp = { 4, 0, 0 },
+		.hsub = 1,
+		.vsub = 1,
+	}, {
+		.drm_fmt = DRM_FORMAT_RGBX1010102,
+		.depth = 30,
+		.num_planes = 1,
+		.cpp = { 4, 0, 0 },
+		.hsub = 1,
+		.vsub = 1,
+	}, {
+		.drm_fmt = DRM_FORMAT_BGRX1010102,
+		.depth = 30,
+		.num_planes = 1,
+		.cpp = { 4, 0, 0 },
+		.hsub = 1,
+		.vsub = 1,
+	}, {
+		.drm_fmt = DRM_FORMAT_ARGB2101010,
+		.depth = 30,
+		.num_planes = 1,
+		.cpp = { 4, 0, 0 },
+		.hsub = 1,
+		.vsub = 1,
+		.has_alpha = true,
+	}, {
+		.drm_fmt = DRM_FORMAT_ABGR2101010,
+		.depth = 30,
+		.num_planes = 1,
+		.cpp = { 4, 0, 0 },
+		.hsub = 1,
+		.vsub = 1,
+		.has_alpha = true,
+	}, {
+		.drm_fmt = DRM_FORMAT_RGBA1010102,
+		.depth = 30,
+		.num_planes = 1,
+		.cpp = { 4, 0, 0 },
+		.hsub = 1,
+		.vsub = 1,
+		.has_alpha = true,
+	}, {
+		.drm_fmt = DRM_FORMAT_BGRA1010102,
+		.depth = 30,
+		.num_planes = 1,
+		.cpp = { 4, 0, 0 },
+		.hsub = 1,
+		.vsub = 1,
+		.has_alpha = true,
+	}, {
+		.drm_fmt = DRM_FORMAT_ARGB8888,
+		.depth = 32,
+		.num_planes = 1,
+		.cpp = { 4, 0, 0 },
+		.hsub = 1,
+		.vsub = 1,
+		.has_alpha = true,
+	}, {
+		.drm_fmt = DRM_FORMAT_ABGR8888,
+		.depth = 32,
+		.num_planes = 1,
+		.cpp = { 4, 0, 0 },
+		.hsub = 1,
+		.vsub = 1,
+		.has_alpha = true,
+	}, {
+		.drm_fmt = DRM_FORMAT_RGBA8888,
+		.depth = 32,
+		.num_planes = 1,
+		.cpp = { 4, 0, 0 },
+		.hsub = 1,
+		.vsub = 1,
+		.has_alpha = true,
+	}, {
+		.drm_fmt = DRM_FORMAT_BGRA8888,
+		.depth = 32,
+		.num_planes = 1,
+		.cpp = { 4, 0, 0 },
+		.hsub = 1,
+		.vsub = 1,
+		.has_alpha = true,
+	}, {
+		.drm_fmt = DRM_FORMAT_RGB888_A8,
+		.depth = 32,
+		.num_planes = 2,
+		.cpp = { 3, 1, 0 },
+		.hsub = 1,
+		.vsub = 1,
+		.has_alpha = true,
+	}, {
+		.drm_fmt = DRM_FORMAT_BGR888_A8,
+		.depth = 32,
+		.num_planes = 2,
+		.cpp = { 3, 1, 0 },
+		.hsub = 1,
+		.vsub = 1,
+		.has_alpha = true,
+	}, {
+		.drm_fmt = DRM_FORMAT_XRGB8888_A8,
+		.depth = 32,
+		.num_planes = 2,
+		.cpp = { 4, 1, 0 },
+		.hsub = 1,
+		.vsub = 1,
+		.has_alpha = true,
+	}, {
+		.drm_fmt = DRM_FORMAT_XBGR8888_A8,
+		.depth = 32,
+		.num_planes = 2,
+		.cpp = { 4, 1, 0 },
+		.hsub = 1,
+		.vsub = 1,
+		.has_alpha = true,
+	}, {
+		.drm_fmt = DRM_FORMAT_RGBX8888_A8,
+		.depth = 32,
+		.num_planes = 2,
+		.cpp = { 4, 1, 0 },
+		.hsub = 1,
+		.vsub = 1,
+		.has_alpha = true,
+	}, {
+		.drm_fmt = DRM_FORMAT_BGRX8888_A8,
+		.depth = 32,
+		.num_planes = 2,
+		.cpp = { 4, 1, 0 },
+		.hsub = 1,
+		.vsub = 1,
+		.has_alpha = true,
+	}, {
+		.drm_fmt = DRM_FORMAT_YUV410,
+		.depth = 0,
+		.num_planes = 3,
+		.cpp = { 1, 1, 1 },
+		.hsub = 4,
+		.vsub = 4,
+		.is_yuv = true,
+	}, {
+		.drm_fmt = DRM_FORMAT_YVU410,
+		.depth = 0,
+		.num_planes = 3,
+		.cpp = { 1, 1, 1 },
+		.hsub = 4,
+		.vsub = 4,
+		.is_yuv = true,
+	}, {
+		.drm_fmt = DRM_FORMAT_YUV411,
+		.depth = 0,
+		.num_planes = 3,
+		.cpp = { 1, 1, 1 },
+		.hsub = 4,
+		.vsub = 1,
+		.is_yuv = true,
+	}, {
+		.drm_fmt = DRM_FORMAT_YVU411,
+		.depth = 0,
+		.num_planes = 3,
+		.cpp = { 1, 1, 1 },
+		.hsub = 4,
+		.vsub = 1,
+		.is_yuv = true,
+	}, {
+		.drm_fmt = DRM_FORMAT_YUV420,
+		.depth = 0,
+		.num_planes = 3,
+		.cpp = { 1, 1, 1 },
+		.hsub = 2,
+		.vsub = 2,
+		.is_yuv = true,
+	}, {
+		.drm_fmt = DRM_FORMAT_YVU420,
+		.depth = 0,
+		.num_planes = 3,
+		.cpp = { 1, 1, 1 },
+		.hsub = 2,
+		.vsub = 2,
+		.is_yuv = true,
+	}, {
+		.drm_fmt = DRM_FORMAT_YUV422,
+		.depth = 0,
+		.num_planes = 3,
+		.cpp = { 1, 1, 1 },
+		.hsub = 2,
+		.vsub = 1,
+		.is_yuv = true,
+	}, {
+		.drm_fmt = DRM_FORMAT_YVU422,
+		.depth = 0,
+		.num_planes = 3,
+		.cpp = { 1, 1, 1 },
+		.hsub = 2,
+		.vsub = 1,
+		.is_yuv = true,
+	}, {
+		.drm_fmt = DRM_FORMAT_YUV444,
+		.depth = 0,
+		.num_planes = 3,
+		.cpp = { 1, 1, 1 },
+		.hsub = 1,
+		.vsub = 1,
+		.is_yuv = true,
+	}, {
+		.drm_fmt = DRM_FORMAT_YVU444,
+		.depth = 0,
+		.num_planes = 3,
+		.cpp = { 1, 1, 1 },
+		.hsub = 1,
+		.vsub = 1,
+		.is_yuv = true,
+	}, {
+		.drm_fmt = DRM_FORMAT_NV12,
+		.depth = 0,
+		.num_planes = 2,
+		.cpp = { 1, 2, 0 },
+		.hsub = 2,
+		.vsub = 2,
+		.is_yuv = true,
+	}, {
+		.drm_fmt = DRM_FORMAT_NV21,
+		.depth = 0,
+		.num_planes = 2,
+		.cpp = { 1, 2, 0 },
+		.hsub = 2,
+		.vsub = 2,
+		.is_yuv = true,
+	}, {
+		.drm_fmt = DRM_FORMAT_NV16,
+		.depth = 0,
+		.num_planes = 2,
+		.cpp = { 1, 2, 0 },
+		.hsub = 2,
+		.vsub = 1,
+		.is_yuv = true,
+	}, {
+		.drm_fmt = DRM_FORMAT_NV61,
+		.depth = 0,
+		.num_planes = 2,
+		.cpp = { 1, 2, 0 },
+		.hsub = 2,
+		.vsub = 1,
+		.is_yuv = true,
+	}, {
+		.drm_fmt = DRM_FORMAT_NV24,
+		.depth = 0,
+		.num_planes = 2,
+		.cpp = { 1, 2, 0 },
+		.hsub = 1,
+		.vsub = 1,
+		.is_yuv = true,
+	}, {
+		.drm_fmt = DRM_FORMAT_NV42,
+		.depth = 0,
+		.num_planes = 2,
+		.cpp = { 1, 2, 0 },
+		.hsub = 1,
+		.vsub = 1,
+		.is_yuv = true,
+	}, {
+		.drm_fmt = DRM_FORMAT_YUYV,
+		.depth = 0,
+		.num_planes = 1,
+		.cpp = { 2, 0, 0 },
+		.hsub = 2,
+		.vsub = 1,
+		.is_yuv = true,
+	}, {
+		.drm_fmt = DRM_FORMAT_YVYU,
+		.depth = 0,
+		.num_planes = 1,
+		.cpp = { 2, 0, 0 },
+		.hsub = 2,
+		.vsub = 1,
+		.is_yuv = true,
+	}, {
+		.drm_fmt = DRM_FORMAT_UYVY,
+		.depth = 0,
+		.num_planes = 1,
+		.cpp = { 2, 0, 0 },
+		.hsub = 2,
+		.vsub = 1,
+		.is_yuv = true,
+	}, {
+		.drm_fmt = DRM_FORMAT_VYUY,
+		.depth = 0,
+		.num_planes = 1,
+		.cpp = { 2, 0, 0 },
+		.hsub = 2,
+		.vsub = 1,
+		.is_yuv = true,
+	}, {
+		.drm_fmt = DRM_FORMAT_XYUV8888,
+		.depth = 0,
+		.num_planes = 1,
+		.cpp = { 4, 0, 0 },
+		.hsub = 1,
+		.vsub = 1,
+		.is_yuv = true,
+	}, {
+		.drm_fmt = DRM_FORMAT_AYUV,
+		.depth = 0,
+		.num_planes = 1,
+		.cpp = { 4, 0, 0 },
+		.hsub = 1,
+		.vsub = 1,
+		.has_alpha = true,
+		.is_yuv = true,
+	}, {
+		.drm_fmt = DRM_FORMAT_Y0L0,
+		.depth = 0,
+		.num_planes = 1,
+		.char_per_block = { 8, 0, 0 },
+		.block_w = { 2, 0, 0 },
+		.block_h = { 2, 0, 0 },
+		.hsub = 2,
+		.vsub = 2,
+		.has_alpha = true,
+		.is_yuv = true,
+	}, {
+		.drm_fmt = DRM_FORMAT_X0L0,
+		.depth = 0,
+		.num_planes = 1,
+		.char_per_block = { 8, 0, 0 },
+		.block_w = { 2, 0, 0 },
+		.block_h = { 2, 0, 0 },
+		.hsub = 2,
+		.vsub = 2,
+		.is_yuv = true,
+	}, {
+		.drm_fmt = DRM_FORMAT_Y0L2,
+		.depth = 0,
+		.num_planes = 1,
+		.char_per_block = { 8, 0, 0 },
+		.block_w = { 2, 0, 0 },
+		.block_h = { 2, 0, 0 },
+		.hsub = 2,
+		.vsub = 2,
+		.has_alpha = true,
+		.is_yuv = true,
+	}, {
+		.drm_fmt = DRM_FORMAT_X0L2,
+		.depth = 0,
+		.num_planes = 1,
+		.char_per_block = { 8, 0, 0 },
+		.block_w = { 2, 0, 0 },
+		.block_h = { 2, 0, 0 },
+		.hsub = 2,
+		.vsub = 2,
+		.is_yuv = true,
+	},
+};
+
+#define __image_format_lookup(_field, _fmt)			\
+	({							\
+		const struct image_format_info *format = NULL;	\
+		unsigned i;					\
+								\
+		for (i = 0; i < ARRAY_SIZE(formats); i++)	\
+			if (formats[i]._field == _fmt)		\
+				format = &formats[i];		\
+								\
+		format;						\
+	})
+
+/**
+ * __image_format_drm_lookup - query information for a given format
+ * @drm: DRM fourcc pixel format (DRM_FORMAT_*)
+ *
+ * The caller should only pass a supported pixel format to this function.
+ *
+ * Returns:
+ * The instance of struct image_format_info that describes the pixel format, or
+ * NULL if the format is unsupported.
+ */
+const struct image_format_info *__image_format_drm_lookup(u32 drm)
+{
+	return __image_format_lookup(drm_fmt, drm);
+}
+EXPORT_SYMBOL(__image_format_drm_lookup);
+
+/**
+ * image_format_drm_lookup - query information for a given format
+ * @drm: DRM fourcc pixel format (DRM_FORMAT_*)
+ *
+ * The caller should only pass a supported pixel format to this function.
+ * Unsupported pixel formats will generate a warning in the kernel log.
+ *
+ * Returns:
+ * The instance of struct image_format_info that describes the pixel format, or
+ * NULL if the format is unsupported.
+ */
+const struct image_format_info *image_format_drm_lookup(u32 drm)
+{
+	const struct image_format_info *format;
+
+	format = __image_format_drm_lookup(drm);
+
+	WARN_ON(!format);
+	return format;
+}
+EXPORT_SYMBOL(image_format_drm_lookup);
+
+/**
+ * image_format_plane_cpp - determine the bytes per pixel value
+ * @format: pointer to the image_format
+ * @plane: plane index
+ *
+ * Returns:
+ * The bytes per pixel value for the specified plane.
+ */
+unsigned int image_format_plane_cpp(const struct image_format_info *format,
+				    int plane)
+{
+	if (!format || plane >= format->num_planes)
+		return 0;
+
+	return format->cpp[plane];
+}
+EXPORT_SYMBOL(image_format_plane_cpp);
+
+/**
+ * image_format_plane_width - width of the plane given the first plane
+ * @format: pointer to the image_format
+ * @width: width of the first plane
+ * @plane: plane index
+ *
+ * Returns:
+ * The width of @plane, given that the width of the first plane is @width.
+ */
+unsigned int image_format_plane_width(int width,
+				      const struct image_format_info *format,
+				      int plane)
+{
+	if (!format || plane >= format->num_planes)
+		return 0;
+
+	if (plane == 0)
+		return width;
+
+	return width / format->hsub;
+}
+EXPORT_SYMBOL(image_format_plane_width);
+
+/**
+ * image_format_plane_height - height of the plane given the first plane
+ * @format: pointer to the image_format
+ * @height: height of the first plane
+ * @plane: plane index
+ *
+ * Returns:
+ * The height of @plane, given that the height of the first plane is @height.
+ */
+unsigned int image_format_plane_height(int height,
+				       const struct image_format_info *format,
+				       int plane)
+{
+	if (!format || plane >= format->num_planes)
+		return 0;
+
+	if (plane == 0)
+		return height;
+
+	return height / format->vsub;
+}
+EXPORT_SYMBOL(image_format_plane_height);
+
+/**
+ * image_format_block_width - width in pixels of block.
+ * @format: pointer to the image_format
+ * @plane: plane index
+ *
+ * Returns:
+ * The width in pixels of a block, depending on the plane index.
+ */
+unsigned int image_format_block_width(const struct image_format_info *format,
+				      int plane)
+{
+	if (!format || plane < 0 || plane >= format->num_planes)
+		return 0;
+
+	if (!format->block_w[plane])
+		return 1;
+
+	return format->block_w[plane];
+}
+EXPORT_SYMBOL(image_format_block_width);
+
+/**
+ * image_format_block_height - height in pixels of a block
+ * @info: pointer to the image_format
+ * @plane: plane index
+ *
+ * Returns:
+ * The height in pixels of a block, depending on the plane index.
+ */
+unsigned int image_format_block_height(const struct image_format_info *format,
+				       int plane)
+{
+	if (!format || plane < 0 || plane >= format->num_planes)
+		return 0;
+
+	if (!format->block_h[plane])
+		return 1;
+
+	return format->block_h[plane];
+}
+EXPORT_SYMBOL(image_format_block_height);
+
+/**
+ * image_format_min_pitch - computes the minimum required pitch in bytes
+ * @info: pixel format info
+ * @plane: plane index
+ * @buffer_width: buffer width in pixels
+ *
+ * Returns:
+ * The minimum required pitch in bytes for a buffer by taking into consideration
+ * the pixel format information and the buffer width.
+ */
+uint64_t image_format_min_pitch(const struct image_format_info *info,
+				int plane, unsigned int buffer_width)
+{
+	if (!info || plane < 0 || plane >= info->num_planes)
+		return 0;
+
+	return DIV_ROUND_UP_ULL((u64)buffer_width * info->char_per_block[plane],
+			    image_format_block_width(info, plane) *
+			    image_format_block_height(info, plane));
+}
+EXPORT_SYMBOL(image_format_min_pitch);
-- 
git-series 0.9.1

WARNING: multiple messages have this Message-ID (diff)
From: Maxime Ripard <maxime.ripard@bootlin.com>
To: Daniel Vetter <daniel.vetter@intel.com>,
	David Airlie <airlied@linux.ie>,
	Maarten Lankhorst <maarten.lankhorst@linux.intel.com>,
	Sean Paul <seanpaul@chromium.org>,
	Maxime Ripard <maxime.ripard@bootlin.com>,
	Mauro Carvalho Chehab <mchehab@kernel.org>
Cc: Sakari Ailus <sakari.ailus@linux.intel.com>,
	linux-kernel@vger.kernel.org, dri-devel@lists.freedesktop.org,
	Paul Kocialkowski <paul.kocialkowski@bootlin.com>,
	Hans Verkuil <hans.verkuil@cisco.com>,
	Laurent Pinchart <laurent.pinchart@ideasonboard.com>,
	Thomas Petazzoni <thomas.petazzoni@bootlin.com>,
	linux-media@vger.kernel.org
Subject: [RFC PATCH 06/20] lib: Add video format information library
Date: Tue, 19 Mar 2019 22:57:11 +0100	[thread overview]
Message-ID: <a2ecd9e599e0b536c2a005e5feb140463566788e.1553032382.git-series.maxime.ripard@bootlin.com> (raw)
In-Reply-To: <cover.92acdec88ee4c280cb74e08ea22f0075e5fa055c.1553032382.git-series.maxime.ripard@bootlin.com>

Move the DRM formats API to turn this into a more generic image formats API
to be able to leverage it into some other places of the kernel, such as
v4l2 drivers.

Signed-off-by: Maxime Ripard <maxime.ripard@bootlin.com>
---
 include/linux/image-formats.h | 240 +++++++++++-
 lib/Kconfig                   |   7 +-
 lib/Makefile                  |   3 +-
 lib/image-formats-selftests.c | 326 +++++++++++++++-
 lib/image-formats.c           | 760 +++++++++++++++++++++++++++++++++++-
 5 files changed, 1336 insertions(+)
 create mode 100644 include/linux/image-formats.h
 create mode 100644 lib/image-formats-selftests.c
 create mode 100644 lib/image-formats.c

diff --git a/include/linux/image-formats.h b/include/linux/image-formats.h
new file mode 100644
index 000000000000..53fd73a71b3d
--- /dev/null
+++ b/include/linux/image-formats.h
@@ -0,0 +1,240 @@
+#ifndef _IMAGE_FORMATS_H_
+#define _IMAGE_FORMATS_H_
+
+#include <linux/types.h>
+
+/**
+ * struct image_format_info - information about a image format
+ */
+struct image_format_info {
+	union {
+		/**
+		 * @drm_fmt:
+		 *
+		 * DRM 4CC format identifier (DRM_FORMAT_*)
+		 */
+		u32 drm_fmt;
+
+		/**
+		 * @format:
+		 *
+		 * DRM 4CC format identifier (DRM_FORMAT_*). Kept
+		 * around for compatibility reasons with the current
+		 * DRM drivers.
+		 */
+		u32 format;
+	};
+
+	/**
+	 * @depth:
+	 *
+	 * Color depth (number of bits per pixel excluding padding bits),
+	 * valid for a subset of RGB formats only. This is a legacy field, do
+	 * not use in new code and set to 0 for new formats.
+	 */
+	u8 depth;
+
+	/** @num_planes: Number of color planes (1 to 3) */
+	u8 num_planes;
+
+	union {
+		/**
+		 * @cpp:
+		 *
+		 * Number of bytes per pixel (per plane), this is aliased with
+		 * @char_per_block. It is deprecated in favour of using the
+		 * triplet @char_per_block, @block_w, @block_h for better
+		 * describing the pixel format.
+		 */
+		u8 cpp[3];
+
+		/**
+		 * @char_per_block:
+		 *
+		 * Number of bytes per block (per plane), where blocks are
+		 * defined as a rectangle of pixels which are stored next to
+		 * each other in a byte aligned memory region. Together with
+		 * @block_w and @block_h this is used to properly describe tiles
+		 * in tiled formats or to describe groups of pixels in packed
+		 * formats for which the memory needed for a single pixel is not
+		 * byte aligned.
+		 *
+		 * @cpp has been kept for historical reasons because there are
+		 * a lot of places in drivers where it's used. In drm core for
+		 * generic code paths the preferred way is to use
+		 * @char_per_block, image_format_block_width() and
+		 * image_format_block_height() which allows handling both
+		 * block and non-block formats in the same way.
+		 *
+		 * For formats that are intended to be used only with non-linear
+		 * modifiers both @cpp and @char_per_block must be 0 in the
+		 * generic format table. Drivers could supply accurate
+		 * information from their drm_mode_config.get_format_info hook
+		 * if they want the core to be validating the pitch.
+		 */
+		u8 char_per_block[3];
+	};
+
+	/**
+	 * @block_w:
+	 *
+	 * Block width in pixels, this is intended to be accessed through
+	 * image_format_block_width()
+	 */
+	u8 block_w[3];
+
+	/**
+	 * @block_h:
+	 *
+	 * Block height in pixels, this is intended to be accessed through
+	 * image_format_block_height()
+	 */
+	u8 block_h[3];
+
+	/** @hsub: Horizontal chroma subsampling factor */
+	u8 hsub;
+	/** @vsub: Vertical chroma subsampling factor */
+	u8 vsub;
+
+	/** @has_alpha: Does the format embeds an alpha component? */
+	bool has_alpha;
+
+	/** @is_yuv: Is it a YUV format? */
+	bool is_yuv;
+};
+
+/**
+ * image_format_info_is_yuv_packed - check that the format info matches a YUV
+ * format with data laid in a single plane
+ * @info: format info
+ *
+ * Returns:
+ * A boolean indicating whether the format info matches a packed YUV format.
+ */
+static inline bool
+image_format_info_is_yuv_packed(const struct image_format_info *info)
+{
+	return info->is_yuv && info->num_planes == 1;
+}
+
+/**
+ * image_format_info_is_yuv_semiplanar - check that the format info matches a YUV
+ * format with data laid in two planes (luminance and chrominance)
+ * @info: format info
+ *
+ * Returns:
+ * A boolean indicating whether the format info matches a semiplanar YUV format.
+ */
+static inline bool
+image_format_info_is_yuv_semiplanar(const struct image_format_info *info)
+{
+	return info->is_yuv && info->num_planes == 2;
+}
+
+/**
+ * image_format_info_is_yuv_planar - check that the format info matches a YUV
+ * format with data laid in three planes (one for each YUV component)
+ * @info: format info
+ *
+ * Returns:
+ * A boolean indicating whether the format info matches a planar YUV format.
+ */
+static inline bool
+image_format_info_is_yuv_planar(const struct image_format_info *info)
+{
+	return info->is_yuv && info->num_planes == 3;
+}
+
+/**
+ * image_format_info_is_yuv_sampling_410 - check that the format info matches a
+ * YUV format with 4:1:0 sub-sampling
+ * @info: format info
+ *
+ * Returns:
+ * A boolean indicating whether the format info matches a YUV format with 4:1:0
+ * sub-sampling.
+ */
+static inline bool
+image_format_info_is_yuv_sampling_410(const struct image_format_info *info)
+{
+	return info->is_yuv && info->hsub == 4 && info->vsub == 4;
+}
+
+/**
+ * image_format_info_is_yuv_sampling_411 - check that the format info matches a
+ * YUV format with 4:1:1 sub-sampling
+ * @info: format info
+ *
+ * Returns:
+ * A boolean indicating whether the format info matches a YUV format with 4:1:1
+ * sub-sampling.
+ */
+static inline bool
+image_format_info_is_yuv_sampling_411(const struct image_format_info *info)
+{
+	return info->is_yuv && info->hsub == 4 && info->vsub == 1;
+}
+
+/**
+ * image_format_info_is_yuv_sampling_420 - check that the format info matches a
+ * YUV format with 4:2:0 sub-sampling
+ * @info: format info
+ *
+ * Returns:
+ * A boolean indicating whether the format info matches a YUV format with 4:2:0
+ * sub-sampling.
+ */
+static inline bool
+image_format_info_is_yuv_sampling_420(const struct image_format_info *info)
+{
+	return info->is_yuv && info->hsub == 2 && info->vsub == 2;
+}
+
+/**
+ * image_format_info_is_yuv_sampling_422 - check that the format info matches a
+ * YUV format with 4:2:2 sub-sampling
+ * @info: format info
+ *
+ * Returns:
+ * A boolean indicating whether the format info matches a YUV format with 4:2:2
+ * sub-sampling.
+ */
+static inline bool
+image_format_info_is_yuv_sampling_422(const struct image_format_info *info)
+{
+	return info->is_yuv && info->hsub == 2 && info->vsub == 1;
+}
+
+/**
+ * image_format_info_is_yuv_sampling_444 - check that the format info matches a
+ * YUV format with 4:4:4 sub-sampling
+ * @info: format info
+ *
+ * Returns:
+ * A boolean indicating whether the format info matches a YUV format with 4:4:4
+ * sub-sampling.
+ */
+static inline bool
+image_format_info_is_yuv_sampling_444(const struct image_format_info *info)
+{
+	return info->is_yuv && info->hsub == 1 && info->vsub == 1;
+}
+
+const struct image_format_info *__image_format_drm_lookup(u32 drm);
+const struct image_format_info *image_format_drm_lookup(u32 drm);
+unsigned int image_format_plane_cpp(const struct image_format_info *format,
+				    int plane);
+unsigned int image_format_plane_width(int width,
+				      const struct image_format_info *format,
+				      int plane);
+unsigned int image_format_plane_height(int height,
+				       const struct image_format_info *format,
+				       int plane);
+unsigned int image_format_block_width(const struct image_format_info *format,
+				      int plane);
+unsigned int image_format_block_height(const struct image_format_info *format,
+				       int plane);
+uint64_t image_format_min_pitch(const struct image_format_info *info,
+				int plane, unsigned int buffer_width);
+
+#endif /* _IMAGE_FORMATS_H_ */
diff --git a/lib/Kconfig b/lib/Kconfig
index a9e56539bd11..421acac83b13 100644
--- a/lib/Kconfig
+++ b/lib/Kconfig
@@ -635,3 +635,10 @@ config GENERIC_LIB_UCMPDI2
 
 config OBJAGG
 	tristate "objagg" if COMPILE_TEST
+
+config IMAGE_FORMATS
+	bool
+
+config IMAGE_FORMATS_SELFTESTS
+	tristate "Test image format functions"
+	depends on IMAGE_FORMATS
diff --git a/lib/Makefile b/lib/Makefile
index e1b59da71418..b1916e6d30da 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -276,3 +276,6 @@ obj-$(CONFIG_GENERIC_LIB_MULDI3) += muldi3.o
 obj-$(CONFIG_GENERIC_LIB_CMPDI2) += cmpdi2.o
 obj-$(CONFIG_GENERIC_LIB_UCMPDI2) += ucmpdi2.o
 obj-$(CONFIG_OBJAGG) += objagg.o
+
+obj-$(CONFIG_IMAGE_FORMATS) += image-formats.o
+obj-$(CONFIG_IMAGE_FORMATS_SELFTESTS) += image-formats-selftests.o
diff --git a/lib/image-formats-selftests.c b/lib/image-formats-selftests.c
new file mode 100644
index 000000000000..8fdc50b15dcc
--- /dev/null
+++ b/lib/image-formats-selftests.c
@@ -0,0 +1,326 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Test cases for the image_format functions
+ */
+
+#define pr_fmt(fmt) "image_format: " fmt
+
+#include <linux/errno.h>
+#include <linux/image-formats.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+
+#include <drm/drm_fourcc.h>
+
+#define FAIL(test, msg, ...) \
+	do { \
+		if (test) { \
+			pr_err("%s/%u: " msg, __FUNCTION__, __LINE__, ##__VA_ARGS__); \
+			return -EINVAL; \
+		} \
+	} while (0)
+
+#define FAIL_ON(x) FAIL((x), "%s", "FAIL_ON(" __stringify(x) ")\n")
+
+static int test_image_format_block_width(void)
+{
+	const struct image_format_info *info = NULL;
+
+	/* Test invalid arguments */
+	FAIL_ON(image_format_block_width(info, 0) != 0);
+	FAIL_ON(image_format_block_width(info, -1) != 0);
+	FAIL_ON(image_format_block_width(info, 1) != 0);
+
+	/* Test 1 plane format */
+	info = image_format_drm_lookup(DRM_FORMAT_XRGB4444);
+	FAIL_ON(!info);
+	FAIL_ON(image_format_block_width(info, 0) != 1);
+	FAIL_ON(image_format_block_width(info, 1) != 0);
+	FAIL_ON(image_format_block_width(info, -1) != 0);
+
+	/* Test 2 planes format */
+	info = image_format_drm_lookup(DRM_FORMAT_NV12);
+	FAIL_ON(!info);
+	FAIL_ON(image_format_block_width(info, 0) != 1);
+	FAIL_ON(image_format_block_width(info, 1) != 1);
+	FAIL_ON(image_format_block_width(info, 2) != 0);
+	FAIL_ON(image_format_block_width(info, -1) != 0);
+
+	/* Test 3 planes format */
+	info = image_format_drm_lookup(DRM_FORMAT_YUV422);
+	FAIL_ON(!info);
+	FAIL_ON(image_format_block_width(info, 0) != 1);
+	FAIL_ON(image_format_block_width(info, 1) != 1);
+	FAIL_ON(image_format_block_width(info, 2) != 1);
+	FAIL_ON(image_format_block_width(info, 3) != 0);
+	FAIL_ON(image_format_block_width(info, -1) != 0);
+
+	/* Test a tiled format */
+	info = image_format_drm_lookup(DRM_FORMAT_X0L0);
+	FAIL_ON(!info);
+	FAIL_ON(image_format_block_width(info, 0) != 2);
+	FAIL_ON(image_format_block_width(info, 1) != 0);
+	FAIL_ON(image_format_block_width(info, -1) != 0);
+
+	return 0;
+}
+
+static int test_image_format_block_height(void)
+{
+	const struct image_format_info *info = NULL;
+
+	/* Test invalid arguments */
+	FAIL_ON(image_format_block_height(info, 0) != 0);
+	FAIL_ON(image_format_block_height(info, -1) != 0);
+	FAIL_ON(image_format_block_height(info, 1) != 0);
+
+	/* Test 1 plane format */
+	info = image_format_drm_lookup(DRM_FORMAT_XRGB4444);
+	FAIL_ON(!info);
+	FAIL_ON(image_format_block_height(info, 0) != 1);
+	FAIL_ON(image_format_block_height(info, 1) != 0);
+	FAIL_ON(image_format_block_height(info, -1) != 0);
+
+	/* Test 2 planes format */
+	info = image_format_drm_lookup(DRM_FORMAT_NV12);
+	FAIL_ON(!info);
+	FAIL_ON(image_format_block_height(info, 0) != 1);
+	FAIL_ON(image_format_block_height(info, 1) != 1);
+	FAIL_ON(image_format_block_height(info, 2) != 0);
+	FAIL_ON(image_format_block_height(info, -1) != 0);
+
+	/* Test 3 planes format */
+	info = image_format_drm_lookup(DRM_FORMAT_YUV422);
+	FAIL_ON(!info);
+	FAIL_ON(image_format_block_height(info, 0) != 1);
+	FAIL_ON(image_format_block_height(info, 1) != 1);
+	FAIL_ON(image_format_block_height(info, 2) != 1);
+	FAIL_ON(image_format_block_height(info, 3) != 0);
+	FAIL_ON(image_format_block_height(info, -1) != 0);
+
+	/* Test a tiled format */
+	info = image_format_drm_lookup(DRM_FORMAT_X0L0);
+	FAIL_ON(!info);
+	FAIL_ON(image_format_block_height(info, 0) != 2);
+	FAIL_ON(image_format_block_height(info, 1) != 0);
+	FAIL_ON(image_format_block_height(info, -1) != 0);
+
+	return 0;
+}
+
+static int test_image_format_min_pitch(void)
+{
+	const struct image_format_info *info = NULL;
+
+	/* Test invalid arguments */
+	FAIL_ON(image_format_min_pitch(info, 0, 0) != 0);
+	FAIL_ON(image_format_min_pitch(info, -1, 0) != 0);
+	FAIL_ON(image_format_min_pitch(info, 1, 0) != 0);
+
+	/* Test 1 plane 8 bits per pixel format */
+	info = image_format_drm_lookup(DRM_FORMAT_RGB332);
+	FAIL_ON(!info);
+	FAIL_ON(image_format_min_pitch(info, 0, 0) != 0);
+	FAIL_ON(image_format_min_pitch(info, -1, 0) != 0);
+	FAIL_ON(image_format_min_pitch(info, 1, 0) != 0);
+
+	FAIL_ON(image_format_min_pitch(info, 0, 1) != 1);
+	FAIL_ON(image_format_min_pitch(info, 0, 2) != 2);
+	FAIL_ON(image_format_min_pitch(info, 0, 640) != 640);
+	FAIL_ON(image_format_min_pitch(info, 0, 1024) != 1024);
+	FAIL_ON(image_format_min_pitch(info, 0, 1920) != 1920);
+	FAIL_ON(image_format_min_pitch(info, 0, 4096) != 4096);
+	FAIL_ON(image_format_min_pitch(info, 0, 671) != 671);
+	FAIL_ON(image_format_min_pitch(info, 0, UINT_MAX) !=
+			(uint64_t)UINT_MAX);
+	FAIL_ON(image_format_min_pitch(info, 0, (UINT_MAX - 1)) !=
+			(uint64_t)(UINT_MAX - 1));
+
+	/* Test 1 plane 16 bits per pixel format */
+	info = image_format_drm_lookup(DRM_FORMAT_XRGB4444);
+	FAIL_ON(!info);
+	FAIL_ON(image_format_min_pitch(info, 0, 0) != 0);
+	FAIL_ON(image_format_min_pitch(info, -1, 0) != 0);
+	FAIL_ON(image_format_min_pitch(info, 1, 0) != 0);
+
+	FAIL_ON(image_format_min_pitch(info, 0, 1) != 2);
+	FAIL_ON(image_format_min_pitch(info, 0, 2) != 4);
+	FAIL_ON(image_format_min_pitch(info, 0, 640) != 1280);
+	FAIL_ON(image_format_min_pitch(info, 0, 1024) != 2048);
+	FAIL_ON(image_format_min_pitch(info, 0, 1920) != 3840);
+	FAIL_ON(image_format_min_pitch(info, 0, 4096) != 8192);
+	FAIL_ON(image_format_min_pitch(info, 0, 671) != 1342);
+	FAIL_ON(image_format_min_pitch(info, 0, UINT_MAX) !=
+			(uint64_t)UINT_MAX * 2);
+	FAIL_ON(image_format_min_pitch(info, 0, (UINT_MAX - 1)) !=
+			(uint64_t)(UINT_MAX - 1) * 2);
+
+	/* Test 1 plane 24 bits per pixel format */
+	info = image_format_drm_lookup(DRM_FORMAT_RGB888);
+	FAIL_ON(!info);
+	FAIL_ON(image_format_min_pitch(info, 0, 0) != 0);
+	FAIL_ON(image_format_min_pitch(info, -1, 0) != 0);
+	FAIL_ON(image_format_min_pitch(info, 1, 0) != 0);
+
+	FAIL_ON(image_format_min_pitch(info, 0, 1) != 3);
+	FAIL_ON(image_format_min_pitch(info, 0, 2) != 6);
+	FAIL_ON(image_format_min_pitch(info, 0, 640) != 1920);
+	FAIL_ON(image_format_min_pitch(info, 0, 1024) != 3072);
+	FAIL_ON(image_format_min_pitch(info, 0, 1920) != 5760);
+	FAIL_ON(image_format_min_pitch(info, 0, 4096) != 12288);
+	FAIL_ON(image_format_min_pitch(info, 0, 671) != 2013);
+	FAIL_ON(image_format_min_pitch(info, 0, UINT_MAX) !=
+			(uint64_t)UINT_MAX * 3);
+	FAIL_ON(image_format_min_pitch(info, 0, UINT_MAX - 1) !=
+			(uint64_t)(UINT_MAX - 1) * 3);
+
+	/* Test 1 plane 32 bits per pixel format */
+	info = image_format_drm_lookup(DRM_FORMAT_ABGR8888);
+	FAIL_ON(!info);
+	FAIL_ON(image_format_min_pitch(info, 0, 0) != 0);
+	FAIL_ON(image_format_min_pitch(info, -1, 0) != 0);
+	FAIL_ON(image_format_min_pitch(info, 1, 0) != 0);
+
+	FAIL_ON(image_format_min_pitch(info, 0, 1) != 4);
+	FAIL_ON(image_format_min_pitch(info, 0, 2) != 8);
+	FAIL_ON(image_format_min_pitch(info, 0, 640) != 2560);
+	FAIL_ON(image_format_min_pitch(info, 0, 1024) != 4096);
+	FAIL_ON(image_format_min_pitch(info, 0, 1920) != 7680);
+	FAIL_ON(image_format_min_pitch(info, 0, 4096) != 16384);
+	FAIL_ON(image_format_min_pitch(info, 0, 671) != 2684);
+	FAIL_ON(image_format_min_pitch(info, 0, UINT_MAX) !=
+			(uint64_t)UINT_MAX * 4);
+	FAIL_ON(image_format_min_pitch(info, 0, UINT_MAX - 1) !=
+			(uint64_t)(UINT_MAX - 1) * 4);
+
+	/* Test 2 planes format */
+	info = image_format_drm_lookup(DRM_FORMAT_NV12);
+	FAIL_ON(!info);
+	FAIL_ON(image_format_min_pitch(info, 0, 0) != 0);
+	FAIL_ON(image_format_min_pitch(info, 1, 0) != 0);
+	FAIL_ON(image_format_min_pitch(info, -1, 0) != 0);
+	FAIL_ON(image_format_min_pitch(info, 2, 0) != 0);
+
+	FAIL_ON(image_format_min_pitch(info, 0, 1) != 1);
+	FAIL_ON(image_format_min_pitch(info, 1, 1) != 2);
+	FAIL_ON(image_format_min_pitch(info, 0, 2) != 2);
+	FAIL_ON(image_format_min_pitch(info, 1, 1) != 2);
+	FAIL_ON(image_format_min_pitch(info, 0, 640) != 640);
+	FAIL_ON(image_format_min_pitch(info, 1, 320) != 640);
+	FAIL_ON(image_format_min_pitch(info, 0, 1024) != 1024);
+	FAIL_ON(image_format_min_pitch(info, 1, 512) != 1024);
+	FAIL_ON(image_format_min_pitch(info, 0, 1920) != 1920);
+	FAIL_ON(image_format_min_pitch(info, 1, 960) != 1920);
+	FAIL_ON(image_format_min_pitch(info, 0, 4096) != 4096);
+	FAIL_ON(image_format_min_pitch(info, 1, 2048) != 4096);
+	FAIL_ON(image_format_min_pitch(info, 0, 671) != 671);
+	FAIL_ON(image_format_min_pitch(info, 1, 336) != 672);
+	FAIL_ON(image_format_min_pitch(info, 0, UINT_MAX) !=
+			(uint64_t)UINT_MAX);
+	FAIL_ON(image_format_min_pitch(info, 1, UINT_MAX / 2 + 1) !=
+			(uint64_t)UINT_MAX + 1);
+	FAIL_ON(image_format_min_pitch(info, 0, (UINT_MAX - 1)) !=
+			(uint64_t)(UINT_MAX - 1));
+	FAIL_ON(image_format_min_pitch(info, 1, (UINT_MAX - 1) /  2) !=
+			(uint64_t)(UINT_MAX - 1));
+
+	/* Test 3 planes 8 bits per pixel format */
+	info = image_format_drm_lookup(DRM_FORMAT_YUV422);
+	FAIL_ON(!info);
+	FAIL_ON(image_format_min_pitch(info, 0, 0) != 0);
+	FAIL_ON(image_format_min_pitch(info, 1, 0) != 0);
+	FAIL_ON(image_format_min_pitch(info, 2, 0) != 0);
+	FAIL_ON(image_format_min_pitch(info, -1, 0) != 0);
+	FAIL_ON(image_format_min_pitch(info, 3, 0) != 0);
+
+	FAIL_ON(image_format_min_pitch(info, 0, 1) != 1);
+	FAIL_ON(image_format_min_pitch(info, 1, 1) != 1);
+	FAIL_ON(image_format_min_pitch(info, 2, 1) != 1);
+	FAIL_ON(image_format_min_pitch(info, 0, 2) != 2);
+	FAIL_ON(image_format_min_pitch(info, 1, 2) != 2);
+	FAIL_ON(image_format_min_pitch(info, 2, 2) != 2);
+	FAIL_ON(image_format_min_pitch(info, 0, 640) != 640);
+	FAIL_ON(image_format_min_pitch(info, 1, 320) != 320);
+	FAIL_ON(image_format_min_pitch(info, 2, 320) != 320);
+	FAIL_ON(image_format_min_pitch(info, 0, 1024) != 1024);
+	FAIL_ON(image_format_min_pitch(info, 1, 512) != 512);
+	FAIL_ON(image_format_min_pitch(info, 2, 512) != 512);
+	FAIL_ON(image_format_min_pitch(info, 0, 1920) != 1920);
+	FAIL_ON(image_format_min_pitch(info, 1, 960) != 960);
+	FAIL_ON(image_format_min_pitch(info, 2, 960) != 960);
+	FAIL_ON(image_format_min_pitch(info, 0, 4096) != 4096);
+	FAIL_ON(image_format_min_pitch(info, 1, 2048) != 2048);
+	FAIL_ON(image_format_min_pitch(info, 2, 2048) != 2048);
+	FAIL_ON(image_format_min_pitch(info, 0, 671) != 671);
+	FAIL_ON(image_format_min_pitch(info, 1, 336) != 336);
+	FAIL_ON(image_format_min_pitch(info, 2, 336) != 336);
+	FAIL_ON(image_format_min_pitch(info, 0, UINT_MAX) !=
+			(uint64_t)UINT_MAX);
+	FAIL_ON(image_format_min_pitch(info, 1, UINT_MAX / 2 + 1) !=
+			(uint64_t)UINT_MAX / 2 + 1);
+	FAIL_ON(image_format_min_pitch(info, 2, UINT_MAX / 2 + 1) !=
+			(uint64_t)UINT_MAX / 2 + 1);
+	FAIL_ON(image_format_min_pitch(info, 0, (UINT_MAX - 1) / 2) !=
+			(uint64_t)(UINT_MAX - 1) / 2);
+	FAIL_ON(image_format_min_pitch(info, 1, (UINT_MAX - 1) / 2) !=
+			(uint64_t)(UINT_MAX - 1) / 2);
+	FAIL_ON(image_format_min_pitch(info, 2, (UINT_MAX - 1) / 2) !=
+			(uint64_t)(UINT_MAX - 1) / 2);
+
+	/* Test tiled format */
+	info = image_format_drm_lookup(DRM_FORMAT_X0L2);
+	FAIL_ON(!info);
+	FAIL_ON(image_format_min_pitch(info, 0, 0) != 0);
+	FAIL_ON(image_format_min_pitch(info, -1, 0) != 0);
+	FAIL_ON(image_format_min_pitch(info, 1, 0) != 0);
+
+	FAIL_ON(image_format_min_pitch(info, 0, 1) != 2);
+	FAIL_ON(image_format_min_pitch(info, 0, 2) != 4);
+	FAIL_ON(image_format_min_pitch(info, 0, 640) != 1280);
+	FAIL_ON(image_format_min_pitch(info, 0, 1024) != 2048);
+	FAIL_ON(image_format_min_pitch(info, 0, 1920) != 3840);
+	FAIL_ON(image_format_min_pitch(info, 0, 4096) != 8192);
+	FAIL_ON(image_format_min_pitch(info, 0, 671) != 1342);
+	FAIL_ON(image_format_min_pitch(info, 0, UINT_MAX) !=
+			(uint64_t)UINT_MAX * 2);
+	FAIL_ON(image_format_min_pitch(info, 0, UINT_MAX - 1) !=
+			(uint64_t)(UINT_MAX - 1) * 2);
+
+	return 0;
+}
+
+#define selftest(test)	{ .name = #test, .func = test, }
+
+static struct image_format_test {
+	char	*name;
+	int	(*func)(void);
+} tests[] = {
+	selftest(test_image_format_block_height),
+	selftest(test_image_format_block_width),
+	selftest(test_image_format_min_pitch),
+};
+
+static int __init image_format_test_init(void)
+{
+	unsigned int i;
+
+	for (i = 0; i < ARRAY_SIZE(tests); i++) {
+		struct image_format_test *test = &tests[i];
+		int ret;
+
+		ret = test->func();
+		if (ret) {
+			pr_err("Failed test %s\n", test->name);
+			return ret;
+		}
+	}
+
+	pr_info("All tests executed properly.\n");
+	return 0;
+}
+
+static void __exit image_format_test_exit(void)
+{
+}
+module_init(image_format_test_init);
+module_exit(image_format_test_exit);
diff --git a/lib/image-formats.c b/lib/image-formats.c
new file mode 100644
index 000000000000..9b9a73220c5d
--- /dev/null
+++ b/lib/image-formats.c
@@ -0,0 +1,760 @@
+#include <linux/bug.h>
+#include <linux/image-formats.h>
+#include <linux/kernel.h>
+#include <linux/math64.h>
+
+#include <uapi/drm/drm_fourcc.h>
+
+static const struct image_format_info formats[] = {
+	{
+		.drm_fmt = DRM_FORMAT_C8,
+		.depth = 8,
+		.num_planes = 1,
+		.cpp = { 1, 0, 0 },
+		.hsub = 1,
+		.vsub = 1,
+	}, {
+		.drm_fmt = DRM_FORMAT_RGB332,
+		.depth = 8,
+		.num_planes = 1,
+		.cpp = { 1, 0, 0 },
+		.hsub = 1,
+		.vsub = 1,
+	}, {
+		.drm_fmt = DRM_FORMAT_BGR233,
+		.depth = 8,
+		.num_planes = 1,
+		.cpp = { 1, 0, 0 },
+		.hsub = 1,
+		.vsub = 1,
+	}, {
+		.drm_fmt = DRM_FORMAT_XRGB4444,
+		.depth = 0,
+		.num_planes = 1,
+		.cpp = { 2, 0, 0 },
+		.hsub = 1,
+		.vsub = 1,
+	}, {
+		.drm_fmt = DRM_FORMAT_XBGR4444,
+		.depth = 0,
+		.num_planes = 1,
+		.cpp = { 2, 0, 0 },
+		.hsub = 1,
+		.vsub = 1,
+	}, {
+		.drm_fmt = DRM_FORMAT_RGBX4444,
+		.depth = 0,
+		.num_planes = 1,
+		.cpp = { 2, 0, 0 },
+		.hsub = 1,
+		.vsub = 1,
+	}, {
+		.drm_fmt = DRM_FORMAT_BGRX4444,
+		.depth = 0,
+		.num_planes = 1,
+		.cpp = { 2, 0, 0 },
+		.hsub = 1,
+		.vsub = 1,
+	}, {
+		.drm_fmt = DRM_FORMAT_ARGB4444,
+		.depth = 0,
+		.num_planes = 1,
+		.cpp = { 2, 0, 0 },
+		.hsub = 1,
+		.vsub = 1,
+		.has_alpha = true,
+	}, {
+		.drm_fmt = DRM_FORMAT_ABGR4444,
+		.depth = 0,
+		.num_planes = 1,
+		.cpp = { 2, 0, 0 },
+		.hsub = 1,
+		.vsub = 1,
+		.has_alpha = true,
+	}, {
+		.drm_fmt = DRM_FORMAT_RGBA4444,
+		.depth = 0,
+		.num_planes = 1,
+		.cpp = { 2, 0, 0 },
+		.hsub = 1,
+		.vsub = 1,
+		.has_alpha = true,
+	}, {
+		.drm_fmt = DRM_FORMAT_BGRA4444,
+		.depth = 0,
+		.num_planes = 1,
+		.cpp = { 2, 0, 0 },
+		.hsub = 1,
+		.vsub = 1,
+		.has_alpha = true,
+	}, {
+		.drm_fmt = DRM_FORMAT_XRGB1555,
+		.depth = 15,
+		.num_planes = 1,
+		.cpp = { 2, 0, 0 },
+		.hsub = 1,
+		.vsub = 1,
+	}, {
+		.drm_fmt = DRM_FORMAT_XBGR1555,
+		.depth = 15,
+		.num_planes = 1,
+		.cpp = { 2, 0, 0 },
+		.hsub = 1,
+		.vsub = 1,
+	}, {
+		.drm_fmt = DRM_FORMAT_RGBX5551,
+		.depth = 15,
+		.num_planes = 1,
+		.cpp = { 2, 0, 0 },
+		.hsub = 1,
+		.vsub = 1,
+	}, {
+		.drm_fmt = DRM_FORMAT_BGRX5551,
+		.depth = 15,
+		.num_planes = 1,
+		.cpp = { 2, 0, 0 },
+		.hsub = 1,
+		.vsub = 1,
+	}, {
+		.drm_fmt = DRM_FORMAT_ARGB1555,
+		.depth = 15,
+		.num_planes = 1,
+		.cpp = { 2, 0, 0 },
+		.hsub = 1,
+		.vsub = 1,
+		.has_alpha = true,
+	}, {
+		.drm_fmt = DRM_FORMAT_ABGR1555,
+		.depth = 15,
+		.num_planes = 1,
+		.cpp = { 2, 0, 0 },
+		.hsub = 1,
+		.vsub = 1,
+		.has_alpha = true,
+	}, {
+		.drm_fmt = DRM_FORMAT_RGBA5551,
+		.depth = 15,
+		.num_planes = 1,
+		.cpp = { 2, 0, 0 },
+		.hsub = 1,
+		.vsub = 1,
+		.has_alpha = true,
+	}, {
+		.drm_fmt = DRM_FORMAT_BGRA5551,
+		.depth = 15,
+		.num_planes = 1,
+		.cpp = { 2, 0, 0 },
+		.hsub = 1,
+		.vsub = 1,
+		.has_alpha = true,
+	}, {
+		.drm_fmt = DRM_FORMAT_RGB565,
+		.depth = 16,
+		.num_planes = 1,
+		.cpp = { 2, 0, 0 },
+		.hsub = 1,
+		.vsub = 1,
+	}, {
+		.drm_fmt = DRM_FORMAT_BGR565,
+		.depth = 16,
+		.num_planes = 1,
+		.cpp = { 2, 0, 0 },
+		.hsub = 1,
+		.vsub = 1,
+	}, {
+		.drm_fmt = DRM_FORMAT_RGB888,
+		.depth = 24,
+		.num_planes = 1,
+		.cpp = { 3, 0, 0 },
+		.hsub = 1,
+		.vsub = 1,
+	}, {
+		.drm_fmt = DRM_FORMAT_BGR888,
+		.depth = 24,
+		.num_planes = 1,
+		.cpp = { 3, 0, 0 },
+		.hsub = 1,
+		.vsub = 1,
+	}, {
+		.drm_fmt = DRM_FORMAT_XRGB8888,
+		.depth = 24,
+		.num_planes = 1,
+		.cpp = { 4, 0, 0 },
+		.hsub = 1,
+		.vsub = 1,
+	}, {
+		.drm_fmt = DRM_FORMAT_XBGR8888,
+		.depth = 24,
+		.num_planes = 1,
+		.cpp = { 4, 0, 0 },
+		.hsub = 1,
+		.vsub = 1,
+	}, {
+		.drm_fmt = DRM_FORMAT_RGBX8888,
+		.depth = 24,
+		.num_planes = 1,
+		.cpp = { 4, 0, 0 },
+		.hsub = 1,
+		.vsub = 1,
+	}, {
+		.drm_fmt = DRM_FORMAT_BGRX8888,
+		.depth = 24,
+		.num_planes = 1,
+		.cpp = { 4, 0, 0 },
+		.hsub = 1,
+		.vsub = 1,
+	}, {
+		.drm_fmt = DRM_FORMAT_RGB565_A8,
+		.depth = 24,
+		.num_planes = 2,
+		.cpp = { 2, 1, 0 },
+		.hsub = 1,
+		.vsub = 1,
+		.has_alpha = true,
+	}, {
+		.drm_fmt = DRM_FORMAT_BGR565_A8,
+		.depth = 24,
+		.num_planes = 2,
+		.cpp = { 2, 1, 0 },
+		.hsub = 1,
+		.vsub = 1,
+		.has_alpha = true,
+	}, {
+		.drm_fmt = DRM_FORMAT_XRGB2101010,
+		.depth = 30,
+		.num_planes = 1,
+		.cpp = { 4, 0, 0 },
+		.hsub = 1,
+		.vsub = 1,
+	}, {
+		.drm_fmt = DRM_FORMAT_XBGR2101010,
+		.depth = 30,
+		.num_planes = 1,
+		.cpp = { 4, 0, 0 },
+		.hsub = 1,
+		.vsub = 1,
+	}, {
+		.drm_fmt = DRM_FORMAT_RGBX1010102,
+		.depth = 30,
+		.num_planes = 1,
+		.cpp = { 4, 0, 0 },
+		.hsub = 1,
+		.vsub = 1,
+	}, {
+		.drm_fmt = DRM_FORMAT_BGRX1010102,
+		.depth = 30,
+		.num_planes = 1,
+		.cpp = { 4, 0, 0 },
+		.hsub = 1,
+		.vsub = 1,
+	}, {
+		.drm_fmt = DRM_FORMAT_ARGB2101010,
+		.depth = 30,
+		.num_planes = 1,
+		.cpp = { 4, 0, 0 },
+		.hsub = 1,
+		.vsub = 1,
+		.has_alpha = true,
+	}, {
+		.drm_fmt = DRM_FORMAT_ABGR2101010,
+		.depth = 30,
+		.num_planes = 1,
+		.cpp = { 4, 0, 0 },
+		.hsub = 1,
+		.vsub = 1,
+		.has_alpha = true,
+	}, {
+		.drm_fmt = DRM_FORMAT_RGBA1010102,
+		.depth = 30,
+		.num_planes = 1,
+		.cpp = { 4, 0, 0 },
+		.hsub = 1,
+		.vsub = 1,
+		.has_alpha = true,
+	}, {
+		.drm_fmt = DRM_FORMAT_BGRA1010102,
+		.depth = 30,
+		.num_planes = 1,
+		.cpp = { 4, 0, 0 },
+		.hsub = 1,
+		.vsub = 1,
+		.has_alpha = true,
+	}, {
+		.drm_fmt = DRM_FORMAT_ARGB8888,
+		.depth = 32,
+		.num_planes = 1,
+		.cpp = { 4, 0, 0 },
+		.hsub = 1,
+		.vsub = 1,
+		.has_alpha = true,
+	}, {
+		.drm_fmt = DRM_FORMAT_ABGR8888,
+		.depth = 32,
+		.num_planes = 1,
+		.cpp = { 4, 0, 0 },
+		.hsub = 1,
+		.vsub = 1,
+		.has_alpha = true,
+	}, {
+		.drm_fmt = DRM_FORMAT_RGBA8888,
+		.depth = 32,
+		.num_planes = 1,
+		.cpp = { 4, 0, 0 },
+		.hsub = 1,
+		.vsub = 1,
+		.has_alpha = true,
+	}, {
+		.drm_fmt = DRM_FORMAT_BGRA8888,
+		.depth = 32,
+		.num_planes = 1,
+		.cpp = { 4, 0, 0 },
+		.hsub = 1,
+		.vsub = 1,
+		.has_alpha = true,
+	}, {
+		.drm_fmt = DRM_FORMAT_RGB888_A8,
+		.depth = 32,
+		.num_planes = 2,
+		.cpp = { 3, 1, 0 },
+		.hsub = 1,
+		.vsub = 1,
+		.has_alpha = true,
+	}, {
+		.drm_fmt = DRM_FORMAT_BGR888_A8,
+		.depth = 32,
+		.num_planes = 2,
+		.cpp = { 3, 1, 0 },
+		.hsub = 1,
+		.vsub = 1,
+		.has_alpha = true,
+	}, {
+		.drm_fmt = DRM_FORMAT_XRGB8888_A8,
+		.depth = 32,
+		.num_planes = 2,
+		.cpp = { 4, 1, 0 },
+		.hsub = 1,
+		.vsub = 1,
+		.has_alpha = true,
+	}, {
+		.drm_fmt = DRM_FORMAT_XBGR8888_A8,
+		.depth = 32,
+		.num_planes = 2,
+		.cpp = { 4, 1, 0 },
+		.hsub = 1,
+		.vsub = 1,
+		.has_alpha = true,
+	}, {
+		.drm_fmt = DRM_FORMAT_RGBX8888_A8,
+		.depth = 32,
+		.num_planes = 2,
+		.cpp = { 4, 1, 0 },
+		.hsub = 1,
+		.vsub = 1,
+		.has_alpha = true,
+	}, {
+		.drm_fmt = DRM_FORMAT_BGRX8888_A8,
+		.depth = 32,
+		.num_planes = 2,
+		.cpp = { 4, 1, 0 },
+		.hsub = 1,
+		.vsub = 1,
+		.has_alpha = true,
+	}, {
+		.drm_fmt = DRM_FORMAT_YUV410,
+		.depth = 0,
+		.num_planes = 3,
+		.cpp = { 1, 1, 1 },
+		.hsub = 4,
+		.vsub = 4,
+		.is_yuv = true,
+	}, {
+		.drm_fmt = DRM_FORMAT_YVU410,
+		.depth = 0,
+		.num_planes = 3,
+		.cpp = { 1, 1, 1 },
+		.hsub = 4,
+		.vsub = 4,
+		.is_yuv = true,
+	}, {
+		.drm_fmt = DRM_FORMAT_YUV411,
+		.depth = 0,
+		.num_planes = 3,
+		.cpp = { 1, 1, 1 },
+		.hsub = 4,
+		.vsub = 1,
+		.is_yuv = true,
+	}, {
+		.drm_fmt = DRM_FORMAT_YVU411,
+		.depth = 0,
+		.num_planes = 3,
+		.cpp = { 1, 1, 1 },
+		.hsub = 4,
+		.vsub = 1,
+		.is_yuv = true,
+	}, {
+		.drm_fmt = DRM_FORMAT_YUV420,
+		.depth = 0,
+		.num_planes = 3,
+		.cpp = { 1, 1, 1 },
+		.hsub = 2,
+		.vsub = 2,
+		.is_yuv = true,
+	}, {
+		.drm_fmt = DRM_FORMAT_YVU420,
+		.depth = 0,
+		.num_planes = 3,
+		.cpp = { 1, 1, 1 },
+		.hsub = 2,
+		.vsub = 2,
+		.is_yuv = true,
+	}, {
+		.drm_fmt = DRM_FORMAT_YUV422,
+		.depth = 0,
+		.num_planes = 3,
+		.cpp = { 1, 1, 1 },
+		.hsub = 2,
+		.vsub = 1,
+		.is_yuv = true,
+	}, {
+		.drm_fmt = DRM_FORMAT_YVU422,
+		.depth = 0,
+		.num_planes = 3,
+		.cpp = { 1, 1, 1 },
+		.hsub = 2,
+		.vsub = 1,
+		.is_yuv = true,
+	}, {
+		.drm_fmt = DRM_FORMAT_YUV444,
+		.depth = 0,
+		.num_planes = 3,
+		.cpp = { 1, 1, 1 },
+		.hsub = 1,
+		.vsub = 1,
+		.is_yuv = true,
+	}, {
+		.drm_fmt = DRM_FORMAT_YVU444,
+		.depth = 0,
+		.num_planes = 3,
+		.cpp = { 1, 1, 1 },
+		.hsub = 1,
+		.vsub = 1,
+		.is_yuv = true,
+	}, {
+		.drm_fmt = DRM_FORMAT_NV12,
+		.depth = 0,
+		.num_planes = 2,
+		.cpp = { 1, 2, 0 },
+		.hsub = 2,
+		.vsub = 2,
+		.is_yuv = true,
+	}, {
+		.drm_fmt = DRM_FORMAT_NV21,
+		.depth = 0,
+		.num_planes = 2,
+		.cpp = { 1, 2, 0 },
+		.hsub = 2,
+		.vsub = 2,
+		.is_yuv = true,
+	}, {
+		.drm_fmt = DRM_FORMAT_NV16,
+		.depth = 0,
+		.num_planes = 2,
+		.cpp = { 1, 2, 0 },
+		.hsub = 2,
+		.vsub = 1,
+		.is_yuv = true,
+	}, {
+		.drm_fmt = DRM_FORMAT_NV61,
+		.depth = 0,
+		.num_planes = 2,
+		.cpp = { 1, 2, 0 },
+		.hsub = 2,
+		.vsub = 1,
+		.is_yuv = true,
+	}, {
+		.drm_fmt = DRM_FORMAT_NV24,
+		.depth = 0,
+		.num_planes = 2,
+		.cpp = { 1, 2, 0 },
+		.hsub = 1,
+		.vsub = 1,
+		.is_yuv = true,
+	}, {
+		.drm_fmt = DRM_FORMAT_NV42,
+		.depth = 0,
+		.num_planes = 2,
+		.cpp = { 1, 2, 0 },
+		.hsub = 1,
+		.vsub = 1,
+		.is_yuv = true,
+	}, {
+		.drm_fmt = DRM_FORMAT_YUYV,
+		.depth = 0,
+		.num_planes = 1,
+		.cpp = { 2, 0, 0 },
+		.hsub = 2,
+		.vsub = 1,
+		.is_yuv = true,
+	}, {
+		.drm_fmt = DRM_FORMAT_YVYU,
+		.depth = 0,
+		.num_planes = 1,
+		.cpp = { 2, 0, 0 },
+		.hsub = 2,
+		.vsub = 1,
+		.is_yuv = true,
+	}, {
+		.drm_fmt = DRM_FORMAT_UYVY,
+		.depth = 0,
+		.num_planes = 1,
+		.cpp = { 2, 0, 0 },
+		.hsub = 2,
+		.vsub = 1,
+		.is_yuv = true,
+	}, {
+		.drm_fmt = DRM_FORMAT_VYUY,
+		.depth = 0,
+		.num_planes = 1,
+		.cpp = { 2, 0, 0 },
+		.hsub = 2,
+		.vsub = 1,
+		.is_yuv = true,
+	}, {
+		.drm_fmt = DRM_FORMAT_XYUV8888,
+		.depth = 0,
+		.num_planes = 1,
+		.cpp = { 4, 0, 0 },
+		.hsub = 1,
+		.vsub = 1,
+		.is_yuv = true,
+	}, {
+		.drm_fmt = DRM_FORMAT_AYUV,
+		.depth = 0,
+		.num_planes = 1,
+		.cpp = { 4, 0, 0 },
+		.hsub = 1,
+		.vsub = 1,
+		.has_alpha = true,
+		.is_yuv = true,
+	}, {
+		.drm_fmt = DRM_FORMAT_Y0L0,
+		.depth = 0,
+		.num_planes = 1,
+		.char_per_block = { 8, 0, 0 },
+		.block_w = { 2, 0, 0 },
+		.block_h = { 2, 0, 0 },
+		.hsub = 2,
+		.vsub = 2,
+		.has_alpha = true,
+		.is_yuv = true,
+	}, {
+		.drm_fmt = DRM_FORMAT_X0L0,
+		.depth = 0,
+		.num_planes = 1,
+		.char_per_block = { 8, 0, 0 },
+		.block_w = { 2, 0, 0 },
+		.block_h = { 2, 0, 0 },
+		.hsub = 2,
+		.vsub = 2,
+		.is_yuv = true,
+	}, {
+		.drm_fmt = DRM_FORMAT_Y0L2,
+		.depth = 0,
+		.num_planes = 1,
+		.char_per_block = { 8, 0, 0 },
+		.block_w = { 2, 0, 0 },
+		.block_h = { 2, 0, 0 },
+		.hsub = 2,
+		.vsub = 2,
+		.has_alpha = true,
+		.is_yuv = true,
+	}, {
+		.drm_fmt = DRM_FORMAT_X0L2,
+		.depth = 0,
+		.num_planes = 1,
+		.char_per_block = { 8, 0, 0 },
+		.block_w = { 2, 0, 0 },
+		.block_h = { 2, 0, 0 },
+		.hsub = 2,
+		.vsub = 2,
+		.is_yuv = true,
+	},
+};
+
+#define __image_format_lookup(_field, _fmt)			\
+	({							\
+		const struct image_format_info *format = NULL;	\
+		unsigned i;					\
+								\
+		for (i = 0; i < ARRAY_SIZE(formats); i++)	\
+			if (formats[i]._field == _fmt)		\
+				format = &formats[i];		\
+								\
+		format;						\
+	})
+
+/**
+ * __image_format_drm_lookup - query information for a given format
+ * @drm: DRM fourcc pixel format (DRM_FORMAT_*)
+ *
+ * The caller should only pass a supported pixel format to this function.
+ *
+ * Returns:
+ * The instance of struct image_format_info that describes the pixel format, or
+ * NULL if the format is unsupported.
+ */
+const struct image_format_info *__image_format_drm_lookup(u32 drm)
+{
+	return __image_format_lookup(drm_fmt, drm);
+}
+EXPORT_SYMBOL(__image_format_drm_lookup);
+
+/**
+ * image_format_drm_lookup - query information for a given format
+ * @drm: DRM fourcc pixel format (DRM_FORMAT_*)
+ *
+ * The caller should only pass a supported pixel format to this function.
+ * Unsupported pixel formats will generate a warning in the kernel log.
+ *
+ * Returns:
+ * The instance of struct image_format_info that describes the pixel format, or
+ * NULL if the format is unsupported.
+ */
+const struct image_format_info *image_format_drm_lookup(u32 drm)
+{
+	const struct image_format_info *format;
+
+	format = __image_format_drm_lookup(drm);
+
+	WARN_ON(!format);
+	return format;
+}
+EXPORT_SYMBOL(image_format_drm_lookup);
+
+/**
+ * image_format_plane_cpp - determine the bytes per pixel value
+ * @format: pointer to the image_format
+ * @plane: plane index
+ *
+ * Returns:
+ * The bytes per pixel value for the specified plane.
+ */
+unsigned int image_format_plane_cpp(const struct image_format_info *format,
+				    int plane)
+{
+	if (!format || plane >= format->num_planes)
+		return 0;
+
+	return format->cpp[plane];
+}
+EXPORT_SYMBOL(image_format_plane_cpp);
+
+/**
+ * image_format_plane_width - width of the plane given the first plane
+ * @format: pointer to the image_format
+ * @width: width of the first plane
+ * @plane: plane index
+ *
+ * Returns:
+ * The width of @plane, given that the width of the first plane is @width.
+ */
+unsigned int image_format_plane_width(int width,
+				      const struct image_format_info *format,
+				      int plane)
+{
+	if (!format || plane >= format->num_planes)
+		return 0;
+
+	if (plane == 0)
+		return width;
+
+	return width / format->hsub;
+}
+EXPORT_SYMBOL(image_format_plane_width);
+
+/**
+ * image_format_plane_height - height of the plane given the first plane
+ * @format: pointer to the image_format
+ * @height: height of the first plane
+ * @plane: plane index
+ *
+ * Returns:
+ * The height of @plane, given that the height of the first plane is @height.
+ */
+unsigned int image_format_plane_height(int height,
+				       const struct image_format_info *format,
+				       int plane)
+{
+	if (!format || plane >= format->num_planes)
+		return 0;
+
+	if (plane == 0)
+		return height;
+
+	return height / format->vsub;
+}
+EXPORT_SYMBOL(image_format_plane_height);
+
+/**
+ * image_format_block_width - width in pixels of block.
+ * @format: pointer to the image_format
+ * @plane: plane index
+ *
+ * Returns:
+ * The width in pixels of a block, depending on the plane index.
+ */
+unsigned int image_format_block_width(const struct image_format_info *format,
+				      int plane)
+{
+	if (!format || plane < 0 || plane >= format->num_planes)
+		return 0;
+
+	if (!format->block_w[plane])
+		return 1;
+
+	return format->block_w[plane];
+}
+EXPORT_SYMBOL(image_format_block_width);
+
+/**
+ * image_format_block_height - height in pixels of a block
+ * @info: pointer to the image_format
+ * @plane: plane index
+ *
+ * Returns:
+ * The height in pixels of a block, depending on the plane index.
+ */
+unsigned int image_format_block_height(const struct image_format_info *format,
+				       int plane)
+{
+	if (!format || plane < 0 || plane >= format->num_planes)
+		return 0;
+
+	if (!format->block_h[plane])
+		return 1;
+
+	return format->block_h[plane];
+}
+EXPORT_SYMBOL(image_format_block_height);
+
+/**
+ * image_format_min_pitch - computes the minimum required pitch in bytes
+ * @info: pixel format info
+ * @plane: plane index
+ * @buffer_width: buffer width in pixels
+ *
+ * Returns:
+ * The minimum required pitch in bytes for a buffer by taking into consideration
+ * the pixel format information and the buffer width.
+ */
+uint64_t image_format_min_pitch(const struct image_format_info *info,
+				int plane, unsigned int buffer_width)
+{
+	if (!info || plane < 0 || plane >= info->num_planes)
+		return 0;
+
+	return DIV_ROUND_UP_ULL((u64)buffer_width * info->char_per_block[plane],
+			    image_format_block_width(info, plane) *
+			    image_format_block_height(info, plane));
+}
+EXPORT_SYMBOL(image_format_min_pitch);
-- 
git-series 0.9.1
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

  parent reply	other threads:[~2019-03-19 21:59 UTC|newest]

Thread overview: 69+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2019-03-19 21:57 [RFC PATCH 00/20] drm: Split out the formats API and move it to a common place Maxime Ripard
2019-03-19 21:57 ` [RFC PATCH 01/20] drm: Remove users of drm_format_num_planes Maxime Ripard
2019-03-20 14:16   ` Paul Kocialkowski
2019-04-02  9:43   ` Emil Velikov
2019-04-02 14:51     ` Maxime Ripard
2019-04-04 16:24       ` Emil Velikov
2019-03-19 21:57 ` [RFC PATCH 02/20] drm: Remove users of drm_format_(horz|vert)_chroma_subsampling Maxime Ripard
2019-03-20 14:19   ` Paul Kocialkowski
2019-03-20 14:19     ` Paul Kocialkowski
2019-03-19 21:57 ` [RFC PATCH 03/20] drm/fourcc: Pass the format_info pointer to drm_format_plane_cpp Maxime Ripard
2019-03-19 21:57   ` Maxime Ripard
2019-03-20 14:24   ` Paul Kocialkowski
2019-03-21 10:13     ` Maxime Ripard
2019-03-21 10:13       ` Maxime Ripard
2019-03-19 21:57 ` [RFC PATCH 04/20] drm/fourcc: Pass the format_info pointer to drm_format_plane_width/height Maxime Ripard
2019-03-20 14:26   ` Paul Kocialkowski
2019-03-19 21:57 ` [RFC PATCH 05/20] drm: Replace instances of drm_format_info by drm_get_format_info Maxime Ripard
2019-03-20 14:27   ` Paul Kocialkowski
2019-03-19 21:57 ` Maxime Ripard [this message]
2019-03-19 21:57   ` [RFC PATCH 06/20] lib: Add video format information library Maxime Ripard
2019-03-20 13:39   ` Boris Brezillon
2019-03-21  8:20     ` Maxime Ripard
2019-03-21  8:20       ` Maxime Ripard
2019-03-21  8:40       ` Boris Brezillon
2019-03-19 21:57 ` [RFC PATCH 07/20] drm/fb: Move from drm_format_info to image_format_info Maxime Ripard
2019-03-19 21:57 ` [RFC PATCH 08/20] drm/malidp: Convert to generic image format library Maxime Ripard
2019-03-19 21:57 ` [RFC PATCH 09/20] drm/client: " Maxime Ripard
2019-03-19 21:57 ` [RFC PATCH 10/20] drm/exynos: " Maxime Ripard
2019-03-19 21:57 ` [RFC PATCH 11/20] drm/i915: " Maxime Ripard
2019-03-19 21:57 ` [RFC PATCH 12/20] drm/ipuv3: " Maxime Ripard
2019-03-19 21:57   ` Maxime Ripard
2019-03-19 21:57 ` [RFC PATCH 13/20] drm/msm: " Maxime Ripard
2019-03-19 21:57 ` [RFC PATCH 14/20] drm/omap: " Maxime Ripard
2019-03-19 21:57 ` [RFC PATCH 15/20] drm/rockchip: " Maxime Ripard
2019-03-19 21:57 ` [RFC PATCH 16/20] drm/tegra: " Maxime Ripard
2019-03-19 21:57   ` Maxime Ripard
2019-03-19 21:57 ` [RFC PATCH 17/20] drm/fourcc: Remove old DRM format API Maxime Ripard
2019-03-19 21:57 ` [RFC PATCH 18/20] lib: image-formats: Add v4l2 formats support Maxime Ripard
2019-03-19 23:29   ` Nicolas Dufresne
2019-03-20 14:27     ` Ville Syrjälä
2019-03-20 15:51       ` Nicolas Dufresne
2019-03-20 16:09         ` Ville Syrjälä
2019-03-20 16:30           ` Nicolas Dufresne
2019-03-20 16:41             ` Ville Syrjälä
2019-03-20 18:27               ` Nicolas Dufresne
2019-03-20 18:39                 ` Ville Syrjälä
2019-03-21 16:04                   ` Paul Kocialkowski
2019-03-21 16:04                     ` Paul Kocialkowski
2019-03-21 16:35                     ` Ville Syrjälä
2019-03-21 19:14                       ` Nicolas Dufresne
2019-03-21 21:44                         ` Ville Syrjälä
2019-03-22 18:24                           ` Nicolas Dufresne
2019-03-22 18:44                             ` Ville Syrjälä
2019-03-22 19:25                               ` Nicolas Dufresne
2019-03-22 14:42                         ` Ville Syrjälä
2019-03-22 18:11                           ` Nicolas Dufresne
2019-03-20 18:15     ` Brian Starkey
2019-03-21 15:47       ` Maxime Ripard
2019-03-22 19:55   ` Nicolas Dufresne
2019-04-01 14:44     ` Maxime Ripard
2019-04-11  7:24       ` Hans Verkuil
2019-04-11  7:38     ` Hans Verkuil
2019-04-11 15:55       ` Maxime Ripard
2019-04-11  7:12   ` Hans Verkuil
2019-04-11  7:15     ` Hans Verkuil
2019-04-11  7:15       ` Hans Verkuil
2019-03-19 21:57 ` [RFC PATCH 19/20] lib: image-formats: Add more functions Maxime Ripard
2019-03-19 21:57   ` Maxime Ripard
2019-03-19 21:57 ` [RFC PATCH 20/20] media: sun6i: Convert to the image format API Maxime Ripard

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=a2ecd9e599e0b536c2a005e5feb140463566788e.1553032382.git-series.maxime.ripard@bootlin.com \
    --to=maxime.ripard@bootlin.com \
    --cc=airlied@linux.ie \
    --cc=daniel.vetter@intel.com \
    --cc=dri-devel@lists.freedesktop.org \
    --cc=hans.verkuil@cisco.com \
    --cc=laurent.pinchart@ideasonboard.com \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-media@vger.kernel.org \
    --cc=maarten.lankhorst@linux.intel.com \
    --cc=mchehab@kernel.org \
    --cc=paul.kocialkowski@bootlin.com \
    --cc=sakari.ailus@linux.intel.com \
    --cc=seanpaul@chromium.org \
    --cc=thomas.petazzoni@bootlin.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
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.