[PATCH 07/11] drm/fbdevdrm: Add DRM <-> fbdev pixel-format conversion

Thomas Zimmermann tzimmermann at suse.de
Tue Mar 26 09:17:40 UTC 2019


Signed-off-by: Thomas Zimmermann <tzimmermann at suse.de>
---
 drivers/gpu/drm/fbdevdrm/Makefile          |   1 +
 drivers/gpu/drm/fbdevdrm/fbdevdrm_format.c | 441 +++++++++++++++++++++
 drivers/gpu/drm/fbdevdrm/fbdevdrm_format.h |  26 ++
 3 files changed, 468 insertions(+)
 create mode 100644 drivers/gpu/drm/fbdevdrm/fbdevdrm_format.c
 create mode 100644 drivers/gpu/drm/fbdevdrm/fbdevdrm_format.h

diff --git a/drivers/gpu/drm/fbdevdrm/Makefile b/drivers/gpu/drm/fbdevdrm/Makefile
index b8fab9d52faa..aef60d0f4888 100644
--- a/drivers/gpu/drm/fbdevdrm/Makefile
+++ b/drivers/gpu/drm/fbdevdrm/Makefile
@@ -2,6 +2,7 @@ ccflags-y = -Iinclude/drm
 fbdevdrm-y := fbdevdrm_bo.o \
 	      fbdevdrm_device.o \
 	      fbdevdrm_drv.o \
+	      fbdevdrm_format.o \
 	      fbdevdrm_modeset.o \
 	      fbdevdrm_ttm.o
 
diff --git a/drivers/gpu/drm/fbdevdrm/fbdevdrm_format.c b/drivers/gpu/drm/fbdevdrm/fbdevdrm_format.c
new file mode 100644
index 000000000000..208f7c60e525
--- /dev/null
+++ b/drivers/gpu/drm/fbdevdrm/fbdevdrm_format.c
@@ -0,0 +1,441 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later
+ *
+ * One purpose of this driver is to allow for easy conversion of framebuffer
+ * drivers to DRM. As a special exception to the GNU GPL, you are allowed to
+ * relicense this file under the terms of a license of your choice if you're
+ * porting a framebuffer driver. In order to do so, update the SPDX license
+ * identifier to the new license and remove this exception.
+ *
+ * If you add code to this file, please ensure that it's compatible with the
+ * stated exception.
+ */
+
+#include "fbdevdrm_format.h"
+#include <asm/byteorder.h>
+#include <linux/fb.h>
+
+#if defined __BIG_ENDIAN
+#define HOST_FUNC(_func) \
+	_func ## _be
+#elif defined __LITTLE_ENDIAN
+#define HOST_FUNC(_func) \
+	_func ## _le
+#else
+#error "Unsupported endianess"
+#endif
+
+static bool is_c8(const struct fb_info* fb_info)
+{
+	return fb_info->var.bits_per_pixel == 8;
+}
+
+static bool is_rgb565_be(const struct fb_info* fb_info)
+{
+	return (fb_info->var.bits_per_pixel == 16) &&
+	       (fb_info->var.red.offset == 0) &&
+	       (fb_info->var.red.length == 5) &&
+	       (fb_info->var.green.offset == 5) &&
+	       (fb_info->var.green.length == 6) &&
+	       (fb_info->var.blue.offset == 11) &&
+	       (fb_info->var.blue.length == 5);
+}
+
+static bool is_bgr565_be(const struct fb_info* fb_info)
+{
+	return (fb_info->var.bits_per_pixel == 16) &&
+	       (fb_info->var.red.offset == 11) &&
+	       (fb_info->var.red.length == 5) &&
+	       (fb_info->var.green.offset == 5) &&
+	       (fb_info->var.green.length == 6) &&
+	       (fb_info->var.blue.offset == 0) &&
+	       (fb_info->var.blue.length == 5);
+}
+
+static bool is_rgb888_be(const struct fb_info* fb_info)
+{
+	return (fb_info->var.bits_per_pixel == 24) &&
+	       (fb_info->var.red.offset == 0) &&
+	       (fb_info->var.red.length == 8) &&
+	       (fb_info->var.green.offset == 8) &&
+	       (fb_info->var.green.length == 8) &&
+	       (fb_info->var.blue.offset == 16) &&
+	       (fb_info->var.blue.length == 8);
+}
+
+static bool is_bgr888_be(const struct fb_info* fb_info)
+{
+	return (fb_info->var.bits_per_pixel == 24) &&
+	       (fb_info->var.red.offset == 16) &&
+	       (fb_info->var.red.length == 8) &&
+	       (fb_info->var.green.offset == 8) &&
+	       (fb_info->var.green.length == 8) &&
+	       (fb_info->var.blue.offset == 0) &&
+	       (fb_info->var.blue.length == 8);
+}
+
+static bool is_xrgb8888_be(const struct fb_info* fb_info)
+{
+	return (fb_info->var.bits_per_pixel == 32) &&
+	       (fb_info->var.red.offset == 8) &&
+	       (fb_info->var.red.length == 8) &&
+	       (fb_info->var.green.offset == 16) &&
+	       (fb_info->var.green.length == 8) &&
+	       (fb_info->var.blue.offset == 24) &&
+	       (fb_info->var.blue.length == 8) &&
+	       (fb_info->var.transp.length == 0);
+}
+
+static bool is_xbgr8888_be(const struct fb_info* fb_info)
+{
+	return (fb_info->var.bits_per_pixel == 32) &&
+	       (fb_info->var.red.offset == 24) &&
+	       (fb_info->var.red.length == 8) &&
+	       (fb_info->var.green.offset == 16) &&
+	       (fb_info->var.green.length == 8) &&
+	       (fb_info->var.blue.offset == 8) &&
+	       (fb_info->var.blue.length == 8) &&
+	       (fb_info->var.transp.length == 0);
+}
+
+static bool is_rgbx8888_be(const struct fb_info* fb_info)
+{
+	return (fb_info->var.bits_per_pixel == 32) &&
+	       (fb_info->var.red.offset == 0) &&
+	       (fb_info->var.red.length == 8) &&
+	       (fb_info->var.green.offset == 8) &&
+	       (fb_info->var.green.length == 8) &&
+	       (fb_info->var.blue.offset == 16) &&
+	       (fb_info->var.blue.length == 8) &&
+	       (fb_info->var.transp.length == 0);
+}
+
+static bool is_bgrx8888_be(const struct fb_info* fb_info)
+{
+	return (fb_info->var.bits_per_pixel == 32) &&
+	       (fb_info->var.red.offset == 16) &&
+	       (fb_info->var.red.length == 8) &&
+	       (fb_info->var.green.offset == 8) &&
+	       (fb_info->var.green.length == 8) &&
+	       (fb_info->var.blue.offset == 0) &&
+	       (fb_info->var.blue.length == 8) &&
+	       (fb_info->var.transp.length == 0);
+}
+
+static bool is_argb8888_be(const struct fb_info* fb_info)
+{
+	return (fb_info->var.bits_per_pixel == 32) &&
+	       (fb_info->var.red.offset == 8) &&
+	       (fb_info->var.red.length == 8) &&
+	       (fb_info->var.green.offset == 16) &&
+	       (fb_info->var.green.length == 8) &&
+	       (fb_info->var.blue.offset == 24) &&
+	       (fb_info->var.blue.length == 8) &&
+	       (fb_info->var.transp.offset == 0) &&
+	       (fb_info->var.transp.length == 8);
+}
+
+static bool is_abgr8888_be(const struct fb_info* fb_info)
+{
+	return (fb_info->var.bits_per_pixel == 32) &&
+	       (fb_info->var.red.offset == 24) &&
+	       (fb_info->var.red.length == 8) &&
+	       (fb_info->var.green.offset == 16) &&
+	       (fb_info->var.green.length == 8) &&
+	       (fb_info->var.blue.offset == 8) &&
+	       (fb_info->var.blue.length == 8) &&
+	       (fb_info->var.transp.offset == 0) &&
+	       (fb_info->var.transp.length == 8);
+}
+
+static bool is_rgba8888_be(const struct fb_info* fb_info)
+{
+	return (fb_info->var.bits_per_pixel == 32) &&
+	       (fb_info->var.red.offset == 0) &&
+	       (fb_info->var.red.length == 8) &&
+	       (fb_info->var.green.offset == 8) &&
+	       (fb_info->var.green.length == 8) &&
+	       (fb_info->var.blue.offset == 16) &&
+	       (fb_info->var.blue.length == 8) &&
+	       (fb_info->var.transp.offset == 24) &&
+	       (fb_info->var.transp.length == 8);
+}
+
+static bool is_bgra8888_be(const struct fb_info* fb_info)
+{
+	return (fb_info->var.bits_per_pixel == 32) &&
+	       (fb_info->var.red.offset == 16) &&
+	       (fb_info->var.red.length == 8) &&
+	       (fb_info->var.green.offset == 8) &&
+	       (fb_info->var.green.length == 8) &&
+	       (fb_info->var.blue.offset == 0) &&
+	       (fb_info->var.blue.length == 8) &&
+	       (fb_info->var.transp.offset == 24) &&
+	       (fb_info->var.transp.length == 8);
+}
+
+#define is_rgb565_le is_bgr565_be
+#define is_bgr565_le is_rgb565_be
+#define is_rgb888_le is_bgr888_be
+#define is_bgr888_le is_rgb888_be
+#define is_xrgb8888_le is_bgrx8888_be
+#define is_xbgr8888_le is_rgbx8888_be
+#define is_rgbx8888_le is_xbgr8888_be
+#define is_bgrx8888_le is_xrgb8888_be
+#define is_argb8888_le is_bgra8888_be
+#define is_abgr8888_le is_rgba8888_be
+#define is_rgba8888_le is_abgr8888_be
+#define is_bgra8888_le is_argb8888_be
+
+struct format_map {
+	bool (*is_format)(const struct fb_info*);
+	uint32_t format;
+};
+
+uint32_t fbdevdrm_format_of_fb_info(const struct fb_info *fb_info)
+{
+	static const struct format_map map[] = {
+		{ is_c8,                  DRM_FORMAT_C8 },      /* 256-color palette */
+		{ HOST_FUNC(is_rgb565),   DRM_FORMAT_RGB565 },
+		{ HOST_FUNC(is_bgr565),   DRM_FORMAT_BGR565 },
+		{ HOST_FUNC(is_rgb888),   DRM_FORMAT_RGB888 },
+		{ HOST_FUNC(is_bgr888),   DRM_FORMAT_BGR888 },
+		{ HOST_FUNC(is_xrgb8888), DRM_FORMAT_XRGB8888 },
+		{ HOST_FUNC(is_xbgr8888), DRM_FORMAT_XBGR8888 },
+		{ HOST_FUNC(is_rgbx8888), DRM_FORMAT_RGBX8888 },
+		{ HOST_FUNC(is_bgrx8888), DRM_FORMAT_BGRX8888 },
+		{ HOST_FUNC(is_argb8888), DRM_FORMAT_ARGB8888 },
+		{ HOST_FUNC(is_abgr8888), DRM_FORMAT_ABGR8888 },
+		{ HOST_FUNC(is_rgba8888), DRM_FORMAT_RGBA8888 },
+		{ HOST_FUNC(is_bgra8888), DRM_FORMAT_BGRA8888 }
+	};
+
+	size_t i;
+
+	if (fb_info->fix.type != FB_TYPE_PACKED_PIXELS)
+		goto err; /* multi-plane formats are not supported */
+	if (fb_info->var.bits_per_pixel < 8)
+		goto err; /* at least 8-bit color required */
+	if (fb_info->var.grayscale == 1)
+		goto err; /* grayscale output is not supported */
+
+	for (i = 0; i < ARRAY_SIZE(map); ++i) {
+		if (map[i].is_format(fb_info))
+			return map[i].format;
+	}
+
+err:
+	return DRM_FORMAT_INVALID;
+}
+
+static void set_fb_bitfield(struct fb_bitfield *bits, __u32 offset,
+			    __u32 length)
+{
+	bits->offset = offset;
+	bits->length = length;
+	bits->msb_right = 0;
+}
+
+static void set_c8(struct fb_var_screeninfo *fb_var)
+{
+	fb_var->bits_per_pixel = 8;
+	fb_var->grayscale = 0;
+	set_fb_bitfield(&fb_var->red,    0, 8);
+	set_fb_bitfield(&fb_var->green,  0, 8);
+	set_fb_bitfield(&fb_var->blue,   0, 8);
+	set_fb_bitfield(&fb_var->transp, 0, 0);
+	fb_var->nonstd = 0;
+}
+
+static void set_rgb565_be(struct fb_var_screeninfo *fb_var)
+{
+	fb_var->bits_per_pixel = 16;
+	fb_var->grayscale = 0;
+	set_fb_bitfield(&fb_var->red,    0, 5);
+	set_fb_bitfield(&fb_var->green,  5, 6);
+	set_fb_bitfield(&fb_var->blue,  11, 5);
+	set_fb_bitfield(&fb_var->transp, 0, 0);
+	fb_var->nonstd = 0;
+}
+
+static void set_bgr565_be(struct fb_var_screeninfo *fb_var)
+{
+	fb_var->bits_per_pixel = 16;
+	fb_var->grayscale = 0;
+	set_fb_bitfield(&fb_var->red,   11, 5);
+	set_fb_bitfield(&fb_var->green,  5, 6);
+	set_fb_bitfield(&fb_var->blue,   0, 5);
+	set_fb_bitfield(&fb_var->transp, 0, 0);
+	fb_var->nonstd = 0;
+}
+
+static void set_rgb888_be(struct fb_var_screeninfo *fb_var)
+{
+	fb_var->bits_per_pixel = 24;
+	fb_var->grayscale = 0;
+	set_fb_bitfield(&fb_var->red,    0, 8);
+	set_fb_bitfield(&fb_var->green,  8, 8);
+	set_fb_bitfield(&fb_var->blue,  16, 8);
+	set_fb_bitfield(&fb_var->transp, 0, 0);
+	fb_var->nonstd = 0;
+}
+
+static void set_bgr888_be(struct fb_var_screeninfo *fb_var)
+{
+	fb_var->bits_per_pixel = 24;
+	fb_var->grayscale = 0;
+	set_fb_bitfield(&fb_var->red,   16, 8);
+	set_fb_bitfield(&fb_var->green,  8, 8);
+	set_fb_bitfield(&fb_var->blue,   0, 8);
+	set_fb_bitfield(&fb_var->transp, 0, 0);
+	fb_var->nonstd = 0;
+}
+
+static void set_xrgb8888_be(struct fb_var_screeninfo *fb_var)
+{
+	fb_var->bits_per_pixel = 32;
+	fb_var->grayscale = 0;
+	set_fb_bitfield(&fb_var->red,    8, 8);
+	set_fb_bitfield(&fb_var->green, 16, 8);
+	set_fb_bitfield(&fb_var->blue,  24, 8);
+	set_fb_bitfield(&fb_var->transp, 0, 0);
+	fb_var->nonstd = 0;
+}
+
+static void set_xbgr8888_be(struct fb_var_screeninfo *fb_var)
+{
+	fb_var->bits_per_pixel = 32;
+	fb_var->grayscale = 0;
+	set_fb_bitfield(&fb_var->red,   24, 8);
+	set_fb_bitfield(&fb_var->green, 16, 8);
+	set_fb_bitfield(&fb_var->blue,   8, 8);
+	set_fb_bitfield(&fb_var->transp, 0, 0);
+	fb_var->nonstd = 0;
+}
+
+static void set_rgbx8888_be(struct fb_var_screeninfo *fb_var)
+{
+	fb_var->bits_per_pixel = 32;
+	fb_var->grayscale = 0;
+	set_fb_bitfield(&fb_var->red,     0, 8);
+	set_fb_bitfield(&fb_var->green,   8, 8);
+	set_fb_bitfield(&fb_var->blue,   16, 8);
+	set_fb_bitfield(&fb_var->transp, 24, 0);
+	fb_var->nonstd = 0;
+}
+
+static void set_bgrx8888_be(struct fb_var_screeninfo *fb_var)
+{
+	fb_var->bits_per_pixel = 32;
+	fb_var->grayscale = 0;
+	set_fb_bitfield(&fb_var->red,    16, 8);
+	set_fb_bitfield(&fb_var->green,   8, 8);
+	set_fb_bitfield(&fb_var->blue,    0, 8);
+	set_fb_bitfield(&fb_var->transp, 24, 0);
+	fb_var->nonstd = 0;
+}
+
+static void set_argb8888_be(struct fb_var_screeninfo *fb_var)
+{
+	fb_var->bits_per_pixel = 32;
+	fb_var->grayscale = 0;
+	set_fb_bitfield(&fb_var->red,    8, 8);
+	set_fb_bitfield(&fb_var->green, 16, 8);
+	set_fb_bitfield(&fb_var->blue,  24, 8);
+	set_fb_bitfield(&fb_var->transp, 0, 8);
+	fb_var->nonstd = 0;
+}
+
+static void set_abgr8888_be(struct fb_var_screeninfo *fb_var)
+{
+	fb_var->bits_per_pixel = 32;
+	fb_var->grayscale = 0;
+	set_fb_bitfield(&fb_var->red,   24, 8);
+	set_fb_bitfield(&fb_var->green, 16, 8);
+	set_fb_bitfield(&fb_var->blue,   8, 8);
+	set_fb_bitfield(&fb_var->transp, 0, 8);
+	fb_var->nonstd = 0;
+}
+
+static void set_rgba8888_be(struct fb_var_screeninfo *fb_var)
+{
+	fb_var->bits_per_pixel = 32;
+	fb_var->grayscale = 0;
+	set_fb_bitfield(&fb_var->red,     0, 8);
+	set_fb_bitfield(&fb_var->green,   8, 8);
+	set_fb_bitfield(&fb_var->blue,   16, 8);
+	set_fb_bitfield(&fb_var->transp, 24, 8);
+	fb_var->nonstd = 0;
+}
+
+static void set_bgra8888_be(struct fb_var_screeninfo *fb_var)
+{
+	fb_var->bits_per_pixel = 32;
+	fb_var->grayscale = 0;
+	set_fb_bitfield(&fb_var->red,    16, 8);
+	set_fb_bitfield(&fb_var->green,   8, 8);
+	set_fb_bitfield(&fb_var->blue,    0, 8);
+	set_fb_bitfield(&fb_var->transp, 24, 8);
+	fb_var->nonstd = 0;
+}
+
+#define set_rgb565_le set_bgr565_be
+#define set_bgr565_le set_rgb565_be
+#define set_rgb888_le set_bgr888_be
+#define set_bgr888_le set_rgb888_be
+#define set_xrgb8888_le set_bgrx8888_be
+#define set_xbgr8888_le set_rgbx8888_be
+#define set_rgbx8888_le set_xbgr8888_be
+#define set_bgrx8888_le set_xrgb8888_be
+#define set_argb8888_le set_bgra8888_be
+#define set_abgr8888_le set_rgba8888_be
+#define set_rgba8888_le set_abgr8888_be
+#define set_bgra8888_le set_argb8888_be
+
+int fbdevdrm_update_fb_var_screeninfo_from_format(
+	struct fb_var_screeninfo *fb_var, uint32_t format)
+{
+	switch (format) {
+	case DRM_FORMAT_C8:
+		set_c8(fb_var);
+		break;
+	case DRM_FORMAT_RGB565:
+		HOST_FUNC(set_rgb565)(fb_var);
+		break;
+	case DRM_FORMAT_BGR565:
+		HOST_FUNC(set_bgr565)(fb_var);
+		break;
+	case DRM_FORMAT_RGB888:
+		HOST_FUNC(set_rgb888)(fb_var);
+		break;
+	case DRM_FORMAT_BGR888:
+		HOST_FUNC(set_bgr888)(fb_var);
+		break;
+	case DRM_FORMAT_XRGB8888:
+		HOST_FUNC(set_xrgb8888)(fb_var);
+		break;
+	case DRM_FORMAT_XBGR8888:
+		HOST_FUNC(set_xbgr8888)(fb_var);
+		break;
+	case DRM_FORMAT_RGBX8888:
+		HOST_FUNC(set_rgbx8888)(fb_var);
+		break;
+	case DRM_FORMAT_BGRX8888:
+		HOST_FUNC(set_bgrx8888)(fb_var);
+		break;
+	case DRM_FORMAT_ARGB8888:
+		HOST_FUNC(set_argb8888)(fb_var);
+		break;
+	case DRM_FORMAT_ABGR8888:
+		HOST_FUNC(set_abgr8888)(fb_var);
+		break;
+	case DRM_FORMAT_RGBA8888:
+		HOST_FUNC(set_rgba8888)(fb_var);
+		break;
+	case DRM_FORMAT_BGRA8888:
+		HOST_FUNC(set_bgra8888)(fb_var);
+		break;
+	default:
+		return -EINVAL;
+	}
+	return 0;
+}
diff --git a/drivers/gpu/drm/fbdevdrm/fbdevdrm_format.h b/drivers/gpu/drm/fbdevdrm/fbdevdrm_format.h
new file mode 100644
index 000000000000..e837978ac8fc
--- /dev/null
+++ b/drivers/gpu/drm/fbdevdrm/fbdevdrm_format.h
@@ -0,0 +1,26 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later
+ *
+ * One purpose of this driver is to allow for easy conversion of framebuffer
+ * drivers to DRM. As a special exception to the GNU GPL, you are allowed to
+ * relicense this file under the terms of a license of your choice if you're
+ * porting a framebuffer driver. In order to do so, update the SPDX license
+ * identifier to the new license and remove this exception.
+ *
+ * If you add code to this file, please ensure that it's compatible with the
+ * stated exception.
+ */
+
+#ifndef FBDEVDRM_FORMAT_H
+#define FBDEVDRM_FORMAT_H
+
+#include <drm/drm_fourcc.h>
+
+struct fb_info;
+struct fb_var_screeninfo;
+
+uint32_t fbdevdrm_format_of_fb_info(const struct fb_info *fb_info);
+
+int fbdevdrm_update_fb_var_screeninfo_from_format(
+	struct fb_var_screeninfo *fb_var, uint32_t format);
+
+#endif
-- 
2.21.0



More information about the dri-devel mailing list