All of lore.kernel.org
 help / color / mirror / Atom feed
diff for duplicates of <825691480430000@web35j.yandex.ru>

diff --git a/a/1.txt b/N1/1.txt
index 145530a..656effd 100644
--- a/a/1.txt
+++ b/N1/1.txt
@@ -1,16 +1,16 @@
 
 
-29.11.2016, 22:30, "Daniel Vetter" <daniel@ffwll.ch>:
+29.11.2016, 22:30, "Daniel Vetter" <daniel-/w4YWyX8dFk@public.gmane.org>:
 > On Mon, Nov 28, 2016 at 03:23:54PM +0100, Jean-Francois Moine wrote:
->> ?Allwinner's recent SoCs, as A64, A83T and H3, contain a new display
->> ?engine, DE2.
->> ?This patch adds a DRM video driver for this device.
+>>  Allwinner's recent SoCs, as A64, A83T and H3, contain a new display
+>>  engine, DE2.
+>>  This patch adds a DRM video driver for this device.
 >>
->> ?Signed-off-by: Jean-Francois Moine <moinejf@free.fr>
+>>  Signed-off-by: Jean-Francois Moine <moinejf-GANU6spQydw@public.gmane.org>
 >
 > Scrolled around a bit, seemed all reasonable.
 >
-> Acked-by: Daniel Vetter <daniel.vetter@ffwll.ch>
+> Acked-by: Daniel Vetter <daniel.vetter-/w4YWyX8dFk@public.gmane.org>
 >
 > Not sure a new driver for each chip is reasonable, experience says that
 > long-term you want to share quite a pile of code between different hw
@@ -23,1723 +23,1723 @@ the ones on A33 and older.
 It's called "DE 2.0" in the user manual of the SoCs.
 
 >
->> ?---
->> ??drivers/gpu/drm/Kconfig | 2 +
->> ??drivers/gpu/drm/Makefile | 1 +
->> ??drivers/gpu/drm/sun8i/Kconfig | 19 +
->> ??drivers/gpu/drm/sun8i/Makefile | 7 +
->> ??drivers/gpu/drm/sun8i/de2_crtc.c | 449 +++++++++++++++++++++++
->> ??drivers/gpu/drm/sun8i/de2_crtc.h | 50 +++
->> ??drivers/gpu/drm/sun8i/de2_drv.c | 317 ++++++++++++++++
->> ??drivers/gpu/drm/sun8i/de2_drv.h | 48 +++
->> ??drivers/gpu/drm/sun8i/de2_plane.c | 734 ++++++++++++++++++++++++++++++++++++++
->> ??9 files changed, 1627 insertions(+)
->> ??create mode 100644 drivers/gpu/drm/sun8i/Kconfig
->> ??create mode 100644 drivers/gpu/drm/sun8i/Makefile
->> ??create mode 100644 drivers/gpu/drm/sun8i/de2_crtc.c
->> ??create mode 100644 drivers/gpu/drm/sun8i/de2_crtc.h
->> ??create mode 100644 drivers/gpu/drm/sun8i/de2_drv.c
->> ??create mode 100644 drivers/gpu/drm/sun8i/de2_drv.h
->> ??create mode 100644 drivers/gpu/drm/sun8i/de2_plane.c
+>>  ---
+>>   drivers/gpu/drm/Kconfig | 2 +
+>>   drivers/gpu/drm/Makefile | 1 +
+>>   drivers/gpu/drm/sun8i/Kconfig | 19 +
+>>   drivers/gpu/drm/sun8i/Makefile | 7 +
+>>   drivers/gpu/drm/sun8i/de2_crtc.c | 449 +++++++++++++++++++++++
+>>   drivers/gpu/drm/sun8i/de2_crtc.h | 50 +++
+>>   drivers/gpu/drm/sun8i/de2_drv.c | 317 ++++++++++++++++
+>>   drivers/gpu/drm/sun8i/de2_drv.h | 48 +++
+>>   drivers/gpu/drm/sun8i/de2_plane.c | 734 ++++++++++++++++++++++++++++++++++++++
+>>   9 files changed, 1627 insertions(+)
+>>   create mode 100644 drivers/gpu/drm/sun8i/Kconfig
+>>   create mode 100644 drivers/gpu/drm/sun8i/Makefile
+>>   create mode 100644 drivers/gpu/drm/sun8i/de2_crtc.c
+>>   create mode 100644 drivers/gpu/drm/sun8i/de2_crtc.h
+>>   create mode 100644 drivers/gpu/drm/sun8i/de2_drv.c
+>>   create mode 100644 drivers/gpu/drm/sun8i/de2_drv.h
+>>   create mode 100644 drivers/gpu/drm/sun8i/de2_plane.c
 >>
->> ?diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig
->> ?index 95fc041..bb1bfbc 100644
->> ?--- a/drivers/gpu/drm/Kconfig
->> ?+++ b/drivers/gpu/drm/Kconfig
->> ?@@ -202,6 +202,8 @@ source "drivers/gpu/drm/shmobile/Kconfig"
+>>  diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig
+>>  index 95fc041..bb1bfbc 100644
+>>  --- a/drivers/gpu/drm/Kconfig
+>>  +++ b/drivers/gpu/drm/Kconfig
+>>  @@ -202,6 +202,8 @@ source "drivers/gpu/drm/shmobile/Kconfig"
 >>
->> ??source "drivers/gpu/drm/sun4i/Kconfig"
+>>   source "drivers/gpu/drm/sun4i/Kconfig"
 >>
->> ?+source "drivers/gpu/drm/sun8i/Kconfig"
->> ?+
->> ??source "drivers/gpu/drm/omapdrm/Kconfig"
+>>  +source "drivers/gpu/drm/sun8i/Kconfig"
+>>  +
+>>   source "drivers/gpu/drm/omapdrm/Kconfig"
 >>
->> ??source "drivers/gpu/drm/tilcdc/Kconfig"
->> ?diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile
->> ?index 883f3e7..3e1eaa0 100644
->> ?--- a/drivers/gpu/drm/Makefile
->> ?+++ b/drivers/gpu/drm/Makefile
->> ?@@ -72,6 +72,7 @@ obj-$(CONFIG_DRM_RCAR_DU) += rcar-du/
->> ??obj-$(CONFIG_DRM_SHMOBILE) +=shmobile/
->> ??obj-y += omapdrm/
->> ??obj-$(CONFIG_DRM_SUN4I) += sun4i/
->> ?+obj-$(CONFIG_DRM_SUN8I) += sun8i/
->> ??obj-y += tilcdc/
->> ??obj-$(CONFIG_DRM_QXL) += qxl/
->> ??obj-$(CONFIG_DRM_BOCHS) += bochs/
->> ?diff --git a/drivers/gpu/drm/sun8i/Kconfig b/drivers/gpu/drm/sun8i/Kconfig
->> ?new file mode 100644
->> ?index 0000000..6940895
->> ?--- /dev/null
->> ?+++ b/drivers/gpu/drm/sun8i/Kconfig
->> ?@@ -0,0 +1,19 @@
->> ?+#
->> ?+# Allwinner DE2 Video configuration
->> ?+#
->> ?+
->> ?+config DRM_SUN8I
->> ?+ bool
->> ?+
->> ?+config DRM_SUN8I_DE2
->> ?+ tristate "Support for Allwinner Video with DE2 interface"
->> ?+ depends on DRM && OF
->> ?+ depends on ARCH_SUNXI || COMPILE_TEST
->> ?+ select DRM_GEM_CMA_HELPER
->> ?+ select DRM_KMS_CMA_HELPER
->> ?+ select DRM_KMS_HELPER
->> ?+ select DRM_SUN8I
->> ?+ help
->> ?+ Choose this option if your Allwinner chipset has the DE2 interface
->> ?+ as the A64, A83T and H3. If M is selected the module will be called
->> ?+ sun8i-de2-drm.
->> ?diff --git a/drivers/gpu/drm/sun8i/Makefile b/drivers/gpu/drm/sun8i/Makefile
->> ?new file mode 100644
->> ?index 0000000..f107919
->> ?--- /dev/null
->> ?+++ b/drivers/gpu/drm/sun8i/Makefile
->> ?@@ -0,0 +1,7 @@
->> ?+#
->> ?+# Makefile for Allwinner's sun8i DRM device driver
->> ?+#
->> ?+
->> ?+sun8i-de2-drm-objs := de2_drv.o de2_crtc.o de2_plane.o
->> ?+
->> ?+obj-$(CONFIG_DRM_SUN8I_DE2) += sun8i-de2-drm.o
->> ?diff --git a/drivers/gpu/drm/sun8i/de2_crtc.c b/drivers/gpu/drm/sun8i/de2_crtc.c
->> ?new file mode 100644
->> ?index 0000000..4e94ccc
->> ?--- /dev/null
->> ?+++ b/drivers/gpu/drm/sun8i/de2_crtc.c
->> ?@@ -0,0 +1,449 @@
->> ?+/*
->> ?+ * Allwinner DRM driver - DE2 CRTC
->> ?+ *
->> ?+ * Copyright (C) 2016 Jean-Francois Moine <moinejf@free.fr>
->> ?+ *
->> ?+ * This program is free software; you can redistribute it and/or
->> ?+ * modify it under the terms of the GNU General Public License as
->> ?+ * published by the Free Software Foundation; either version 2 of
->> ?+ * the License, or (at your option) any later version.
->> ?+ */
->> ?+
->> ?+#include <linux/component.h>
->> ?+#include <drm/drm_crtc_helper.h>
->> ?+#include <drm/drm_atomic_helper.h>
->> ?+#include <linux/io.h>
->> ?+#include <linux/of_irq.h>
->> ?+#include <linux/of_graph.h>
->> ?+
->> ?+#include "de2_drv.h"
->> ?+#include "de2_crtc.h"
->> ?+
->> ?+/* I/O map */
->> ?+
->> ?+#define TCON_GCTL_REG 0x00
->> ?+#define TCON_GCTL_TCON_ENABLE BIT(31)
->> ?+#define TCON_GINT0_REG 0x04
->> ?+#define TCON_GINT0_TCON1_Vb_Int_En BIT(30)
->> ?+#define TCON_GINT0_TCON1_Vb_Int_Flag BIT(14)
->> ?+#define TCON_GINT0_TCON1_Vb_Line_Int_Flag BIT(12)
->> ?+#define TCON0_CTL_REG 0x40
->> ?+#define TCON0_CTL_TCON_ENABLE BIT(31)
->> ?+#define TCON1_CTL_REG 0x90
->> ?+#define TCON1_CTL_TCON_ENABLE BIT(31)
->> ?+#define TCON1_CTL_INTERLACE_ENABLE BIT(20)
->> ?+#define TCON1_CTL_Start_Delay_SHIFT 4
->> ?+#define TCON1_CTL_Start_Delay_MASK GENMASK(8, 4)
->> ?+#define TCON1_BASIC0_REG 0x94 /* XI/YI */
->> ?+#define TCON1_BASIC1_REG 0x98 /* LS_XO/LS_YO */
->> ?+#define TCON1_BASIC2_REG 0x9c /* XO/YO */
->> ?+#define TCON1_BASIC3_REG 0xa0 /* HT/HBP */
->> ?+#define TCON1_BASIC4_REG 0xa4 /* VT/VBP */
->> ?+#define TCON1_BASIC5_REG 0xa8 /* HSPW/VSPW */
->> ?+#define TCON1_PS_SYNC_REG 0xb0
->> ?+#define TCON1_IO_POL_REG 0xf0
->> ?+#define TCON1_IO_POL_IO0_inv BIT(24)
->> ?+#define TCON1_IO_POL_IO1_inv BIT(25)
->> ?+#define TCON1_IO_POL_IO2_inv BIT(26)
->> ?+#define TCON1_IO_TRI_REG 0xf4
->> ?+#define TCON_CEU_CTL_REG 0x100
->> ?+#define TCON_CEU_CTL_ceu_en BIT(31)
->> ?+#define TCON1_FILL_CTL_REG 0x300
->> ?+#define TCON1_FILL_START0_REG 0x304
->> ?+#define TCON1_FILL_END0_REG 0x308
->> ?+#define TCON1_FILL_DATA0_REG 0x30c
->> ?+
->> ?+#define XY(x, y) (((x) << 16) | (y))
->> ?+
->> ?+#define andl_relaxed(addr, val) \
->> ?+ writel_relaxed(readl_relaxed(addr) & val, addr)
->> ?+#define orl_relaxed(addr, val) \
->> ?+ writel_relaxed(readl_relaxed(addr) | val, addr)
->> ?+
->> ?+/* vertical blank functions */
->> ?+
->> ?+static void de2_atomic_flush(struct drm_crtc *crtc,
->> ?+ struct drm_crtc_state *old_state)
->> ?+{
->> ?+ struct drm_pending_vblank_event *event = crtc->state->event;
->> ?+
->> ?+ if (event) {
->> ?+ crtc->state->event = NULL;
->> ?+ spin_lock_irq(&crtc->dev->event_lock);
->> ?+ 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 irqreturn_t de2_lcd_irq(int irq, void *dev_id)
->> ?+{
->> ?+ struct lcd *lcd = (struct lcd *) dev_id;
->> ?+ u32 isr;
->> ?+
->> ?+ isr = readl_relaxed(lcd->mmio + TCON_GINT0_REG);
->> ?+
->> ?+ drm_crtc_handle_vblank(&lcd->crtc);
->> ?+
->> ?+ writel_relaxed(isr &
->> ?+ ~(TCON_GINT0_TCON1_Vb_Int_Flag |
->> ?+ TCON_GINT0_TCON1_Vb_Line_Int_Flag),
->> ?+ lcd->mmio + TCON_GINT0_REG);
->> ?+
->> ?+ return IRQ_HANDLED;
->> ?+}
->> ?+
->> ?+int de2_enable_vblank(struct drm_device *drm, unsigned int crtc_ix)
->> ?+{
->> ?+ struct priv *priv = drm_to_priv(drm);
->> ?+ struct lcd *lcd = priv->lcds[crtc_ix];
->> ?+
->> ?+ orl_relaxed(lcd->mmio + TCON_GINT0_REG, TCON_GINT0_TCON1_Vb_Int_En);
->> ?+
->> ?+ return 0;
->> ?+}
->> ?+
->> ?+void de2_disable_vblank(struct drm_device *drm, unsigned int crtc_ix)
->> ?+{
->> ?+ struct priv *priv = drm_to_priv(drm);
->> ?+ struct lcd *lcd = priv->lcds[crtc_ix];
->> ?+
->> ?+ andl_relaxed(lcd->mmio + TCON_GINT0_REG, ~TCON_GINT0_TCON1_Vb_Int_En);
->> ?+}
->> ?+
->> ?+void de2_vblank_reset(struct lcd *lcd)
->> ?+{
->> ?+ drm_crtc_vblank_reset(&lcd->crtc);
->> ?+}
->> ?+
->> ?+/* frame functions */
->> ?+static int de2_crtc_set_clock(struct lcd *lcd, int rate)
->> ?+{
->> ?+ struct clk *parent_clk;
->> ?+ u32 parent_rate;
->> ?+ int ret;
->> ?+
->> ?+ /* determine and set the best rate for the parent clock (pll-video) */
->> ?+ if ((270000 * 2) % rate == 0)
->> ?+ parent_rate = 270000000;
->> ?+ else if (297000 % rate == 0)
->> ?+ parent_rate = 297000000;
->> ?+ else
->> ?+ return -EINVAL; /* unsupported clock */
->> ?+
->> ?+ parent_clk = clk_get_parent(lcd->clk);
->> ?+
->> ?+ ret = clk_set_rate(parent_clk, parent_rate);
->> ?+ if (ret) {
->> ?+ dev_err(lcd->dev, "set parent rate failed %d\n", ret);
->> ?+ return ret;
->> ?+ }
->> ?+ ret = clk_set_rate(lcd->clk, rate * 1000);
->> ?+ if (ret) {
->> ?+ dev_err(lcd->dev, "set rate failed %d\n", ret);
->> ?+ return ret;
->> ?+ }
->> ?+
->> ?+ /* enable the clock */
->> ?+ reset_control_deassert(lcd->reset);
->> ?+ clk_prepare_enable(lcd->bus);
->> ?+ clk_prepare_enable(lcd->clk);
->> ?+
->> ?+ return ret;
->> ?+}
->> ?+
->> ?+static void de2_tcon_init(struct lcd *lcd)
->> ?+{
->> ?+ andl_relaxed(lcd->mmio + TCON0_CTL_REG, ~TCON0_CTL_TCON_ENABLE);
->> ?+ andl_relaxed(lcd->mmio + TCON1_CTL_REG, ~TCON1_CTL_TCON_ENABLE);
->> ?+ andl_relaxed(lcd->mmio + TCON_GCTL_REG, ~TCON_GCTL_TCON_ENABLE);
->> ?+
->> ?+ /* disable/ack interrupts */
->> ?+ writel_relaxed(0, lcd->mmio + TCON_GINT0_REG);
->> ?+}
->> ?+
->> ?+static void de2_tcon_enable(struct lcd *lcd)
->> ?+{
->> ?+ struct drm_crtc *crtc = &lcd->crtc;
->> ?+ const struct drm_display_mode *mode = &crtc->mode;
->> ?+ int interlace = mode->flags & DRM_MODE_FLAG_INTERLACE ? 2 : 1;
->> ?+ int start_delay;
->> ?+ u32 data;
->> ?+
->> ?+ orl_relaxed(lcd->mmio + TCON_GCTL_REG, TCON_GCTL_TCON_ENABLE);
->> ?+
->> ?+ data = XY(mode->hdisplay - 1, mode->vdisplay / interlace - 1);
->> ?+ writel_relaxed(data, lcd->mmio + TCON1_BASIC0_REG);
->> ?+ writel_relaxed(data, lcd->mmio + TCON1_BASIC1_REG);
->> ?+ writel_relaxed(data, lcd->mmio + TCON1_BASIC2_REG);
->> ?+ writel_relaxed(XY(mode->htotal - 1,
->> ?+ mode->htotal - mode->hsync_start - 1),
->> ?+ lcd->mmio + TCON1_BASIC3_REG);
->> ?+ writel_relaxed(XY(mode->vtotal * (3 - interlace),
->> ?+ mode->vtotal - mode->vsync_start - 1),
->> ?+ lcd->mmio + TCON1_BASIC4_REG);
->> ?+ writel_relaxed(XY(mode->hsync_end - mode->hsync_start - 1,
->> ?+ mode->vsync_end - mode->vsync_start - 1),
->> ?+ lcd->mmio + TCON1_BASIC5_REG);
->> ?+
->> ?+ data = TCON1_IO_POL_IO2_inv;
->> ?+ if (mode->flags & DRM_MODE_FLAG_PVSYNC)
->> ?+ data |= TCON1_IO_POL_IO0_inv;
->> ?+ if (mode->flags & DRM_MODE_FLAG_PHSYNC)
->> ?+ data |= TCON1_IO_POL_IO1_inv;
->> ?+ writel_relaxed(data, lcd->mmio + TCON1_IO_POL_REG);
->> ?+
->> ?+ andl_relaxed(lcd->mmio + TCON_CEU_CTL_REG, ~TCON_CEU_CTL_ceu_en);
->> ?+
->> ?+ if (interlace == 2)
->> ?+ orl_relaxed(lcd->mmio + TCON1_CTL_REG,
->> ?+ TCON1_CTL_INTERLACE_ENABLE);
->> ?+ else
->> ?+ andl_relaxed(lcd->mmio + TCON1_CTL_REG,
->> ?+ ~TCON1_CTL_INTERLACE_ENABLE);
->> ?+
->> ?+ writel_relaxed(0, lcd->mmio + TCON1_FILL_CTL_REG);
->> ?+ writel_relaxed(mode->vtotal + 1, lcd->mmio + TCON1_FILL_START0_REG);
->> ?+ writel_relaxed(mode->vtotal, lcd->mmio + TCON1_FILL_END0_REG);
->> ?+ writel_relaxed(0, lcd->mmio + TCON1_FILL_DATA0_REG);
->> ?+
->> ?+ start_delay = (mode->vtotal - mode->vdisplay) / interlace - 5;
->> ?+ if (start_delay > 31)
->> ?+ start_delay = 31;
->> ?+ data = readl_relaxed(lcd->mmio + TCON1_CTL_REG);
->> ?+ data &= ~TCON1_CTL_Start_Delay_MASK;
->> ?+ data |= start_delay << TCON1_CTL_Start_Delay_SHIFT;
->> ?+ writel_relaxed(data, lcd->mmio + TCON1_CTL_REG);
->> ?+
->> ?+ orl_relaxed(lcd->mmio + TCON1_CTL_REG, TCON1_CTL_TCON_ENABLE);
->> ?+}
->> ?+
->> ?+static void de2_tcon_disable(struct lcd *lcd)
->> ?+{
->> ?+ andl_relaxed(lcd->mmio + TCON1_CTL_REG, ~TCON1_CTL_TCON_ENABLE);
->> ?+ andl_relaxed(lcd->mmio + TCON_GCTL_REG, ~TCON_GCTL_TCON_ENABLE);
->> ?+}
->> ?+
->> ?+static void de2_crtc_enable(struct drm_crtc *crtc)
->> ?+{
->> ?+ struct lcd *lcd = crtc_to_lcd(crtc);
->> ?+ struct drm_display_mode *mode = &crtc->mode;
->> ?+
->> ?+ if (de2_crtc_set_clock(lcd, mode->clock) < 0)
->> ?+ return;
->> ?+ lcd->clk_enabled = true;
->> ?+
->> ?+ /* start the TCON and the DE */
->> ?+ de2_tcon_enable(lcd);
->> ?+ de2_de_enable(lcd);
->> ?+
->> ?+ /* turn on blanking interrupt */
->> ?+ drm_crtc_vblank_on(crtc);
->> ?+}
->> ?+
->> ?+static void de2_crtc_disable(struct drm_crtc *crtc,
->> ?+ struct drm_crtc_state *old_crtc_state)
->> ?+{
->> ?+ struct lcd *lcd = crtc_to_lcd(crtc);
->> ?+
->> ?+ if (!lcd->clk_enabled)
->> ?+ return; /* already disabled */
->> ?+ lcd->clk_enabled = false;
->> ?+
->> ?+ de2_de_disable(lcd);
->> ?+
->> ?+ drm_crtc_vblank_off(crtc);
->> ?+
->> ?+ de2_tcon_disable(lcd);
->> ?+
->> ?+ clk_disable_unprepare(lcd->clk);
->> ?+ clk_disable_unprepare(lcd->bus);
->> ?+ reset_control_assert(lcd->reset);
->> ?+}
->> ?+
->> ?+static const struct drm_crtc_funcs de2_crtc_funcs = {
->> ?+ .destroy = drm_crtc_cleanup,
->> ?+ .set_config = drm_atomic_helper_set_config,
->> ?+ .page_flip = drm_atomic_helper_page_flip,
->> ?+ .reset = drm_atomic_helper_crtc_reset,
->> ?+ .atomic_duplicate_state = drm_atomic_helper_crtc_duplicate_state,
->> ?+ .atomic_destroy_state = drm_atomic_helper_crtc_destroy_state,
->> ?+};
->> ?+
->> ?+static const struct drm_crtc_helper_funcs de2_crtc_helper_funcs = {
->> ?+ .atomic_flush = de2_atomic_flush,
->> ?+ .enable = de2_crtc_enable,
->> ?+ .atomic_disable = de2_crtc_disable,
->> ?+};
->> ?+
->> ?+/* device init */
->> ?+static int de2_lcd_bind(struct device *dev, struct device *master,
->> ?+ void *data)
->> ?+{
->> ?+ struct drm_device *drm = data;
->> ?+ struct priv *priv = drm_to_priv(drm);
->> ?+ struct lcd *lcd = dev_get_drvdata(dev);
->> ?+ struct drm_crtc *crtc = &lcd->crtc;
->> ?+ int ret, i, crtc_ix;
->> ?+
->> ?+ lcd->priv = priv;
->> ?+
->> ?+ /* set the CRTC reference */
->> ?+ crtc_ix = drm_crtc_index(crtc);
->> ?+ if (crtc_ix >= ARRAY_SIZE(priv->lcds)) {
->> ?+ dev_err(drm->dev, "Bad crtc index");
->> ?+ return -ENOENT;
->> ?+ }
->> ?+ priv->lcds[crtc_ix] = lcd;
->> ?+
->> ?+ /* and the mixer index (DT port index in the DE) */
->> ?+ for (i = 0; ; i++) {
->> ?+ struct device_node *port;
->> ?+
->> ?+ port = of_parse_phandle(drm->dev->of_node, "ports", i);
->> ?+ if (!port)
->> ?+ break;
->> ?+ if (port == lcd->crtc.port) {
->> ?+ lcd->mixer = i;
->> ?+ break;
->> ?+ }
->> ?+ }
->> ?+
->> ?+ ret = de2_plane_init(drm, lcd);
->> ?+ if (ret < 0)
->> ?+ return ret;
->> ?+
->> ?+ drm_crtc_helper_add(crtc, &de2_crtc_helper_funcs);
->> ?+
->> ?+ return drm_crtc_init_with_planes(drm, crtc,
->> ?+ &lcd->planes[DE2_PRIMARY_PLANE],
->> ?+ &lcd->planes[DE2_CURSOR_PLANE],
->> ?+ &de2_crtc_funcs, NULL);
->> ?+}
->> ?+
->> ?+static void de2_lcd_unbind(struct device *dev, struct device *master,
->> ?+ void *data)
->> ?+{
->> ?+ struct platform_device *pdev = to_platform_device(dev);
->> ?+ struct lcd *lcd = platform_get_drvdata(pdev);
->> ?+
->> ?+ if (lcd->priv)
->> ?+ lcd->priv->lcds[drm_crtc_index(&lcd->crtc)] = NULL;
->> ?+}
->> ?+
->> ?+static const struct component_ops de2_lcd_ops = {
->> ?+ .bind = de2_lcd_bind,
->> ?+ .unbind = de2_lcd_unbind,
->> ?+};
->> ?+
->> ?+static int de2_lcd_probe(struct platform_device *pdev)
->> ?+{
->> ?+ struct device *dev = &pdev->dev;
->> ?+ struct device_node *np = dev->of_node, *tmp, *parent, *port;
->> ?+ struct lcd *lcd;
->> ?+ struct resource *res;
->> ?+ int id, irq, ret;
->> ?+
->> ?+ lcd = devm_kzalloc(dev, sizeof(*lcd), GFP_KERNEL);
->> ?+ if (!lcd)
->> ?+ return -ENOMEM;
->> ?+
->> ?+ dev_set_drvdata(dev, lcd);
->> ?+ lcd->dev = dev;
->> ?+ lcd->mixer = id;
->> ?+
->> ?+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
->> ?+ if (!res) {
->> ?+ dev_err(dev, "failed to get memory resource\n");
->> ?+ return -EINVAL;
->> ?+ }
->> ?+
->> ?+ lcd->mmio = devm_ioremap_resource(dev, res);
->> ?+ if (IS_ERR(lcd->mmio)) {
->> ?+ dev_err(dev, "failed to map registers\n");
->> ?+ return PTR_ERR(lcd->mmio);
->> ?+ }
->> ?+
->> ?+ /* possible CRTC */
->> ?+ parent = np;
->> ?+ tmp = of_get_child_by_name(np, "ports");
->> ?+ if (tmp)
->> ?+ parent = tmp;
->> ?+ port = of_get_child_by_name(parent, "port");
->> ?+ of_node_put(tmp);
->> ?+ if (!port) {
->> ?+ dev_err(dev, "no port node\n");
->> ?+ return -ENXIO;
->> ?+ }
->> ?+ lcd->crtc.port = port;
->> ?+
->> ?+ lcd->bus = devm_clk_get(dev, "bus");
->> ?+ if (IS_ERR(lcd->bus)) {
->> ?+ dev_err(dev, "get bus clock err %d\n", (int) PTR_ERR(lcd->bus));
->> ?+ ret = PTR_ERR(lcd->bus);
->> ?+ goto err;
->> ?+ }
->> ?+
->> ?+ lcd->clk = devm_clk_get(dev, "clock");
->> ?+ if (IS_ERR(lcd->clk)) {
->> ?+ ret = PTR_ERR(lcd->clk);
->> ?+ dev_err(dev, "get video clock err %d\n", ret);
->> ?+ goto err;
->> ?+ }
->> ?+
->> ?+ lcd->reset = devm_reset_control_get(dev, NULL);
->> ?+ if (IS_ERR(lcd->reset)) {
->> ?+ ret = PTR_ERR(lcd->reset);
->> ?+ dev_err(dev, "get reset err %d\n", ret);
->> ?+ goto err;
->> ?+ }
->> ?+
->> ?+ irq = platform_get_irq(pdev, 0);
->> ?+ if (irq <= 0) {
->> ?+ dev_err(dev, "unable to get irq\n");
->> ?+ ret = -EINVAL;
->> ?+ goto err;
->> ?+ }
->> ?+
->> ?+ de2_tcon_init(lcd); /* stop TCON and avoid interrupts */
->> ?+
->> ?+ ret = devm_request_irq(dev, irq, de2_lcd_irq, 0,
->> ?+ dev_name(dev), lcd);
->> ?+ if (ret < 0) {
->> ?+ dev_err(dev, "unable to request irq %d\n", irq);
->> ?+ goto err;
->> ?+ }
->> ?+
->> ?+ return component_add(dev, &de2_lcd_ops);
->> ?+
->> ?+err:
->> ?+ of_node_put(lcd->crtc.port);
->> ?+ return ret;
->> ?+}
->> ?+
->> ?+static int de2_lcd_remove(struct platform_device *pdev)
->> ?+{
->> ?+ struct lcd *lcd = platform_get_drvdata(pdev);
->> ?+
->> ?+ component_del(&pdev->dev, &de2_lcd_ops);
->> ?+
->> ?+ of_node_put(lcd->crtc.port);
->> ?+
->> ?+ return 0;
->> ?+}
->> ?+
->> ?+static const struct of_device_id de2_lcd_ids[] = {
->> ?+ { .compatible = "allwinner,sun8i-a83t-tcon", },
->> ?+ { }
->> ?+};
->> ?+
->> ?+struct platform_driver de2_lcd_platform_driver = {
->> ?+ .probe = de2_lcd_probe,
->> ?+ .remove = de2_lcd_remove,
->> ?+ .driver = {
->> ?+ .name = "sun8i-de2-tcon",
->> ?+ .of_match_table = of_match_ptr(de2_lcd_ids),
->> ?+ },
->> ?+};
->> ?diff --git a/drivers/gpu/drm/sun8i/de2_crtc.h b/drivers/gpu/drm/sun8i/de2_crtc.h
->> ?new file mode 100644
->> ?index 0000000..c0d34a7
->> ?--- /dev/null
->> ?+++ b/drivers/gpu/drm/sun8i/de2_crtc.h
->> ?@@ -0,0 +1,50 @@
->> ?+#ifndef __DE2_CRTC_H__
->> ?+#define __DE2_CRTC_H__
->> ?+/*
->> ?+ * Copyright (C) 2016 Jean-Fran??ois Moine
->> ?+ *
->> ?+ * This program is free software; you can redistribute it and/or
->> ?+ * modify it under the terms of the GNU General Public License as
->> ?+ * published by the Free Software Foundation; either version 2 of
->> ?+ * the License, or (at your option) any later version.
->> ?+ */
->> ?+
->> ?+#include <drm/drm_plane_helper.h>
->> ?+
->> ?+struct clk;
->> ?+struct reset_control;
->> ?+struct priv;
->> ?+
->> ?+/* planes */
->> ?+#define DE2_PRIMARY_PLANE 0
->> ?+#define DE2_CURSOR_PLANE 1
->> ?+#define DE2_N_PLANES 5 /* number of planes - see plane_tb[] in de2_plane.c */
->> ?+
->> ?+struct lcd {
->> ?+ void __iomem *mmio;
->> ?+
->> ?+ struct device *dev;
->> ?+ struct drm_crtc crtc;
->> ?+
->> ?+ struct priv *priv; /* DRM/DE private data */
->> ?+
->> ?+ u8 mixer; /* LCD (mixer) number */
->> ?+ u8 delayed; /* bitmap of planes with delayed update */
->> ?+
->> ?+ u8 clk_enabled; /* used for error in crtc_enable */
->> ?+
->> ?+ struct clk *clk;
->> ?+ struct clk *bus;
->> ?+ struct reset_control *reset;
->> ?+
->> ?+ struct drm_plane planes[DE2_N_PLANES];
->> ?+};
->> ?+
->> ?+#define crtc_to_lcd(x) container_of(x, struct lcd, crtc)
->> ?+
->> ?+/* in de2_plane.c */
->> ?+void de2_de_enable(struct lcd *lcd);
->> ?+void de2_de_disable(struct lcd *lcd);
->> ?+int de2_plane_init(struct drm_device *drm, struct lcd *lcd);
->> ?+
->> ?+#endif /* __DE2_CRTC_H__ */
->> ?diff --git a/drivers/gpu/drm/sun8i/de2_drv.c b/drivers/gpu/drm/sun8i/de2_drv.c
->> ?new file mode 100644
->> ?index 0000000..f96babe
->> ?--- /dev/null
->> ?+++ b/drivers/gpu/drm/sun8i/de2_drv.c
->> ?@@ -0,0 +1,317 @@
->> ?+/*
->> ?+ * Allwinner DRM driver - DE2 DRM driver
->> ?+ *
->> ?+ * Copyright (C) 2016 Jean-Francois Moine <moinejf@free.fr>
->> ?+ *
->> ?+ * This program is free software; you can redistribute it and/or
->> ?+ * modify it under the terms of the GNU General Public License as
->> ?+ * published by the Free Software Foundation; either version 2 of
->> ?+ * the License, or (at your option) any later version.
->> ?+ */
->> ?+
->> ?+#include <linux/module.h>
->> ?+#include <linux/of_device.h>
->> ?+#include <drm/drm_of.h>
->> ?+#include <linux/component.h>
->> ?+#include <drm/drm_atomic_helper.h>
->> ?+#include <drm/drm_crtc_helper.h>
->> ?+#include <drm/drm_fb_cma_helper.h>
->> ?+#include <drm/drm_gem_cma_helper.h>
->> ?+
->> ?+#include "de2_drv.h"
->> ?+
->> ?+#define DRIVER_NAME "sun8i-de2"
->> ?+#define DRIVER_DESC "Allwinner DRM DE2"
->> ?+#define DRIVER_DATE "20161101"
->> ?+#define DRIVER_MAJOR 1
->> ?+#define DRIVER_MINOR 0
->> ?+
->> ?+static const struct of_device_id de2_drm_of_match[] = {
->> ?+ { .compatible = "allwinner,sun8i-a83t-display-engine",
->> ?+ .data = (void *) SOC_A83T },
->> ?+ { .compatible = "allwinner,sun8i-h3-display-engine",
->> ?+ .data = (void *) SOC_H3 },
->> ?+ { },
->> ?+};
->> ?+MODULE_DEVICE_TABLE(of, de2_drm_of_match);
->> ?+
->> ?+static void de2_fb_output_poll_changed(struct drm_device *drm)
->> ?+{
->> ?+ struct priv *priv = drm_to_priv(drm);
->> ?+
->> ?+ if (priv->fbdev)
->> ?+ drm_fbdev_cma_hotplug_event(priv->fbdev);
->> ?+}
->> ?+
->> ?+static const struct drm_mode_config_funcs de2_mode_config_funcs = {
->> ?+ .fb_create = drm_fb_cma_create,
->> ?+ .output_poll_changed = de2_fb_output_poll_changed,
->> ?+ .atomic_check = drm_atomic_helper_check,
->> ?+ .atomic_commit = drm_atomic_helper_commit,
->> ?+};
->> ?+
->> ?+/* -- DRM operations -- */
->> ?+
->> ?+static void de2_lastclose(struct drm_device *drm)
->> ?+{
->> ?+ struct priv *priv = drm_to_priv(drm);
->> ?+
->> ?+ if (priv->fbdev)
->> ?+ drm_fbdev_cma_restore_mode(priv->fbdev);
->> ?+}
->> ?+
->> ?+static const struct file_operations de2_fops = {
->> ?+ .owner = THIS_MODULE,
->> ?+ .open = drm_open,
->> ?+ .release = drm_release,
->> ?+ .unlocked_ioctl = drm_ioctl,
->> ?+ .poll = drm_poll,
->> ?+ .read = drm_read,
->> ?+ .llseek = no_llseek,
->> ?+ .mmap = drm_gem_cma_mmap,
->> ?+};
->> ?+
->> ?+static struct drm_driver de2_drm_driver = {
->> ?+ .driver_features = DRIVER_GEM | DRIVER_MODESET | DRIVER_PRIME |
->> ?+ DRIVER_ATOMIC,
->> ?+ .lastclose = de2_lastclose,
->> ?+ .get_vblank_counter = drm_vblank_no_hw_counter,
->> ?+ .enable_vblank = de2_enable_vblank,
->> ?+ .disable_vblank = de2_disable_vblank,
->> ?+ .gem_free_object = drm_gem_cma_free_object,
->> ?+ .gem_vm_ops = &drm_gem_cma_vm_ops,
->> ?+ .prime_handle_to_fd = drm_gem_prime_handle_to_fd,
->> ?+ .prime_fd_to_handle = drm_gem_prime_fd_to_handle,
->> ?+ .gem_prime_import = drm_gem_prime_import,
->> ?+ .gem_prime_export = drm_gem_prime_export,
->> ?+ .gem_prime_get_sg_table = drm_gem_cma_prime_get_sg_table,
->> ?+ .gem_prime_import_sg_table = drm_gem_cma_prime_import_sg_table,
->> ?+ .gem_prime_vmap = drm_gem_cma_prime_vmap,
->> ?+ .gem_prime_vunmap = drm_gem_cma_prime_vunmap,
->> ?+ .gem_prime_mmap = drm_gem_cma_prime_mmap,
->> ?+ .dumb_create = drm_gem_cma_dumb_create,
->> ?+ .dumb_map_offset = drm_gem_cma_dumb_map_offset,
->> ?+ .dumb_destroy = drm_gem_dumb_destroy,
->> ?+ .fops = &de2_fops,
->> ?+ .name = DRIVER_NAME,
->> ?+ .desc = DRIVER_DESC,
->> ?+ .date = DRIVER_DATE,
->> ?+ .major = DRIVER_MAJOR,
->> ?+ .minor = DRIVER_MINOR,
->> ?+};
->> ?+
->> ?+/*
->> ?+ * Platform driver
->> ?+ */
->> ?+
->> ?+static int de2_drm_bind(struct device *dev)
->> ?+{
->> ?+ struct drm_device *drm;
->> ?+ struct priv *priv;
->> ?+ struct resource *res;
->> ?+ struct lcd *lcd;
->> ?+ int i, ret;
->> ?+
->> ?+ priv = kzalloc(sizeof(*priv), GFP_KERNEL);
->> ?+ if (!priv)
->> ?+ return -ENOMEM;
->> ?+
->> ?+ drm = &priv->drm;
->> ?+ dev_set_drvdata(dev, drm);
->> ?+
->> ?+ /* get the resources */
->> ?+ priv->soc_type = (int) of_match_device(de2_drm_of_match, dev)->data;
->> ?+
->> ?+ res = platform_get_resource(to_platform_device(dev),
->> ?+ IORESOURCE_MEM, 0);
->> ?+ if (!res) {
->> ?+ dev_err(dev, "failed to get memory resource\n");
->> ?+ ret = -EINVAL;
->> ?+ goto out1;
->> ?+ }
->> ?+
->> ?+ priv->mmio = devm_ioremap_resource(dev, res);
->> ?+ if (IS_ERR(priv->mmio)) {
->> ?+ ret = PTR_ERR(priv->mmio);
->> ?+ dev_err(dev, "failed to map registers %d\n", ret);
->> ?+ goto out1;
->> ?+ }
->> ?+
->> ?+ priv->gate = devm_clk_get(dev, "bus");
->> ?+ if (IS_ERR(priv->gate)) {
->> ?+ ret = PTR_ERR(priv->gate);
->> ?+ dev_err(dev, "bus gate err %d\n", ret);
->> ?+ goto out1;
->> ?+ }
->> ?+
->> ?+ priv->clk = devm_clk_get(dev, "clock");
->> ?+ if (IS_ERR(priv->clk)) {
->> ?+ ret = PTR_ERR(priv->clk);
->> ?+ dev_err(dev, "clock err %d\n", ret);
->> ?+ goto out1;
->> ?+ }
->> ?+
->> ?+ priv->reset = devm_reset_control_get(dev, NULL);
->> ?+ if (IS_ERR(priv->reset)) {
->> ?+ ret = PTR_ERR(priv->reset);
->> ?+ dev_err(dev, "reset err %d\n", ret);
->> ?+ goto out1;
->> ?+ }
->> ?+
->> ?+ mutex_init(&priv->mutex); /* protect DE I/O accesses */
->> ?+
->> ?+ ret = drm_dev_init(drm, &de2_drm_driver, dev);
->> ?+ if (ret != 0) {
->> ?+ dev_err(dev, "dev_init failed %d\n", ret);
->> ?+ goto out1;
->> ?+ }
->> ?+
->> ?+ drm_mode_config_init(drm);
->> ?+ drm->mode_config.min_width = 32; /* needed for cursor */
->> ?+ drm->mode_config.min_height = 32;
->> ?+ drm->mode_config.max_width = 1920;
->> ?+ drm->mode_config.max_height = 1080;
->> ?+ drm->mode_config.funcs = &de2_mode_config_funcs;
->> ?+
->> ?+ drm->irq_enabled = true;
->> ?+
->> ?+ /* start the subdevices */
->> ?+ ret = component_bind_all(dev, drm);
->> ?+ if (ret < 0)
->> ?+ goto out2;
->> ?+
->> ?+ /* initialize and disable vertical blanking on all CRTCs */
->> ?+ ret = drm_vblank_init(drm, drm->mode_config.num_crtc);
->> ?+ if (ret < 0)
->> ?+ dev_warn(dev, "vblank_init failed %d\n", ret);
->> ?+
->> ?+ for (i = 0; i < ARRAY_SIZE(priv->lcds); i++) {
->> ?+ lcd = priv->lcds[i];
->> ?+ if (lcd)
->> ?+ de2_vblank_reset(lcd);
->> ?+ }
->> ?+
->> ?+ drm_mode_config_reset(drm);
->> ?+
->> ?+ priv->fbdev = drm_fbdev_cma_init(drm,
->> ?+ 32, /* bpp */
->> ?+ drm->mode_config.num_crtc,
->> ?+ drm->mode_config.num_connector);
->> ?+ if (IS_ERR(priv->fbdev)) {
->> ?+ ret = PTR_ERR(priv->fbdev);
->> ?+ priv->fbdev = NULL;
->> ?+ goto out3;
->> ?+ }
->> ?+
->> ?+ drm_kms_helper_poll_init(drm);
->> ?+
->> ?+ ret = drm_dev_register(drm, 0);
->> ?+ if (ret < 0)
->> ?+ goto out4;
->> ?+
->> ?+ return 0;
->> ?+
->> ?+out4:
->> ?+ drm_fbdev_cma_fini(priv->fbdev);
->> ?+out3:
->> ?+ component_unbind_all(dev, drm);
->> ?+out2:
->> ?+ drm_dev_unref(drm);
->> ?+out1:
->> ?+ kfree(priv);
->> ?+ return ret;
->> ?+}
->> ?+
->> ?+static void de2_drm_unbind(struct device *dev)
->> ?+{
->> ?+ struct drm_device *drm = dev_get_drvdata(dev);
->> ?+ struct priv *priv = drm_to_priv(drm);
->> ?+
->> ?+ drm_dev_unregister(drm);
->> ?+
->> ?+ drm_fbdev_cma_fini(priv->fbdev);
->> ?+ drm_kms_helper_poll_fini(drm);
->> ?+ drm_vblank_cleanup(drm);
->> ?+ drm_mode_config_cleanup(drm);
->> ?+
->> ?+ component_unbind_all(dev, drm);
->> ?+
->> ?+ kfree(priv);
->> ?+}
->> ?+
->> ?+static const struct component_master_ops de2_drm_comp_ops = {
->> ?+ .bind = de2_drm_bind,
->> ?+ .unbind = de2_drm_unbind,
->> ?+};
->> ?+
->> ?+/*
->> ?+ * drm_of_component_probe() does:
->> ?+ * - bind of the ports (lcd-controller.port)
->> ?+ * - bind of the remote nodes (hdmi, tve..)
->> ?+ */
->> ?+static int compare_of(struct device *dev, void *data)
->> ?+{
->> ?+ struct device_node *np = data;
->> ?+
->> ?+ if (of_node_cmp(np->name, "port") == 0) {
->> ?+ np = of_get_parent(np);
->> ?+ of_node_put(np);
->> ?+ }
->> ?+ return dev->of_node == np;
->> ?+}
->> ?+
->> ?+static int de2_drm_probe(struct platform_device *pdev)
->> ?+{
->> ?+ int ret;
->> ?+
->> ?+ ret = drm_of_component_probe(&pdev->dev,
->> ?+ compare_of,
->> ?+ &de2_drm_comp_ops);
->> ?+ if (ret == -EINVAL)
->> ?+ ret = -ENXIO;
->> ?+ return ret;
->> ?+}
->> ?+
->> ?+static int de2_drm_remove(struct platform_device *pdev)
->> ?+{
->> ?+ component_master_del(&pdev->dev, &de2_drm_comp_ops);
->> ?+
->> ?+ return 0;
->> ?+}
->> ?+
->> ?+static struct platform_driver de2_drm_platform_driver = {
->> ?+ .probe = de2_drm_probe,
->> ?+ .remove = de2_drm_remove,
->> ?+ .driver = {
->> ?+ .name = DRIVER_NAME,
->> ?+ .of_match_table = de2_drm_of_match,
->> ?+ },
->> ?+};
->> ?+
->> ?+static int __init de2_drm_init(void)
->> ?+{
->> ?+ int ret;
->> ?+
->> ?+ ret = platform_driver_register(&de2_lcd_platform_driver);
->> ?+ if (ret < 0)
->> ?+ return ret;
->> ?+
->> ?+ ret = platform_driver_register(&de2_drm_platform_driver);
->> ?+ if (ret < 0)
->> ?+ platform_driver_unregister(&de2_lcd_platform_driver);
->> ?+
->> ?+ return ret;
->> ?+}
->> ?+
->> ?+static void __exit de2_drm_fini(void)
->> ?+{
->> ?+ platform_driver_unregister(&de2_lcd_platform_driver);
->> ?+ platform_driver_unregister(&de2_drm_platform_driver);
->> ?+}
->> ?+
->> ?+module_init(de2_drm_init);
->> ?+module_exit(de2_drm_fini);
->> ?+
->> ?+MODULE_AUTHOR("Jean-Francois Moine <moinejf@free.fr>");
->> ?+MODULE_DESCRIPTION("Allwinner DE2 DRM Driver");
->> ?+MODULE_LICENSE("GPL v2");
->> ?diff --git a/drivers/gpu/drm/sun8i/de2_drv.h b/drivers/gpu/drm/sun8i/de2_drv.h
->> ?new file mode 100644
->> ?index 0000000..c42c30a
->> ?--- /dev/null
->> ?+++ b/drivers/gpu/drm/sun8i/de2_drv.h
->> ?@@ -0,0 +1,48 @@
->> ?+#ifndef __DE2_DRM_H__
->> ?+#define __DE2_DRM_H__
->> ?+/*
->> ?+ * Copyright (C) 2016 Jean-Fran??ois Moine
->> ?+ *
->> ?+ * This program is free software; you can redistribute it and/or
->> ?+ * modify it under the terms of the GNU General Public License as
->> ?+ * published by the Free Software Foundation; either version 2 of
->> ?+ * the License, or (at your option) any later version.
->> ?+ */
->> ?+
->> ?+#include <drm/drmP.h>
->> ?+#include <linux/clk.h>
->> ?+#include <linux/reset.h>
->> ?+
->> ?+struct drm_fbdev_cma;
->> ?+struct lcd;
->> ?+
->> ?+#define N_LCDS 2
->> ?+
->> ?+struct priv {
->> ?+ struct drm_device drm;
->> ?+ void __iomem *mmio;
->> ?+ struct clk *clk;
->> ?+ struct clk *gate;
->> ?+ struct reset_control *reset;
->> ?+
->> ?+ struct mutex mutex; /* protect DE I/O access */
->> ?+ u8 soc_type;
->> ?+#define SOC_A83T 0
->> ?+#define SOC_H3 1
->> ?+ u8 started; /* bitmap of started mixers */
->> ?+ u8 clean; /* bitmap of clean mixers */
->> ?+
->> ?+ struct drm_fbdev_cma *fbdev;
->> ?+
->> ?+ struct lcd *lcds[N_LCDS]; /* CRTCs */
->> ?+};
->> ?+
->> ?+#define drm_to_priv(x) container_of(x, struct priv, drm)
->> ?+
->> ?+/* in de2_crtc.c */
->> ?+int de2_enable_vblank(struct drm_device *drm, unsigned int crtc);
->> ?+void de2_disable_vblank(struct drm_device *drm, unsigned int crtc);
->> ?+void de2_vblank_reset(struct lcd *lcd);
->> ?+extern struct platform_driver de2_lcd_platform_driver;
->> ?+
->> ?+#endif /* __DE2_DRM_H__ */
->> ?diff --git a/drivers/gpu/drm/sun8i/de2_plane.c b/drivers/gpu/drm/sun8i/de2_plane.c
->> ?new file mode 100644
->> ?index 0000000..2fd72dc
->> ?--- /dev/null
->> ?+++ b/drivers/gpu/drm/sun8i/de2_plane.c
->> ?@@ -0,0 +1,734 @@
->> ?+/*
->> ?+ * Allwinner DRM driver - Display Engine 2
->> ?+ *
->> ?+ * Copyright (C) 2016 Jean-Francois Moine <moinejf@free.fr>
->> ?+ * Adapted from the sun8iw6 and sun8iw7 disp2 drivers
->> ?+ * Copyright (c) 2016 Allwinnertech Co., Ltd.
->> ?+ *
->> ?+ * This program is free software; you can redistribute it and/or
->> ?+ * modify it under the terms of the GNU General Public License as
->> ?+ * published by the Free Software Foundation; either version 2 of
->> ?+ * the License, or (at your option) any later version.
->> ?+ */
->> ?+
->> ?+#include <linux/io.h>
->> ?+#include <drm/drm_atomic_helper.h>
->> ?+#include <drm/drm_crtc_helper.h>
->> ?+#include <drm/drm_fb_cma_helper.h>
->> ?+#include <drm/drm_gem_cma_helper.h>
->> ?+#include <drm/drm_plane_helper.h>
->> ?+
->> ?+#include "de2_drv.h"
->> ?+#include "de2_crtc.h"
->> ?+
->> ?+/* DE2 I/O map */
->> ?+
->> ?+#define DE2_MOD_REG 0x0000 /* 1 bit per LCD */
->> ?+#define DE2_GATE_REG 0x0004
->> ?+#define DE2_RESET_REG 0x0008
->> ?+#define DE2_DIV_REG 0x000c /* 4 bits per LCD */
->> ?+#define DE2_SEL_REG 0x0010
->> ?+
->> ?+#define DE2_MIXER0_BASE 0x00100000 /* LCD 0 */
->> ?+#define DE2_MIXER1_BASE 0x00200000 /* LCD 1 */
->> ?+
->> ?+/* mixer registers (addr / mixer base) */
->> ?+#define MIXER_GLB_REGS 0x00000 /* global control */
->> ?+#define MIXER_BLD_REGS 0x01000 /* alpha blending */
->> ?+#define MIXER_CHAN_REGS 0x02000 /* VI/UI overlay channels */
->> ?+#define MIXER_CHAN_SZ 0x1000 /* size of a channel */
->> ?+#define MIXER_VSU_REGS 0x20000 /* VSU */
->> ?+#define MIXER_GSU1_REGS 0x30000 /* GSUs */
->> ?+#define MIXER_GSU2_REGS 0x40000
->> ?+#define MIXER_GSU3_REGS 0x50000
->> ?+#define MIXER_FCE_REGS 0xa0000 /* FCE */
->> ?+#define MIXER_BWS_REGS 0xa2000 /* BWS */
->> ?+#define MIXER_LTI_REGS 0xa4000 /* LTI */
->> ?+#define MIXER_PEAK_REGS 0xa6000 /* PEAK */
->> ?+#define MIXER_ASE_REGS 0xa8000 /* ASE */
->> ?+#define MIXER_FCC_REGS 0xaa000 /* FCC */
->> ?+#define MIXER_DCSC_REGS 0xb0000 /* DCSC/SMBL */
->> ?+
->> ?+/* global control */
->> ?+#define MIXER_GLB_CTL_REG 0x00
->> ?+#define MIXER_GLB_CTL_rt_en BIT(0)
->> ?+#define MIXER_GLB_CTL_finish_irq_en BIT(4)
->> ?+#define MIXER_GLB_CTL_rtwb_port BIT(12)
->> ?+#define MIXER_GLB_STATUS_REG 0x04
->> ?+#define MIXER_GLB_DBUFF_REG 0x08
->> ?+#define MIXER_GLB_SIZE_REG 0x0c
->> ?+
->> ?+/* alpha blending */
->> ?+#define MIXER_BLD_FCOLOR_CTL_REG 0x00
->> ?+#define MIXER_BLD_FCOLOR_CTL_PEN(pipe) (0x0100 << (pipe))
->> ?+#define MIXER_BLD_ATTR_N 4 /* number of attribute blocks */
->> ?+#define MIXER_BLD_ATTR_SIZE (4 * 4) /* size of an attribute block */
->> ?+#define MIXER_BLD_ATTRx_FCOLOR(x) (0x04 + MIXER_BLD_ATTR_SIZE * (x))
->> ?+#define MIXER_BLD_ATTRx_INSIZE(x) (0x08 + MIXER_BLD_ATTR_SIZE * (x))
->> ?+#define MIXER_BLD_ATTRx_OFFSET(x) (0x0c + MIXER_BLD_ATTR_SIZE * (x))
->> ?+#define MIXER_BLD_ROUTE_REG 0x80
->> ?+#define MIXER_BLD_ROUTE(chan, pipe) ((chan) << ((pipe) * 4))
->> ?+#define MIXER_BLD_PREMULTIPLY_REG 0x84
->> ?+#define MIXER_BLD_BKCOLOR_REG 0x88
->> ?+#define MIXER_BLD_OUTPUT_SIZE_REG 0x8c
->> ?+#define MIXER_BLD_MODEx_REG(x) (0x90 + 4 * (x)) /* x = 0..3 */
->> ?+#define MIXER_BLD_MODE_SRCOVER 0x03010301
->> ?+#define MIXER_BLD_OUT_CTL_REG 0xfc
->> ?+
->> ?+/* VI channel (channel 0) */
->> ?+#define VI_CFG_N 4 /* number of layers */
->> ?+#define VI_CFG_SIZE 0x30 /* size of a layer */
->> ?+#define VI_CFGx_ATTR(l) (0x00 + VI_CFG_SIZE * (l))
->> ?+#define VI_CFG_ATTR_en BIT(0)
->> ?+#define VI_CFG_ATTR_fcolor_en BIT(4)
->> ?+#define VI_CFG_ATTR_fmt_SHIFT 8
->> ?+#define VI_CFG_ATTR_fmt_MASK GENMASK(12, 8)
->> ?+#define VI_CFG_ATTR_ui_sel BIT(15)
->> ?+#define VI_CFG_ATTR_top_down BIT(23)
->> ?+#define VI_CFGx_SIZE(l) (0x04 + VI_CFG_SIZE * (l))
->> ?+#define VI_CFGx_COORD(l) (0x08 + VI_CFG_SIZE * (l))
->> ?+#define VI_N_PLANES 3
->> ?+#define VI_CFGx_PITCHy(l, p) (0x0c + VI_CFG_SIZE * (l) + 4 * (p))
->> ?+#define VI_CFGx_TOP_LADDRy(l, p) (0x18 + VI_CFG_SIZE * (l) + 4 * (p))
->> ?+#define VI_CFGx_BOT_LADDRy(l, p) (0x24 + VI_CFG_SIZE * (l) + 4 * (p))
->> ?+#define VI_FCOLORx(l) (0xc0 + 4 * (l))
->> ?+#define VI_TOP_HADDRx(p) (0xd0 + 4 * (p))
->> ?+#define VI_BOT_HADDRx(p) (0xdc + 4 * (p))
->> ?+#define VI_OVL_SIZEx(n) (0xe8 + 4 * (n))
->> ?+#define VI_HORI_DSx(n) (0xf0 + 4 * (n))
->> ?+#define VI_VERT_DSx(n) (0xf8 + 4 * (n))
->> ?+#define VI_SIZE 0x100
->> ?+
->> ?+/* UI channel (channels 1..3) */
->> ?+#define UI_CFG_N 4 /* number of layers */
->> ?+#define UI_CFG_SIZE (8 * 4) /* size of a layer */
->> ?+#define UI_CFGx_ATTR(l) (0x00 + UI_CFG_SIZE * (l))
->> ?+#define UI_CFG_ATTR_en BIT(0)
->> ?+#define UI_CFG_ATTR_alpmod_SHIFT 1
->> ?+#define UI_CFG_ATTR_alpmod_MASK GENMASK(2, 1)
->> ?+#define UI_CFG_ATTR_fcolor_en BIT(4)
->> ?+#define UI_CFG_ATTR_fmt_SHIFT 8
->> ?+#define UI_CFG_ATTR_fmt_MASK GENMASK(12, 8)
->> ?+#define UI_CFG_ATTR_top_down BIT(23)
->> ?+#define UI_CFG_ATTR_alpha_SHIFT 24
->> ?+#define UI_CFG_ATTR_alpha_MASK GENMASK(31, 24)
->> ?+#define UI_CFGx_SIZE(l) (0x04 + UI_CFG_SIZE * (l))
->> ?+#define UI_CFGx_COORD(l) (0x08 + UI_CFG_SIZE * (l))
->> ?+#define UI_CFGx_PITCH(l) (0x0c + UI_CFG_SIZE * (l))
->> ?+#define UI_CFGx_TOP_LADDR(l) (0x10 + UI_CFG_SIZE * (l))
->> ?+#define UI_CFGx_BOT_LADDR(l) (0x14 + UI_CFG_SIZE * (l))
->> ?+#define UI_CFGx_FCOLOR(l) (0x18 + UI_CFG_SIZE * (l))
->> ?+#define UI_TOP_HADDR 0x80
->> ?+#define UI_BOT_HADDR 0x84
->> ?+#define UI_OVL_SIZE 0x88
->> ?+#define UI_SIZE 0x8c
->> ?+
->> ?+/* coordinates and sizes */
->> ?+#define XY(x, y) (((y) << 16) | (x))
->> ?+#define WH(w, h) ((((h) - 1) << 16) | ((w) - 1))
->> ?+
->> ?+/* UI video formats */
->> ?+#define DE2_FORMAT_ARGB_8888 0
->> ?+#define DE2_FORMAT_BGRA_8888 3
->> ?+#define DE2_FORMAT_XRGB_8888 4
->> ?+#define DE2_FORMAT_RGB_888 8
->> ?+#define DE2_FORMAT_BGR_888 9
->> ?+
->> ?+/* VI video formats */
->> ?+#define DE2_FORMAT_YUV422_I_YVYU 1 /* YVYU */
->> ?+#define DE2_FORMAT_YUV422_I_UYVY 2 /* UYVY */
->> ?+#define DE2_FORMAT_YUV422_I_YUYV 3 /* YUYV */
->> ?+#define DE2_FORMAT_YUV422_P 6 /* YYYY UU VV planar */
->> ?+#define DE2_FORMAT_YUV420_P 10 /* YYYY U V planar */
->> ?+
->> ?+/* plane formats */
->> ?+static const uint32_t ui_formats[] = {
->> ?+ DRM_FORMAT_ARGB8888,
->> ?+ DRM_FORMAT_BGRA8888,
->> ?+ DRM_FORMAT_XRGB8888,
->> ?+ DRM_FORMAT_RGB888,
->> ?+ DRM_FORMAT_BGR888,
->> ?+};
->> ?+
->> ?+static const uint32_t vi_formats[] = {
->> ?+ DRM_FORMAT_XRGB8888,
->> ?+ DRM_FORMAT_YUYV,
->> ?+ DRM_FORMAT_YVYU,
->> ?+ DRM_FORMAT_YUV422,
->> ?+ DRM_FORMAT_YUV420,
->> ?+ DRM_FORMAT_UYVY,
->> ?+ DRM_FORMAT_BGRA8888,
->> ?+ DRM_FORMAT_RGB888,
->> ?+ DRM_FORMAT_BGR888,
->> ?+};
->> ?+
->> ?+/*
->> ?+ * plane table
->> ?+ *
->> ?+ * The chosen channel/layer assignment of the planes respects
->> ?+ * the following constraints:
->> ?+ * - the cursor must be in a channel higher than the primary channel
->> ?+ * - there are 4 channels in the LCD 0 and only 2 channels in the LCD 1
->> ?+ */
->> ?+static const struct {
->> ?+ u8 chan;
->> ?+ u8 layer;
->> ?+ u8 pipe;
->> ?+ u8 type; /* plane type */
->> ?+ const uint32_t *formats;
->> ?+ u8 n_formats;
->> ?+} plane_tb[] = {
->> ?+ [DE2_PRIMARY_PLANE] = { /* primary plane: channel 0 (VI) */
->> ?+ 0, 0, 0,
->> ?+ DRM_PLANE_TYPE_PRIMARY,
->> ?+ ui_formats, ARRAY_SIZE(ui_formats),
->> ?+ },
->> ?+ [DE2_CURSOR_PLANE] = { /* cursor: channel 1 (UI) */
->> ?+ 1, 0, 1,
->> ?+ DRM_PLANE_TYPE_CURSOR,
->> ?+ ui_formats, ARRAY_SIZE(ui_formats),
->> ?+ },
->> ?+ {
->> ?+ 0, 1, 0, /* 1st overlay: channel 0, layer 1 */
->> ?+ DRM_PLANE_TYPE_OVERLAY,
->> ?+ vi_formats, ARRAY_SIZE(vi_formats),
->> ?+ },
->> ?+ {
->> ?+ 0, 2, 0, /* 2nd overlay: channel 0, layer 2 */
->> ?+ DRM_PLANE_TYPE_OVERLAY,
->> ?+ vi_formats, ARRAY_SIZE(vi_formats),
->> ?+ },
->> ?+ {
->> ?+ 0, 3, 0, /* 3rd overlay: channel 0, layer 3 */
->> ?+ DRM_PLANE_TYPE_OVERLAY,
->> ?+ vi_formats, ARRAY_SIZE(vi_formats),
->> ?+ },
->> ?+};
->> ?+
->> ?+static inline void andl_relaxed(void __iomem *addr, u32 val)
->> ?+{
->> ?+ writel_relaxed(readl_relaxed(addr) & val, addr);
->> ?+}
->> ?+
->> ?+static inline void orl_relaxed(void __iomem *addr, u32 val)
->> ?+{
->> ?+ writel_relaxed(readl_relaxed(addr) | val, addr);
->> ?+}
->> ?+
->> ?+/* alert the DE processor about changes in a mixer configuration */
->> ?+static void de2_mixer_select(struct priv *priv,
->> ?+ int mixer,
->> ?+ void __iomem *mixer_io)
->> ?+{
->> ?+ /* select the mixer */
->> ?+ andl_relaxed(priv->mmio + DE2_SEL_REG, ~1);
->> ?+
->> ?+ /* double register switch */
->> ?+ writel_relaxed(1, mixer_io + MIXER_GLB_REGS + MIXER_GLB_DBUFF_REG);
->> ?+}
->> ?+
->> ?+/*
->> ?+ * cleanup a mixer
->> ?+ *
->> ?+ * This is needed only once after power on.
->> ?+ */
->> ?+static void de2_mixer_cleanup(struct priv *priv, int mixer,
->> ?+ u32 size)
->> ?+{
->> ?+ void __iomem *mixer_io = priv->mmio;
->> ?+ void __iomem *chan_io;
->> ?+ u32 data;
->> ?+ unsigned int i;
->> ?+
->> ?+ mixer_io += (mixer == 0) ? DE2_MIXER0_BASE : DE2_MIXER1_BASE;
->> ?+ chan_io = mixer_io + MIXER_CHAN_REGS;
->> ?+
->> ?+ andl_relaxed(priv->mmio + DE2_SEL_REG, ~1);
->> ?+ writel_relaxed(1, mixer_io + MIXER_GLB_REGS + MIXER_GLB_DBUFF_REG);
->> ?+
->> ?+ writel_relaxed(MIXER_GLB_CTL_rt_en,
->> ?+ mixer_io + MIXER_GLB_REGS + MIXER_GLB_CTL_REG);
->> ?+ writel_relaxed(0, mixer_io + MIXER_GLB_REGS + MIXER_GLB_STATUS_REG);
->> ?+
->> ?+ writel_relaxed(size, mixer_io + MIXER_GLB_REGS + MIXER_GLB_SIZE_REG);
->> ?+
->> ?+ /*
->> ?+ * clear the VI/UI channels
->> ?+ * LCD0: 1 VI and 3 UIs
->> ?+ * LCD1: 1 VI and 1 UI
->> ?+ */
->> ?+ memset_io(chan_io, 0, VI_SIZE);
->> ?+ memset_io(chan_io + MIXER_CHAN_SZ, 0, UI_SIZE);
->> ?+ if (mixer == 0) {
->> ?+ memset_io(chan_io + MIXER_CHAN_SZ * 2, 0, UI_SIZE);
->> ?+ memset_io(chan_io + MIXER_CHAN_SZ * 3, 0, UI_SIZE);
->> ?+ }
->> ?+
->> ?+ /* alpha blending */
->> ?+ writel_relaxed(0x00000001 | /* fcolor for primary */
->> ?+ MIXER_BLD_FCOLOR_CTL_PEN(0),
->> ?+ mixer_io + MIXER_BLD_REGS + MIXER_BLD_FCOLOR_CTL_REG);
->> ?+ for (i = 0; i < MIXER_BLD_ATTR_N; i++) {
->> ?+ writel_relaxed(0xff000000,
->> ?+ mixer_io + MIXER_BLD_REGS + MIXER_BLD_ATTRx_FCOLOR(i));
->> ?+ writel_relaxed(size,
->> ?+ mixer_io + MIXER_BLD_REGS + MIXER_BLD_ATTRx_INSIZE(i));
->> ?+ writel_relaxed(0,
->> ?+ mixer_io + MIXER_BLD_REGS + MIXER_BLD_ATTRx_OFFSET(i));
->> ?+ }
->> ?+ writel_relaxed(0, mixer_io + MIXER_BLD_REGS + MIXER_BLD_OUT_CTL_REG);
->> ?+
->> ?+ /* prepare the pipe route for the planes */
->> ?+ data = 0;
->> ?+ for (i = 0; i < DE2_N_PLANES; i++)
->> ?+ data |= MIXER_BLD_ROUTE(plane_tb[i].chan, plane_tb[i].pipe);
->> ?+ writel_relaxed(data, mixer_io + MIXER_BLD_REGS + MIXER_BLD_ROUTE_REG);
->> ?+
->> ?+ writel_relaxed(0, mixer_io + MIXER_BLD_REGS +
->> ?+ MIXER_BLD_PREMULTIPLY_REG);
->> ?+ writel_relaxed(0xff000000, mixer_io + MIXER_BLD_REGS +
->> ?+ MIXER_BLD_BKCOLOR_REG);
->> ?+ writel_relaxed(size, mixer_io + MIXER_BLD_REGS +
->> ?+ MIXER_BLD_OUTPUT_SIZE_REG);
->> ?+ writel_relaxed(MIXER_BLD_MODE_SRCOVER,
->> ?+ mixer_io + MIXER_BLD_REGS + MIXER_BLD_MODEx_REG(0));
->> ?+ writel_relaxed(MIXER_BLD_MODE_SRCOVER,
->> ?+ mixer_io + MIXER_BLD_REGS + MIXER_BLD_MODEx_REG(1));
->> ?+
->> ?+ /* disable the enhancements */
->> ?+ writel_relaxed(0, mixer_io + MIXER_VSU_REGS);
->> ?+ writel_relaxed(0, mixer_io + MIXER_GSU1_REGS);
->> ?+ writel_relaxed(0, mixer_io + MIXER_GSU2_REGS);
->> ?+ writel_relaxed(0, mixer_io + MIXER_GSU3_REGS);
->> ?+ writel_relaxed(0, mixer_io + MIXER_FCE_REGS);
->> ?+ writel_relaxed(0, mixer_io + MIXER_BWS_REGS);
->> ?+ writel_relaxed(0, mixer_io + MIXER_LTI_REGS);
->> ?+ writel_relaxed(0, mixer_io + MIXER_PEAK_REGS);
->> ?+ writel_relaxed(0, mixer_io + MIXER_ASE_REGS);
->> ?+ writel_relaxed(0, mixer_io + MIXER_FCC_REGS);
->> ?+ writel_relaxed(0, mixer_io + MIXER_DCSC_REGS);
->> ?+}
->> ?+
->> ?+/* enable a mixer */
->> ?+static void de2_mixer_enable(struct lcd *lcd)
->> ?+{
->> ?+ struct priv *priv = lcd->priv;
->> ?+ void __iomem *mixer_io = priv->mmio;
->> ?+ struct drm_display_mode *mode = &lcd->crtc.mode;
->> ?+ u32 size = WH(mode->hdisplay, mode->vdisplay);
->> ?+ u32 data;
->> ?+ int mixer = lcd->mixer;
->> ?+ int i;
->> ?+
->> ?+ mixer_io += (mixer == 0) ? DE2_MIXER0_BASE : DE2_MIXER1_BASE;
->> ?+
->> ?+ /* if not done yet, start the DE processor */
->> ?+ if (!priv->started) {
->> ?+ reset_control_deassert(priv->reset);
->> ?+ clk_prepare_enable(priv->gate);
->> ?+ clk_prepare_enable(priv->clk);
->> ?+ }
->> ?+ priv->started |= 1 << mixer;
->> ?+
->> ?+ /* set the A83T clock divider (500 / 2) = 250MHz */
->> ?+ if (priv->soc_type == SOC_A83T)
->> ?+ writel_relaxed(0x00000011, /* div = 2 for both LCDs */
->> ?+ priv->mmio + DE2_DIV_REG);
->> ?+
->> ?+ /* deassert the mixer and enable its clock */
->> ?+ orl_relaxed(priv->mmio + DE2_RESET_REG, mixer == 0 ? 1 : 4);
->> ?+ data = 1 << mixer; /* 1 bit / lcd */
->> ?+ orl_relaxed(priv->mmio + DE2_GATE_REG, data);
->> ?+ orl_relaxed(priv->mmio + DE2_MOD_REG, data);
->> ?+
->> ?+ /* if not done yet, cleanup and enable */
->> ?+ if (!(priv->clean & (1 << mixer))) {
->> ?+ priv->clean |= 1 << mixer;
->> ?+ de2_mixer_cleanup(priv, mixer, size);
->> ?+ return;
->> ?+ }
->> ?+
->> ?+ /* enable */
->> ?+ de2_mixer_select(priv, mixer, mixer_io);
->> ?+
->> ?+ writel_relaxed(MIXER_GLB_CTL_rt_en,
->> ?+ mixer_io + MIXER_GLB_REGS + MIXER_GLB_CTL_REG);
->> ?+ writel_relaxed(0, mixer_io + MIXER_GLB_REGS + MIXER_GLB_STATUS_REG);
->> ?+
->> ?+ /* set the size of the frame buffer */
->> ?+ writel_relaxed(size, mixer_io + MIXER_GLB_REGS + MIXER_GLB_SIZE_REG);
->> ?+ for (i = 0; i < MIXER_BLD_ATTR_N; i++)
->> ?+ writel_relaxed(size, mixer_io + MIXER_BLD_REGS +
->> ?+ MIXER_BLD_ATTRx_INSIZE(i));
->> ?+ writel_relaxed(size, mixer_io + MIXER_BLD_REGS +
->> ?+ MIXER_BLD_OUTPUT_SIZE_REG);
->> ?+
->> ?+ writel_relaxed(mode->flags & DRM_MODE_FLAG_INTERLACE ? 2 : 0,
->> ?+ mixer_io + MIXER_BLD_REGS + MIXER_BLD_OUT_CTL_REG);
->> ?+}
->> ?+
->> ?+/* enable a LCD (DE mixer) */
->> ?+void de2_de_enable(struct lcd *lcd)
->> ?+{
->> ?+ mutex_lock(&lcd->priv->mutex);
->> ?+
->> ?+ de2_mixer_enable(lcd);
->> ?+
->> ?+ mutex_unlock(&lcd->priv->mutex);
->> ?+}
->> ?+
->> ?+/* disable a LCD (DE mixer) */
->> ?+void de2_de_disable(struct lcd *lcd)
->> ?+{
->> ?+ struct priv *priv = lcd->priv;
->> ?+ void __iomem *mixer_io = priv->mmio;
->> ?+ int mixer = lcd->mixer;
->> ?+ u32 data;
->> ?+
->> ?+ mixer_io += (mixer == 0) ? DE2_MIXER0_BASE : DE2_MIXER1_BASE;
->> ?+
->> ?+ mutex_lock(&priv->mutex);
->> ?+
->> ?+ de2_mixer_select(priv, mixer, mixer_io);
->> ?+
->> ?+ writel_relaxed(0, mixer_io + MIXER_GLB_REGS + MIXER_GLB_CTL_REG);
->> ?+
->> ?+ data = ~(1 << mixer);
->> ?+ andl_relaxed(priv->mmio + DE2_MOD_REG, data);
->> ?+ andl_relaxed(priv->mmio + DE2_GATE_REG, data);
->> ?+ andl_relaxed(priv->mmio + DE2_RESET_REG, data);
->> ?+
->> ?+ mutex_unlock(&priv->mutex);
->> ?+
->> ?+ /* if all mixers are disabled, stop the DE */
->> ?+ priv->started &= ~(1 << mixer);
->> ?+ if (!priv->started) {
->> ?+ clk_disable_unprepare(priv->clk);
->> ?+ clk_disable_unprepare(priv->gate);
->> ?+ reset_control_assert(priv->reset);
->> ?+ }
->> ?+}
->> ?+
->> ?+static void de2_vi_update(void __iomem *chan_io,
->> ?+ struct drm_gem_cma_object *gem,
->> ?+ int layer,
->> ?+ unsigned int fmt,
->> ?+ u32 ui_sel,
->> ?+ u32 size,
->> ?+ u32 coord,
->> ?+ struct drm_framebuffer *fb,
->> ?+ u32 screen_size)
->> ?+{
->> ?+ int i;
->> ?+
->> ?+ writel_relaxed(VI_CFG_ATTR_en |
->> ?+ (fmt << VI_CFG_ATTR_fmt_SHIFT) |
->> ?+ ui_sel,
->> ?+ chan_io + VI_CFGx_ATTR(layer));
->> ?+ writel_relaxed(size, chan_io + VI_CFGx_SIZE(layer));
->> ?+ writel_relaxed(coord, chan_io + VI_CFGx_COORD(layer));
->> ?+ for (i = 0; i < VI_N_PLANES; i++) {
->> ?+ writel_relaxed(fb->pitches[i] ? fb->pitches[i] :
->> ?+ fb->pitches[0],
->> ?+ chan_io + VI_CFGx_PITCHy(layer, i));
->> ?+ writel_relaxed(gem->paddr + fb->offsets[i],
->> ?+ chan_io + VI_CFGx_TOP_LADDRy(layer, i));
->> ?+ }
->> ?+ writel_relaxed(0xff000000, chan_io + VI_FCOLORx(layer));
->> ?+ if (layer == 0) {
->> ?+ writel_relaxed(screen_size,
->> ?+ chan_io + VI_OVL_SIZEx(0));
->> ?+ }
->> ?+}
->> ?+
->> ?+static void de2_ui_update(void __iomem *chan_io,
->> ?+ struct drm_gem_cma_object *gem,
->> ?+ int layer,
->> ?+ unsigned int fmt,
->> ?+ u32 alpha_glob,
->> ?+ u32 size,
->> ?+ u32 coord,
->> ?+ struct drm_framebuffer *fb,
->> ?+ u32 screen_size)
->> ?+{
->> ?+ writel_relaxed(UI_CFG_ATTR_en |
->> ?+ (fmt << UI_CFG_ATTR_fmt_SHIFT) |
->> ?+ alpha_glob,
->> ?+ chan_io + UI_CFGx_ATTR(layer));
->> ?+ writel_relaxed(size, chan_io + UI_CFGx_SIZE(layer));
->> ?+ writel_relaxed(coord, chan_io + UI_CFGx_COORD(layer));
->> ?+ writel_relaxed(fb->pitches[0], chan_io + UI_CFGx_PITCH(layer));
->> ?+ writel_relaxed(gem->paddr + fb->offsets[0],
->> ?+ chan_io + UI_CFGx_TOP_LADDR(layer));
->> ?+ if (layer == 0)
->> ?+ writel_relaxed(screen_size, chan_io + UI_OVL_SIZE);
->> ?+}
->> ?+
->> ?+static void de2_plane_update(struct priv *priv, struct lcd *lcd,
->> ?+ int plane_num,
->> ?+ struct drm_plane_state *state,
->> ?+ struct drm_plane_state *old_state)
->> ?+{
->> ?+ void __iomem *mixer_io = priv->mmio;
->> ?+ void __iomem *chan_io;
->> ?+ struct drm_framebuffer *fb = state->fb;
->> ?+ struct drm_gem_cma_object *gem;
->> ?+ u32 size = WH(state->crtc_w, state->crtc_h);
->> ?+ u32 coord, screen_size;
->> ?+ u32 fcolor;
->> ?+ u32 ui_sel, alpha_glob;
->> ?+ int mixer = lcd->mixer;
->> ?+ int chan, layer, x, y;
->> ?+ unsigned int fmt;
->> ?+
->> ?+ chan = plane_tb[plane_num].chan;
->> ?+ layer = plane_tb[plane_num].layer;
->> ?+
->> ?+ mixer_io += (mixer == 0) ? DE2_MIXER0_BASE : DE2_MIXER1_BASE;
->> ?+ chan_io = mixer_io + MIXER_CHAN_REGS + MIXER_CHAN_SZ * chan;
->> ?+
->> ?+ x = state->crtc_x >= 0 ? state->crtc_x : 0;
->> ?+ y = state->crtc_y >= 0 ? state->crtc_y : 0;
->> ?+ coord = XY(x, y);
->> ?+
->> ?+ /* if plane update was delayed, force a full update */
->> ?+ if (priv->lcds[drm_crtc_index(&lcd->crtc)]->delayed &
->> ?+ (1 << plane_num)) {
->> ?+ priv->lcds[drm_crtc_index(&lcd->crtc)]->delayed &=
->> ?+ ~(1 << plane_num);
->> ?+
->> ?+ /* handle plane move */
->> ?+ } else if (fb == old_state->fb) {
->> ?+ de2_mixer_select(priv, mixer, mixer_io);
->> ?+ if (chan == 0)
->> ?+ writel_relaxed(coord, chan_io + VI_CFGx_COORD(layer));
->> ?+ else
->> ?+ writel_relaxed(coord, chan_io + UI_CFGx_COORD(layer));
->> ?+ return;
->> ?+ }
->> ?+
->> ?+ gem = drm_fb_cma_get_gem_obj(fb, 0);
->> ?+
->> ?+ ui_sel = alpha_glob = 0;
->> ?+
->> ?+ switch (fb->pixel_format) {
->> ?+ case DRM_FORMAT_ARGB8888:
->> ?+ fmt = DE2_FORMAT_ARGB_8888;
->> ?+ ui_sel = VI_CFG_ATTR_ui_sel;
->> ?+ break;
->> ?+ case DRM_FORMAT_BGRA8888:
->> ?+ fmt = DE2_FORMAT_BGRA_8888;
->> ?+ ui_sel = VI_CFG_ATTR_ui_sel;
->> ?+ break;
->> ?+ case DRM_FORMAT_XRGB8888:
->> ?+ fmt = DE2_FORMAT_XRGB_8888;
->> ?+ ui_sel = VI_CFG_ATTR_ui_sel;
->> ?+ alpha_glob = (1 << UI_CFG_ATTR_alpmod_SHIFT) |
->> ?+ (0xff << UI_CFG_ATTR_alpha_SHIFT);
->> ?+ break;
->> ?+ case DRM_FORMAT_RGB888:
->> ?+ fmt = DE2_FORMAT_RGB_888;
->> ?+ ui_sel = VI_CFG_ATTR_ui_sel;
->> ?+ break;
->> ?+ case DRM_FORMAT_BGR888:
->> ?+ fmt = DE2_FORMAT_BGR_888;
->> ?+ ui_sel = VI_CFG_ATTR_ui_sel;
->> ?+ break;
->> ?+ case DRM_FORMAT_YUYV:
->> ?+ fmt = DE2_FORMAT_YUV422_I_YUYV;
->> ?+ break;
->> ?+ case DRM_FORMAT_YVYU:
->> ?+ fmt = DE2_FORMAT_YUV422_I_YVYU;
->> ?+ break;
->> ?+ case DRM_FORMAT_YUV422:
->> ?+ fmt = DE2_FORMAT_YUV422_P;
->> ?+ break;
->> ?+ case DRM_FORMAT_YUV420:
->> ?+ fmt = DE2_FORMAT_YUV420_P;
->> ?+ break;
->> ?+ case DRM_FORMAT_UYVY:
->> ?+ fmt = DE2_FORMAT_YUV422_I_UYVY;
->> ?+ break;
->> ?+ default:
->> ?+ pr_err("de2_plane_update: format %.4s not yet treated\n",
->> ?+ (char *) &fb->pixel_format);
->> ?+ return;
->> ?+ }
->> ?+
->> ?+ /* the overlay size is the one of the primary plane */
->> ?+ screen_size = plane_num == DE2_PRIMARY_PLANE ?
->> ?+ size :
->> ?+ readl_relaxed(mixer_io + MIXER_GLB_REGS + MIXER_GLB_SIZE_REG);
->> ?+
->> ?+ /* prepare pipe enable */
->> ?+ fcolor = readl_relaxed(mixer_io + MIXER_BLD_REGS +
->> ?+ MIXER_BLD_FCOLOR_CTL_REG);
->> ?+ fcolor |= MIXER_BLD_FCOLOR_CTL_PEN(plane_tb[plane_num].pipe);
->> ?+
->> ?+ de2_mixer_select(priv, mixer, mixer_io);
->> ?+
->> ?+ if (chan == 0) /* VI channel */
->> ?+ de2_vi_update(chan_io, gem, layer, fmt, ui_sel, size, coord,
->> ?+ fb, screen_size);
->> ?+ else /* UI channel */
->> ?+ de2_ui_update(chan_io, gem, layer, fmt, alpha_glob, size, coord,
->> ?+ fb, screen_size);
->> ?+ writel_relaxed(fcolor, mixer_io + MIXER_BLD_REGS +
->> ?+ MIXER_BLD_FCOLOR_CTL_REG);
->> ?+}
->> ?+
->> ?+static int vi_nb_layers(void __iomem *chan_io)
->> ?+{
->> ?+ int layer, n = 0;
->> ?+
->> ?+ for (layer = 0; layer < 4; layer++) {
->> ?+ if (readl_relaxed(chan_io + VI_CFGx_ATTR(layer)) != 0)
->> ?+ n++;
->> ?+ }
->> ?+
->> ?+ return n;
->> ?+}
->> ?+
->> ?+static int ui_nb_layers(void __iomem *chan_io)
->> ?+{
->> ?+ int layer, n = 0;
->> ?+
->> ?+ for (layer = 0; layer < 4; layer++) {
->> ?+ if (readl_relaxed(chan_io + UI_CFGx_ATTR(layer)) != 0)
->> ?+ n++;
->> ?+ }
->> ?+
->> ?+ return n;
->> ?+}
->> ?+
->> ?+static void de2_plane_disable(struct priv *priv,
->> ?+ int mixer, int plane_num)
->> ?+{
->> ?+ void __iomem *mixer_io = priv->mmio;
->> ?+ void __iomem *chan_io;
->> ?+ u32 fcolor;
->> ?+ int chan, layer, n;
->> ?+
->> ?+ chan = plane_tb[plane_num].chan;
->> ?+ layer = plane_tb[plane_num].layer;
->> ?+
->> ?+ mixer_io += (mixer == 0) ? DE2_MIXER0_BASE : DE2_MIXER1_BASE;
->> ?+ chan_io = mixer_io + MIXER_CHAN_REGS + MIXER_CHAN_SZ * chan;
->> ?+
->> ?+ if (chan == 0)
->> ?+ n = vi_nb_layers(chan_io);
->> ?+ else
->> ?+ n = ui_nb_layers(chan_io);
->> ?+
->> ?+ fcolor = readl_relaxed(mixer_io + MIXER_BLD_REGS +
->> ?+ MIXER_BLD_FCOLOR_CTL_REG);
->> ?+
->> ?+ de2_mixer_select(priv, mixer, mixer_io);
->> ?+
->> ?+ if (chan == 0)
->> ?+ writel_relaxed(0, chan_io + VI_CFGx_ATTR(layer));
->> ?+ else
->> ?+ writel_relaxed(0, chan_io + UI_CFGx_ATTR(layer));
->> ?+
->> ?+ /* disable the pipe if no more active layer */
->> ?+ if (n <= 1)
->> ?+ writel_relaxed(fcolor &
->> ?+ ~MIXER_BLD_FCOLOR_CTL_PEN(plane_tb[plane_num].pipe),
->> ?+ mixer_io + MIXER_BLD_REGS + MIXER_BLD_FCOLOR_CTL_REG);
->> ?+}
->> ?+
->> ?+static void de2_drm_plane_update(struct drm_plane *plane,
->> ?+ struct drm_plane_state *old_state)
->> ?+{
->> ?+ struct drm_plane_state *state = plane->state;
->> ?+ struct drm_crtc *crtc = state->crtc;
->> ?+ struct lcd *lcd = crtc_to_lcd(crtc);
->> ?+ struct priv *priv = lcd->priv;
->> ?+ int plane_num = plane - lcd->planes;
->> ?+
->> ?+ /* if the crtc is disabled, mark update delayed */
->> ?+ if (!(priv->started & (1 << lcd->mixer))) {
->> ?+ lcd->delayed |= 1 << plane_num;
->> ?+ return; /* mixer disabled */
->> ?+ }
->> ?+
->> ?+ mutex_lock(&priv->mutex);
->> ?+
->> ?+ de2_plane_update(priv, lcd, plane_num, state, old_state);
->> ?+
->> ?+ mutex_unlock(&priv->mutex);
->> ?+}
->> ?+
->> ?+static void de2_drm_plane_disable(struct drm_plane *plane,
->> ?+ struct drm_plane_state *old_state)
->> ?+{
->> ?+ struct drm_crtc *crtc = old_state->crtc;
->> ?+ struct lcd *lcd = crtc_to_lcd(crtc);
->> ?+ struct priv *priv = lcd->priv;
->> ?+ int plane_num = plane - lcd->planes;
->> ?+
->> ?+ if (!(priv->started & (1 << lcd->mixer)))
->> ?+ return; /* mixer disabled */
->> ?+
->> ?+ mutex_lock(&priv->mutex);
->> ?+
->> ?+ de2_plane_disable(lcd->priv, lcd->mixer, plane_num);
->> ?+
->> ?+ mutex_unlock(&priv->mutex);
->> ?+}
->> ?+
->> ?+static const struct drm_plane_helper_funcs plane_helper_funcs = {
->> ?+ .atomic_update = de2_drm_plane_update,
->> ?+ .atomic_disable = de2_drm_plane_disable,
->> ?+};
->> ?+
->> ?+static const struct drm_plane_funcs plane_funcs = {
->> ?+ .update_plane = drm_atomic_helper_update_plane,
->> ?+ .disable_plane = drm_atomic_helper_disable_plane,
->> ?+ .destroy = drm_plane_cleanup,
->> ?+ .reset = drm_atomic_helper_plane_reset,
->> ?+ .atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state,
->> ?+ .atomic_destroy_state = drm_atomic_helper_plane_destroy_state,
->> ?+};
->> ?+
->> ?+static int de2_one_plane_init(struct drm_device *drm,
->> ?+ struct drm_plane *plane,
->> ?+ int possible_crtcs,
->> ?+ int plane_num)
->> ?+{
->> ?+ int ret;
->> ?+
->> ?+ ret = drm_universal_plane_init(drm, plane, possible_crtcs,
->> ?+ &plane_funcs,
->> ?+ plane_tb[plane_num].formats,
->> ?+ plane_tb[plane_num].n_formats,
->> ?+ plane_tb[plane_num].type, NULL);
->> ?+ if (ret >= 0)
->> ?+ drm_plane_helper_add(plane, &plane_helper_funcs);
->> ?+
->> ?+ return ret;
->> ?+}
->> ?+
->> ?+/* initialize the planes */
->> ?+int de2_plane_init(struct drm_device *drm, struct lcd *lcd)
->> ?+{
->> ?+ int i, n, ret, possible_crtcs = 1 << drm_crtc_index(&lcd->crtc);
->> ?+
->> ?+ n = ARRAY_SIZE(plane_tb);
->> ?+ if (n != DE2_N_PLANES) {
->> ?+ dev_err(lcd->dev, "Bug: incorrect number of planes %d != "
->> ?+ __stringify(DE2_N_PLANES) "\n", n);
->> ?+ return -EINVAL;
->> ?+ }
->> ?+
->> ?+ for (i = 0; i < n; i++) {
->> ?+ ret = de2_one_plane_init(drm, &lcd->planes[i],
->> ?+ possible_crtcs, i);
->> ?+ if (ret < 0) {
->> ?+ dev_err(lcd->dev, "plane init failed %d\n", ret);
->> ?+ break;
->> ?+ }
->> ?+ }
->> ?+
->> ?+ return ret;
->> ?+}
->> ?--
->> ?2.10.2
+>>   source "drivers/gpu/drm/tilcdc/Kconfig"
+>>  diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile
+>>  index 883f3e7..3e1eaa0 100644
+>>  --- a/drivers/gpu/drm/Makefile
+>>  +++ b/drivers/gpu/drm/Makefile
+>>  @@ -72,6 +72,7 @@ obj-$(CONFIG_DRM_RCAR_DU) += rcar-du/
+>>   obj-$(CONFIG_DRM_SHMOBILE) +=shmobile/
+>>   obj-y += omapdrm/
+>>   obj-$(CONFIG_DRM_SUN4I) += sun4i/
+>>  +obj-$(CONFIG_DRM_SUN8I) += sun8i/
+>>   obj-y += tilcdc/
+>>   obj-$(CONFIG_DRM_QXL) += qxl/
+>>   obj-$(CONFIG_DRM_BOCHS) += bochs/
+>>  diff --git a/drivers/gpu/drm/sun8i/Kconfig b/drivers/gpu/drm/sun8i/Kconfig
+>>  new file mode 100644
+>>  index 0000000..6940895
+>>  --- /dev/null
+>>  +++ b/drivers/gpu/drm/sun8i/Kconfig
+>>  @@ -0,0 +1,19 @@
+>>  +#
+>>  +# Allwinner DE2 Video configuration
+>>  +#
+>>  +
+>>  +config DRM_SUN8I
+>>  + bool
+>>  +
+>>  +config DRM_SUN8I_DE2
+>>  + tristate "Support for Allwinner Video with DE2 interface"
+>>  + depends on DRM && OF
+>>  + depends on ARCH_SUNXI || COMPILE_TEST
+>>  + select DRM_GEM_CMA_HELPER
+>>  + select DRM_KMS_CMA_HELPER
+>>  + select DRM_KMS_HELPER
+>>  + select DRM_SUN8I
+>>  + help
+>>  + Choose this option if your Allwinner chipset has the DE2 interface
+>>  + as the A64, A83T and H3. If M is selected the module will be called
+>>  + sun8i-de2-drm.
+>>  diff --git a/drivers/gpu/drm/sun8i/Makefile b/drivers/gpu/drm/sun8i/Makefile
+>>  new file mode 100644
+>>  index 0000000..f107919
+>>  --- /dev/null
+>>  +++ b/drivers/gpu/drm/sun8i/Makefile
+>>  @@ -0,0 +1,7 @@
+>>  +#
+>>  +# Makefile for Allwinner's sun8i DRM device driver
+>>  +#
+>>  +
+>>  +sun8i-de2-drm-objs := de2_drv.o de2_crtc.o de2_plane.o
+>>  +
+>>  +obj-$(CONFIG_DRM_SUN8I_DE2) += sun8i-de2-drm.o
+>>  diff --git a/drivers/gpu/drm/sun8i/de2_crtc.c b/drivers/gpu/drm/sun8i/de2_crtc.c
+>>  new file mode 100644
+>>  index 0000000..4e94ccc
+>>  --- /dev/null
+>>  +++ b/drivers/gpu/drm/sun8i/de2_crtc.c
+>>  @@ -0,0 +1,449 @@
+>>  +/*
+>>  + * Allwinner DRM driver - DE2 CRTC
+>>  + *
+>>  + * Copyright (C) 2016 Jean-Francois Moine <moinejf-GANU6spQydw@public.gmane.org>
+>>  + *
+>>  + * This program is free software; you can redistribute it and/or
+>>  + * modify it under the terms of the GNU General Public License as
+>>  + * published by the Free Software Foundation; either version 2 of
+>>  + * the License, or (at your option) any later version.
+>>  + */
+>>  +
+>>  +#include <linux/component.h>
+>>  +#include <drm/drm_crtc_helper.h>
+>>  +#include <drm/drm_atomic_helper.h>
+>>  +#include <linux/io.h>
+>>  +#include <linux/of_irq.h>
+>>  +#include <linux/of_graph.h>
+>>  +
+>>  +#include "de2_drv.h"
+>>  +#include "de2_crtc.h"
+>>  +
+>>  +/* I/O map */
+>>  +
+>>  +#define TCON_GCTL_REG 0x00
+>>  +#define TCON_GCTL_TCON_ENABLE BIT(31)
+>>  +#define TCON_GINT0_REG 0x04
+>>  +#define TCON_GINT0_TCON1_Vb_Int_En BIT(30)
+>>  +#define TCON_GINT0_TCON1_Vb_Int_Flag BIT(14)
+>>  +#define TCON_GINT0_TCON1_Vb_Line_Int_Flag BIT(12)
+>>  +#define TCON0_CTL_REG 0x40
+>>  +#define TCON0_CTL_TCON_ENABLE BIT(31)
+>>  +#define TCON1_CTL_REG 0x90
+>>  +#define TCON1_CTL_TCON_ENABLE BIT(31)
+>>  +#define TCON1_CTL_INTERLACE_ENABLE BIT(20)
+>>  +#define TCON1_CTL_Start_Delay_SHIFT 4
+>>  +#define TCON1_CTL_Start_Delay_MASK GENMASK(8, 4)
+>>  +#define TCON1_BASIC0_REG 0x94 /* XI/YI */
+>>  +#define TCON1_BASIC1_REG 0x98 /* LS_XO/LS_YO */
+>>  +#define TCON1_BASIC2_REG 0x9c /* XO/YO */
+>>  +#define TCON1_BASIC3_REG 0xa0 /* HT/HBP */
+>>  +#define TCON1_BASIC4_REG 0xa4 /* VT/VBP */
+>>  +#define TCON1_BASIC5_REG 0xa8 /* HSPW/VSPW */
+>>  +#define TCON1_PS_SYNC_REG 0xb0
+>>  +#define TCON1_IO_POL_REG 0xf0
+>>  +#define TCON1_IO_POL_IO0_inv BIT(24)
+>>  +#define TCON1_IO_POL_IO1_inv BIT(25)
+>>  +#define TCON1_IO_POL_IO2_inv BIT(26)
+>>  +#define TCON1_IO_TRI_REG 0xf4
+>>  +#define TCON_CEU_CTL_REG 0x100
+>>  +#define TCON_CEU_CTL_ceu_en BIT(31)
+>>  +#define TCON1_FILL_CTL_REG 0x300
+>>  +#define TCON1_FILL_START0_REG 0x304
+>>  +#define TCON1_FILL_END0_REG 0x308
+>>  +#define TCON1_FILL_DATA0_REG 0x30c
+>>  +
+>>  +#define XY(x, y) (((x) << 16) | (y))
+>>  +
+>>  +#define andl_relaxed(addr, val) \
+>>  + writel_relaxed(readl_relaxed(addr) & val, addr)
+>>  +#define orl_relaxed(addr, val) \
+>>  + writel_relaxed(readl_relaxed(addr) | val, addr)
+>>  +
+>>  +/* vertical blank functions */
+>>  +
+>>  +static void de2_atomic_flush(struct drm_crtc *crtc,
+>>  + struct drm_crtc_state *old_state)
+>>  +{
+>>  + struct drm_pending_vblank_event *event = crtc->state->event;
+>>  +
+>>  + if (event) {
+>>  + crtc->state->event = NULL;
+>>  + spin_lock_irq(&crtc->dev->event_lock);
+>>  + 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 irqreturn_t de2_lcd_irq(int irq, void *dev_id)
+>>  +{
+>>  + struct lcd *lcd = (struct lcd *) dev_id;
+>>  + u32 isr;
+>>  +
+>>  + isr = readl_relaxed(lcd->mmio + TCON_GINT0_REG);
+>>  +
+>>  + drm_crtc_handle_vblank(&lcd->crtc);
+>>  +
+>>  + writel_relaxed(isr &
+>>  + ~(TCON_GINT0_TCON1_Vb_Int_Flag |
+>>  + TCON_GINT0_TCON1_Vb_Line_Int_Flag),
+>>  + lcd->mmio + TCON_GINT0_REG);
+>>  +
+>>  + return IRQ_HANDLED;
+>>  +}
+>>  +
+>>  +int de2_enable_vblank(struct drm_device *drm, unsigned int crtc_ix)
+>>  +{
+>>  + struct priv *priv = drm_to_priv(drm);
+>>  + struct lcd *lcd = priv->lcds[crtc_ix];
+>>  +
+>>  + orl_relaxed(lcd->mmio + TCON_GINT0_REG, TCON_GINT0_TCON1_Vb_Int_En);
+>>  +
+>>  + return 0;
+>>  +}
+>>  +
+>>  +void de2_disable_vblank(struct drm_device *drm, unsigned int crtc_ix)
+>>  +{
+>>  + struct priv *priv = drm_to_priv(drm);
+>>  + struct lcd *lcd = priv->lcds[crtc_ix];
+>>  +
+>>  + andl_relaxed(lcd->mmio + TCON_GINT0_REG, ~TCON_GINT0_TCON1_Vb_Int_En);
+>>  +}
+>>  +
+>>  +void de2_vblank_reset(struct lcd *lcd)
+>>  +{
+>>  + drm_crtc_vblank_reset(&lcd->crtc);
+>>  +}
+>>  +
+>>  +/* frame functions */
+>>  +static int de2_crtc_set_clock(struct lcd *lcd, int rate)
+>>  +{
+>>  + struct clk *parent_clk;
+>>  + u32 parent_rate;
+>>  + int ret;
+>>  +
+>>  + /* determine and set the best rate for the parent clock (pll-video) */
+>>  + if ((270000 * 2) % rate == 0)
+>>  + parent_rate = 270000000;
+>>  + else if (297000 % rate == 0)
+>>  + parent_rate = 297000000;
+>>  + else
+>>  + return -EINVAL; /* unsupported clock */
+>>  +
+>>  + parent_clk = clk_get_parent(lcd->clk);
+>>  +
+>>  + ret = clk_set_rate(parent_clk, parent_rate);
+>>  + if (ret) {
+>>  + dev_err(lcd->dev, "set parent rate failed %d\n", ret);
+>>  + return ret;
+>>  + }
+>>  + ret = clk_set_rate(lcd->clk, rate * 1000);
+>>  + if (ret) {
+>>  + dev_err(lcd->dev, "set rate failed %d\n", ret);
+>>  + return ret;
+>>  + }
+>>  +
+>>  + /* enable the clock */
+>>  + reset_control_deassert(lcd->reset);
+>>  + clk_prepare_enable(lcd->bus);
+>>  + clk_prepare_enable(lcd->clk);
+>>  +
+>>  + return ret;
+>>  +}
+>>  +
+>>  +static void de2_tcon_init(struct lcd *lcd)
+>>  +{
+>>  + andl_relaxed(lcd->mmio + TCON0_CTL_REG, ~TCON0_CTL_TCON_ENABLE);
+>>  + andl_relaxed(lcd->mmio + TCON1_CTL_REG, ~TCON1_CTL_TCON_ENABLE);
+>>  + andl_relaxed(lcd->mmio + TCON_GCTL_REG, ~TCON_GCTL_TCON_ENABLE);
+>>  +
+>>  + /* disable/ack interrupts */
+>>  + writel_relaxed(0, lcd->mmio + TCON_GINT0_REG);
+>>  +}
+>>  +
+>>  +static void de2_tcon_enable(struct lcd *lcd)
+>>  +{
+>>  + struct drm_crtc *crtc = &lcd->crtc;
+>>  + const struct drm_display_mode *mode = &crtc->mode;
+>>  + int interlace = mode->flags & DRM_MODE_FLAG_INTERLACE ? 2 : 1;
+>>  + int start_delay;
+>>  + u32 data;
+>>  +
+>>  + orl_relaxed(lcd->mmio + TCON_GCTL_REG, TCON_GCTL_TCON_ENABLE);
+>>  +
+>>  + data = XY(mode->hdisplay - 1, mode->vdisplay / interlace - 1);
+>>  + writel_relaxed(data, lcd->mmio + TCON1_BASIC0_REG);
+>>  + writel_relaxed(data, lcd->mmio + TCON1_BASIC1_REG);
+>>  + writel_relaxed(data, lcd->mmio + TCON1_BASIC2_REG);
+>>  + writel_relaxed(XY(mode->htotal - 1,
+>>  + mode->htotal - mode->hsync_start - 1),
+>>  + lcd->mmio + TCON1_BASIC3_REG);
+>>  + writel_relaxed(XY(mode->vtotal * (3 - interlace),
+>>  + mode->vtotal - mode->vsync_start - 1),
+>>  + lcd->mmio + TCON1_BASIC4_REG);
+>>  + writel_relaxed(XY(mode->hsync_end - mode->hsync_start - 1,
+>>  + mode->vsync_end - mode->vsync_start - 1),
+>>  + lcd->mmio + TCON1_BASIC5_REG);
+>>  +
+>>  + data = TCON1_IO_POL_IO2_inv;
+>>  + if (mode->flags & DRM_MODE_FLAG_PVSYNC)
+>>  + data |= TCON1_IO_POL_IO0_inv;
+>>  + if (mode->flags & DRM_MODE_FLAG_PHSYNC)
+>>  + data |= TCON1_IO_POL_IO1_inv;
+>>  + writel_relaxed(data, lcd->mmio + TCON1_IO_POL_REG);
+>>  +
+>>  + andl_relaxed(lcd->mmio + TCON_CEU_CTL_REG, ~TCON_CEU_CTL_ceu_en);
+>>  +
+>>  + if (interlace == 2)
+>>  + orl_relaxed(lcd->mmio + TCON1_CTL_REG,
+>>  + TCON1_CTL_INTERLACE_ENABLE);
+>>  + else
+>>  + andl_relaxed(lcd->mmio + TCON1_CTL_REG,
+>>  + ~TCON1_CTL_INTERLACE_ENABLE);
+>>  +
+>>  + writel_relaxed(0, lcd->mmio + TCON1_FILL_CTL_REG);
+>>  + writel_relaxed(mode->vtotal + 1, lcd->mmio + TCON1_FILL_START0_REG);
+>>  + writel_relaxed(mode->vtotal, lcd->mmio + TCON1_FILL_END0_REG);
+>>  + writel_relaxed(0, lcd->mmio + TCON1_FILL_DATA0_REG);
+>>  +
+>>  + start_delay = (mode->vtotal - mode->vdisplay) / interlace - 5;
+>>  + if (start_delay > 31)
+>>  + start_delay = 31;
+>>  + data = readl_relaxed(lcd->mmio + TCON1_CTL_REG);
+>>  + data &= ~TCON1_CTL_Start_Delay_MASK;
+>>  + data |= start_delay << TCON1_CTL_Start_Delay_SHIFT;
+>>  + writel_relaxed(data, lcd->mmio + TCON1_CTL_REG);
+>>  +
+>>  + orl_relaxed(lcd->mmio + TCON1_CTL_REG, TCON1_CTL_TCON_ENABLE);
+>>  +}
+>>  +
+>>  +static void de2_tcon_disable(struct lcd *lcd)
+>>  +{
+>>  + andl_relaxed(lcd->mmio + TCON1_CTL_REG, ~TCON1_CTL_TCON_ENABLE);
+>>  + andl_relaxed(lcd->mmio + TCON_GCTL_REG, ~TCON_GCTL_TCON_ENABLE);
+>>  +}
+>>  +
+>>  +static void de2_crtc_enable(struct drm_crtc *crtc)
+>>  +{
+>>  + struct lcd *lcd = crtc_to_lcd(crtc);
+>>  + struct drm_display_mode *mode = &crtc->mode;
+>>  +
+>>  + if (de2_crtc_set_clock(lcd, mode->clock) < 0)
+>>  + return;
+>>  + lcd->clk_enabled = true;
+>>  +
+>>  + /* start the TCON and the DE */
+>>  + de2_tcon_enable(lcd);
+>>  + de2_de_enable(lcd);
+>>  +
+>>  + /* turn on blanking interrupt */
+>>  + drm_crtc_vblank_on(crtc);
+>>  +}
+>>  +
+>>  +static void de2_crtc_disable(struct drm_crtc *crtc,
+>>  + struct drm_crtc_state *old_crtc_state)
+>>  +{
+>>  + struct lcd *lcd = crtc_to_lcd(crtc);
+>>  +
+>>  + if (!lcd->clk_enabled)
+>>  + return; /* already disabled */
+>>  + lcd->clk_enabled = false;
+>>  +
+>>  + de2_de_disable(lcd);
+>>  +
+>>  + drm_crtc_vblank_off(crtc);
+>>  +
+>>  + de2_tcon_disable(lcd);
+>>  +
+>>  + clk_disable_unprepare(lcd->clk);
+>>  + clk_disable_unprepare(lcd->bus);
+>>  + reset_control_assert(lcd->reset);
+>>  +}
+>>  +
+>>  +static const struct drm_crtc_funcs de2_crtc_funcs = {
+>>  + .destroy = drm_crtc_cleanup,
+>>  + .set_config = drm_atomic_helper_set_config,
+>>  + .page_flip = drm_atomic_helper_page_flip,
+>>  + .reset = drm_atomic_helper_crtc_reset,
+>>  + .atomic_duplicate_state = drm_atomic_helper_crtc_duplicate_state,
+>>  + .atomic_destroy_state = drm_atomic_helper_crtc_destroy_state,
+>>  +};
+>>  +
+>>  +static const struct drm_crtc_helper_funcs de2_crtc_helper_funcs = {
+>>  + .atomic_flush = de2_atomic_flush,
+>>  + .enable = de2_crtc_enable,
+>>  + .atomic_disable = de2_crtc_disable,
+>>  +};
+>>  +
+>>  +/* device init */
+>>  +static int de2_lcd_bind(struct device *dev, struct device *master,
+>>  + void *data)
+>>  +{
+>>  + struct drm_device *drm = data;
+>>  + struct priv *priv = drm_to_priv(drm);
+>>  + struct lcd *lcd = dev_get_drvdata(dev);
+>>  + struct drm_crtc *crtc = &lcd->crtc;
+>>  + int ret, i, crtc_ix;
+>>  +
+>>  + lcd->priv = priv;
+>>  +
+>>  + /* set the CRTC reference */
+>>  + crtc_ix = drm_crtc_index(crtc);
+>>  + if (crtc_ix >= ARRAY_SIZE(priv->lcds)) {
+>>  + dev_err(drm->dev, "Bad crtc index");
+>>  + return -ENOENT;
+>>  + }
+>>  + priv->lcds[crtc_ix] = lcd;
+>>  +
+>>  + /* and the mixer index (DT port index in the DE) */
+>>  + for (i = 0; ; i++) {
+>>  + struct device_node *port;
+>>  +
+>>  + port = of_parse_phandle(drm->dev->of_node, "ports", i);
+>>  + if (!port)
+>>  + break;
+>>  + if (port == lcd->crtc.port) {
+>>  + lcd->mixer = i;
+>>  + break;
+>>  + }
+>>  + }
+>>  +
+>>  + ret = de2_plane_init(drm, lcd);
+>>  + if (ret < 0)
+>>  + return ret;
+>>  +
+>>  + drm_crtc_helper_add(crtc, &de2_crtc_helper_funcs);
+>>  +
+>>  + return drm_crtc_init_with_planes(drm, crtc,
+>>  + &lcd->planes[DE2_PRIMARY_PLANE],
+>>  + &lcd->planes[DE2_CURSOR_PLANE],
+>>  + &de2_crtc_funcs, NULL);
+>>  +}
+>>  +
+>>  +static void de2_lcd_unbind(struct device *dev, struct device *master,
+>>  + void *data)
+>>  +{
+>>  + struct platform_device *pdev = to_platform_device(dev);
+>>  + struct lcd *lcd = platform_get_drvdata(pdev);
+>>  +
+>>  + if (lcd->priv)
+>>  + lcd->priv->lcds[drm_crtc_index(&lcd->crtc)] = NULL;
+>>  +}
+>>  +
+>>  +static const struct component_ops de2_lcd_ops = {
+>>  + .bind = de2_lcd_bind,
+>>  + .unbind = de2_lcd_unbind,
+>>  +};
+>>  +
+>>  +static int de2_lcd_probe(struct platform_device *pdev)
+>>  +{
+>>  + struct device *dev = &pdev->dev;
+>>  + struct device_node *np = dev->of_node, *tmp, *parent, *port;
+>>  + struct lcd *lcd;
+>>  + struct resource *res;
+>>  + int id, irq, ret;
+>>  +
+>>  + lcd = devm_kzalloc(dev, sizeof(*lcd), GFP_KERNEL);
+>>  + if (!lcd)
+>>  + return -ENOMEM;
+>>  +
+>>  + dev_set_drvdata(dev, lcd);
+>>  + lcd->dev = dev;
+>>  + lcd->mixer = id;
+>>  +
+>>  + res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+>>  + if (!res) {
+>>  + dev_err(dev, "failed to get memory resource\n");
+>>  + return -EINVAL;
+>>  + }
+>>  +
+>>  + lcd->mmio = devm_ioremap_resource(dev, res);
+>>  + if (IS_ERR(lcd->mmio)) {
+>>  + dev_err(dev, "failed to map registers\n");
+>>  + return PTR_ERR(lcd->mmio);
+>>  + }
+>>  +
+>>  + /* possible CRTC */
+>>  + parent = np;
+>>  + tmp = of_get_child_by_name(np, "ports");
+>>  + if (tmp)
+>>  + parent = tmp;
+>>  + port = of_get_child_by_name(parent, "port");
+>>  + of_node_put(tmp);
+>>  + if (!port) {
+>>  + dev_err(dev, "no port node\n");
+>>  + return -ENXIO;
+>>  + }
+>>  + lcd->crtc.port = port;
+>>  +
+>>  + lcd->bus = devm_clk_get(dev, "bus");
+>>  + if (IS_ERR(lcd->bus)) {
+>>  + dev_err(dev, "get bus clock err %d\n", (int) PTR_ERR(lcd->bus));
+>>  + ret = PTR_ERR(lcd->bus);
+>>  + goto err;
+>>  + }
+>>  +
+>>  + lcd->clk = devm_clk_get(dev, "clock");
+>>  + if (IS_ERR(lcd->clk)) {
+>>  + ret = PTR_ERR(lcd->clk);
+>>  + dev_err(dev, "get video clock err %d\n", ret);
+>>  + goto err;
+>>  + }
+>>  +
+>>  + lcd->reset = devm_reset_control_get(dev, NULL);
+>>  + if (IS_ERR(lcd->reset)) {
+>>  + ret = PTR_ERR(lcd->reset);
+>>  + dev_err(dev, "get reset err %d\n", ret);
+>>  + goto err;
+>>  + }
+>>  +
+>>  + irq = platform_get_irq(pdev, 0);
+>>  + if (irq <= 0) {
+>>  + dev_err(dev, "unable to get irq\n");
+>>  + ret = -EINVAL;
+>>  + goto err;
+>>  + }
+>>  +
+>>  + de2_tcon_init(lcd); /* stop TCON and avoid interrupts */
+>>  +
+>>  + ret = devm_request_irq(dev, irq, de2_lcd_irq, 0,
+>>  + dev_name(dev), lcd);
+>>  + if (ret < 0) {
+>>  + dev_err(dev, "unable to request irq %d\n", irq);
+>>  + goto err;
+>>  + }
+>>  +
+>>  + return component_add(dev, &de2_lcd_ops);
+>>  +
+>>  +err:
+>>  + of_node_put(lcd->crtc.port);
+>>  + return ret;
+>>  +}
+>>  +
+>>  +static int de2_lcd_remove(struct platform_device *pdev)
+>>  +{
+>>  + struct lcd *lcd = platform_get_drvdata(pdev);
+>>  +
+>>  + component_del(&pdev->dev, &de2_lcd_ops);
+>>  +
+>>  + of_node_put(lcd->crtc.port);
+>>  +
+>>  + return 0;
+>>  +}
+>>  +
+>>  +static const struct of_device_id de2_lcd_ids[] = {
+>>  + { .compatible = "allwinner,sun8i-a83t-tcon", },
+>>  + { }
+>>  +};
+>>  +
+>>  +struct platform_driver de2_lcd_platform_driver = {
+>>  + .probe = de2_lcd_probe,
+>>  + .remove = de2_lcd_remove,
+>>  + .driver = {
+>>  + .name = "sun8i-de2-tcon",
+>>  + .of_match_table = of_match_ptr(de2_lcd_ids),
+>>  + },
+>>  +};
+>>  diff --git a/drivers/gpu/drm/sun8i/de2_crtc.h b/drivers/gpu/drm/sun8i/de2_crtc.h
+>>  new file mode 100644
+>>  index 0000000..c0d34a7
+>>  --- /dev/null
+>>  +++ b/drivers/gpu/drm/sun8i/de2_crtc.h
+>>  @@ -0,0 +1,50 @@
+>>  +#ifndef __DE2_CRTC_H__
+>>  +#define __DE2_CRTC_H__
+>>  +/*
+>>  + * Copyright (C) 2016 Jean-Fran??ois Moine
+>>  + *
+>>  + * This program is free software; you can redistribute it and/or
+>>  + * modify it under the terms of the GNU General Public License as
+>>  + * published by the Free Software Foundation; either version 2 of
+>>  + * the License, or (at your option) any later version.
+>>  + */
+>>  +
+>>  +#include <drm/drm_plane_helper.h>
+>>  +
+>>  +struct clk;
+>>  +struct reset_control;
+>>  +struct priv;
+>>  +
+>>  +/* planes */
+>>  +#define DE2_PRIMARY_PLANE 0
+>>  +#define DE2_CURSOR_PLANE 1
+>>  +#define DE2_N_PLANES 5 /* number of planes - see plane_tb[] in de2_plane.c */
+>>  +
+>>  +struct lcd {
+>>  + void __iomem *mmio;
+>>  +
+>>  + struct device *dev;
+>>  + struct drm_crtc crtc;
+>>  +
+>>  + struct priv *priv; /* DRM/DE private data */
+>>  +
+>>  + u8 mixer; /* LCD (mixer) number */
+>>  + u8 delayed; /* bitmap of planes with delayed update */
+>>  +
+>>  + u8 clk_enabled; /* used for error in crtc_enable */
+>>  +
+>>  + struct clk *clk;
+>>  + struct clk *bus;
+>>  + struct reset_control *reset;
+>>  +
+>>  + struct drm_plane planes[DE2_N_PLANES];
+>>  +};
+>>  +
+>>  +#define crtc_to_lcd(x) container_of(x, struct lcd, crtc)
+>>  +
+>>  +/* in de2_plane.c */
+>>  +void de2_de_enable(struct lcd *lcd);
+>>  +void de2_de_disable(struct lcd *lcd);
+>>  +int de2_plane_init(struct drm_device *drm, struct lcd *lcd);
+>>  +
+>>  +#endif /* __DE2_CRTC_H__ */
+>>  diff --git a/drivers/gpu/drm/sun8i/de2_drv.c b/drivers/gpu/drm/sun8i/de2_drv.c
+>>  new file mode 100644
+>>  index 0000000..f96babe
+>>  --- /dev/null
+>>  +++ b/drivers/gpu/drm/sun8i/de2_drv.c
+>>  @@ -0,0 +1,317 @@
+>>  +/*
+>>  + * Allwinner DRM driver - DE2 DRM driver
+>>  + *
+>>  + * Copyright (C) 2016 Jean-Francois Moine <moinejf-GANU6spQydw@public.gmane.org>
+>>  + *
+>>  + * This program is free software; you can redistribute it and/or
+>>  + * modify it under the terms of the GNU General Public License as
+>>  + * published by the Free Software Foundation; either version 2 of
+>>  + * the License, or (at your option) any later version.
+>>  + */
+>>  +
+>>  +#include <linux/module.h>
+>>  +#include <linux/of_device.h>
+>>  +#include <drm/drm_of.h>
+>>  +#include <linux/component.h>
+>>  +#include <drm/drm_atomic_helper.h>
+>>  +#include <drm/drm_crtc_helper.h>
+>>  +#include <drm/drm_fb_cma_helper.h>
+>>  +#include <drm/drm_gem_cma_helper.h>
+>>  +
+>>  +#include "de2_drv.h"
+>>  +
+>>  +#define DRIVER_NAME "sun8i-de2"
+>>  +#define DRIVER_DESC "Allwinner DRM DE2"
+>>  +#define DRIVER_DATE "20161101"
+>>  +#define DRIVER_MAJOR 1
+>>  +#define DRIVER_MINOR 0
+>>  +
+>>  +static const struct of_device_id de2_drm_of_match[] = {
+>>  + { .compatible = "allwinner,sun8i-a83t-display-engine",
+>>  + .data = (void *) SOC_A83T },
+>>  + { .compatible = "allwinner,sun8i-h3-display-engine",
+>>  + .data = (void *) SOC_H3 },
+>>  + { },
+>>  +};
+>>  +MODULE_DEVICE_TABLE(of, de2_drm_of_match);
+>>  +
+>>  +static void de2_fb_output_poll_changed(struct drm_device *drm)
+>>  +{
+>>  + struct priv *priv = drm_to_priv(drm);
+>>  +
+>>  + if (priv->fbdev)
+>>  + drm_fbdev_cma_hotplug_event(priv->fbdev);
+>>  +}
+>>  +
+>>  +static const struct drm_mode_config_funcs de2_mode_config_funcs = {
+>>  + .fb_create = drm_fb_cma_create,
+>>  + .output_poll_changed = de2_fb_output_poll_changed,
+>>  + .atomic_check = drm_atomic_helper_check,
+>>  + .atomic_commit = drm_atomic_helper_commit,
+>>  +};
+>>  +
+>>  +/* -- DRM operations -- */
+>>  +
+>>  +static void de2_lastclose(struct drm_device *drm)
+>>  +{
+>>  + struct priv *priv = drm_to_priv(drm);
+>>  +
+>>  + if (priv->fbdev)
+>>  + drm_fbdev_cma_restore_mode(priv->fbdev);
+>>  +}
+>>  +
+>>  +static const struct file_operations de2_fops = {
+>>  + .owner = THIS_MODULE,
+>>  + .open = drm_open,
+>>  + .release = drm_release,
+>>  + .unlocked_ioctl = drm_ioctl,
+>>  + .poll = drm_poll,
+>>  + .read = drm_read,
+>>  + .llseek = no_llseek,
+>>  + .mmap = drm_gem_cma_mmap,
+>>  +};
+>>  +
+>>  +static struct drm_driver de2_drm_driver = {
+>>  + .driver_features = DRIVER_GEM | DRIVER_MODESET | DRIVER_PRIME |
+>>  + DRIVER_ATOMIC,
+>>  + .lastclose = de2_lastclose,
+>>  + .get_vblank_counter = drm_vblank_no_hw_counter,
+>>  + .enable_vblank = de2_enable_vblank,
+>>  + .disable_vblank = de2_disable_vblank,
+>>  + .gem_free_object = drm_gem_cma_free_object,
+>>  + .gem_vm_ops = &drm_gem_cma_vm_ops,
+>>  + .prime_handle_to_fd = drm_gem_prime_handle_to_fd,
+>>  + .prime_fd_to_handle = drm_gem_prime_fd_to_handle,
+>>  + .gem_prime_import = drm_gem_prime_import,
+>>  + .gem_prime_export = drm_gem_prime_export,
+>>  + .gem_prime_get_sg_table = drm_gem_cma_prime_get_sg_table,
+>>  + .gem_prime_import_sg_table = drm_gem_cma_prime_import_sg_table,
+>>  + .gem_prime_vmap = drm_gem_cma_prime_vmap,
+>>  + .gem_prime_vunmap = drm_gem_cma_prime_vunmap,
+>>  + .gem_prime_mmap = drm_gem_cma_prime_mmap,
+>>  + .dumb_create = drm_gem_cma_dumb_create,
+>>  + .dumb_map_offset = drm_gem_cma_dumb_map_offset,
+>>  + .dumb_destroy = drm_gem_dumb_destroy,
+>>  + .fops = &de2_fops,
+>>  + .name = DRIVER_NAME,
+>>  + .desc = DRIVER_DESC,
+>>  + .date = DRIVER_DATE,
+>>  + .major = DRIVER_MAJOR,
+>>  + .minor = DRIVER_MINOR,
+>>  +};
+>>  +
+>>  +/*
+>>  + * Platform driver
+>>  + */
+>>  +
+>>  +static int de2_drm_bind(struct device *dev)
+>>  +{
+>>  + struct drm_device *drm;
+>>  + struct priv *priv;
+>>  + struct resource *res;
+>>  + struct lcd *lcd;
+>>  + int i, ret;
+>>  +
+>>  + priv = kzalloc(sizeof(*priv), GFP_KERNEL);
+>>  + if (!priv)
+>>  + return -ENOMEM;
+>>  +
+>>  + drm = &priv->drm;
+>>  + dev_set_drvdata(dev, drm);
+>>  +
+>>  + /* get the resources */
+>>  + priv->soc_type = (int) of_match_device(de2_drm_of_match, dev)->data;
+>>  +
+>>  + res = platform_get_resource(to_platform_device(dev),
+>>  + IORESOURCE_MEM, 0);
+>>  + if (!res) {
+>>  + dev_err(dev, "failed to get memory resource\n");
+>>  + ret = -EINVAL;
+>>  + goto out1;
+>>  + }
+>>  +
+>>  + priv->mmio = devm_ioremap_resource(dev, res);
+>>  + if (IS_ERR(priv->mmio)) {
+>>  + ret = PTR_ERR(priv->mmio);
+>>  + dev_err(dev, "failed to map registers %d\n", ret);
+>>  + goto out1;
+>>  + }
+>>  +
+>>  + priv->gate = devm_clk_get(dev, "bus");
+>>  + if (IS_ERR(priv->gate)) {
+>>  + ret = PTR_ERR(priv->gate);
+>>  + dev_err(dev, "bus gate err %d\n", ret);
+>>  + goto out1;
+>>  + }
+>>  +
+>>  + priv->clk = devm_clk_get(dev, "clock");
+>>  + if (IS_ERR(priv->clk)) {
+>>  + ret = PTR_ERR(priv->clk);
+>>  + dev_err(dev, "clock err %d\n", ret);
+>>  + goto out1;
+>>  + }
+>>  +
+>>  + priv->reset = devm_reset_control_get(dev, NULL);
+>>  + if (IS_ERR(priv->reset)) {
+>>  + ret = PTR_ERR(priv->reset);
+>>  + dev_err(dev, "reset err %d\n", ret);
+>>  + goto out1;
+>>  + }
+>>  +
+>>  + mutex_init(&priv->mutex); /* protect DE I/O accesses */
+>>  +
+>>  + ret = drm_dev_init(drm, &de2_drm_driver, dev);
+>>  + if (ret != 0) {
+>>  + dev_err(dev, "dev_init failed %d\n", ret);
+>>  + goto out1;
+>>  + }
+>>  +
+>>  + drm_mode_config_init(drm);
+>>  + drm->mode_config.min_width = 32; /* needed for cursor */
+>>  + drm->mode_config.min_height = 32;
+>>  + drm->mode_config.max_width = 1920;
+>>  + drm->mode_config.max_height = 1080;
+>>  + drm->mode_config.funcs = &de2_mode_config_funcs;
+>>  +
+>>  + drm->irq_enabled = true;
+>>  +
+>>  + /* start the subdevices */
+>>  + ret = component_bind_all(dev, drm);
+>>  + if (ret < 0)
+>>  + goto out2;
+>>  +
+>>  + /* initialize and disable vertical blanking on all CRTCs */
+>>  + ret = drm_vblank_init(drm, drm->mode_config.num_crtc);
+>>  + if (ret < 0)
+>>  + dev_warn(dev, "vblank_init failed %d\n", ret);
+>>  +
+>>  + for (i = 0; i < ARRAY_SIZE(priv->lcds); i++) {
+>>  + lcd = priv->lcds[i];
+>>  + if (lcd)
+>>  + de2_vblank_reset(lcd);
+>>  + }
+>>  +
+>>  + drm_mode_config_reset(drm);
+>>  +
+>>  + priv->fbdev = drm_fbdev_cma_init(drm,
+>>  + 32, /* bpp */
+>>  + drm->mode_config.num_crtc,
+>>  + drm->mode_config.num_connector);
+>>  + if (IS_ERR(priv->fbdev)) {
+>>  + ret = PTR_ERR(priv->fbdev);
+>>  + priv->fbdev = NULL;
+>>  + goto out3;
+>>  + }
+>>  +
+>>  + drm_kms_helper_poll_init(drm);
+>>  +
+>>  + ret = drm_dev_register(drm, 0);
+>>  + if (ret < 0)
+>>  + goto out4;
+>>  +
+>>  + return 0;
+>>  +
+>>  +out4:
+>>  + drm_fbdev_cma_fini(priv->fbdev);
+>>  +out3:
+>>  + component_unbind_all(dev, drm);
+>>  +out2:
+>>  + drm_dev_unref(drm);
+>>  +out1:
+>>  + kfree(priv);
+>>  + return ret;
+>>  +}
+>>  +
+>>  +static void de2_drm_unbind(struct device *dev)
+>>  +{
+>>  + struct drm_device *drm = dev_get_drvdata(dev);
+>>  + struct priv *priv = drm_to_priv(drm);
+>>  +
+>>  + drm_dev_unregister(drm);
+>>  +
+>>  + drm_fbdev_cma_fini(priv->fbdev);
+>>  + drm_kms_helper_poll_fini(drm);
+>>  + drm_vblank_cleanup(drm);
+>>  + drm_mode_config_cleanup(drm);
+>>  +
+>>  + component_unbind_all(dev, drm);
+>>  +
+>>  + kfree(priv);
+>>  +}
+>>  +
+>>  +static const struct component_master_ops de2_drm_comp_ops = {
+>>  + .bind = de2_drm_bind,
+>>  + .unbind = de2_drm_unbind,
+>>  +};
+>>  +
+>>  +/*
+>>  + * drm_of_component_probe() does:
+>>  + * - bind of the ports (lcd-controller.port)
+>>  + * - bind of the remote nodes (hdmi, tve..)
+>>  + */
+>>  +static int compare_of(struct device *dev, void *data)
+>>  +{
+>>  + struct device_node *np = data;
+>>  +
+>>  + if (of_node_cmp(np->name, "port") == 0) {
+>>  + np = of_get_parent(np);
+>>  + of_node_put(np);
+>>  + }
+>>  + return dev->of_node == np;
+>>  +}
+>>  +
+>>  +static int de2_drm_probe(struct platform_device *pdev)
+>>  +{
+>>  + int ret;
+>>  +
+>>  + ret = drm_of_component_probe(&pdev->dev,
+>>  + compare_of,
+>>  + &de2_drm_comp_ops);
+>>  + if (ret == -EINVAL)
+>>  + ret = -ENXIO;
+>>  + return ret;
+>>  +}
+>>  +
+>>  +static int de2_drm_remove(struct platform_device *pdev)
+>>  +{
+>>  + component_master_del(&pdev->dev, &de2_drm_comp_ops);
+>>  +
+>>  + return 0;
+>>  +}
+>>  +
+>>  +static struct platform_driver de2_drm_platform_driver = {
+>>  + .probe = de2_drm_probe,
+>>  + .remove = de2_drm_remove,
+>>  + .driver = {
+>>  + .name = DRIVER_NAME,
+>>  + .of_match_table = de2_drm_of_match,
+>>  + },
+>>  +};
+>>  +
+>>  +static int __init de2_drm_init(void)
+>>  +{
+>>  + int ret;
+>>  +
+>>  + ret = platform_driver_register(&de2_lcd_platform_driver);
+>>  + if (ret < 0)
+>>  + return ret;
+>>  +
+>>  + ret = platform_driver_register(&de2_drm_platform_driver);
+>>  + if (ret < 0)
+>>  + platform_driver_unregister(&de2_lcd_platform_driver);
+>>  +
+>>  + return ret;
+>>  +}
+>>  +
+>>  +static void __exit de2_drm_fini(void)
+>>  +{
+>>  + platform_driver_unregister(&de2_lcd_platform_driver);
+>>  + platform_driver_unregister(&de2_drm_platform_driver);
+>>  +}
+>>  +
+>>  +module_init(de2_drm_init);
+>>  +module_exit(de2_drm_fini);
+>>  +
+>>  +MODULE_AUTHOR("Jean-Francois Moine <moinejf-GANU6spQydw@public.gmane.org>");
+>>  +MODULE_DESCRIPTION("Allwinner DE2 DRM Driver");
+>>  +MODULE_LICENSE("GPL v2");
+>>  diff --git a/drivers/gpu/drm/sun8i/de2_drv.h b/drivers/gpu/drm/sun8i/de2_drv.h
+>>  new file mode 100644
+>>  index 0000000..c42c30a
+>>  --- /dev/null
+>>  +++ b/drivers/gpu/drm/sun8i/de2_drv.h
+>>  @@ -0,0 +1,48 @@
+>>  +#ifndef __DE2_DRM_H__
+>>  +#define __DE2_DRM_H__
+>>  +/*
+>>  + * Copyright (C) 2016 Jean-Fran??ois Moine
+>>  + *
+>>  + * This program is free software; you can redistribute it and/or
+>>  + * modify it under the terms of the GNU General Public License as
+>>  + * published by the Free Software Foundation; either version 2 of
+>>  + * the License, or (at your option) any later version.
+>>  + */
+>>  +
+>>  +#include <drm/drmP.h>
+>>  +#include <linux/clk.h>
+>>  +#include <linux/reset.h>
+>>  +
+>>  +struct drm_fbdev_cma;
+>>  +struct lcd;
+>>  +
+>>  +#define N_LCDS 2
+>>  +
+>>  +struct priv {
+>>  + struct drm_device drm;
+>>  + void __iomem *mmio;
+>>  + struct clk *clk;
+>>  + struct clk *gate;
+>>  + struct reset_control *reset;
+>>  +
+>>  + struct mutex mutex; /* protect DE I/O access */
+>>  + u8 soc_type;
+>>  +#define SOC_A83T 0
+>>  +#define SOC_H3 1
+>>  + u8 started; /* bitmap of started mixers */
+>>  + u8 clean; /* bitmap of clean mixers */
+>>  +
+>>  + struct drm_fbdev_cma *fbdev;
+>>  +
+>>  + struct lcd *lcds[N_LCDS]; /* CRTCs */
+>>  +};
+>>  +
+>>  +#define drm_to_priv(x) container_of(x, struct priv, drm)
+>>  +
+>>  +/* in de2_crtc.c */
+>>  +int de2_enable_vblank(struct drm_device *drm, unsigned int crtc);
+>>  +void de2_disable_vblank(struct drm_device *drm, unsigned int crtc);
+>>  +void de2_vblank_reset(struct lcd *lcd);
+>>  +extern struct platform_driver de2_lcd_platform_driver;
+>>  +
+>>  +#endif /* __DE2_DRM_H__ */
+>>  diff --git a/drivers/gpu/drm/sun8i/de2_plane.c b/drivers/gpu/drm/sun8i/de2_plane.c
+>>  new file mode 100644
+>>  index 0000000..2fd72dc
+>>  --- /dev/null
+>>  +++ b/drivers/gpu/drm/sun8i/de2_plane.c
+>>  @@ -0,0 +1,734 @@
+>>  +/*
+>>  + * Allwinner DRM driver - Display Engine 2
+>>  + *
+>>  + * Copyright (C) 2016 Jean-Francois Moine <moinejf-GANU6spQydw@public.gmane.org>
+>>  + * Adapted from the sun8iw6 and sun8iw7 disp2 drivers
+>>  + * Copyright (c) 2016 Allwinnertech Co., Ltd.
+>>  + *
+>>  + * This program is free software; you can redistribute it and/or
+>>  + * modify it under the terms of the GNU General Public License as
+>>  + * published by the Free Software Foundation; either version 2 of
+>>  + * the License, or (at your option) any later version.
+>>  + */
+>>  +
+>>  +#include <linux/io.h>
+>>  +#include <drm/drm_atomic_helper.h>
+>>  +#include <drm/drm_crtc_helper.h>
+>>  +#include <drm/drm_fb_cma_helper.h>
+>>  +#include <drm/drm_gem_cma_helper.h>
+>>  +#include <drm/drm_plane_helper.h>
+>>  +
+>>  +#include "de2_drv.h"
+>>  +#include "de2_crtc.h"
+>>  +
+>>  +/* DE2 I/O map */
+>>  +
+>>  +#define DE2_MOD_REG 0x0000 /* 1 bit per LCD */
+>>  +#define DE2_GATE_REG 0x0004
+>>  +#define DE2_RESET_REG 0x0008
+>>  +#define DE2_DIV_REG 0x000c /* 4 bits per LCD */
+>>  +#define DE2_SEL_REG 0x0010
+>>  +
+>>  +#define DE2_MIXER0_BASE 0x00100000 /* LCD 0 */
+>>  +#define DE2_MIXER1_BASE 0x00200000 /* LCD 1 */
+>>  +
+>>  +/* mixer registers (addr / mixer base) */
+>>  +#define MIXER_GLB_REGS 0x00000 /* global control */
+>>  +#define MIXER_BLD_REGS 0x01000 /* alpha blending */
+>>  +#define MIXER_CHAN_REGS 0x02000 /* VI/UI overlay channels */
+>>  +#define MIXER_CHAN_SZ 0x1000 /* size of a channel */
+>>  +#define MIXER_VSU_REGS 0x20000 /* VSU */
+>>  +#define MIXER_GSU1_REGS 0x30000 /* GSUs */
+>>  +#define MIXER_GSU2_REGS 0x40000
+>>  +#define MIXER_GSU3_REGS 0x50000
+>>  +#define MIXER_FCE_REGS 0xa0000 /* FCE */
+>>  +#define MIXER_BWS_REGS 0xa2000 /* BWS */
+>>  +#define MIXER_LTI_REGS 0xa4000 /* LTI */
+>>  +#define MIXER_PEAK_REGS 0xa6000 /* PEAK */
+>>  +#define MIXER_ASE_REGS 0xa8000 /* ASE */
+>>  +#define MIXER_FCC_REGS 0xaa000 /* FCC */
+>>  +#define MIXER_DCSC_REGS 0xb0000 /* DCSC/SMBL */
+>>  +
+>>  +/* global control */
+>>  +#define MIXER_GLB_CTL_REG 0x00
+>>  +#define MIXER_GLB_CTL_rt_en BIT(0)
+>>  +#define MIXER_GLB_CTL_finish_irq_en BIT(4)
+>>  +#define MIXER_GLB_CTL_rtwb_port BIT(12)
+>>  +#define MIXER_GLB_STATUS_REG 0x04
+>>  +#define MIXER_GLB_DBUFF_REG 0x08
+>>  +#define MIXER_GLB_SIZE_REG 0x0c
+>>  +
+>>  +/* alpha blending */
+>>  +#define MIXER_BLD_FCOLOR_CTL_REG 0x00
+>>  +#define MIXER_BLD_FCOLOR_CTL_PEN(pipe) (0x0100 << (pipe))
+>>  +#define MIXER_BLD_ATTR_N 4 /* number of attribute blocks */
+>>  +#define MIXER_BLD_ATTR_SIZE (4 * 4) /* size of an attribute block */
+>>  +#define MIXER_BLD_ATTRx_FCOLOR(x) (0x04 + MIXER_BLD_ATTR_SIZE * (x))
+>>  +#define MIXER_BLD_ATTRx_INSIZE(x) (0x08 + MIXER_BLD_ATTR_SIZE * (x))
+>>  +#define MIXER_BLD_ATTRx_OFFSET(x) (0x0c + MIXER_BLD_ATTR_SIZE * (x))
+>>  +#define MIXER_BLD_ROUTE_REG 0x80
+>>  +#define MIXER_BLD_ROUTE(chan, pipe) ((chan) << ((pipe) * 4))
+>>  +#define MIXER_BLD_PREMULTIPLY_REG 0x84
+>>  +#define MIXER_BLD_BKCOLOR_REG 0x88
+>>  +#define MIXER_BLD_OUTPUT_SIZE_REG 0x8c
+>>  +#define MIXER_BLD_MODEx_REG(x) (0x90 + 4 * (x)) /* x = 0..3 */
+>>  +#define MIXER_BLD_MODE_SRCOVER 0x03010301
+>>  +#define MIXER_BLD_OUT_CTL_REG 0xfc
+>>  +
+>>  +/* VI channel (channel 0) */
+>>  +#define VI_CFG_N 4 /* number of layers */
+>>  +#define VI_CFG_SIZE 0x30 /* size of a layer */
+>>  +#define VI_CFGx_ATTR(l) (0x00 + VI_CFG_SIZE * (l))
+>>  +#define VI_CFG_ATTR_en BIT(0)
+>>  +#define VI_CFG_ATTR_fcolor_en BIT(4)
+>>  +#define VI_CFG_ATTR_fmt_SHIFT 8
+>>  +#define VI_CFG_ATTR_fmt_MASK GENMASK(12, 8)
+>>  +#define VI_CFG_ATTR_ui_sel BIT(15)
+>>  +#define VI_CFG_ATTR_top_down BIT(23)
+>>  +#define VI_CFGx_SIZE(l) (0x04 + VI_CFG_SIZE * (l))
+>>  +#define VI_CFGx_COORD(l) (0x08 + VI_CFG_SIZE * (l))
+>>  +#define VI_N_PLANES 3
+>>  +#define VI_CFGx_PITCHy(l, p) (0x0c + VI_CFG_SIZE * (l) + 4 * (p))
+>>  +#define VI_CFGx_TOP_LADDRy(l, p) (0x18 + VI_CFG_SIZE * (l) + 4 * (p))
+>>  +#define VI_CFGx_BOT_LADDRy(l, p) (0x24 + VI_CFG_SIZE * (l) + 4 * (p))
+>>  +#define VI_FCOLORx(l) (0xc0 + 4 * (l))
+>>  +#define VI_TOP_HADDRx(p) (0xd0 + 4 * (p))
+>>  +#define VI_BOT_HADDRx(p) (0xdc + 4 * (p))
+>>  +#define VI_OVL_SIZEx(n) (0xe8 + 4 * (n))
+>>  +#define VI_HORI_DSx(n) (0xf0 + 4 * (n))
+>>  +#define VI_VERT_DSx(n) (0xf8 + 4 * (n))
+>>  +#define VI_SIZE 0x100
+>>  +
+>>  +/* UI channel (channels 1..3) */
+>>  +#define UI_CFG_N 4 /* number of layers */
+>>  +#define UI_CFG_SIZE (8 * 4) /* size of a layer */
+>>  +#define UI_CFGx_ATTR(l) (0x00 + UI_CFG_SIZE * (l))
+>>  +#define UI_CFG_ATTR_en BIT(0)
+>>  +#define UI_CFG_ATTR_alpmod_SHIFT 1
+>>  +#define UI_CFG_ATTR_alpmod_MASK GENMASK(2, 1)
+>>  +#define UI_CFG_ATTR_fcolor_en BIT(4)
+>>  +#define UI_CFG_ATTR_fmt_SHIFT 8
+>>  +#define UI_CFG_ATTR_fmt_MASK GENMASK(12, 8)
+>>  +#define UI_CFG_ATTR_top_down BIT(23)
+>>  +#define UI_CFG_ATTR_alpha_SHIFT 24
+>>  +#define UI_CFG_ATTR_alpha_MASK GENMASK(31, 24)
+>>  +#define UI_CFGx_SIZE(l) (0x04 + UI_CFG_SIZE * (l))
+>>  +#define UI_CFGx_COORD(l) (0x08 + UI_CFG_SIZE * (l))
+>>  +#define UI_CFGx_PITCH(l) (0x0c + UI_CFG_SIZE * (l))
+>>  +#define UI_CFGx_TOP_LADDR(l) (0x10 + UI_CFG_SIZE * (l))
+>>  +#define UI_CFGx_BOT_LADDR(l) (0x14 + UI_CFG_SIZE * (l))
+>>  +#define UI_CFGx_FCOLOR(l) (0x18 + UI_CFG_SIZE * (l))
+>>  +#define UI_TOP_HADDR 0x80
+>>  +#define UI_BOT_HADDR 0x84
+>>  +#define UI_OVL_SIZE 0x88
+>>  +#define UI_SIZE 0x8c
+>>  +
+>>  +/* coordinates and sizes */
+>>  +#define XY(x, y) (((y) << 16) | (x))
+>>  +#define WH(w, h) ((((h) - 1) << 16) | ((w) - 1))
+>>  +
+>>  +/* UI video formats */
+>>  +#define DE2_FORMAT_ARGB_8888 0
+>>  +#define DE2_FORMAT_BGRA_8888 3
+>>  +#define DE2_FORMAT_XRGB_8888 4
+>>  +#define DE2_FORMAT_RGB_888 8
+>>  +#define DE2_FORMAT_BGR_888 9
+>>  +
+>>  +/* VI video formats */
+>>  +#define DE2_FORMAT_YUV422_I_YVYU 1 /* YVYU */
+>>  +#define DE2_FORMAT_YUV422_I_UYVY 2 /* UYVY */
+>>  +#define DE2_FORMAT_YUV422_I_YUYV 3 /* YUYV */
+>>  +#define DE2_FORMAT_YUV422_P 6 /* YYYY UU VV planar */
+>>  +#define DE2_FORMAT_YUV420_P 10 /* YYYY U V planar */
+>>  +
+>>  +/* plane formats */
+>>  +static const uint32_t ui_formats[] = {
+>>  + DRM_FORMAT_ARGB8888,
+>>  + DRM_FORMAT_BGRA8888,
+>>  + DRM_FORMAT_XRGB8888,
+>>  + DRM_FORMAT_RGB888,
+>>  + DRM_FORMAT_BGR888,
+>>  +};
+>>  +
+>>  +static const uint32_t vi_formats[] = {
+>>  + DRM_FORMAT_XRGB8888,
+>>  + DRM_FORMAT_YUYV,
+>>  + DRM_FORMAT_YVYU,
+>>  + DRM_FORMAT_YUV422,
+>>  + DRM_FORMAT_YUV420,
+>>  + DRM_FORMAT_UYVY,
+>>  + DRM_FORMAT_BGRA8888,
+>>  + DRM_FORMAT_RGB888,
+>>  + DRM_FORMAT_BGR888,
+>>  +};
+>>  +
+>>  +/*
+>>  + * plane table
+>>  + *
+>>  + * The chosen channel/layer assignment of the planes respects
+>>  + * the following constraints:
+>>  + * - the cursor must be in a channel higher than the primary channel
+>>  + * - there are 4 channels in the LCD 0 and only 2 channels in the LCD 1
+>>  + */
+>>  +static const struct {
+>>  + u8 chan;
+>>  + u8 layer;
+>>  + u8 pipe;
+>>  + u8 type; /* plane type */
+>>  + const uint32_t *formats;
+>>  + u8 n_formats;
+>>  +} plane_tb[] = {
+>>  + [DE2_PRIMARY_PLANE] = { /* primary plane: channel 0 (VI) */
+>>  + 0, 0, 0,
+>>  + DRM_PLANE_TYPE_PRIMARY,
+>>  + ui_formats, ARRAY_SIZE(ui_formats),
+>>  + },
+>>  + [DE2_CURSOR_PLANE] = { /* cursor: channel 1 (UI) */
+>>  + 1, 0, 1,
+>>  + DRM_PLANE_TYPE_CURSOR,
+>>  + ui_formats, ARRAY_SIZE(ui_formats),
+>>  + },
+>>  + {
+>>  + 0, 1, 0, /* 1st overlay: channel 0, layer 1 */
+>>  + DRM_PLANE_TYPE_OVERLAY,
+>>  + vi_formats, ARRAY_SIZE(vi_formats),
+>>  + },
+>>  + {
+>>  + 0, 2, 0, /* 2nd overlay: channel 0, layer 2 */
+>>  + DRM_PLANE_TYPE_OVERLAY,
+>>  + vi_formats, ARRAY_SIZE(vi_formats),
+>>  + },
+>>  + {
+>>  + 0, 3, 0, /* 3rd overlay: channel 0, layer 3 */
+>>  + DRM_PLANE_TYPE_OVERLAY,
+>>  + vi_formats, ARRAY_SIZE(vi_formats),
+>>  + },
+>>  +};
+>>  +
+>>  +static inline void andl_relaxed(void __iomem *addr, u32 val)
+>>  +{
+>>  + writel_relaxed(readl_relaxed(addr) & val, addr);
+>>  +}
+>>  +
+>>  +static inline void orl_relaxed(void __iomem *addr, u32 val)
+>>  +{
+>>  + writel_relaxed(readl_relaxed(addr) | val, addr);
+>>  +}
+>>  +
+>>  +/* alert the DE processor about changes in a mixer configuration */
+>>  +static void de2_mixer_select(struct priv *priv,
+>>  + int mixer,
+>>  + void __iomem *mixer_io)
+>>  +{
+>>  + /* select the mixer */
+>>  + andl_relaxed(priv->mmio + DE2_SEL_REG, ~1);
+>>  +
+>>  + /* double register switch */
+>>  + writel_relaxed(1, mixer_io + MIXER_GLB_REGS + MIXER_GLB_DBUFF_REG);
+>>  +}
+>>  +
+>>  +/*
+>>  + * cleanup a mixer
+>>  + *
+>>  + * This is needed only once after power on.
+>>  + */
+>>  +static void de2_mixer_cleanup(struct priv *priv, int mixer,
+>>  + u32 size)
+>>  +{
+>>  + void __iomem *mixer_io = priv->mmio;
+>>  + void __iomem *chan_io;
+>>  + u32 data;
+>>  + unsigned int i;
+>>  +
+>>  + mixer_io += (mixer == 0) ? DE2_MIXER0_BASE : DE2_MIXER1_BASE;
+>>  + chan_io = mixer_io + MIXER_CHAN_REGS;
+>>  +
+>>  + andl_relaxed(priv->mmio + DE2_SEL_REG, ~1);
+>>  + writel_relaxed(1, mixer_io + MIXER_GLB_REGS + MIXER_GLB_DBUFF_REG);
+>>  +
+>>  + writel_relaxed(MIXER_GLB_CTL_rt_en,
+>>  + mixer_io + MIXER_GLB_REGS + MIXER_GLB_CTL_REG);
+>>  + writel_relaxed(0, mixer_io + MIXER_GLB_REGS + MIXER_GLB_STATUS_REG);
+>>  +
+>>  + writel_relaxed(size, mixer_io + MIXER_GLB_REGS + MIXER_GLB_SIZE_REG);
+>>  +
+>>  + /*
+>>  + * clear the VI/UI channels
+>>  + * LCD0: 1 VI and 3 UIs
+>>  + * LCD1: 1 VI and 1 UI
+>>  + */
+>>  + memset_io(chan_io, 0, VI_SIZE);
+>>  + memset_io(chan_io + MIXER_CHAN_SZ, 0, UI_SIZE);
+>>  + if (mixer == 0) {
+>>  + memset_io(chan_io + MIXER_CHAN_SZ * 2, 0, UI_SIZE);
+>>  + memset_io(chan_io + MIXER_CHAN_SZ * 3, 0, UI_SIZE);
+>>  + }
+>>  +
+>>  + /* alpha blending */
+>>  + writel_relaxed(0x00000001 | /* fcolor for primary */
+>>  + MIXER_BLD_FCOLOR_CTL_PEN(0),
+>>  + mixer_io + MIXER_BLD_REGS + MIXER_BLD_FCOLOR_CTL_REG);
+>>  + for (i = 0; i < MIXER_BLD_ATTR_N; i++) {
+>>  + writel_relaxed(0xff000000,
+>>  + mixer_io + MIXER_BLD_REGS + MIXER_BLD_ATTRx_FCOLOR(i));
+>>  + writel_relaxed(size,
+>>  + mixer_io + MIXER_BLD_REGS + MIXER_BLD_ATTRx_INSIZE(i));
+>>  + writel_relaxed(0,
+>>  + mixer_io + MIXER_BLD_REGS + MIXER_BLD_ATTRx_OFFSET(i));
+>>  + }
+>>  + writel_relaxed(0, mixer_io + MIXER_BLD_REGS + MIXER_BLD_OUT_CTL_REG);
+>>  +
+>>  + /* prepare the pipe route for the planes */
+>>  + data = 0;
+>>  + for (i = 0; i < DE2_N_PLANES; i++)
+>>  + data |= MIXER_BLD_ROUTE(plane_tb[i].chan, plane_tb[i].pipe);
+>>  + writel_relaxed(data, mixer_io + MIXER_BLD_REGS + MIXER_BLD_ROUTE_REG);
+>>  +
+>>  + writel_relaxed(0, mixer_io + MIXER_BLD_REGS +
+>>  + MIXER_BLD_PREMULTIPLY_REG);
+>>  + writel_relaxed(0xff000000, mixer_io + MIXER_BLD_REGS +
+>>  + MIXER_BLD_BKCOLOR_REG);
+>>  + writel_relaxed(size, mixer_io + MIXER_BLD_REGS +
+>>  + MIXER_BLD_OUTPUT_SIZE_REG);
+>>  + writel_relaxed(MIXER_BLD_MODE_SRCOVER,
+>>  + mixer_io + MIXER_BLD_REGS + MIXER_BLD_MODEx_REG(0));
+>>  + writel_relaxed(MIXER_BLD_MODE_SRCOVER,
+>>  + mixer_io + MIXER_BLD_REGS + MIXER_BLD_MODEx_REG(1));
+>>  +
+>>  + /* disable the enhancements */
+>>  + writel_relaxed(0, mixer_io + MIXER_VSU_REGS);
+>>  + writel_relaxed(0, mixer_io + MIXER_GSU1_REGS);
+>>  + writel_relaxed(0, mixer_io + MIXER_GSU2_REGS);
+>>  + writel_relaxed(0, mixer_io + MIXER_GSU3_REGS);
+>>  + writel_relaxed(0, mixer_io + MIXER_FCE_REGS);
+>>  + writel_relaxed(0, mixer_io + MIXER_BWS_REGS);
+>>  + writel_relaxed(0, mixer_io + MIXER_LTI_REGS);
+>>  + writel_relaxed(0, mixer_io + MIXER_PEAK_REGS);
+>>  + writel_relaxed(0, mixer_io + MIXER_ASE_REGS);
+>>  + writel_relaxed(0, mixer_io + MIXER_FCC_REGS);
+>>  + writel_relaxed(0, mixer_io + MIXER_DCSC_REGS);
+>>  +}
+>>  +
+>>  +/* enable a mixer */
+>>  +static void de2_mixer_enable(struct lcd *lcd)
+>>  +{
+>>  + struct priv *priv = lcd->priv;
+>>  + void __iomem *mixer_io = priv->mmio;
+>>  + struct drm_display_mode *mode = &lcd->crtc.mode;
+>>  + u32 size = WH(mode->hdisplay, mode->vdisplay);
+>>  + u32 data;
+>>  + int mixer = lcd->mixer;
+>>  + int i;
+>>  +
+>>  + mixer_io += (mixer == 0) ? DE2_MIXER0_BASE : DE2_MIXER1_BASE;
+>>  +
+>>  + /* if not done yet, start the DE processor */
+>>  + if (!priv->started) {
+>>  + reset_control_deassert(priv->reset);
+>>  + clk_prepare_enable(priv->gate);
+>>  + clk_prepare_enable(priv->clk);
+>>  + }
+>>  + priv->started |= 1 << mixer;
+>>  +
+>>  + /* set the A83T clock divider (500 / 2) = 250MHz */
+>>  + if (priv->soc_type == SOC_A83T)
+>>  + writel_relaxed(0x00000011, /* div = 2 for both LCDs */
+>>  + priv->mmio + DE2_DIV_REG);
+>>  +
+>>  + /* deassert the mixer and enable its clock */
+>>  + orl_relaxed(priv->mmio + DE2_RESET_REG, mixer == 0 ? 1 : 4);
+>>  + data = 1 << mixer; /* 1 bit / lcd */
+>>  + orl_relaxed(priv->mmio + DE2_GATE_REG, data);
+>>  + orl_relaxed(priv->mmio + DE2_MOD_REG, data);
+>>  +
+>>  + /* if not done yet, cleanup and enable */
+>>  + if (!(priv->clean & (1 << mixer))) {
+>>  + priv->clean |= 1 << mixer;
+>>  + de2_mixer_cleanup(priv, mixer, size);
+>>  + return;
+>>  + }
+>>  +
+>>  + /* enable */
+>>  + de2_mixer_select(priv, mixer, mixer_io);
+>>  +
+>>  + writel_relaxed(MIXER_GLB_CTL_rt_en,
+>>  + mixer_io + MIXER_GLB_REGS + MIXER_GLB_CTL_REG);
+>>  + writel_relaxed(0, mixer_io + MIXER_GLB_REGS + MIXER_GLB_STATUS_REG);
+>>  +
+>>  + /* set the size of the frame buffer */
+>>  + writel_relaxed(size, mixer_io + MIXER_GLB_REGS + MIXER_GLB_SIZE_REG);
+>>  + for (i = 0; i < MIXER_BLD_ATTR_N; i++)
+>>  + writel_relaxed(size, mixer_io + MIXER_BLD_REGS +
+>>  + MIXER_BLD_ATTRx_INSIZE(i));
+>>  + writel_relaxed(size, mixer_io + MIXER_BLD_REGS +
+>>  + MIXER_BLD_OUTPUT_SIZE_REG);
+>>  +
+>>  + writel_relaxed(mode->flags & DRM_MODE_FLAG_INTERLACE ? 2 : 0,
+>>  + mixer_io + MIXER_BLD_REGS + MIXER_BLD_OUT_CTL_REG);
+>>  +}
+>>  +
+>>  +/* enable a LCD (DE mixer) */
+>>  +void de2_de_enable(struct lcd *lcd)
+>>  +{
+>>  + mutex_lock(&lcd->priv->mutex);
+>>  +
+>>  + de2_mixer_enable(lcd);
+>>  +
+>>  + mutex_unlock(&lcd->priv->mutex);
+>>  +}
+>>  +
+>>  +/* disable a LCD (DE mixer) */
+>>  +void de2_de_disable(struct lcd *lcd)
+>>  +{
+>>  + struct priv *priv = lcd->priv;
+>>  + void __iomem *mixer_io = priv->mmio;
+>>  + int mixer = lcd->mixer;
+>>  + u32 data;
+>>  +
+>>  + mixer_io += (mixer == 0) ? DE2_MIXER0_BASE : DE2_MIXER1_BASE;
+>>  +
+>>  + mutex_lock(&priv->mutex);
+>>  +
+>>  + de2_mixer_select(priv, mixer, mixer_io);
+>>  +
+>>  + writel_relaxed(0, mixer_io + MIXER_GLB_REGS + MIXER_GLB_CTL_REG);
+>>  +
+>>  + data = ~(1 << mixer);
+>>  + andl_relaxed(priv->mmio + DE2_MOD_REG, data);
+>>  + andl_relaxed(priv->mmio + DE2_GATE_REG, data);
+>>  + andl_relaxed(priv->mmio + DE2_RESET_REG, data);
+>>  +
+>>  + mutex_unlock(&priv->mutex);
+>>  +
+>>  + /* if all mixers are disabled, stop the DE */
+>>  + priv->started &= ~(1 << mixer);
+>>  + if (!priv->started) {
+>>  + clk_disable_unprepare(priv->clk);
+>>  + clk_disable_unprepare(priv->gate);
+>>  + reset_control_assert(priv->reset);
+>>  + }
+>>  +}
+>>  +
+>>  +static void de2_vi_update(void __iomem *chan_io,
+>>  + struct drm_gem_cma_object *gem,
+>>  + int layer,
+>>  + unsigned int fmt,
+>>  + u32 ui_sel,
+>>  + u32 size,
+>>  + u32 coord,
+>>  + struct drm_framebuffer *fb,
+>>  + u32 screen_size)
+>>  +{
+>>  + int i;
+>>  +
+>>  + writel_relaxed(VI_CFG_ATTR_en |
+>>  + (fmt << VI_CFG_ATTR_fmt_SHIFT) |
+>>  + ui_sel,
+>>  + chan_io + VI_CFGx_ATTR(layer));
+>>  + writel_relaxed(size, chan_io + VI_CFGx_SIZE(layer));
+>>  + writel_relaxed(coord, chan_io + VI_CFGx_COORD(layer));
+>>  + for (i = 0; i < VI_N_PLANES; i++) {
+>>  + writel_relaxed(fb->pitches[i] ? fb->pitches[i] :
+>>  + fb->pitches[0],
+>>  + chan_io + VI_CFGx_PITCHy(layer, i));
+>>  + writel_relaxed(gem->paddr + fb->offsets[i],
+>>  + chan_io + VI_CFGx_TOP_LADDRy(layer, i));
+>>  + }
+>>  + writel_relaxed(0xff000000, chan_io + VI_FCOLORx(layer));
+>>  + if (layer == 0) {
+>>  + writel_relaxed(screen_size,
+>>  + chan_io + VI_OVL_SIZEx(0));
+>>  + }
+>>  +}
+>>  +
+>>  +static void de2_ui_update(void __iomem *chan_io,
+>>  + struct drm_gem_cma_object *gem,
+>>  + int layer,
+>>  + unsigned int fmt,
+>>  + u32 alpha_glob,
+>>  + u32 size,
+>>  + u32 coord,
+>>  + struct drm_framebuffer *fb,
+>>  + u32 screen_size)
+>>  +{
+>>  + writel_relaxed(UI_CFG_ATTR_en |
+>>  + (fmt << UI_CFG_ATTR_fmt_SHIFT) |
+>>  + alpha_glob,
+>>  + chan_io + UI_CFGx_ATTR(layer));
+>>  + writel_relaxed(size, chan_io + UI_CFGx_SIZE(layer));
+>>  + writel_relaxed(coord, chan_io + UI_CFGx_COORD(layer));
+>>  + writel_relaxed(fb->pitches[0], chan_io + UI_CFGx_PITCH(layer));
+>>  + writel_relaxed(gem->paddr + fb->offsets[0],
+>>  + chan_io + UI_CFGx_TOP_LADDR(layer));
+>>  + if (layer == 0)
+>>  + writel_relaxed(screen_size, chan_io + UI_OVL_SIZE);
+>>  +}
+>>  +
+>>  +static void de2_plane_update(struct priv *priv, struct lcd *lcd,
+>>  + int plane_num,
+>>  + struct drm_plane_state *state,
+>>  + struct drm_plane_state *old_state)
+>>  +{
+>>  + void __iomem *mixer_io = priv->mmio;
+>>  + void __iomem *chan_io;
+>>  + struct drm_framebuffer *fb = state->fb;
+>>  + struct drm_gem_cma_object *gem;
+>>  + u32 size = WH(state->crtc_w, state->crtc_h);
+>>  + u32 coord, screen_size;
+>>  + u32 fcolor;
+>>  + u32 ui_sel, alpha_glob;
+>>  + int mixer = lcd->mixer;
+>>  + int chan, layer, x, y;
+>>  + unsigned int fmt;
+>>  +
+>>  + chan = plane_tb[plane_num].chan;
+>>  + layer = plane_tb[plane_num].layer;
+>>  +
+>>  + mixer_io += (mixer == 0) ? DE2_MIXER0_BASE : DE2_MIXER1_BASE;
+>>  + chan_io = mixer_io + MIXER_CHAN_REGS + MIXER_CHAN_SZ * chan;
+>>  +
+>>  + x = state->crtc_x >= 0 ? state->crtc_x : 0;
+>>  + y = state->crtc_y >= 0 ? state->crtc_y : 0;
+>>  + coord = XY(x, y);
+>>  +
+>>  + /* if plane update was delayed, force a full update */
+>>  + if (priv->lcds[drm_crtc_index(&lcd->crtc)]->delayed &
+>>  + (1 << plane_num)) {
+>>  + priv->lcds[drm_crtc_index(&lcd->crtc)]->delayed &=
+>>  + ~(1 << plane_num);
+>>  +
+>>  + /* handle plane move */
+>>  + } else if (fb == old_state->fb) {
+>>  + de2_mixer_select(priv, mixer, mixer_io);
+>>  + if (chan == 0)
+>>  + writel_relaxed(coord, chan_io + VI_CFGx_COORD(layer));
+>>  + else
+>>  + writel_relaxed(coord, chan_io + UI_CFGx_COORD(layer));
+>>  + return;
+>>  + }
+>>  +
+>>  + gem = drm_fb_cma_get_gem_obj(fb, 0);
+>>  +
+>>  + ui_sel = alpha_glob = 0;
+>>  +
+>>  + switch (fb->pixel_format) {
+>>  + case DRM_FORMAT_ARGB8888:
+>>  + fmt = DE2_FORMAT_ARGB_8888;
+>>  + ui_sel = VI_CFG_ATTR_ui_sel;
+>>  + break;
+>>  + case DRM_FORMAT_BGRA8888:
+>>  + fmt = DE2_FORMAT_BGRA_8888;
+>>  + ui_sel = VI_CFG_ATTR_ui_sel;
+>>  + break;
+>>  + case DRM_FORMAT_XRGB8888:
+>>  + fmt = DE2_FORMAT_XRGB_8888;
+>>  + ui_sel = VI_CFG_ATTR_ui_sel;
+>>  + alpha_glob = (1 << UI_CFG_ATTR_alpmod_SHIFT) |
+>>  + (0xff << UI_CFG_ATTR_alpha_SHIFT);
+>>  + break;
+>>  + case DRM_FORMAT_RGB888:
+>>  + fmt = DE2_FORMAT_RGB_888;
+>>  + ui_sel = VI_CFG_ATTR_ui_sel;
+>>  + break;
+>>  + case DRM_FORMAT_BGR888:
+>>  + fmt = DE2_FORMAT_BGR_888;
+>>  + ui_sel = VI_CFG_ATTR_ui_sel;
+>>  + break;
+>>  + case DRM_FORMAT_YUYV:
+>>  + fmt = DE2_FORMAT_YUV422_I_YUYV;
+>>  + break;
+>>  + case DRM_FORMAT_YVYU:
+>>  + fmt = DE2_FORMAT_YUV422_I_YVYU;
+>>  + break;
+>>  + case DRM_FORMAT_YUV422:
+>>  + fmt = DE2_FORMAT_YUV422_P;
+>>  + break;
+>>  + case DRM_FORMAT_YUV420:
+>>  + fmt = DE2_FORMAT_YUV420_P;
+>>  + break;
+>>  + case DRM_FORMAT_UYVY:
+>>  + fmt = DE2_FORMAT_YUV422_I_UYVY;
+>>  + break;
+>>  + default:
+>>  + pr_err("de2_plane_update: format %.4s not yet treated\n",
+>>  + (char *) &fb->pixel_format);
+>>  + return;
+>>  + }
+>>  +
+>>  + /* the overlay size is the one of the primary plane */
+>>  + screen_size = plane_num == DE2_PRIMARY_PLANE ?
+>>  + size :
+>>  + readl_relaxed(mixer_io + MIXER_GLB_REGS + MIXER_GLB_SIZE_REG);
+>>  +
+>>  + /* prepare pipe enable */
+>>  + fcolor = readl_relaxed(mixer_io + MIXER_BLD_REGS +
+>>  + MIXER_BLD_FCOLOR_CTL_REG);
+>>  + fcolor |= MIXER_BLD_FCOLOR_CTL_PEN(plane_tb[plane_num].pipe);
+>>  +
+>>  + de2_mixer_select(priv, mixer, mixer_io);
+>>  +
+>>  + if (chan == 0) /* VI channel */
+>>  + de2_vi_update(chan_io, gem, layer, fmt, ui_sel, size, coord,
+>>  + fb, screen_size);
+>>  + else /* UI channel */
+>>  + de2_ui_update(chan_io, gem, layer, fmt, alpha_glob, size, coord,
+>>  + fb, screen_size);
+>>  + writel_relaxed(fcolor, mixer_io + MIXER_BLD_REGS +
+>>  + MIXER_BLD_FCOLOR_CTL_REG);
+>>  +}
+>>  +
+>>  +static int vi_nb_layers(void __iomem *chan_io)
+>>  +{
+>>  + int layer, n = 0;
+>>  +
+>>  + for (layer = 0; layer < 4; layer++) {
+>>  + if (readl_relaxed(chan_io + VI_CFGx_ATTR(layer)) != 0)
+>>  + n++;
+>>  + }
+>>  +
+>>  + return n;
+>>  +}
+>>  +
+>>  +static int ui_nb_layers(void __iomem *chan_io)
+>>  +{
+>>  + int layer, n = 0;
+>>  +
+>>  + for (layer = 0; layer < 4; layer++) {
+>>  + if (readl_relaxed(chan_io + UI_CFGx_ATTR(layer)) != 0)
+>>  + n++;
+>>  + }
+>>  +
+>>  + return n;
+>>  +}
+>>  +
+>>  +static void de2_plane_disable(struct priv *priv,
+>>  + int mixer, int plane_num)
+>>  +{
+>>  + void __iomem *mixer_io = priv->mmio;
+>>  + void __iomem *chan_io;
+>>  + u32 fcolor;
+>>  + int chan, layer, n;
+>>  +
+>>  + chan = plane_tb[plane_num].chan;
+>>  + layer = plane_tb[plane_num].layer;
+>>  +
+>>  + mixer_io += (mixer == 0) ? DE2_MIXER0_BASE : DE2_MIXER1_BASE;
+>>  + chan_io = mixer_io + MIXER_CHAN_REGS + MIXER_CHAN_SZ * chan;
+>>  +
+>>  + if (chan == 0)
+>>  + n = vi_nb_layers(chan_io);
+>>  + else
+>>  + n = ui_nb_layers(chan_io);
+>>  +
+>>  + fcolor = readl_relaxed(mixer_io + MIXER_BLD_REGS +
+>>  + MIXER_BLD_FCOLOR_CTL_REG);
+>>  +
+>>  + de2_mixer_select(priv, mixer, mixer_io);
+>>  +
+>>  + if (chan == 0)
+>>  + writel_relaxed(0, chan_io + VI_CFGx_ATTR(layer));
+>>  + else
+>>  + writel_relaxed(0, chan_io + UI_CFGx_ATTR(layer));
+>>  +
+>>  + /* disable the pipe if no more active layer */
+>>  + if (n <= 1)
+>>  + writel_relaxed(fcolor &
+>>  + ~MIXER_BLD_FCOLOR_CTL_PEN(plane_tb[plane_num].pipe),
+>>  + mixer_io + MIXER_BLD_REGS + MIXER_BLD_FCOLOR_CTL_REG);
+>>  +}
+>>  +
+>>  +static void de2_drm_plane_update(struct drm_plane *plane,
+>>  + struct drm_plane_state *old_state)
+>>  +{
+>>  + struct drm_plane_state *state = plane->state;
+>>  + struct drm_crtc *crtc = state->crtc;
+>>  + struct lcd *lcd = crtc_to_lcd(crtc);
+>>  + struct priv *priv = lcd->priv;
+>>  + int plane_num = plane - lcd->planes;
+>>  +
+>>  + /* if the crtc is disabled, mark update delayed */
+>>  + if (!(priv->started & (1 << lcd->mixer))) {
+>>  + lcd->delayed |= 1 << plane_num;
+>>  + return; /* mixer disabled */
+>>  + }
+>>  +
+>>  + mutex_lock(&priv->mutex);
+>>  +
+>>  + de2_plane_update(priv, lcd, plane_num, state, old_state);
+>>  +
+>>  + mutex_unlock(&priv->mutex);
+>>  +}
+>>  +
+>>  +static void de2_drm_plane_disable(struct drm_plane *plane,
+>>  + struct drm_plane_state *old_state)
+>>  +{
+>>  + struct drm_crtc *crtc = old_state->crtc;
+>>  + struct lcd *lcd = crtc_to_lcd(crtc);
+>>  + struct priv *priv = lcd->priv;
+>>  + int plane_num = plane - lcd->planes;
+>>  +
+>>  + if (!(priv->started & (1 << lcd->mixer)))
+>>  + return; /* mixer disabled */
+>>  +
+>>  + mutex_lock(&priv->mutex);
+>>  +
+>>  + de2_plane_disable(lcd->priv, lcd->mixer, plane_num);
+>>  +
+>>  + mutex_unlock(&priv->mutex);
+>>  +}
+>>  +
+>>  +static const struct drm_plane_helper_funcs plane_helper_funcs = {
+>>  + .atomic_update = de2_drm_plane_update,
+>>  + .atomic_disable = de2_drm_plane_disable,
+>>  +};
+>>  +
+>>  +static const struct drm_plane_funcs plane_funcs = {
+>>  + .update_plane = drm_atomic_helper_update_plane,
+>>  + .disable_plane = drm_atomic_helper_disable_plane,
+>>  + .destroy = drm_plane_cleanup,
+>>  + .reset = drm_atomic_helper_plane_reset,
+>>  + .atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state,
+>>  + .atomic_destroy_state = drm_atomic_helper_plane_destroy_state,
+>>  +};
+>>  +
+>>  +static int de2_one_plane_init(struct drm_device *drm,
+>>  + struct drm_plane *plane,
+>>  + int possible_crtcs,
+>>  + int plane_num)
+>>  +{
+>>  + int ret;
+>>  +
+>>  + ret = drm_universal_plane_init(drm, plane, possible_crtcs,
+>>  + &plane_funcs,
+>>  + plane_tb[plane_num].formats,
+>>  + plane_tb[plane_num].n_formats,
+>>  + plane_tb[plane_num].type, NULL);
+>>  + if (ret >= 0)
+>>  + drm_plane_helper_add(plane, &plane_helper_funcs);
+>>  +
+>>  + return ret;
+>>  +}
+>>  +
+>>  +/* initialize the planes */
+>>  +int de2_plane_init(struct drm_device *drm, struct lcd *lcd)
+>>  +{
+>>  + int i, n, ret, possible_crtcs = 1 << drm_crtc_index(&lcd->crtc);
+>>  +
+>>  + n = ARRAY_SIZE(plane_tb);
+>>  + if (n != DE2_N_PLANES) {
+>>  + dev_err(lcd->dev, "Bug: incorrect number of planes %d != "
+>>  + __stringify(DE2_N_PLANES) "\n", n);
+>>  + return -EINVAL;
+>>  + }
+>>  +
+>>  + for (i = 0; i < n; i++) {
+>>  + ret = de2_one_plane_init(drm, &lcd->planes[i],
+>>  + possible_crtcs, i);
+>>  + if (ret < 0) {
+>>  + dev_err(lcd->dev, "plane init failed %d\n", ret);
+>>  + break;
+>>  + }
+>>  + }
+>>  +
+>>  + return ret;
+>>  +}
+>>  --
+>>  2.10.2
 >
->> ?_______________________________________________
->> ?dri-devel mailing list
->> ?dri-devel at lists.freedesktop.org
->> ?https://lists.freedesktop.org/mailman/listinfo/dri-devel
+>>  _______________________________________________
+>>  dri-devel mailing list
+>>  dri-devel-PD4FTy7X32lNgt0PjOBp9y5qC8QIuHrW@public.gmane.org
+>>  https://lists.freedesktop.org/mailman/listinfo/dri-devel
 >
 > --
 > Daniel Vetter
@@ -1748,5 +1748,10 @@ It's called "DE 2.0" in the user manual of the SoCs.
 >
 > --
 > You received this message because you are subscribed to the Google Groups "linux-sunxi" group.
-> To unsubscribe from this group and stop receiving emails from it, send an email to linux-sunxi+unsubscribe at googlegroups.com.
+> To unsubscribe from this group and stop receiving emails from it, send an email to linux-sunxi+unsubscribe-/JYPxA39Uh5TLH3MbocFF+G/Ez6ZCGd0@public.gmane.org
 > For more options, visit https://groups.google.com/d/optout.
+
+-- 
+You received this message because you are subscribed to the Google Groups "linux-sunxi" group.
+To unsubscribe from this group and stop receiving emails from it, send an email to linux-sunxi+unsubscribe-/JYPxA39Uh5TLH3MbocFF+G/Ez6ZCGd0@public.gmane.org
+For more options, visit https://groups.google.com/d/optout.
diff --git a/a/content_digest b/N1/content_digest
index fdb7c0b..e8f9c05 100644
--- a/a/content_digest
+++ b/N1/content_digest
@@ -1,25 +1,34 @@
  "ref\0cover.1480414715.git.moinejf@free.fr\0"
  "ref\0592a49a2d9505fc0f09b555847892fb7a4047530.1480414715.git.moinejf@free.fr\0"
  "ref\020161129143051.vn6exubsirwcauag@phenom.ffwll.local\0"
- "From\0icenowy@aosc.xyz (Icenowy Zheng)\0"
- "Subject\0[linux-sunxi] Re: [PATCH v7 1/8] drm: sun8i: Add a basic DRM driver for Allwinner DE2\0"
+ "ref\020161129143051.vn6exubsirwcauag-dv86pmgwkMBes7Z6vYuT8azUEOm+Xw19@public.gmane.org\0"
+ "From\0Icenowy Zheng <icenowy-ymACFijhrKM@public.gmane.org>\0"
+ "Subject\0Re: Re: [PATCH v7 1/8] drm: sun8i: Add a basic DRM driver for Allwinner DE2\0"
  "Date\0Tue, 29 Nov 2016 22:33:20 +0800\0"
- "To\0linux-arm-kernel@lists.infradead.org\0"
+ "To\0daniel-/w4YWyX8dFk@public.gmane.org <daniel-/w4YWyX8dFk@public.gmane.org>"
+ " Jean-Francois Moine <moinejf-GANU6spQydw@public.gmane.org>\0"
+ "Cc\0Dave Airlie <airlied-cv59FeDIM0c@public.gmane.org>"
+  Maxime Ripard <maxime.ripard-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org>
+  Rob Herring <robh+dt-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>
+  devicetree-u79uwXL29TY76Z2rM5mHXA@public.gmane.org <devicetree-u79uwXL29TY76Z2rM5mHXA@public.gmane.org>
+  linux-sunxi-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org <linux-sunxi-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org>
+  linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r@public.gmane.org <linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r@public.gmane.org>
+ " dri-devel-PD4FTy7X32lNgt0PjOBp9y5qC8QIuHrW@public.gmane.org <dri-devel-PD4FTy7X32lNgt0PjOBp9y5qC8QIuHrW@public.gmane.org>\0"
  "\00:1\0"
  "b\0"
  "\n"
  "\n"
- "29.11.2016, 22:30, \"Daniel Vetter\" <daniel@ffwll.ch>:\n"
+ "29.11.2016, 22:30, \"Daniel Vetter\" <daniel-/w4YWyX8dFk@public.gmane.org>:\n"
  "> On Mon, Nov 28, 2016 at 03:23:54PM +0100, Jean-Francois Moine wrote:\n"
- ">> ?Allwinner's recent SoCs, as A64, A83T and H3, contain a new display\n"
- ">> ?engine, DE2.\n"
- ">> ?This patch adds a DRM video driver for this device.\n"
+ ">> \302\240Allwinner's recent SoCs, as A64, A83T and H3, contain a new display\n"
+ ">> \302\240engine, DE2.\n"
+ ">> \302\240This patch adds a DRM video driver for this device.\n"
  ">>\n"
- ">> ?Signed-off-by: Jean-Francois Moine <moinejf@free.fr>\n"
+ ">> \302\240Signed-off-by: Jean-Francois Moine <moinejf-GANU6spQydw@public.gmane.org>\n"
  ">\n"
  "> Scrolled around a bit, seemed all reasonable.\n"
  ">\n"
- "> Acked-by: Daniel Vetter <daniel.vetter@ffwll.ch>\n"
+ "> Acked-by: Daniel Vetter <daniel.vetter-/w4YWyX8dFk@public.gmane.org>\n"
  ">\n"
  "> Not sure a new driver for each chip is reasonable, experience says that\n"
  "> long-term you want to share quite a pile of code between different hw\n"
@@ -32,1723 +41,1723 @@
  "It's called \"DE 2.0\" in the user manual of the SoCs.\n"
  "\n"
  ">\n"
- ">> ?---\n"
- ">> ??drivers/gpu/drm/Kconfig | 2 +\n"
- ">> ??drivers/gpu/drm/Makefile | 1 +\n"
- ">> ??drivers/gpu/drm/sun8i/Kconfig | 19 +\n"
- ">> ??drivers/gpu/drm/sun8i/Makefile | 7 +\n"
- ">> ??drivers/gpu/drm/sun8i/de2_crtc.c | 449 +++++++++++++++++++++++\n"
- ">> ??drivers/gpu/drm/sun8i/de2_crtc.h | 50 +++\n"
- ">> ??drivers/gpu/drm/sun8i/de2_drv.c | 317 ++++++++++++++++\n"
- ">> ??drivers/gpu/drm/sun8i/de2_drv.h | 48 +++\n"
- ">> ??drivers/gpu/drm/sun8i/de2_plane.c | 734 ++++++++++++++++++++++++++++++++++++++\n"
- ">> ??9 files changed, 1627 insertions(+)\n"
- ">> ??create mode 100644 drivers/gpu/drm/sun8i/Kconfig\n"
- ">> ??create mode 100644 drivers/gpu/drm/sun8i/Makefile\n"
- ">> ??create mode 100644 drivers/gpu/drm/sun8i/de2_crtc.c\n"
- ">> ??create mode 100644 drivers/gpu/drm/sun8i/de2_crtc.h\n"
- ">> ??create mode 100644 drivers/gpu/drm/sun8i/de2_drv.c\n"
- ">> ??create mode 100644 drivers/gpu/drm/sun8i/de2_drv.h\n"
- ">> ??create mode 100644 drivers/gpu/drm/sun8i/de2_plane.c\n"
+ ">> \302\240---\n"
+ ">> \302\240\302\240drivers/gpu/drm/Kconfig | 2 +\n"
+ ">> \302\240\302\240drivers/gpu/drm/Makefile | 1 +\n"
+ ">> \302\240\302\240drivers/gpu/drm/sun8i/Kconfig | 19 +\n"
+ ">> \302\240\302\240drivers/gpu/drm/sun8i/Makefile | 7 +\n"
+ ">> \302\240\302\240drivers/gpu/drm/sun8i/de2_crtc.c | 449 +++++++++++++++++++++++\n"
+ ">> \302\240\302\240drivers/gpu/drm/sun8i/de2_crtc.h | 50 +++\n"
+ ">> \302\240\302\240drivers/gpu/drm/sun8i/de2_drv.c | 317 ++++++++++++++++\n"
+ ">> \302\240\302\240drivers/gpu/drm/sun8i/de2_drv.h | 48 +++\n"
+ ">> \302\240\302\240drivers/gpu/drm/sun8i/de2_plane.c | 734 ++++++++++++++++++++++++++++++++++++++\n"
+ ">> \302\240\302\2409 files changed, 1627 insertions(+)\n"
+ ">> \302\240\302\240create mode 100644 drivers/gpu/drm/sun8i/Kconfig\n"
+ ">> \302\240\302\240create mode 100644 drivers/gpu/drm/sun8i/Makefile\n"
+ ">> \302\240\302\240create mode 100644 drivers/gpu/drm/sun8i/de2_crtc.c\n"
+ ">> \302\240\302\240create mode 100644 drivers/gpu/drm/sun8i/de2_crtc.h\n"
+ ">> \302\240\302\240create mode 100644 drivers/gpu/drm/sun8i/de2_drv.c\n"
+ ">> \302\240\302\240create mode 100644 drivers/gpu/drm/sun8i/de2_drv.h\n"
+ ">> \302\240\302\240create mode 100644 drivers/gpu/drm/sun8i/de2_plane.c\n"
  ">>\n"
- ">> ?diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig\n"
- ">> ?index 95fc041..bb1bfbc 100644\n"
- ">> ?--- a/drivers/gpu/drm/Kconfig\n"
- ">> ?+++ b/drivers/gpu/drm/Kconfig\n"
- ">> ?@@ -202,6 +202,8 @@ source \"drivers/gpu/drm/shmobile/Kconfig\"\n"
+ ">> \302\240diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig\n"
+ ">> \302\240index 95fc041..bb1bfbc 100644\n"
+ ">> \302\240--- a/drivers/gpu/drm/Kconfig\n"
+ ">> \302\240+++ b/drivers/gpu/drm/Kconfig\n"
+ ">> \302\240@@ -202,6 +202,8 @@ source \"drivers/gpu/drm/shmobile/Kconfig\"\n"
  ">>\n"
- ">> ??source \"drivers/gpu/drm/sun4i/Kconfig\"\n"
+ ">> \302\240\302\240source \"drivers/gpu/drm/sun4i/Kconfig\"\n"
  ">>\n"
- ">> ?+source \"drivers/gpu/drm/sun8i/Kconfig\"\n"
- ">> ?+\n"
- ">> ??source \"drivers/gpu/drm/omapdrm/Kconfig\"\n"
+ ">> \302\240+source \"drivers/gpu/drm/sun8i/Kconfig\"\n"
+ ">> \302\240+\n"
+ ">> \302\240\302\240source \"drivers/gpu/drm/omapdrm/Kconfig\"\n"
  ">>\n"
- ">> ??source \"drivers/gpu/drm/tilcdc/Kconfig\"\n"
- ">> ?diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile\n"
- ">> ?index 883f3e7..3e1eaa0 100644\n"
- ">> ?--- a/drivers/gpu/drm/Makefile\n"
- ">> ?+++ b/drivers/gpu/drm/Makefile\n"
- ">> ?@@ -72,6 +72,7 @@ obj-$(CONFIG_DRM_RCAR_DU) += rcar-du/\n"
- ">> ??obj-$(CONFIG_DRM_SHMOBILE) +=shmobile/\n"
- ">> ??obj-y += omapdrm/\n"
- ">> ??obj-$(CONFIG_DRM_SUN4I) += sun4i/\n"
- ">> ?+obj-$(CONFIG_DRM_SUN8I) += sun8i/\n"
- ">> ??obj-y += tilcdc/\n"
- ">> ??obj-$(CONFIG_DRM_QXL) += qxl/\n"
- ">> ??obj-$(CONFIG_DRM_BOCHS) += bochs/\n"
- ">> ?diff --git a/drivers/gpu/drm/sun8i/Kconfig b/drivers/gpu/drm/sun8i/Kconfig\n"
- ">> ?new file mode 100644\n"
- ">> ?index 0000000..6940895\n"
- ">> ?--- /dev/null\n"
- ">> ?+++ b/drivers/gpu/drm/sun8i/Kconfig\n"
- ">> ?@@ -0,0 +1,19 @@\n"
- ">> ?+#\n"
- ">> ?+# Allwinner DE2 Video configuration\n"
- ">> ?+#\n"
- ">> ?+\n"
- ">> ?+config DRM_SUN8I\n"
- ">> ?+ bool\n"
- ">> ?+\n"
- ">> ?+config DRM_SUN8I_DE2\n"
- ">> ?+ tristate \"Support for Allwinner Video with DE2 interface\"\n"
- ">> ?+ depends on DRM && OF\n"
- ">> ?+ depends on ARCH_SUNXI || COMPILE_TEST\n"
- ">> ?+ select DRM_GEM_CMA_HELPER\n"
- ">> ?+ select DRM_KMS_CMA_HELPER\n"
- ">> ?+ select DRM_KMS_HELPER\n"
- ">> ?+ select DRM_SUN8I\n"
- ">> ?+ help\n"
- ">> ?+ Choose this option if your Allwinner chipset has the DE2 interface\n"
- ">> ?+ as the A64, A83T and H3. If M is selected the module will be called\n"
- ">> ?+ sun8i-de2-drm.\n"
- ">> ?diff --git a/drivers/gpu/drm/sun8i/Makefile b/drivers/gpu/drm/sun8i/Makefile\n"
- ">> ?new file mode 100644\n"
- ">> ?index 0000000..f107919\n"
- ">> ?--- /dev/null\n"
- ">> ?+++ b/drivers/gpu/drm/sun8i/Makefile\n"
- ">> ?@@ -0,0 +1,7 @@\n"
- ">> ?+#\n"
- ">> ?+# Makefile for Allwinner's sun8i DRM device driver\n"
- ">> ?+#\n"
- ">> ?+\n"
- ">> ?+sun8i-de2-drm-objs := de2_drv.o de2_crtc.o de2_plane.o\n"
- ">> ?+\n"
- ">> ?+obj-$(CONFIG_DRM_SUN8I_DE2) += sun8i-de2-drm.o\n"
- ">> ?diff --git a/drivers/gpu/drm/sun8i/de2_crtc.c b/drivers/gpu/drm/sun8i/de2_crtc.c\n"
- ">> ?new file mode 100644\n"
- ">> ?index 0000000..4e94ccc\n"
- ">> ?--- /dev/null\n"
- ">> ?+++ b/drivers/gpu/drm/sun8i/de2_crtc.c\n"
- ">> ?@@ -0,0 +1,449 @@\n"
- ">> ?+/*\n"
- ">> ?+ * Allwinner DRM driver - DE2 CRTC\n"
- ">> ?+ *\n"
- ">> ?+ * Copyright (C) 2016 Jean-Francois Moine <moinejf@free.fr>\n"
- ">> ?+ *\n"
- ">> ?+ * This program is free software; you can redistribute it and/or\n"
- ">> ?+ * modify it under the terms of the GNU General Public License as\n"
- ">> ?+ * published by the Free Software Foundation; either version 2 of\n"
- ">> ?+ * the License, or (at your option) any later version.\n"
- ">> ?+ */\n"
- ">> ?+\n"
- ">> ?+#include <linux/component.h>\n"
- ">> ?+#include <drm/drm_crtc_helper.h>\n"
- ">> ?+#include <drm/drm_atomic_helper.h>\n"
- ">> ?+#include <linux/io.h>\n"
- ">> ?+#include <linux/of_irq.h>\n"
- ">> ?+#include <linux/of_graph.h>\n"
- ">> ?+\n"
- ">> ?+#include \"de2_drv.h\"\n"
- ">> ?+#include \"de2_crtc.h\"\n"
- ">> ?+\n"
- ">> ?+/* I/O map */\n"
- ">> ?+\n"
- ">> ?+#define TCON_GCTL_REG 0x00\n"
- ">> ?+#define TCON_GCTL_TCON_ENABLE BIT(31)\n"
- ">> ?+#define TCON_GINT0_REG 0x04\n"
- ">> ?+#define TCON_GINT0_TCON1_Vb_Int_En BIT(30)\n"
- ">> ?+#define TCON_GINT0_TCON1_Vb_Int_Flag BIT(14)\n"
- ">> ?+#define TCON_GINT0_TCON1_Vb_Line_Int_Flag BIT(12)\n"
- ">> ?+#define TCON0_CTL_REG 0x40\n"
- ">> ?+#define TCON0_CTL_TCON_ENABLE BIT(31)\n"
- ">> ?+#define TCON1_CTL_REG 0x90\n"
- ">> ?+#define TCON1_CTL_TCON_ENABLE BIT(31)\n"
- ">> ?+#define TCON1_CTL_INTERLACE_ENABLE BIT(20)\n"
- ">> ?+#define TCON1_CTL_Start_Delay_SHIFT 4\n"
- ">> ?+#define TCON1_CTL_Start_Delay_MASK GENMASK(8, 4)\n"
- ">> ?+#define TCON1_BASIC0_REG 0x94 /* XI/YI */\n"
- ">> ?+#define TCON1_BASIC1_REG 0x98 /* LS_XO/LS_YO */\n"
- ">> ?+#define TCON1_BASIC2_REG 0x9c /* XO/YO */\n"
- ">> ?+#define TCON1_BASIC3_REG 0xa0 /* HT/HBP */\n"
- ">> ?+#define TCON1_BASIC4_REG 0xa4 /* VT/VBP */\n"
- ">> ?+#define TCON1_BASIC5_REG 0xa8 /* HSPW/VSPW */\n"
- ">> ?+#define TCON1_PS_SYNC_REG 0xb0\n"
- ">> ?+#define TCON1_IO_POL_REG 0xf0\n"
- ">> ?+#define TCON1_IO_POL_IO0_inv BIT(24)\n"
- ">> ?+#define TCON1_IO_POL_IO1_inv BIT(25)\n"
- ">> ?+#define TCON1_IO_POL_IO2_inv BIT(26)\n"
- ">> ?+#define TCON1_IO_TRI_REG 0xf4\n"
- ">> ?+#define TCON_CEU_CTL_REG 0x100\n"
- ">> ?+#define TCON_CEU_CTL_ceu_en BIT(31)\n"
- ">> ?+#define TCON1_FILL_CTL_REG 0x300\n"
- ">> ?+#define TCON1_FILL_START0_REG 0x304\n"
- ">> ?+#define TCON1_FILL_END0_REG 0x308\n"
- ">> ?+#define TCON1_FILL_DATA0_REG 0x30c\n"
- ">> ?+\n"
- ">> ?+#define XY(x, y) (((x) << 16) | (y))\n"
- ">> ?+\n"
- ">> ?+#define andl_relaxed(addr, val) \\\n"
- ">> ?+ writel_relaxed(readl_relaxed(addr) & val, addr)\n"
- ">> ?+#define orl_relaxed(addr, val) \\\n"
- ">> ?+ writel_relaxed(readl_relaxed(addr) | val, addr)\n"
- ">> ?+\n"
- ">> ?+/* vertical blank functions */\n"
- ">> ?+\n"
- ">> ?+static void de2_atomic_flush(struct drm_crtc *crtc,\n"
- ">> ?+ struct drm_crtc_state *old_state)\n"
- ">> ?+{\n"
- ">> ?+ struct drm_pending_vblank_event *event = crtc->state->event;\n"
- ">> ?+\n"
- ">> ?+ if (event) {\n"
- ">> ?+ crtc->state->event = NULL;\n"
- ">> ?+ spin_lock_irq(&crtc->dev->event_lock);\n"
- ">> ?+ if (drm_crtc_vblank_get(crtc) == 0)\n"
- ">> ?+ drm_crtc_arm_vblank_event(crtc, event);\n"
- ">> ?+ else\n"
- ">> ?+ drm_crtc_send_vblank_event(crtc, event);\n"
- ">> ?+ spin_unlock_irq(&crtc->dev->event_lock);\n"
- ">> ?+ }\n"
- ">> ?+}\n"
- ">> ?+\n"
- ">> ?+static irqreturn_t de2_lcd_irq(int irq, void *dev_id)\n"
- ">> ?+{\n"
- ">> ?+ struct lcd *lcd = (struct lcd *) dev_id;\n"
- ">> ?+ u32 isr;\n"
- ">> ?+\n"
- ">> ?+ isr = readl_relaxed(lcd->mmio + TCON_GINT0_REG);\n"
- ">> ?+\n"
- ">> ?+ drm_crtc_handle_vblank(&lcd->crtc);\n"
- ">> ?+\n"
- ">> ?+ writel_relaxed(isr &\n"
- ">> ?+ ~(TCON_GINT0_TCON1_Vb_Int_Flag |\n"
- ">> ?+ TCON_GINT0_TCON1_Vb_Line_Int_Flag),\n"
- ">> ?+ lcd->mmio + TCON_GINT0_REG);\n"
- ">> ?+\n"
- ">> ?+ return IRQ_HANDLED;\n"
- ">> ?+}\n"
- ">> ?+\n"
- ">> ?+int de2_enable_vblank(struct drm_device *drm, unsigned int crtc_ix)\n"
- ">> ?+{\n"
- ">> ?+ struct priv *priv = drm_to_priv(drm);\n"
- ">> ?+ struct lcd *lcd = priv->lcds[crtc_ix];\n"
- ">> ?+\n"
- ">> ?+ orl_relaxed(lcd->mmio + TCON_GINT0_REG, TCON_GINT0_TCON1_Vb_Int_En);\n"
- ">> ?+\n"
- ">> ?+ return 0;\n"
- ">> ?+}\n"
- ">> ?+\n"
- ">> ?+void de2_disable_vblank(struct drm_device *drm, unsigned int crtc_ix)\n"
- ">> ?+{\n"
- ">> ?+ struct priv *priv = drm_to_priv(drm);\n"
- ">> ?+ struct lcd *lcd = priv->lcds[crtc_ix];\n"
- ">> ?+\n"
- ">> ?+ andl_relaxed(lcd->mmio + TCON_GINT0_REG, ~TCON_GINT0_TCON1_Vb_Int_En);\n"
- ">> ?+}\n"
- ">> ?+\n"
- ">> ?+void de2_vblank_reset(struct lcd *lcd)\n"
- ">> ?+{\n"
- ">> ?+ drm_crtc_vblank_reset(&lcd->crtc);\n"
- ">> ?+}\n"
- ">> ?+\n"
- ">> ?+/* frame functions */\n"
- ">> ?+static int de2_crtc_set_clock(struct lcd *lcd, int rate)\n"
- ">> ?+{\n"
- ">> ?+ struct clk *parent_clk;\n"
- ">> ?+ u32 parent_rate;\n"
- ">> ?+ int ret;\n"
- ">> ?+\n"
- ">> ?+ /* determine and set the best rate for the parent clock (pll-video) */\n"
- ">> ?+ if ((270000 * 2) % rate == 0)\n"
- ">> ?+ parent_rate = 270000000;\n"
- ">> ?+ else if (297000 % rate == 0)\n"
- ">> ?+ parent_rate = 297000000;\n"
- ">> ?+ else\n"
- ">> ?+ return -EINVAL; /* unsupported clock */\n"
- ">> ?+\n"
- ">> ?+ parent_clk = clk_get_parent(lcd->clk);\n"
- ">> ?+\n"
- ">> ?+ ret = clk_set_rate(parent_clk, parent_rate);\n"
- ">> ?+ if (ret) {\n"
- ">> ?+ dev_err(lcd->dev, \"set parent rate failed %d\\n\", ret);\n"
- ">> ?+ return ret;\n"
- ">> ?+ }\n"
- ">> ?+ ret = clk_set_rate(lcd->clk, rate * 1000);\n"
- ">> ?+ if (ret) {\n"
- ">> ?+ dev_err(lcd->dev, \"set rate failed %d\\n\", ret);\n"
- ">> ?+ return ret;\n"
- ">> ?+ }\n"
- ">> ?+\n"
- ">> ?+ /* enable the clock */\n"
- ">> ?+ reset_control_deassert(lcd->reset);\n"
- ">> ?+ clk_prepare_enable(lcd->bus);\n"
- ">> ?+ clk_prepare_enable(lcd->clk);\n"
- ">> ?+\n"
- ">> ?+ return ret;\n"
- ">> ?+}\n"
- ">> ?+\n"
- ">> ?+static void de2_tcon_init(struct lcd *lcd)\n"
- ">> ?+{\n"
- ">> ?+ andl_relaxed(lcd->mmio + TCON0_CTL_REG, ~TCON0_CTL_TCON_ENABLE);\n"
- ">> ?+ andl_relaxed(lcd->mmio + TCON1_CTL_REG, ~TCON1_CTL_TCON_ENABLE);\n"
- ">> ?+ andl_relaxed(lcd->mmio + TCON_GCTL_REG, ~TCON_GCTL_TCON_ENABLE);\n"
- ">> ?+\n"
- ">> ?+ /* disable/ack interrupts */\n"
- ">> ?+ writel_relaxed(0, lcd->mmio + TCON_GINT0_REG);\n"
- ">> ?+}\n"
- ">> ?+\n"
- ">> ?+static void de2_tcon_enable(struct lcd *lcd)\n"
- ">> ?+{\n"
- ">> ?+ struct drm_crtc *crtc = &lcd->crtc;\n"
- ">> ?+ const struct drm_display_mode *mode = &crtc->mode;\n"
- ">> ?+ int interlace = mode->flags & DRM_MODE_FLAG_INTERLACE ? 2 : 1;\n"
- ">> ?+ int start_delay;\n"
- ">> ?+ u32 data;\n"
- ">> ?+\n"
- ">> ?+ orl_relaxed(lcd->mmio + TCON_GCTL_REG, TCON_GCTL_TCON_ENABLE);\n"
- ">> ?+\n"
- ">> ?+ data = XY(mode->hdisplay - 1, mode->vdisplay / interlace - 1);\n"
- ">> ?+ writel_relaxed(data, lcd->mmio + TCON1_BASIC0_REG);\n"
- ">> ?+ writel_relaxed(data, lcd->mmio + TCON1_BASIC1_REG);\n"
- ">> ?+ writel_relaxed(data, lcd->mmio + TCON1_BASIC2_REG);\n"
- ">> ?+ writel_relaxed(XY(mode->htotal - 1,\n"
- ">> ?+ mode->htotal - mode->hsync_start - 1),\n"
- ">> ?+ lcd->mmio + TCON1_BASIC3_REG);\n"
- ">> ?+ writel_relaxed(XY(mode->vtotal * (3 - interlace),\n"
- ">> ?+ mode->vtotal - mode->vsync_start - 1),\n"
- ">> ?+ lcd->mmio + TCON1_BASIC4_REG);\n"
- ">> ?+ writel_relaxed(XY(mode->hsync_end - mode->hsync_start - 1,\n"
- ">> ?+ mode->vsync_end - mode->vsync_start - 1),\n"
- ">> ?+ lcd->mmio + TCON1_BASIC5_REG);\n"
- ">> ?+\n"
- ">> ?+ data = TCON1_IO_POL_IO2_inv;\n"
- ">> ?+ if (mode->flags & DRM_MODE_FLAG_PVSYNC)\n"
- ">> ?+ data |= TCON1_IO_POL_IO0_inv;\n"
- ">> ?+ if (mode->flags & DRM_MODE_FLAG_PHSYNC)\n"
- ">> ?+ data |= TCON1_IO_POL_IO1_inv;\n"
- ">> ?+ writel_relaxed(data, lcd->mmio + TCON1_IO_POL_REG);\n"
- ">> ?+\n"
- ">> ?+ andl_relaxed(lcd->mmio + TCON_CEU_CTL_REG, ~TCON_CEU_CTL_ceu_en);\n"
- ">> ?+\n"
- ">> ?+ if (interlace == 2)\n"
- ">> ?+ orl_relaxed(lcd->mmio + TCON1_CTL_REG,\n"
- ">> ?+ TCON1_CTL_INTERLACE_ENABLE);\n"
- ">> ?+ else\n"
- ">> ?+ andl_relaxed(lcd->mmio + TCON1_CTL_REG,\n"
- ">> ?+ ~TCON1_CTL_INTERLACE_ENABLE);\n"
- ">> ?+\n"
- ">> ?+ writel_relaxed(0, lcd->mmio + TCON1_FILL_CTL_REG);\n"
- ">> ?+ writel_relaxed(mode->vtotal + 1, lcd->mmio + TCON1_FILL_START0_REG);\n"
- ">> ?+ writel_relaxed(mode->vtotal, lcd->mmio + TCON1_FILL_END0_REG);\n"
- ">> ?+ writel_relaxed(0, lcd->mmio + TCON1_FILL_DATA0_REG);\n"
- ">> ?+\n"
- ">> ?+ start_delay = (mode->vtotal - mode->vdisplay) / interlace - 5;\n"
- ">> ?+ if (start_delay > 31)\n"
- ">> ?+ start_delay = 31;\n"
- ">> ?+ data = readl_relaxed(lcd->mmio + TCON1_CTL_REG);\n"
- ">> ?+ data &= ~TCON1_CTL_Start_Delay_MASK;\n"
- ">> ?+ data |= start_delay << TCON1_CTL_Start_Delay_SHIFT;\n"
- ">> ?+ writel_relaxed(data, lcd->mmio + TCON1_CTL_REG);\n"
- ">> ?+\n"
- ">> ?+ orl_relaxed(lcd->mmio + TCON1_CTL_REG, TCON1_CTL_TCON_ENABLE);\n"
- ">> ?+}\n"
- ">> ?+\n"
- ">> ?+static void de2_tcon_disable(struct lcd *lcd)\n"
- ">> ?+{\n"
- ">> ?+ andl_relaxed(lcd->mmio + TCON1_CTL_REG, ~TCON1_CTL_TCON_ENABLE);\n"
- ">> ?+ andl_relaxed(lcd->mmio + TCON_GCTL_REG, ~TCON_GCTL_TCON_ENABLE);\n"
- ">> ?+}\n"
- ">> ?+\n"
- ">> ?+static void de2_crtc_enable(struct drm_crtc *crtc)\n"
- ">> ?+{\n"
- ">> ?+ struct lcd *lcd = crtc_to_lcd(crtc);\n"
- ">> ?+ struct drm_display_mode *mode = &crtc->mode;\n"
- ">> ?+\n"
- ">> ?+ if (de2_crtc_set_clock(lcd, mode->clock) < 0)\n"
- ">> ?+ return;\n"
- ">> ?+ lcd->clk_enabled = true;\n"
- ">> ?+\n"
- ">> ?+ /* start the TCON and the DE */\n"
- ">> ?+ de2_tcon_enable(lcd);\n"
- ">> ?+ de2_de_enable(lcd);\n"
- ">> ?+\n"
- ">> ?+ /* turn on blanking interrupt */\n"
- ">> ?+ drm_crtc_vblank_on(crtc);\n"
- ">> ?+}\n"
- ">> ?+\n"
- ">> ?+static void de2_crtc_disable(struct drm_crtc *crtc,\n"
- ">> ?+ struct drm_crtc_state *old_crtc_state)\n"
- ">> ?+{\n"
- ">> ?+ struct lcd *lcd = crtc_to_lcd(crtc);\n"
- ">> ?+\n"
- ">> ?+ if (!lcd->clk_enabled)\n"
- ">> ?+ return; /* already disabled */\n"
- ">> ?+ lcd->clk_enabled = false;\n"
- ">> ?+\n"
- ">> ?+ de2_de_disable(lcd);\n"
- ">> ?+\n"
- ">> ?+ drm_crtc_vblank_off(crtc);\n"
- ">> ?+\n"
- ">> ?+ de2_tcon_disable(lcd);\n"
- ">> ?+\n"
- ">> ?+ clk_disable_unprepare(lcd->clk);\n"
- ">> ?+ clk_disable_unprepare(lcd->bus);\n"
- ">> ?+ reset_control_assert(lcd->reset);\n"
- ">> ?+}\n"
- ">> ?+\n"
- ">> ?+static const struct drm_crtc_funcs de2_crtc_funcs = {\n"
- ">> ?+ .destroy = drm_crtc_cleanup,\n"
- ">> ?+ .set_config = drm_atomic_helper_set_config,\n"
- ">> ?+ .page_flip = drm_atomic_helper_page_flip,\n"
- ">> ?+ .reset = drm_atomic_helper_crtc_reset,\n"
- ">> ?+ .atomic_duplicate_state = drm_atomic_helper_crtc_duplicate_state,\n"
- ">> ?+ .atomic_destroy_state = drm_atomic_helper_crtc_destroy_state,\n"
- ">> ?+};\n"
- ">> ?+\n"
- ">> ?+static const struct drm_crtc_helper_funcs de2_crtc_helper_funcs = {\n"
- ">> ?+ .atomic_flush = de2_atomic_flush,\n"
- ">> ?+ .enable = de2_crtc_enable,\n"
- ">> ?+ .atomic_disable = de2_crtc_disable,\n"
- ">> ?+};\n"
- ">> ?+\n"
- ">> ?+/* device init */\n"
- ">> ?+static int de2_lcd_bind(struct device *dev, struct device *master,\n"
- ">> ?+ void *data)\n"
- ">> ?+{\n"
- ">> ?+ struct drm_device *drm = data;\n"
- ">> ?+ struct priv *priv = drm_to_priv(drm);\n"
- ">> ?+ struct lcd *lcd = dev_get_drvdata(dev);\n"
- ">> ?+ struct drm_crtc *crtc = &lcd->crtc;\n"
- ">> ?+ int ret, i, crtc_ix;\n"
- ">> ?+\n"
- ">> ?+ lcd->priv = priv;\n"
- ">> ?+\n"
- ">> ?+ /* set the CRTC reference */\n"
- ">> ?+ crtc_ix = drm_crtc_index(crtc);\n"
- ">> ?+ if (crtc_ix >= ARRAY_SIZE(priv->lcds)) {\n"
- ">> ?+ dev_err(drm->dev, \"Bad crtc index\");\n"
- ">> ?+ return -ENOENT;\n"
- ">> ?+ }\n"
- ">> ?+ priv->lcds[crtc_ix] = lcd;\n"
- ">> ?+\n"
- ">> ?+ /* and the mixer index (DT port index in the DE) */\n"
- ">> ?+ for (i = 0; ; i++) {\n"
- ">> ?+ struct device_node *port;\n"
- ">> ?+\n"
- ">> ?+ port = of_parse_phandle(drm->dev->of_node, \"ports\", i);\n"
- ">> ?+ if (!port)\n"
- ">> ?+ break;\n"
- ">> ?+ if (port == lcd->crtc.port) {\n"
- ">> ?+ lcd->mixer = i;\n"
- ">> ?+ break;\n"
- ">> ?+ }\n"
- ">> ?+ }\n"
- ">> ?+\n"
- ">> ?+ ret = de2_plane_init(drm, lcd);\n"
- ">> ?+ if (ret < 0)\n"
- ">> ?+ return ret;\n"
- ">> ?+\n"
- ">> ?+ drm_crtc_helper_add(crtc, &de2_crtc_helper_funcs);\n"
- ">> ?+\n"
- ">> ?+ return drm_crtc_init_with_planes(drm, crtc,\n"
- ">> ?+ &lcd->planes[DE2_PRIMARY_PLANE],\n"
- ">> ?+ &lcd->planes[DE2_CURSOR_PLANE],\n"
- ">> ?+ &de2_crtc_funcs, NULL);\n"
- ">> ?+}\n"
- ">> ?+\n"
- ">> ?+static void de2_lcd_unbind(struct device *dev, struct device *master,\n"
- ">> ?+ void *data)\n"
- ">> ?+{\n"
- ">> ?+ struct platform_device *pdev = to_platform_device(dev);\n"
- ">> ?+ struct lcd *lcd = platform_get_drvdata(pdev);\n"
- ">> ?+\n"
- ">> ?+ if (lcd->priv)\n"
- ">> ?+ lcd->priv->lcds[drm_crtc_index(&lcd->crtc)] = NULL;\n"
- ">> ?+}\n"
- ">> ?+\n"
- ">> ?+static const struct component_ops de2_lcd_ops = {\n"
- ">> ?+ .bind = de2_lcd_bind,\n"
- ">> ?+ .unbind = de2_lcd_unbind,\n"
- ">> ?+};\n"
- ">> ?+\n"
- ">> ?+static int de2_lcd_probe(struct platform_device *pdev)\n"
- ">> ?+{\n"
- ">> ?+ struct device *dev = &pdev->dev;\n"
- ">> ?+ struct device_node *np = dev->of_node, *tmp, *parent, *port;\n"
- ">> ?+ struct lcd *lcd;\n"
- ">> ?+ struct resource *res;\n"
- ">> ?+ int id, irq, ret;\n"
- ">> ?+\n"
- ">> ?+ lcd = devm_kzalloc(dev, sizeof(*lcd), GFP_KERNEL);\n"
- ">> ?+ if (!lcd)\n"
- ">> ?+ return -ENOMEM;\n"
- ">> ?+\n"
- ">> ?+ dev_set_drvdata(dev, lcd);\n"
- ">> ?+ lcd->dev = dev;\n"
- ">> ?+ lcd->mixer = id;\n"
- ">> ?+\n"
- ">> ?+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);\n"
- ">> ?+ if (!res) {\n"
- ">> ?+ dev_err(dev, \"failed to get memory resource\\n\");\n"
- ">> ?+ return -EINVAL;\n"
- ">> ?+ }\n"
- ">> ?+\n"
- ">> ?+ lcd->mmio = devm_ioremap_resource(dev, res);\n"
- ">> ?+ if (IS_ERR(lcd->mmio)) {\n"
- ">> ?+ dev_err(dev, \"failed to map registers\\n\");\n"
- ">> ?+ return PTR_ERR(lcd->mmio);\n"
- ">> ?+ }\n"
- ">> ?+\n"
- ">> ?+ /* possible CRTC */\n"
- ">> ?+ parent = np;\n"
- ">> ?+ tmp = of_get_child_by_name(np, \"ports\");\n"
- ">> ?+ if (tmp)\n"
- ">> ?+ parent = tmp;\n"
- ">> ?+ port = of_get_child_by_name(parent, \"port\");\n"
- ">> ?+ of_node_put(tmp);\n"
- ">> ?+ if (!port) {\n"
- ">> ?+ dev_err(dev, \"no port node\\n\");\n"
- ">> ?+ return -ENXIO;\n"
- ">> ?+ }\n"
- ">> ?+ lcd->crtc.port = port;\n"
- ">> ?+\n"
- ">> ?+ lcd->bus = devm_clk_get(dev, \"bus\");\n"
- ">> ?+ if (IS_ERR(lcd->bus)) {\n"
- ">> ?+ dev_err(dev, \"get bus clock err %d\\n\", (int) PTR_ERR(lcd->bus));\n"
- ">> ?+ ret = PTR_ERR(lcd->bus);\n"
- ">> ?+ goto err;\n"
- ">> ?+ }\n"
- ">> ?+\n"
- ">> ?+ lcd->clk = devm_clk_get(dev, \"clock\");\n"
- ">> ?+ if (IS_ERR(lcd->clk)) {\n"
- ">> ?+ ret = PTR_ERR(lcd->clk);\n"
- ">> ?+ dev_err(dev, \"get video clock err %d\\n\", ret);\n"
- ">> ?+ goto err;\n"
- ">> ?+ }\n"
- ">> ?+\n"
- ">> ?+ lcd->reset = devm_reset_control_get(dev, NULL);\n"
- ">> ?+ if (IS_ERR(lcd->reset)) {\n"
- ">> ?+ ret = PTR_ERR(lcd->reset);\n"
- ">> ?+ dev_err(dev, \"get reset err %d\\n\", ret);\n"
- ">> ?+ goto err;\n"
- ">> ?+ }\n"
- ">> ?+\n"
- ">> ?+ irq = platform_get_irq(pdev, 0);\n"
- ">> ?+ if (irq <= 0) {\n"
- ">> ?+ dev_err(dev, \"unable to get irq\\n\");\n"
- ">> ?+ ret = -EINVAL;\n"
- ">> ?+ goto err;\n"
- ">> ?+ }\n"
- ">> ?+\n"
- ">> ?+ de2_tcon_init(lcd); /* stop TCON and avoid interrupts */\n"
- ">> ?+\n"
- ">> ?+ ret = devm_request_irq(dev, irq, de2_lcd_irq, 0,\n"
- ">> ?+ dev_name(dev), lcd);\n"
- ">> ?+ if (ret < 0) {\n"
- ">> ?+ dev_err(dev, \"unable to request irq %d\\n\", irq);\n"
- ">> ?+ goto err;\n"
- ">> ?+ }\n"
- ">> ?+\n"
- ">> ?+ return component_add(dev, &de2_lcd_ops);\n"
- ">> ?+\n"
- ">> ?+err:\n"
- ">> ?+ of_node_put(lcd->crtc.port);\n"
- ">> ?+ return ret;\n"
- ">> ?+}\n"
- ">> ?+\n"
- ">> ?+static int de2_lcd_remove(struct platform_device *pdev)\n"
- ">> ?+{\n"
- ">> ?+ struct lcd *lcd = platform_get_drvdata(pdev);\n"
- ">> ?+\n"
- ">> ?+ component_del(&pdev->dev, &de2_lcd_ops);\n"
- ">> ?+\n"
- ">> ?+ of_node_put(lcd->crtc.port);\n"
- ">> ?+\n"
- ">> ?+ return 0;\n"
- ">> ?+}\n"
- ">> ?+\n"
- ">> ?+static const struct of_device_id de2_lcd_ids[] = {\n"
- ">> ?+ { .compatible = \"allwinner,sun8i-a83t-tcon\", },\n"
- ">> ?+ { }\n"
- ">> ?+};\n"
- ">> ?+\n"
- ">> ?+struct platform_driver de2_lcd_platform_driver = {\n"
- ">> ?+ .probe = de2_lcd_probe,\n"
- ">> ?+ .remove = de2_lcd_remove,\n"
- ">> ?+ .driver = {\n"
- ">> ?+ .name = \"sun8i-de2-tcon\",\n"
- ">> ?+ .of_match_table = of_match_ptr(de2_lcd_ids),\n"
- ">> ?+ },\n"
- ">> ?+};\n"
- ">> ?diff --git a/drivers/gpu/drm/sun8i/de2_crtc.h b/drivers/gpu/drm/sun8i/de2_crtc.h\n"
- ">> ?new file mode 100644\n"
- ">> ?index 0000000..c0d34a7\n"
- ">> ?--- /dev/null\n"
- ">> ?+++ b/drivers/gpu/drm/sun8i/de2_crtc.h\n"
- ">> ?@@ -0,0 +1,50 @@\n"
- ">> ?+#ifndef __DE2_CRTC_H__\n"
- ">> ?+#define __DE2_CRTC_H__\n"
- ">> ?+/*\n"
- ">> ?+ * Copyright (C) 2016 Jean-Fran??ois Moine\n"
- ">> ?+ *\n"
- ">> ?+ * This program is free software; you can redistribute it and/or\n"
- ">> ?+ * modify it under the terms of the GNU General Public License as\n"
- ">> ?+ * published by the Free Software Foundation; either version 2 of\n"
- ">> ?+ * the License, or (at your option) any later version.\n"
- ">> ?+ */\n"
- ">> ?+\n"
- ">> ?+#include <drm/drm_plane_helper.h>\n"
- ">> ?+\n"
- ">> ?+struct clk;\n"
- ">> ?+struct reset_control;\n"
- ">> ?+struct priv;\n"
- ">> ?+\n"
- ">> ?+/* planes */\n"
- ">> ?+#define DE2_PRIMARY_PLANE 0\n"
- ">> ?+#define DE2_CURSOR_PLANE 1\n"
- ">> ?+#define DE2_N_PLANES 5 /* number of planes - see plane_tb[] in de2_plane.c */\n"
- ">> ?+\n"
- ">> ?+struct lcd {\n"
- ">> ?+ void __iomem *mmio;\n"
- ">> ?+\n"
- ">> ?+ struct device *dev;\n"
- ">> ?+ struct drm_crtc crtc;\n"
- ">> ?+\n"
- ">> ?+ struct priv *priv; /* DRM/DE private data */\n"
- ">> ?+\n"
- ">> ?+ u8 mixer; /* LCD (mixer) number */\n"
- ">> ?+ u8 delayed; /* bitmap of planes with delayed update */\n"
- ">> ?+\n"
- ">> ?+ u8 clk_enabled; /* used for error in crtc_enable */\n"
- ">> ?+\n"
- ">> ?+ struct clk *clk;\n"
- ">> ?+ struct clk *bus;\n"
- ">> ?+ struct reset_control *reset;\n"
- ">> ?+\n"
- ">> ?+ struct drm_plane planes[DE2_N_PLANES];\n"
- ">> ?+};\n"
- ">> ?+\n"
- ">> ?+#define crtc_to_lcd(x) container_of(x, struct lcd, crtc)\n"
- ">> ?+\n"
- ">> ?+/* in de2_plane.c */\n"
- ">> ?+void de2_de_enable(struct lcd *lcd);\n"
- ">> ?+void de2_de_disable(struct lcd *lcd);\n"
- ">> ?+int de2_plane_init(struct drm_device *drm, struct lcd *lcd);\n"
- ">> ?+\n"
- ">> ?+#endif /* __DE2_CRTC_H__ */\n"
- ">> ?diff --git a/drivers/gpu/drm/sun8i/de2_drv.c b/drivers/gpu/drm/sun8i/de2_drv.c\n"
- ">> ?new file mode 100644\n"
- ">> ?index 0000000..f96babe\n"
- ">> ?--- /dev/null\n"
- ">> ?+++ b/drivers/gpu/drm/sun8i/de2_drv.c\n"
- ">> ?@@ -0,0 +1,317 @@\n"
- ">> ?+/*\n"
- ">> ?+ * Allwinner DRM driver - DE2 DRM driver\n"
- ">> ?+ *\n"
- ">> ?+ * Copyright (C) 2016 Jean-Francois Moine <moinejf@free.fr>\n"
- ">> ?+ *\n"
- ">> ?+ * This program is free software; you can redistribute it and/or\n"
- ">> ?+ * modify it under the terms of the GNU General Public License as\n"
- ">> ?+ * published by the Free Software Foundation; either version 2 of\n"
- ">> ?+ * the License, or (at your option) any later version.\n"
- ">> ?+ */\n"
- ">> ?+\n"
- ">> ?+#include <linux/module.h>\n"
- ">> ?+#include <linux/of_device.h>\n"
- ">> ?+#include <drm/drm_of.h>\n"
- ">> ?+#include <linux/component.h>\n"
- ">> ?+#include <drm/drm_atomic_helper.h>\n"
- ">> ?+#include <drm/drm_crtc_helper.h>\n"
- ">> ?+#include <drm/drm_fb_cma_helper.h>\n"
- ">> ?+#include <drm/drm_gem_cma_helper.h>\n"
- ">> ?+\n"
- ">> ?+#include \"de2_drv.h\"\n"
- ">> ?+\n"
- ">> ?+#define DRIVER_NAME \"sun8i-de2\"\n"
- ">> ?+#define DRIVER_DESC \"Allwinner DRM DE2\"\n"
- ">> ?+#define DRIVER_DATE \"20161101\"\n"
- ">> ?+#define DRIVER_MAJOR 1\n"
- ">> ?+#define DRIVER_MINOR 0\n"
- ">> ?+\n"
- ">> ?+static const struct of_device_id de2_drm_of_match[] = {\n"
- ">> ?+ { .compatible = \"allwinner,sun8i-a83t-display-engine\",\n"
- ">> ?+ .data = (void *) SOC_A83T },\n"
- ">> ?+ { .compatible = \"allwinner,sun8i-h3-display-engine\",\n"
- ">> ?+ .data = (void *) SOC_H3 },\n"
- ">> ?+ { },\n"
- ">> ?+};\n"
- ">> ?+MODULE_DEVICE_TABLE(of, de2_drm_of_match);\n"
- ">> ?+\n"
- ">> ?+static void de2_fb_output_poll_changed(struct drm_device *drm)\n"
- ">> ?+{\n"
- ">> ?+ struct priv *priv = drm_to_priv(drm);\n"
- ">> ?+\n"
- ">> ?+ if (priv->fbdev)\n"
- ">> ?+ drm_fbdev_cma_hotplug_event(priv->fbdev);\n"
- ">> ?+}\n"
- ">> ?+\n"
- ">> ?+static const struct drm_mode_config_funcs de2_mode_config_funcs = {\n"
- ">> ?+ .fb_create = drm_fb_cma_create,\n"
- ">> ?+ .output_poll_changed = de2_fb_output_poll_changed,\n"
- ">> ?+ .atomic_check = drm_atomic_helper_check,\n"
- ">> ?+ .atomic_commit = drm_atomic_helper_commit,\n"
- ">> ?+};\n"
- ">> ?+\n"
- ">> ?+/* -- DRM operations -- */\n"
- ">> ?+\n"
- ">> ?+static void de2_lastclose(struct drm_device *drm)\n"
- ">> ?+{\n"
- ">> ?+ struct priv *priv = drm_to_priv(drm);\n"
- ">> ?+\n"
- ">> ?+ if (priv->fbdev)\n"
- ">> ?+ drm_fbdev_cma_restore_mode(priv->fbdev);\n"
- ">> ?+}\n"
- ">> ?+\n"
- ">> ?+static const struct file_operations de2_fops = {\n"
- ">> ?+ .owner = THIS_MODULE,\n"
- ">> ?+ .open = drm_open,\n"
- ">> ?+ .release = drm_release,\n"
- ">> ?+ .unlocked_ioctl = drm_ioctl,\n"
- ">> ?+ .poll = drm_poll,\n"
- ">> ?+ .read = drm_read,\n"
- ">> ?+ .llseek = no_llseek,\n"
- ">> ?+ .mmap = drm_gem_cma_mmap,\n"
- ">> ?+};\n"
- ">> ?+\n"
- ">> ?+static struct drm_driver de2_drm_driver = {\n"
- ">> ?+ .driver_features = DRIVER_GEM | DRIVER_MODESET | DRIVER_PRIME |\n"
- ">> ?+ DRIVER_ATOMIC,\n"
- ">> ?+ .lastclose = de2_lastclose,\n"
- ">> ?+ .get_vblank_counter = drm_vblank_no_hw_counter,\n"
- ">> ?+ .enable_vblank = de2_enable_vblank,\n"
- ">> ?+ .disable_vblank = de2_disable_vblank,\n"
- ">> ?+ .gem_free_object = drm_gem_cma_free_object,\n"
- ">> ?+ .gem_vm_ops = &drm_gem_cma_vm_ops,\n"
- ">> ?+ .prime_handle_to_fd = drm_gem_prime_handle_to_fd,\n"
- ">> ?+ .prime_fd_to_handle = drm_gem_prime_fd_to_handle,\n"
- ">> ?+ .gem_prime_import = drm_gem_prime_import,\n"
- ">> ?+ .gem_prime_export = drm_gem_prime_export,\n"
- ">> ?+ .gem_prime_get_sg_table = drm_gem_cma_prime_get_sg_table,\n"
- ">> ?+ .gem_prime_import_sg_table = drm_gem_cma_prime_import_sg_table,\n"
- ">> ?+ .gem_prime_vmap = drm_gem_cma_prime_vmap,\n"
- ">> ?+ .gem_prime_vunmap = drm_gem_cma_prime_vunmap,\n"
- ">> ?+ .gem_prime_mmap = drm_gem_cma_prime_mmap,\n"
- ">> ?+ .dumb_create = drm_gem_cma_dumb_create,\n"
- ">> ?+ .dumb_map_offset = drm_gem_cma_dumb_map_offset,\n"
- ">> ?+ .dumb_destroy = drm_gem_dumb_destroy,\n"
- ">> ?+ .fops = &de2_fops,\n"
- ">> ?+ .name = DRIVER_NAME,\n"
- ">> ?+ .desc = DRIVER_DESC,\n"
- ">> ?+ .date = DRIVER_DATE,\n"
- ">> ?+ .major = DRIVER_MAJOR,\n"
- ">> ?+ .minor = DRIVER_MINOR,\n"
- ">> ?+};\n"
- ">> ?+\n"
- ">> ?+/*\n"
- ">> ?+ * Platform driver\n"
- ">> ?+ */\n"
- ">> ?+\n"
- ">> ?+static int de2_drm_bind(struct device *dev)\n"
- ">> ?+{\n"
- ">> ?+ struct drm_device *drm;\n"
- ">> ?+ struct priv *priv;\n"
- ">> ?+ struct resource *res;\n"
- ">> ?+ struct lcd *lcd;\n"
- ">> ?+ int i, ret;\n"
- ">> ?+\n"
- ">> ?+ priv = kzalloc(sizeof(*priv), GFP_KERNEL);\n"
- ">> ?+ if (!priv)\n"
- ">> ?+ return -ENOMEM;\n"
- ">> ?+\n"
- ">> ?+ drm = &priv->drm;\n"
- ">> ?+ dev_set_drvdata(dev, drm);\n"
- ">> ?+\n"
- ">> ?+ /* get the resources */\n"
- ">> ?+ priv->soc_type = (int) of_match_device(de2_drm_of_match, dev)->data;\n"
- ">> ?+\n"
- ">> ?+ res = platform_get_resource(to_platform_device(dev),\n"
- ">> ?+ IORESOURCE_MEM, 0);\n"
- ">> ?+ if (!res) {\n"
- ">> ?+ dev_err(dev, \"failed to get memory resource\\n\");\n"
- ">> ?+ ret = -EINVAL;\n"
- ">> ?+ goto out1;\n"
- ">> ?+ }\n"
- ">> ?+\n"
- ">> ?+ priv->mmio = devm_ioremap_resource(dev, res);\n"
- ">> ?+ if (IS_ERR(priv->mmio)) {\n"
- ">> ?+ ret = PTR_ERR(priv->mmio);\n"
- ">> ?+ dev_err(dev, \"failed to map registers %d\\n\", ret);\n"
- ">> ?+ goto out1;\n"
- ">> ?+ }\n"
- ">> ?+\n"
- ">> ?+ priv->gate = devm_clk_get(dev, \"bus\");\n"
- ">> ?+ if (IS_ERR(priv->gate)) {\n"
- ">> ?+ ret = PTR_ERR(priv->gate);\n"
- ">> ?+ dev_err(dev, \"bus gate err %d\\n\", ret);\n"
- ">> ?+ goto out1;\n"
- ">> ?+ }\n"
- ">> ?+\n"
- ">> ?+ priv->clk = devm_clk_get(dev, \"clock\");\n"
- ">> ?+ if (IS_ERR(priv->clk)) {\n"
- ">> ?+ ret = PTR_ERR(priv->clk);\n"
- ">> ?+ dev_err(dev, \"clock err %d\\n\", ret);\n"
- ">> ?+ goto out1;\n"
- ">> ?+ }\n"
- ">> ?+\n"
- ">> ?+ priv->reset = devm_reset_control_get(dev, NULL);\n"
- ">> ?+ if (IS_ERR(priv->reset)) {\n"
- ">> ?+ ret = PTR_ERR(priv->reset);\n"
- ">> ?+ dev_err(dev, \"reset err %d\\n\", ret);\n"
- ">> ?+ goto out1;\n"
- ">> ?+ }\n"
- ">> ?+\n"
- ">> ?+ mutex_init(&priv->mutex); /* protect DE I/O accesses */\n"
- ">> ?+\n"
- ">> ?+ ret = drm_dev_init(drm, &de2_drm_driver, dev);\n"
- ">> ?+ if (ret != 0) {\n"
- ">> ?+ dev_err(dev, \"dev_init failed %d\\n\", ret);\n"
- ">> ?+ goto out1;\n"
- ">> ?+ }\n"
- ">> ?+\n"
- ">> ?+ drm_mode_config_init(drm);\n"
- ">> ?+ drm->mode_config.min_width = 32; /* needed for cursor */\n"
- ">> ?+ drm->mode_config.min_height = 32;\n"
- ">> ?+ drm->mode_config.max_width = 1920;\n"
- ">> ?+ drm->mode_config.max_height = 1080;\n"
- ">> ?+ drm->mode_config.funcs = &de2_mode_config_funcs;\n"
- ">> ?+\n"
- ">> ?+ drm->irq_enabled = true;\n"
- ">> ?+\n"
- ">> ?+ /* start the subdevices */\n"
- ">> ?+ ret = component_bind_all(dev, drm);\n"
- ">> ?+ if (ret < 0)\n"
- ">> ?+ goto out2;\n"
- ">> ?+\n"
- ">> ?+ /* initialize and disable vertical blanking on all CRTCs */\n"
- ">> ?+ ret = drm_vblank_init(drm, drm->mode_config.num_crtc);\n"
- ">> ?+ if (ret < 0)\n"
- ">> ?+ dev_warn(dev, \"vblank_init failed %d\\n\", ret);\n"
- ">> ?+\n"
- ">> ?+ for (i = 0; i < ARRAY_SIZE(priv->lcds); i++) {\n"
- ">> ?+ lcd = priv->lcds[i];\n"
- ">> ?+ if (lcd)\n"
- ">> ?+ de2_vblank_reset(lcd);\n"
- ">> ?+ }\n"
- ">> ?+\n"
- ">> ?+ drm_mode_config_reset(drm);\n"
- ">> ?+\n"
- ">> ?+ priv->fbdev = drm_fbdev_cma_init(drm,\n"
- ">> ?+ 32, /* bpp */\n"
- ">> ?+ drm->mode_config.num_crtc,\n"
- ">> ?+ drm->mode_config.num_connector);\n"
- ">> ?+ if (IS_ERR(priv->fbdev)) {\n"
- ">> ?+ ret = PTR_ERR(priv->fbdev);\n"
- ">> ?+ priv->fbdev = NULL;\n"
- ">> ?+ goto out3;\n"
- ">> ?+ }\n"
- ">> ?+\n"
- ">> ?+ drm_kms_helper_poll_init(drm);\n"
- ">> ?+\n"
- ">> ?+ ret = drm_dev_register(drm, 0);\n"
- ">> ?+ if (ret < 0)\n"
- ">> ?+ goto out4;\n"
- ">> ?+\n"
- ">> ?+ return 0;\n"
- ">> ?+\n"
- ">> ?+out4:\n"
- ">> ?+ drm_fbdev_cma_fini(priv->fbdev);\n"
- ">> ?+out3:\n"
- ">> ?+ component_unbind_all(dev, drm);\n"
- ">> ?+out2:\n"
- ">> ?+ drm_dev_unref(drm);\n"
- ">> ?+out1:\n"
- ">> ?+ kfree(priv);\n"
- ">> ?+ return ret;\n"
- ">> ?+}\n"
- ">> ?+\n"
- ">> ?+static void de2_drm_unbind(struct device *dev)\n"
- ">> ?+{\n"
- ">> ?+ struct drm_device *drm = dev_get_drvdata(dev);\n"
- ">> ?+ struct priv *priv = drm_to_priv(drm);\n"
- ">> ?+\n"
- ">> ?+ drm_dev_unregister(drm);\n"
- ">> ?+\n"
- ">> ?+ drm_fbdev_cma_fini(priv->fbdev);\n"
- ">> ?+ drm_kms_helper_poll_fini(drm);\n"
- ">> ?+ drm_vblank_cleanup(drm);\n"
- ">> ?+ drm_mode_config_cleanup(drm);\n"
- ">> ?+\n"
- ">> ?+ component_unbind_all(dev, drm);\n"
- ">> ?+\n"
- ">> ?+ kfree(priv);\n"
- ">> ?+}\n"
- ">> ?+\n"
- ">> ?+static const struct component_master_ops de2_drm_comp_ops = {\n"
- ">> ?+ .bind = de2_drm_bind,\n"
- ">> ?+ .unbind = de2_drm_unbind,\n"
- ">> ?+};\n"
- ">> ?+\n"
- ">> ?+/*\n"
- ">> ?+ * drm_of_component_probe() does:\n"
- ">> ?+ * - bind of the ports (lcd-controller.port)\n"
- ">> ?+ * - bind of the remote nodes (hdmi, tve..)\n"
- ">> ?+ */\n"
- ">> ?+static int compare_of(struct device *dev, void *data)\n"
- ">> ?+{\n"
- ">> ?+ struct device_node *np = data;\n"
- ">> ?+\n"
- ">> ?+ if (of_node_cmp(np->name, \"port\") == 0) {\n"
- ">> ?+ np = of_get_parent(np);\n"
- ">> ?+ of_node_put(np);\n"
- ">> ?+ }\n"
- ">> ?+ return dev->of_node == np;\n"
- ">> ?+}\n"
- ">> ?+\n"
- ">> ?+static int de2_drm_probe(struct platform_device *pdev)\n"
- ">> ?+{\n"
- ">> ?+ int ret;\n"
- ">> ?+\n"
- ">> ?+ ret = drm_of_component_probe(&pdev->dev,\n"
- ">> ?+ compare_of,\n"
- ">> ?+ &de2_drm_comp_ops);\n"
- ">> ?+ if (ret == -EINVAL)\n"
- ">> ?+ ret = -ENXIO;\n"
- ">> ?+ return ret;\n"
- ">> ?+}\n"
- ">> ?+\n"
- ">> ?+static int de2_drm_remove(struct platform_device *pdev)\n"
- ">> ?+{\n"
- ">> ?+ component_master_del(&pdev->dev, &de2_drm_comp_ops);\n"
- ">> ?+\n"
- ">> ?+ return 0;\n"
- ">> ?+}\n"
- ">> ?+\n"
- ">> ?+static struct platform_driver de2_drm_platform_driver = {\n"
- ">> ?+ .probe = de2_drm_probe,\n"
- ">> ?+ .remove = de2_drm_remove,\n"
- ">> ?+ .driver = {\n"
- ">> ?+ .name = DRIVER_NAME,\n"
- ">> ?+ .of_match_table = de2_drm_of_match,\n"
- ">> ?+ },\n"
- ">> ?+};\n"
- ">> ?+\n"
- ">> ?+static int __init de2_drm_init(void)\n"
- ">> ?+{\n"
- ">> ?+ int ret;\n"
- ">> ?+\n"
- ">> ?+ ret = platform_driver_register(&de2_lcd_platform_driver);\n"
- ">> ?+ if (ret < 0)\n"
- ">> ?+ return ret;\n"
- ">> ?+\n"
- ">> ?+ ret = platform_driver_register(&de2_drm_platform_driver);\n"
- ">> ?+ if (ret < 0)\n"
- ">> ?+ platform_driver_unregister(&de2_lcd_platform_driver);\n"
- ">> ?+\n"
- ">> ?+ return ret;\n"
- ">> ?+}\n"
- ">> ?+\n"
- ">> ?+static void __exit de2_drm_fini(void)\n"
- ">> ?+{\n"
- ">> ?+ platform_driver_unregister(&de2_lcd_platform_driver);\n"
- ">> ?+ platform_driver_unregister(&de2_drm_platform_driver);\n"
- ">> ?+}\n"
- ">> ?+\n"
- ">> ?+module_init(de2_drm_init);\n"
- ">> ?+module_exit(de2_drm_fini);\n"
- ">> ?+\n"
- ">> ?+MODULE_AUTHOR(\"Jean-Francois Moine <moinejf@free.fr>\");\n"
- ">> ?+MODULE_DESCRIPTION(\"Allwinner DE2 DRM Driver\");\n"
- ">> ?+MODULE_LICENSE(\"GPL v2\");\n"
- ">> ?diff --git a/drivers/gpu/drm/sun8i/de2_drv.h b/drivers/gpu/drm/sun8i/de2_drv.h\n"
- ">> ?new file mode 100644\n"
- ">> ?index 0000000..c42c30a\n"
- ">> ?--- /dev/null\n"
- ">> ?+++ b/drivers/gpu/drm/sun8i/de2_drv.h\n"
- ">> ?@@ -0,0 +1,48 @@\n"
- ">> ?+#ifndef __DE2_DRM_H__\n"
- ">> ?+#define __DE2_DRM_H__\n"
- ">> ?+/*\n"
- ">> ?+ * Copyright (C) 2016 Jean-Fran??ois Moine\n"
- ">> ?+ *\n"
- ">> ?+ * This program is free software; you can redistribute it and/or\n"
- ">> ?+ * modify it under the terms of the GNU General Public License as\n"
- ">> ?+ * published by the Free Software Foundation; either version 2 of\n"
- ">> ?+ * the License, or (at your option) any later version.\n"
- ">> ?+ */\n"
- ">> ?+\n"
- ">> ?+#include <drm/drmP.h>\n"
- ">> ?+#include <linux/clk.h>\n"
- ">> ?+#include <linux/reset.h>\n"
- ">> ?+\n"
- ">> ?+struct drm_fbdev_cma;\n"
- ">> ?+struct lcd;\n"
- ">> ?+\n"
- ">> ?+#define N_LCDS 2\n"
- ">> ?+\n"
- ">> ?+struct priv {\n"
- ">> ?+ struct drm_device drm;\n"
- ">> ?+ void __iomem *mmio;\n"
- ">> ?+ struct clk *clk;\n"
- ">> ?+ struct clk *gate;\n"
- ">> ?+ struct reset_control *reset;\n"
- ">> ?+\n"
- ">> ?+ struct mutex mutex; /* protect DE I/O access */\n"
- ">> ?+ u8 soc_type;\n"
- ">> ?+#define SOC_A83T 0\n"
- ">> ?+#define SOC_H3 1\n"
- ">> ?+ u8 started; /* bitmap of started mixers */\n"
- ">> ?+ u8 clean; /* bitmap of clean mixers */\n"
- ">> ?+\n"
- ">> ?+ struct drm_fbdev_cma *fbdev;\n"
- ">> ?+\n"
- ">> ?+ struct lcd *lcds[N_LCDS]; /* CRTCs */\n"
- ">> ?+};\n"
- ">> ?+\n"
- ">> ?+#define drm_to_priv(x) container_of(x, struct priv, drm)\n"
- ">> ?+\n"
- ">> ?+/* in de2_crtc.c */\n"
- ">> ?+int de2_enable_vblank(struct drm_device *drm, unsigned int crtc);\n"
- ">> ?+void de2_disable_vblank(struct drm_device *drm, unsigned int crtc);\n"
- ">> ?+void de2_vblank_reset(struct lcd *lcd);\n"
- ">> ?+extern struct platform_driver de2_lcd_platform_driver;\n"
- ">> ?+\n"
- ">> ?+#endif /* __DE2_DRM_H__ */\n"
- ">> ?diff --git a/drivers/gpu/drm/sun8i/de2_plane.c b/drivers/gpu/drm/sun8i/de2_plane.c\n"
- ">> ?new file mode 100644\n"
- ">> ?index 0000000..2fd72dc\n"
- ">> ?--- /dev/null\n"
- ">> ?+++ b/drivers/gpu/drm/sun8i/de2_plane.c\n"
- ">> ?@@ -0,0 +1,734 @@\n"
- ">> ?+/*\n"
- ">> ?+ * Allwinner DRM driver - Display Engine 2\n"
- ">> ?+ *\n"
- ">> ?+ * Copyright (C) 2016 Jean-Francois Moine <moinejf@free.fr>\n"
- ">> ?+ * Adapted from the sun8iw6 and sun8iw7 disp2 drivers\n"
- ">> ?+ * Copyright (c) 2016 Allwinnertech Co., Ltd.\n"
- ">> ?+ *\n"
- ">> ?+ * This program is free software; you can redistribute it and/or\n"
- ">> ?+ * modify it under the terms of the GNU General Public License as\n"
- ">> ?+ * published by the Free Software Foundation; either version 2 of\n"
- ">> ?+ * the License, or (at your option) any later version.\n"
- ">> ?+ */\n"
- ">> ?+\n"
- ">> ?+#include <linux/io.h>\n"
- ">> ?+#include <drm/drm_atomic_helper.h>\n"
- ">> ?+#include <drm/drm_crtc_helper.h>\n"
- ">> ?+#include <drm/drm_fb_cma_helper.h>\n"
- ">> ?+#include <drm/drm_gem_cma_helper.h>\n"
- ">> ?+#include <drm/drm_plane_helper.h>\n"
- ">> ?+\n"
- ">> ?+#include \"de2_drv.h\"\n"
- ">> ?+#include \"de2_crtc.h\"\n"
- ">> ?+\n"
- ">> ?+/* DE2 I/O map */\n"
- ">> ?+\n"
- ">> ?+#define DE2_MOD_REG 0x0000 /* 1 bit per LCD */\n"
- ">> ?+#define DE2_GATE_REG 0x0004\n"
- ">> ?+#define DE2_RESET_REG 0x0008\n"
- ">> ?+#define DE2_DIV_REG 0x000c /* 4 bits per LCD */\n"
- ">> ?+#define DE2_SEL_REG 0x0010\n"
- ">> ?+\n"
- ">> ?+#define DE2_MIXER0_BASE 0x00100000 /* LCD 0 */\n"
- ">> ?+#define DE2_MIXER1_BASE 0x00200000 /* LCD 1 */\n"
- ">> ?+\n"
- ">> ?+/* mixer registers (addr / mixer base) */\n"
- ">> ?+#define MIXER_GLB_REGS 0x00000 /* global control */\n"
- ">> ?+#define MIXER_BLD_REGS 0x01000 /* alpha blending */\n"
- ">> ?+#define MIXER_CHAN_REGS 0x02000 /* VI/UI overlay channels */\n"
- ">> ?+#define MIXER_CHAN_SZ 0x1000 /* size of a channel */\n"
- ">> ?+#define MIXER_VSU_REGS 0x20000 /* VSU */\n"
- ">> ?+#define MIXER_GSU1_REGS 0x30000 /* GSUs */\n"
- ">> ?+#define MIXER_GSU2_REGS 0x40000\n"
- ">> ?+#define MIXER_GSU3_REGS 0x50000\n"
- ">> ?+#define MIXER_FCE_REGS 0xa0000 /* FCE */\n"
- ">> ?+#define MIXER_BWS_REGS 0xa2000 /* BWS */\n"
- ">> ?+#define MIXER_LTI_REGS 0xa4000 /* LTI */\n"
- ">> ?+#define MIXER_PEAK_REGS 0xa6000 /* PEAK */\n"
- ">> ?+#define MIXER_ASE_REGS 0xa8000 /* ASE */\n"
- ">> ?+#define MIXER_FCC_REGS 0xaa000 /* FCC */\n"
- ">> ?+#define MIXER_DCSC_REGS 0xb0000 /* DCSC/SMBL */\n"
- ">> ?+\n"
- ">> ?+/* global control */\n"
- ">> ?+#define MIXER_GLB_CTL_REG 0x00\n"
- ">> ?+#define MIXER_GLB_CTL_rt_en BIT(0)\n"
- ">> ?+#define MIXER_GLB_CTL_finish_irq_en BIT(4)\n"
- ">> ?+#define MIXER_GLB_CTL_rtwb_port BIT(12)\n"
- ">> ?+#define MIXER_GLB_STATUS_REG 0x04\n"
- ">> ?+#define MIXER_GLB_DBUFF_REG 0x08\n"
- ">> ?+#define MIXER_GLB_SIZE_REG 0x0c\n"
- ">> ?+\n"
- ">> ?+/* alpha blending */\n"
- ">> ?+#define MIXER_BLD_FCOLOR_CTL_REG 0x00\n"
- ">> ?+#define MIXER_BLD_FCOLOR_CTL_PEN(pipe) (0x0100 << (pipe))\n"
- ">> ?+#define MIXER_BLD_ATTR_N 4 /* number of attribute blocks */\n"
- ">> ?+#define MIXER_BLD_ATTR_SIZE (4 * 4) /* size of an attribute block */\n"
- ">> ?+#define MIXER_BLD_ATTRx_FCOLOR(x) (0x04 + MIXER_BLD_ATTR_SIZE * (x))\n"
- ">> ?+#define MIXER_BLD_ATTRx_INSIZE(x) (0x08 + MIXER_BLD_ATTR_SIZE * (x))\n"
- ">> ?+#define MIXER_BLD_ATTRx_OFFSET(x) (0x0c + MIXER_BLD_ATTR_SIZE * (x))\n"
- ">> ?+#define MIXER_BLD_ROUTE_REG 0x80\n"
- ">> ?+#define MIXER_BLD_ROUTE(chan, pipe) ((chan) << ((pipe) * 4))\n"
- ">> ?+#define MIXER_BLD_PREMULTIPLY_REG 0x84\n"
- ">> ?+#define MIXER_BLD_BKCOLOR_REG 0x88\n"
- ">> ?+#define MIXER_BLD_OUTPUT_SIZE_REG 0x8c\n"
- ">> ?+#define MIXER_BLD_MODEx_REG(x) (0x90 + 4 * (x)) /* x = 0..3 */\n"
- ">> ?+#define MIXER_BLD_MODE_SRCOVER 0x03010301\n"
- ">> ?+#define MIXER_BLD_OUT_CTL_REG 0xfc\n"
- ">> ?+\n"
- ">> ?+/* VI channel (channel 0) */\n"
- ">> ?+#define VI_CFG_N 4 /* number of layers */\n"
- ">> ?+#define VI_CFG_SIZE 0x30 /* size of a layer */\n"
- ">> ?+#define VI_CFGx_ATTR(l) (0x00 + VI_CFG_SIZE * (l))\n"
- ">> ?+#define VI_CFG_ATTR_en BIT(0)\n"
- ">> ?+#define VI_CFG_ATTR_fcolor_en BIT(4)\n"
- ">> ?+#define VI_CFG_ATTR_fmt_SHIFT 8\n"
- ">> ?+#define VI_CFG_ATTR_fmt_MASK GENMASK(12, 8)\n"
- ">> ?+#define VI_CFG_ATTR_ui_sel BIT(15)\n"
- ">> ?+#define VI_CFG_ATTR_top_down BIT(23)\n"
- ">> ?+#define VI_CFGx_SIZE(l) (0x04 + VI_CFG_SIZE * (l))\n"
- ">> ?+#define VI_CFGx_COORD(l) (0x08 + VI_CFG_SIZE * (l))\n"
- ">> ?+#define VI_N_PLANES 3\n"
- ">> ?+#define VI_CFGx_PITCHy(l, p) (0x0c + VI_CFG_SIZE * (l) + 4 * (p))\n"
- ">> ?+#define VI_CFGx_TOP_LADDRy(l, p) (0x18 + VI_CFG_SIZE * (l) + 4 * (p))\n"
- ">> ?+#define VI_CFGx_BOT_LADDRy(l, p) (0x24 + VI_CFG_SIZE * (l) + 4 * (p))\n"
- ">> ?+#define VI_FCOLORx(l) (0xc0 + 4 * (l))\n"
- ">> ?+#define VI_TOP_HADDRx(p) (0xd0 + 4 * (p))\n"
- ">> ?+#define VI_BOT_HADDRx(p) (0xdc + 4 * (p))\n"
- ">> ?+#define VI_OVL_SIZEx(n) (0xe8 + 4 * (n))\n"
- ">> ?+#define VI_HORI_DSx(n) (0xf0 + 4 * (n))\n"
- ">> ?+#define VI_VERT_DSx(n) (0xf8 + 4 * (n))\n"
- ">> ?+#define VI_SIZE 0x100\n"
- ">> ?+\n"
- ">> ?+/* UI channel (channels 1..3) */\n"
- ">> ?+#define UI_CFG_N 4 /* number of layers */\n"
- ">> ?+#define UI_CFG_SIZE (8 * 4) /* size of a layer */\n"
- ">> ?+#define UI_CFGx_ATTR(l) (0x00 + UI_CFG_SIZE * (l))\n"
- ">> ?+#define UI_CFG_ATTR_en BIT(0)\n"
- ">> ?+#define UI_CFG_ATTR_alpmod_SHIFT 1\n"
- ">> ?+#define UI_CFG_ATTR_alpmod_MASK GENMASK(2, 1)\n"
- ">> ?+#define UI_CFG_ATTR_fcolor_en BIT(4)\n"
- ">> ?+#define UI_CFG_ATTR_fmt_SHIFT 8\n"
- ">> ?+#define UI_CFG_ATTR_fmt_MASK GENMASK(12, 8)\n"
- ">> ?+#define UI_CFG_ATTR_top_down BIT(23)\n"
- ">> ?+#define UI_CFG_ATTR_alpha_SHIFT 24\n"
- ">> ?+#define UI_CFG_ATTR_alpha_MASK GENMASK(31, 24)\n"
- ">> ?+#define UI_CFGx_SIZE(l) (0x04 + UI_CFG_SIZE * (l))\n"
- ">> ?+#define UI_CFGx_COORD(l) (0x08 + UI_CFG_SIZE * (l))\n"
- ">> ?+#define UI_CFGx_PITCH(l) (0x0c + UI_CFG_SIZE * (l))\n"
- ">> ?+#define UI_CFGx_TOP_LADDR(l) (0x10 + UI_CFG_SIZE * (l))\n"
- ">> ?+#define UI_CFGx_BOT_LADDR(l) (0x14 + UI_CFG_SIZE * (l))\n"
- ">> ?+#define UI_CFGx_FCOLOR(l) (0x18 + UI_CFG_SIZE * (l))\n"
- ">> ?+#define UI_TOP_HADDR 0x80\n"
- ">> ?+#define UI_BOT_HADDR 0x84\n"
- ">> ?+#define UI_OVL_SIZE 0x88\n"
- ">> ?+#define UI_SIZE 0x8c\n"
- ">> ?+\n"
- ">> ?+/* coordinates and sizes */\n"
- ">> ?+#define XY(x, y) (((y) << 16) | (x))\n"
- ">> ?+#define WH(w, h) ((((h) - 1) << 16) | ((w) - 1))\n"
- ">> ?+\n"
- ">> ?+/* UI video formats */\n"
- ">> ?+#define DE2_FORMAT_ARGB_8888 0\n"
- ">> ?+#define DE2_FORMAT_BGRA_8888 3\n"
- ">> ?+#define DE2_FORMAT_XRGB_8888 4\n"
- ">> ?+#define DE2_FORMAT_RGB_888 8\n"
- ">> ?+#define DE2_FORMAT_BGR_888 9\n"
- ">> ?+\n"
- ">> ?+/* VI video formats */\n"
- ">> ?+#define DE2_FORMAT_YUV422_I_YVYU 1 /* YVYU */\n"
- ">> ?+#define DE2_FORMAT_YUV422_I_UYVY 2 /* UYVY */\n"
- ">> ?+#define DE2_FORMAT_YUV422_I_YUYV 3 /* YUYV */\n"
- ">> ?+#define DE2_FORMAT_YUV422_P 6 /* YYYY UU VV planar */\n"
- ">> ?+#define DE2_FORMAT_YUV420_P 10 /* YYYY U V planar */\n"
- ">> ?+\n"
- ">> ?+/* plane formats */\n"
- ">> ?+static const uint32_t ui_formats[] = {\n"
- ">> ?+ DRM_FORMAT_ARGB8888,\n"
- ">> ?+ DRM_FORMAT_BGRA8888,\n"
- ">> ?+ DRM_FORMAT_XRGB8888,\n"
- ">> ?+ DRM_FORMAT_RGB888,\n"
- ">> ?+ DRM_FORMAT_BGR888,\n"
- ">> ?+};\n"
- ">> ?+\n"
- ">> ?+static const uint32_t vi_formats[] = {\n"
- ">> ?+ DRM_FORMAT_XRGB8888,\n"
- ">> ?+ DRM_FORMAT_YUYV,\n"
- ">> ?+ DRM_FORMAT_YVYU,\n"
- ">> ?+ DRM_FORMAT_YUV422,\n"
- ">> ?+ DRM_FORMAT_YUV420,\n"
- ">> ?+ DRM_FORMAT_UYVY,\n"
- ">> ?+ DRM_FORMAT_BGRA8888,\n"
- ">> ?+ DRM_FORMAT_RGB888,\n"
- ">> ?+ DRM_FORMAT_BGR888,\n"
- ">> ?+};\n"
- ">> ?+\n"
- ">> ?+/*\n"
- ">> ?+ * plane table\n"
- ">> ?+ *\n"
- ">> ?+ * The chosen channel/layer assignment of the planes respects\n"
- ">> ?+ * the following constraints:\n"
- ">> ?+ * - the cursor must be in a channel higher than the primary channel\n"
- ">> ?+ * - there are 4 channels in the LCD 0 and only 2 channels in the LCD 1\n"
- ">> ?+ */\n"
- ">> ?+static const struct {\n"
- ">> ?+ u8 chan;\n"
- ">> ?+ u8 layer;\n"
- ">> ?+ u8 pipe;\n"
- ">> ?+ u8 type; /* plane type */\n"
- ">> ?+ const uint32_t *formats;\n"
- ">> ?+ u8 n_formats;\n"
- ">> ?+} plane_tb[] = {\n"
- ">> ?+ [DE2_PRIMARY_PLANE] = { /* primary plane: channel 0 (VI) */\n"
- ">> ?+ 0, 0, 0,\n"
- ">> ?+ DRM_PLANE_TYPE_PRIMARY,\n"
- ">> ?+ ui_formats, ARRAY_SIZE(ui_formats),\n"
- ">> ?+ },\n"
- ">> ?+ [DE2_CURSOR_PLANE] = { /* cursor: channel 1 (UI) */\n"
- ">> ?+ 1, 0, 1,\n"
- ">> ?+ DRM_PLANE_TYPE_CURSOR,\n"
- ">> ?+ ui_formats, ARRAY_SIZE(ui_formats),\n"
- ">> ?+ },\n"
- ">> ?+ {\n"
- ">> ?+ 0, 1, 0, /* 1st overlay: channel 0, layer 1 */\n"
- ">> ?+ DRM_PLANE_TYPE_OVERLAY,\n"
- ">> ?+ vi_formats, ARRAY_SIZE(vi_formats),\n"
- ">> ?+ },\n"
- ">> ?+ {\n"
- ">> ?+ 0, 2, 0, /* 2nd overlay: channel 0, layer 2 */\n"
- ">> ?+ DRM_PLANE_TYPE_OVERLAY,\n"
- ">> ?+ vi_formats, ARRAY_SIZE(vi_formats),\n"
- ">> ?+ },\n"
- ">> ?+ {\n"
- ">> ?+ 0, 3, 0, /* 3rd overlay: channel 0, layer 3 */\n"
- ">> ?+ DRM_PLANE_TYPE_OVERLAY,\n"
- ">> ?+ vi_formats, ARRAY_SIZE(vi_formats),\n"
- ">> ?+ },\n"
- ">> ?+};\n"
- ">> ?+\n"
- ">> ?+static inline void andl_relaxed(void __iomem *addr, u32 val)\n"
- ">> ?+{\n"
- ">> ?+ writel_relaxed(readl_relaxed(addr) & val, addr);\n"
- ">> ?+}\n"
- ">> ?+\n"
- ">> ?+static inline void orl_relaxed(void __iomem *addr, u32 val)\n"
- ">> ?+{\n"
- ">> ?+ writel_relaxed(readl_relaxed(addr) | val, addr);\n"
- ">> ?+}\n"
- ">> ?+\n"
- ">> ?+/* alert the DE processor about changes in a mixer configuration */\n"
- ">> ?+static void de2_mixer_select(struct priv *priv,\n"
- ">> ?+ int mixer,\n"
- ">> ?+ void __iomem *mixer_io)\n"
- ">> ?+{\n"
- ">> ?+ /* select the mixer */\n"
- ">> ?+ andl_relaxed(priv->mmio + DE2_SEL_REG, ~1);\n"
- ">> ?+\n"
- ">> ?+ /* double register switch */\n"
- ">> ?+ writel_relaxed(1, mixer_io + MIXER_GLB_REGS + MIXER_GLB_DBUFF_REG);\n"
- ">> ?+}\n"
- ">> ?+\n"
- ">> ?+/*\n"
- ">> ?+ * cleanup a mixer\n"
- ">> ?+ *\n"
- ">> ?+ * This is needed only once after power on.\n"
- ">> ?+ */\n"
- ">> ?+static void de2_mixer_cleanup(struct priv *priv, int mixer,\n"
- ">> ?+ u32 size)\n"
- ">> ?+{\n"
- ">> ?+ void __iomem *mixer_io = priv->mmio;\n"
- ">> ?+ void __iomem *chan_io;\n"
- ">> ?+ u32 data;\n"
- ">> ?+ unsigned int i;\n"
- ">> ?+\n"
- ">> ?+ mixer_io += (mixer == 0) ? DE2_MIXER0_BASE : DE2_MIXER1_BASE;\n"
- ">> ?+ chan_io = mixer_io + MIXER_CHAN_REGS;\n"
- ">> ?+\n"
- ">> ?+ andl_relaxed(priv->mmio + DE2_SEL_REG, ~1);\n"
- ">> ?+ writel_relaxed(1, mixer_io + MIXER_GLB_REGS + MIXER_GLB_DBUFF_REG);\n"
- ">> ?+\n"
- ">> ?+ writel_relaxed(MIXER_GLB_CTL_rt_en,\n"
- ">> ?+ mixer_io + MIXER_GLB_REGS + MIXER_GLB_CTL_REG);\n"
- ">> ?+ writel_relaxed(0, mixer_io + MIXER_GLB_REGS + MIXER_GLB_STATUS_REG);\n"
- ">> ?+\n"
- ">> ?+ writel_relaxed(size, mixer_io + MIXER_GLB_REGS + MIXER_GLB_SIZE_REG);\n"
- ">> ?+\n"
- ">> ?+ /*\n"
- ">> ?+ * clear the VI/UI channels\n"
- ">> ?+ * LCD0: 1 VI and 3 UIs\n"
- ">> ?+ * LCD1: 1 VI and 1 UI\n"
- ">> ?+ */\n"
- ">> ?+ memset_io(chan_io, 0, VI_SIZE);\n"
- ">> ?+ memset_io(chan_io + MIXER_CHAN_SZ, 0, UI_SIZE);\n"
- ">> ?+ if (mixer == 0) {\n"
- ">> ?+ memset_io(chan_io + MIXER_CHAN_SZ * 2, 0, UI_SIZE);\n"
- ">> ?+ memset_io(chan_io + MIXER_CHAN_SZ * 3, 0, UI_SIZE);\n"
- ">> ?+ }\n"
- ">> ?+\n"
- ">> ?+ /* alpha blending */\n"
- ">> ?+ writel_relaxed(0x00000001 | /* fcolor for primary */\n"
- ">> ?+ MIXER_BLD_FCOLOR_CTL_PEN(0),\n"
- ">> ?+ mixer_io + MIXER_BLD_REGS + MIXER_BLD_FCOLOR_CTL_REG);\n"
- ">> ?+ for (i = 0; i < MIXER_BLD_ATTR_N; i++) {\n"
- ">> ?+ writel_relaxed(0xff000000,\n"
- ">> ?+ mixer_io + MIXER_BLD_REGS + MIXER_BLD_ATTRx_FCOLOR(i));\n"
- ">> ?+ writel_relaxed(size,\n"
- ">> ?+ mixer_io + MIXER_BLD_REGS + MIXER_BLD_ATTRx_INSIZE(i));\n"
- ">> ?+ writel_relaxed(0,\n"
- ">> ?+ mixer_io + MIXER_BLD_REGS + MIXER_BLD_ATTRx_OFFSET(i));\n"
- ">> ?+ }\n"
- ">> ?+ writel_relaxed(0, mixer_io + MIXER_BLD_REGS + MIXER_BLD_OUT_CTL_REG);\n"
- ">> ?+\n"
- ">> ?+ /* prepare the pipe route for the planes */\n"
- ">> ?+ data = 0;\n"
- ">> ?+ for (i = 0; i < DE2_N_PLANES; i++)\n"
- ">> ?+ data |= MIXER_BLD_ROUTE(plane_tb[i].chan, plane_tb[i].pipe);\n"
- ">> ?+ writel_relaxed(data, mixer_io + MIXER_BLD_REGS + MIXER_BLD_ROUTE_REG);\n"
- ">> ?+\n"
- ">> ?+ writel_relaxed(0, mixer_io + MIXER_BLD_REGS +\n"
- ">> ?+ MIXER_BLD_PREMULTIPLY_REG);\n"
- ">> ?+ writel_relaxed(0xff000000, mixer_io + MIXER_BLD_REGS +\n"
- ">> ?+ MIXER_BLD_BKCOLOR_REG);\n"
- ">> ?+ writel_relaxed(size, mixer_io + MIXER_BLD_REGS +\n"
- ">> ?+ MIXER_BLD_OUTPUT_SIZE_REG);\n"
- ">> ?+ writel_relaxed(MIXER_BLD_MODE_SRCOVER,\n"
- ">> ?+ mixer_io + MIXER_BLD_REGS + MIXER_BLD_MODEx_REG(0));\n"
- ">> ?+ writel_relaxed(MIXER_BLD_MODE_SRCOVER,\n"
- ">> ?+ mixer_io + MIXER_BLD_REGS + MIXER_BLD_MODEx_REG(1));\n"
- ">> ?+\n"
- ">> ?+ /* disable the enhancements */\n"
- ">> ?+ writel_relaxed(0, mixer_io + MIXER_VSU_REGS);\n"
- ">> ?+ writel_relaxed(0, mixer_io + MIXER_GSU1_REGS);\n"
- ">> ?+ writel_relaxed(0, mixer_io + MIXER_GSU2_REGS);\n"
- ">> ?+ writel_relaxed(0, mixer_io + MIXER_GSU3_REGS);\n"
- ">> ?+ writel_relaxed(0, mixer_io + MIXER_FCE_REGS);\n"
- ">> ?+ writel_relaxed(0, mixer_io + MIXER_BWS_REGS);\n"
- ">> ?+ writel_relaxed(0, mixer_io + MIXER_LTI_REGS);\n"
- ">> ?+ writel_relaxed(0, mixer_io + MIXER_PEAK_REGS);\n"
- ">> ?+ writel_relaxed(0, mixer_io + MIXER_ASE_REGS);\n"
- ">> ?+ writel_relaxed(0, mixer_io + MIXER_FCC_REGS);\n"
- ">> ?+ writel_relaxed(0, mixer_io + MIXER_DCSC_REGS);\n"
- ">> ?+}\n"
- ">> ?+\n"
- ">> ?+/* enable a mixer */\n"
- ">> ?+static void de2_mixer_enable(struct lcd *lcd)\n"
- ">> ?+{\n"
- ">> ?+ struct priv *priv = lcd->priv;\n"
- ">> ?+ void __iomem *mixer_io = priv->mmio;\n"
- ">> ?+ struct drm_display_mode *mode = &lcd->crtc.mode;\n"
- ">> ?+ u32 size = WH(mode->hdisplay, mode->vdisplay);\n"
- ">> ?+ u32 data;\n"
- ">> ?+ int mixer = lcd->mixer;\n"
- ">> ?+ int i;\n"
- ">> ?+\n"
- ">> ?+ mixer_io += (mixer == 0) ? DE2_MIXER0_BASE : DE2_MIXER1_BASE;\n"
- ">> ?+\n"
- ">> ?+ /* if not done yet, start the DE processor */\n"
- ">> ?+ if (!priv->started) {\n"
- ">> ?+ reset_control_deassert(priv->reset);\n"
- ">> ?+ clk_prepare_enable(priv->gate);\n"
- ">> ?+ clk_prepare_enable(priv->clk);\n"
- ">> ?+ }\n"
- ">> ?+ priv->started |= 1 << mixer;\n"
- ">> ?+\n"
- ">> ?+ /* set the A83T clock divider (500 / 2) = 250MHz */\n"
- ">> ?+ if (priv->soc_type == SOC_A83T)\n"
- ">> ?+ writel_relaxed(0x00000011, /* div = 2 for both LCDs */\n"
- ">> ?+ priv->mmio + DE2_DIV_REG);\n"
- ">> ?+\n"
- ">> ?+ /* deassert the mixer and enable its clock */\n"
- ">> ?+ orl_relaxed(priv->mmio + DE2_RESET_REG, mixer == 0 ? 1 : 4);\n"
- ">> ?+ data = 1 << mixer; /* 1 bit / lcd */\n"
- ">> ?+ orl_relaxed(priv->mmio + DE2_GATE_REG, data);\n"
- ">> ?+ orl_relaxed(priv->mmio + DE2_MOD_REG, data);\n"
- ">> ?+\n"
- ">> ?+ /* if not done yet, cleanup and enable */\n"
- ">> ?+ if (!(priv->clean & (1 << mixer))) {\n"
- ">> ?+ priv->clean |= 1 << mixer;\n"
- ">> ?+ de2_mixer_cleanup(priv, mixer, size);\n"
- ">> ?+ return;\n"
- ">> ?+ }\n"
- ">> ?+\n"
- ">> ?+ /* enable */\n"
- ">> ?+ de2_mixer_select(priv, mixer, mixer_io);\n"
- ">> ?+\n"
- ">> ?+ writel_relaxed(MIXER_GLB_CTL_rt_en,\n"
- ">> ?+ mixer_io + MIXER_GLB_REGS + MIXER_GLB_CTL_REG);\n"
- ">> ?+ writel_relaxed(0, mixer_io + MIXER_GLB_REGS + MIXER_GLB_STATUS_REG);\n"
- ">> ?+\n"
- ">> ?+ /* set the size of the frame buffer */\n"
- ">> ?+ writel_relaxed(size, mixer_io + MIXER_GLB_REGS + MIXER_GLB_SIZE_REG);\n"
- ">> ?+ for (i = 0; i < MIXER_BLD_ATTR_N; i++)\n"
- ">> ?+ writel_relaxed(size, mixer_io + MIXER_BLD_REGS +\n"
- ">> ?+ MIXER_BLD_ATTRx_INSIZE(i));\n"
- ">> ?+ writel_relaxed(size, mixer_io + MIXER_BLD_REGS +\n"
- ">> ?+ MIXER_BLD_OUTPUT_SIZE_REG);\n"
- ">> ?+\n"
- ">> ?+ writel_relaxed(mode->flags & DRM_MODE_FLAG_INTERLACE ? 2 : 0,\n"
- ">> ?+ mixer_io + MIXER_BLD_REGS + MIXER_BLD_OUT_CTL_REG);\n"
- ">> ?+}\n"
- ">> ?+\n"
- ">> ?+/* enable a LCD (DE mixer) */\n"
- ">> ?+void de2_de_enable(struct lcd *lcd)\n"
- ">> ?+{\n"
- ">> ?+ mutex_lock(&lcd->priv->mutex);\n"
- ">> ?+\n"
- ">> ?+ de2_mixer_enable(lcd);\n"
- ">> ?+\n"
- ">> ?+ mutex_unlock(&lcd->priv->mutex);\n"
- ">> ?+}\n"
- ">> ?+\n"
- ">> ?+/* disable a LCD (DE mixer) */\n"
- ">> ?+void de2_de_disable(struct lcd *lcd)\n"
- ">> ?+{\n"
- ">> ?+ struct priv *priv = lcd->priv;\n"
- ">> ?+ void __iomem *mixer_io = priv->mmio;\n"
- ">> ?+ int mixer = lcd->mixer;\n"
- ">> ?+ u32 data;\n"
- ">> ?+\n"
- ">> ?+ mixer_io += (mixer == 0) ? DE2_MIXER0_BASE : DE2_MIXER1_BASE;\n"
- ">> ?+\n"
- ">> ?+ mutex_lock(&priv->mutex);\n"
- ">> ?+\n"
- ">> ?+ de2_mixer_select(priv, mixer, mixer_io);\n"
- ">> ?+\n"
- ">> ?+ writel_relaxed(0, mixer_io + MIXER_GLB_REGS + MIXER_GLB_CTL_REG);\n"
- ">> ?+\n"
- ">> ?+ data = ~(1 << mixer);\n"
- ">> ?+ andl_relaxed(priv->mmio + DE2_MOD_REG, data);\n"
- ">> ?+ andl_relaxed(priv->mmio + DE2_GATE_REG, data);\n"
- ">> ?+ andl_relaxed(priv->mmio + DE2_RESET_REG, data);\n"
- ">> ?+\n"
- ">> ?+ mutex_unlock(&priv->mutex);\n"
- ">> ?+\n"
- ">> ?+ /* if all mixers are disabled, stop the DE */\n"
- ">> ?+ priv->started &= ~(1 << mixer);\n"
- ">> ?+ if (!priv->started) {\n"
- ">> ?+ clk_disable_unprepare(priv->clk);\n"
- ">> ?+ clk_disable_unprepare(priv->gate);\n"
- ">> ?+ reset_control_assert(priv->reset);\n"
- ">> ?+ }\n"
- ">> ?+}\n"
- ">> ?+\n"
- ">> ?+static void de2_vi_update(void __iomem *chan_io,\n"
- ">> ?+ struct drm_gem_cma_object *gem,\n"
- ">> ?+ int layer,\n"
- ">> ?+ unsigned int fmt,\n"
- ">> ?+ u32 ui_sel,\n"
- ">> ?+ u32 size,\n"
- ">> ?+ u32 coord,\n"
- ">> ?+ struct drm_framebuffer *fb,\n"
- ">> ?+ u32 screen_size)\n"
- ">> ?+{\n"
- ">> ?+ int i;\n"
- ">> ?+\n"
- ">> ?+ writel_relaxed(VI_CFG_ATTR_en |\n"
- ">> ?+ (fmt << VI_CFG_ATTR_fmt_SHIFT) |\n"
- ">> ?+ ui_sel,\n"
- ">> ?+ chan_io + VI_CFGx_ATTR(layer));\n"
- ">> ?+ writel_relaxed(size, chan_io + VI_CFGx_SIZE(layer));\n"
- ">> ?+ writel_relaxed(coord, chan_io + VI_CFGx_COORD(layer));\n"
- ">> ?+ for (i = 0; i < VI_N_PLANES; i++) {\n"
- ">> ?+ writel_relaxed(fb->pitches[i] ? fb->pitches[i] :\n"
- ">> ?+ fb->pitches[0],\n"
- ">> ?+ chan_io + VI_CFGx_PITCHy(layer, i));\n"
- ">> ?+ writel_relaxed(gem->paddr + fb->offsets[i],\n"
- ">> ?+ chan_io + VI_CFGx_TOP_LADDRy(layer, i));\n"
- ">> ?+ }\n"
- ">> ?+ writel_relaxed(0xff000000, chan_io + VI_FCOLORx(layer));\n"
- ">> ?+ if (layer == 0) {\n"
- ">> ?+ writel_relaxed(screen_size,\n"
- ">> ?+ chan_io + VI_OVL_SIZEx(0));\n"
- ">> ?+ }\n"
- ">> ?+}\n"
- ">> ?+\n"
- ">> ?+static void de2_ui_update(void __iomem *chan_io,\n"
- ">> ?+ struct drm_gem_cma_object *gem,\n"
- ">> ?+ int layer,\n"
- ">> ?+ unsigned int fmt,\n"
- ">> ?+ u32 alpha_glob,\n"
- ">> ?+ u32 size,\n"
- ">> ?+ u32 coord,\n"
- ">> ?+ struct drm_framebuffer *fb,\n"
- ">> ?+ u32 screen_size)\n"
- ">> ?+{\n"
- ">> ?+ writel_relaxed(UI_CFG_ATTR_en |\n"
- ">> ?+ (fmt << UI_CFG_ATTR_fmt_SHIFT) |\n"
- ">> ?+ alpha_glob,\n"
- ">> ?+ chan_io + UI_CFGx_ATTR(layer));\n"
- ">> ?+ writel_relaxed(size, chan_io + UI_CFGx_SIZE(layer));\n"
- ">> ?+ writel_relaxed(coord, chan_io + UI_CFGx_COORD(layer));\n"
- ">> ?+ writel_relaxed(fb->pitches[0], chan_io + UI_CFGx_PITCH(layer));\n"
- ">> ?+ writel_relaxed(gem->paddr + fb->offsets[0],\n"
- ">> ?+ chan_io + UI_CFGx_TOP_LADDR(layer));\n"
- ">> ?+ if (layer == 0)\n"
- ">> ?+ writel_relaxed(screen_size, chan_io + UI_OVL_SIZE);\n"
- ">> ?+}\n"
- ">> ?+\n"
- ">> ?+static void de2_plane_update(struct priv *priv, struct lcd *lcd,\n"
- ">> ?+ int plane_num,\n"
- ">> ?+ struct drm_plane_state *state,\n"
- ">> ?+ struct drm_plane_state *old_state)\n"
- ">> ?+{\n"
- ">> ?+ void __iomem *mixer_io = priv->mmio;\n"
- ">> ?+ void __iomem *chan_io;\n"
- ">> ?+ struct drm_framebuffer *fb = state->fb;\n"
- ">> ?+ struct drm_gem_cma_object *gem;\n"
- ">> ?+ u32 size = WH(state->crtc_w, state->crtc_h);\n"
- ">> ?+ u32 coord, screen_size;\n"
- ">> ?+ u32 fcolor;\n"
- ">> ?+ u32 ui_sel, alpha_glob;\n"
- ">> ?+ int mixer = lcd->mixer;\n"
- ">> ?+ int chan, layer, x, y;\n"
- ">> ?+ unsigned int fmt;\n"
- ">> ?+\n"
- ">> ?+ chan = plane_tb[plane_num].chan;\n"
- ">> ?+ layer = plane_tb[plane_num].layer;\n"
- ">> ?+\n"
- ">> ?+ mixer_io += (mixer == 0) ? DE2_MIXER0_BASE : DE2_MIXER1_BASE;\n"
- ">> ?+ chan_io = mixer_io + MIXER_CHAN_REGS + MIXER_CHAN_SZ * chan;\n"
- ">> ?+\n"
- ">> ?+ x = state->crtc_x >= 0 ? state->crtc_x : 0;\n"
- ">> ?+ y = state->crtc_y >= 0 ? state->crtc_y : 0;\n"
- ">> ?+ coord = XY(x, y);\n"
- ">> ?+\n"
- ">> ?+ /* if plane update was delayed, force a full update */\n"
- ">> ?+ if (priv->lcds[drm_crtc_index(&lcd->crtc)]->delayed &\n"
- ">> ?+ (1 << plane_num)) {\n"
- ">> ?+ priv->lcds[drm_crtc_index(&lcd->crtc)]->delayed &=\n"
- ">> ?+ ~(1 << plane_num);\n"
- ">> ?+\n"
- ">> ?+ /* handle plane move */\n"
- ">> ?+ } else if (fb == old_state->fb) {\n"
- ">> ?+ de2_mixer_select(priv, mixer, mixer_io);\n"
- ">> ?+ if (chan == 0)\n"
- ">> ?+ writel_relaxed(coord, chan_io + VI_CFGx_COORD(layer));\n"
- ">> ?+ else\n"
- ">> ?+ writel_relaxed(coord, chan_io + UI_CFGx_COORD(layer));\n"
- ">> ?+ return;\n"
- ">> ?+ }\n"
- ">> ?+\n"
- ">> ?+ gem = drm_fb_cma_get_gem_obj(fb, 0);\n"
- ">> ?+\n"
- ">> ?+ ui_sel = alpha_glob = 0;\n"
- ">> ?+\n"
- ">> ?+ switch (fb->pixel_format) {\n"
- ">> ?+ case DRM_FORMAT_ARGB8888:\n"
- ">> ?+ fmt = DE2_FORMAT_ARGB_8888;\n"
- ">> ?+ ui_sel = VI_CFG_ATTR_ui_sel;\n"
- ">> ?+ break;\n"
- ">> ?+ case DRM_FORMAT_BGRA8888:\n"
- ">> ?+ fmt = DE2_FORMAT_BGRA_8888;\n"
- ">> ?+ ui_sel = VI_CFG_ATTR_ui_sel;\n"
- ">> ?+ break;\n"
- ">> ?+ case DRM_FORMAT_XRGB8888:\n"
- ">> ?+ fmt = DE2_FORMAT_XRGB_8888;\n"
- ">> ?+ ui_sel = VI_CFG_ATTR_ui_sel;\n"
- ">> ?+ alpha_glob = (1 << UI_CFG_ATTR_alpmod_SHIFT) |\n"
- ">> ?+ (0xff << UI_CFG_ATTR_alpha_SHIFT);\n"
- ">> ?+ break;\n"
- ">> ?+ case DRM_FORMAT_RGB888:\n"
- ">> ?+ fmt = DE2_FORMAT_RGB_888;\n"
- ">> ?+ ui_sel = VI_CFG_ATTR_ui_sel;\n"
- ">> ?+ break;\n"
- ">> ?+ case DRM_FORMAT_BGR888:\n"
- ">> ?+ fmt = DE2_FORMAT_BGR_888;\n"
- ">> ?+ ui_sel = VI_CFG_ATTR_ui_sel;\n"
- ">> ?+ break;\n"
- ">> ?+ case DRM_FORMAT_YUYV:\n"
- ">> ?+ fmt = DE2_FORMAT_YUV422_I_YUYV;\n"
- ">> ?+ break;\n"
- ">> ?+ case DRM_FORMAT_YVYU:\n"
- ">> ?+ fmt = DE2_FORMAT_YUV422_I_YVYU;\n"
- ">> ?+ break;\n"
- ">> ?+ case DRM_FORMAT_YUV422:\n"
- ">> ?+ fmt = DE2_FORMAT_YUV422_P;\n"
- ">> ?+ break;\n"
- ">> ?+ case DRM_FORMAT_YUV420:\n"
- ">> ?+ fmt = DE2_FORMAT_YUV420_P;\n"
- ">> ?+ break;\n"
- ">> ?+ case DRM_FORMAT_UYVY:\n"
- ">> ?+ fmt = DE2_FORMAT_YUV422_I_UYVY;\n"
- ">> ?+ break;\n"
- ">> ?+ default:\n"
- ">> ?+ pr_err(\"de2_plane_update: format %.4s not yet treated\\n\",\n"
- ">> ?+ (char *) &fb->pixel_format);\n"
- ">> ?+ return;\n"
- ">> ?+ }\n"
- ">> ?+\n"
- ">> ?+ /* the overlay size is the one of the primary plane */\n"
- ">> ?+ screen_size = plane_num == DE2_PRIMARY_PLANE ?\n"
- ">> ?+ size :\n"
- ">> ?+ readl_relaxed(mixer_io + MIXER_GLB_REGS + MIXER_GLB_SIZE_REG);\n"
- ">> ?+\n"
- ">> ?+ /* prepare pipe enable */\n"
- ">> ?+ fcolor = readl_relaxed(mixer_io + MIXER_BLD_REGS +\n"
- ">> ?+ MIXER_BLD_FCOLOR_CTL_REG);\n"
- ">> ?+ fcolor |= MIXER_BLD_FCOLOR_CTL_PEN(plane_tb[plane_num].pipe);\n"
- ">> ?+\n"
- ">> ?+ de2_mixer_select(priv, mixer, mixer_io);\n"
- ">> ?+\n"
- ">> ?+ if (chan == 0) /* VI channel */\n"
- ">> ?+ de2_vi_update(chan_io, gem, layer, fmt, ui_sel, size, coord,\n"
- ">> ?+ fb, screen_size);\n"
- ">> ?+ else /* UI channel */\n"
- ">> ?+ de2_ui_update(chan_io, gem, layer, fmt, alpha_glob, size, coord,\n"
- ">> ?+ fb, screen_size);\n"
- ">> ?+ writel_relaxed(fcolor, mixer_io + MIXER_BLD_REGS +\n"
- ">> ?+ MIXER_BLD_FCOLOR_CTL_REG);\n"
- ">> ?+}\n"
- ">> ?+\n"
- ">> ?+static int vi_nb_layers(void __iomem *chan_io)\n"
- ">> ?+{\n"
- ">> ?+ int layer, n = 0;\n"
- ">> ?+\n"
- ">> ?+ for (layer = 0; layer < 4; layer++) {\n"
- ">> ?+ if (readl_relaxed(chan_io + VI_CFGx_ATTR(layer)) != 0)\n"
- ">> ?+ n++;\n"
- ">> ?+ }\n"
- ">> ?+\n"
- ">> ?+ return n;\n"
- ">> ?+}\n"
- ">> ?+\n"
- ">> ?+static int ui_nb_layers(void __iomem *chan_io)\n"
- ">> ?+{\n"
- ">> ?+ int layer, n = 0;\n"
- ">> ?+\n"
- ">> ?+ for (layer = 0; layer < 4; layer++) {\n"
- ">> ?+ if (readl_relaxed(chan_io + UI_CFGx_ATTR(layer)) != 0)\n"
- ">> ?+ n++;\n"
- ">> ?+ }\n"
- ">> ?+\n"
- ">> ?+ return n;\n"
- ">> ?+}\n"
- ">> ?+\n"
- ">> ?+static void de2_plane_disable(struct priv *priv,\n"
- ">> ?+ int mixer, int plane_num)\n"
- ">> ?+{\n"
- ">> ?+ void __iomem *mixer_io = priv->mmio;\n"
- ">> ?+ void __iomem *chan_io;\n"
- ">> ?+ u32 fcolor;\n"
- ">> ?+ int chan, layer, n;\n"
- ">> ?+\n"
- ">> ?+ chan = plane_tb[plane_num].chan;\n"
- ">> ?+ layer = plane_tb[plane_num].layer;\n"
- ">> ?+\n"
- ">> ?+ mixer_io += (mixer == 0) ? DE2_MIXER0_BASE : DE2_MIXER1_BASE;\n"
- ">> ?+ chan_io = mixer_io + MIXER_CHAN_REGS + MIXER_CHAN_SZ * chan;\n"
- ">> ?+\n"
- ">> ?+ if (chan == 0)\n"
- ">> ?+ n = vi_nb_layers(chan_io);\n"
- ">> ?+ else\n"
- ">> ?+ n = ui_nb_layers(chan_io);\n"
- ">> ?+\n"
- ">> ?+ fcolor = readl_relaxed(mixer_io + MIXER_BLD_REGS +\n"
- ">> ?+ MIXER_BLD_FCOLOR_CTL_REG);\n"
- ">> ?+\n"
- ">> ?+ de2_mixer_select(priv, mixer, mixer_io);\n"
- ">> ?+\n"
- ">> ?+ if (chan == 0)\n"
- ">> ?+ writel_relaxed(0, chan_io + VI_CFGx_ATTR(layer));\n"
- ">> ?+ else\n"
- ">> ?+ writel_relaxed(0, chan_io + UI_CFGx_ATTR(layer));\n"
- ">> ?+\n"
- ">> ?+ /* disable the pipe if no more active layer */\n"
- ">> ?+ if (n <= 1)\n"
- ">> ?+ writel_relaxed(fcolor &\n"
- ">> ?+ ~MIXER_BLD_FCOLOR_CTL_PEN(plane_tb[plane_num].pipe),\n"
- ">> ?+ mixer_io + MIXER_BLD_REGS + MIXER_BLD_FCOLOR_CTL_REG);\n"
- ">> ?+}\n"
- ">> ?+\n"
- ">> ?+static void de2_drm_plane_update(struct drm_plane *plane,\n"
- ">> ?+ struct drm_plane_state *old_state)\n"
- ">> ?+{\n"
- ">> ?+ struct drm_plane_state *state = plane->state;\n"
- ">> ?+ struct drm_crtc *crtc = state->crtc;\n"
- ">> ?+ struct lcd *lcd = crtc_to_lcd(crtc);\n"
- ">> ?+ struct priv *priv = lcd->priv;\n"
- ">> ?+ int plane_num = plane - lcd->planes;\n"
- ">> ?+\n"
- ">> ?+ /* if the crtc is disabled, mark update delayed */\n"
- ">> ?+ if (!(priv->started & (1 << lcd->mixer))) {\n"
- ">> ?+ lcd->delayed |= 1 << plane_num;\n"
- ">> ?+ return; /* mixer disabled */\n"
- ">> ?+ }\n"
- ">> ?+\n"
- ">> ?+ mutex_lock(&priv->mutex);\n"
- ">> ?+\n"
- ">> ?+ de2_plane_update(priv, lcd, plane_num, state, old_state);\n"
- ">> ?+\n"
- ">> ?+ mutex_unlock(&priv->mutex);\n"
- ">> ?+}\n"
- ">> ?+\n"
- ">> ?+static void de2_drm_plane_disable(struct drm_plane *plane,\n"
- ">> ?+ struct drm_plane_state *old_state)\n"
- ">> ?+{\n"
- ">> ?+ struct drm_crtc *crtc = old_state->crtc;\n"
- ">> ?+ struct lcd *lcd = crtc_to_lcd(crtc);\n"
- ">> ?+ struct priv *priv = lcd->priv;\n"
- ">> ?+ int plane_num = plane - lcd->planes;\n"
- ">> ?+\n"
- ">> ?+ if (!(priv->started & (1 << lcd->mixer)))\n"
- ">> ?+ return; /* mixer disabled */\n"
- ">> ?+\n"
- ">> ?+ mutex_lock(&priv->mutex);\n"
- ">> ?+\n"
- ">> ?+ de2_plane_disable(lcd->priv, lcd->mixer, plane_num);\n"
- ">> ?+\n"
- ">> ?+ mutex_unlock(&priv->mutex);\n"
- ">> ?+}\n"
- ">> ?+\n"
- ">> ?+static const struct drm_plane_helper_funcs plane_helper_funcs = {\n"
- ">> ?+ .atomic_update = de2_drm_plane_update,\n"
- ">> ?+ .atomic_disable = de2_drm_plane_disable,\n"
- ">> ?+};\n"
- ">> ?+\n"
- ">> ?+static const struct drm_plane_funcs plane_funcs = {\n"
- ">> ?+ .update_plane = drm_atomic_helper_update_plane,\n"
- ">> ?+ .disable_plane = drm_atomic_helper_disable_plane,\n"
- ">> ?+ .destroy = drm_plane_cleanup,\n"
- ">> ?+ .reset = drm_atomic_helper_plane_reset,\n"
- ">> ?+ .atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state,\n"
- ">> ?+ .atomic_destroy_state = drm_atomic_helper_plane_destroy_state,\n"
- ">> ?+};\n"
- ">> ?+\n"
- ">> ?+static int de2_one_plane_init(struct drm_device *drm,\n"
- ">> ?+ struct drm_plane *plane,\n"
- ">> ?+ int possible_crtcs,\n"
- ">> ?+ int plane_num)\n"
- ">> ?+{\n"
- ">> ?+ int ret;\n"
- ">> ?+\n"
- ">> ?+ ret = drm_universal_plane_init(drm, plane, possible_crtcs,\n"
- ">> ?+ &plane_funcs,\n"
- ">> ?+ plane_tb[plane_num].formats,\n"
- ">> ?+ plane_tb[plane_num].n_formats,\n"
- ">> ?+ plane_tb[plane_num].type, NULL);\n"
- ">> ?+ if (ret >= 0)\n"
- ">> ?+ drm_plane_helper_add(plane, &plane_helper_funcs);\n"
- ">> ?+\n"
- ">> ?+ return ret;\n"
- ">> ?+}\n"
- ">> ?+\n"
- ">> ?+/* initialize the planes */\n"
- ">> ?+int de2_plane_init(struct drm_device *drm, struct lcd *lcd)\n"
- ">> ?+{\n"
- ">> ?+ int i, n, ret, possible_crtcs = 1 << drm_crtc_index(&lcd->crtc);\n"
- ">> ?+\n"
- ">> ?+ n = ARRAY_SIZE(plane_tb);\n"
- ">> ?+ if (n != DE2_N_PLANES) {\n"
- ">> ?+ dev_err(lcd->dev, \"Bug: incorrect number of planes %d != \"\n"
- ">> ?+ __stringify(DE2_N_PLANES) \"\\n\", n);\n"
- ">> ?+ return -EINVAL;\n"
- ">> ?+ }\n"
- ">> ?+\n"
- ">> ?+ for (i = 0; i < n; i++) {\n"
- ">> ?+ ret = de2_one_plane_init(drm, &lcd->planes[i],\n"
- ">> ?+ possible_crtcs, i);\n"
- ">> ?+ if (ret < 0) {\n"
- ">> ?+ dev_err(lcd->dev, \"plane init failed %d\\n\", ret);\n"
- ">> ?+ break;\n"
- ">> ?+ }\n"
- ">> ?+ }\n"
- ">> ?+\n"
- ">> ?+ return ret;\n"
- ">> ?+}\n"
- ">> ?--\n"
- ">> ?2.10.2\n"
+ ">> \302\240\302\240source \"drivers/gpu/drm/tilcdc/Kconfig\"\n"
+ ">> \302\240diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile\n"
+ ">> \302\240index 883f3e7..3e1eaa0 100644\n"
+ ">> \302\240--- a/drivers/gpu/drm/Makefile\n"
+ ">> \302\240+++ b/drivers/gpu/drm/Makefile\n"
+ ">> \302\240@@ -72,6 +72,7 @@ obj-$(CONFIG_DRM_RCAR_DU) += rcar-du/\n"
+ ">> \302\240\302\240obj-$(CONFIG_DRM_SHMOBILE) +=shmobile/\n"
+ ">> \302\240\302\240obj-y += omapdrm/\n"
+ ">> \302\240\302\240obj-$(CONFIG_DRM_SUN4I) += sun4i/\n"
+ ">> \302\240+obj-$(CONFIG_DRM_SUN8I) += sun8i/\n"
+ ">> \302\240\302\240obj-y += tilcdc/\n"
+ ">> \302\240\302\240obj-$(CONFIG_DRM_QXL) += qxl/\n"
+ ">> \302\240\302\240obj-$(CONFIG_DRM_BOCHS) += bochs/\n"
+ ">> \302\240diff --git a/drivers/gpu/drm/sun8i/Kconfig b/drivers/gpu/drm/sun8i/Kconfig\n"
+ ">> \302\240new file mode 100644\n"
+ ">> \302\240index 0000000..6940895\n"
+ ">> \302\240--- /dev/null\n"
+ ">> \302\240+++ b/drivers/gpu/drm/sun8i/Kconfig\n"
+ ">> \302\240@@ -0,0 +1,19 @@\n"
+ ">> \302\240+#\n"
+ ">> \302\240+# Allwinner DE2 Video configuration\n"
+ ">> \302\240+#\n"
+ ">> \302\240+\n"
+ ">> \302\240+config DRM_SUN8I\n"
+ ">> \302\240+ bool\n"
+ ">> \302\240+\n"
+ ">> \302\240+config DRM_SUN8I_DE2\n"
+ ">> \302\240+ tristate \"Support for Allwinner Video with DE2 interface\"\n"
+ ">> \302\240+ depends on DRM && OF\n"
+ ">> \302\240+ depends on ARCH_SUNXI || COMPILE_TEST\n"
+ ">> \302\240+ select DRM_GEM_CMA_HELPER\n"
+ ">> \302\240+ select DRM_KMS_CMA_HELPER\n"
+ ">> \302\240+ select DRM_KMS_HELPER\n"
+ ">> \302\240+ select DRM_SUN8I\n"
+ ">> \302\240+ help\n"
+ ">> \302\240+ Choose this option if your Allwinner chipset has the DE2 interface\n"
+ ">> \302\240+ as the A64, A83T and H3. If M is selected the module will be called\n"
+ ">> \302\240+ sun8i-de2-drm.\n"
+ ">> \302\240diff --git a/drivers/gpu/drm/sun8i/Makefile b/drivers/gpu/drm/sun8i/Makefile\n"
+ ">> \302\240new file mode 100644\n"
+ ">> \302\240index 0000000..f107919\n"
+ ">> \302\240--- /dev/null\n"
+ ">> \302\240+++ b/drivers/gpu/drm/sun8i/Makefile\n"
+ ">> \302\240@@ -0,0 +1,7 @@\n"
+ ">> \302\240+#\n"
+ ">> \302\240+# Makefile for Allwinner's sun8i DRM device driver\n"
+ ">> \302\240+#\n"
+ ">> \302\240+\n"
+ ">> \302\240+sun8i-de2-drm-objs := de2_drv.o de2_crtc.o de2_plane.o\n"
+ ">> \302\240+\n"
+ ">> \302\240+obj-$(CONFIG_DRM_SUN8I_DE2) += sun8i-de2-drm.o\n"
+ ">> \302\240diff --git a/drivers/gpu/drm/sun8i/de2_crtc.c b/drivers/gpu/drm/sun8i/de2_crtc.c\n"
+ ">> \302\240new file mode 100644\n"
+ ">> \302\240index 0000000..4e94ccc\n"
+ ">> \302\240--- /dev/null\n"
+ ">> \302\240+++ b/drivers/gpu/drm/sun8i/de2_crtc.c\n"
+ ">> \302\240@@ -0,0 +1,449 @@\n"
+ ">> \302\240+/*\n"
+ ">> \302\240+ * Allwinner DRM driver - DE2 CRTC\n"
+ ">> \302\240+ *\n"
+ ">> \302\240+ * Copyright (C) 2016 Jean-Francois Moine <moinejf-GANU6spQydw@public.gmane.org>\n"
+ ">> \302\240+ *\n"
+ ">> \302\240+ * This program is free software; you can redistribute it and/or\n"
+ ">> \302\240+ * modify it under the terms of the GNU General Public License as\n"
+ ">> \302\240+ * published by the Free Software Foundation; either version 2 of\n"
+ ">> \302\240+ * the License, or (at your option) any later version.\n"
+ ">> \302\240+ */\n"
+ ">> \302\240+\n"
+ ">> \302\240+#include <linux/component.h>\n"
+ ">> \302\240+#include <drm/drm_crtc_helper.h>\n"
+ ">> \302\240+#include <drm/drm_atomic_helper.h>\n"
+ ">> \302\240+#include <linux/io.h>\n"
+ ">> \302\240+#include <linux/of_irq.h>\n"
+ ">> \302\240+#include <linux/of_graph.h>\n"
+ ">> \302\240+\n"
+ ">> \302\240+#include \"de2_drv.h\"\n"
+ ">> \302\240+#include \"de2_crtc.h\"\n"
+ ">> \302\240+\n"
+ ">> \302\240+/* I/O map */\n"
+ ">> \302\240+\n"
+ ">> \302\240+#define TCON_GCTL_REG 0x00\n"
+ ">> \302\240+#define TCON_GCTL_TCON_ENABLE BIT(31)\n"
+ ">> \302\240+#define TCON_GINT0_REG 0x04\n"
+ ">> \302\240+#define TCON_GINT0_TCON1_Vb_Int_En BIT(30)\n"
+ ">> \302\240+#define TCON_GINT0_TCON1_Vb_Int_Flag BIT(14)\n"
+ ">> \302\240+#define TCON_GINT0_TCON1_Vb_Line_Int_Flag BIT(12)\n"
+ ">> \302\240+#define TCON0_CTL_REG 0x40\n"
+ ">> \302\240+#define TCON0_CTL_TCON_ENABLE BIT(31)\n"
+ ">> \302\240+#define TCON1_CTL_REG 0x90\n"
+ ">> \302\240+#define TCON1_CTL_TCON_ENABLE BIT(31)\n"
+ ">> \302\240+#define TCON1_CTL_INTERLACE_ENABLE BIT(20)\n"
+ ">> \302\240+#define TCON1_CTL_Start_Delay_SHIFT 4\n"
+ ">> \302\240+#define TCON1_CTL_Start_Delay_MASK GENMASK(8, 4)\n"
+ ">> \302\240+#define TCON1_BASIC0_REG 0x94 /* XI/YI */\n"
+ ">> \302\240+#define TCON1_BASIC1_REG 0x98 /* LS_XO/LS_YO */\n"
+ ">> \302\240+#define TCON1_BASIC2_REG 0x9c /* XO/YO */\n"
+ ">> \302\240+#define TCON1_BASIC3_REG 0xa0 /* HT/HBP */\n"
+ ">> \302\240+#define TCON1_BASIC4_REG 0xa4 /* VT/VBP */\n"
+ ">> \302\240+#define TCON1_BASIC5_REG 0xa8 /* HSPW/VSPW */\n"
+ ">> \302\240+#define TCON1_PS_SYNC_REG 0xb0\n"
+ ">> \302\240+#define TCON1_IO_POL_REG 0xf0\n"
+ ">> \302\240+#define TCON1_IO_POL_IO0_inv BIT(24)\n"
+ ">> \302\240+#define TCON1_IO_POL_IO1_inv BIT(25)\n"
+ ">> \302\240+#define TCON1_IO_POL_IO2_inv BIT(26)\n"
+ ">> \302\240+#define TCON1_IO_TRI_REG 0xf4\n"
+ ">> \302\240+#define TCON_CEU_CTL_REG 0x100\n"
+ ">> \302\240+#define TCON_CEU_CTL_ceu_en BIT(31)\n"
+ ">> \302\240+#define TCON1_FILL_CTL_REG 0x300\n"
+ ">> \302\240+#define TCON1_FILL_START0_REG 0x304\n"
+ ">> \302\240+#define TCON1_FILL_END0_REG 0x308\n"
+ ">> \302\240+#define TCON1_FILL_DATA0_REG 0x30c\n"
+ ">> \302\240+\n"
+ ">> \302\240+#define XY(x, y) (((x) << 16) | (y))\n"
+ ">> \302\240+\n"
+ ">> \302\240+#define andl_relaxed(addr, val) \\\n"
+ ">> \302\240+ writel_relaxed(readl_relaxed(addr) & val, addr)\n"
+ ">> \302\240+#define orl_relaxed(addr, val) \\\n"
+ ">> \302\240+ writel_relaxed(readl_relaxed(addr) | val, addr)\n"
+ ">> \302\240+\n"
+ ">> \302\240+/* vertical blank functions */\n"
+ ">> \302\240+\n"
+ ">> \302\240+static void de2_atomic_flush(struct drm_crtc *crtc,\n"
+ ">> \302\240+ struct drm_crtc_state *old_state)\n"
+ ">> \302\240+{\n"
+ ">> \302\240+ struct drm_pending_vblank_event *event = crtc->state->event;\n"
+ ">> \302\240+\n"
+ ">> \302\240+ if (event) {\n"
+ ">> \302\240+ crtc->state->event = NULL;\n"
+ ">> \302\240+ spin_lock_irq(&crtc->dev->event_lock);\n"
+ ">> \302\240+ if (drm_crtc_vblank_get(crtc) == 0)\n"
+ ">> \302\240+ drm_crtc_arm_vblank_event(crtc, event);\n"
+ ">> \302\240+ else\n"
+ ">> \302\240+ drm_crtc_send_vblank_event(crtc, event);\n"
+ ">> \302\240+ spin_unlock_irq(&crtc->dev->event_lock);\n"
+ ">> \302\240+ }\n"
+ ">> \302\240+}\n"
+ ">> \302\240+\n"
+ ">> \302\240+static irqreturn_t de2_lcd_irq(int irq, void *dev_id)\n"
+ ">> \302\240+{\n"
+ ">> \302\240+ struct lcd *lcd = (struct lcd *) dev_id;\n"
+ ">> \302\240+ u32 isr;\n"
+ ">> \302\240+\n"
+ ">> \302\240+ isr = readl_relaxed(lcd->mmio + TCON_GINT0_REG);\n"
+ ">> \302\240+\n"
+ ">> \302\240+ drm_crtc_handle_vblank(&lcd->crtc);\n"
+ ">> \302\240+\n"
+ ">> \302\240+ writel_relaxed(isr &\n"
+ ">> \302\240+ ~(TCON_GINT0_TCON1_Vb_Int_Flag |\n"
+ ">> \302\240+ TCON_GINT0_TCON1_Vb_Line_Int_Flag),\n"
+ ">> \302\240+ lcd->mmio + TCON_GINT0_REG);\n"
+ ">> \302\240+\n"
+ ">> \302\240+ return IRQ_HANDLED;\n"
+ ">> \302\240+}\n"
+ ">> \302\240+\n"
+ ">> \302\240+int de2_enable_vblank(struct drm_device *drm, unsigned int crtc_ix)\n"
+ ">> \302\240+{\n"
+ ">> \302\240+ struct priv *priv = drm_to_priv(drm);\n"
+ ">> \302\240+ struct lcd *lcd = priv->lcds[crtc_ix];\n"
+ ">> \302\240+\n"
+ ">> \302\240+ orl_relaxed(lcd->mmio + TCON_GINT0_REG, TCON_GINT0_TCON1_Vb_Int_En);\n"
+ ">> \302\240+\n"
+ ">> \302\240+ return 0;\n"
+ ">> \302\240+}\n"
+ ">> \302\240+\n"
+ ">> \302\240+void de2_disable_vblank(struct drm_device *drm, unsigned int crtc_ix)\n"
+ ">> \302\240+{\n"
+ ">> \302\240+ struct priv *priv = drm_to_priv(drm);\n"
+ ">> \302\240+ struct lcd *lcd = priv->lcds[crtc_ix];\n"
+ ">> \302\240+\n"
+ ">> \302\240+ andl_relaxed(lcd->mmio + TCON_GINT0_REG, ~TCON_GINT0_TCON1_Vb_Int_En);\n"
+ ">> \302\240+}\n"
+ ">> \302\240+\n"
+ ">> \302\240+void de2_vblank_reset(struct lcd *lcd)\n"
+ ">> \302\240+{\n"
+ ">> \302\240+ drm_crtc_vblank_reset(&lcd->crtc);\n"
+ ">> \302\240+}\n"
+ ">> \302\240+\n"
+ ">> \302\240+/* frame functions */\n"
+ ">> \302\240+static int de2_crtc_set_clock(struct lcd *lcd, int rate)\n"
+ ">> \302\240+{\n"
+ ">> \302\240+ struct clk *parent_clk;\n"
+ ">> \302\240+ u32 parent_rate;\n"
+ ">> \302\240+ int ret;\n"
+ ">> \302\240+\n"
+ ">> \302\240+ /* determine and set the best rate for the parent clock (pll-video) */\n"
+ ">> \302\240+ if ((270000 * 2) % rate == 0)\n"
+ ">> \302\240+ parent_rate = 270000000;\n"
+ ">> \302\240+ else if (297000 % rate == 0)\n"
+ ">> \302\240+ parent_rate = 297000000;\n"
+ ">> \302\240+ else\n"
+ ">> \302\240+ return -EINVAL; /* unsupported clock */\n"
+ ">> \302\240+\n"
+ ">> \302\240+ parent_clk = clk_get_parent(lcd->clk);\n"
+ ">> \302\240+\n"
+ ">> \302\240+ ret = clk_set_rate(parent_clk, parent_rate);\n"
+ ">> \302\240+ if (ret) {\n"
+ ">> \302\240+ dev_err(lcd->dev, \"set parent rate failed %d\\n\", ret);\n"
+ ">> \302\240+ return ret;\n"
+ ">> \302\240+ }\n"
+ ">> \302\240+ ret = clk_set_rate(lcd->clk, rate * 1000);\n"
+ ">> \302\240+ if (ret) {\n"
+ ">> \302\240+ dev_err(lcd->dev, \"set rate failed %d\\n\", ret);\n"
+ ">> \302\240+ return ret;\n"
+ ">> \302\240+ }\n"
+ ">> \302\240+\n"
+ ">> \302\240+ /* enable the clock */\n"
+ ">> \302\240+ reset_control_deassert(lcd->reset);\n"
+ ">> \302\240+ clk_prepare_enable(lcd->bus);\n"
+ ">> \302\240+ clk_prepare_enable(lcd->clk);\n"
+ ">> \302\240+\n"
+ ">> \302\240+ return ret;\n"
+ ">> \302\240+}\n"
+ ">> \302\240+\n"
+ ">> \302\240+static void de2_tcon_init(struct lcd *lcd)\n"
+ ">> \302\240+{\n"
+ ">> \302\240+ andl_relaxed(lcd->mmio + TCON0_CTL_REG, ~TCON0_CTL_TCON_ENABLE);\n"
+ ">> \302\240+ andl_relaxed(lcd->mmio + TCON1_CTL_REG, ~TCON1_CTL_TCON_ENABLE);\n"
+ ">> \302\240+ andl_relaxed(lcd->mmio + TCON_GCTL_REG, ~TCON_GCTL_TCON_ENABLE);\n"
+ ">> \302\240+\n"
+ ">> \302\240+ /* disable/ack interrupts */\n"
+ ">> \302\240+ writel_relaxed(0, lcd->mmio + TCON_GINT0_REG);\n"
+ ">> \302\240+}\n"
+ ">> \302\240+\n"
+ ">> \302\240+static void de2_tcon_enable(struct lcd *lcd)\n"
+ ">> \302\240+{\n"
+ ">> \302\240+ struct drm_crtc *crtc = &lcd->crtc;\n"
+ ">> \302\240+ const struct drm_display_mode *mode = &crtc->mode;\n"
+ ">> \302\240+ int interlace = mode->flags & DRM_MODE_FLAG_INTERLACE ? 2 : 1;\n"
+ ">> \302\240+ int start_delay;\n"
+ ">> \302\240+ u32 data;\n"
+ ">> \302\240+\n"
+ ">> \302\240+ orl_relaxed(lcd->mmio + TCON_GCTL_REG, TCON_GCTL_TCON_ENABLE);\n"
+ ">> \302\240+\n"
+ ">> \302\240+ data = XY(mode->hdisplay - 1, mode->vdisplay / interlace - 1);\n"
+ ">> \302\240+ writel_relaxed(data, lcd->mmio + TCON1_BASIC0_REG);\n"
+ ">> \302\240+ writel_relaxed(data, lcd->mmio + TCON1_BASIC1_REG);\n"
+ ">> \302\240+ writel_relaxed(data, lcd->mmio + TCON1_BASIC2_REG);\n"
+ ">> \302\240+ writel_relaxed(XY(mode->htotal - 1,\n"
+ ">> \302\240+ mode->htotal - mode->hsync_start - 1),\n"
+ ">> \302\240+ lcd->mmio + TCON1_BASIC3_REG);\n"
+ ">> \302\240+ writel_relaxed(XY(mode->vtotal * (3 - interlace),\n"
+ ">> \302\240+ mode->vtotal - mode->vsync_start - 1),\n"
+ ">> \302\240+ lcd->mmio + TCON1_BASIC4_REG);\n"
+ ">> \302\240+ writel_relaxed(XY(mode->hsync_end - mode->hsync_start - 1,\n"
+ ">> \302\240+ mode->vsync_end - mode->vsync_start - 1),\n"
+ ">> \302\240+ lcd->mmio + TCON1_BASIC5_REG);\n"
+ ">> \302\240+\n"
+ ">> \302\240+ data = TCON1_IO_POL_IO2_inv;\n"
+ ">> \302\240+ if (mode->flags & DRM_MODE_FLAG_PVSYNC)\n"
+ ">> \302\240+ data |= TCON1_IO_POL_IO0_inv;\n"
+ ">> \302\240+ if (mode->flags & DRM_MODE_FLAG_PHSYNC)\n"
+ ">> \302\240+ data |= TCON1_IO_POL_IO1_inv;\n"
+ ">> \302\240+ writel_relaxed(data, lcd->mmio + TCON1_IO_POL_REG);\n"
+ ">> \302\240+\n"
+ ">> \302\240+ andl_relaxed(lcd->mmio + TCON_CEU_CTL_REG, ~TCON_CEU_CTL_ceu_en);\n"
+ ">> \302\240+\n"
+ ">> \302\240+ if (interlace == 2)\n"
+ ">> \302\240+ orl_relaxed(lcd->mmio + TCON1_CTL_REG,\n"
+ ">> \302\240+ TCON1_CTL_INTERLACE_ENABLE);\n"
+ ">> \302\240+ else\n"
+ ">> \302\240+ andl_relaxed(lcd->mmio + TCON1_CTL_REG,\n"
+ ">> \302\240+ ~TCON1_CTL_INTERLACE_ENABLE);\n"
+ ">> \302\240+\n"
+ ">> \302\240+ writel_relaxed(0, lcd->mmio + TCON1_FILL_CTL_REG);\n"
+ ">> \302\240+ writel_relaxed(mode->vtotal + 1, lcd->mmio + TCON1_FILL_START0_REG);\n"
+ ">> \302\240+ writel_relaxed(mode->vtotal, lcd->mmio + TCON1_FILL_END0_REG);\n"
+ ">> \302\240+ writel_relaxed(0, lcd->mmio + TCON1_FILL_DATA0_REG);\n"
+ ">> \302\240+\n"
+ ">> \302\240+ start_delay = (mode->vtotal - mode->vdisplay) / interlace - 5;\n"
+ ">> \302\240+ if (start_delay > 31)\n"
+ ">> \302\240+ start_delay = 31;\n"
+ ">> \302\240+ data = readl_relaxed(lcd->mmio + TCON1_CTL_REG);\n"
+ ">> \302\240+ data &= ~TCON1_CTL_Start_Delay_MASK;\n"
+ ">> \302\240+ data |= start_delay << TCON1_CTL_Start_Delay_SHIFT;\n"
+ ">> \302\240+ writel_relaxed(data, lcd->mmio + TCON1_CTL_REG);\n"
+ ">> \302\240+\n"
+ ">> \302\240+ orl_relaxed(lcd->mmio + TCON1_CTL_REG, TCON1_CTL_TCON_ENABLE);\n"
+ ">> \302\240+}\n"
+ ">> \302\240+\n"
+ ">> \302\240+static void de2_tcon_disable(struct lcd *lcd)\n"
+ ">> \302\240+{\n"
+ ">> \302\240+ andl_relaxed(lcd->mmio + TCON1_CTL_REG, ~TCON1_CTL_TCON_ENABLE);\n"
+ ">> \302\240+ andl_relaxed(lcd->mmio + TCON_GCTL_REG, ~TCON_GCTL_TCON_ENABLE);\n"
+ ">> \302\240+}\n"
+ ">> \302\240+\n"
+ ">> \302\240+static void de2_crtc_enable(struct drm_crtc *crtc)\n"
+ ">> \302\240+{\n"
+ ">> \302\240+ struct lcd *lcd = crtc_to_lcd(crtc);\n"
+ ">> \302\240+ struct drm_display_mode *mode = &crtc->mode;\n"
+ ">> \302\240+\n"
+ ">> \302\240+ if (de2_crtc_set_clock(lcd, mode->clock) < 0)\n"
+ ">> \302\240+ return;\n"
+ ">> \302\240+ lcd->clk_enabled = true;\n"
+ ">> \302\240+\n"
+ ">> \302\240+ /* start the TCON and the DE */\n"
+ ">> \302\240+ de2_tcon_enable(lcd);\n"
+ ">> \302\240+ de2_de_enable(lcd);\n"
+ ">> \302\240+\n"
+ ">> \302\240+ /* turn on blanking interrupt */\n"
+ ">> \302\240+ drm_crtc_vblank_on(crtc);\n"
+ ">> \302\240+}\n"
+ ">> \302\240+\n"
+ ">> \302\240+static void de2_crtc_disable(struct drm_crtc *crtc,\n"
+ ">> \302\240+ struct drm_crtc_state *old_crtc_state)\n"
+ ">> \302\240+{\n"
+ ">> \302\240+ struct lcd *lcd = crtc_to_lcd(crtc);\n"
+ ">> \302\240+\n"
+ ">> \302\240+ if (!lcd->clk_enabled)\n"
+ ">> \302\240+ return; /* already disabled */\n"
+ ">> \302\240+ lcd->clk_enabled = false;\n"
+ ">> \302\240+\n"
+ ">> \302\240+ de2_de_disable(lcd);\n"
+ ">> \302\240+\n"
+ ">> \302\240+ drm_crtc_vblank_off(crtc);\n"
+ ">> \302\240+\n"
+ ">> \302\240+ de2_tcon_disable(lcd);\n"
+ ">> \302\240+\n"
+ ">> \302\240+ clk_disable_unprepare(lcd->clk);\n"
+ ">> \302\240+ clk_disable_unprepare(lcd->bus);\n"
+ ">> \302\240+ reset_control_assert(lcd->reset);\n"
+ ">> \302\240+}\n"
+ ">> \302\240+\n"
+ ">> \302\240+static const struct drm_crtc_funcs de2_crtc_funcs = {\n"
+ ">> \302\240+ .destroy = drm_crtc_cleanup,\n"
+ ">> \302\240+ .set_config = drm_atomic_helper_set_config,\n"
+ ">> \302\240+ .page_flip = drm_atomic_helper_page_flip,\n"
+ ">> \302\240+ .reset = drm_atomic_helper_crtc_reset,\n"
+ ">> \302\240+ .atomic_duplicate_state = drm_atomic_helper_crtc_duplicate_state,\n"
+ ">> \302\240+ .atomic_destroy_state = drm_atomic_helper_crtc_destroy_state,\n"
+ ">> \302\240+};\n"
+ ">> \302\240+\n"
+ ">> \302\240+static const struct drm_crtc_helper_funcs de2_crtc_helper_funcs = {\n"
+ ">> \302\240+ .atomic_flush = de2_atomic_flush,\n"
+ ">> \302\240+ .enable = de2_crtc_enable,\n"
+ ">> \302\240+ .atomic_disable = de2_crtc_disable,\n"
+ ">> \302\240+};\n"
+ ">> \302\240+\n"
+ ">> \302\240+/* device init */\n"
+ ">> \302\240+static int de2_lcd_bind(struct device *dev, struct device *master,\n"
+ ">> \302\240+ void *data)\n"
+ ">> \302\240+{\n"
+ ">> \302\240+ struct drm_device *drm = data;\n"
+ ">> \302\240+ struct priv *priv = drm_to_priv(drm);\n"
+ ">> \302\240+ struct lcd *lcd = dev_get_drvdata(dev);\n"
+ ">> \302\240+ struct drm_crtc *crtc = &lcd->crtc;\n"
+ ">> \302\240+ int ret, i, crtc_ix;\n"
+ ">> \302\240+\n"
+ ">> \302\240+ lcd->priv = priv;\n"
+ ">> \302\240+\n"
+ ">> \302\240+ /* set the CRTC reference */\n"
+ ">> \302\240+ crtc_ix = drm_crtc_index(crtc);\n"
+ ">> \302\240+ if (crtc_ix >= ARRAY_SIZE(priv->lcds)) {\n"
+ ">> \302\240+ dev_err(drm->dev, \"Bad crtc index\");\n"
+ ">> \302\240+ return -ENOENT;\n"
+ ">> \302\240+ }\n"
+ ">> \302\240+ priv->lcds[crtc_ix] = lcd;\n"
+ ">> \302\240+\n"
+ ">> \302\240+ /* and the mixer index (DT port index in the DE) */\n"
+ ">> \302\240+ for (i = 0; ; i++) {\n"
+ ">> \302\240+ struct device_node *port;\n"
+ ">> \302\240+\n"
+ ">> \302\240+ port = of_parse_phandle(drm->dev->of_node, \"ports\", i);\n"
+ ">> \302\240+ if (!port)\n"
+ ">> \302\240+ break;\n"
+ ">> \302\240+ if (port == lcd->crtc.port) {\n"
+ ">> \302\240+ lcd->mixer = i;\n"
+ ">> \302\240+ break;\n"
+ ">> \302\240+ }\n"
+ ">> \302\240+ }\n"
+ ">> \302\240+\n"
+ ">> \302\240+ ret = de2_plane_init(drm, lcd);\n"
+ ">> \302\240+ if (ret < 0)\n"
+ ">> \302\240+ return ret;\n"
+ ">> \302\240+\n"
+ ">> \302\240+ drm_crtc_helper_add(crtc, &de2_crtc_helper_funcs);\n"
+ ">> \302\240+\n"
+ ">> \302\240+ return drm_crtc_init_with_planes(drm, crtc,\n"
+ ">> \302\240+ &lcd->planes[DE2_PRIMARY_PLANE],\n"
+ ">> \302\240+ &lcd->planes[DE2_CURSOR_PLANE],\n"
+ ">> \302\240+ &de2_crtc_funcs, NULL);\n"
+ ">> \302\240+}\n"
+ ">> \302\240+\n"
+ ">> \302\240+static void de2_lcd_unbind(struct device *dev, struct device *master,\n"
+ ">> \302\240+ void *data)\n"
+ ">> \302\240+{\n"
+ ">> \302\240+ struct platform_device *pdev = to_platform_device(dev);\n"
+ ">> \302\240+ struct lcd *lcd = platform_get_drvdata(pdev);\n"
+ ">> \302\240+\n"
+ ">> \302\240+ if (lcd->priv)\n"
+ ">> \302\240+ lcd->priv->lcds[drm_crtc_index(&lcd->crtc)] = NULL;\n"
+ ">> \302\240+}\n"
+ ">> \302\240+\n"
+ ">> \302\240+static const struct component_ops de2_lcd_ops = {\n"
+ ">> \302\240+ .bind = de2_lcd_bind,\n"
+ ">> \302\240+ .unbind = de2_lcd_unbind,\n"
+ ">> \302\240+};\n"
+ ">> \302\240+\n"
+ ">> \302\240+static int de2_lcd_probe(struct platform_device *pdev)\n"
+ ">> \302\240+{\n"
+ ">> \302\240+ struct device *dev = &pdev->dev;\n"
+ ">> \302\240+ struct device_node *np = dev->of_node, *tmp, *parent, *port;\n"
+ ">> \302\240+ struct lcd *lcd;\n"
+ ">> \302\240+ struct resource *res;\n"
+ ">> \302\240+ int id, irq, ret;\n"
+ ">> \302\240+\n"
+ ">> \302\240+ lcd = devm_kzalloc(dev, sizeof(*lcd), GFP_KERNEL);\n"
+ ">> \302\240+ if (!lcd)\n"
+ ">> \302\240+ return -ENOMEM;\n"
+ ">> \302\240+\n"
+ ">> \302\240+ dev_set_drvdata(dev, lcd);\n"
+ ">> \302\240+ lcd->dev = dev;\n"
+ ">> \302\240+ lcd->mixer = id;\n"
+ ">> \302\240+\n"
+ ">> \302\240+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);\n"
+ ">> \302\240+ if (!res) {\n"
+ ">> \302\240+ dev_err(dev, \"failed to get memory resource\\n\");\n"
+ ">> \302\240+ return -EINVAL;\n"
+ ">> \302\240+ }\n"
+ ">> \302\240+\n"
+ ">> \302\240+ lcd->mmio = devm_ioremap_resource(dev, res);\n"
+ ">> \302\240+ if (IS_ERR(lcd->mmio)) {\n"
+ ">> \302\240+ dev_err(dev, \"failed to map registers\\n\");\n"
+ ">> \302\240+ return PTR_ERR(lcd->mmio);\n"
+ ">> \302\240+ }\n"
+ ">> \302\240+\n"
+ ">> \302\240+ /* possible CRTC */\n"
+ ">> \302\240+ parent = np;\n"
+ ">> \302\240+ tmp = of_get_child_by_name(np, \"ports\");\n"
+ ">> \302\240+ if (tmp)\n"
+ ">> \302\240+ parent = tmp;\n"
+ ">> \302\240+ port = of_get_child_by_name(parent, \"port\");\n"
+ ">> \302\240+ of_node_put(tmp);\n"
+ ">> \302\240+ if (!port) {\n"
+ ">> \302\240+ dev_err(dev, \"no port node\\n\");\n"
+ ">> \302\240+ return -ENXIO;\n"
+ ">> \302\240+ }\n"
+ ">> \302\240+ lcd->crtc.port = port;\n"
+ ">> \302\240+\n"
+ ">> \302\240+ lcd->bus = devm_clk_get(dev, \"bus\");\n"
+ ">> \302\240+ if (IS_ERR(lcd->bus)) {\n"
+ ">> \302\240+ dev_err(dev, \"get bus clock err %d\\n\", (int) PTR_ERR(lcd->bus));\n"
+ ">> \302\240+ ret = PTR_ERR(lcd->bus);\n"
+ ">> \302\240+ goto err;\n"
+ ">> \302\240+ }\n"
+ ">> \302\240+\n"
+ ">> \302\240+ lcd->clk = devm_clk_get(dev, \"clock\");\n"
+ ">> \302\240+ if (IS_ERR(lcd->clk)) {\n"
+ ">> \302\240+ ret = PTR_ERR(lcd->clk);\n"
+ ">> \302\240+ dev_err(dev, \"get video clock err %d\\n\", ret);\n"
+ ">> \302\240+ goto err;\n"
+ ">> \302\240+ }\n"
+ ">> \302\240+\n"
+ ">> \302\240+ lcd->reset = devm_reset_control_get(dev, NULL);\n"
+ ">> \302\240+ if (IS_ERR(lcd->reset)) {\n"
+ ">> \302\240+ ret = PTR_ERR(lcd->reset);\n"
+ ">> \302\240+ dev_err(dev, \"get reset err %d\\n\", ret);\n"
+ ">> \302\240+ goto err;\n"
+ ">> \302\240+ }\n"
+ ">> \302\240+\n"
+ ">> \302\240+ irq = platform_get_irq(pdev, 0);\n"
+ ">> \302\240+ if (irq <= 0) {\n"
+ ">> \302\240+ dev_err(dev, \"unable to get irq\\n\");\n"
+ ">> \302\240+ ret = -EINVAL;\n"
+ ">> \302\240+ goto err;\n"
+ ">> \302\240+ }\n"
+ ">> \302\240+\n"
+ ">> \302\240+ de2_tcon_init(lcd); /* stop TCON and avoid interrupts */\n"
+ ">> \302\240+\n"
+ ">> \302\240+ ret = devm_request_irq(dev, irq, de2_lcd_irq, 0,\n"
+ ">> \302\240+ dev_name(dev), lcd);\n"
+ ">> \302\240+ if (ret < 0) {\n"
+ ">> \302\240+ dev_err(dev, \"unable to request irq %d\\n\", irq);\n"
+ ">> \302\240+ goto err;\n"
+ ">> \302\240+ }\n"
+ ">> \302\240+\n"
+ ">> \302\240+ return component_add(dev, &de2_lcd_ops);\n"
+ ">> \302\240+\n"
+ ">> \302\240+err:\n"
+ ">> \302\240+ of_node_put(lcd->crtc.port);\n"
+ ">> \302\240+ return ret;\n"
+ ">> \302\240+}\n"
+ ">> \302\240+\n"
+ ">> \302\240+static int de2_lcd_remove(struct platform_device *pdev)\n"
+ ">> \302\240+{\n"
+ ">> \302\240+ struct lcd *lcd = platform_get_drvdata(pdev);\n"
+ ">> \302\240+\n"
+ ">> \302\240+ component_del(&pdev->dev, &de2_lcd_ops);\n"
+ ">> \302\240+\n"
+ ">> \302\240+ of_node_put(lcd->crtc.port);\n"
+ ">> \302\240+\n"
+ ">> \302\240+ return 0;\n"
+ ">> \302\240+}\n"
+ ">> \302\240+\n"
+ ">> \302\240+static const struct of_device_id de2_lcd_ids[] = {\n"
+ ">> \302\240+ { .compatible = \"allwinner,sun8i-a83t-tcon\", },\n"
+ ">> \302\240+ { }\n"
+ ">> \302\240+};\n"
+ ">> \302\240+\n"
+ ">> \302\240+struct platform_driver de2_lcd_platform_driver = {\n"
+ ">> \302\240+ .probe = de2_lcd_probe,\n"
+ ">> \302\240+ .remove = de2_lcd_remove,\n"
+ ">> \302\240+ .driver = {\n"
+ ">> \302\240+ .name = \"sun8i-de2-tcon\",\n"
+ ">> \302\240+ .of_match_table = of_match_ptr(de2_lcd_ids),\n"
+ ">> \302\240+ },\n"
+ ">> \302\240+};\n"
+ ">> \302\240diff --git a/drivers/gpu/drm/sun8i/de2_crtc.h b/drivers/gpu/drm/sun8i/de2_crtc.h\n"
+ ">> \302\240new file mode 100644\n"
+ ">> \302\240index 0000000..c0d34a7\n"
+ ">> \302\240--- /dev/null\n"
+ ">> \302\240+++ b/drivers/gpu/drm/sun8i/de2_crtc.h\n"
+ ">> \302\240@@ -0,0 +1,50 @@\n"
+ ">> \302\240+#ifndef __DE2_CRTC_H__\n"
+ ">> \302\240+#define __DE2_CRTC_H__\n"
+ ">> \302\240+/*\n"
+ ">> \302\240+ * Copyright (C) 2016 Jean-Fran??ois Moine\n"
+ ">> \302\240+ *\n"
+ ">> \302\240+ * This program is free software; you can redistribute it and/or\n"
+ ">> \302\240+ * modify it under the terms of the GNU General Public License as\n"
+ ">> \302\240+ * published by the Free Software Foundation; either version 2 of\n"
+ ">> \302\240+ * the License, or (at your option) any later version.\n"
+ ">> \302\240+ */\n"
+ ">> \302\240+\n"
+ ">> \302\240+#include <drm/drm_plane_helper.h>\n"
+ ">> \302\240+\n"
+ ">> \302\240+struct clk;\n"
+ ">> \302\240+struct reset_control;\n"
+ ">> \302\240+struct priv;\n"
+ ">> \302\240+\n"
+ ">> \302\240+/* planes */\n"
+ ">> \302\240+#define DE2_PRIMARY_PLANE 0\n"
+ ">> \302\240+#define DE2_CURSOR_PLANE 1\n"
+ ">> \302\240+#define DE2_N_PLANES 5 /* number of planes - see plane_tb[] in de2_plane.c */\n"
+ ">> \302\240+\n"
+ ">> \302\240+struct lcd {\n"
+ ">> \302\240+ void __iomem *mmio;\n"
+ ">> \302\240+\n"
+ ">> \302\240+ struct device *dev;\n"
+ ">> \302\240+ struct drm_crtc crtc;\n"
+ ">> \302\240+\n"
+ ">> \302\240+ struct priv *priv; /* DRM/DE private data */\n"
+ ">> \302\240+\n"
+ ">> \302\240+ u8 mixer; /* LCD (mixer) number */\n"
+ ">> \302\240+ u8 delayed; /* bitmap of planes with delayed update */\n"
+ ">> \302\240+\n"
+ ">> \302\240+ u8 clk_enabled; /* used for error in crtc_enable */\n"
+ ">> \302\240+\n"
+ ">> \302\240+ struct clk *clk;\n"
+ ">> \302\240+ struct clk *bus;\n"
+ ">> \302\240+ struct reset_control *reset;\n"
+ ">> \302\240+\n"
+ ">> \302\240+ struct drm_plane planes[DE2_N_PLANES];\n"
+ ">> \302\240+};\n"
+ ">> \302\240+\n"
+ ">> \302\240+#define crtc_to_lcd(x) container_of(x, struct lcd, crtc)\n"
+ ">> \302\240+\n"
+ ">> \302\240+/* in de2_plane.c */\n"
+ ">> \302\240+void de2_de_enable(struct lcd *lcd);\n"
+ ">> \302\240+void de2_de_disable(struct lcd *lcd);\n"
+ ">> \302\240+int de2_plane_init(struct drm_device *drm, struct lcd *lcd);\n"
+ ">> \302\240+\n"
+ ">> \302\240+#endif /* __DE2_CRTC_H__ */\n"
+ ">> \302\240diff --git a/drivers/gpu/drm/sun8i/de2_drv.c b/drivers/gpu/drm/sun8i/de2_drv.c\n"
+ ">> \302\240new file mode 100644\n"
+ ">> \302\240index 0000000..f96babe\n"
+ ">> \302\240--- /dev/null\n"
+ ">> \302\240+++ b/drivers/gpu/drm/sun8i/de2_drv.c\n"
+ ">> \302\240@@ -0,0 +1,317 @@\n"
+ ">> \302\240+/*\n"
+ ">> \302\240+ * Allwinner DRM driver - DE2 DRM driver\n"
+ ">> \302\240+ *\n"
+ ">> \302\240+ * Copyright (C) 2016 Jean-Francois Moine <moinejf-GANU6spQydw@public.gmane.org>\n"
+ ">> \302\240+ *\n"
+ ">> \302\240+ * This program is free software; you can redistribute it and/or\n"
+ ">> \302\240+ * modify it under the terms of the GNU General Public License as\n"
+ ">> \302\240+ * published by the Free Software Foundation; either version 2 of\n"
+ ">> \302\240+ * the License, or (at your option) any later version.\n"
+ ">> \302\240+ */\n"
+ ">> \302\240+\n"
+ ">> \302\240+#include <linux/module.h>\n"
+ ">> \302\240+#include <linux/of_device.h>\n"
+ ">> \302\240+#include <drm/drm_of.h>\n"
+ ">> \302\240+#include <linux/component.h>\n"
+ ">> \302\240+#include <drm/drm_atomic_helper.h>\n"
+ ">> \302\240+#include <drm/drm_crtc_helper.h>\n"
+ ">> \302\240+#include <drm/drm_fb_cma_helper.h>\n"
+ ">> \302\240+#include <drm/drm_gem_cma_helper.h>\n"
+ ">> \302\240+\n"
+ ">> \302\240+#include \"de2_drv.h\"\n"
+ ">> \302\240+\n"
+ ">> \302\240+#define DRIVER_NAME \"sun8i-de2\"\n"
+ ">> \302\240+#define DRIVER_DESC \"Allwinner DRM DE2\"\n"
+ ">> \302\240+#define DRIVER_DATE \"20161101\"\n"
+ ">> \302\240+#define DRIVER_MAJOR 1\n"
+ ">> \302\240+#define DRIVER_MINOR 0\n"
+ ">> \302\240+\n"
+ ">> \302\240+static const struct of_device_id de2_drm_of_match[] = {\n"
+ ">> \302\240+ { .compatible = \"allwinner,sun8i-a83t-display-engine\",\n"
+ ">> \302\240+ .data = (void *) SOC_A83T },\n"
+ ">> \302\240+ { .compatible = \"allwinner,sun8i-h3-display-engine\",\n"
+ ">> \302\240+ .data = (void *) SOC_H3 },\n"
+ ">> \302\240+ { },\n"
+ ">> \302\240+};\n"
+ ">> \302\240+MODULE_DEVICE_TABLE(of, de2_drm_of_match);\n"
+ ">> \302\240+\n"
+ ">> \302\240+static void de2_fb_output_poll_changed(struct drm_device *drm)\n"
+ ">> \302\240+{\n"
+ ">> \302\240+ struct priv *priv = drm_to_priv(drm);\n"
+ ">> \302\240+\n"
+ ">> \302\240+ if (priv->fbdev)\n"
+ ">> \302\240+ drm_fbdev_cma_hotplug_event(priv->fbdev);\n"
+ ">> \302\240+}\n"
+ ">> \302\240+\n"
+ ">> \302\240+static const struct drm_mode_config_funcs de2_mode_config_funcs = {\n"
+ ">> \302\240+ .fb_create = drm_fb_cma_create,\n"
+ ">> \302\240+ .output_poll_changed = de2_fb_output_poll_changed,\n"
+ ">> \302\240+ .atomic_check = drm_atomic_helper_check,\n"
+ ">> \302\240+ .atomic_commit = drm_atomic_helper_commit,\n"
+ ">> \302\240+};\n"
+ ">> \302\240+\n"
+ ">> \302\240+/* -- DRM operations -- */\n"
+ ">> \302\240+\n"
+ ">> \302\240+static void de2_lastclose(struct drm_device *drm)\n"
+ ">> \302\240+{\n"
+ ">> \302\240+ struct priv *priv = drm_to_priv(drm);\n"
+ ">> \302\240+\n"
+ ">> \302\240+ if (priv->fbdev)\n"
+ ">> \302\240+ drm_fbdev_cma_restore_mode(priv->fbdev);\n"
+ ">> \302\240+}\n"
+ ">> \302\240+\n"
+ ">> \302\240+static const struct file_operations de2_fops = {\n"
+ ">> \302\240+ .owner = THIS_MODULE,\n"
+ ">> \302\240+ .open = drm_open,\n"
+ ">> \302\240+ .release = drm_release,\n"
+ ">> \302\240+ .unlocked_ioctl = drm_ioctl,\n"
+ ">> \302\240+ .poll = drm_poll,\n"
+ ">> \302\240+ .read = drm_read,\n"
+ ">> \302\240+ .llseek = no_llseek,\n"
+ ">> \302\240+ .mmap = drm_gem_cma_mmap,\n"
+ ">> \302\240+};\n"
+ ">> \302\240+\n"
+ ">> \302\240+static struct drm_driver de2_drm_driver = {\n"
+ ">> \302\240+ .driver_features = DRIVER_GEM | DRIVER_MODESET | DRIVER_PRIME |\n"
+ ">> \302\240+ DRIVER_ATOMIC,\n"
+ ">> \302\240+ .lastclose = de2_lastclose,\n"
+ ">> \302\240+ .get_vblank_counter = drm_vblank_no_hw_counter,\n"
+ ">> \302\240+ .enable_vblank = de2_enable_vblank,\n"
+ ">> \302\240+ .disable_vblank = de2_disable_vblank,\n"
+ ">> \302\240+ .gem_free_object = drm_gem_cma_free_object,\n"
+ ">> \302\240+ .gem_vm_ops = &drm_gem_cma_vm_ops,\n"
+ ">> \302\240+ .prime_handle_to_fd = drm_gem_prime_handle_to_fd,\n"
+ ">> \302\240+ .prime_fd_to_handle = drm_gem_prime_fd_to_handle,\n"
+ ">> \302\240+ .gem_prime_import = drm_gem_prime_import,\n"
+ ">> \302\240+ .gem_prime_export = drm_gem_prime_export,\n"
+ ">> \302\240+ .gem_prime_get_sg_table = drm_gem_cma_prime_get_sg_table,\n"
+ ">> \302\240+ .gem_prime_import_sg_table = drm_gem_cma_prime_import_sg_table,\n"
+ ">> \302\240+ .gem_prime_vmap = drm_gem_cma_prime_vmap,\n"
+ ">> \302\240+ .gem_prime_vunmap = drm_gem_cma_prime_vunmap,\n"
+ ">> \302\240+ .gem_prime_mmap = drm_gem_cma_prime_mmap,\n"
+ ">> \302\240+ .dumb_create = drm_gem_cma_dumb_create,\n"
+ ">> \302\240+ .dumb_map_offset = drm_gem_cma_dumb_map_offset,\n"
+ ">> \302\240+ .dumb_destroy = drm_gem_dumb_destroy,\n"
+ ">> \302\240+ .fops = &de2_fops,\n"
+ ">> \302\240+ .name = DRIVER_NAME,\n"
+ ">> \302\240+ .desc = DRIVER_DESC,\n"
+ ">> \302\240+ .date = DRIVER_DATE,\n"
+ ">> \302\240+ .major = DRIVER_MAJOR,\n"
+ ">> \302\240+ .minor = DRIVER_MINOR,\n"
+ ">> \302\240+};\n"
+ ">> \302\240+\n"
+ ">> \302\240+/*\n"
+ ">> \302\240+ * Platform driver\n"
+ ">> \302\240+ */\n"
+ ">> \302\240+\n"
+ ">> \302\240+static int de2_drm_bind(struct device *dev)\n"
+ ">> \302\240+{\n"
+ ">> \302\240+ struct drm_device *drm;\n"
+ ">> \302\240+ struct priv *priv;\n"
+ ">> \302\240+ struct resource *res;\n"
+ ">> \302\240+ struct lcd *lcd;\n"
+ ">> \302\240+ int i, ret;\n"
+ ">> \302\240+\n"
+ ">> \302\240+ priv = kzalloc(sizeof(*priv), GFP_KERNEL);\n"
+ ">> \302\240+ if (!priv)\n"
+ ">> \302\240+ return -ENOMEM;\n"
+ ">> \302\240+\n"
+ ">> \302\240+ drm = &priv->drm;\n"
+ ">> \302\240+ dev_set_drvdata(dev, drm);\n"
+ ">> \302\240+\n"
+ ">> \302\240+ /* get the resources */\n"
+ ">> \302\240+ priv->soc_type = (int) of_match_device(de2_drm_of_match, dev)->data;\n"
+ ">> \302\240+\n"
+ ">> \302\240+ res = platform_get_resource(to_platform_device(dev),\n"
+ ">> \302\240+ IORESOURCE_MEM, 0);\n"
+ ">> \302\240+ if (!res) {\n"
+ ">> \302\240+ dev_err(dev, \"failed to get memory resource\\n\");\n"
+ ">> \302\240+ ret = -EINVAL;\n"
+ ">> \302\240+ goto out1;\n"
+ ">> \302\240+ }\n"
+ ">> \302\240+\n"
+ ">> \302\240+ priv->mmio = devm_ioremap_resource(dev, res);\n"
+ ">> \302\240+ if (IS_ERR(priv->mmio)) {\n"
+ ">> \302\240+ ret = PTR_ERR(priv->mmio);\n"
+ ">> \302\240+ dev_err(dev, \"failed to map registers %d\\n\", ret);\n"
+ ">> \302\240+ goto out1;\n"
+ ">> \302\240+ }\n"
+ ">> \302\240+\n"
+ ">> \302\240+ priv->gate = devm_clk_get(dev, \"bus\");\n"
+ ">> \302\240+ if (IS_ERR(priv->gate)) {\n"
+ ">> \302\240+ ret = PTR_ERR(priv->gate);\n"
+ ">> \302\240+ dev_err(dev, \"bus gate err %d\\n\", ret);\n"
+ ">> \302\240+ goto out1;\n"
+ ">> \302\240+ }\n"
+ ">> \302\240+\n"
+ ">> \302\240+ priv->clk = devm_clk_get(dev, \"clock\");\n"
+ ">> \302\240+ if (IS_ERR(priv->clk)) {\n"
+ ">> \302\240+ ret = PTR_ERR(priv->clk);\n"
+ ">> \302\240+ dev_err(dev, \"clock err %d\\n\", ret);\n"
+ ">> \302\240+ goto out1;\n"
+ ">> \302\240+ }\n"
+ ">> \302\240+\n"
+ ">> \302\240+ priv->reset = devm_reset_control_get(dev, NULL);\n"
+ ">> \302\240+ if (IS_ERR(priv->reset)) {\n"
+ ">> \302\240+ ret = PTR_ERR(priv->reset);\n"
+ ">> \302\240+ dev_err(dev, \"reset err %d\\n\", ret);\n"
+ ">> \302\240+ goto out1;\n"
+ ">> \302\240+ }\n"
+ ">> \302\240+\n"
+ ">> \302\240+ mutex_init(&priv->mutex); /* protect DE I/O accesses */\n"
+ ">> \302\240+\n"
+ ">> \302\240+ ret = drm_dev_init(drm, &de2_drm_driver, dev);\n"
+ ">> \302\240+ if (ret != 0) {\n"
+ ">> \302\240+ dev_err(dev, \"dev_init failed %d\\n\", ret);\n"
+ ">> \302\240+ goto out1;\n"
+ ">> \302\240+ }\n"
+ ">> \302\240+\n"
+ ">> \302\240+ drm_mode_config_init(drm);\n"
+ ">> \302\240+ drm->mode_config.min_width = 32; /* needed for cursor */\n"
+ ">> \302\240+ drm->mode_config.min_height = 32;\n"
+ ">> \302\240+ drm->mode_config.max_width = 1920;\n"
+ ">> \302\240+ drm->mode_config.max_height = 1080;\n"
+ ">> \302\240+ drm->mode_config.funcs = &de2_mode_config_funcs;\n"
+ ">> \302\240+\n"
+ ">> \302\240+ drm->irq_enabled = true;\n"
+ ">> \302\240+\n"
+ ">> \302\240+ /* start the subdevices */\n"
+ ">> \302\240+ ret = component_bind_all(dev, drm);\n"
+ ">> \302\240+ if (ret < 0)\n"
+ ">> \302\240+ goto out2;\n"
+ ">> \302\240+\n"
+ ">> \302\240+ /* initialize and disable vertical blanking on all CRTCs */\n"
+ ">> \302\240+ ret = drm_vblank_init(drm, drm->mode_config.num_crtc);\n"
+ ">> \302\240+ if (ret < 0)\n"
+ ">> \302\240+ dev_warn(dev, \"vblank_init failed %d\\n\", ret);\n"
+ ">> \302\240+\n"
+ ">> \302\240+ for (i = 0; i < ARRAY_SIZE(priv->lcds); i++) {\n"
+ ">> \302\240+ lcd = priv->lcds[i];\n"
+ ">> \302\240+ if (lcd)\n"
+ ">> \302\240+ de2_vblank_reset(lcd);\n"
+ ">> \302\240+ }\n"
+ ">> \302\240+\n"
+ ">> \302\240+ drm_mode_config_reset(drm);\n"
+ ">> \302\240+\n"
+ ">> \302\240+ priv->fbdev = drm_fbdev_cma_init(drm,\n"
+ ">> \302\240+ 32, /* bpp */\n"
+ ">> \302\240+ drm->mode_config.num_crtc,\n"
+ ">> \302\240+ drm->mode_config.num_connector);\n"
+ ">> \302\240+ if (IS_ERR(priv->fbdev)) {\n"
+ ">> \302\240+ ret = PTR_ERR(priv->fbdev);\n"
+ ">> \302\240+ priv->fbdev = NULL;\n"
+ ">> \302\240+ goto out3;\n"
+ ">> \302\240+ }\n"
+ ">> \302\240+\n"
+ ">> \302\240+ drm_kms_helper_poll_init(drm);\n"
+ ">> \302\240+\n"
+ ">> \302\240+ ret = drm_dev_register(drm, 0);\n"
+ ">> \302\240+ if (ret < 0)\n"
+ ">> \302\240+ goto out4;\n"
+ ">> \302\240+\n"
+ ">> \302\240+ return 0;\n"
+ ">> \302\240+\n"
+ ">> \302\240+out4:\n"
+ ">> \302\240+ drm_fbdev_cma_fini(priv->fbdev);\n"
+ ">> \302\240+out3:\n"
+ ">> \302\240+ component_unbind_all(dev, drm);\n"
+ ">> \302\240+out2:\n"
+ ">> \302\240+ drm_dev_unref(drm);\n"
+ ">> \302\240+out1:\n"
+ ">> \302\240+ kfree(priv);\n"
+ ">> \302\240+ return ret;\n"
+ ">> \302\240+}\n"
+ ">> \302\240+\n"
+ ">> \302\240+static void de2_drm_unbind(struct device *dev)\n"
+ ">> \302\240+{\n"
+ ">> \302\240+ struct drm_device *drm = dev_get_drvdata(dev);\n"
+ ">> \302\240+ struct priv *priv = drm_to_priv(drm);\n"
+ ">> \302\240+\n"
+ ">> \302\240+ drm_dev_unregister(drm);\n"
+ ">> \302\240+\n"
+ ">> \302\240+ drm_fbdev_cma_fini(priv->fbdev);\n"
+ ">> \302\240+ drm_kms_helper_poll_fini(drm);\n"
+ ">> \302\240+ drm_vblank_cleanup(drm);\n"
+ ">> \302\240+ drm_mode_config_cleanup(drm);\n"
+ ">> \302\240+\n"
+ ">> \302\240+ component_unbind_all(dev, drm);\n"
+ ">> \302\240+\n"
+ ">> \302\240+ kfree(priv);\n"
+ ">> \302\240+}\n"
+ ">> \302\240+\n"
+ ">> \302\240+static const struct component_master_ops de2_drm_comp_ops = {\n"
+ ">> \302\240+ .bind = de2_drm_bind,\n"
+ ">> \302\240+ .unbind = de2_drm_unbind,\n"
+ ">> \302\240+};\n"
+ ">> \302\240+\n"
+ ">> \302\240+/*\n"
+ ">> \302\240+ * drm_of_component_probe() does:\n"
+ ">> \302\240+ * - bind of the ports (lcd-controller.port)\n"
+ ">> \302\240+ * - bind of the remote nodes (hdmi, tve..)\n"
+ ">> \302\240+ */\n"
+ ">> \302\240+static int compare_of(struct device *dev, void *data)\n"
+ ">> \302\240+{\n"
+ ">> \302\240+ struct device_node *np = data;\n"
+ ">> \302\240+\n"
+ ">> \302\240+ if (of_node_cmp(np->name, \"port\") == 0) {\n"
+ ">> \302\240+ np = of_get_parent(np);\n"
+ ">> \302\240+ of_node_put(np);\n"
+ ">> \302\240+ }\n"
+ ">> \302\240+ return dev->of_node == np;\n"
+ ">> \302\240+}\n"
+ ">> \302\240+\n"
+ ">> \302\240+static int de2_drm_probe(struct platform_device *pdev)\n"
+ ">> \302\240+{\n"
+ ">> \302\240+ int ret;\n"
+ ">> \302\240+\n"
+ ">> \302\240+ ret = drm_of_component_probe(&pdev->dev,\n"
+ ">> \302\240+ compare_of,\n"
+ ">> \302\240+ &de2_drm_comp_ops);\n"
+ ">> \302\240+ if (ret == -EINVAL)\n"
+ ">> \302\240+ ret = -ENXIO;\n"
+ ">> \302\240+ return ret;\n"
+ ">> \302\240+}\n"
+ ">> \302\240+\n"
+ ">> \302\240+static int de2_drm_remove(struct platform_device *pdev)\n"
+ ">> \302\240+{\n"
+ ">> \302\240+ component_master_del(&pdev->dev, &de2_drm_comp_ops);\n"
+ ">> \302\240+\n"
+ ">> \302\240+ return 0;\n"
+ ">> \302\240+}\n"
+ ">> \302\240+\n"
+ ">> \302\240+static struct platform_driver de2_drm_platform_driver = {\n"
+ ">> \302\240+ .probe = de2_drm_probe,\n"
+ ">> \302\240+ .remove = de2_drm_remove,\n"
+ ">> \302\240+ .driver = {\n"
+ ">> \302\240+ .name = DRIVER_NAME,\n"
+ ">> \302\240+ .of_match_table = de2_drm_of_match,\n"
+ ">> \302\240+ },\n"
+ ">> \302\240+};\n"
+ ">> \302\240+\n"
+ ">> \302\240+static int __init de2_drm_init(void)\n"
+ ">> \302\240+{\n"
+ ">> \302\240+ int ret;\n"
+ ">> \302\240+\n"
+ ">> \302\240+ ret = platform_driver_register(&de2_lcd_platform_driver);\n"
+ ">> \302\240+ if (ret < 0)\n"
+ ">> \302\240+ return ret;\n"
+ ">> \302\240+\n"
+ ">> \302\240+ ret = platform_driver_register(&de2_drm_platform_driver);\n"
+ ">> \302\240+ if (ret < 0)\n"
+ ">> \302\240+ platform_driver_unregister(&de2_lcd_platform_driver);\n"
+ ">> \302\240+\n"
+ ">> \302\240+ return ret;\n"
+ ">> \302\240+}\n"
+ ">> \302\240+\n"
+ ">> \302\240+static void __exit de2_drm_fini(void)\n"
+ ">> \302\240+{\n"
+ ">> \302\240+ platform_driver_unregister(&de2_lcd_platform_driver);\n"
+ ">> \302\240+ platform_driver_unregister(&de2_drm_platform_driver);\n"
+ ">> \302\240+}\n"
+ ">> \302\240+\n"
+ ">> \302\240+module_init(de2_drm_init);\n"
+ ">> \302\240+module_exit(de2_drm_fini);\n"
+ ">> \302\240+\n"
+ ">> \302\240+MODULE_AUTHOR(\"Jean-Francois Moine <moinejf-GANU6spQydw@public.gmane.org>\");\n"
+ ">> \302\240+MODULE_DESCRIPTION(\"Allwinner DE2 DRM Driver\");\n"
+ ">> \302\240+MODULE_LICENSE(\"GPL v2\");\n"
+ ">> \302\240diff --git a/drivers/gpu/drm/sun8i/de2_drv.h b/drivers/gpu/drm/sun8i/de2_drv.h\n"
+ ">> \302\240new file mode 100644\n"
+ ">> \302\240index 0000000..c42c30a\n"
+ ">> \302\240--- /dev/null\n"
+ ">> \302\240+++ b/drivers/gpu/drm/sun8i/de2_drv.h\n"
+ ">> \302\240@@ -0,0 +1,48 @@\n"
+ ">> \302\240+#ifndef __DE2_DRM_H__\n"
+ ">> \302\240+#define __DE2_DRM_H__\n"
+ ">> \302\240+/*\n"
+ ">> \302\240+ * Copyright (C) 2016 Jean-Fran??ois Moine\n"
+ ">> \302\240+ *\n"
+ ">> \302\240+ * This program is free software; you can redistribute it and/or\n"
+ ">> \302\240+ * modify it under the terms of the GNU General Public License as\n"
+ ">> \302\240+ * published by the Free Software Foundation; either version 2 of\n"
+ ">> \302\240+ * the License, or (at your option) any later version.\n"
+ ">> \302\240+ */\n"
+ ">> \302\240+\n"
+ ">> \302\240+#include <drm/drmP.h>\n"
+ ">> \302\240+#include <linux/clk.h>\n"
+ ">> \302\240+#include <linux/reset.h>\n"
+ ">> \302\240+\n"
+ ">> \302\240+struct drm_fbdev_cma;\n"
+ ">> \302\240+struct lcd;\n"
+ ">> \302\240+\n"
+ ">> \302\240+#define N_LCDS 2\n"
+ ">> \302\240+\n"
+ ">> \302\240+struct priv {\n"
+ ">> \302\240+ struct drm_device drm;\n"
+ ">> \302\240+ void __iomem *mmio;\n"
+ ">> \302\240+ struct clk *clk;\n"
+ ">> \302\240+ struct clk *gate;\n"
+ ">> \302\240+ struct reset_control *reset;\n"
+ ">> \302\240+\n"
+ ">> \302\240+ struct mutex mutex; /* protect DE I/O access */\n"
+ ">> \302\240+ u8 soc_type;\n"
+ ">> \302\240+#define SOC_A83T 0\n"
+ ">> \302\240+#define SOC_H3 1\n"
+ ">> \302\240+ u8 started; /* bitmap of started mixers */\n"
+ ">> \302\240+ u8 clean; /* bitmap of clean mixers */\n"
+ ">> \302\240+\n"
+ ">> \302\240+ struct drm_fbdev_cma *fbdev;\n"
+ ">> \302\240+\n"
+ ">> \302\240+ struct lcd *lcds[N_LCDS]; /* CRTCs */\n"
+ ">> \302\240+};\n"
+ ">> \302\240+\n"
+ ">> \302\240+#define drm_to_priv(x) container_of(x, struct priv, drm)\n"
+ ">> \302\240+\n"
+ ">> \302\240+/* in de2_crtc.c */\n"
+ ">> \302\240+int de2_enable_vblank(struct drm_device *drm, unsigned int crtc);\n"
+ ">> \302\240+void de2_disable_vblank(struct drm_device *drm, unsigned int crtc);\n"
+ ">> \302\240+void de2_vblank_reset(struct lcd *lcd);\n"
+ ">> \302\240+extern struct platform_driver de2_lcd_platform_driver;\n"
+ ">> \302\240+\n"
+ ">> \302\240+#endif /* __DE2_DRM_H__ */\n"
+ ">> \302\240diff --git a/drivers/gpu/drm/sun8i/de2_plane.c b/drivers/gpu/drm/sun8i/de2_plane.c\n"
+ ">> \302\240new file mode 100644\n"
+ ">> \302\240index 0000000..2fd72dc\n"
+ ">> \302\240--- /dev/null\n"
+ ">> \302\240+++ b/drivers/gpu/drm/sun8i/de2_plane.c\n"
+ ">> \302\240@@ -0,0 +1,734 @@\n"
+ ">> \302\240+/*\n"
+ ">> \302\240+ * Allwinner DRM driver - Display Engine 2\n"
+ ">> \302\240+ *\n"
+ ">> \302\240+ * Copyright (C) 2016 Jean-Francois Moine <moinejf-GANU6spQydw@public.gmane.org>\n"
+ ">> \302\240+ * Adapted from the sun8iw6 and sun8iw7 disp2 drivers\n"
+ ">> \302\240+ * Copyright (c) 2016 Allwinnertech Co., Ltd.\n"
+ ">> \302\240+ *\n"
+ ">> \302\240+ * This program is free software; you can redistribute it and/or\n"
+ ">> \302\240+ * modify it under the terms of the GNU General Public License as\n"
+ ">> \302\240+ * published by the Free Software Foundation; either version 2 of\n"
+ ">> \302\240+ * the License, or (at your option) any later version.\n"
+ ">> \302\240+ */\n"
+ ">> \302\240+\n"
+ ">> \302\240+#include <linux/io.h>\n"
+ ">> \302\240+#include <drm/drm_atomic_helper.h>\n"
+ ">> \302\240+#include <drm/drm_crtc_helper.h>\n"
+ ">> \302\240+#include <drm/drm_fb_cma_helper.h>\n"
+ ">> \302\240+#include <drm/drm_gem_cma_helper.h>\n"
+ ">> \302\240+#include <drm/drm_plane_helper.h>\n"
+ ">> \302\240+\n"
+ ">> \302\240+#include \"de2_drv.h\"\n"
+ ">> \302\240+#include \"de2_crtc.h\"\n"
+ ">> \302\240+\n"
+ ">> \302\240+/* DE2 I/O map */\n"
+ ">> \302\240+\n"
+ ">> \302\240+#define DE2_MOD_REG 0x0000 /* 1 bit per LCD */\n"
+ ">> \302\240+#define DE2_GATE_REG 0x0004\n"
+ ">> \302\240+#define DE2_RESET_REG 0x0008\n"
+ ">> \302\240+#define DE2_DIV_REG 0x000c /* 4 bits per LCD */\n"
+ ">> \302\240+#define DE2_SEL_REG 0x0010\n"
+ ">> \302\240+\n"
+ ">> \302\240+#define DE2_MIXER0_BASE 0x00100000 /* LCD 0 */\n"
+ ">> \302\240+#define DE2_MIXER1_BASE 0x00200000 /* LCD 1 */\n"
+ ">> \302\240+\n"
+ ">> \302\240+/* mixer registers (addr / mixer base) */\n"
+ ">> \302\240+#define MIXER_GLB_REGS 0x00000 /* global control */\n"
+ ">> \302\240+#define MIXER_BLD_REGS 0x01000 /* alpha blending */\n"
+ ">> \302\240+#define MIXER_CHAN_REGS 0x02000 /* VI/UI overlay channels */\n"
+ ">> \302\240+#define MIXER_CHAN_SZ 0x1000 /* size of a channel */\n"
+ ">> \302\240+#define MIXER_VSU_REGS 0x20000 /* VSU */\n"
+ ">> \302\240+#define MIXER_GSU1_REGS 0x30000 /* GSUs */\n"
+ ">> \302\240+#define MIXER_GSU2_REGS 0x40000\n"
+ ">> \302\240+#define MIXER_GSU3_REGS 0x50000\n"
+ ">> \302\240+#define MIXER_FCE_REGS 0xa0000 /* FCE */\n"
+ ">> \302\240+#define MIXER_BWS_REGS 0xa2000 /* BWS */\n"
+ ">> \302\240+#define MIXER_LTI_REGS 0xa4000 /* LTI */\n"
+ ">> \302\240+#define MIXER_PEAK_REGS 0xa6000 /* PEAK */\n"
+ ">> \302\240+#define MIXER_ASE_REGS 0xa8000 /* ASE */\n"
+ ">> \302\240+#define MIXER_FCC_REGS 0xaa000 /* FCC */\n"
+ ">> \302\240+#define MIXER_DCSC_REGS 0xb0000 /* DCSC/SMBL */\n"
+ ">> \302\240+\n"
+ ">> \302\240+/* global control */\n"
+ ">> \302\240+#define MIXER_GLB_CTL_REG 0x00\n"
+ ">> \302\240+#define MIXER_GLB_CTL_rt_en BIT(0)\n"
+ ">> \302\240+#define MIXER_GLB_CTL_finish_irq_en BIT(4)\n"
+ ">> \302\240+#define MIXER_GLB_CTL_rtwb_port BIT(12)\n"
+ ">> \302\240+#define MIXER_GLB_STATUS_REG 0x04\n"
+ ">> \302\240+#define MIXER_GLB_DBUFF_REG 0x08\n"
+ ">> \302\240+#define MIXER_GLB_SIZE_REG 0x0c\n"
+ ">> \302\240+\n"
+ ">> \302\240+/* alpha blending */\n"
+ ">> \302\240+#define MIXER_BLD_FCOLOR_CTL_REG 0x00\n"
+ ">> \302\240+#define MIXER_BLD_FCOLOR_CTL_PEN(pipe) (0x0100 << (pipe))\n"
+ ">> \302\240+#define MIXER_BLD_ATTR_N 4 /* number of attribute blocks */\n"
+ ">> \302\240+#define MIXER_BLD_ATTR_SIZE (4 * 4) /* size of an attribute block */\n"
+ ">> \302\240+#define MIXER_BLD_ATTRx_FCOLOR(x) (0x04 + MIXER_BLD_ATTR_SIZE * (x))\n"
+ ">> \302\240+#define MIXER_BLD_ATTRx_INSIZE(x) (0x08 + MIXER_BLD_ATTR_SIZE * (x))\n"
+ ">> \302\240+#define MIXER_BLD_ATTRx_OFFSET(x) (0x0c + MIXER_BLD_ATTR_SIZE * (x))\n"
+ ">> \302\240+#define MIXER_BLD_ROUTE_REG 0x80\n"
+ ">> \302\240+#define MIXER_BLD_ROUTE(chan, pipe) ((chan) << ((pipe) * 4))\n"
+ ">> \302\240+#define MIXER_BLD_PREMULTIPLY_REG 0x84\n"
+ ">> \302\240+#define MIXER_BLD_BKCOLOR_REG 0x88\n"
+ ">> \302\240+#define MIXER_BLD_OUTPUT_SIZE_REG 0x8c\n"
+ ">> \302\240+#define MIXER_BLD_MODEx_REG(x) (0x90 + 4 * (x)) /* x = 0..3 */\n"
+ ">> \302\240+#define MIXER_BLD_MODE_SRCOVER 0x03010301\n"
+ ">> \302\240+#define MIXER_BLD_OUT_CTL_REG 0xfc\n"
+ ">> \302\240+\n"
+ ">> \302\240+/* VI channel (channel 0) */\n"
+ ">> \302\240+#define VI_CFG_N 4 /* number of layers */\n"
+ ">> \302\240+#define VI_CFG_SIZE 0x30 /* size of a layer */\n"
+ ">> \302\240+#define VI_CFGx_ATTR(l) (0x00 + VI_CFG_SIZE * (l))\n"
+ ">> \302\240+#define VI_CFG_ATTR_en BIT(0)\n"
+ ">> \302\240+#define VI_CFG_ATTR_fcolor_en BIT(4)\n"
+ ">> \302\240+#define VI_CFG_ATTR_fmt_SHIFT 8\n"
+ ">> \302\240+#define VI_CFG_ATTR_fmt_MASK GENMASK(12, 8)\n"
+ ">> \302\240+#define VI_CFG_ATTR_ui_sel BIT(15)\n"
+ ">> \302\240+#define VI_CFG_ATTR_top_down BIT(23)\n"
+ ">> \302\240+#define VI_CFGx_SIZE(l) (0x04 + VI_CFG_SIZE * (l))\n"
+ ">> \302\240+#define VI_CFGx_COORD(l) (0x08 + VI_CFG_SIZE * (l))\n"
+ ">> \302\240+#define VI_N_PLANES 3\n"
+ ">> \302\240+#define VI_CFGx_PITCHy(l, p) (0x0c + VI_CFG_SIZE * (l) + 4 * (p))\n"
+ ">> \302\240+#define VI_CFGx_TOP_LADDRy(l, p) (0x18 + VI_CFG_SIZE * (l) + 4 * (p))\n"
+ ">> \302\240+#define VI_CFGx_BOT_LADDRy(l, p) (0x24 + VI_CFG_SIZE * (l) + 4 * (p))\n"
+ ">> \302\240+#define VI_FCOLORx(l) (0xc0 + 4 * (l))\n"
+ ">> \302\240+#define VI_TOP_HADDRx(p) (0xd0 + 4 * (p))\n"
+ ">> \302\240+#define VI_BOT_HADDRx(p) (0xdc + 4 * (p))\n"
+ ">> \302\240+#define VI_OVL_SIZEx(n) (0xe8 + 4 * (n))\n"
+ ">> \302\240+#define VI_HORI_DSx(n) (0xf0 + 4 * (n))\n"
+ ">> \302\240+#define VI_VERT_DSx(n) (0xf8 + 4 * (n))\n"
+ ">> \302\240+#define VI_SIZE 0x100\n"
+ ">> \302\240+\n"
+ ">> \302\240+/* UI channel (channels 1..3) */\n"
+ ">> \302\240+#define UI_CFG_N 4 /* number of layers */\n"
+ ">> \302\240+#define UI_CFG_SIZE (8 * 4) /* size of a layer */\n"
+ ">> \302\240+#define UI_CFGx_ATTR(l) (0x00 + UI_CFG_SIZE * (l))\n"
+ ">> \302\240+#define UI_CFG_ATTR_en BIT(0)\n"
+ ">> \302\240+#define UI_CFG_ATTR_alpmod_SHIFT 1\n"
+ ">> \302\240+#define UI_CFG_ATTR_alpmod_MASK GENMASK(2, 1)\n"
+ ">> \302\240+#define UI_CFG_ATTR_fcolor_en BIT(4)\n"
+ ">> \302\240+#define UI_CFG_ATTR_fmt_SHIFT 8\n"
+ ">> \302\240+#define UI_CFG_ATTR_fmt_MASK GENMASK(12, 8)\n"
+ ">> \302\240+#define UI_CFG_ATTR_top_down BIT(23)\n"
+ ">> \302\240+#define UI_CFG_ATTR_alpha_SHIFT 24\n"
+ ">> \302\240+#define UI_CFG_ATTR_alpha_MASK GENMASK(31, 24)\n"
+ ">> \302\240+#define UI_CFGx_SIZE(l) (0x04 + UI_CFG_SIZE * (l))\n"
+ ">> \302\240+#define UI_CFGx_COORD(l) (0x08 + UI_CFG_SIZE * (l))\n"
+ ">> \302\240+#define UI_CFGx_PITCH(l) (0x0c + UI_CFG_SIZE * (l))\n"
+ ">> \302\240+#define UI_CFGx_TOP_LADDR(l) (0x10 + UI_CFG_SIZE * (l))\n"
+ ">> \302\240+#define UI_CFGx_BOT_LADDR(l) (0x14 + UI_CFG_SIZE * (l))\n"
+ ">> \302\240+#define UI_CFGx_FCOLOR(l) (0x18 + UI_CFG_SIZE * (l))\n"
+ ">> \302\240+#define UI_TOP_HADDR 0x80\n"
+ ">> \302\240+#define UI_BOT_HADDR 0x84\n"
+ ">> \302\240+#define UI_OVL_SIZE 0x88\n"
+ ">> \302\240+#define UI_SIZE 0x8c\n"
+ ">> \302\240+\n"
+ ">> \302\240+/* coordinates and sizes */\n"
+ ">> \302\240+#define XY(x, y) (((y) << 16) | (x))\n"
+ ">> \302\240+#define WH(w, h) ((((h) - 1) << 16) | ((w) - 1))\n"
+ ">> \302\240+\n"
+ ">> \302\240+/* UI video formats */\n"
+ ">> \302\240+#define DE2_FORMAT_ARGB_8888 0\n"
+ ">> \302\240+#define DE2_FORMAT_BGRA_8888 3\n"
+ ">> \302\240+#define DE2_FORMAT_XRGB_8888 4\n"
+ ">> \302\240+#define DE2_FORMAT_RGB_888 8\n"
+ ">> \302\240+#define DE2_FORMAT_BGR_888 9\n"
+ ">> \302\240+\n"
+ ">> \302\240+/* VI video formats */\n"
+ ">> \302\240+#define DE2_FORMAT_YUV422_I_YVYU 1 /* YVYU */\n"
+ ">> \302\240+#define DE2_FORMAT_YUV422_I_UYVY 2 /* UYVY */\n"
+ ">> \302\240+#define DE2_FORMAT_YUV422_I_YUYV 3 /* YUYV */\n"
+ ">> \302\240+#define DE2_FORMAT_YUV422_P 6 /* YYYY UU VV planar */\n"
+ ">> \302\240+#define DE2_FORMAT_YUV420_P 10 /* YYYY U V planar */\n"
+ ">> \302\240+\n"
+ ">> \302\240+/* plane formats */\n"
+ ">> \302\240+static const uint32_t ui_formats[] = {\n"
+ ">> \302\240+ DRM_FORMAT_ARGB8888,\n"
+ ">> \302\240+ DRM_FORMAT_BGRA8888,\n"
+ ">> \302\240+ DRM_FORMAT_XRGB8888,\n"
+ ">> \302\240+ DRM_FORMAT_RGB888,\n"
+ ">> \302\240+ DRM_FORMAT_BGR888,\n"
+ ">> \302\240+};\n"
+ ">> \302\240+\n"
+ ">> \302\240+static const uint32_t vi_formats[] = {\n"
+ ">> \302\240+ DRM_FORMAT_XRGB8888,\n"
+ ">> \302\240+ DRM_FORMAT_YUYV,\n"
+ ">> \302\240+ DRM_FORMAT_YVYU,\n"
+ ">> \302\240+ DRM_FORMAT_YUV422,\n"
+ ">> \302\240+ DRM_FORMAT_YUV420,\n"
+ ">> \302\240+ DRM_FORMAT_UYVY,\n"
+ ">> \302\240+ DRM_FORMAT_BGRA8888,\n"
+ ">> \302\240+ DRM_FORMAT_RGB888,\n"
+ ">> \302\240+ DRM_FORMAT_BGR888,\n"
+ ">> \302\240+};\n"
+ ">> \302\240+\n"
+ ">> \302\240+/*\n"
+ ">> \302\240+ * plane table\n"
+ ">> \302\240+ *\n"
+ ">> \302\240+ * The chosen channel/layer assignment of the planes respects\n"
+ ">> \302\240+ * the following constraints:\n"
+ ">> \302\240+ * - the cursor must be in a channel higher than the primary channel\n"
+ ">> \302\240+ * - there are 4 channels in the LCD 0 and only 2 channels in the LCD 1\n"
+ ">> \302\240+ */\n"
+ ">> \302\240+static const struct {\n"
+ ">> \302\240+ u8 chan;\n"
+ ">> \302\240+ u8 layer;\n"
+ ">> \302\240+ u8 pipe;\n"
+ ">> \302\240+ u8 type; /* plane type */\n"
+ ">> \302\240+ const uint32_t *formats;\n"
+ ">> \302\240+ u8 n_formats;\n"
+ ">> \302\240+} plane_tb[] = {\n"
+ ">> \302\240+ [DE2_PRIMARY_PLANE] = { /* primary plane: channel 0 (VI) */\n"
+ ">> \302\240+ 0, 0, 0,\n"
+ ">> \302\240+ DRM_PLANE_TYPE_PRIMARY,\n"
+ ">> \302\240+ ui_formats, ARRAY_SIZE(ui_formats),\n"
+ ">> \302\240+ },\n"
+ ">> \302\240+ [DE2_CURSOR_PLANE] = { /* cursor: channel 1 (UI) */\n"
+ ">> \302\240+ 1, 0, 1,\n"
+ ">> \302\240+ DRM_PLANE_TYPE_CURSOR,\n"
+ ">> \302\240+ ui_formats, ARRAY_SIZE(ui_formats),\n"
+ ">> \302\240+ },\n"
+ ">> \302\240+ {\n"
+ ">> \302\240+ 0, 1, 0, /* 1st overlay: channel 0, layer 1 */\n"
+ ">> \302\240+ DRM_PLANE_TYPE_OVERLAY,\n"
+ ">> \302\240+ vi_formats, ARRAY_SIZE(vi_formats),\n"
+ ">> \302\240+ },\n"
+ ">> \302\240+ {\n"
+ ">> \302\240+ 0, 2, 0, /* 2nd overlay: channel 0, layer 2 */\n"
+ ">> \302\240+ DRM_PLANE_TYPE_OVERLAY,\n"
+ ">> \302\240+ vi_formats, ARRAY_SIZE(vi_formats),\n"
+ ">> \302\240+ },\n"
+ ">> \302\240+ {\n"
+ ">> \302\240+ 0, 3, 0, /* 3rd overlay: channel 0, layer 3 */\n"
+ ">> \302\240+ DRM_PLANE_TYPE_OVERLAY,\n"
+ ">> \302\240+ vi_formats, ARRAY_SIZE(vi_formats),\n"
+ ">> \302\240+ },\n"
+ ">> \302\240+};\n"
+ ">> \302\240+\n"
+ ">> \302\240+static inline void andl_relaxed(void __iomem *addr, u32 val)\n"
+ ">> \302\240+{\n"
+ ">> \302\240+ writel_relaxed(readl_relaxed(addr) & val, addr);\n"
+ ">> \302\240+}\n"
+ ">> \302\240+\n"
+ ">> \302\240+static inline void orl_relaxed(void __iomem *addr, u32 val)\n"
+ ">> \302\240+{\n"
+ ">> \302\240+ writel_relaxed(readl_relaxed(addr) | val, addr);\n"
+ ">> \302\240+}\n"
+ ">> \302\240+\n"
+ ">> \302\240+/* alert the DE processor about changes in a mixer configuration */\n"
+ ">> \302\240+static void de2_mixer_select(struct priv *priv,\n"
+ ">> \302\240+ int mixer,\n"
+ ">> \302\240+ void __iomem *mixer_io)\n"
+ ">> \302\240+{\n"
+ ">> \302\240+ /* select the mixer */\n"
+ ">> \302\240+ andl_relaxed(priv->mmio + DE2_SEL_REG, ~1);\n"
+ ">> \302\240+\n"
+ ">> \302\240+ /* double register switch */\n"
+ ">> \302\240+ writel_relaxed(1, mixer_io + MIXER_GLB_REGS + MIXER_GLB_DBUFF_REG);\n"
+ ">> \302\240+}\n"
+ ">> \302\240+\n"
+ ">> \302\240+/*\n"
+ ">> \302\240+ * cleanup a mixer\n"
+ ">> \302\240+ *\n"
+ ">> \302\240+ * This is needed only once after power on.\n"
+ ">> \302\240+ */\n"
+ ">> \302\240+static void de2_mixer_cleanup(struct priv *priv, int mixer,\n"
+ ">> \302\240+ u32 size)\n"
+ ">> \302\240+{\n"
+ ">> \302\240+ void __iomem *mixer_io = priv->mmio;\n"
+ ">> \302\240+ void __iomem *chan_io;\n"
+ ">> \302\240+ u32 data;\n"
+ ">> \302\240+ unsigned int i;\n"
+ ">> \302\240+\n"
+ ">> \302\240+ mixer_io += (mixer == 0) ? DE2_MIXER0_BASE : DE2_MIXER1_BASE;\n"
+ ">> \302\240+ chan_io = mixer_io + MIXER_CHAN_REGS;\n"
+ ">> \302\240+\n"
+ ">> \302\240+ andl_relaxed(priv->mmio + DE2_SEL_REG, ~1);\n"
+ ">> \302\240+ writel_relaxed(1, mixer_io + MIXER_GLB_REGS + MIXER_GLB_DBUFF_REG);\n"
+ ">> \302\240+\n"
+ ">> \302\240+ writel_relaxed(MIXER_GLB_CTL_rt_en,\n"
+ ">> \302\240+ mixer_io + MIXER_GLB_REGS + MIXER_GLB_CTL_REG);\n"
+ ">> \302\240+ writel_relaxed(0, mixer_io + MIXER_GLB_REGS + MIXER_GLB_STATUS_REG);\n"
+ ">> \302\240+\n"
+ ">> \302\240+ writel_relaxed(size, mixer_io + MIXER_GLB_REGS + MIXER_GLB_SIZE_REG);\n"
+ ">> \302\240+\n"
+ ">> \302\240+ /*\n"
+ ">> \302\240+ * clear the VI/UI channels\n"
+ ">> \302\240+ * LCD0: 1 VI and 3 UIs\n"
+ ">> \302\240+ * LCD1: 1 VI and 1 UI\n"
+ ">> \302\240+ */\n"
+ ">> \302\240+ memset_io(chan_io, 0, VI_SIZE);\n"
+ ">> \302\240+ memset_io(chan_io + MIXER_CHAN_SZ, 0, UI_SIZE);\n"
+ ">> \302\240+ if (mixer == 0) {\n"
+ ">> \302\240+ memset_io(chan_io + MIXER_CHAN_SZ * 2, 0, UI_SIZE);\n"
+ ">> \302\240+ memset_io(chan_io + MIXER_CHAN_SZ * 3, 0, UI_SIZE);\n"
+ ">> \302\240+ }\n"
+ ">> \302\240+\n"
+ ">> \302\240+ /* alpha blending */\n"
+ ">> \302\240+ writel_relaxed(0x00000001 | /* fcolor for primary */\n"
+ ">> \302\240+ MIXER_BLD_FCOLOR_CTL_PEN(0),\n"
+ ">> \302\240+ mixer_io + MIXER_BLD_REGS + MIXER_BLD_FCOLOR_CTL_REG);\n"
+ ">> \302\240+ for (i = 0; i < MIXER_BLD_ATTR_N; i++) {\n"
+ ">> \302\240+ writel_relaxed(0xff000000,\n"
+ ">> \302\240+ mixer_io + MIXER_BLD_REGS + MIXER_BLD_ATTRx_FCOLOR(i));\n"
+ ">> \302\240+ writel_relaxed(size,\n"
+ ">> \302\240+ mixer_io + MIXER_BLD_REGS + MIXER_BLD_ATTRx_INSIZE(i));\n"
+ ">> \302\240+ writel_relaxed(0,\n"
+ ">> \302\240+ mixer_io + MIXER_BLD_REGS + MIXER_BLD_ATTRx_OFFSET(i));\n"
+ ">> \302\240+ }\n"
+ ">> \302\240+ writel_relaxed(0, mixer_io + MIXER_BLD_REGS + MIXER_BLD_OUT_CTL_REG);\n"
+ ">> \302\240+\n"
+ ">> \302\240+ /* prepare the pipe route for the planes */\n"
+ ">> \302\240+ data = 0;\n"
+ ">> \302\240+ for (i = 0; i < DE2_N_PLANES; i++)\n"
+ ">> \302\240+ data |= MIXER_BLD_ROUTE(plane_tb[i].chan, plane_tb[i].pipe);\n"
+ ">> \302\240+ writel_relaxed(data, mixer_io + MIXER_BLD_REGS + MIXER_BLD_ROUTE_REG);\n"
+ ">> \302\240+\n"
+ ">> \302\240+ writel_relaxed(0, mixer_io + MIXER_BLD_REGS +\n"
+ ">> \302\240+ MIXER_BLD_PREMULTIPLY_REG);\n"
+ ">> \302\240+ writel_relaxed(0xff000000, mixer_io + MIXER_BLD_REGS +\n"
+ ">> \302\240+ MIXER_BLD_BKCOLOR_REG);\n"
+ ">> \302\240+ writel_relaxed(size, mixer_io + MIXER_BLD_REGS +\n"
+ ">> \302\240+ MIXER_BLD_OUTPUT_SIZE_REG);\n"
+ ">> \302\240+ writel_relaxed(MIXER_BLD_MODE_SRCOVER,\n"
+ ">> \302\240+ mixer_io + MIXER_BLD_REGS + MIXER_BLD_MODEx_REG(0));\n"
+ ">> \302\240+ writel_relaxed(MIXER_BLD_MODE_SRCOVER,\n"
+ ">> \302\240+ mixer_io + MIXER_BLD_REGS + MIXER_BLD_MODEx_REG(1));\n"
+ ">> \302\240+\n"
+ ">> \302\240+ /* disable the enhancements */\n"
+ ">> \302\240+ writel_relaxed(0, mixer_io + MIXER_VSU_REGS);\n"
+ ">> \302\240+ writel_relaxed(0, mixer_io + MIXER_GSU1_REGS);\n"
+ ">> \302\240+ writel_relaxed(0, mixer_io + MIXER_GSU2_REGS);\n"
+ ">> \302\240+ writel_relaxed(0, mixer_io + MIXER_GSU3_REGS);\n"
+ ">> \302\240+ writel_relaxed(0, mixer_io + MIXER_FCE_REGS);\n"
+ ">> \302\240+ writel_relaxed(0, mixer_io + MIXER_BWS_REGS);\n"
+ ">> \302\240+ writel_relaxed(0, mixer_io + MIXER_LTI_REGS);\n"
+ ">> \302\240+ writel_relaxed(0, mixer_io + MIXER_PEAK_REGS);\n"
+ ">> \302\240+ writel_relaxed(0, mixer_io + MIXER_ASE_REGS);\n"
+ ">> \302\240+ writel_relaxed(0, mixer_io + MIXER_FCC_REGS);\n"
+ ">> \302\240+ writel_relaxed(0, mixer_io + MIXER_DCSC_REGS);\n"
+ ">> \302\240+}\n"
+ ">> \302\240+\n"
+ ">> \302\240+/* enable a mixer */\n"
+ ">> \302\240+static void de2_mixer_enable(struct lcd *lcd)\n"
+ ">> \302\240+{\n"
+ ">> \302\240+ struct priv *priv = lcd->priv;\n"
+ ">> \302\240+ void __iomem *mixer_io = priv->mmio;\n"
+ ">> \302\240+ struct drm_display_mode *mode = &lcd->crtc.mode;\n"
+ ">> \302\240+ u32 size = WH(mode->hdisplay, mode->vdisplay);\n"
+ ">> \302\240+ u32 data;\n"
+ ">> \302\240+ int mixer = lcd->mixer;\n"
+ ">> \302\240+ int i;\n"
+ ">> \302\240+\n"
+ ">> \302\240+ mixer_io += (mixer == 0) ? DE2_MIXER0_BASE : DE2_MIXER1_BASE;\n"
+ ">> \302\240+\n"
+ ">> \302\240+ /* if not done yet, start the DE processor */\n"
+ ">> \302\240+ if (!priv->started) {\n"
+ ">> \302\240+ reset_control_deassert(priv->reset);\n"
+ ">> \302\240+ clk_prepare_enable(priv->gate);\n"
+ ">> \302\240+ clk_prepare_enable(priv->clk);\n"
+ ">> \302\240+ }\n"
+ ">> \302\240+ priv->started |= 1 << mixer;\n"
+ ">> \302\240+\n"
+ ">> \302\240+ /* set the A83T clock divider (500 / 2) = 250MHz */\n"
+ ">> \302\240+ if (priv->soc_type == SOC_A83T)\n"
+ ">> \302\240+ writel_relaxed(0x00000011, /* div = 2 for both LCDs */\n"
+ ">> \302\240+ priv->mmio + DE2_DIV_REG);\n"
+ ">> \302\240+\n"
+ ">> \302\240+ /* deassert the mixer and enable its clock */\n"
+ ">> \302\240+ orl_relaxed(priv->mmio + DE2_RESET_REG, mixer == 0 ? 1 : 4);\n"
+ ">> \302\240+ data = 1 << mixer; /* 1 bit / lcd */\n"
+ ">> \302\240+ orl_relaxed(priv->mmio + DE2_GATE_REG, data);\n"
+ ">> \302\240+ orl_relaxed(priv->mmio + DE2_MOD_REG, data);\n"
+ ">> \302\240+\n"
+ ">> \302\240+ /* if not done yet, cleanup and enable */\n"
+ ">> \302\240+ if (!(priv->clean & (1 << mixer))) {\n"
+ ">> \302\240+ priv->clean |= 1 << mixer;\n"
+ ">> \302\240+ de2_mixer_cleanup(priv, mixer, size);\n"
+ ">> \302\240+ return;\n"
+ ">> \302\240+ }\n"
+ ">> \302\240+\n"
+ ">> \302\240+ /* enable */\n"
+ ">> \302\240+ de2_mixer_select(priv, mixer, mixer_io);\n"
+ ">> \302\240+\n"
+ ">> \302\240+ writel_relaxed(MIXER_GLB_CTL_rt_en,\n"
+ ">> \302\240+ mixer_io + MIXER_GLB_REGS + MIXER_GLB_CTL_REG);\n"
+ ">> \302\240+ writel_relaxed(0, mixer_io + MIXER_GLB_REGS + MIXER_GLB_STATUS_REG);\n"
+ ">> \302\240+\n"
+ ">> \302\240+ /* set the size of the frame buffer */\n"
+ ">> \302\240+ writel_relaxed(size, mixer_io + MIXER_GLB_REGS + MIXER_GLB_SIZE_REG);\n"
+ ">> \302\240+ for (i = 0; i < MIXER_BLD_ATTR_N; i++)\n"
+ ">> \302\240+ writel_relaxed(size, mixer_io + MIXER_BLD_REGS +\n"
+ ">> \302\240+ MIXER_BLD_ATTRx_INSIZE(i));\n"
+ ">> \302\240+ writel_relaxed(size, mixer_io + MIXER_BLD_REGS +\n"
+ ">> \302\240+ MIXER_BLD_OUTPUT_SIZE_REG);\n"
+ ">> \302\240+\n"
+ ">> \302\240+ writel_relaxed(mode->flags & DRM_MODE_FLAG_INTERLACE ? 2 : 0,\n"
+ ">> \302\240+ mixer_io + MIXER_BLD_REGS + MIXER_BLD_OUT_CTL_REG);\n"
+ ">> \302\240+}\n"
+ ">> \302\240+\n"
+ ">> \302\240+/* enable a LCD (DE mixer) */\n"
+ ">> \302\240+void de2_de_enable(struct lcd *lcd)\n"
+ ">> \302\240+{\n"
+ ">> \302\240+ mutex_lock(&lcd->priv->mutex);\n"
+ ">> \302\240+\n"
+ ">> \302\240+ de2_mixer_enable(lcd);\n"
+ ">> \302\240+\n"
+ ">> \302\240+ mutex_unlock(&lcd->priv->mutex);\n"
+ ">> \302\240+}\n"
+ ">> \302\240+\n"
+ ">> \302\240+/* disable a LCD (DE mixer) */\n"
+ ">> \302\240+void de2_de_disable(struct lcd *lcd)\n"
+ ">> \302\240+{\n"
+ ">> \302\240+ struct priv *priv = lcd->priv;\n"
+ ">> \302\240+ void __iomem *mixer_io = priv->mmio;\n"
+ ">> \302\240+ int mixer = lcd->mixer;\n"
+ ">> \302\240+ u32 data;\n"
+ ">> \302\240+\n"
+ ">> \302\240+ mixer_io += (mixer == 0) ? DE2_MIXER0_BASE : DE2_MIXER1_BASE;\n"
+ ">> \302\240+\n"
+ ">> \302\240+ mutex_lock(&priv->mutex);\n"
+ ">> \302\240+\n"
+ ">> \302\240+ de2_mixer_select(priv, mixer, mixer_io);\n"
+ ">> \302\240+\n"
+ ">> \302\240+ writel_relaxed(0, mixer_io + MIXER_GLB_REGS + MIXER_GLB_CTL_REG);\n"
+ ">> \302\240+\n"
+ ">> \302\240+ data = ~(1 << mixer);\n"
+ ">> \302\240+ andl_relaxed(priv->mmio + DE2_MOD_REG, data);\n"
+ ">> \302\240+ andl_relaxed(priv->mmio + DE2_GATE_REG, data);\n"
+ ">> \302\240+ andl_relaxed(priv->mmio + DE2_RESET_REG, data);\n"
+ ">> \302\240+\n"
+ ">> \302\240+ mutex_unlock(&priv->mutex);\n"
+ ">> \302\240+\n"
+ ">> \302\240+ /* if all mixers are disabled, stop the DE */\n"
+ ">> \302\240+ priv->started &= ~(1 << mixer);\n"
+ ">> \302\240+ if (!priv->started) {\n"
+ ">> \302\240+ clk_disable_unprepare(priv->clk);\n"
+ ">> \302\240+ clk_disable_unprepare(priv->gate);\n"
+ ">> \302\240+ reset_control_assert(priv->reset);\n"
+ ">> \302\240+ }\n"
+ ">> \302\240+}\n"
+ ">> \302\240+\n"
+ ">> \302\240+static void de2_vi_update(void __iomem *chan_io,\n"
+ ">> \302\240+ struct drm_gem_cma_object *gem,\n"
+ ">> \302\240+ int layer,\n"
+ ">> \302\240+ unsigned int fmt,\n"
+ ">> \302\240+ u32 ui_sel,\n"
+ ">> \302\240+ u32 size,\n"
+ ">> \302\240+ u32 coord,\n"
+ ">> \302\240+ struct drm_framebuffer *fb,\n"
+ ">> \302\240+ u32 screen_size)\n"
+ ">> \302\240+{\n"
+ ">> \302\240+ int i;\n"
+ ">> \302\240+\n"
+ ">> \302\240+ writel_relaxed(VI_CFG_ATTR_en |\n"
+ ">> \302\240+ (fmt << VI_CFG_ATTR_fmt_SHIFT) |\n"
+ ">> \302\240+ ui_sel,\n"
+ ">> \302\240+ chan_io + VI_CFGx_ATTR(layer));\n"
+ ">> \302\240+ writel_relaxed(size, chan_io + VI_CFGx_SIZE(layer));\n"
+ ">> \302\240+ writel_relaxed(coord, chan_io + VI_CFGx_COORD(layer));\n"
+ ">> \302\240+ for (i = 0; i < VI_N_PLANES; i++) {\n"
+ ">> \302\240+ writel_relaxed(fb->pitches[i] ? fb->pitches[i] :\n"
+ ">> \302\240+ fb->pitches[0],\n"
+ ">> \302\240+ chan_io + VI_CFGx_PITCHy(layer, i));\n"
+ ">> \302\240+ writel_relaxed(gem->paddr + fb->offsets[i],\n"
+ ">> \302\240+ chan_io + VI_CFGx_TOP_LADDRy(layer, i));\n"
+ ">> \302\240+ }\n"
+ ">> \302\240+ writel_relaxed(0xff000000, chan_io + VI_FCOLORx(layer));\n"
+ ">> \302\240+ if (layer == 0) {\n"
+ ">> \302\240+ writel_relaxed(screen_size,\n"
+ ">> \302\240+ chan_io + VI_OVL_SIZEx(0));\n"
+ ">> \302\240+ }\n"
+ ">> \302\240+}\n"
+ ">> \302\240+\n"
+ ">> \302\240+static void de2_ui_update(void __iomem *chan_io,\n"
+ ">> \302\240+ struct drm_gem_cma_object *gem,\n"
+ ">> \302\240+ int layer,\n"
+ ">> \302\240+ unsigned int fmt,\n"
+ ">> \302\240+ u32 alpha_glob,\n"
+ ">> \302\240+ u32 size,\n"
+ ">> \302\240+ u32 coord,\n"
+ ">> \302\240+ struct drm_framebuffer *fb,\n"
+ ">> \302\240+ u32 screen_size)\n"
+ ">> \302\240+{\n"
+ ">> \302\240+ writel_relaxed(UI_CFG_ATTR_en |\n"
+ ">> \302\240+ (fmt << UI_CFG_ATTR_fmt_SHIFT) |\n"
+ ">> \302\240+ alpha_glob,\n"
+ ">> \302\240+ chan_io + UI_CFGx_ATTR(layer));\n"
+ ">> \302\240+ writel_relaxed(size, chan_io + UI_CFGx_SIZE(layer));\n"
+ ">> \302\240+ writel_relaxed(coord, chan_io + UI_CFGx_COORD(layer));\n"
+ ">> \302\240+ writel_relaxed(fb->pitches[0], chan_io + UI_CFGx_PITCH(layer));\n"
+ ">> \302\240+ writel_relaxed(gem->paddr + fb->offsets[0],\n"
+ ">> \302\240+ chan_io + UI_CFGx_TOP_LADDR(layer));\n"
+ ">> \302\240+ if (layer == 0)\n"
+ ">> \302\240+ writel_relaxed(screen_size, chan_io + UI_OVL_SIZE);\n"
+ ">> \302\240+}\n"
+ ">> \302\240+\n"
+ ">> \302\240+static void de2_plane_update(struct priv *priv, struct lcd *lcd,\n"
+ ">> \302\240+ int plane_num,\n"
+ ">> \302\240+ struct drm_plane_state *state,\n"
+ ">> \302\240+ struct drm_plane_state *old_state)\n"
+ ">> \302\240+{\n"
+ ">> \302\240+ void __iomem *mixer_io = priv->mmio;\n"
+ ">> \302\240+ void __iomem *chan_io;\n"
+ ">> \302\240+ struct drm_framebuffer *fb = state->fb;\n"
+ ">> \302\240+ struct drm_gem_cma_object *gem;\n"
+ ">> \302\240+ u32 size = WH(state->crtc_w, state->crtc_h);\n"
+ ">> \302\240+ u32 coord, screen_size;\n"
+ ">> \302\240+ u32 fcolor;\n"
+ ">> \302\240+ u32 ui_sel, alpha_glob;\n"
+ ">> \302\240+ int mixer = lcd->mixer;\n"
+ ">> \302\240+ int chan, layer, x, y;\n"
+ ">> \302\240+ unsigned int fmt;\n"
+ ">> \302\240+\n"
+ ">> \302\240+ chan = plane_tb[plane_num].chan;\n"
+ ">> \302\240+ layer = plane_tb[plane_num].layer;\n"
+ ">> \302\240+\n"
+ ">> \302\240+ mixer_io += (mixer == 0) ? DE2_MIXER0_BASE : DE2_MIXER1_BASE;\n"
+ ">> \302\240+ chan_io = mixer_io + MIXER_CHAN_REGS + MIXER_CHAN_SZ * chan;\n"
+ ">> \302\240+\n"
+ ">> \302\240+ x = state->crtc_x >= 0 ? state->crtc_x : 0;\n"
+ ">> \302\240+ y = state->crtc_y >= 0 ? state->crtc_y : 0;\n"
+ ">> \302\240+ coord = XY(x, y);\n"
+ ">> \302\240+\n"
+ ">> \302\240+ /* if plane update was delayed, force a full update */\n"
+ ">> \302\240+ if (priv->lcds[drm_crtc_index(&lcd->crtc)]->delayed &\n"
+ ">> \302\240+ (1 << plane_num)) {\n"
+ ">> \302\240+ priv->lcds[drm_crtc_index(&lcd->crtc)]->delayed &=\n"
+ ">> \302\240+ ~(1 << plane_num);\n"
+ ">> \302\240+\n"
+ ">> \302\240+ /* handle plane move */\n"
+ ">> \302\240+ } else if (fb == old_state->fb) {\n"
+ ">> \302\240+ de2_mixer_select(priv, mixer, mixer_io);\n"
+ ">> \302\240+ if (chan == 0)\n"
+ ">> \302\240+ writel_relaxed(coord, chan_io + VI_CFGx_COORD(layer));\n"
+ ">> \302\240+ else\n"
+ ">> \302\240+ writel_relaxed(coord, chan_io + UI_CFGx_COORD(layer));\n"
+ ">> \302\240+ return;\n"
+ ">> \302\240+ }\n"
+ ">> \302\240+\n"
+ ">> \302\240+ gem = drm_fb_cma_get_gem_obj(fb, 0);\n"
+ ">> \302\240+\n"
+ ">> \302\240+ ui_sel = alpha_glob = 0;\n"
+ ">> \302\240+\n"
+ ">> \302\240+ switch (fb->pixel_format) {\n"
+ ">> \302\240+ case DRM_FORMAT_ARGB8888:\n"
+ ">> \302\240+ fmt = DE2_FORMAT_ARGB_8888;\n"
+ ">> \302\240+ ui_sel = VI_CFG_ATTR_ui_sel;\n"
+ ">> \302\240+ break;\n"
+ ">> \302\240+ case DRM_FORMAT_BGRA8888:\n"
+ ">> \302\240+ fmt = DE2_FORMAT_BGRA_8888;\n"
+ ">> \302\240+ ui_sel = VI_CFG_ATTR_ui_sel;\n"
+ ">> \302\240+ break;\n"
+ ">> \302\240+ case DRM_FORMAT_XRGB8888:\n"
+ ">> \302\240+ fmt = DE2_FORMAT_XRGB_8888;\n"
+ ">> \302\240+ ui_sel = VI_CFG_ATTR_ui_sel;\n"
+ ">> \302\240+ alpha_glob = (1 << UI_CFG_ATTR_alpmod_SHIFT) |\n"
+ ">> \302\240+ (0xff << UI_CFG_ATTR_alpha_SHIFT);\n"
+ ">> \302\240+ break;\n"
+ ">> \302\240+ case DRM_FORMAT_RGB888:\n"
+ ">> \302\240+ fmt = DE2_FORMAT_RGB_888;\n"
+ ">> \302\240+ ui_sel = VI_CFG_ATTR_ui_sel;\n"
+ ">> \302\240+ break;\n"
+ ">> \302\240+ case DRM_FORMAT_BGR888:\n"
+ ">> \302\240+ fmt = DE2_FORMAT_BGR_888;\n"
+ ">> \302\240+ ui_sel = VI_CFG_ATTR_ui_sel;\n"
+ ">> \302\240+ break;\n"
+ ">> \302\240+ case DRM_FORMAT_YUYV:\n"
+ ">> \302\240+ fmt = DE2_FORMAT_YUV422_I_YUYV;\n"
+ ">> \302\240+ break;\n"
+ ">> \302\240+ case DRM_FORMAT_YVYU:\n"
+ ">> \302\240+ fmt = DE2_FORMAT_YUV422_I_YVYU;\n"
+ ">> \302\240+ break;\n"
+ ">> \302\240+ case DRM_FORMAT_YUV422:\n"
+ ">> \302\240+ fmt = DE2_FORMAT_YUV422_P;\n"
+ ">> \302\240+ break;\n"
+ ">> \302\240+ case DRM_FORMAT_YUV420:\n"
+ ">> \302\240+ fmt = DE2_FORMAT_YUV420_P;\n"
+ ">> \302\240+ break;\n"
+ ">> \302\240+ case DRM_FORMAT_UYVY:\n"
+ ">> \302\240+ fmt = DE2_FORMAT_YUV422_I_UYVY;\n"
+ ">> \302\240+ break;\n"
+ ">> \302\240+ default:\n"
+ ">> \302\240+ pr_err(\"de2_plane_update: format %.4s not yet treated\\n\",\n"
+ ">> \302\240+ (char *) &fb->pixel_format);\n"
+ ">> \302\240+ return;\n"
+ ">> \302\240+ }\n"
+ ">> \302\240+\n"
+ ">> \302\240+ /* the overlay size is the one of the primary plane */\n"
+ ">> \302\240+ screen_size = plane_num == DE2_PRIMARY_PLANE ?\n"
+ ">> \302\240+ size :\n"
+ ">> \302\240+ readl_relaxed(mixer_io + MIXER_GLB_REGS + MIXER_GLB_SIZE_REG);\n"
+ ">> \302\240+\n"
+ ">> \302\240+ /* prepare pipe enable */\n"
+ ">> \302\240+ fcolor = readl_relaxed(mixer_io + MIXER_BLD_REGS +\n"
+ ">> \302\240+ MIXER_BLD_FCOLOR_CTL_REG);\n"
+ ">> \302\240+ fcolor |= MIXER_BLD_FCOLOR_CTL_PEN(plane_tb[plane_num].pipe);\n"
+ ">> \302\240+\n"
+ ">> \302\240+ de2_mixer_select(priv, mixer, mixer_io);\n"
+ ">> \302\240+\n"
+ ">> \302\240+ if (chan == 0) /* VI channel */\n"
+ ">> \302\240+ de2_vi_update(chan_io, gem, layer, fmt, ui_sel, size, coord,\n"
+ ">> \302\240+ fb, screen_size);\n"
+ ">> \302\240+ else /* UI channel */\n"
+ ">> \302\240+ de2_ui_update(chan_io, gem, layer, fmt, alpha_glob, size, coord,\n"
+ ">> \302\240+ fb, screen_size);\n"
+ ">> \302\240+ writel_relaxed(fcolor, mixer_io + MIXER_BLD_REGS +\n"
+ ">> \302\240+ MIXER_BLD_FCOLOR_CTL_REG);\n"
+ ">> \302\240+}\n"
+ ">> \302\240+\n"
+ ">> \302\240+static int vi_nb_layers(void __iomem *chan_io)\n"
+ ">> \302\240+{\n"
+ ">> \302\240+ int layer, n = 0;\n"
+ ">> \302\240+\n"
+ ">> \302\240+ for (layer = 0; layer < 4; layer++) {\n"
+ ">> \302\240+ if (readl_relaxed(chan_io + VI_CFGx_ATTR(layer)) != 0)\n"
+ ">> \302\240+ n++;\n"
+ ">> \302\240+ }\n"
+ ">> \302\240+\n"
+ ">> \302\240+ return n;\n"
+ ">> \302\240+}\n"
+ ">> \302\240+\n"
+ ">> \302\240+static int ui_nb_layers(void __iomem *chan_io)\n"
+ ">> \302\240+{\n"
+ ">> \302\240+ int layer, n = 0;\n"
+ ">> \302\240+\n"
+ ">> \302\240+ for (layer = 0; layer < 4; layer++) {\n"
+ ">> \302\240+ if (readl_relaxed(chan_io + UI_CFGx_ATTR(layer)) != 0)\n"
+ ">> \302\240+ n++;\n"
+ ">> \302\240+ }\n"
+ ">> \302\240+\n"
+ ">> \302\240+ return n;\n"
+ ">> \302\240+}\n"
+ ">> \302\240+\n"
+ ">> \302\240+static void de2_plane_disable(struct priv *priv,\n"
+ ">> \302\240+ int mixer, int plane_num)\n"
+ ">> \302\240+{\n"
+ ">> \302\240+ void __iomem *mixer_io = priv->mmio;\n"
+ ">> \302\240+ void __iomem *chan_io;\n"
+ ">> \302\240+ u32 fcolor;\n"
+ ">> \302\240+ int chan, layer, n;\n"
+ ">> \302\240+\n"
+ ">> \302\240+ chan = plane_tb[plane_num].chan;\n"
+ ">> \302\240+ layer = plane_tb[plane_num].layer;\n"
+ ">> \302\240+\n"
+ ">> \302\240+ mixer_io += (mixer == 0) ? DE2_MIXER0_BASE : DE2_MIXER1_BASE;\n"
+ ">> \302\240+ chan_io = mixer_io + MIXER_CHAN_REGS + MIXER_CHAN_SZ * chan;\n"
+ ">> \302\240+\n"
+ ">> \302\240+ if (chan == 0)\n"
+ ">> \302\240+ n = vi_nb_layers(chan_io);\n"
+ ">> \302\240+ else\n"
+ ">> \302\240+ n = ui_nb_layers(chan_io);\n"
+ ">> \302\240+\n"
+ ">> \302\240+ fcolor = readl_relaxed(mixer_io + MIXER_BLD_REGS +\n"
+ ">> \302\240+ MIXER_BLD_FCOLOR_CTL_REG);\n"
+ ">> \302\240+\n"
+ ">> \302\240+ de2_mixer_select(priv, mixer, mixer_io);\n"
+ ">> \302\240+\n"
+ ">> \302\240+ if (chan == 0)\n"
+ ">> \302\240+ writel_relaxed(0, chan_io + VI_CFGx_ATTR(layer));\n"
+ ">> \302\240+ else\n"
+ ">> \302\240+ writel_relaxed(0, chan_io + UI_CFGx_ATTR(layer));\n"
+ ">> \302\240+\n"
+ ">> \302\240+ /* disable the pipe if no more active layer */\n"
+ ">> \302\240+ if (n <= 1)\n"
+ ">> \302\240+ writel_relaxed(fcolor &\n"
+ ">> \302\240+ ~MIXER_BLD_FCOLOR_CTL_PEN(plane_tb[plane_num].pipe),\n"
+ ">> \302\240+ mixer_io + MIXER_BLD_REGS + MIXER_BLD_FCOLOR_CTL_REG);\n"
+ ">> \302\240+}\n"
+ ">> \302\240+\n"
+ ">> \302\240+static void de2_drm_plane_update(struct drm_plane *plane,\n"
+ ">> \302\240+ struct drm_plane_state *old_state)\n"
+ ">> \302\240+{\n"
+ ">> \302\240+ struct drm_plane_state *state = plane->state;\n"
+ ">> \302\240+ struct drm_crtc *crtc = state->crtc;\n"
+ ">> \302\240+ struct lcd *lcd = crtc_to_lcd(crtc);\n"
+ ">> \302\240+ struct priv *priv = lcd->priv;\n"
+ ">> \302\240+ int plane_num = plane - lcd->planes;\n"
+ ">> \302\240+\n"
+ ">> \302\240+ /* if the crtc is disabled, mark update delayed */\n"
+ ">> \302\240+ if (!(priv->started & (1 << lcd->mixer))) {\n"
+ ">> \302\240+ lcd->delayed |= 1 << plane_num;\n"
+ ">> \302\240+ return; /* mixer disabled */\n"
+ ">> \302\240+ }\n"
+ ">> \302\240+\n"
+ ">> \302\240+ mutex_lock(&priv->mutex);\n"
+ ">> \302\240+\n"
+ ">> \302\240+ de2_plane_update(priv, lcd, plane_num, state, old_state);\n"
+ ">> \302\240+\n"
+ ">> \302\240+ mutex_unlock(&priv->mutex);\n"
+ ">> \302\240+}\n"
+ ">> \302\240+\n"
+ ">> \302\240+static void de2_drm_plane_disable(struct drm_plane *plane,\n"
+ ">> \302\240+ struct drm_plane_state *old_state)\n"
+ ">> \302\240+{\n"
+ ">> \302\240+ struct drm_crtc *crtc = old_state->crtc;\n"
+ ">> \302\240+ struct lcd *lcd = crtc_to_lcd(crtc);\n"
+ ">> \302\240+ struct priv *priv = lcd->priv;\n"
+ ">> \302\240+ int plane_num = plane - lcd->planes;\n"
+ ">> \302\240+\n"
+ ">> \302\240+ if (!(priv->started & (1 << lcd->mixer)))\n"
+ ">> \302\240+ return; /* mixer disabled */\n"
+ ">> \302\240+\n"
+ ">> \302\240+ mutex_lock(&priv->mutex);\n"
+ ">> \302\240+\n"
+ ">> \302\240+ de2_plane_disable(lcd->priv, lcd->mixer, plane_num);\n"
+ ">> \302\240+\n"
+ ">> \302\240+ mutex_unlock(&priv->mutex);\n"
+ ">> \302\240+}\n"
+ ">> \302\240+\n"
+ ">> \302\240+static const struct drm_plane_helper_funcs plane_helper_funcs = {\n"
+ ">> \302\240+ .atomic_update = de2_drm_plane_update,\n"
+ ">> \302\240+ .atomic_disable = de2_drm_plane_disable,\n"
+ ">> \302\240+};\n"
+ ">> \302\240+\n"
+ ">> \302\240+static const struct drm_plane_funcs plane_funcs = {\n"
+ ">> \302\240+ .update_plane = drm_atomic_helper_update_plane,\n"
+ ">> \302\240+ .disable_plane = drm_atomic_helper_disable_plane,\n"
+ ">> \302\240+ .destroy = drm_plane_cleanup,\n"
+ ">> \302\240+ .reset = drm_atomic_helper_plane_reset,\n"
+ ">> \302\240+ .atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state,\n"
+ ">> \302\240+ .atomic_destroy_state = drm_atomic_helper_plane_destroy_state,\n"
+ ">> \302\240+};\n"
+ ">> \302\240+\n"
+ ">> \302\240+static int de2_one_plane_init(struct drm_device *drm,\n"
+ ">> \302\240+ struct drm_plane *plane,\n"
+ ">> \302\240+ int possible_crtcs,\n"
+ ">> \302\240+ int plane_num)\n"
+ ">> \302\240+{\n"
+ ">> \302\240+ int ret;\n"
+ ">> \302\240+\n"
+ ">> \302\240+ ret = drm_universal_plane_init(drm, plane, possible_crtcs,\n"
+ ">> \302\240+ &plane_funcs,\n"
+ ">> \302\240+ plane_tb[plane_num].formats,\n"
+ ">> \302\240+ plane_tb[plane_num].n_formats,\n"
+ ">> \302\240+ plane_tb[plane_num].type, NULL);\n"
+ ">> \302\240+ if (ret >= 0)\n"
+ ">> \302\240+ drm_plane_helper_add(plane, &plane_helper_funcs);\n"
+ ">> \302\240+\n"
+ ">> \302\240+ return ret;\n"
+ ">> \302\240+}\n"
+ ">> \302\240+\n"
+ ">> \302\240+/* initialize the planes */\n"
+ ">> \302\240+int de2_plane_init(struct drm_device *drm, struct lcd *lcd)\n"
+ ">> \302\240+{\n"
+ ">> \302\240+ int i, n, ret, possible_crtcs = 1 << drm_crtc_index(&lcd->crtc);\n"
+ ">> \302\240+\n"
+ ">> \302\240+ n = ARRAY_SIZE(plane_tb);\n"
+ ">> \302\240+ if (n != DE2_N_PLANES) {\n"
+ ">> \302\240+ dev_err(lcd->dev, \"Bug: incorrect number of planes %d != \"\n"
+ ">> \302\240+ __stringify(DE2_N_PLANES) \"\\n\", n);\n"
+ ">> \302\240+ return -EINVAL;\n"
+ ">> \302\240+ }\n"
+ ">> \302\240+\n"
+ ">> \302\240+ for (i = 0; i < n; i++) {\n"
+ ">> \302\240+ ret = de2_one_plane_init(drm, &lcd->planes[i],\n"
+ ">> \302\240+ possible_crtcs, i);\n"
+ ">> \302\240+ if (ret < 0) {\n"
+ ">> \302\240+ dev_err(lcd->dev, \"plane init failed %d\\n\", ret);\n"
+ ">> \302\240+ break;\n"
+ ">> \302\240+ }\n"
+ ">> \302\240+ }\n"
+ ">> \302\240+\n"
+ ">> \302\240+ return ret;\n"
+ ">> \302\240+}\n"
+ ">> \302\240--\n"
+ ">> \302\2402.10.2\n"
  ">\n"
- ">> ?_______________________________________________\n"
- ">> ?dri-devel mailing list\n"
- ">> ?dri-devel at lists.freedesktop.org\n"
- ">> ?https://lists.freedesktop.org/mailman/listinfo/dri-devel\n"
+ ">> \302\240_______________________________________________\n"
+ ">> \302\240dri-devel mailing list\n"
+ ">> \302\240dri-devel-PD4FTy7X32lNgt0PjOBp9y5qC8QIuHrW@public.gmane.org\n"
+ ">> \302\240https://lists.freedesktop.org/mailman/listinfo/dri-devel\n"
  ">\n"
  "> --\n"
  "> Daniel Vetter\n"
@@ -1757,7 +1766,12 @@
  ">\n"
  "> --\n"
  "> You received this message because you are subscribed to the Google Groups \"linux-sunxi\" group.\n"
- "> To unsubscribe from this group and stop receiving emails from it, send an email to linux-sunxi+unsubscribe at googlegroups.com.\n"
- > For more options, visit https://groups.google.com/d/optout.
+ "> To unsubscribe from this group and stop receiving emails from it, send an email to linux-sunxi+unsubscribe-/JYPxA39Uh5TLH3MbocFF+G/Ez6ZCGd0@public.gmane.org\n"
+ "> For more options, visit https://groups.google.com/d/optout.\n"
+ "\n"
+ "-- \n"
+ "You received this message because you are subscribed to the Google Groups \"linux-sunxi\" group.\n"
+ "To unsubscribe from this group and stop receiving emails from it, send an email to linux-sunxi+unsubscribe-/JYPxA39Uh5TLH3MbocFF+G/Ez6ZCGd0@public.gmane.org\n"
+ For more options, visit https://groups.google.com/d/optout.
 
-1c96ad56c7f73cffdfcb0deff32e32dab963d25fc7e1605bd437e1842257174a
+65971c0cc1f54cb5b5bc960f5fa112086de31e7df6db9fef2e7f6eca54573a42

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.