My penguin has blue feets (aka: RGB versus BGR troubles)
Sam Ravnborg
sam at ravnborg.org
Fri Jul 26 20:36:26 UTC 2019
Hi all.
The Atmel at91sam9263 has a nice LCDC IP core that supports several
formats:
DRM_FORMAT_XBGR8888, DRM_FORMAT_BGR888, DRM_FORMAT_BGR565
(It also supports a palletized C8 format, but thats for later).
The formats are all BGR formats - and some boards actually reverse Blue
and Red when wiring up the display. I have added a DT property to
identify boards with this difference.
The penguin shown during boot of the kernel had blue feet which is a
clear sign that RED and GREEN was reversed.
So to fix this I (got help from imirkin on irc) I implmented a quirk.
See patch below.
With the quirk enabled I see:
- penguin shown during kernel boot has yellow feets (OK)
- modetest tell the driver reports: XB24 BG24 BG16 (as expected)
- modetest -s fails with:
# modetest -M atmel-lcdc -s 34:800x480-60Hz
setting mode 800x480-60Hz at XR24 on connectors 34, crtc 32
failed to set mode: Function not implemented
Snip from dmesg:
drm:drm_ioctl] pid=208, dev=0xe201, auth=1, DRM_IOCTL_MODE_ADDFB2
[drm:drm_mode_addfb2] [FB:37]
[drm:drm_ioctl] pid=208, dev=0xe201, auth=1, DRM_IOCTL_MODE_SETCRTC
[drm:drm_mode_setcrtc] [CRTC:32:crtc-0]
[drm:drm_mode_setcrtc] Invalid pixel format XR24 little-endian (0x34325258), modifier 0x0
^^^^
[drm:drm_mode_object_put] OBJ ID: 37 (2)
[drm:drm_ioctl] pid=208, ret = -22
[drm:drm_ioctl] pid=208, dev=0xe201, auth=1, DRM_IOCTL_MODE_DIRTYFB
[drm:drm_mode_object_put] OBJ ID: 37 (2)
[drm:drm_ioctl] pid=208, ret = -38
[drm:drm_ioctl] pid=208, dev=0xe201, auth=1, DRM_IOCTL_MODE_RMFB
[drm:drm_mode_object_put] OBJ ID: 37 (2)
[drm:drm_mode_object_put] OBJ ID: 37 (1)
[drm:drm_ioctl] pid=208, dev=0xe201, auth=1, DRM_IOCTL_MODE_DESTROY_DUMB
[drm:drm_release] open_count = 1
[drm:drm_file_free] pid = 208, device = 0xe201, open_count = 1
[drm:drm_lastclose]
[drm:drm_lastclose] driver lastclose completed
Notice that somehow we have a framebuffer in XR24 format, which is not
supported by the driver.
I have tried to tell that my driver supports DRM_FORMAT_XRGB8888,
DRM_FORMAT_RGB888, DRM_FORMAT_RGB565 and then modetest works.
But in the output of modetest -s the blue and red colors are reversed.
*Any* hints why modetest fails when my driver reports the correct formats?
For reference I will post source for the driver in a follow-up mail.
Sam
The quirk I implmented looks like this (preliminary patch):
>From ab0f213e50fbe1b053d624745306252b28e6ecdc Mon Sep 17 00:00:00 2001
From: Sam Ravnborg <sam at ravnborg.org>
Date: Sun, 21 Jul 2019 08:59:49 +0200
Subject: [PATCH 21/22] drm: add quirk_addfb_rgb_to_bgr
Used for drivers where the format supported is default BGR.
Then use this quirk to force drm_fb_helper to convert the
framebuffer from RGB => BGR.
Signed-off-by: Sam Ravnborg <sam at ravnborg.org>
---
drivers/gpu/drm/drm_fb_helper.c | 46 +++++++++++++++++++++++----------
drivers/gpu/drm/drm_fourcc.c | 14 ++++++++++
include/drm/drm_mode_config.h | 7 +++++
3 files changed, 53 insertions(+), 14 deletions(-)
diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c
index a7ba5b4902d6..adc1b1fcb153 100644
--- a/drivers/gpu/drm/drm_fb_helper.c
+++ b/drivers/gpu/drm/drm_fb_helper.c
@@ -1236,9 +1236,9 @@ static bool drm_fb_pixel_format_equal(const struct fb_var_screeninfo *var_1,
}
static void drm_fb_helper_fill_pixel_fmt(struct fb_var_screeninfo *var,
- u8 depth)
+ struct drm_framebuffer *fb)
{
- switch (depth) {
+ switch (fb->format->depth) {
case 8:
var->red.offset = 0;
var->green.offset = 0;
@@ -1260,18 +1260,30 @@ static void drm_fb_helper_fill_pixel_fmt(struct fb_var_screeninfo *var,
var->transp.length = 1;
break;
case 16:
- var->red.offset = 11;
- var->green.offset = 5;
- var->blue.offset = 0;
+ if (!fb->dev->mode_config.quirk_addfb_rgb_to_bgr) {
+ var->red.offset = 11;
+ var->green.offset = 5;
+ var->blue.offset = 0;
+ } else {
+ var->red.offset = 0;
+ var->green.offset = 5;
+ var->blue.offset = 11;
+ }
var->red.length = 5;
var->green.length = 6;
var->blue.length = 5;
var->transp.offset = 0;
break;
case 24:
- var->red.offset = 16;
- var->green.offset = 8;
- var->blue.offset = 0;
+ if (!fb->dev->mode_config.quirk_addfb_rgb_to_bgr) {
+ var->red.offset = 16;
+ var->green.offset = 8;
+ var->blue.offset = 0;
+ } else {
+ var->red.offset = 0;
+ var->green.offset = 8;
+ var->blue.offset = 16;
+ }
var->red.length = 8;
var->green.length = 8;
var->blue.length = 8;
@@ -1279,9 +1291,15 @@ static void drm_fb_helper_fill_pixel_fmt(struct fb_var_screeninfo *var,
var->transp.length = 0;
break;
case 32:
- var->red.offset = 16;
- var->green.offset = 8;
- var->blue.offset = 0;
+ if (!fb->dev->mode_config.quirk_addfb_rgb_to_bgr) {
+ var->red.offset = 16;
+ var->green.offset = 8;
+ var->blue.offset = 0;
+ } else {
+ var->red.offset = 0;
+ var->green.offset = 8;
+ var->blue.offset = 16;
+ }
var->red.length = 8;
var->green.length = 8;
var->blue.length = 8;
@@ -1342,7 +1360,7 @@ int drm_fb_helper_check_var(struct fb_var_screeninfo *var,
!var->blue.length && !var->transp.length &&
!var->red.msb_right && !var->green.msb_right &&
!var->blue.msb_right && !var->transp.msb_right) {
- drm_fb_helper_fill_pixel_fmt(var, fb->format->depth);
+ drm_fb_helper_fill_pixel_fmt(var, fb);
}
/*
@@ -1684,7 +1702,7 @@ static void drm_fb_helper_fill_var(struct fb_info *info,
info->var.yoffset = 0;
info->var.activate = FB_ACTIVATE_NOW;
- drm_fb_helper_fill_pixel_fmt(&info->var, fb->format->depth);
+ drm_fb_helper_fill_pixel_fmt(&info->var, fb);
info->var.xres = fb_width;
info->var.yres = fb_height;
@@ -2205,7 +2223,7 @@ int drm_fb_helper_generic_probe(struct drm_fb_helper *fb_helper,
sizes->surface_width, sizes->surface_height,
sizes->surface_bpp);
- format = drm_mode_legacy_fb_format(sizes->surface_bpp, sizes->surface_depth);
+ format = drm_driver_legacy_fb_format(fb_helper->dev, sizes->surface_bpp, sizes->surface_depth);
buffer = drm_client_framebuffer_create(client, sizes->surface_width,
sizes->surface_height, format);
if (IS_ERR(buffer))
diff --git a/drivers/gpu/drm/drm_fourcc.c b/drivers/gpu/drm/drm_fourcc.c
index c630064ccf41..972ea746c06d 100644
--- a/drivers/gpu/drm/drm_fourcc.c
+++ b/drivers/gpu/drm/drm_fourcc.c
@@ -126,6 +126,20 @@ uint32_t drm_driver_legacy_fb_format(struct drm_device *dev,
fmt == DRM_FORMAT_XRGB2101010)
fmt = DRM_FORMAT_XBGR2101010;
+ if (dev->mode_config.quirk_addfb_rgb_to_bgr) {
+ switch (fmt) {
+ case DRM_FORMAT_RGB565:
+ fmt = DRM_FORMAT_BGR565;
+ break;
+ case DRM_FORMAT_RGB888:
+ fmt = DRM_FORMAT_BGR888;
+ break;
+ case DRM_FORMAT_XRGB8888:
+ fmt = DRM_FORMAT_XBGR8888;
+ break;
+ }
+ }
+
return fmt;
}
EXPORT_SYMBOL(drm_driver_legacy_fb_format);
diff --git a/include/drm/drm_mode_config.h b/include/drm/drm_mode_config.h
index f57eea0481e0..58aa8c02232e 100644
--- a/include/drm/drm_mode_config.h
+++ b/include/drm/drm_mode_config.h
@@ -881,6 +881,13 @@ struct drm_mode_config {
*/
bool quirk_addfb_prefer_host_byte_order;
+ /**
+ * @quirk_addfb_rgb_to_bgr:
+ *
+ * TODO
+ */
+ bool quirk_addfb_rgb_to_bgr;
+
/**
* @async_page_flip: Does this device support async flips on the primary
* plane?
--
2.20.1
More information about the dri-devel
mailing list