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: [PATCH 06/20] lib: Add video format information library
Date: Wed, 17 Apr 2019 09:54:32 +0200	[thread overview]
Message-ID: <c17a896150f0b793cfa8581d18969cd7b3e93bf2.1555487650.git-series.maxime.ripard@bootlin.com> (raw)
In-Reply-To: <cover.8ec406bf8f4f097e9dc909d5aac466556822f592.1555487650.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 | 387 +++++++++++++++++++++-
 lib/Kconfig                   |   7 +-
 lib/Makefile                  |   3 +-
 lib/image-formats-selftests.c | 325 +++++++++++++++++-
 lib/image-formats.c           | 655 +++++++++++++++++++++++++++++++++++-
 5 files changed, 1377 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..ec43d9f9a527
--- /dev/null
+++ b/include/linux/image-formats.h
@@ -0,0 +1,387 @@
+/*
+ * Copyright (c) 2016 Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+ * Copyright (c) 2019 Maxime Ripard <maxime.ripard@bootlin.com>
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that copyright
+ * notice and this permission notice appear in supporting documentation, and
+ * that the name of the copyright holders not be used in advertising or
+ * publicity pertaining to distribution of the software without specific,
+ * written prior permission.  The copyright holders make no representations
+ * about the suitability of this software for any purpose.  It is provided "as
+ * is" without express or implied warranty.
+ *
+ * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
+ * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+ * OF THIS SOFTWARE.
+ */
+
+#ifndef _IMAGE_FORMATS_H_
+#define _IMAGE_FORMATS_H_
+
+#include <linux/kernel.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_info_block_width() and
+		 * image_format_info_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_info_block_width()
+	 */
+	u8 block_w[3];
+
+	/**
+	 * @block_h:
+	 *
+	 * Block height in pixels, this is intended to be accessed through
+	 * image_format_info_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;
+}
+
+/**
+ * image_format_info_plane_cpp - determine the bytes per pixel value
+ * @format: pixel format info
+ * @plane: plane index
+ *
+ * Returns:
+ * The bytes per pixel value for the specified plane.
+ */
+static inline
+int image_format_info_plane_cpp(const struct image_format_info *info, int plane)
+{
+	if (!info || plane >= info->num_planes)
+		return 0;
+
+	return info->cpp[plane];
+}
+
+/**
+ * image_format_info_plane_width - width of the plane given the first plane
+ * @format: pixel format info
+ * @width: width of the first plane
+ * @plane: plane index
+ *
+ * Returns:
+ * The width of @plane, given that the width of the first plane is @width.
+ */
+static inline
+int image_format_info_plane_width(const struct image_format_info *info, int width,
+				  int plane)
+{
+	if (!info || plane >= info->num_planes)
+		return 0;
+
+	if (plane == 0)
+		return width;
+
+	return width / info->hsub;
+}
+
+/**
+ * image_format_info_plane_height - height of the plane given the first plane
+ * @format: pixel format info
+ * @height: height of the first plane
+ * @plane: plane index
+ *
+ * Returns:
+ * The height of @plane, given that the height of the first plane is @height.
+ */
+static inline
+int image_format_info_plane_height(const struct image_format_info *info, int height,
+				   int plane)
+{
+	if (!info || plane >= info->num_planes)
+		return 0;
+
+	if (plane == 0)
+		return height;
+
+	return height / info->vsub;
+}
+
+/**
+ * image_format_info_block_width - width in pixels of block.
+ * @format: pointer to the image_format_info
+ * @plane: plane index
+ *
+ * Returns:
+ * The width in pixels of a block, depending on the plane index.
+ */
+static inline
+unsigned int image_format_info_block_width(const struct image_format_info *format,
+					   int plane)
+{
+	if (!format)
+		return 0;
+
+	if (plane < 0 || plane >= ARRAY_SIZE(format->block_w))
+		return 0;
+
+	if (plane >= format->num_planes)
+		return 0;
+
+	if (!format->block_w[plane])
+		return 1;
+
+	return format->block_w[plane];
+}
+
+/**
+ * image_format_info_block_height - height in pixels of a block
+ * @info: pointer to the image_format_info
+ * @plane: plane index
+ *
+ * Returns:
+ * The height in pixels of a block, depending on the plane index.
+ */
+static inline
+unsigned int image_format_info_block_height(const struct image_format_info *format,
+					    int plane)
+{
+	if (!format)
+		return 0;
+
+	if (plane < 0 || plane >= ARRAY_SIZE(format->block_w))
+		return 0;
+
+	if (plane >= format->num_planes)
+		return 0;
+
+	if (!format->block_h[plane])
+		return 1;
+
+	return format->block_h[plane];
+}
+
+/**
+ * image_format_info_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.
+ */
+static inline
+uint64_t image_format_info_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_info_block_width(info, plane) *
+			    image_format_info_block_height(info, plane));
+}
+
+const struct image_format_info *__image_format_drm_lookup(u32 drm);
+const struct image_format_info *image_format_drm_lookup(u32 drm);
+
+#endif /* _IMAGE_FORMATS_H_ */
diff --git a/lib/Kconfig b/lib/Kconfig
index fb453afff32e..9a0160d3123b 100644
--- a/lib/Kconfig
+++ b/lib/Kconfig
@@ -625,3 +625,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 6996d2b9f401..203336b91248 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -280,3 +280,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..d0f0011b535e
--- /dev/null
+++ b/lib/image-formats-selftests.c
@@ -0,0 +1,325 @@
+// 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_info_block_width(void)
+{
+	const struct image_format_info *info = NULL;
+
+	/* Test invalid arguments */
+	FAIL_ON(image_format_info_block_width(info, 0) != 0);
+	FAIL_ON(image_format_info_block_width(info, -1) != 0);
+	FAIL_ON(image_format_info_block_width(info, 1) != 0);
+
+	/* Test 1 plane format */
+	info = image_format_drm_lookup(DRM_FORMAT_XRGB4444);
+	FAIL_ON(!info);
+	FAIL_ON(image_format_info_block_width(info, 0) != 1);
+	FAIL_ON(image_format_info_block_width(info, 1) != 0);
+	FAIL_ON(image_format_info_block_width(info, -1) != 0);
+
+	/* Test 2 planes format */
+	info = image_format_drm_lookup(DRM_FORMAT_NV12);
+	FAIL_ON(!info);
+	FAIL_ON(image_format_info_block_width(info, 0) != 1);
+	FAIL_ON(image_format_info_block_width(info, 1) != 1);
+	FAIL_ON(image_format_info_block_width(info, 2) != 0);
+	FAIL_ON(image_format_info_block_width(info, -1) != 0);
+
+	/* Test 3 planes format */
+	info = image_format_drm_lookup(DRM_FORMAT_YUV422);
+	FAIL_ON(!info);
+	FAIL_ON(image_format_info_block_width(info, 0) != 1);
+	FAIL_ON(image_format_info_block_width(info, 1) != 1);
+	FAIL_ON(image_format_info_block_width(info, 2) != 1);
+	FAIL_ON(image_format_info_block_width(info, 3) != 0);
+	FAIL_ON(image_format_info_block_width(info, -1) != 0);
+
+	/* Test a tiled format */
+	info = image_format_drm_lookup(DRM_FORMAT_X0L0);
+	FAIL_ON(!info);
+	FAIL_ON(image_format_info_block_width(info, 0) != 2);
+	FAIL_ON(image_format_info_block_width(info, 1) != 0);
+	FAIL_ON(image_format_info_block_width(info, -1) != 0);
+
+	return 0;
+}
+
+static int test_image_format_info_block_height(void)
+{
+	const struct image_format_info *info = NULL;
+
+	/* Test invalid arguments */
+	FAIL_ON(image_format_info_block_height(info, 0) != 0);
+	FAIL_ON(image_format_info_block_height(info, -1) != 0);
+	FAIL_ON(image_format_info_block_height(info, 1) != 0);
+
+	/* Test 1 plane format */
+	info = image_format_drm_lookup(DRM_FORMAT_XRGB4444);
+	FAIL_ON(!info);
+	FAIL_ON(image_format_info_block_height(info, 0) != 1);
+	FAIL_ON(image_format_info_block_height(info, 1) != 0);
+	FAIL_ON(image_format_info_block_height(info, -1) != 0);
+
+	/* Test 2 planes format */
+	info = image_format_drm_lookup(DRM_FORMAT_NV12);
+	FAIL_ON(!info);
+	FAIL_ON(image_format_info_block_height(info, 0) != 1);
+	FAIL_ON(image_format_info_block_height(info, 1) != 1);
+	FAIL_ON(image_format_info_block_height(info, 2) != 0);
+	FAIL_ON(image_format_info_block_height(info, -1) != 0);
+
+	/* Test 3 planes format */
+	info = image_format_drm_lookup(DRM_FORMAT_YUV422);
+	FAIL_ON(!info);
+	FAIL_ON(image_format_info_block_height(info, 0) != 1);
+	FAIL_ON(image_format_info_block_height(info, 1) != 1);
+	FAIL_ON(image_format_info_block_height(info, 2) != 1);
+	FAIL_ON(image_format_info_block_height(info, 3) != 0);
+	FAIL_ON(image_format_info_block_height(info, -1) != 0);
+
+	/* Test a tiled format */
+	info = image_format_drm_lookup(DRM_FORMAT_X0L0);
+	FAIL_ON(!info);
+	FAIL_ON(image_format_info_block_height(info, 0) != 2);
+	FAIL_ON(image_format_info_block_height(info, 1) != 0);
+	FAIL_ON(image_format_info_block_height(info, -1) != 0);
+
+	return 0;
+}
+
+static int test_image_format_info_min_pitch(void)
+{
+	const struct image_format_info *info = NULL;
+
+	/* Test invalid arguments */
+	FAIL_ON(image_format_info_min_pitch(info, 0, 0) != 0);
+	FAIL_ON(image_format_info_min_pitch(info, -1, 0) != 0);
+	FAIL_ON(image_format_info_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_info_min_pitch(info, 0, 0) != 0);
+	FAIL_ON(image_format_info_min_pitch(info, -1, 0) != 0);
+	FAIL_ON(image_format_info_min_pitch(info, 1, 0) != 0);
+
+	FAIL_ON(image_format_info_min_pitch(info, 0, 1) != 1);
+	FAIL_ON(image_format_info_min_pitch(info, 0, 2) != 2);
+	FAIL_ON(image_format_info_min_pitch(info, 0, 640) != 640);
+	FAIL_ON(image_format_info_min_pitch(info, 0, 1024) != 1024);
+	FAIL_ON(image_format_info_min_pitch(info, 0, 1920) != 1920);
+	FAIL_ON(image_format_info_min_pitch(info, 0, 4096) != 4096);
+	FAIL_ON(image_format_info_min_pitch(info, 0, 671) != 671);
+	FAIL_ON(image_format_info_min_pitch(info, 0, UINT_MAX) !=
+			(uint64_t)UINT_MAX);
+	FAIL_ON(image_format_info_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_info_min_pitch(info, 0, 0) != 0);
+	FAIL_ON(image_format_info_min_pitch(info, -1, 0) != 0);
+	FAIL_ON(image_format_info_min_pitch(info, 1, 0) != 0);
+
+	FAIL_ON(image_format_info_min_pitch(info, 0, 1) != 2);
+	FAIL_ON(image_format_info_min_pitch(info, 0, 2) != 4);
+	FAIL_ON(image_format_info_min_pitch(info, 0, 640) != 1280);
+	FAIL_ON(image_format_info_min_pitch(info, 0, 1024) != 2048);
+	FAIL_ON(image_format_info_min_pitch(info, 0, 1920) != 3840);
+	FAIL_ON(image_format_info_min_pitch(info, 0, 4096) != 8192);
+	FAIL_ON(image_format_info_min_pitch(info, 0, 671) != 1342);
+	FAIL_ON(image_format_info_min_pitch(info, 0, UINT_MAX) !=
+			(uint64_t)UINT_MAX * 2);
+	FAIL_ON(image_format_info_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_info_min_pitch(info, 0, 0) != 0);
+	FAIL_ON(image_format_info_min_pitch(info, -1, 0) != 0);
+	FAIL_ON(image_format_info_min_pitch(info, 1, 0) != 0);
+
+	FAIL_ON(image_format_info_min_pitch(info, 0, 1) != 3);
+	FAIL_ON(image_format_info_min_pitch(info, 0, 2) != 6);
+	FAIL_ON(image_format_info_min_pitch(info, 0, 640) != 1920);
+	FAIL_ON(image_format_info_min_pitch(info, 0, 1024) != 3072);
+	FAIL_ON(image_format_info_min_pitch(info, 0, 1920) != 5760);
+	FAIL_ON(image_format_info_min_pitch(info, 0, 4096) != 12288);
+	FAIL_ON(image_format_info_min_pitch(info, 0, 671) != 2013);
+	FAIL_ON(image_format_info_min_pitch(info, 0, UINT_MAX) !=
+			(uint64_t)UINT_MAX * 3);
+	FAIL_ON(image_format_info_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_info_min_pitch(info, 0, 0) != 0);
+	FAIL_ON(image_format_info_min_pitch(info, -1, 0) != 0);
+	FAIL_ON(image_format_info_min_pitch(info, 1, 0) != 0);
+
+	FAIL_ON(image_format_info_min_pitch(info, 0, 1) != 4);
+	FAIL_ON(image_format_info_min_pitch(info, 0, 2) != 8);
+	FAIL_ON(image_format_info_min_pitch(info, 0, 640) != 2560);
+	FAIL_ON(image_format_info_min_pitch(info, 0, 1024) != 4096);
+	FAIL_ON(image_format_info_min_pitch(info, 0, 1920) != 7680);
+	FAIL_ON(image_format_info_min_pitch(info, 0, 4096) != 16384);
+	FAIL_ON(image_format_info_min_pitch(info, 0, 671) != 2684);
+	FAIL_ON(image_format_info_min_pitch(info, 0, UINT_MAX) !=
+			(uint64_t)UINT_MAX * 4);
+	FAIL_ON(image_format_info_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_info_min_pitch(info, 0, 0) != 0);
+	FAIL_ON(image_format_info_min_pitch(info, 1, 0) != 0);
+	FAIL_ON(image_format_info_min_pitch(info, -1, 0) != 0);
+	FAIL_ON(image_format_info_min_pitch(info, 2, 0) != 0);
+
+	FAIL_ON(image_format_info_min_pitch(info, 0, 1) != 1);
+	FAIL_ON(image_format_info_min_pitch(info, 1, 1) != 2);
+	FAIL_ON(image_format_info_min_pitch(info, 0, 2) != 2);
+	FAIL_ON(image_format_info_min_pitch(info, 1, 1) != 2);
+	FAIL_ON(image_format_info_min_pitch(info, 0, 640) != 640);
+	FAIL_ON(image_format_info_min_pitch(info, 1, 320) != 640);
+	FAIL_ON(image_format_info_min_pitch(info, 0, 1024) != 1024);
+	FAIL_ON(image_format_info_min_pitch(info, 1, 512) != 1024);
+	FAIL_ON(image_format_info_min_pitch(info, 0, 1920) != 1920);
+	FAIL_ON(image_format_info_min_pitch(info, 1, 960) != 1920);
+	FAIL_ON(image_format_info_min_pitch(info, 0, 4096) != 4096);
+	FAIL_ON(image_format_info_min_pitch(info, 1, 2048) != 4096);
+	FAIL_ON(image_format_info_min_pitch(info, 0, 671) != 671);
+	FAIL_ON(image_format_info_min_pitch(info, 1, 336) != 672);
+	FAIL_ON(image_format_info_min_pitch(info, 0, UINT_MAX) !=
+			(uint64_t)UINT_MAX);
+	FAIL_ON(image_format_info_min_pitch(info, 1, UINT_MAX / 2 + 1) !=
+			(uint64_t)UINT_MAX + 1);
+	FAIL_ON(image_format_info_min_pitch(info, 0, (UINT_MAX - 1)) !=
+			(uint64_t)(UINT_MAX - 1));
+	FAIL_ON(image_format_info_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_info_min_pitch(info, 0, 0) != 0);
+	FAIL_ON(image_format_info_min_pitch(info, 1, 0) != 0);
+	FAIL_ON(image_format_info_min_pitch(info, 2, 0) != 0);
+	FAIL_ON(image_format_info_min_pitch(info, -1, 0) != 0);
+	FAIL_ON(image_format_info_min_pitch(info, 3, 0) != 0);
+
+	FAIL_ON(image_format_info_min_pitch(info, 0, 1) != 1);
+	FAIL_ON(image_format_info_min_pitch(info, 1, 1) != 1);
+	FAIL_ON(image_format_info_min_pitch(info, 2, 1) != 1);
+	FAIL_ON(image_format_info_min_pitch(info, 0, 2) != 2);
+	FAIL_ON(image_format_info_min_pitch(info, 1, 2) != 2);
+	FAIL_ON(image_format_info_min_pitch(info, 2, 2) != 2);
+	FAIL_ON(image_format_info_min_pitch(info, 0, 640) != 640);
+	FAIL_ON(image_format_info_min_pitch(info, 1, 320) != 320);
+	FAIL_ON(image_format_info_min_pitch(info, 2, 320) != 320);
+	FAIL_ON(image_format_info_min_pitch(info, 0, 1024) != 1024);
+	FAIL_ON(image_format_info_min_pitch(info, 1, 512) != 512);
+	FAIL_ON(image_format_info_min_pitch(info, 2, 512) != 512);
+	FAIL_ON(image_format_info_min_pitch(info, 0, 1920) != 1920);
+	FAIL_ON(image_format_info_min_pitch(info, 1, 960) != 960);
+	FAIL_ON(image_format_info_min_pitch(info, 2, 960) != 960);
+	FAIL_ON(image_format_info_min_pitch(info, 0, 4096) != 4096);
+	FAIL_ON(image_format_info_min_pitch(info, 1, 2048) != 2048);
+	FAIL_ON(image_format_info_min_pitch(info, 2, 2048) != 2048);
+	FAIL_ON(image_format_info_min_pitch(info, 0, 671) != 671);
+	FAIL_ON(image_format_info_min_pitch(info, 1, 336) != 336);
+	FAIL_ON(image_format_info_min_pitch(info, 2, 336) != 336);
+	FAIL_ON(image_format_info_min_pitch(info, 0, UINT_MAX) !=
+			(uint64_t)UINT_MAX);
+	FAIL_ON(image_format_info_min_pitch(info, 1, UINT_MAX / 2 + 1) !=
+			(uint64_t)UINT_MAX / 2 + 1);
+	FAIL_ON(image_format_info_min_pitch(info, 2, UINT_MAX / 2 + 1) !=
+			(uint64_t)UINT_MAX / 2 + 1);
+	FAIL_ON(image_format_info_min_pitch(info, 0, (UINT_MAX - 1) / 2) !=
+			(uint64_t)(UINT_MAX - 1) / 2);
+	FAIL_ON(image_format_info_min_pitch(info, 1, (UINT_MAX - 1) / 2) !=
+			(uint64_t)(UINT_MAX - 1) / 2);
+	FAIL_ON(image_format_info_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_info_min_pitch(info, 0, 0) != 0);
+	FAIL_ON(image_format_info_min_pitch(info, -1, 0) != 0);
+	FAIL_ON(image_format_info_min_pitch(info, 1, 0) != 0);
+
+	FAIL_ON(image_format_info_min_pitch(info, 0, 1) != 2);
+	FAIL_ON(image_format_info_min_pitch(info, 0, 2) != 4);
+	FAIL_ON(image_format_info_min_pitch(info, 0, 640) != 1280);
+	FAIL_ON(image_format_info_min_pitch(info, 0, 1024) != 2048);
+	FAIL_ON(image_format_info_min_pitch(info, 0, 1920) != 3840);
+	FAIL_ON(image_format_info_min_pitch(info, 0, 4096) != 8192);
+	FAIL_ON(image_format_info_min_pitch(info, 0, 671) != 1342);
+	FAIL_ON(image_format_info_min_pitch(info, 0, UINT_MAX) !=
+			(uint64_t)UINT_MAX * 2);
+	FAIL_ON(image_format_info_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_info_block_height),
+	selftest(test_image_format_info_block_width),
+	selftest(test_image_format_info_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;
+}
+module_init(image_format_test_init);
+
+MODULE_AUTHOR("Intel Corporation");
+MODULE_AUTHOR("Maxime Ripard <maxime.ripard@bootlin.com>");
+MODULE_LICENSE("GPL");
diff --git a/lib/image-formats.c b/lib/image-formats.c
new file mode 100644
index 000000000000..1e52a7410222
--- /dev/null
+++ b/lib/image-formats.c
@@ -0,0 +1,655 @@
+/*
+ * Copyright (c) 2016 Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+ * Copyright (c) 2019 Maxime Ripard <maxime.ripard@bootlin.com>
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that copyright
+ * notice and this permission notice appear in supporting documentation, and
+ * that the name of the copyright holders not be used in advertising or
+ * publicity pertaining to distribution of the software without specific,
+ * written prior permission.  The copyright holders make no representations
+ * about the suitability of this software for any purpose.  It is provided "as
+ * is" without express or implied warranty.
+ *
+ * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
+ * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+ * OF THIS SOFTWARE.
+ */
+
+#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);
-- 
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: [PATCH 06/20] lib: Add video format information library
Date: Wed, 17 Apr 2019 09:54:32 +0200	[thread overview]
Message-ID: <c17a896150f0b793cfa8581d18969cd7b3e93bf2.1555487650.git-series.maxime.ripard@bootlin.com> (raw)
In-Reply-To: <cover.8ec406bf8f4f097e9dc909d5aac466556822f592.1555487650.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 | 387 +++++++++++++++++++++-
 lib/Kconfig                   |   7 +-
 lib/Makefile                  |   3 +-
 lib/image-formats-selftests.c | 325 +++++++++++++++++-
 lib/image-formats.c           | 655 +++++++++++++++++++++++++++++++++++-
 5 files changed, 1377 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..ec43d9f9a527
--- /dev/null
+++ b/include/linux/image-formats.h
@@ -0,0 +1,387 @@
+/*
+ * Copyright (c) 2016 Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+ * Copyright (c) 2019 Maxime Ripard <maxime.ripard@bootlin.com>
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that copyright
+ * notice and this permission notice appear in supporting documentation, and
+ * that the name of the copyright holders not be used in advertising or
+ * publicity pertaining to distribution of the software without specific,
+ * written prior permission.  The copyright holders make no representations
+ * about the suitability of this software for any purpose.  It is provided "as
+ * is" without express or implied warranty.
+ *
+ * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
+ * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+ * OF THIS SOFTWARE.
+ */
+
+#ifndef _IMAGE_FORMATS_H_
+#define _IMAGE_FORMATS_H_
+
+#include <linux/kernel.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_info_block_width() and
+		 * image_format_info_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_info_block_width()
+	 */
+	u8 block_w[3];
+
+	/**
+	 * @block_h:
+	 *
+	 * Block height in pixels, this is intended to be accessed through
+	 * image_format_info_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;
+}
+
+/**
+ * image_format_info_plane_cpp - determine the bytes per pixel value
+ * @format: pixel format info
+ * @plane: plane index
+ *
+ * Returns:
+ * The bytes per pixel value for the specified plane.
+ */
+static inline
+int image_format_info_plane_cpp(const struct image_format_info *info, int plane)
+{
+	if (!info || plane >= info->num_planes)
+		return 0;
+
+	return info->cpp[plane];
+}
+
+/**
+ * image_format_info_plane_width - width of the plane given the first plane
+ * @format: pixel format info
+ * @width: width of the first plane
+ * @plane: plane index
+ *
+ * Returns:
+ * The width of @plane, given that the width of the first plane is @width.
+ */
+static inline
+int image_format_info_plane_width(const struct image_format_info *info, int width,
+				  int plane)
+{
+	if (!info || plane >= info->num_planes)
+		return 0;
+
+	if (plane == 0)
+		return width;
+
+	return width / info->hsub;
+}
+
+/**
+ * image_format_info_plane_height - height of the plane given the first plane
+ * @format: pixel format info
+ * @height: height of the first plane
+ * @plane: plane index
+ *
+ * Returns:
+ * The height of @plane, given that the height of the first plane is @height.
+ */
+static inline
+int image_format_info_plane_height(const struct image_format_info *info, int height,
+				   int plane)
+{
+	if (!info || plane >= info->num_planes)
+		return 0;
+
+	if (plane == 0)
+		return height;
+
+	return height / info->vsub;
+}
+
+/**
+ * image_format_info_block_width - width in pixels of block.
+ * @format: pointer to the image_format_info
+ * @plane: plane index
+ *
+ * Returns:
+ * The width in pixels of a block, depending on the plane index.
+ */
+static inline
+unsigned int image_format_info_block_width(const struct image_format_info *format,
+					   int plane)
+{
+	if (!format)
+		return 0;
+
+	if (plane < 0 || plane >= ARRAY_SIZE(format->block_w))
+		return 0;
+
+	if (plane >= format->num_planes)
+		return 0;
+
+	if (!format->block_w[plane])
+		return 1;
+
+	return format->block_w[plane];
+}
+
+/**
+ * image_format_info_block_height - height in pixels of a block
+ * @info: pointer to the image_format_info
+ * @plane: plane index
+ *
+ * Returns:
+ * The height in pixels of a block, depending on the plane index.
+ */
+static inline
+unsigned int image_format_info_block_height(const struct image_format_info *format,
+					    int plane)
+{
+	if (!format)
+		return 0;
+
+	if (plane < 0 || plane >= ARRAY_SIZE(format->block_w))
+		return 0;
+
+	if (plane >= format->num_planes)
+		return 0;
+
+	if (!format->block_h[plane])
+		return 1;
+
+	return format->block_h[plane];
+}
+
+/**
+ * image_format_info_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.
+ */
+static inline
+uint64_t image_format_info_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_info_block_width(info, plane) *
+			    image_format_info_block_height(info, plane));
+}
+
+const struct image_format_info *__image_format_drm_lookup(u32 drm);
+const struct image_format_info *image_format_drm_lookup(u32 drm);
+
+#endif /* _IMAGE_FORMATS_H_ */
diff --git a/lib/Kconfig b/lib/Kconfig
index fb453afff32e..9a0160d3123b 100644
--- a/lib/Kconfig
+++ b/lib/Kconfig
@@ -625,3 +625,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 6996d2b9f401..203336b91248 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -280,3 +280,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..d0f0011b535e
--- /dev/null
+++ b/lib/image-formats-selftests.c
@@ -0,0 +1,325 @@
+// 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_info_block_width(void)
+{
+	const struct image_format_info *info = NULL;
+
+	/* Test invalid arguments */
+	FAIL_ON(image_format_info_block_width(info, 0) != 0);
+	FAIL_ON(image_format_info_block_width(info, -1) != 0);
+	FAIL_ON(image_format_info_block_width(info, 1) != 0);
+
+	/* Test 1 plane format */
+	info = image_format_drm_lookup(DRM_FORMAT_XRGB4444);
+	FAIL_ON(!info);
+	FAIL_ON(image_format_info_block_width(info, 0) != 1);
+	FAIL_ON(image_format_info_block_width(info, 1) != 0);
+	FAIL_ON(image_format_info_block_width(info, -1) != 0);
+
+	/* Test 2 planes format */
+	info = image_format_drm_lookup(DRM_FORMAT_NV12);
+	FAIL_ON(!info);
+	FAIL_ON(image_format_info_block_width(info, 0) != 1);
+	FAIL_ON(image_format_info_block_width(info, 1) != 1);
+	FAIL_ON(image_format_info_block_width(info, 2) != 0);
+	FAIL_ON(image_format_info_block_width(info, -1) != 0);
+
+	/* Test 3 planes format */
+	info = image_format_drm_lookup(DRM_FORMAT_YUV422);
+	FAIL_ON(!info);
+	FAIL_ON(image_format_info_block_width(info, 0) != 1);
+	FAIL_ON(image_format_info_block_width(info, 1) != 1);
+	FAIL_ON(image_format_info_block_width(info, 2) != 1);
+	FAIL_ON(image_format_info_block_width(info, 3) != 0);
+	FAIL_ON(image_format_info_block_width(info, -1) != 0);
+
+	/* Test a tiled format */
+	info = image_format_drm_lookup(DRM_FORMAT_X0L0);
+	FAIL_ON(!info);
+	FAIL_ON(image_format_info_block_width(info, 0) != 2);
+	FAIL_ON(image_format_info_block_width(info, 1) != 0);
+	FAIL_ON(image_format_info_block_width(info, -1) != 0);
+
+	return 0;
+}
+
+static int test_image_format_info_block_height(void)
+{
+	const struct image_format_info *info = NULL;
+
+	/* Test invalid arguments */
+	FAIL_ON(image_format_info_block_height(info, 0) != 0);
+	FAIL_ON(image_format_info_block_height(info, -1) != 0);
+	FAIL_ON(image_format_info_block_height(info, 1) != 0);
+
+	/* Test 1 plane format */
+	info = image_format_drm_lookup(DRM_FORMAT_XRGB4444);
+	FAIL_ON(!info);
+	FAIL_ON(image_format_info_block_height(info, 0) != 1);
+	FAIL_ON(image_format_info_block_height(info, 1) != 0);
+	FAIL_ON(image_format_info_block_height(info, -1) != 0);
+
+	/* Test 2 planes format */
+	info = image_format_drm_lookup(DRM_FORMAT_NV12);
+	FAIL_ON(!info);
+	FAIL_ON(image_format_info_block_height(info, 0) != 1);
+	FAIL_ON(image_format_info_block_height(info, 1) != 1);
+	FAIL_ON(image_format_info_block_height(info, 2) != 0);
+	FAIL_ON(image_format_info_block_height(info, -1) != 0);
+
+	/* Test 3 planes format */
+	info = image_format_drm_lookup(DRM_FORMAT_YUV422);
+	FAIL_ON(!info);
+	FAIL_ON(image_format_info_block_height(info, 0) != 1);
+	FAIL_ON(image_format_info_block_height(info, 1) != 1);
+	FAIL_ON(image_format_info_block_height(info, 2) != 1);
+	FAIL_ON(image_format_info_block_height(info, 3) != 0);
+	FAIL_ON(image_format_info_block_height(info, -1) != 0);
+
+	/* Test a tiled format */
+	info = image_format_drm_lookup(DRM_FORMAT_X0L0);
+	FAIL_ON(!info);
+	FAIL_ON(image_format_info_block_height(info, 0) != 2);
+	FAIL_ON(image_format_info_block_height(info, 1) != 0);
+	FAIL_ON(image_format_info_block_height(info, -1) != 0);
+
+	return 0;
+}
+
+static int test_image_format_info_min_pitch(void)
+{
+	const struct image_format_info *info = NULL;
+
+	/* Test invalid arguments */
+	FAIL_ON(image_format_info_min_pitch(info, 0, 0) != 0);
+	FAIL_ON(image_format_info_min_pitch(info, -1, 0) != 0);
+	FAIL_ON(image_format_info_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_info_min_pitch(info, 0, 0) != 0);
+	FAIL_ON(image_format_info_min_pitch(info, -1, 0) != 0);
+	FAIL_ON(image_format_info_min_pitch(info, 1, 0) != 0);
+
+	FAIL_ON(image_format_info_min_pitch(info, 0, 1) != 1);
+	FAIL_ON(image_format_info_min_pitch(info, 0, 2) != 2);
+	FAIL_ON(image_format_info_min_pitch(info, 0, 640) != 640);
+	FAIL_ON(image_format_info_min_pitch(info, 0, 1024) != 1024);
+	FAIL_ON(image_format_info_min_pitch(info, 0, 1920) != 1920);
+	FAIL_ON(image_format_info_min_pitch(info, 0, 4096) != 4096);
+	FAIL_ON(image_format_info_min_pitch(info, 0, 671) != 671);
+	FAIL_ON(image_format_info_min_pitch(info, 0, UINT_MAX) !=
+			(uint64_t)UINT_MAX);
+	FAIL_ON(image_format_info_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_info_min_pitch(info, 0, 0) != 0);
+	FAIL_ON(image_format_info_min_pitch(info, -1, 0) != 0);
+	FAIL_ON(image_format_info_min_pitch(info, 1, 0) != 0);
+
+	FAIL_ON(image_format_info_min_pitch(info, 0, 1) != 2);
+	FAIL_ON(image_format_info_min_pitch(info, 0, 2) != 4);
+	FAIL_ON(image_format_info_min_pitch(info, 0, 640) != 1280);
+	FAIL_ON(image_format_info_min_pitch(info, 0, 1024) != 2048);
+	FAIL_ON(image_format_info_min_pitch(info, 0, 1920) != 3840);
+	FAIL_ON(image_format_info_min_pitch(info, 0, 4096) != 8192);
+	FAIL_ON(image_format_info_min_pitch(info, 0, 671) != 1342);
+	FAIL_ON(image_format_info_min_pitch(info, 0, UINT_MAX) !=
+			(uint64_t)UINT_MAX * 2);
+	FAIL_ON(image_format_info_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_info_min_pitch(info, 0, 0) != 0);
+	FAIL_ON(image_format_info_min_pitch(info, -1, 0) != 0);
+	FAIL_ON(image_format_info_min_pitch(info, 1, 0) != 0);
+
+	FAIL_ON(image_format_info_min_pitch(info, 0, 1) != 3);
+	FAIL_ON(image_format_info_min_pitch(info, 0, 2) != 6);
+	FAIL_ON(image_format_info_min_pitch(info, 0, 640) != 1920);
+	FAIL_ON(image_format_info_min_pitch(info, 0, 1024) != 3072);
+	FAIL_ON(image_format_info_min_pitch(info, 0, 1920) != 5760);
+	FAIL_ON(image_format_info_min_pitch(info, 0, 4096) != 12288);
+	FAIL_ON(image_format_info_min_pitch(info, 0, 671) != 2013);
+	FAIL_ON(image_format_info_min_pitch(info, 0, UINT_MAX) !=
+			(uint64_t)UINT_MAX * 3);
+	FAIL_ON(image_format_info_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_info_min_pitch(info, 0, 0) != 0);
+	FAIL_ON(image_format_info_min_pitch(info, -1, 0) != 0);
+	FAIL_ON(image_format_info_min_pitch(info, 1, 0) != 0);
+
+	FAIL_ON(image_format_info_min_pitch(info, 0, 1) != 4);
+	FAIL_ON(image_format_info_min_pitch(info, 0, 2) != 8);
+	FAIL_ON(image_format_info_min_pitch(info, 0, 640) != 2560);
+	FAIL_ON(image_format_info_min_pitch(info, 0, 1024) != 4096);
+	FAIL_ON(image_format_info_min_pitch(info, 0, 1920) != 7680);
+	FAIL_ON(image_format_info_min_pitch(info, 0, 4096) != 16384);
+	FAIL_ON(image_format_info_min_pitch(info, 0, 671) != 2684);
+	FAIL_ON(image_format_info_min_pitch(info, 0, UINT_MAX) !=
+			(uint64_t)UINT_MAX * 4);
+	FAIL_ON(image_format_info_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_info_min_pitch(info, 0, 0) != 0);
+	FAIL_ON(image_format_info_min_pitch(info, 1, 0) != 0);
+	FAIL_ON(image_format_info_min_pitch(info, -1, 0) != 0);
+	FAIL_ON(image_format_info_min_pitch(info, 2, 0) != 0);
+
+	FAIL_ON(image_format_info_min_pitch(info, 0, 1) != 1);
+	FAIL_ON(image_format_info_min_pitch(info, 1, 1) != 2);
+	FAIL_ON(image_format_info_min_pitch(info, 0, 2) != 2);
+	FAIL_ON(image_format_info_min_pitch(info, 1, 1) != 2);
+	FAIL_ON(image_format_info_min_pitch(info, 0, 640) != 640);
+	FAIL_ON(image_format_info_min_pitch(info, 1, 320) != 640);
+	FAIL_ON(image_format_info_min_pitch(info, 0, 1024) != 1024);
+	FAIL_ON(image_format_info_min_pitch(info, 1, 512) != 1024);
+	FAIL_ON(image_format_info_min_pitch(info, 0, 1920) != 1920);
+	FAIL_ON(image_format_info_min_pitch(info, 1, 960) != 1920);
+	FAIL_ON(image_format_info_min_pitch(info, 0, 4096) != 4096);
+	FAIL_ON(image_format_info_min_pitch(info, 1, 2048) != 4096);
+	FAIL_ON(image_format_info_min_pitch(info, 0, 671) != 671);
+	FAIL_ON(image_format_info_min_pitch(info, 1, 336) != 672);
+	FAIL_ON(image_format_info_min_pitch(info, 0, UINT_MAX) !=
+			(uint64_t)UINT_MAX);
+	FAIL_ON(image_format_info_min_pitch(info, 1, UINT_MAX / 2 + 1) !=
+			(uint64_t)UINT_MAX + 1);
+	FAIL_ON(image_format_info_min_pitch(info, 0, (UINT_MAX - 1)) !=
+			(uint64_t)(UINT_MAX - 1));
+	FAIL_ON(image_format_info_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_info_min_pitch(info, 0, 0) != 0);
+	FAIL_ON(image_format_info_min_pitch(info, 1, 0) != 0);
+	FAIL_ON(image_format_info_min_pitch(info, 2, 0) != 0);
+	FAIL_ON(image_format_info_min_pitch(info, -1, 0) != 0);
+	FAIL_ON(image_format_info_min_pitch(info, 3, 0) != 0);
+
+	FAIL_ON(image_format_info_min_pitch(info, 0, 1) != 1);
+	FAIL_ON(image_format_info_min_pitch(info, 1, 1) != 1);
+	FAIL_ON(image_format_info_min_pitch(info, 2, 1) != 1);
+	FAIL_ON(image_format_info_min_pitch(info, 0, 2) != 2);
+	FAIL_ON(image_format_info_min_pitch(info, 1, 2) != 2);
+	FAIL_ON(image_format_info_min_pitch(info, 2, 2) != 2);
+	FAIL_ON(image_format_info_min_pitch(info, 0, 640) != 640);
+	FAIL_ON(image_format_info_min_pitch(info, 1, 320) != 320);
+	FAIL_ON(image_format_info_min_pitch(info, 2, 320) != 320);
+	FAIL_ON(image_format_info_min_pitch(info, 0, 1024) != 1024);
+	FAIL_ON(image_format_info_min_pitch(info, 1, 512) != 512);
+	FAIL_ON(image_format_info_min_pitch(info, 2, 512) != 512);
+	FAIL_ON(image_format_info_min_pitch(info, 0, 1920) != 1920);
+	FAIL_ON(image_format_info_min_pitch(info, 1, 960) != 960);
+	FAIL_ON(image_format_info_min_pitch(info, 2, 960) != 960);
+	FAIL_ON(image_format_info_min_pitch(info, 0, 4096) != 4096);
+	FAIL_ON(image_format_info_min_pitch(info, 1, 2048) != 2048);
+	FAIL_ON(image_format_info_min_pitch(info, 2, 2048) != 2048);
+	FAIL_ON(image_format_info_min_pitch(info, 0, 671) != 671);
+	FAIL_ON(image_format_info_min_pitch(info, 1, 336) != 336);
+	FAIL_ON(image_format_info_min_pitch(info, 2, 336) != 336);
+	FAIL_ON(image_format_info_min_pitch(info, 0, UINT_MAX) !=
+			(uint64_t)UINT_MAX);
+	FAIL_ON(image_format_info_min_pitch(info, 1, UINT_MAX / 2 + 1) !=
+			(uint64_t)UINT_MAX / 2 + 1);
+	FAIL_ON(image_format_info_min_pitch(info, 2, UINT_MAX / 2 + 1) !=
+			(uint64_t)UINT_MAX / 2 + 1);
+	FAIL_ON(image_format_info_min_pitch(info, 0, (UINT_MAX - 1) / 2) !=
+			(uint64_t)(UINT_MAX - 1) / 2);
+	FAIL_ON(image_format_info_min_pitch(info, 1, (UINT_MAX - 1) / 2) !=
+			(uint64_t)(UINT_MAX - 1) / 2);
+	FAIL_ON(image_format_info_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_info_min_pitch(info, 0, 0) != 0);
+	FAIL_ON(image_format_info_min_pitch(info, -1, 0) != 0);
+	FAIL_ON(image_format_info_min_pitch(info, 1, 0) != 0);
+
+	FAIL_ON(image_format_info_min_pitch(info, 0, 1) != 2);
+	FAIL_ON(image_format_info_min_pitch(info, 0, 2) != 4);
+	FAIL_ON(image_format_info_min_pitch(info, 0, 640) != 1280);
+	FAIL_ON(image_format_info_min_pitch(info, 0, 1024) != 2048);
+	FAIL_ON(image_format_info_min_pitch(info, 0, 1920) != 3840);
+	FAIL_ON(image_format_info_min_pitch(info, 0, 4096) != 8192);
+	FAIL_ON(image_format_info_min_pitch(info, 0, 671) != 1342);
+	FAIL_ON(image_format_info_min_pitch(info, 0, UINT_MAX) !=
+			(uint64_t)UINT_MAX * 2);
+	FAIL_ON(image_format_info_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_info_block_height),
+	selftest(test_image_format_info_block_width),
+	selftest(test_image_format_info_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;
+}
+module_init(image_format_test_init);
+
+MODULE_AUTHOR("Intel Corporation");
+MODULE_AUTHOR("Maxime Ripard <maxime.ripard@bootlin.com>");
+MODULE_LICENSE("GPL");
diff --git a/lib/image-formats.c b/lib/image-formats.c
new file mode 100644
index 000000000000..1e52a7410222
--- /dev/null
+++ b/lib/image-formats.c
@@ -0,0 +1,655 @@
+/*
+ * Copyright (c) 2016 Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+ * Copyright (c) 2019 Maxime Ripard <maxime.ripard@bootlin.com>
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that copyright
+ * notice and this permission notice appear in supporting documentation, and
+ * that the name of the copyright holders not be used in advertising or
+ * publicity pertaining to distribution of the software without specific,
+ * written prior permission.  The copyright holders make no representations
+ * about the suitability of this software for any purpose.  It is provided "as
+ * is" without express or implied warranty.
+ *
+ * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
+ * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+ * OF THIS SOFTWARE.
+ */
+
+#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);
-- 
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-04-17  7:56 UTC|newest]

Thread overview: 115+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2019-04-17  7:54 [PATCH 00/20] drm: Split out the formats API and move it to a common place Maxime Ripard
2019-04-17  7:54 ` [PATCH 01/20] drm: Remove users of drm_format_num_planes Maxime Ripard
2019-04-17  7:54 ` [PATCH 02/20] drm: Remove users of drm_format_(horz|vert)_chroma_subsampling Maxime Ripard
2019-04-17  7:54   ` Maxime Ripard
2019-04-17 13:32   ` Philipp Zabel
2019-04-17  7:54 ` [PATCH 03/20] drm/fourcc: Pass the format_info pointer to drm_format_plane_cpp Maxime Ripard
2019-04-17  7:54   ` Maxime Ripard
2019-04-17  7:54 ` [PATCH 04/20] drm/fourcc: Pass the format_info pointer to drm_format_plane_width/height Maxime Ripard
2019-04-17 10:47   ` Maarten Lankhorst
2019-04-17 11:01     ` Maxime Ripard
2019-04-17 11:10       ` Maarten Lankhorst
2019-04-17 13:12         ` Maxime Ripard
2019-04-17  7:54 ` [PATCH 05/20] drm: Replace instances of drm_format_info by drm_get_format_info Maxime Ripard
2019-04-17  7:54 ` Maxime Ripard [this message]
2019-04-17  7:54   ` [PATCH 06/20] lib: Add video format information library Maxime Ripard
2019-04-17 12:34   ` Paul Kocialkowski
2019-04-17 12:48     ` Maxime Ripard
2019-04-17 14:03       ` Paul Kocialkowski
2019-04-23 11:22   ` Thomas Zimmermann
2019-04-23 16:56     ` Paul Kocialkowski
2019-04-23 16:56       ` Paul Kocialkowski
2019-04-17  7:54 ` [PATCH 07/20] drm/fb: Move from drm_format_info to image_format_info Maxime Ripard
2019-04-17  7:54   ` Maxime Ripard
2019-04-17  7:54 ` [PATCH 08/20] drm/malidp: Convert to generic image format library Maxime Ripard
2019-04-17  7:54   ` Maxime Ripard
2019-04-17  7:54 ` [PATCH 09/20] drm/client: " Maxime Ripard
2019-04-17  7:54 ` [PATCH 10/20] drm/exynos: " Maxime Ripard
2019-04-17  7:54   ` Maxime Ripard
2019-04-17  7:54 ` [PATCH 11/20] drm/i915: " Maxime Ripard
2019-04-17  7:54   ` Maxime Ripard
2019-04-17  7:54 ` [PATCH 12/20] drm/ipuv3: " Maxime Ripard
2019-04-17  7:54 ` [PATCH 13/20] drm/msm: " Maxime Ripard
2019-04-17  7:54 ` [PATCH 14/20] drm/omap: " Maxime Ripard
2019-04-17  7:54   ` Maxime Ripard
2019-04-17  7:54 ` [PATCH 15/20] drm/rockchip: " Maxime Ripard
2019-04-17  7:54   ` Maxime Ripard
2019-04-17  7:54 ` [PATCH 16/20] drm/tegra: " Maxime Ripard
2019-04-17  7:54   ` Maxime Ripard
2019-04-17  7:54 ` [PATCH 17/20] drm/fourcc: Remove old DRM format API Maxime Ripard
2019-04-17  7:54 ` [PATCH 18/20] lib: image-formats: Add v4l2 formats support Maxime Ripard
2019-04-17  7:54   ` Maxime Ripard
2019-05-02  8:24   ` Hans Verkuil
2019-05-06 13:22     ` Maxime Ripard
2019-04-17  7:54 ` [PATCH 19/20] lib: image-formats: Add more functions Maxime Ripard
2019-04-17 12:39   ` Paul Kocialkowski
2019-04-17 12:39     ` Paul Kocialkowski
2019-04-17 12:41   ` Sakari Ailus
2019-04-17  7:54 ` [PATCH 20/20] media: sun6i: Convert to the image format API Maxime Ripard
2019-04-17 12:23 ` [PATCH 00/20] drm: Split out the formats API and move it to a common place Paul Kocialkowski
2019-04-17 12:38 ` Paul Kocialkowski
2019-04-17 15:41 ` Daniel Vetter
2019-04-17 15:41   ` Daniel Vetter
2019-04-18  6:22   ` Maxime Ripard
2019-04-18  7:52     ` Daniel Vetter
2019-04-18  7:52       ` Daniel Vetter
2019-04-18  9:02       ` Maxime Ripard
2019-04-18  9:02         ` Maxime Ripard
2019-04-18 10:07         ` Daniel Vetter
2019-04-18 10:07           ` Daniel Vetter
2019-04-18 12:01           ` Maxime Ripard
2019-04-18 12:01             ` Maxime Ripard
2019-04-18 12:32             ` Daniel Vetter
2019-04-18 12:32               ` Daniel Vetter
2019-04-18 20:56               ` Maxime Ripard
2019-04-18 20:56                 ` Maxime Ripard
2019-04-20 23:05                 ` Laurent Pinchart
2019-04-20 23:05                   ` Laurent Pinchart
2019-05-02  8:25                 ` Hans Verkuil
2019-05-02  8:25                   ` Hans Verkuil
2019-04-20 22:59           ` Laurent Pinchart
2019-04-20 22:59             ` Laurent Pinchart
2019-04-23  7:25             ` Daniel Vetter
2019-04-23  7:25               ` Daniel Vetter
2019-04-23  8:59               ` Daniel Stone
2019-04-23  8:59                 ` Daniel Stone
2019-04-23 15:54                 ` Laurent Pinchart
2019-04-23 15:54                   ` Laurent Pinchart
2019-04-23 16:02                   ` Daniel Stone
2019-04-23 16:02                     ` Daniel Stone
2019-04-23 16:38                     ` Paul Kocialkowski
2019-04-23 16:38                       ` Paul Kocialkowski
2019-04-23 15:45               ` Laurent Pinchart
2019-04-23 15:45                 ` Laurent Pinchart
2019-04-23 16:46                 ` Paul Kocialkowski
2019-04-23 16:46                   ` Paul Kocialkowski
2019-04-23 19:18                 ` Daniel Vetter
2019-04-23 19:18                   ` Daniel Vetter
2019-05-11 19:26                   ` Laurent Pinchart
2019-05-11 19:26                     ` Laurent Pinchart
2019-05-13 14:57                     ` Daniel Vetter
2019-05-13 14:57                       ` Daniel Vetter
2019-05-13 15:23                       ` Mauro Carvalho Chehab
2019-05-13 15:23                         ` Mauro Carvalho Chehab
2019-04-18 11:49         ` Paul Kocialkowski
2019-04-18 11:49           ` Paul Kocialkowski
2019-04-20 22:40           ` Laurent Pinchart
2019-04-20 22:40             ` Laurent Pinchart
2019-04-23  7:30             ` Daniel Vetter
2019-04-23  7:30               ` Daniel Vetter
2019-04-23 12:33               ` Paul Kocialkowski
2019-04-23 12:33                 ` Paul Kocialkowski
2019-04-23 14:28                 ` Nicolas Dufresne
2019-04-23 14:28                   ` Nicolas Dufresne
2019-04-23 14:55                   ` Paul Kocialkowski
2019-04-23 14:55                     ` Paul Kocialkowski
2019-04-23 15:09                   ` Daniel Vetter
2019-04-23 15:09                     ` Daniel Vetter
2019-04-23 17:16                     ` Nicolas Dufresne
2019-04-23 17:16                       ` Nicolas Dufresne
2019-04-23 19:06                       ` Daniel Vetter
2019-04-23 19:06                         ` Daniel Vetter
2019-04-23 16:54             ` Paul Kocialkowski
2019-04-23 16:54               ` Paul Kocialkowski
2019-05-11 19:19               ` Laurent Pinchart
2019-05-11 19:19                 ` Laurent Pinchart

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=c17a896150f0b793cfa8581d18969cd7b3e93bf2.1555487650.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.