All of lore.kernel.org
 help / color / mirror / Atom feed
* My penguin has blue feets (aka: RGB versus BGR troubles)
@ 2019-07-26 20:36 Sam Ravnborg
  2019-07-26 20:44 ` [RFC PATCH] drm: add Atmel LCDC display controller support Sam Ravnborg
                   ` (2 more replies)
  0 siblings, 3 replies; 7+ messages in thread
From: Sam Ravnborg @ 2019-07-26 20:36 UTC (permalink / raw)
  To: dri-devel

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@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@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@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

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

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

* [RFC PATCH] drm: add Atmel LCDC display controller support
  2019-07-26 20:36 My penguin has blue feets (aka: RGB versus BGR troubles) Sam Ravnborg
@ 2019-07-26 20:44 ` Sam Ravnborg
  2019-07-26 21:35 ` My penguin has blue feets (aka: RGB versus BGR troubles) Ilia Mirkin
  2019-07-27  9:56 ` Sam Ravnborg
  2 siblings, 0 replies; 7+ messages in thread
From: Sam Ravnborg @ 2019-07-26 20:44 UTC (permalink / raw)
  To: dri-devel

This is the current state of the driver for the at91sam* LCDC IP.
Notice that it needs some other companion drivers and I posted this
code-drop only to support the request for help on the BGR versus RGB
issue.
That said - any review feedback will be appreciated!

	Sam

From c4c2274313dbb23f38626920834819735f70d899 Mon Sep 17 00:00:00 2001
From: Sam Ravnborg <sam@ravnborg.org>
Date: Thu, 27 Dec 2018 02:23:31 +0100
Subject: [PATCH 22/22] drm: add Atmel LCDC display controller support

This is a DRM based driver for the Atmel LCDC IP.
There exist today a framebuffer based driver and
this is a re-implmentation of the same on top of DRM.

The rewrite was based on the original fbdev driver
but the driver has also seen inspiration from
the atmel-hlcdc_dc driver and others.

The driver is not a full replacement:
- STN displays are not supported
        STN displays are not considered relevant for
        current kernels, and there is no plan to add STN support

The atmel-lcdc driver is divided into a few files:
atmel_lcdc.h            - definitions shared by the driver implmentation
../linux/atmel-lcdc.h   - definitions shared with the pwm subdriver
atmel_lcdc_drv.c        - all the driver details such as DT support etc.
atmel_lcdc_pipe.c       - the display pipeline, including the outputs

v3:
- reworked most of the driver after feedback and more testing

Signed-off-by: Sam Ravnborg <sam@ravnborg.org>
Cc: Nicolas Ferre <nicolas.ferre@atmel.com>
Cc: Boris Brezillon <boris.brezillon@free-electrons.com>
Cc: Alexandre Belloni <alexandre.belloni@bootlin.com>
---
 drivers/gpu/drm/Makefile                |   1 +
 drivers/gpu/drm/atmel/Kconfig           |  12 +
 drivers/gpu/drm/atmel/Makefile          |   3 +
 drivers/gpu/drm/atmel/atmel_lcdc.h      |  81 +++
 drivers/gpu/drm/atmel/atmel_lcdc_drv.c  | 408 ++++++++++++++
 drivers/gpu/drm/atmel/atmel_lcdc_pipe.c | 675 ++++++++++++++++++++++++
 6 files changed, 1180 insertions(+)
 create mode 100644 drivers/gpu/drm/atmel/atmel_lcdc.h
 create mode 100644 drivers/gpu/drm/atmel/atmel_lcdc_drv.c
 create mode 100644 drivers/gpu/drm/atmel/atmel_lcdc_pipe.c

diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile
index d7f5328918ab..386fc6166de1 100644
--- a/drivers/gpu/drm/Makefile
+++ b/drivers/gpu/drm/Makefile
@@ -87,6 +87,7 @@ obj-$(CONFIG_DRM_UDL) += udl/
 obj-$(CONFIG_DRM_AST) += ast/
 obj-$(CONFIG_DRM_ARMADA) += armada/
 obj-$(CONFIG_DRM_ATMEL_HLCDC)	+= atmel/
+obj-$(CONFIG_DRM_ATMEL_LCDC)	+= atmel/
 obj-y			+= rcar-du/
 obj-$(CONFIG_DRM_SHMOBILE) +=shmobile/
 obj-y			+= omapdrm/
diff --git a/drivers/gpu/drm/atmel/Kconfig b/drivers/gpu/drm/atmel/Kconfig
index 5f67f001553b..1405ae2802a3 100644
--- a/drivers/gpu/drm/atmel/Kconfig
+++ b/drivers/gpu/drm/atmel/Kconfig
@@ -9,3 +9,15 @@ config DRM_ATMEL_HLCDC
 	help
 	  Choose this option if you have an ATMEL SoC with an HLCDC display
 	  controller (i.e. at91sam9n12, at91sam9x5 family or sama5d3 family).
+
+config DRM_ATMEL_LCDC
+	tristate "DRM Support for ATMEL LCDC Display Controller"
+	depends on DRM && OF && COMMON_CLK && MFD_ATMEL_LCDC
+	depends on ARM || COMPILE_TEST
+	select DRM_GEM_CMA_HELPER
+	select DRM_KMS_HELPER
+	select DRM_KMS_CMA_HELPER
+	select DRM_PANEL
+	help
+	  Choose this option if you have an ATMEL SoC with an LCDC display
+	  controller (found on many SoC's in the at91sam9 family).
diff --git a/drivers/gpu/drm/atmel/Makefile b/drivers/gpu/drm/atmel/Makefile
index 49dc89f36b73..9d95543f39a3 100644
--- a/drivers/gpu/drm/atmel/Makefile
+++ b/drivers/gpu/drm/atmel/Makefile
@@ -5,3 +5,6 @@ atmel-hlcdc-dc-y := atmel_hlcdc_crtc.o \
 		atmel_hlcdc_plane.o
 
 obj-$(CONFIG_DRM_ATMEL_HLCDC)	+= atmel-hlcdc-dc.o
+
+atmel-lcdc-y := atmel_lcdc_drv.o atmel_lcdc_pipe.o
+obj-$(CONFIG_DRM_ATMEL_LCDC)	+= atmel-lcdc.o
diff --git a/drivers/gpu/drm/atmel/atmel_lcdc.h b/drivers/gpu/drm/atmel/atmel_lcdc.h
new file mode 100644
index 000000000000..e1b3290c3c81
--- /dev/null
+++ b/drivers/gpu/drm/atmel/atmel_lcdc.h
@@ -0,0 +1,81 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) 2018 Sam Ravnborg
+ *
+ * Author: Sam Ravnborg <sam@ravnborg.org>
+ */
+
+#ifndef __DRM_ATMEL_LCDC_H
+#define __DRM_ATMEL_LCDC_H
+
+#include <linux/workqueue.h>
+
+#include <drm/drm_connector.h>
+#include <drm/drm_simple_kms_helper.h>
+
+#include <linux/mfd/atmel-lcdc.h>
+
+struct clk;
+struct regmap;
+struct regulator;
+
+#define ATMEL_LCDC_DMA_BURST_LEN	8	/* words */
+
+/*
+ * struct atmel_lcdc_desc - CPU specific configuration properties
+ */
+struct atmel_lcdc_desc {
+	/* Default is 1, maybe we need to change this later */
+	int guard_time;
+
+	/* 512 or 2018 */
+	int fifo_size;
+
+	/* Maximum resolution */
+	int max_width;
+	int max_height;
+
+	/* false if "Pixel_clock = system_clock / (CLKVAL + 1) x 2" */
+	/* true if "Pixel_clock = system_clock / (CLKVAL + 1)" */
+	bool have_alt_pixclock;
+};
+
+/*
+ * Private data for the lcdc driver
+ */
+struct lcdc {
+	struct drm_device drm;
+	struct device *dev;
+
+	const struct atmel_lcdc_desc *desc;
+
+	struct atmel_mfd_lcdc *mfd;
+
+	bool wiring_reversed;	/* Select between BGR or RGB */
+
+	struct drm_simple_display_pipe pipe;
+	struct work_struct reset_lcdc_work;
+
+	struct drm_panel *panel;
+	struct drm_connector *connector;
+
+	struct mutex enable_lock;
+	bool enabled;
+
+	/* Saved state during suspend */
+	struct {
+		u32 imr;
+		/* true if suspended */
+		bool state;
+	} suspend;
+};
+
+/* atmel_lcdc_pipe.c */
+int atmel_lcdc_vblank_init(struct lcdc *lcdc);
+void atmel_lcdc_vblank(struct lcdc *ldcd);
+
+void atmel_lcdc_start(struct lcdc *lcdc);
+void atmel_lcdc_stop(struct lcdc *lcdc);
+int atmel_lcdc_modeset_init(struct lcdc *lcdc);
+
+#endif /* __DRM_ATMEL_LCDC_H */
diff --git a/drivers/gpu/drm/atmel/atmel_lcdc_drv.c b/drivers/gpu/drm/atmel/atmel_lcdc_drv.c
new file mode 100644
index 000000000000..2c94761ea648
--- /dev/null
+++ b/drivers/gpu/drm/atmel/atmel_lcdc_drv.c
@@ -0,0 +1,408 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2018 Sam Ravnborg
+ *
+ * The driver is based on atmel_lcdfb which is:
+ * Copyright (C) 2007 Atmel Corporation
+ *
+ */
+
+/**
+ * DOC: Atmel LCD Controller Display Controller.
+ *
+ * The Atmel LCD Controller supports in the following configuration:
+ * - TFT only, 24 bits/pixel
+ * - Resolution up to 2048x2048
+ * - Single plane, crtc, one fixed output
+ *
+ * Features not (yet) ported from atmel_lcdfb:
+ * - set color / palette handling
+ */
+
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/consumer.h>
+
+#include <drm/drm_atomic_helper.h>
+#include <drm/drm_crtc_helper.h>
+#include <drm/drm_drv.h>
+#include <drm/drm_fb_helper.h>
+#include <drm/drm_gem_cma_helper.h>
+#include <drm/drm_irq.h>
+#include <drm/drm_print.h>
+#include <drm/drm_probe_helper.h>
+
+#include "atmel_lcdc.h"
+
+/* Configuration of individual CPU's */
+static const struct atmel_lcdc_desc lcdc_at91sam9261 = {
+	.guard_time = 1,
+	.fifo_size = 512,
+	.max_width = 2048,
+	.max_height = 2048,
+	.have_alt_pixclock = false,
+};
+
+static const struct atmel_lcdc_desc lcdc_at91sam9263 = {
+	.guard_time = 1,
+	.fifo_size = 2048,
+	.max_width = 2048,
+	.max_height = 2048,
+	.have_alt_pixclock = false,
+};
+
+static const struct atmel_lcdc_desc lcdc_at91sam9g10 = {
+	.guard_time = 1,
+	.fifo_size = 512,
+	.max_width = 2048,
+	.max_height = 2048,
+	.have_alt_pixclock = false,
+};
+
+static const struct atmel_lcdc_desc lcdc_at91sam9g45 = {
+	.guard_time = 1,
+	.fifo_size = 512,
+	.max_width = 2048,
+	.max_height = 2048,
+	.have_alt_pixclock = true,
+};
+
+static const struct atmel_lcdc_desc lcdc_at91sam9g46 = {
+	.guard_time = 1,
+	.fifo_size = 512,
+	.max_width = 2048,
+	.max_height = 2048,
+	.have_alt_pixclock = true,
+};
+
+static const struct atmel_lcdc_desc lcdc_at91sam9m10 = {
+	.guard_time = 1,
+	.fifo_size = 512,
+	.max_width = 2048,
+	.max_height = 2048,
+	.have_alt_pixclock = true,
+};
+
+static const struct atmel_lcdc_desc lcdc_at91sam9m11 = {
+	.guard_time = 1,
+	.fifo_size = 512,
+	.max_width = 2048,
+	.max_height = 2048,
+	.have_alt_pixclock = true,
+};
+
+static const struct atmel_lcdc_desc lcdc_at91sam9rl = {
+	.guard_time = 1,
+	.fifo_size = 512,
+	.max_width = 2048,
+	.max_height = 2048,
+	.have_alt_pixclock = false,
+};
+
+static const struct of_device_id lcdc_of_match[] = {
+	{ .compatible = "atmel,at91sam9261-lcdc",   .data = &lcdc_at91sam9261 },
+	{ .compatible = "atmel,at91sam9263-lcdc",   .data = &lcdc_at91sam9263 },
+	{ .compatible = "atmel,at91sam9g10-lcdc",   .data = &lcdc_at91sam9g10 },
+	{ .compatible = "atmel,at91sam9g45-lcdc",   .data = &lcdc_at91sam9g45 },
+	{ .compatible = "atmel,at91sam9g45es-lcdc", .data = &lcdc_at91sam9g45 },
+	{ .compatible = "atmel,at91sam9g46-lcdc",   .data = &lcdc_at91sam9g46 },
+	{ .compatible = "atmel,at91sam9m10-lcdc",   .data = &lcdc_at91sam9m10 },
+	{ .compatible = "atmel,at91sam9m11-lcdc",   .data = &lcdc_at91sam9m11 },
+	{ .compatible = "atmel,at91sam9rl-lcdc",    .data = &lcdc_at91sam9rl },
+	{ /* sentinel */ },
+};
+MODULE_DEVICE_TABLE(of, lcdc_of_match);
+
+
+/* scheduled worker to reset LCD */
+static void reset_lcdc_work(struct work_struct *work)
+{
+	struct lcdc *lcdc;
+
+	lcdc = container_of(work, struct lcdc, reset_lcdc_work);
+
+	mutex_lock(&lcdc->enable_lock);
+
+	/* Check that we are enabled and not suspended */
+	if (lcdc->enabled && !lcdc->suspend.state) {
+		atmel_lcdc_stop(lcdc);
+		atmel_lcdc_start(lcdc);
+	}
+	mutex_unlock(&lcdc->enable_lock);
+}
+
+static irqreturn_t lcdc_irq_handler(int irq, void *arg)
+{
+	struct drm_device *drm;
+	unsigned int status;
+	struct lcdc *lcdc;
+	unsigned int imr;
+	unsigned int isr;
+
+	drm = arg;
+	lcdc = drm->dev_private;
+
+	regmap_read(lcdc->mfd->regmap, ATMEL_LCDC_IMR, &imr);
+	regmap_read(lcdc->mfd->regmap, ATMEL_LCDC_ISR, &isr);
+	status = imr & isr;
+	if (!status)
+		return IRQ_NONE;
+
+	if (status & ATMEL_LCDC_LSTLNI)
+		atmel_lcdc_vblank(lcdc);
+
+	if (status & ATMEL_LCDC_UFLWI) {
+		DRM_DEV_INFO(lcdc->dev, "FIFO underflow %#x\n", status);
+		/* reset DMA and FIFO to avoid screen shifting */
+		schedule_work(&lcdc->reset_lcdc_work);
+	}
+
+	if (status & ATMEL_LCDC_OWRI)
+		DRM_DEV_INFO(lcdc->dev, "FIFO overwrite interrupt\n");
+
+	if (status & ATMEL_LCDC_MERI)
+		DRM_DEV_INFO(lcdc->dev, "DMA memory error\n");
+
+	/* Clear all reported (from ISR) interrupts */
+	regmap_write(lcdc->mfd->regmap, ATMEL_LCDC_ICR, isr);
+
+	return IRQ_HANDLED;
+}
+
+static int lcdc_irq_postinstall(struct drm_device *dev)
+{
+	struct lcdc *lcdc;
+	unsigned int ier;
+
+	lcdc = dev->dev_private;
+
+	ier = 0;
+	/* FIFO underflow interrupt enable */
+	ier |= ATMEL_LCDC_UFLWI;
+	/* FIFO overwrite interrupt enable */
+	ier |= ATMEL_LCDC_OWRI;
+	/* DMA memory error interrupt enable */
+	ier |= ATMEL_LCDC_MERI;
+	regmap_write(lcdc->mfd->regmap, ATMEL_LCDC_IER, ier);
+
+	return 0;
+}
+
+static void lcdc_irq_uninstall(struct drm_device *dev)
+{
+	struct lcdc *lcdc;
+	unsigned int isr;
+
+	lcdc = dev->dev_private;
+
+	/* disable all interrupts */
+	regmap_write(lcdc->mfd->regmap, ATMEL_LCDC_IDR, ~0);
+	regmap_write(lcdc->mfd->regmap, ATMEL_LCDC_ICR, ~0);
+
+	/* Clear any pending interrupts */
+	regmap_read(lcdc->mfd->regmap, ATMEL_LCDC_ISR, &isr);
+}
+
+static void lcdc_release(struct drm_device *drm)
+{
+	struct lcdc *lcdc;
+
+	lcdc = drm->dev_private;
+
+	flush_work(&lcdc->reset_lcdc_work);
+	drm_kms_helper_poll_fini(drm);
+
+	drm_mode_config_cleanup(drm);
+
+	pm_runtime_get_sync(drm->dev);
+	drm_irq_uninstall(drm);
+	pm_runtime_put_sync(drm->dev);
+	cancel_work_sync(&lcdc->reset_lcdc_work);
+	pm_runtime_disable(drm->dev);
+
+	drm_dev_fini(drm);
+	kfree(lcdc);
+}
+
+DEFINE_DRM_GEM_CMA_FOPS(lcdc_drm_fops);
+
+static struct drm_driver lcdc_drm_driver = {
+	.driver_features = DRIVER_GEM | DRIVER_MODESET | DRIVER_ATOMIC,
+	.name = ATMEL_LCDC_DRM_DRV_NAME,
+	.desc = "Atmel LCD Display Controller DRM",
+	.date = "20180808",
+	.major = 1,
+	.minor = 0,
+	.patchlevel = 0,
+
+	.irq_handler = lcdc_irq_handler,
+	.irq_preinstall = lcdc_irq_uninstall,
+	.irq_postinstall = lcdc_irq_postinstall,
+	.irq_uninstall = lcdc_irq_uninstall,
+
+	.fops = &lcdc_drm_fops,
+	.release = lcdc_release,
+
+	DRM_GEM_CMA_VMAP_DRIVER_OPS,
+};
+
+static int lcdc_probe(struct platform_device *pdev)
+{
+	const struct of_device_id *match;
+	struct atmel_mfd_lcdc *mfd;
+	struct drm_device *drm;
+	struct device *dev;
+	struct lcdc *lcdc;
+	int ret;
+
+	dev = pdev->dev.parent;
+	mfd = dev_get_drvdata(dev);
+	/* the MFD device driver prepares clocks etc. */
+	if (!mfd)
+		return -EPROBE_DEFER;
+
+
+	lcdc = kzalloc(sizeof(*lcdc), GFP_KERNEL);
+	if (!lcdc)
+		return -ENOMEM;
+
+	drm = &lcdc->drm;
+	ret = devm_drm_dev_init(dev, drm, &lcdc_drm_driver);
+	if (ret) {
+		kfree(lcdc);
+		return ret;
+	}
+
+	match = of_match_node(lcdc_of_match, dev->of_node);
+	if (!match || !match->data) {
+		DRM_DEV_ERROR(dev, "failed to find compatible match\n");
+		return -EINVAL;
+	}
+
+	lcdc->desc = match->data;
+
+	drm->dev_private = lcdc;
+	lcdc->dev = dev;
+	lcdc->mfd = mfd;
+	platform_set_drvdata(pdev, drm);
+
+	mutex_init(&lcdc->enable_lock);
+
+	/* reset of lcdc might sleep and require a preemptible task context */
+	INIT_WORK(&lcdc->reset_lcdc_work, reset_lcdc_work);
+
+	pm_runtime_enable(dev);
+
+	ret = atmel_lcdc_vblank_init(lcdc);
+	if (ret)
+		goto err_pm_runtime_disable;
+
+	ret = atmel_lcdc_modeset_init(lcdc);
+	if (ret)
+		goto err_pm_runtime_disable;
+
+	pm_runtime_get_sync(dev);
+
+	ret = drm_irq_install(drm, mfd->irq);
+	pm_runtime_put_sync(dev);
+	if (ret < 0) {
+		DRM_DEV_ERROR(dev, "failed to install IRQ: %d\n", ret);
+		goto err_pm_runtime_disable;
+	}
+
+	drm_kms_helper_poll_init(drm);
+
+	ret = drm_dev_register(drm, 0);
+	if (ret) {
+		DRM_DEV_ERROR(dev, "failed to register drm: %d\n", ret);
+		goto err_pm_runtime_disable;
+	}
+
+	ret = drm_fbdev_generic_setup(drm, 24);
+	if (ret < 0)
+		DRM_DEV_ERROR(dev, "failed to initialize fbdev: %d\n", ret);
+
+	return 0;
+
+err_pm_runtime_disable:
+	cancel_work_sync(&lcdc->reset_lcdc_work);
+	pm_runtime_disable(dev);
+
+	return ret;
+}
+
+static int lcdc_remove(struct platform_device *pdev)
+{
+	struct drm_device *drm;
+
+	drm = platform_get_drvdata(pdev);
+	drm_dev_unregister(drm);
+	drm_atomic_helper_shutdown(drm);
+
+	return 0;
+}
+
+static void lcdc_shutdown(struct platform_device *pdev)
+{
+	drm_atomic_helper_shutdown(platform_get_drvdata(pdev));
+}
+
+static int __maybe_unused lcdc_drm_suspend(struct device *dev)
+{
+	struct drm_device *drm;
+	struct lcdc *lcdc;
+	int ret;
+
+	drm = dev_get_drvdata(dev);
+	lcdc = drm->dev_private;
+
+	ret = drm_mode_config_helper_suspend(drm);
+	if (ret < 0)
+		return ret;
+
+	lcdc->suspend.state = true;
+
+	/* Disable interrupts */
+	regmap_read(lcdc->mfd->regmap, ATMEL_LCDC_IMR, &lcdc->suspend.imr);
+	regmap_write(lcdc->mfd->regmap, ATMEL_LCDC_IDR, lcdc->suspend.imr);
+
+	return 0;
+}
+
+static int __maybe_unused lcdc_drm_resume(struct device *dev)
+{
+	struct drm_device *drm;
+	struct lcdc *lcdc;
+
+	drm = dev_get_drvdata(dev);
+	lcdc = drm->dev_private;
+
+	/* Enable interrupts */
+	regmap_write(lcdc->mfd->regmap, ATMEL_LCDC_IER, lcdc->suspend.imr);
+
+	lcdc->suspend.state = false;
+	return drm_mode_config_helper_resume(drm);
+}
+
+static SIMPLE_DEV_PM_OPS(lcdc_pm_ops,
+		lcdc_drm_suspend, lcdc_drm_resume);
+
+static struct platform_driver lcdc_driver = {
+	.driver = {
+		.name	= ATMEL_LCDC_DRM_DRV_NAME,
+		.of_match_table = lcdc_of_match,
+		.pm = &lcdc_pm_ops,
+	},
+	.probe = lcdc_probe,
+	.remove = lcdc_remove,
+	.shutdown = lcdc_shutdown,
+};
+
+module_platform_driver(lcdc_driver);
+
+MODULE_AUTHOR("Sam Ravnborg <sam@ravnborg.org>");
+MODULE_DESCRIPTION("Atmel LCDC Display Controller DRM Driver");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:atmel-lcdc");
diff --git a/drivers/gpu/drm/atmel/atmel_lcdc_pipe.c b/drivers/gpu/drm/atmel/atmel_lcdc_pipe.c
new file mode 100644
index 000000000000..c40175cd1e1f
--- /dev/null
+++ b/drivers/gpu/drm/atmel/atmel_lcdc_pipe.c
@@ -0,0 +1,675 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2018 Sam Ravnborg
+ *
+ */
+
+#include <linux/regulator/consumer.h>
+#include <linux/pm_runtime.h>
+
+#include <drm/drm_atomic_helper.h>
+#include <drm/drm_device.h>
+#include <drm/drm_fb_cma_helper.h>
+#include <drm/drm_fourcc.h>
+#include <drm/drm_gem_framebuffer_helper.h>
+#include <drm/drm_of.h>
+#include <drm/drm_panel.h>
+#include <drm/drm_print.h>
+#include <drm/drm_vblank.h>
+
+#include "atmel_lcdc.h"
+
+/**
+ * DOC: Display pipe for Atmel LCDC
+ *
+ * The LCDC display pipe utilize the drm_simple_kms_helper infrastructure
+ * to provide the necessary DRM functionality.
+ *
+ * The LCDC IP core is always used in setups with only a single
+ * output with direct connection to a panel.
+ */
+
+/*
+ * Atmel LCD controller 24 bit formats.
+ * Formats for reversed wiring included.
+ */
+static const u32 bgr_formats[] = {
+	DRM_FORMAT_XBGR8888,
+	DRM_FORMAT_BGR888,
+	DRM_FORMAT_BGR565,
+};
+
+static const u32 rgb_formats[] = {
+	DRM_FORMAT_XRGB8888,
+	DRM_FORMAT_RGB888,
+	DRM_FORMAT_RGB565,
+};
+
+static const u32* get_formats(bool reversed, size_t *nformats)
+{
+	if (reversed) {
+		/* B and R are swapped in HW */
+		*nformats = ARRAY_SIZE(rgb_formats);
+		return rgb_formats;
+	} else {
+		/* Normal wiring, use BGR formats */
+		*nformats = ARRAY_SIZE(bgr_formats);
+		return bgr_formats;
+	}
+}
+
+static void set_lcdcon2(struct lcdc *lcdc,
+			const struct drm_format_info *format)
+{
+	struct drm_format_name_buf format_buf;
+	struct drm_display_mode *dmode;
+	unsigned int lcdcon2;
+	u32 bus_flags;
+
+	dmode = &lcdc->pipe.crtc.state->adjusted_mode;
+
+	/* Control register 2 */
+	/* Only TFT supported (Controller supports STN too) */
+	lcdcon2 = ATMEL_LCDC_DISTYPE_TFT;
+
+	/* scan mode */
+	if (dmode->flags & DRM_MODE_FLAG_DBLSCAN)
+		lcdcon2 |= ATMEL_LCDC_SCANMOD_DUAL;
+	else
+		lcdcon2 |= ATMEL_LCDC_SCANMOD_SINGLE;
+
+	/* Interface width 4 bits (STN only) */
+	lcdcon2 |= ATMEL_LCDC_IFWIDTH_4;
+
+	switch (format->format) {
+	case DRM_FORMAT_XBGR8888:
+	case DRM_FORMAT_XRGB8888:
+		/* 32 bit layout */
+		lcdcon2 |= ATMEL_LCDC_PIXELSIZE_24;
+		break;
+	case DRM_FORMAT_BGR888:
+	case DRM_FORMAT_RGB888:
+		/* 24 bit layout */
+		lcdcon2 |= ATMEL_LCDC_PIXELSIZE_24_PACKED;
+		break;
+	case DRM_FORMAT_BGR565:
+	case DRM_FORMAT_RGB565:
+		/* 16 bit layout */
+		lcdcon2 |= ATMEL_LCDC_PIXELSIZE_16;
+		break;
+	default:
+		lcdcon2 |= ATMEL_LCDC_PIXELSIZE_24;
+		DRM_DEV_INFO(lcdc->dev, "Unsupported format %s\n",
+			     drm_get_format_name(format->format, &format_buf));
+	}
+
+	/* LCDD Polarity normal */
+	lcdcon2 |= ATMEL_LCDC_INVVD_NORMAL;
+
+	/* vsync polarity - TODO: Check ! again */
+	if (!(dmode->flags & DRM_MODE_FLAG_PVSYNC))
+		lcdcon2 |= ATMEL_LCDC_INVFRAME_INVERTED;
+	else
+		lcdcon2 |= ATMEL_LCDC_INVFRAME_NORMAL;
+
+	/* hsync polarity - TODO: Check ! again*/
+	if (!(dmode->flags & DRM_MODE_FLAG_PHSYNC))
+		lcdcon2 |= ATMEL_LCDC_INVLINE_INVERTED;
+	else
+		lcdcon2 |= ATMEL_LCDC_INVLINE_NORMAL;
+
+	bus_flags = lcdc->connector->display_info.bus_flags;
+
+	/* dot clock (pix clock) polarity */
+	if (bus_flags & DRM_BUS_FLAG_PIXDATA_NEGEDGE)
+		lcdcon2 |= ATMEL_LCDC_INVCLK_INVERTED;
+	else
+		lcdcon2 |= ATMEL_LCDC_INVCLK_NORMAL;
+
+	/* Date Enable polarity */
+	if (bus_flags & DRM_BUS_FLAG_DE_LOW)
+		lcdcon2 |= ATMEL_LCDC_INVDVAL_INVERTED;
+	else
+		lcdcon2 |= ATMEL_LCDC_INVDVAL_NORMAL;
+
+	/* Clock is always active */
+	lcdcon2 |= ATMEL_LCDC_CLKMOD_ALWAYSACTIVE;
+
+	/* Memory layout */
+	if (format->format & DRM_FORMAT_BIG_ENDIAN)
+		lcdcon2 |= ATMEL_LCDC_MEMOR_BIG;
+	else
+		lcdcon2 |= ATMEL_LCDC_MEMOR_LITTLE;
+
+	regmap_write(lcdc->mfd->regmap, ATMEL_LCDC_LCDCON2, lcdcon2);
+}
+
+/* Check that the configuation is supported */
+static int lcdc_pipe_check(struct drm_simple_display_pipe *pipe,
+			   struct drm_plane_state *pstate,
+			   struct drm_crtc_state *cstate)
+{
+	const struct drm_display_mode *dmode;
+	struct drm_framebuffer *fb;
+	struct lcdc *lcdc;
+	long clk_rate;
+
+	lcdc = pipe->crtc.dev->dev_private;
+	dmode = &cstate->mode;
+	fb = pstate->fb;
+
+	if (!fb)
+		return 0;
+
+	/* Check if we can support the requested clock rate */
+	clk_rate = dmode->clock * 1000;
+	if (clk_rate > clk_get_rate(lcdc->mfd->lcdc_clk))
+		return -EINVAL;
+
+	/* Only one plane supported */
+	if (fb->format->num_planes != 1)
+		return -EINVAL;
+
+	return 0;
+}
+
+/*
+ * DMA config. Set frame size and burst length
+ * Frame_size equals size of visible area * bits / 32
+ * (size in 32 bit words)
+ */
+static void lcdc_pipe_enable_dma(struct lcdc *lcdc)
+{
+	const struct drm_format_info *format_info;
+	struct drm_plane_state *plane_state;
+	unsigned int width, height;
+	unsigned int frame_size;
+	unsigned int dmafrmcfg;
+
+	plane_state = lcdc->pipe.plane.state;
+	format_info = drm_format_info(plane_state->fb->format->format);
+	width = plane_state->crtc->state->adjusted_mode.hdisplay;
+	height = plane_state->crtc->state->adjusted_mode.vdisplay;
+
+	frame_size = width * height * format_info->depth;
+	dmafrmcfg = frame_size / 32;
+
+	dmafrmcfg |= (ATMEL_LCDC_DMA_BURST_LEN - 1) << ATMEL_LCDC_BLENGTH_OFFSET;
+
+	regmap_write(lcdc->mfd->regmap, ATMEL_LCDC_DMAFRMCFG, dmafrmcfg);
+}
+
+static void set_vertical_timing(struct lcdc *lcdc,
+				struct drm_display_mode *dmode)
+{
+	unsigned int tim1;
+	unsigned int vfp;
+	unsigned int vbp;
+	unsigned int vpw;
+	unsigned int vhdly;
+
+	/* VFP: Vertical Front Porch */
+	vfp = dmode->vsync_start - dmode->vdisplay;
+
+	/* VBP: Vertical Back Porch */
+	vbp = dmode->vtotal - dmode->vsync_end;
+
+	/* VPW: Vertical Synchronization pulse width */
+	vpw = dmode->vsync_end - dmode->vsync_start - 1;
+
+	/* VHDLY: Vertical to horizontal delay */
+	vhdly = 0;
+
+	tim1 = vfp << ATMEL_LCDC_VFP_OFFSET |
+	       vbp << ATMEL_LCDC_VBP_OFFSET |
+	       vpw << ATMEL_LCDC_VPW_OFFSET |
+	       vhdly << ATMEL_LCDC_VHDLY_OFFSET;
+
+	DRM_DEV_DEBUG(lcdc->dev, " TIM1 = %08x\n", tim1);
+	regmap_write(lcdc->mfd->regmap, ATMEL_LCDC_TIM1, tim1);
+}
+
+static void set_horizontal_timing(struct lcdc *lcdc,
+				  struct drm_display_mode *dmode)
+{
+	unsigned int tim2;
+	unsigned int hbp;
+	unsigned int hpw;
+	unsigned int hfp;
+
+	/* HBP: Horizontal Back Porch */
+	hbp = dmode->htotal - dmode->hsync_end - 1;
+
+	/* HPW: Horizontal synchronization pulse width */
+	hpw = dmode->hsync_end - dmode->hsync_start - 1;
+
+	/* HFP: Horizontal Front Porch */
+	hfp = dmode->hsync_start - dmode->hdisplay - 2;
+
+	tim2 = hbp << ATMEL_LCDC_HBP_OFFSET |
+	       hpw << ATMEL_LCDC_HPW_OFFSET |
+	       hfp << ATMEL_LCDC_HFP_OFFSET;
+
+	DRM_DEV_DEBUG(lcdc->dev, " TIM2 = %08x\n", tim2);
+	regmap_write(lcdc->mfd->regmap, ATMEL_LCDC_TIM2, tim2);
+}
+
+static void lcdc_pipe_enable_timing(struct lcdc *lcdc)
+{
+	struct drm_display_mode *dmode;
+	unsigned int value;
+
+	dmode = &lcdc->pipe.crtc.state->adjusted_mode;
+
+	/* Vertical & horizontal timing */
+	set_vertical_timing(lcdc, dmode);
+	set_horizontal_timing(lcdc, dmode);
+
+	/* Display size */
+	value = (dmode->crtc_hdisplay - 1) << ATMEL_LCDC_HOZVAL_OFFSET;
+	value |= dmode->crtc_vdisplay - 1;
+	DRM_DEV_DEBUG(lcdc->dev, " LCDFRMCFG = %08x\n", value);
+	regmap_write(lcdc->mfd->regmap, ATMEL_LCDC_LCDFRMCFG, value);
+
+	/* FIFO Threshold: Use formula from data sheet */
+	value = lcdc->desc->fifo_size - (2 * ATMEL_LCDC_DMA_BURST_LEN + 3);
+	DRM_DEV_DEBUG(lcdc->dev, " FIFO = %08x\n", value);
+	regmap_write(lcdc->mfd->regmap, ATMEL_LCDC_FIFO, value);
+
+	/*
+	 * Toggle LCD_MODE every frame
+	 * Note: register not documented, this is from atmel_lcdfb
+	 */
+	regmap_write(lcdc->mfd->regmap, ATMEL_LCDC_MVAL, 0);
+}
+
+static void lcdc_pipe_enable_ctrl(struct lcdc *lcdc)
+{
+	const struct drm_format_info *format;
+	struct drm_display_mode *dmode;
+	unsigned long clk_value_khz;
+	unsigned int pix_factor;
+	unsigned int lcdcon1;
+
+	format = lcdc->pipe.crtc.primary->state->fb->format;
+	dmode = &lcdc->pipe.crtc.state->adjusted_mode;
+
+	/* LCDC Control register 1 */
+	/* Set pixel clock */
+	if (lcdc->desc->have_alt_pixclock)
+		pix_factor = 1;
+	else
+		pix_factor = 2;
+
+	clk_value_khz = clk_get_rate(lcdc->mfd->lcdc_clk) / 1000;
+	lcdcon1 = DIV_ROUND_UP(clk_value_khz, dmode->clock);
+
+	if (lcdcon1 < pix_factor) {
+		DRM_DEV_INFO(lcdc->dev, "Bypassing pixel clock divider\n");
+		regmap_write(lcdc->mfd->regmap,
+			     ATMEL_LCDC_LCDCON1, ATMEL_LCDC_BYPASS);
+	} else {
+
+		lcdcon1 = (lcdcon1 / pix_factor) - 1;
+		DRM_DEV_DEBUG(lcdc->dev, "CLKVAL = 0x%08x\n", lcdcon1);
+		regmap_write(lcdc->mfd->regmap, ATMEL_LCDC_LCDCON1,
+			     lcdcon1 << ATMEL_LCDC_CLKVAL_OFFSET);
+		dmode->clock = clk_value_khz / (pix_factor * (lcdcon1 + 1));
+		DRM_DEV_DEBUG(lcdc->dev, "updated pixclk:  %u KHz\n",
+					dmode->clock);
+	}
+
+	/* LCDC Control register 2 */
+	set_lcdcon2(lcdc, format);
+}
+
+static void lcdc_pipe_enable(struct drm_simple_display_pipe *pipe,
+			     struct drm_crtc_state *cstate,
+			     struct drm_plane_state *plane_state)
+{
+	struct drm_device *drm;
+	struct drm_crtc *crtc;
+	struct lcdc *lcdc;
+
+	crtc = &pipe->crtc;
+	drm = crtc->dev;
+	lcdc = drm->dev_private;
+
+	mutex_lock(&lcdc->enable_lock);
+	pm_runtime_get_sync(drm->dev);
+	pm_runtime_forbid(drm->dev);
+
+	lcdc_pipe_enable_timing(lcdc);
+	lcdc_pipe_enable_dma(lcdc);
+	lcdc_pipe_enable_ctrl(lcdc);
+	atmel_lcdc_start(lcdc);
+	drm_crtc_vblank_on(&lcdc->pipe.crtc);
+
+	pm_runtime_put_sync(drm->dev);
+
+	lcdc->enabled = true;
+	mutex_unlock(&lcdc->enable_lock);
+}
+
+static void lcdc_pipe_disable(struct drm_simple_display_pipe *pipe)
+{
+	struct drm_device *drm;
+	struct drm_crtc *crtc;
+	struct lcdc *lcdc;
+
+	crtc = &pipe->crtc;
+	drm = crtc->dev;
+	lcdc = drm->dev_private;
+
+	mutex_lock(&lcdc->enable_lock);
+	pm_runtime_get_sync(drm->dev);
+
+	drm_crtc_vblank_off(crtc);
+	atmel_lcdc_stop(lcdc);
+
+	pm_runtime_allow(drm->dev);
+	pm_runtime_put_sync(drm->dev);
+
+	lcdc->enabled = false;
+	mutex_unlock(&lcdc->enable_lock);
+}
+
+
+static void lcdc_pipe_update_format(struct lcdc *lcdc,
+				    struct drm_simple_display_pipe *pipe)
+{
+	struct drm_plane_state *plane_state;
+	struct drm_framebuffer *fb;
+
+	plane_state = pipe->plane.state;
+	fb = plane_state->fb;
+
+	if (fb)
+		set_lcdcon2(lcdc, fb->format);
+}
+
+/* Update DMA addr */
+static void lcdc_pipe_update_dma(struct lcdc *lcdc,
+				 struct drm_simple_display_pipe *pipe)
+{
+	struct drm_plane_state *plane_state;
+	struct drm_framebuffer *fb;
+	dma_addr_t dma_addr;
+
+	plane_state = pipe->plane.state;
+	fb = plane_state->fb;
+
+	if (fb) {
+		dma_addr = drm_fb_cma_get_gem_addr(fb, pipe->plane.state, 0);
+
+		/* Set frame buffer DMA base address */
+		regmap_write(lcdc->mfd->regmap, ATMEL_LCDC_DMABADDR1, dma_addr);
+	}
+}
+
+static void lcdc_pipe_update_event(struct drm_simple_display_pipe *pipe)
+{
+	struct drm_pending_vblank_event *event;
+	struct drm_crtc *crtc;
+
+	crtc = &pipe->crtc;
+	if (!crtc)
+		return;
+
+	spin_lock_irq(&crtc->dev->event_lock);
+	event = crtc->state->event;
+	if (event) {
+		crtc->state->event = NULL;
+
+		if (drm_crtc_vblank_get(crtc) == 0)
+			drm_crtc_arm_vblank_event(crtc, event);
+		else
+			drm_crtc_send_vblank_event(crtc, event);
+	}
+	spin_unlock_irq(&crtc->dev->event_lock);
+}
+
+static void lcdc_pipe_update(struct drm_simple_display_pipe *pipe,
+			     struct drm_plane_state *old_pstate)
+{
+	struct lcdc *lcdc;
+
+	lcdc = pipe->crtc.dev->dev_private;
+
+	/* Format management */
+	lcdc_pipe_update_format(lcdc, pipe);
+
+	/* DMA engine... */
+	lcdc_pipe_update_dma(lcdc, pipe);
+
+	/* vblank event handling */
+	lcdc_pipe_update_event(pipe);
+}
+
+static int lcdc_pipe_enable_vblank(struct drm_simple_display_pipe *pipe)
+{
+	struct drm_crtc *crtc;
+	struct lcdc *lcdc;
+
+	crtc  = &pipe->crtc;
+	lcdc = crtc->dev->dev_private;
+
+	/* Last line interrupt enable */
+	regmap_write(lcdc->mfd->regmap, ATMEL_LCDC_IER, ATMEL_LCDC_LSTLNI);
+
+	return 0;
+}
+
+static void lcdc_pipe_disable_vblank(struct drm_simple_display_pipe *pipe)
+{
+	struct drm_crtc *crtc;
+	struct lcdc *lcdc;
+
+	crtc  = &pipe->crtc;
+	lcdc = crtc->dev->dev_private;
+
+	/* Last line interrupt disable */
+	regmap_write(lcdc->mfd->regmap, ATMEL_LCDC_IDR, ATMEL_LCDC_LSTLNI);
+}
+
+const struct drm_simple_display_pipe_funcs lcdc_display_funcs = {
+	.check = lcdc_pipe_check,
+	.enable = lcdc_pipe_enable,
+	.disable = lcdc_pipe_disable,
+	.update = lcdc_pipe_update,
+	.prepare_fb = drm_gem_fb_simple_display_pipe_prepare_fb,
+	.enable_vblank = lcdc_pipe_enable_vblank,
+	.disable_vblank = lcdc_pipe_disable_vblank,
+};
+
+static int lcdc_get_of_wiring(struct lcdc *lcdc,
+			      const struct device_node *ep)
+{
+	const char *str;
+	int ret;
+
+	// HACK
+	lcdc->wiring_reversed = true;
+
+	ret = of_property_read_string(ep, "wiring", &str);
+	if (ret)
+		return ret;
+
+	if (strcmp(str, "red-green-reversed") == 0) {
+		lcdc->wiring_reversed = true;
+	} else if (strcmp(str, "straight") == 0) {
+		/* Use default format */
+	} else {
+		DRM_DEV_ERROR(lcdc->dev, "unknown \"wiring\" property: %s\n",
+			      str);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int lcdc_display_init(struct lcdc *lcdc)
+{
+	const u32 *formats;
+	size_t nformats;
+	int ret;
+
+	formats = get_formats(lcdc->wiring_reversed, &nformats);
+
+	ret = drm_simple_display_pipe_init(&lcdc->drm, &lcdc->pipe,
+					   &lcdc_display_funcs,
+					   formats, nformats,
+					   NULL, NULL);
+	if (ret < 0)
+		DRM_DEV_ERROR(lcdc->dev, "failed to init display pipe: %d\n",
+			      ret);
+
+	return ret;
+}
+
+static int lcdc_attach_panel(struct lcdc *lcdc)
+{
+	struct drm_bridge *bridge;
+	struct drm_panel *panel;
+	struct device_node *np;
+	struct device *dev;
+	int ret;
+
+	dev = lcdc->dev;
+	np = dev->of_node;
+	ret = drm_of_find_panel_or_bridge(np, 0, 0, &panel, NULL);
+	if (ret < 0)
+		return ret;
+
+	if (!panel) {
+		DRM_DEV_ERROR(dev, "no panel found\n");
+		return -ENODEV;
+	}
+
+	lcdc->panel = panel;
+	bridge = devm_drm_panel_bridge_add(dev, panel, DRM_MODE_CONNECTOR_DPI);
+	ret = PTR_ERR_OR_ZERO(bridge);
+	if (ret < 0) {
+		DRM_DEV_ERROR(dev, "failed to add bridge: %d\n", ret);
+		return ret;
+	}
+
+	ret = lcdc_display_init(lcdc);
+	if (ret < 0)
+		return ret;
+
+	ret = drm_simple_display_pipe_attach_bridge(&lcdc->pipe, bridge);
+	if (ret < 0)
+		DRM_DEV_ERROR(dev, "failed to attach bridge: %d\n", ret);
+
+	lcdc->connector = panel->connector;
+	return ret;
+}
+
+static int lcdc_create_output(struct lcdc *lcdc)
+{
+	struct device_node *endpoint;
+	struct device_node *np;
+	int ret;
+
+	/* port@0/endpoint@0 is the only port/endpoint */
+	np = lcdc->dev->of_node;
+	endpoint = of_graph_get_endpoint_by_regs(np, 0, 0);
+	if (!endpoint) {
+		DRM_DEV_ERROR(lcdc->dev, "failed to find endpoint node\n");
+		return -ENODEV;
+	}
+
+	lcdc_get_of_wiring(lcdc, endpoint);
+	of_node_put(endpoint);
+
+	ret = lcdc_attach_panel(lcdc);
+
+	return ret;
+}
+
+static const struct drm_mode_config_funcs mode_config_funcs = {
+	.fb_create = drm_gem_fb_create,
+	.atomic_check = drm_atomic_helper_check,
+	.atomic_commit = drm_atomic_helper_commit,
+};
+
+int atmel_lcdc_modeset_init(struct lcdc *lcdc)
+{
+	struct drm_device *drm;
+	struct device *dev;
+	int ret;
+
+	drm = &lcdc->drm;
+	dev = drm->dev;
+
+	drm_mode_config_init(drm);
+	ret = lcdc_create_output(lcdc);
+
+	if (ret) {
+		drm_mode_config_cleanup(drm);
+		return ret;
+	}
+
+	drm->mode_config.min_width  = 0;
+	drm->mode_config.min_height = 0;
+	drm->mode_config.max_width  = lcdc->desc->max_width;
+	drm->mode_config.max_height = lcdc->desc->max_height;
+	drm->mode_config.funcs	    = &mode_config_funcs;
+	drm->mode_config.quirk_addfb_rgb_to_bgr = !lcdc->wiring_reversed;
+
+	drm_mode_config_reset(drm);
+
+	return 0;
+}
+
+int atmel_lcdc_vblank_init(struct lcdc *lcdc)
+{
+	int ret;
+
+	ret = drm_vblank_init(&lcdc->drm, 1);
+	if (ret)
+		DRM_DEV_ERROR(lcdc->dev, "vblank init failed: %d\n", ret);
+
+	return ret;
+}
+
+void atmel_lcdc_vblank(struct lcdc *lcdc)
+{
+	drm_crtc_handle_vblank(&lcdc->pipe.crtc);
+}
+
+/*
+ * Start LCD Controller (DMA + PWR)
+ * Caller must hold enable_lock
+ */
+void atmel_lcdc_start(struct lcdc *lcdc)
+{
+	/* Enable DMA */
+	regmap_write(lcdc->mfd->regmap, ATMEL_LCDC_DMACON, ATMEL_LCDC_DMAEN);
+	/* Enable LCD */
+	regmap_write(lcdc->mfd->regmap, ATMEL_LCDC_PWRCON,
+		     (lcdc->desc->guard_time << ATMEL_LCDC_GUARDT_OFFSET)
+		     | ATMEL_LCDC_PWR);
+}
+
+/*
+ * Stop LCD Controller (PWR + DMA)
+ * Caller must hold enable_lock
+ */
+void atmel_lcdc_stop(struct lcdc *lcdc)
+{
+	unsigned int pwrcon;
+
+	might_sleep();
+
+	/* Turn off the LCD controller and the DMA controller */
+	regmap_write(lcdc->mfd->regmap, ATMEL_LCDC_PWRCON,
+			lcdc->desc->guard_time << ATMEL_LCDC_GUARDT_OFFSET);
+
+	regmap_write(lcdc->mfd->regmap, ATMEL_LCDC_DMACON, !(ATMEL_LCDC_DMAEN));
+
+	/* Wait for the LCDC core to become idle */
+	regmap_read_poll_timeout(lcdc->mfd->regmap, ATMEL_LCDC_PWRCON, pwrcon,
+				 !(pwrcon & ATMEL_LCDC_BUSY), 100, 10000);
+}
-- 
2.20.1

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

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

* Re: My penguin has blue feets (aka: RGB versus BGR troubles)
  2019-07-26 20:36 My penguin has blue feets (aka: RGB versus BGR troubles) Sam Ravnborg
  2019-07-26 20:44 ` [RFC PATCH] drm: add Atmel LCDC display controller support Sam Ravnborg
@ 2019-07-26 21:35 ` Ilia Mirkin
  2019-07-26 22:22   ` Daniel Vetter
  2019-07-27  9:56 ` Sam Ravnborg
  2 siblings, 1 reply; 7+ messages in thread
From: Ilia Mirkin @ 2019-07-26 21:35 UTC (permalink / raw)
  To: Sam Ravnborg; +Cc: dri-devel

On Fri, Jul 26, 2019 at 4:36 PM Sam Ravnborg <sam@ravnborg.org> wrote:
>
> 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@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?

Every driver to date supports XR24. So modetest uses that by default.
But this fails with your driver since it's an unsupported format.
Something like:

modetest -M atmel-lcdc -s 34:800x480-60Hz@XB24

should do the trick. The quirk covers drivers that use AddFB().
However modetest is fancy and uses AddFB2, which takes an explicit
format.

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

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

* Re: My penguin has blue feets (aka: RGB versus BGR troubles)
  2019-07-26 21:35 ` My penguin has blue feets (aka: RGB versus BGR troubles) Ilia Mirkin
@ 2019-07-26 22:22   ` Daniel Vetter
  2019-07-27 10:12     ` Sam Ravnborg
  0 siblings, 1 reply; 7+ messages in thread
From: Daniel Vetter @ 2019-07-26 22:22 UTC (permalink / raw)
  To: Ilia Mirkin; +Cc: Sam Ravnborg, dri-devel

On Fri, Jul 26, 2019 at 11:35 PM Ilia Mirkin <imirkin@alum.mit.edu> wrote:
> On Fri, Jul 26, 2019 at 4:36 PM Sam Ravnborg <sam@ravnborg.org> wrote:
> >
> > 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@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?
>
> Every driver to date supports XR24. So modetest uses that by default.
> But this fails with your driver since it's an unsupported format.
> Something like:
>
> modetest -M atmel-lcdc -s 34:800x480-60Hz@XB24
>
> should do the trick. The quirk covers drivers that use AddFB().
> However modetest is fancy and uses AddFB2, which takes an explicit
> format.

Yeah I thinki for fbdev the correct fix is to look whether the driver
enabled atomic and if so, consult the fourcc format list of the
primary plane of the first crtc to figure out what you might actually
have set. Without atomic you can't realy on the format list being
correct since for drivers who get the default primary plane that
drm_crtc_init sets up the format list is garbage. Reworking the entire
fbdev emulation to use fourcc codes would be even more awesome I
guess.
-Daniel
-- 
Daniel Vetter
Software Engineer, Intel Corporation
+41 (0) 79 365 57 48 - http://blog.ffwll.ch
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

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

* Re: My penguin has blue feets (aka: RGB versus BGR troubles)
  2019-07-26 20:36 My penguin has blue feets (aka: RGB versus BGR troubles) Sam Ravnborg
  2019-07-26 20:44 ` [RFC PATCH] drm: add Atmel LCDC display controller support Sam Ravnborg
  2019-07-26 21:35 ` My penguin has blue feets (aka: RGB versus BGR troubles) Ilia Mirkin
@ 2019-07-27  9:56 ` Sam Ravnborg
  2 siblings, 0 replies; 7+ messages in thread
From: Sam Ravnborg @ 2019-07-27  9:56 UTC (permalink / raw)
  To: dri-devel

Hi all.

Thanks for the responses.
It turns out this was a PICNIC error
(Problem In Chair, Not In Computer)

On Fri, Jul 26, 2019 at 10:36:26PM +0200, Sam Ravnborg wrote:
> 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
modetest do not like the "Hz" prefix when specifying the refresh rate.
When Hz is added it reverts back to XR24.

So when I use:
    # modetest -M atmel-lcdc  -s 34:800x480@BG24

Then I see the expected output with the right colors.

I also had got the false impression that if no format was specified
modetest would use the first format reported from the driver.
This was obviously also wrong.

So all-in-all - I am quite happy with how things works now.
Needs to do more testing, polishing a few patches and then
I can send out a v3 of this driver.

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

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

* Re: My penguin has blue feets (aka: RGB versus BGR troubles)
  2019-07-26 22:22   ` Daniel Vetter
@ 2019-07-27 10:12     ` Sam Ravnborg
  2019-07-27 10:50       ` Sam Ravnborg
  0 siblings, 1 reply; 7+ messages in thread
From: Sam Ravnborg @ 2019-07-27 10:12 UTC (permalink / raw)
  To: Daniel Vetter; +Cc: dri-devel

Hi Daniel.

> > >
> > > *Any* hints why modetest fails when my driver reports the correct formats?
> >
> > Every driver to date supports XR24. So modetest uses that by default.
> > But this fails with your driver since it's an unsupported format.
> > Something like:
> >
> > modetest -M atmel-lcdc -s 34:800x480-60Hz@XB24
> >
> > should do the trick. The quirk covers drivers that use AddFB().
> > However modetest is fancy and uses AddFB2, which takes an explicit
> > format.
> 
> Yeah I thinki for fbdev the correct fix is to look whether the driver
> enabled atomic and if so, consult the fourcc format list of the
> primary plane of the first crtc to figure out what you might actually
> have set. Without atomic you can't realy on the format list being
> correct since for drivers who get the default primary plane that
> drm_crtc_init sets up the format list is garbage.

I do not follow you here.

# modetest -M atmel-lcdc -p
Planes:
id      crtc    fb      CRTC x,y        x,y     gamma size      possible crtcs
31      32      35      0,0             0,0     0               0x00000001
  formats: XB24 BG24 BG16

# modetest -M atmel-lcdc -a -p
Planes:
id      crtc    fb      CRTC x,y        x,y     gamma size      possible crtcs
31      32      35      0,0             0,0     0               0x00000001
  formats: XB24 BG24 BG16

So with or without atomic (-a option) the driver reports the same formats.


# modetest -M atmel-lcdc -a -s ...

does not work btw. It just exists without anything shown on the panel.


> Reworking the entire
> fbdev emulation to use fourcc codes would be even more awesome I
> guess.
To take the bait I would need a little bit more guidiance on this.

Is it something like:
- New variant af drm_fbdev_generic_setup() that takes a fourcc code, not
  a preferred_bpp
- drm_fb_helper_initial_config likewise
- drm_fb_helper_fbdev_setup likewise
- drm_fb_helper_single_fb_probe likewise

And then work through all the code until we no longer rely on
preferred_bpp??

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

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

* Re: My penguin has blue feets (aka: RGB versus BGR troubles)
  2019-07-27 10:12     ` Sam Ravnborg
@ 2019-07-27 10:50       ` Sam Ravnborg
  0 siblings, 0 replies; 7+ messages in thread
From: Sam Ravnborg @ 2019-07-27 10:50 UTC (permalink / raw)
  To: Daniel Vetter; +Cc: dri-devel

Hi

> # modetest -M atmel-lcdc -a -s ...
> 
> does not work btw. It just exists without anything shown on the panel.

Looking at the modetest src -a requires both a primary plane + an overlay.
If either is missing modetest just exists with no errors printed.
Another opportunity to improve error handling.

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

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

end of thread, other threads:[~2019-07-27 10:50 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-07-26 20:36 My penguin has blue feets (aka: RGB versus BGR troubles) Sam Ravnborg
2019-07-26 20:44 ` [RFC PATCH] drm: add Atmel LCDC display controller support Sam Ravnborg
2019-07-26 21:35 ` My penguin has blue feets (aka: RGB versus BGR troubles) Ilia Mirkin
2019-07-26 22:22   ` Daniel Vetter
2019-07-27 10:12     ` Sam Ravnborg
2019-07-27 10:50       ` Sam Ravnborg
2019-07-27  9:56 ` Sam Ravnborg

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.